
    dhs                        d Z ddlZddlZddlZddlZddlZddlmZmZm	Z	m
Z
mZmZmZmZ ddlmZ ddlmZ ddlmZmZ ddlmZmZ dd	lmZmZ dd
lmZmZmZm Z m!Z!  ede"      Z#e#jI                  d      ed               Z%e#jI                  ddg      ed               Z&e#jI                  ddg      ede'fd              Z(e#jI                  ddg      ede'fd              Z)e#jI                  d      ed               Z*e#jI                  d      ede'fd              Z+e#jI                  d      ede'fd              Z,e#jI                  ddg      ed               Z-e#jI                  d      ede'd e.fd!              Z/e#jI                  d"dg      ede'fd#              Z0e#jI                  d$dg      ede'fd%              Z1e#jI                  d&dg      ede'fd'              Z2e#jI                  d(dg      ed)               Z3e#jI                  d*      ed+               Z4e#jI                  d,      ed-               Z5e#jI                  d.      ede'fd/              Z6y)0a  
admin_routes.py

Purpose:
  Admin panel HTML and actions for managing users. Includes add, remove, and
  change-password endpoints, protected by the admin_required decorator.
  Also exposes admin-only JSON APIs to view and manage any user's cameras and
  images, and to read audit logs. All routes are CSRF-protected globally.

Routes:
  - GET /admin
  - POST /admin/add_user
  - POST /admin/remove_user/<int:user_id>
  - POST /admin/change_password/<int:user_id>
  - GET  /admin/users.json
  - GET  /admin/user/<int:user_id>/cameras.json
  - GET  /admin/user/<int:user_id>/images.json
  - POST /admin/user/<int:user_id>/cameras/rename
  - POST /admin/user/<int:user_id>/cameras/delete
  - POST /admin/image/delete
  - GET  /admin/logs.json
    N)	Blueprintrender_templaterequestredirecturl_forflashsessionjsonify   )get_db)admin_required)log_admin_actionget_request_ip)STATIC_PATHUSER_PHOTOS_REAL)latest_from_db_or_fscollect_user_images)parse_ts_from_any	format_dtnormalize_to_static_user_photosbuild_media_urlbuild_share_urladmin_routesz/adminc                  n    t               } | j                  d      j                         }t        d|      S )Nz_SELECT id, username, IFNULL(is_admin,0) AS is_admin FROM users ORDER BY username COLLATE NOCASEz
admin.html)users)r   executefetchallr   )dbr   s     KC:\Users\algun\Documents\ceba web\Ceba - Github\app_modules\admin_routes.pyadmin_panelr    )   s9     
BJJxy  C  C  EE<u55    z/admin/add_userPOST)methodsc                     t         j                  j                  d      xs dj                         j	                         } t         j                  j                  d      xs d}| r|s t        dd       t        t        d            S t        j                  d|       s t        dd       t        t        d            S 	 t        j                  |j                  d	      t        j                               j                  d	      }t               }|j!                  d
| |f       |j#                          t        dd       	 t%        dt'        j                  d      d t)        t               d|         t        t        d            S # t*        $ r Y w xY w# t,        j.                  $ r t        dd       Y Dt,        j0                  $ r t        dd       Y dw xY w)Nusername passwordu&   Korisničko ime i lozinka su obavezni.erroradmin_routes.admin_panelz[a-z0-9_]{3,32}uU   Korisničko ime smije sadržavati samo mala slova, brojeve i donju crtu (3-32 znaka).utf-8z9INSERT INTO users (username, password_hash) VALUES (?, ?)zKorisnik dodan.successadd_useruser_id	username=admin_user_idtarget_user_idipdetailu   Korisničko ime već postoji.   Greška baze.)r   formgetstriplowerr   r   r   re	fullmatchbcrypthashpwencodegensaltdecoder   r   commitr   r	   r   	Exceptionsqlite3IntegrityErrorError)r%   r'   pwd_hashr   s       r   admin_add_userrF   1   s      ,299;AACH||
+1rH86@ :;<<<<*H5egno :;<<(==!96>>;KLSST[\X


NQY[cPde
		+	Zw{{97M^bguv}g~  JS  T\  S]  H^  _ G6788  		!! 8-w7== (ow'(s7   >B F ?3F 	FF FF G6GGz /admin/remove_user/<int:user_id>r-   c                    	 t               }|j                  d| f       |j                  d| f       |j                          t        dd       	 t	        dt        j                  d      | t        t                     t        t        d
            S # t        $ r Y w xY w# t        j                  $ r t        dd	       Y Dw xY w)Nz%DELETE FROM cameras WHERE user_id = ?zDELETE FROM users WHERE id = ?zKorisnik i kamere obrisani.r+   remove_userr-   r0   r1   r2   r4   r(   r)   )r   r   r@   r   r   r	   r6   r   r   rA   rB   rD   r   r   )r-   r   s     r   admin_remove_userrJ   N   s    (X


:WJG


3gZ@
		+Y7	]'++i:Pahm{  }D  nE  F
 G6788	  		== (ow'(s0   AB! /B 	BB! BB! !CCz$/admin/change_password/<int:user_id>c                 N   t         j                  xsG t         j                  j                  d      xs dj	                  dd      d   j                         dk(  }|r>t        j                  d      xs i }|j                  d	      xs dj                         }n1t         j                  j                  d	      xs dj                         }t        |      d
k  r2|rt        ddd      dfS t        dd       t        t        d            S 	 t        j                  |j                  d      t        j                                j#                  d      }t%               }|j'                  d|| f       |j)                          	 t+        dt-        j                  d      | t/        t                      |rt        ddi      S t        dd       t        t        d            S # t0        $ r Y :w xY w# t2        j4                  $ r# |rt        ddd      dfcY S t        dd       Y Xw xY w)zChange a user's password.
    - Supports form POST (HTML) and JSON (AJAX) with CSRF protection.
    - Enforces minimal password policy server-side.
    zContent-Typer&   ;r   r   application/jsonTsilentnew_password   Fz&Lozinka mora imati najmanje 8 znakova.r+   message  r(   r)   r*   z/UPDATE users SET password_hash = ? WHERE id = ?change_passwordr-   rI   r+   zLozinka promijenjena.r4     )r   is_jsonheadersr6   splitr7   get_jsonr5   lenr
   r   r   r   r;   r<   r=   r>   r?   r   r   r@   r   r	   r   rA   rB   rD   )r-   rW   datarP   new_hashr   s         r   admin_change_passwordr^   `   s    oo 			^	,	299#qA!DJJLPbb  t,206B==?((8>BEEG <1u9abcehhh6@ :;<<(==!4!4W!=v~~?OPWWX_`X


DxQXFYZ
			.gkk)>Telq  AH  rI  J It,--%y1
 G6788  		
 == (uIJCOOow'(sC   A4G. /G 0G. ?G. 	G+(G. *G++G. .%H$H$#H$z/admin/users.jsonc            
          t               } | j                  d      j                         }g }|D ]A  }|j                  |d   |d   t	        |d   xs d      dk(  t	        |d   xs d      d       C t        d	|i      S )
Na   
        SELECT u.id, u.username, IFNULL(u.is_admin,0) AS is_admin,
               COUNT(c.camera_id) AS camera_count
        FROM users u
        LEFT JOIN cameras c ON c.user_id = u.id
        GROUP BY u.id
        ORDER BY u.username COLLATE NOCASE
    idr%   is_adminr   r   camera_count)r`   r%   ra   rb   r   )r   r   r   appendintr
   )r   rowsr   rs       r   admin_users_jsonrg      s     
B::  	 
 	 ED'*AjM.Q/14. 1 6Q7	
 	  GU#$$r!   z&/admin/user/<int:user_id>/cameras.jsonc           
         t               }|j                  d      j                         D cg c]  }|d   	 }}dt        |      v }d|rdndz   }|j                  d| d| f      }g }|j                         D ]}  }t	        |d	         }	t        |	|d
   xs dt              \  }
}d}|r|d   nd xs d}|j                  |	|d   |
rt        |
      nd|
rt        |
j                               nd ||d        t        d|i      S c c}w )NzPRAGMA table_info(cameras)r   modelz"camera_id, camera_name, file_pathsz, modelr&   zSELECT zC FROM cameras WHERE user_id = ? ORDER BY camera_name COLLATE NOCASE	camera_id
file_pathsz/static/camera_render.pngzVision minicamera_namezNema aktivnosti)rj   rl   last_activelatest_image_tsthumbnail_urlri   cameras)r   r   r   setstrr   r   rc   r   rd   	timestampr
   )r-   r   rowcols	has_modelselect_fieldscurre   rf   cam_id	latest_dt_	thumb_urlri   s                 r   admin_user_cameras_jsonr}      s$    
B jj)EFOOQRQsCFQDR3t9$I8IXZ[M
**w}o-pqt{s}
~CD\\^Q{^$+FAlO4Ir;W	1/	(7dD}]+3<9Y/BS=Fs9#6#6#89D&
 	  It$%%% Ss   Dz%/admin/user/<int:user_id>/images.jsonc                    t               }t        | |t              }|j                  d| f      j	                         }|D ci c]  }t        |d         |d    }}i }|D ]  }|j                  d      }|s||vr||j                  |d|       g d||<   ||   d   j                  |d   |d   ||j                  d	      rt        |j                  d	            nd
d        t        dt        t        j                  j                  dd                  }	t        dt        t        t        j                  j                  dd            d            }
g }|j                         D ]H  \  }}t        |d         }|d   |	|	|
z    }|	|
z   |k  }|j                  ||d   ||||r|	|
z   nd d       J |j!                  d        t#        |t        |      d      S c c}w )NzQSELECT camera_id, camera_name FROM cameras WHERE user_id = ? ORDER BY camera_namerj   rl   zCamera )rj   rl   imagesr   urlreltsr&   r   r   rj   r   r   offsetr   limit   d   )rj   rl   r   total_counthas_morenext_offsetc                     | d   S )Nrl    xs    r   <lambda>z(admin_user_images_json.<locals>.<lambda>   s	    a&6r!   )key)rp   total_cameras)r   r   r   r   r   rr   r6   rc   r   maxrd   r   argsminitemsr[   sortr
   )r-   r   
all_imagescam_rowsrf   camera_namesrp   imgry   r   r   result_camerascam_datatotal_imagesimages_slicer   s                   r   admin_user_images_jsonr      s    
B$Wb+>J zzmpwoyz  D  D  FHCKL8aC+'=)998LL G% #+//'&8JKGFO
 	!((u:u:.1ggdm)CGGDM*	*
 	 $ C((1567F3s7<<++GR893?@EN#MMO8H-.)&%@UNl2#M2"' -56E>4
 	 , 67!^,  W Ms   Gz/admin/share_linkc                  r   t        j                  d      xs i } t        t        | j	                  d      xs d            }t        | j	                  d      xs d      }t        dt        |d            }|st        d	d
d      dfS t        |      \  }}|st        d	dd      dfS t        j                  j                  t        |      }t        j                  j                  |      st        d	dd      dfS t        t        j                               |dz  z   }t!        ||      }t        d||d      S )zGenerate a short-lived public share URL for an image.
    Admin-only endpoint to prevent user-level mass sharing without oversight.
    Body: { rel: 'User-photos/PICT_...', ttl_minutes: 30 }
    TrN   r   r&   ttl_minutesiN  r   i  FzNedostaje slika.rR   rT   Neispravno ime datoteke.zDatoteka ne postoji.  <   )r+   r   
expires_at)r   rZ   r   rr   r6   rd   r   r   r
   r   ospathjoinr   existstimer   )r\   r   r   r   camabs_pathexpr   s           r   admin_generate_share_linkr      s    4(.BD
)#dhhuo.C*D
ECdhh}-9:Ka[%01K55GHI3NN$GB55OPQSVVVww||K-H77>>(#55KLMsRR
diik
[2-
-C
#s
#CtCsCDDr!   z8/admin/user/<int:user_id>/camera/<camera_id>/images.jsonrj   c                 :   |j                         rt        |      dk(  st        ddi      dfS t               }|j	                  d| |f      j                         }|st        ddi      dfS t        | |t              }|D cg c]  }|j                  d      |k(  s| }}t        d	t        t        j                  j                  d
d	                  }t        dt        t        t        j                  j                  dd            d            }t        |      }	||||z    }
||z   |	k  }g }|
D ]I  }|j                  |d   |d   ||j                  d      rt        |j                  d            ndd       K t        ||d   ||	||r||z   nd |d      S c c}w )N   r(   zInvalid camera IDrT   zCSELECT camera_name FROM cameras WHERE user_id = ? AND camera_id = ?zCamera not foundr   rj   r   r   r   r   r   r   r   r   r   r&   r   rl   )rj   rl   r   r   r   r   current_offset)isdigitr[   r
   r   r   fetchoner   r   r6   r   rd   r   r   r   rc   r   )r-   rj   r   	cam_checkr   r   camera_imagesr   r   r   r   r   result_imagess                r   admin_user_camera_images_jsonr     s    C	Nb$8!456;;	B

`cjlubvw  A  A  CI!345s::$Wb+>J %/TJS#''+2F)2SSJMT C((1567F3s7<<++GR893?@E}%L 7L,.H Mu:u:".1ggdm)CGGDM*	
 	   /#)1v~t   ) Us    FFz%/admin/user/<int:user_id>/cameras/addc           
         t        j                  d      xs i }t        |j                  dd            j	                         }|j                  d      xs dj	                         }|j                         rt        |      dk(  st        ddd	      d
fS |r$t        |      dkD  st        j                  d|      st        ddd	      d
fS t               }	 |j                  d|f      j                         }|rt        ddd	      d
fS |j                  d| f      j                         }|st        ddd	      dfS |j                  d| ||f       |j                          	 t        dt        j                  d      | t!        t               d| d|        t        ddd	      S # t"        $ r Y w xY w# t$        j&                  $ r}t        ddd	      dfcY d }~S d }~ww xY w)NTrN   rj   r&   rl   r   FzID kamere mora biti 12 brojeva.rR   rT   r   [\w\s\-.]{1,60}Neispravan naziv kamere.z-SELECT user_id FROM cameras WHERE camera_id=?u   Kamera s tim ID već postoji.zSELECT id FROM users WHERE id=?zKorisnik ne postoji.r   zi
            INSERT INTO cameras (user_id, camera_id, camera_name) 
            VALUES (?, ?, ?)
        
add_camerar-   
camera_id=z, name=r/   u   Kamera je uspješno dodana.u   Greška baze podataka.rV   )r   rZ   rr   r6   r7   r   r[   r
   r9   r:   r   r   r   r@   r   r	   r   rA   rB   rD   )r-   r\   rj   rl   r   existinguser_existses           r   admin_user_camera_addr   @  s    4(.BDDHH["-.446I88M*0b779KC	Nb$855VWXZ]]]#k*R/r||DVXc7d55OPQSVVV	BU::MPY|\eegu9XYZ\___ jj!BWJOXXZu9OPQSVVV 	

  y+.	0 				\Y9O`glz  |C  mD  OY  Zc  Yd  dk  lw  kx  My  z 44QRSS  		 == U55MNOQTTTUsN   2F5 	2F5 <%F5 "6F& F5 &	F2/F5 1F22F5 5G"GG"G"z(/admin/user/<int:user_id>/cameras/renamec                 &   t        j                  d      xs i }t        |j                  dd            j	                         }|j                  d      xs dj	                         }|j                         rt        |      dk(  st        ddd	      d
fS |r$t        |      dkD  st        j                  d|      st        ddd	      d
fS t               }	 |j                  d|| |f      }|j                          |j                  dk(  rt        ddd	      dfS 	 t        dt        j                  d      | t!        t               d|        t        ddi      S # t"        $ r Y w xY w# t$        j&                  $ r t        ddd	      dfcY S w xY w)NTrN   rj   r&   rl   r   FzNeispravni podaci.rR   rT   r   r   r   z@UPDATE cameras SET camera_name=? WHERE user_id=? AND camera_id=?r      Kamera nije pronađena.r   rename_camerar-   r   r/   r+   r4   rV   )r   rZ   rr   r6   r7   r   r[   r
   r9   r:   r   r   r@   rowcountr   r	   r   rA   rB   rD   )r-   r\   rj   new_namer   rx   s         r   admin_user_camera_renamer   i  s    4(.BDDHH["-.446I'-2446HC	Nb$855IJKSPPs8}r)>PRZ1[55OPQSVVV	BLjj[^fhoqz]{|
		<<1u9RSTVYYY	_GKK	<Rcjo}  F  pG  R\  ]f  \g  Ph  i 	4())  		 == L5_EFKKLs7   AE* 3E E* 	E'$E* &E''E* *#FFz(/admin/user/<int:user_id>/cameras/deletec                 r   t        j                  d      xs i }t        |j                  dd            j	                         }|j                         rt        |      dk(  st        ddd      d	fS t               }	 |j                  d
| |f      }|j                          |j                  dk(  rt        ddd      dfS 	 t        dt        j                  d      | t        t               d|        t        ddi      S # t        $ r Y w xY w# t         j"                  $ r t        ddd      dfcY S w xY w)NTrN   rj   r&   r   FzNeispravan ID kamere.rR   rT   z3DELETE FROM cameras WHERE user_id=? AND camera_id=?r   r   r   delete_camerar-   r   r/   r+   r4   rV   )r   rZ   rr   r6   r7   r   r[   r
   r   r   r@   r   r   r	   r   rA   rB   rD   )r-   r\   rj   r   rx   s        r   admin_user_camera_deleter     sR    4(.BDDHH["-.446IC	Nb$855LMNPSSS	BLjjNQXZcPde
		<<1u9RSTVYYY	_GKK	<Rcjo}  F  pG  R\  ]f  \g  Ph  i 	4())  		 == L5_EFKKLs7   =AD 3D 4D 	D
D DD #D65D6z/admin/image/deletec                  ,   t        j                  d      xs i } t        | j                  dd            }t	        | j                  d      xs d      }|r|st        ddd	      d
fS t        |      \  }}|st        ddd	      d
fS t               }|j                  d||f      j                         }|st        ddd	      dfS t        j                  j                  t        |      }|j                  d      rt        n"t        j                  j!                  t              }t        j                  j!                  |      }	|	j                  |      st        ddd	      d
fS t        j                  j#                  |      rit        j                  j%                  |      }
t        j&                  |
t        j(                        st        ddd	      dfS 	 t        j*                  |       	 |j                  d||f      j                         }|r|d   r|d   j1                  d      D cg c]#  }|j3                         s|j3                         % }}t        j                  j5                  |      }|D cg c]6  }t        j                  j5                  |      |k7  s&t        |      |k7  s5|8 }}|j                  ddj                  |      ||f       |j7                          	 t=        dt?        j                  d      |tA        t               d|        t        ddi      S # t,        $ r t        ddd	      dfcY S t.        $ r t        ddd	      dfcY S w xY wc c}w c c}w # t8        j:                  $ r Y w xY w# tB        $ r Y tw xY w)NTrN   r   r&   r-   r   FzNedostaju podaci.rR   rT   r   z5SELECT 1 FROM cameras WHERE user_id=? AND camera_id=?zNedozvoljeno.i  zUser-photos/zPutanja nije dozvoljena.z)Server nema dozvolu za brisanje datoteke.zNe mogu obrisati datoteku.rV   z>SELECT file_paths FROM cameras WHERE user_id=? AND camera_id=?rk   ,z?UPDATE cameras SET file_paths=? WHERE user_id=? AND camera_id=?delete_imagezrel=r/   r+   )"r   rZ   r   r6   rd   r
   r   r   r   r   r   r   r   r   
startswithr   realpathr   dirnameaccessW_OKremovePermissionErrorOSErrorrY   r7   basenamer@   rB   rD   r   r	   r   rA   )r\   r   r-   r{   r   r   ownerr   real_staticreal_abs
parent_dirrt   pfps	name_onlykepts                   r   admin_delete_imager     sO    4(.BD
)$((5"*=
>C$((9%*+Gg55HIJCOOs#FAs55OPQSVVV	BJJNQXZ]P^_hhjE5_EFKKww||K-H&)nn^&D""''JZJZ[fJgKww)H{+55OPQSVVV	ww~~hWW__X.
yyRWW-u9defhkkk	]IIh	jjY\ceh[ijssu3|$&),&7&=&=c&BP&Baggi1779&BCP((-I"ys!rww'7'7':i'GNmnoNptwNwAsDyJJX[^[c[cdh[ikrtwZxyIIKw{{97M^ejx  zA  kB  MQ  RU  QV  KW  	X It$%%'  	lu9defhkkk 	]u9UVWY\\\	] Qy ==   sl   L+ -?M. ,M$M$%M. 9'M)!M)0M)46M. +3N +M!M! M!$
M. .NN	NNz/admin/logs.jsonc                  |   t        dt        t        t        j                  j                  dd            d            } t               }|j                  d| f      j                         }|j                  d| f      j                         }g }|D ]l  }|j                  |d   d|d	   xs d
|d   xs d|d   xs d |d   |d   xs dd|d   j                         v sd|d   j                         v rdndd       n |D ]  }|d   xs d|d    }|d   xs |d   rd|d    nd}|d   }|r
|d    d| }|j                  |d   d|d	   xs d
|||d   xs dd|d   j                         v sd |d   j                         v rd!ndd        |j                  d" d#$       t        |d |  t        |      d%      S )&Nr   r   r   rV   
        SELECT ts, ip, user_id, username, event, detail, 'auth' as log_type
        FROM auth_log 
        ORDER BY ts DESC LIMIT ?
    n  
        SELECT aa.ts, aa.ip, aa.admin_user_id, aa.target_user_id, aa.action, aa.detail, 'admin' as log_type,
               au.username as admin_username, tu.username as target_username
        FROM admin_audit aa
        LEFT JOIN users au ON au.id = aa.admin_user_id
        LEFT JOIN users tu ON tu.id = aa.target_user_id
        ORDER BY aa.ts DESC LIMIT ?
    r   AUTHr2   Unknownr%   User#r-   ?eventr3   r&   faillockr(   info)r   typer2   r%   actionr3   severityadmin_usernameAdmin#r0   target_usernamer1   r   u    → ADMINdeleter   warningc                     | d   S )Nr   r   r   s    r   r   z!admin_logs_json.<locals>.<lambda>  s    $r!   Tr   reverse)logsr   )r   r   rd   r   r   r6   r   r   r   rc   r8   r   r
   r[   )	r   r   	auth_logs
admin_logsall_logslog
admin_nametarget_nameaction_descs	            r   admin_logs_jsonr     s0    3s7<<++GS9:C@AE	B 

  	 8:	     8:  H d)d)(yJJU3y>3HS2I+J'l(m)r#)S\-?-?-A#AVsSZ|OaOaOcEcio
 	  )*Ms?7K6L.M
+,rTWXhTi5=M9N8O1Poq(m ]O5>Kd)d)(y"!(m)r%-X1D1D1F%F(VYZbVcViViVkJk	qw
 	 & MM'M6% 8}  r!   z/admin/logs/exportc                  t   t         j                  j                  dd      j                         } t	        dt        t        t         j                  j                  dd            d            }t               }|j                  d|f      j                         }|j                  d|f      j                         }g }|D ]  }|j                  |d	   |d	   rt        |d	         nd
d|d   xs d|d   xs d|d   xs d |d   |d   xs d
d|d   j                         v sd|d   j                         v rdndd        |D ]  }|d   xs d|d    }|d   xs |d   rd|d    nd
}|d   }	|r
|d    d| }	|j                  |d	   |d	   rt        |d	         nd
d |d   xs d||	|d   xs d
d!|d   j                         v sd"|d   j                         v rd#ndd        |j                  d$ d%&       | d'k(  r}d(d)lm}
 d(d l}t        t        t!        j                                      t#        |      |d*} |
|j%                  |d+d,-      d.d/d0t        t!        j                                 d1i2      }|S d(d)lm}
 d(d l}d(d3lm}  |       }|j-                  |      }|j/                  g d4       |D ]3  }|j/                  |d5   |d6   |d7   |d   |d   |d   |d   |d8   g       5 |j1                  d(        |
|j3                         d9d/d0t        t!        j                                 d:i2      S );Nformatcsvr   r   i  i  r   r   r   r&   r   r2   r   r%   r   r-   r   r   r3   r   r   r(   r   )rs   datetimer   r2   r%   r   r3   r   r   r   r0   r   r1   r   z -> r   r   r   r   c                     | d   S )Nrs   r   r   s    r   r   z#admin_logs_export.<locals>.<lambda>G  s    +r!   Tr   jsonr   )Response)export_timestamp
total_logsr      F)indentensure_asciirM   zContent-Dispositionz attachment; filename=audit_logs_z.json)mimetyperX   )StringIO)	TimestampDateTimeTypeIPUsernameActionDetailSeverityrs   r  r   r   ztext/csvz.csv)r   r   r6   r8   r   r   rd   r   r   r   rc   r   r   flaskr  r  r   r[   dumpsr  ior  writerwriterowseekgetvalue)format_typer   r   r   r   r   r   r   r   r   r  r  response_dataresponser  r  outputr  s                     r   admin_logs_exportr   
  s    ,,""8U399;K3s7<<++GT:;TBCE	B 

  	 8:	     8:  H T03D		#d),rd)(yJJU3y>3HS2I+J'l(m)r#)S\-?-?-A#AVsSZ|OaOaOcEcio	
 		  )*Ms?7K6L.M
+,rTWXhTi5=M9N8O1Poq(m ]O4}=KT03D		#d),rd)(y"!(m)r%-X1D1D1F%F(VYZbVcViViVkJk	qw	
 		 ( MM.M=f" )#diik*: ;h-

 JJ}QUJC'*.NsSWS\S\S^O_N``e,fg

  	#F# 	kl COOK JFD	JHHJ	 	  	AOO*.NsSWS\S\S^O_N``d,ef
 	
r!   z$/admin/user/<int:user_id>/stats.jsonc                    t               }|j                  d| f      j                         }|st        ddi      dfS |j                  d| f      j	                         }|D ch c]  }t        |d          }}t        |      }d}d}d }	t        j                  j                  t        d      }
dd l} |j                  d	      }t        j                  |
      D ]7  \  }}}|D ]*  }|j                         }|j                  d
      sE|j                  d      s4|j                  d      s#|j                  d      s|j                  d      sjt!        |      \  }}|s(|j#                  |      }|r|d d d   D ]
  }||v s|} n |s||v st        j                  j                  ||      }	 t        j$                  |      }|t)        |j*                        z  }|dz  }|!ddlm} |j/                  |j0                        }|	||	k  s)|}	- : |j                  dd| |d   f      j                         }|j                  d| |d   f      j                         }|j                  dd|d    f      j                         }ddlm} |rt)        |d         n|	rt)        |	j3                               nd}|rt)        |d         nd}|r|d   ndxs d}d }d} |r|d   xs d|d    }t)        |d         } t        |d   |d   t)        |d   xs d      dk(  d |||||||| d!	      S c c}w # t&        $ r Y [w xY w)"NzKSELECT id, username, IFNULL(is_admin,0) AS is_admin FROM users WHERE id = ?r(   z	not foundr   z/SELECT camera_id FROM cameras WHERE user_id = ?rj   r   zUser-photosz[A-Za-z0-9]{12}z.jpgz.jpegz.pngz.gifz.webpr   )r  zfSELECT ts, ip FROM auth_log WHERE event = ? AND (user_id = ? OR username = ?) ORDER BY ts DESC LIMIT 1login_successr%   zSSELECT ts FROM auth_log WHERE (user_id = ? OR username = ?) ORDER BY ts ASC LIMIT 1z
        SELECT aa.ts, aa.admin_user_id, au.username as admin_username
        FROM admin_audit aa
        LEFT JOIN users au ON au.id = aa.admin_user_id
        WHERE aa.action = 'add_user' AND aa.detail LIKE ?
        ORDER BY aa.ts ASC LIMIT 1
    r.   r   r2   r&   r   zAdmin #r0   r`   ra   )r`   r%   ra   )	userrb   image_counttotal_bytesfirst_seen_tslast_login_tslast_login_ipcreated_by_usernamecreated_at_ts)r   r   r   r
   r   rr   r[   r   r   r   r   r9   compilewalkr8   endswithr   findallstatr   rd   st_sizer  fromtimestampst_mtimers   )!r-   r   ur   rf   cam_idsrb   r%  r&  earliest_tsrootr9   
cam_any_redirpathr{   filesnamenlr   r   mtokenr   str  last
first_authcreation_infor'  r(  r)  r*  r+  s!                                    r   admin_user_stats_jsonrC  x  s    
B


`cjblmvvxA-.33zzKgZXaacH,45Hqs1[>"HG5w<LKKK77<<]3D./JWWT]EDBKK'2;;w+?2;;vCVZ\ZeZeflZmqsq|q|  ~E  rF'-GB&&t,!"4R4 G+"'C! ") w77<<6*B s2::.q :1!//<B&"{*:"$K3  +8 ::~  BQ  SZ  \]  ^h  \i  Aj  k  t  t  vDqt{}~  @J  ~K  tL  M  V  V  XJ JJ   a
m_
%	') *2  "-7C
4()^ic+BWBWBY>ZopM'+CT
OM#'T$ZR6BM M+,<=k7=YhKiJjAkM$/0wAjMs1Z=K]\]G^bcGcd$""&&&2&
 
 
} 66  s   "L-.L22	L?>L?)7__doc__r   r9   rB   r;   r   r  r   r   r   r   r   r   r	   r
   r   r   securityr   auditr   r   pathsr   r   images_servicer   r   helpersr   r   r   r   r   __name__bprouter    rF   rd   rJ   r^   rg   r}   r   r   rr   r   r   r   r   r   r   r   rC  r   r!   r   <module>rM     s9  . 
 	    a a a  $ 3 0 E t t ~x( (6  6 
fX.9  /96 
,vh?9s 9  @9  
06(C&93 &9  D&9V 
%  %* 
23&S &  4&. 
125C 5  35p 
x0E  1E0 
DE*3 *3 *  F*Z 
1F8D$U3 $U  E$UN 
4vhGLc L  HL. 
4vhGLc L  HL( 
&2,&  3,&^ 
<  <~ 
i
   i
X 
01O3 O  2Or!   