ó
    ¶ÉjéJ  ã                   óÀ  • % S r SSKrSSKrSSKrSSKrSSKJr  SSKJr  SSKJ	r	J
r
Jr  SSKJr  SSKJr  \R                   " \5      r SSKJr  \" \R*                  5      rS	\S
'   S\S\4S jr\R8                   V s1 s H  o R;                  5       iM     sn rSrSSSS\S1r Sr!0 r"\#\S'   S\4S jr$S\%S\4S jr&S\%S\4S jr'S\%S\(4S jr)S\%S\%4S jr*S\%S\%4S  jr+S!\S\
\   4S" jr,S#\S\%S\\   4S$ jr-S\%S\%S\
\.\%\4      4S% jr/S\%S\%S\
\   4S& jr0S'\S\%4S( jr1S)\%SS4S* jr2S\%S\%S\%S\\   4S+ jr3S\%S\%S\44S, jr5S-\S.\%S\4S/ jr6S-\SS4S0 jr7SMS\\%   SS4S1 jjr8S\%S\
\   4S2 jr9S\%S3\%S\4S4 jr:S-\S5\S6\SS4S7 jr;S\%S\%S\%S\(4S8 jr<S\%S\%S\44S9 jr=S\%S\44S: jr>S\%S\.\%\%4   4S; jr?S5\S\44S< jr@S\%S\
\	   4S= jrAS\%S>\%S\44S? jrBSMS\%S@\\4   S\44SA jjrC   SNS\%SB\\%   SC\\%   SD\\%   SE\\%   SF\\%   SG\4SSH4SI jjrD SMS\%SF\%S\%S\%SJ\%SK\\%   S\%4SL jjrEg! \ a"    \R3                  S\R*                  5        Sr GNñf = fs  sn f )Ou@  
photo_service.py â€” fotos en disco, organizadas como en hec-photo-app.

Layout (una carpeta por colegio, por fotÃ³grafo y por familia):

    photos/{colegio}/{fotÃ³grafo}/{CÃ“DIGO}/foto.jpg
    photos/{colegio}/{fotÃ³grafo}/{CÃ“DIGO}/.qr/â€¦        â†� foto de la tarjeta QR (no se vende)
    photos/{colegio}/{fotÃ³grafo}/{CÃ“DIGO}/.protect/â€¦   â†� cachÃ© de la protecciÃ³n de caras
    photos/.trash/{colegio}/{lote}/â€¦                   â†� papelera (fuera del colegio a propÃ³sito)

Compatibilidad: las instalaciones anteriores guardaban `photos/{CÃ“DIGO}/foto.jpg`.
Esa carpeta sigue leyÃ©ndose (se trata como fotÃ³grafo "") hasta que se vacÃ­e sola
por la retenciÃ³n RGPD; el organizer ya solo escribe en el layout nuevo.

Este mÃ³dulo solo toca el disco: no firma URLs ni sabe de base de datos (eso es
`media_service`).
é    N)Údatetime)ÚPath)ÚDictÚListÚOptional)Úconfig)Ú
FamilyInfo)ÚZoneInfozZoneInfo | NoneÚ	_EVENT_TZuN   No se pudo cargar el huso %s: las bÃºsquedas por hora usarÃ¡n la del servidor.ÚmtimeÚreturnc                 ó4   • [         R                  " U [        S9$ )uX   Instante absoluto â†’ hora del EVENTO (no la del servidor, que en un VPS suele ser UTC).)Útz)r   Úfromtimestampr   )r   s    ÚYD:\Ingenieria\TRABAJOS ONLINE\Projects\11- Photo School\backend\services\photo_service.pyÚ	_event_dtr   '   s   € ä×!Ò! %¬IÑ6Ð6ó    z.trashÚqr_cardsÚ	_qr_cardsÚthumbsz.thumbsÚ_errorsé<   Ú_families_cachec                  ó"   • [         R                  $ ©N©r   Ú
PHOTOS_DIR© r   r   Úphotos_rootr   6   s   € Ü×ÑÐr   Ú	school_idc                 ó(   • [         R                  U -  $ r   r   ©r    s    r   Úschool_rootr#   :   s   € Ü×Ñ˜yÑ(Ð(r   c                 ó6   • [         R                  [        -  U -  $ )z[`photos/.trash/{colegio}`, FUERA de `photos/{colegio}` (mismo volumen: mover es un rename).)r   r   ÚTRASH_DIRNAMEr"   s    r   Ú
trash_rootr&   >   s   € ä×Ñœ}Ñ,¨yÑ8Ð8r   Únamec                 óV   • [        U 5      R                  R                  5       [        ;   $ r   )r   ÚsuffixÚlowerÚ
IMAGE_EXTS)r'   s    r   Úis_imager,   C   s    € Ü�‹:×Ñ×"Ñ"Ó$¬
Ñ2Ð2r   Úfilenamec                 ó6   • U R                  S5      (       a  S$ S$ )uY   Mismo criterio que hec-photo-app: el prefijo del archivo dice quÃ© pipeline lo escribiÃ³.Úia_ÚaiÚoriginal)Ú
startswith)r-   s    r   Ú
photo_kindr3   G   s   € à×&Ñ& u×-Ñ-ˆ4Ð=°:Ð=r   Úcodec                 ób   • U R                  5       R                  SS5      R                  SS5      $ )uX   Compara cÃ³digos sin espacios ni guiones, en mayÃºsculas ('MARABC123' == 'MAR-ABC-123').Ú Ú Ú-)ÚupperÚreplace)r4   s    r   Ú	norm_coder;   L   s(   € à�:‰:‹<×Ñ  RÓ(×0Ñ0°°bÓ9Ð9r   Úrootc                 óp   • U R                  5       (       d  / $ [        S U R                  5        5       5      $ )Nc              3   óÄ   #   • U  HV  nUR                  5       (       d  M  UR                  R                  S 5      (       a  M<  UR                  [        ;  d  MR  Uv •  MX     g7f))Ú_Ú.N)Úis_dirr'   r2   Ú_RESERVED_DIRS)Ú.0Úps     r   Ú	<genexpr>Ú$photographer_dirs.<locals>.<genexpr>T   sJ   é € ð hš^˜Ø—X‘X—Zó Ø()¯©×(9Ñ(9¸*×(Eó ØJKÏ&É&ÔXfÑJf÷ ‘!š^ùs   ‚A ŸA ÁA Á	A )ÚexistsÚsortedÚiterdir)r<   s    r   Úphotographer_dirsrJ   Q   s5   € Ø�;‰;�=‰=Øˆ	Üñ h˜TŸ\™\œ^ó hó hð hr   Úphotographer_dirc                 óˆ  • XR                  5       R                  SS5      -  nUR                  5       (       a  U$ [        U5      n U R	                  5        HY  nUR                  5       (       d  M  UR
                  R                  S5      (       a  M<  [        UR
                  5      U:X  d  MW  Us  $    g! [         a     gf = f)u\   Carpeta del cÃ³digo ignorando guiones/espacios (la que escribiÃ³ el vendedor vs la impresa).r6   r7   r@   N)r9   r:   rA   r;   rI   r'   r2   ÚOSError)rK   r4   ÚdirectÚtargetÚfolders        r   Úresolve_qr_folderrQ   X   s¢   € à§
¡
£× 4Ñ 4°S¸"Ó =Ñ=€FØ‡}�}‡�ØˆÜ�t‹_€FðØ&×.Ñ.Ö0ˆFØ�}‰}�‹ v§{¡{×'=Ñ'=¸c×'BÓ'BÄyÐQW×Q\ÑQ\ÓG]ÐagÕGgØ’ñ 1ð
 øô ó ØØðús*   Á&B4 Á0B4 ÂB4 Â-B4 Â1B4 Â4
CÃ Cc                 óä  • / n[        [        U 5      5       H0  n[        X15      nUc  M  UR                  UR                  U45        M2     [
        R                  UR                  5       R                  SS5      -  nUR                  5       (       a_  UR                  R                  5       UR                  5       :X  a3  UR                  R                  S5      (       d  UR                  SU45        U$ )ui   [(fotÃ³grafo, carpeta)] de una familia: una por fotÃ³grafo que le sacÃ³ fotos, mÃ¡s la antigua si existe.r6   r7   r@   )rJ   r#   rQ   Úappendr'   r   r   r9   r:   rA   r2   )r    r4   ÚoutÚpdrP   Úlegacys         r   Úfamily_dirsrW   g   s´   € à"$€CÜ¤¨IÓ 6Ö7ˆÜ" 2Ó,ˆØÓØ�J‰J˜Ÿ™ Ð(Ö)ñ 8ô ×Ñ §¡£×!5Ñ!5°c¸2Ó!>Ñ>€FØ‡}�}‡�˜6Ÿ;™;×,Ñ,Ó.°$·*±*³,Ó>ÀvÇ{Á{×G]ÑG]Ð^a×GbÑGbØ�
‰
�B˜�<Ô Ø€Jr   c                 óœ  • / n[        X5       H~  u  p4 X$R                  5        Vs/ s HZ  nUR                  5       (       d  M  UR                  R	                  S5      (       a  M<  [        UR                  5      (       d  MX  UPM\     sn-  nM€     [        US S9$ s  snf ! [         a!  n[        R                  SXF5         SnAM¸  SnAff = f)uM   Fotos vendibles de una familia (no entra en subcarpetas: .qr/, .protect/â€¦).r@   zNo se pudo leer %s: %sNc                 ó0   • U R                   [        U 5      4$ r   )r'   Ústr©rD   s    r   Ú<lambda>Ú#list_family_files.<locals>.<lambda>}   s   € ¨¯©´°A³Ñ'7r   )Úkey)
rW   rI   Úis_filer'   r2   r,   rM   ÚloggerÚwarningrH   )r    r4   ÚfilesÚ_phrP   ÚfÚexcs          r   Úlist_family_filesrf   t   s¸   € à€EÜ" 9Ö3‰ˆð	BØ§¡Ô!1ó ZÒ!1˜AØŸ™Ÿó Ø-.¯V©V×->Ñ->¸s×-Có ÜHPÐQR×QWÑQW×HX÷ Ñ!1ñ Zñ ZŠEñ 4ô �%Ñ7Ñ8Ð8ùò	Zøäó 	BÜ�N‰NÐ3°V×AÒAûð	Bús:   ”B ¦BÁBÁ%BÂBÂB ÂB Â 
CÂ*CÃCÚpathc                 ó¶   •  U R                  [        R                  5      n[	        UR
                  5      S:¼  a  UR
                  S   $ S$ ! [         a     gf = f)u:   Nombre del fotÃ³grafo segÃºn la ruta (""= layout antiguo).r7   é   é   )Úrelative_tor   r   Ú
ValueErrorÚlenÚparts)rg   Úrels     r   Úphotographer_ofrp   €   sU   € ðØ×Ñœv×0Ñ0Ó1ˆô ˜sŸy™y›>¨QÓ.ˆ3�9‰9�Q‰<Ð6°BÐ6øô ó Ùðús   ‚A Á
AÁAÚpartc                 ó€   • U (       a(  SU ;   d"  SU ;   d  SU ;   d  U R                  S5      (       a  [        SU < 35      eg )Nz..Ú/Ú\r@   zInvalid path component: )r2   rl   )rq   s    r   Ú
_safe_partru   ‰   s@   € Þ�4˜4“< 3¨$£;°$¸$³,À$Ç/Á/ÐRU×BVÑBVÜÐ3°D±8Ð<Ó=Ð=ð CWr   c                 ór  • U(       a?  [        U5      R                  U:w  d&  UR                  S5      (       d  [        U5      (       d  g[	        X5       HP  u  p4XB-  n UR                  5       R                  UR                  5       5        UR                  5       (       d  MN  Us  $    g! [         a     Mb  f = f)zbRuta absoluta del original, o None si el nombre es sospechoso (../, absoluto, oculto) o no existe.r@   N)	r   r'   r2   r,   rW   Úresolverk   rl   r_   )r    r4   r-   rc   rP   rg   s         r   Ú
find_photorx   Ž   s™   € æ”t˜H“~×*Ñ*¨hÓ6¸(×:MÑ:MÈc×:RÑ:RÔZbÐck×ZlÑZlØÜ" 9Ö3‰ˆØÑ ˆð	Ø�L‰L‹N×&Ñ& v§~¡~Ó'7Ô8ð �<‰<�>‹>ØŠKñ 4ð øô	 ó 	Úð	ús   Á-B(Â(
B6Â5B6c                 ó*   • [        [        X5      5      $ r   )rm   rf   )r    r4   s     r   Úcount_family_photosrz   �   s   € ÜÔ  Ó1Ó2Ð2r   Úsrcr)   c                 óè   •  U R                  [        R                  5      n[        R                  UR                  -  U R                   U 3-  $ ! [         a    [	        U R
                  5      n NOf = f)uL   `photos/a/b/c/x.jpg` â†’ `thumbs/a/b/c/x{suffix}` (suffix incluye el punto).)	rk   r   r   rl   r   r'   Ú
THUMBS_DIRÚparentÚstem)r{   r)   ro   s      r   Úmirror_pathr€   £   sb   € ðØ�o‰oœf×/Ñ/Ó0ˆô ×Ñ˜sŸz™zÑ)¨s¯x©x¨j¸¸Ð,AÑAÐAøô ó Ü�3—8‘8‹nŠðús   ‚A ÁA1Á0A1c                 ób  • [        U S5      R                  n UR                  U R                   S35       H  nUR	                  SS9  M     U R                  S-  n UR                  U R                   S35       H  nUR	                  SS9  M     g! [
         a     NQf = f! [
         a     gf = f)uC   Borra miniaturas, vistas previas y cachÃ© protegida de un original.r7   z.*T)Ú
missing_okz.protectz_heads_*N)r€   r~   Úglobr   ÚunlinkrM   )r{   Údrd   Úprotects       r   Údrop_derivativesr‡   ¬   s¬   € ä�C˜Ó×#Ñ#€AðØ—‘˜3Ÿ8™8˜* B˜Ö(ˆAØ�H‰H ˆHÓ%ñ )ð �j‰j˜:Ñ%€GðØ—‘ §¡ 
¨(Ð3Ö4ˆAØ�H‰H ˆHÓ%ò 5øô	 ó Ùðûô ó Ùðús#   ˜4B Á4B! Â
BÂBÂ!
B.Â-B.c                 ón   • U (       a  [         R                  SU  3S 5        g [         R                  5         g )NÚ	families_)r   ÚpopÚclearr"   s    r   Úinvalidate_families_cacherŒ   ¾   s(   € ÞÜ×Ñ˜i¨	 {Ð3°TÕ:ä×ÑÕr   c                 ó  • [         R                  " 5       nSU  3n[        R                  U5      nU(       a  XS   :  a  US   $ [	        U 5      n0 n0 n[        U5       GH¥  n[        UR                  5       5       GHƒ  nUR                  5       (       a   UR                  R                  S5      (       a  M;  UR                  R                  5       n	Su  p«UR                  5        H�  nUR                  5       (       d  M  UR                  R                  S5      (       a  M<  [        UR                  5      (       d  MX  U
S-  n
 [        X¼R                  5       R                   5      nMƒ     U
S:X  a  Mö  UR%                  U	['        U	S/ S95      nU=R(                  U
-  sl        UR                  UR*                  ;  a%  UR*                  R-                  UR                  5        [        UR                  U	S	5      U5      Xi'   GM†     GM¨     UR/                  5        H.  u  pžUS:”  d  M  [1        U5      R3                  S
5      XY   l        M0     [        UR7                  5       S SS9nXñ[8        -   S.[        U'   U$ ! ["         a     GM¢  f = f)Nr‰   Ú
expires_atÚdatar@   )r   ç        rj   r   )Úqr_codeÚphoto_countÚphotographersr�   ú%Y-%m-%dT%H:%M:%Sc                 óD   • U R                   =(       d    SU R                  4$ )Nr7   )Úlast_photo_atr‘   )rd   s    r   r\   Ú"get_all_families.<locals>.<lambda>æ   s   € °a·o±o×6KÈÈQÏYÉYÑ5Wr   T©r^   Úreverse)r�   rŽ   )ÚtimeÚ	monotonicr   Úgetr#   rJ   rH   rI   rA   r'   r2   r9   r_   r,   ÚmaxÚstatÚst_mtimerM   Ú
setdefaultr	   r’   r“   rS   Úitemsr   Ústrftimer–   ÚvaluesÚ
_CACHE_TTL)r    Únowr^   Úcachedr<   ÚfamiliesÚ
last_mtimerU   rP   r4   ÚcountÚnewestrd   Úfamr   Úresults                   r   Úget_all_familiesr­   Å   s  € Ü
�.Š.Ó
€CØ�i�[Ð
!€CÜ× Ñ  Ó%€FÞ�#˜|Ñ,Ó,Ø�f‰~Ðä�yÓ!€DØ&(€HØ#%€JÜ ×%ˆÜ˜RŸZ™Z›\×*ˆFØ—=‘=—?‘? f§k¡k×&<Ñ&<¸S×&AÑ&AÙØ—;‘;×$Ñ$Ó&ˆDØ"‰MˆEØ—^‘^Ö%�Ø—9‘9—;“; q§v¡v×'8Ñ'8¸×'=Ó'=Ä(È1Ï6É6×BRÓBRØ˜Q‘J�EðÜ!$ V¯V©V«X×->Ñ->Ó!?šñ	 &ð ˜‹zÙØ×%Ñ% d¬J¸tÐQRÐbdÑ,eÓfˆCØ�OŠO˜uÑ$�OØ�w‰w˜c×/Ñ/Ó/Ø×!Ñ!×(Ñ(¨¯©Ô1Ü" :§>¡>°$¸Ó#<¸fÓEˆJÔô% +ñ &ð( "×'Ñ'Ö)‰ˆØ�1�9Ü+4°UÓ+;×+DÑ+DÐEXÓ+YˆH‰NÖ(ñ *ô �H—O‘OÓ%Ñ+WÐaeÑf€FØ$*Ä
Ñ:JÑK„O�CÑØ€Møô #ó Ûðús   Å#I8É8
J	ÊJ	Úkindc                 ó
  • [         R                  " S5      n[        U 5      U SU 3-  nSnUR                  5       (       a2  US-  n[        U 5      U SU SU 3-  nUR                  5       (       a  M2  UR	                  SSS9  U$ )Nz%Y%m%d-%H%M%Sr8   rj   T©ÚparentsÚexist_ok)rš   r¢   r&   rG   Úmkdir)r    r®   ÚstampÚbatchÚns        r   Ú_new_trash_batchr·   í   s‡   € Ü�MŠM˜/Ó*€EÜ�yÓ! u g¨Q¨t¨fÐ$5Ñ5€EØ	€AØ
�,‰,�.‰.Ø	ˆQ‰ˆÜ˜9Ó%¨5¨'°°4°&¸¸!¸Ð(=Ñ=ˆð �,‰,�.‹.ð 
‡K�K˜ t€KÑ,Ø€Lr   rµ   ro   c                 óR  • X-  nUR                   R                  SSS9  UR                  5       (       aK  UR                  UR                   S[        [        R                  " 5       S-  5       UR                   35      n[        R                  " [        U 5      [        U5      5        g )NTr°   r?   iè  )r~   r³   rG   Ú	with_namer   Úintrš   r)   ÚshutilÚmoverZ   )r{   rµ   ro   Údests       r   Ú_move_to_trashr¾   ø   sw   € Ø‰;€DØ‡K�K×Ñ˜d¨TÐÑ2Ø‡{�{‡}�}Ø�~‰~ §¡ ¨1¬S´·²³¸tÑ1CÓ-DÐ,EÀdÇkÁkÀ]ÐSÓTˆÜ
‡K‚K”�C“œ#˜d›)Õ$r   c                 ó¤  • [        U5        [        XU5      nUc  g UR                  [        U 5      5      n[        U S[        U5       35      n[        U5        [        X5U5        [        U 5        [        R                  SXUR                  5        g! [         a2    [        S5      UR                  R                  -  UR                  -  n N—f = f)z?Foto a la papelera (y fuera sus derivados). False si no existe.FÚ_legacyzphoto-u)   Colegio %s: foto a la papelera: %s â†’ %sT)ru   rx   rk   r#   rl   r   r~   r'   r·   r;   r‡   r¾   rŒ   r`   Úinfo)r    r4   r-   rg   ro   rµ   s         r   Údelete_photorÂ      s¶   € äˆxÔÜ�i xÓ0€DØ�|Øð=Ø×Ñœ{¨9Ó5Ó6ˆô ˜Y¨&´¸4³Ð0AÐ(BÓC€EÜ�TÔÜ�4 Ô$Ü˜iÔ(Ü
‡K�KÐ;¸YÈeÏjÉjÔYØøô ó =Ü�9‹o §¡× 0Ñ 0Ñ0°4·9±9Ñ<Šð=ús   �B Â9CÃCc                 óæ  • SnSn[        X5       H´  u  pE[        S UR                  S5       5       5      nUc  [        U S[	        U5       35      nU(       a  [        U5      UR                  -  O[        S5      UR                  -  n[        R                  " [        US-  S5      R                  S	S
9  [        XRU5        X6-  nM¶     U(       a  [        U 5        [        R                  SXU5        U$ )uR   Todas las carpetas de la familia (de todos los fotÃ³grafos) a UN lote restaurable.Nr   c              3   óR   #   • U  H  oR                  5       (       d  M  S v •  M     g7f©rj   N©r_   ©rC   rd   s     r   rE   Ú'delete_family_photos.<locals>.<genexpr>  s   é € Ð@Ò0˜!·I±I·K—A‘AÒ0ùó   ‚'ž	'Ú*zfamily-rÀ   Úxr7   T©Úignore_errorsz-Colegio %s: %d ficheros a la papelera para %s)rW   ÚsumÚrglobr·   r;   r   r'   r»   Úrmtreer€   r~   r¾   rŒ   r`   rÁ   )r    r4   rµ   ÚdeletedÚphrP   rb   ro   s           r   Údelete_family_photosrÓ     sË   € à €EØ€GÜ! )Ö2‰
ˆÜÑ@˜vŸ|™|¨CÔ0Ó@Ó@ˆØ‰=Ü$ Y°'¼)ÀD»/Ð9JÐ0KÓLˆEÞ(*Œd�2‹h˜Ÿ™Ò$´°Y³À&Ç+Á+Ñ0MˆÜ�Š”k &¨3¡,°Ó3×:Ñ:È$ÒOÜ�v cÔ*ØÑŠñ 3ö Ü! )Ô,Ü
‡K�KÐ?ÀÐUYÔZØ€Nr   c           	      ó
  • [        U S5      nSn[        [        U 5      5       HŠ  n[        UR	                  5       5       Hj  nUR                  5       (       d  M  U[        S UR                  S5       5       5      -  n[        XA[        UR                  5      UR                  -  5        Ml     MŒ     [        R                  " [        R                  U -  SS9  [        U 5        [         R#                  SXUR                  5        U$ )uJ   VacÃ­a el colegio moviendo TODAS las familias a la papelera (recuperable).Úallr   c              3   óR   #   • U  H  oR                  5       (       d  M  S v •  M     g7frÅ   rÆ   rÇ   s     r   rE   Ú$delete_all_photos.<locals>.<genexpr>,  s   é € ÐGÒ&7 ¿9¹9¿;Ÿ1™1Ò&7ùrÉ   rÊ   TrÌ   u<   Colegio %s: BORRADO TOTAL â€” %d ficheros a la papelera (%s))r·   rJ   r#   ÚlistrI   rA   rÎ   rÏ   r¾   r   r'   r»   rÐ   r   r}   rŒ   r`   ra   )r    rµ   rÑ   rU   rP   s        r   Údelete_all_photosrÙ   $  sÄ   € ä˜Y¨Ó.€EØ€GÜ¤¨IÓ 6Ö7ˆÜ˜2Ÿ:™:›<Ö(ˆFØ—=‘=—?‘?ÙØ”sÑG f§l¡l°3Ô&7ÓGÓGÑGˆGÜ˜6¬$¨r¯w©w«-¸&¿+¹+Ñ*EÖFó	 )ñ 8ô ‡M‚M”&×#Ñ# iÑ/¸tÒDÜ˜iÔ(Ü
‡N�NÐQÐS\Ðgl×gqÑgqÔrØ€Nr   c                 óÖ   • U R                  SS5      n[        U5      S:  d  [        US   5      S:w  a  SU 4$ US   US   p2US S  SUSS	  SUS	S   S
US S  SUSS  SUSS	  3US   4$ )Nr8   é   é   r   é   r7   rj   ri   é   ÚTÚ:)Úsplitrm   )r'   rn   r…   Úts       r   Ú_batch_labelrã   4  sš   € Ø�J‰J�s˜AÓ€EÜ
ˆ5ƒz�Aƒ~œ˜U 1™X›¨!Ó+Ø�4ˆxˆØ�‰8�U˜1‘X€qØ��ˆeˆW�A�a˜˜!�f�X˜Q˜q  ˜u˜g Q q¨¨! u g¨Q¨q°°1¨v¨h°a¸¸!¸A¸°xÐ@À%ÈÁ(ÐJÐJr   c                 óz   • [        [        R                  " 5       U R                  5       R                  -
  S-  5      $ )Ni€Q )rº   rš   rž   rŸ   )rµ   s    r   Ú_batch_age_daysrå   <  s)   € Ü”—	’	“˜eŸj™j›l×3Ñ3Ñ3°uÑ<Ó=Ð=r   c                 óâ  • [        U 5      nUR                  5       (       d  / $ / nUR                  5        GH!  nUR                  5       (       d  M  UR                  S5       Vs/ s H  oDR	                  5       (       d  M  UPM     nn[        UR                  5      u  pgUR                  UR                  Xv[        U5      [        [        S U 5       5      S-  S5      [        UR                  S5       Vs1 s H%  oˆR                  5       (       d  M  UR                  iM'     sn5      S S [        S[        R                  [!        U5      -
  5      S.5        GM$     [        US	 S
S9$ s  snf s  snf )NrÊ   c              3   óT   #   • U  H  oR                  5       R                  v •  M      g 7fr   )rž   Úst_sizerÇ   s     r   rE   Úlist_trash.<locals>.<genexpr>L  s   é € Ð Aº5°a§¡£×!1Ö!1º5ùs   ‚&(i   rj   z*/*é   r   )Úidr®   Ú
deleted_atÚ
file_countÚsize_mbr§   Úexpires_in_daysc                 ó   • U S   $ )Nrë   r   ©Úes    r   r\   Úlist_trash.<locals>.<lambda>P  s   € ¨¨4ªr   Tr˜   )r&   rA   rI   rÏ   r_   rã   r'   rS   rm   ÚroundrÎ   rH   rƒ   r�   r   ÚTRASH_RETENTION_DAYSrå   )	r    ÚtrashÚentriesrµ   rd   rb   rì   r®   r…   s	            r   Ú
list_trashrø   @  s!  € Ü�yÓ!€EØ�<‰<�>‰>Øˆ	Ø€GØ—‘—ˆØ�|‰|�~‰~ÙØ!ŸK™K¨Ô,Ó<Ò,�q·	±	·—Ñ,ˆÐ<Ü'¨¯
©
Ó3Ñˆ
Ø�‰Ø—*‘* dÔTWÐX]ÓT^ÜœSÑ A¹5Ó AÓAÀGÑKÈQÓOÜ°·
±
¸5Ô0AÓPÒ0A¨1ÇXÁXÇZ£ §¤Ñ0AÑPÓQÐRUÐSUÐVÜ" 1¤f×&AÑ&AÄOÐTYÓDZÑ&ZÓ[ñ	
÷ 	ñ !ô �'Ñ0¸$Ñ?Ð?ùò =ùò
  Qs   Á#E'Á?E'Ã5E,ÄE,Úentry_idc                 óª  • [        UR                  S5      5        [        U 5      nX!-  R                  5       n UR	                  UR                  5       5        UR                  5       (       d  [        SU 35      eSn[        UR                  S5      5       Hè  nUR                  5       (       d  M  UR	                  U5      nUR                  S   S:X  a'  [        R                  [        UR                  SS 6 -  nO[        U 5      U-  nUR                  R!                  S	S	S
9  UR#                  5       (       a  [$        R'                  SU5        Mº  [(        R*                  " [-        U5      [-        U5      5        US-  nMê     [(        R.                  " US	S9  [1        U 5        [$        R3                  SXU5        U$ ! [
         a    [        S5      ef = f)uE   Devuelve un lote a su ruta exacta; lo que ya exista allÃ­ no se pisa.r@   úPath traversal detectedz!Entrada de papelera inexistente: r   rÊ   rÀ   rj   NTr°   z)Papelera: %s ya existe, no se sobrescriberÌ   z/Colegio %s: restaurados %d ficheros del lote %s)ru   Úlstripr&   rw   rk   rl   rA   rØ   rÏ   r_   rn   r   r   r   r#   r~   r³   rG   r`   ra   r»   r¼   rZ   rÐ   rŒ   rÁ   )r    rù   rö   rµ   Úrestoredrd   ro   r½   s           r   Úrestore_trash_entryrþ   S  s}  € äˆx�‰˜sÓ#Ô$Ü�yÓ!€EØÑ×&Ñ&Ó(€Eð4Ø×Ñ˜%Ÿ-™-›/Ô*ð �<‰<�>‰>ÜÐ<¸X¸JÐGÓHÐHØ€HÜ�%—+‘+˜cÓ"Ö#ˆØ�y‰y�{‰{ÙØ�m‰m˜EÓ"ˆØ�9‰9�Q‰<˜9Ó$Ü×$Ñ$¤t¨S¯Y©Y°q°r¨]Ð';Ñ;‰Dä˜yÓ)¨CÑ/ˆDØ�‰×Ñ $°ÐÑ6Ø�;‰;�=‰=Ü�N‰NÐFÈÔMÙÜ�Š”C˜“FœC ›IÔ&Ø�A‰Šñ $ô ‡M‚M�% tÒ,Ü˜iÔ(Ü
‡K�KÐAÀ9ÐX`ÔaØ€Oøô- ó 4ÜÐ2Ó3Ð3ð4ús   ¹F< Æ<GÚretention_daysc                 óf  • Uc  [         R                  OUn[        U 5      nUR                  5       (       d  gSnUR	                  5        Hd  nUR                  5       (       d  M  [        U5      U:¼  d  M+  U[        S UR                  S5       5       5      -  n[        R                  " USS9  Mf     U$ )uc   Borra DEFINITIVAMENTE los lotes mÃ¡s viejos que la retenciÃ³n (nunca mÃ¡s que la RGPD del colegio).r   c              3   óR   #   • U  H  oR                  5       (       d  M  S v •  M     g7frÅ   rÆ   rÇ   s     r   rE   Úpurge_trash.<locals>.<genexpr>|  s   é € ÐEÒ%5 ¿¹¿Ÿ!™!Ò%5ùrÉ   rÊ   TrÌ   )
r   rõ   r&   rA   rI   rå   rÎ   rÏ   r»   rÐ   )r    rÿ   Údaysrö   Úpurgedrµ   s         r   Úpurge_trashr  s  s‹   € à*8Ñ*@Œ6×&Ò&Àn€DÜ�yÓ!€EØ�<‰<�>‰>ØØ€FØ—‘–ˆØ�<‰<�>‹>œo¨eÓ4¸Õ<Ø”cÑE U§[¡[°Ô%5ÓEÓEÑEˆFÜ�MŠM˜%¨tÔ4ñ !ð €Mr   Ú	date_fromÚdate_toÚ	time_fromÚtime_toÚphotographerÚlimitztuple[List[dict], int]c                 ó¶  • [        U 5      nUR                  5       (       d  / S4$ U(       d5  U(       d.  [        [        R                  " 5       5      R	                  S5      =p/ n[        U5       GHµ  n	U(       a  U	R                  U:w  a  M  U	R                  5        GHƒ  n
U
R                  5       (       a   U
R                  R                  S5      (       a  M;  U
R                  5        GH3  nUR                  5       (       a:  UR                  R                  S5      (       d  [        UR                  5      (       d  MU   [        UR                  5       R                  5      nUR	                  S5      UR	                  S5      píU(       a  XÑ:  d  U(       a  XÒ:”  a  M´  U(       a  Xã:  d  U(       a  Xä:”  a  MÎ  UR                  U	R                  U
R                  R!                  5       UR                  [#        UR                  5      UR	                  S5      S.5        GM6     GM†     GM¸     UR%                  S SS	9  US
U ['        U5      4$ ! [         a     GMq  f = f)u±   Fotos del colegio por fecha/hora (en la hora del EVENTO). Sin fechas: hoy, para no devolver
miles de filas. Devuelve (como mucho `limit` mÃ¡s recientes, total de coincidencias).r   z%Y-%m-%dr@   z%H:%Mr”   )r
  r‘   r-   r®   Úcaptured_atc                 ó   • U S   $ )Nr  r   r[   s    r   r\   Ú%list_photos_by_date.<locals>.<lambda>§  s	   € ˜1˜]Ò+r   Tr˜   N)r#   rG   r   rš   r¢   rJ   r'   rI   rA   r2   r_   r,   rž   rŸ   rM   rS   r9   r3   Úsortrm   )r    r  r  r  r	  r
  r  r<   rT   rU   rP   rd   ÚdtÚdayÚhms                  r   Úlist_photos_by_dater  ƒ  s·  € ô �yÓ!€DØ�;‰;�=‰=Ø�1ˆuˆÞžWÜ'¬¯	ª	«Ó4×=Ñ=¸jÓIÐIˆ	Ø€CÜ ×%ˆÞ˜BŸG™G |Ó3ÙØ—j‘j—lˆFØ—=‘=—?‘? f§k¡k×&<Ñ&<¸S×&AÑ&AÙØ—^‘^×%�Ø—y‘y—{‘{ a§f¡f×&7Ñ&7¸×&<Ñ&<ÄHÈQÏVÉV×DTÑDTÙðÜ" 1§6¡6£8×#4Ñ#4Ó5�Bð Ÿ+™+ jÓ1°2·;±;¸wÓ3G�RÞ #£/¶wÀ3Ã=ÙÞ "£.¶gÀ"Ã,ÙØ—
‘
Ø$&§G¡G¸¿¹×8IÑ8IÓ8KÐYZ×Y_ÑY_Ü& q§v¡vÓ.¸r¿{¹{ÐK^Ó?_ñ÷ ô &ô #ñ &ð, ‡H�HÑ+°T€HÑ:Øˆv�ˆ;œ˜C›Ð Ð øô ó Ûðús   Ä<#I	É	
I	ÉI	Útarget_codeÚtarget_photographerc           
      óJ  • U=(       d    UnXX5U4 H  n[        U5        M     [        U 5      R                  5       nXq-  U-  U-  R                  5       n UR                  U5        UR                  5       (       d  [        SU SU SU 35      eXu-  R                  5       n	 U	R                  U5        U	R                  5       (       d  [	        SU 35      e[        X”5      =(       d"    X”R                  5       R                  SS5      -  n
U
R                  SSS9  X£-  nUR                  5       (       aH  UR                  UR                   S	[        [         R                   " 5       5       UR"                   35      n[%        U5        [&        R(                  " [+        U5      [+        U5      5        [-        U 5        [.        R1                  S
XX#XZR2                  UR2                  5        U
R2                  $ ! [         a    [	        S5      ef = f! [         a    [	        S5      ef = f)u"  Mueve una foto a la carpeta de otro cÃ³digo (el QR fotografiado que no se detectÃ³ acabÃ³ bajo el
cÃ³digo anterior). `target_code` puede venir escrito a mano: se resuelve ignorando guiones y, si no
existe, se crea. ValueError (parÃ¡metro invÃ¡lido) / FileNotFoundError (origen inexistente).rû   zPhoto not found: rs   zUnknown target photographer: r6   r7   Tr°   r?   u1   Colegio %s: foto reasignada %s/%s/%s â†’ %s/%s/%s)ru   r#   rw   rk   rl   r_   ÚFileNotFoundErrorrA   rQ   r9   r:   r³   rG   r¹   r   rº   rš   r)   r‡   r»   r¼   rZ   rŒ   r`   rÁ   r'   )r    r
  r4   r-   r  r  rq   r<   r{   Údest_pdrP   r½   s               r   Ú
move_photor  «  sä  € ð
 .×=°ÐØ XÀKÓPˆÜ�4Öñ Qä�yÓ!×)Ñ)Ó+€DØÑ Ñ%¨Ñ0×
9Ñ
9Ó
;€Cð4Ø�‰˜Ôð �;‰;�=‰=ÜÐ"3°L°>ÀÀ4À&ÈÈ(ÈÐ TÓUÐUØÑ)×2Ñ2Ó4€Gð4Ø×Ñ˜DÔ!ð �>‰>×ÑÜÐ8Ð9LÐ8MÐNÓOÐOÜ˜wÓ4×h¸×CTÑCTÓCV×C^ÑC^Ð_bÐdfÓCgÑ9g€FØ
‡L�L˜¨€LÑ-ØÑ€DØ‡{�{‡}�}Ø�~‰~ §¡ ¨1¬S´·²³Ó-=Ð,>¸t¿{¹{¸mÐLÓMˆÜ�SÔÜ
‡K‚K”�C“œ#˜d›)Ô$Ü˜iÔ(Ü
‡K�KÐCÀYÐ^bØ#§[¡[°$·)±)ô=à�;‰;Ðøô+ ó 4ÜÐ2Ó3Ð3ð4ûô ó 4ÜÐ2Ó3Ð3ð4ús   ÁG3 Â"H Ç3H	ÈH"r   )NNNNNi,  )FÚ__doc__ÚloggingÚrer»   rš   r   Úpathlibr   Útypingr   r   r   Úcorer   Úmodels.modelsr	   Ú	getLoggerÚ__name__r`   Úzoneinfor
   ÚEVENT_TIMEZONEr   Ú__annotations__Ú	Exceptionra   Úfloatr   ÚIMAGE_EXTENSIONSr*   r+   r%   rB   r¤   r   Údictr   rZ   r#   r&   Úboolr,   r3   r;   rJ   rQ   ÚtuplerW   rf   rp   ru   rx   rº   rz   r€   r‡   rŒ   r­   r·   r¾   rÂ   rÓ   rÙ   rã   rå   rø   rþ   r  r  r  rñ   s   0r   Ú<module>r-     sT  ðòó" Û 	Û Û Ý Ý ß 'Ñ 'å Ý $à	×	Ò	˜8Ó	$€ðÝ!Ù#+¨F×,AÑ,AÓ#B€IÐ ÓBð7�Uð 7˜xô 7ð
 "(×!8Ò!8Ó9Ò!8˜A�g‰gŽiÑ!8Ñ9€
Ø€ð ˜k¨8°YÀÈyÐY€à€
Ø€�Ó ð�Tô ð)˜3ð ) 4ô )ð9˜#ð 9 $ô 9ð
3�3ð 3˜4ô 3ð>˜ð > ô >ð
:�Cð :˜Cô :ð
h˜Dð h T¨$¡Zô hð¨ð °Cð ¸HÀT¹Nô ð
˜3ð 
 cð 
¨d°5¸¸d¸Ñ3CÑ.Dô 
ð	9 ð 	9¨Cð 	9°D¸±Jô 	9ð7˜$ð 7 3ô 7ð>�Sð >˜Tô >ð
˜#ð  Sð °Cð ¸HÀT¹Nô ð3 3ð 3¨cð 3°cô 3ðB�Tð B 3ð B¨4ô Bð˜$ð  4ô ñ$ ¨°#©ð  À$õ  ð# ð #¨¨ZÑ(8ô #ðP ð ¨3ð °4ô ð%˜ð % Tð %°ð %¸ô %ð˜Cð  sð °cð ¸dô ð$ Cð ¨sð °sô ð$ ð ¨ô ð K�sð K˜u S¨# X™ô Kð>˜4ð > Cô >ð@˜#ð @ $ t¡*ô @ð& 3ð °#ð ¸#ô ñ@˜3ð °¸±ð Èõ ð$ ?CØ>BØ58ñ	%!Øð%!à˜‰}ð%!à.6°s©mð%!ð ˜‰}ð%!ð /7°s©mð%!ð ˜3‘-ð	%!ð 03ð	%!ð
 õ%!ðR 59ñ!˜#ð !¨Sð !¸ð !Àsð !ÐY\ð !Ø$,¨S¡Mð!Ø=@ö!øðS ó Ø
‡N�NÐcÐek×ezÑezÔ{ØƒIðüò :s   Á	H0 Á=IÈ0$IÉI