Ë
    yÌjéJ  ã                   ót  — U d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZ ddlmZ  ej                   e«      Z	 ddlmZ  eej*                  «      Zd	ed
<   dedefd„Zej8                  D � ch c]  } | j;                  «       ’Œ c} ZdZddddedhZ dZ!i Z"e#ed<   defd„Z$de%defd„Z&de%defd„Z'de%de(fd„Z)de%de%fd„Z*de%de%fd „Z+d!ede
e   fd"„Z,d#ede%dee   fd$„Z-de%de%de
e.e%ef      fd%„Z/de%de%de
e   fd&„Z0d'ede%fd(„Z1d)e%ddfd*„Z2de%de%de%dee   fd+„Z3de%de%de4fd,„Z5d-ed.e%defd/„Z6d-eddfd0„Z7dMdee%   ddfd1„Z8de%de
e   fd2„Z9de%d3e%defd4„Z:d-ed5ed6eddfd7„Z;de%de%de%de(fd8„Z<de%de%de4fd9„Z=de%de4fd:„Z>de%de.e%e%f   fd;„Z?d5ede4fd<„Z@de%de
e	   fd=„ZAde%d>e%de4fd?„ZBdMde%d@ee4   de4fdA„ZC	 	 	 dNde%dBee%   dCee%   dDee%   dEee%   dFee%   dGe4ddHfdI„ZD	 dMde%dFe%de%de%dJe%dKee%   de%fdL„ZEy# e$ r" ej3                  dej*                  «       dZY �ŒËw xY wc c} w )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                 ó8   — t        j                  | t        ¬«      S )uX   Instante absoluto â†’ hora del EVENTO (no la del servidor, que en un VPS suele ser UTC).)Útz)r   Úfromtimestampr   )r   s    ú1/var/www/photos/backend/services/photo_service.pyÚ	_event_dtr   '   s   € ä×!Ñ! %¬IÔ6Ð6ó    z.trashÚqr_cardsÚ	_qr_cardsÚthumbsz.thumbsÚ_errorsé<   Ú_families_cachec                  ó"   — t         j                  S ©N©r   Ú
PHOTOS_DIR© r   r   Úphotos_rootr   6   s   € Ü×ÑÐr   Ú	school_idc                 ó(   — t         j                  | z  S r   r   ©r    s    r   Úschool_rootr#   :   s   € Ü×Ñ˜yÑ(Ð(r   c                 ó6   — t         j                  t        z  | z  S )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                 óT   — t        | «      j                  j                  «       t        v S r   )r   ÚsuffixÚlowerÚ
IMAGE_EXTS)r'   s    r   Úis_imager,   C   s    € Ü�‹:×Ñ×"Ñ"Ó$¬
Ð2Ð2r   Úfilenamec                 ó,   — | j                  d«      rdS d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   — | j                  «       j                  dd«      j                  dd«      S )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                 óf   — | j                  «       sg S t        d„ | j                  «       D «       «      S )Nc              3   óš   K  — | ]C  }|j                  «       r1|j                  j                  d «      s|j                  t        vr|–— ŒE y­w))Ú_ú.N)Úis_dirr'   r2   Ú_RESERVED_DIRS)Ú.0Úps     r   ú	<genexpr>z$photographer_dirs.<locals>.<genexpr>T   s?   è ø€ ò h˜Ø—X‘X”Z¨¯©×(9Ñ(9¸*Ô(EÈ!Ï&É&ÔXfÑJfô ñ hùs   ‚A	A)ÚexistsÚsortedÚiterdir)r<   s    r   Úphotographer_dirsrI   Q   s3   € Ø�;‰;Œ=Øˆ	Üñ h˜TŸ\™\›^ô hó hð hr   Úphotographer_dirc                 ób  — | |j                  «       j                  dd«      z  }|j                  «       r|S t        |«      }	 | j	                  «       D ]K  }|j                  «       sŒ|j
                  j                  d«      rŒ0t        |j
                  «      |k(  sŒI|c S  	 y# t        $ r Y yw xY w)u\   Carpeta del cÃ³digo ignorando guiones/espacios (la que escribiÃ³ el vendedor vs la impresa).r6   r7   r@   N)r9   r:   rA   r;   rH   r'   r2   ÚOSError)rJ   r4   ÚdirectÚtargetÚfolders        r   Úresolve_qr_folderrP   X   s¢   € à §
¡
£× 4Ñ 4°S¸"Ó =Ñ=€FØ‡}�}„ØˆÜ�t‹_€FðØ&×.Ñ.Ó0ò 	ˆFØ�}‰}� v§{¡{×'=Ñ'=¸cÕ'BÄyÐQW×Q\ÑQ\ÓG]ÐagÓGgØ’ñ	ð
 øô ò ØØðús*   Á#B" Á&B" ÂB" ÂB" ÂB" Â"	B.Â-B.c                 óÈ  — g }t        t        | «      «      D ].  }t        ||«      }|€Œ|j                  |j                  |f«       Œ0 t
        j                  |j                  «       j                  dd«      z  }|j                  «       rY|j                  j                  «       |j                  «       k(  r.|j                  j                  d«      s|j                  d|f«       |S )ui   [(fotÃ³grafo, carpeta)] de una familia: una por fotÃ³grafo que le sacÃ³ fotos, mÃ¡s la antigua si existe.r6   r7   r@   )rI   r#   rP   Úappendr'   r   r   r9   r:   rA   r2   )r    r4   ÚoutÚpdrO   Úlegacys         r   Úfamily_dirsrV   g   s¶   € à"$€CÜ¤¨IÓ 6Ó7ò *ˆÜ" 2 tÓ,ˆØÑØ�J‰J˜Ÿ™ Ð(Õ)ð*ô ×Ñ §¡£×!5Ñ!5°c¸2Ó!>Ñ>€FØ‡}�}„˜6Ÿ;™;×,Ñ,Ó.°$·*±*³,Ò>ÀvÇ{Á{×G]ÑG]Ð^aÔGbØ�
‰
�B˜�<Ô Ø€Jr   c                 ór  — g }t        | |«      D ]g  \  }}	 ||j                  «       D �cg c]D  }|j                  «       r2|j                  j	                  d«      st        |j                  «      r|‘ŒF c}z  }Œi t        |d„ ¬«      S c c}w # t        $ r!}t        j                  d||«       Y d}~Œ¢d}~ww xY w)uM   Fotos vendibles de una familia (no entra en subcarpetas: .qr/, .protect/â€¦).r@   zNo se pudo leer %s: %sNc                 ó0   — | j                   t        | «      fS r   )r'   Ústr©rD   s    r   ú<lambda>z#list_family_files.<locals>.<lambda>}   s   € ¨¯©´°A³Ð'7€ r   )Úkey)
rV   rH   Úis_filer'   r2   r,   rL   ÚloggerÚwarningrG   )r    r4   ÚfilesÚ_phrO   ÚfÚexcs          r   Úlist_family_filesrd   t   sµ   € à€EÜ" 9¨dÓ3ò B‰ˆˆVð	BØ §¡Ó!1ö Z˜AØŸ™œ¨Q¯V©V×->Ñ->¸sÔ-CÌÐQR×QWÑQWÔHXò ò Zñ Z‰EðBô �%Ñ7Ô8Ð8ùò	Zøäò 	BÜ�N‰NÐ3°V¸S×AÑAûð	Bús)   –B©A	BÁ2BÂBÂ	B6ÂB1Â1B6Úpathc                 ó²   — 	 | j                  t        j                  «      }t	        |j
                  «      dk\  r|j
                  d   S dS # t        $ r Y yw xY w)u:   Nombre del fotÃ³grafo segÃºn la ruta (""= layout antiguo).r7   é   é   )Úrelative_tor   r   Ú
ValueErrorÚlenÚparts)re   Úrels     r   Úphotographer_ofrn   €   sU   € ðØ×Ñœv×0Ñ0Ó1ˆô ˜sŸy™y›>¨QÒ.ˆ3�9‰9�Q‰<Ð6°BÐ6øô ò Ùðús   ‚A
 Á
	AÁAÚpartc                 ó^   — | rd| v sd| v sd| v s| j                  d«      rt        d| ›�«      ‚y )Nz..ú/ú\r@   zInvalid path component: )r2   rj   )ro   s    r   Ú
_safe_partrs   ‰   s=   € Ù�4˜4‘< 3¨$¡;°$¸$±,À$Ç/Á/ÐRUÔBVÜÐ3°D°8Ð<Ó=Ð=ð CWr   c                 óF  — |r4t        |«      j                  |k7  s|j                  d«      st        |«      syt	        | |«      D ]L  \  }}||z  }	 |j                  «       j                  |j                  «       «       |j                  «       sŒJ|c S  y# t        $ r Y Œ[w xY w)zbRuta absoluta del original, o None si el nombre es sospechoso (../, absoluto, oculto) o no existe.r@   N)	r   r'   r2   r,   rV   Úresolveri   rj   r]   )r    r4   r-   ra   rO   re   s         r   Ú
find_photorv   Ž   sœ   € á”t˜H“~×*Ñ*¨hÒ6¸(×:MÑ:MÈcÔ:RÔZbÐckÔZlØÜ" 9¨dÓ3ò ‰ˆˆVØ˜Ñ ˆð	Ø�L‰L‹N×&Ñ& v§~¡~Ó'7Ô8ð �<‰<�>ØŠKðð øô	 ò 	Ùð	ús   Á-BÂ	B ÂB c                 ó,   — t        t        | |«      «      S r   )rk   rd   )r    r4   s     r   Úcount_family_photosrx   �   s   € ÜÔ  ¨DÓ1Ó2Ð2r   Úsrcr)   c                 óæ   — 	 | j                  t        j                  «      }t        j                  |j                  z  | j                  › |› �z  S # t        $ r t	        | j
                  «      }Y ŒNw xY w)uL   `photos/a/b/c/x.jpg` â†’ `thumbs/a/b/c/x{suffix}` (suffix incluye el punto).)	ri   r   r   rj   r   r'   Ú
THUMBS_DIRÚparentÚstem)ry   r)   rm   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 ÁA0Á/A0c                 ód  — t        | d«      j                  }	 |j                  | j                  › d�«      D ]  }|j	                  d¬«       Œ 	 | j                  dz  }	 |j                  | j                  › d�«      D ]  }|j	                  d¬«       Œ y# t
        $ r Y ŒQw xY w# t
        $ r Y yw xY w)uC   Borra miniaturas, vistas previas y cachÃ© protegida de un original.r7   z.*T)Ú
missing_okz.protectz_heads_*N)r~   r|   Úglobr}   ÚunlinkrL   )ry   Údrb   Úprotects       r   Údrop_derivativesr…   ¬   s¶   € ä�C˜Ó×#Ñ#€AðØ—‘˜3Ÿ8™8˜* B˜Ó(ò 	&ˆAØ�H‰H ˆHÕ%ñ	&ð �j‰j˜:Ñ%€GðØ—‘ §¡ 
¨(Ð3Ó4ò 	&ˆAØ�H‰H ˆHÕ%ñ	&øô	 ò Ùðûô ò Ùðús#   ˜5B Á5B# Â	B ÂB Â#	B/Â.B/c                 ód   — | rt         j                  d| › �d «       y t         j                  «        y )NÚ	families_)r   ÚpopÚclearr"   s    r   Úinvalidate_families_cacherŠ   ¾   s(   € ÙÜ×Ñ˜i¨	 {Ð3°TÕ:ä×ÑÕr   c           
      óÆ  — t        j                  «       }d| › �}t        j                  |«      }|r||d   k  r|d   S t	        | «      }i }i }t        |«      D �]…  }t        |j                  «       «      D �]e  }|j                  «       r|j                  j                  d«      rŒ0|j                  j                  «       }	d\  }
}|j                  «       D ]o  }|j                  «       sŒ|j                  j                  d«      rŒ0t        |j                  «      sŒF|
dz  }
	 t        ||j                  «       j                   «      }Œq |
dk(  rŒ×|j%                  |	t'        |	dg ¬«      «      }|xj(                  |
z  c_        |j                  |j*                  vr%|j*                  j-                  |j                  «       t        |j                  |	d	«      |«      ||	<   �Œh �Œˆ |j/                  «       D ]-  \  }	}|dkD  sŒt1        |«      j3                  d
«      ||	   _        Œ/ t        |j7                  «       d„ d¬«      }||t8        z   dœt        |<   |S # t"        $ r Y �Œ‹w xY w)Nr‡   Ú
expires_atÚdatar@   )r   ç        rh   r   )Úqr_codeÚphoto_countÚphotographersrŽ   ú%Y-%m-%dT%H:%M:%Sc                 ó:   — | j                   xs d| j                  fS )Nr7   )Úlast_photo_atr�   )rb   s    r   r[   z"get_all_families.<locals>.<lambda>æ   s   € °a·o±oÒ6KÈÈQÏYÉYÐ5W€ r   T©r\   Úreverse)r�   rŒ   )ÚtimeÚ	monotonicr   Úgetr#   rI   rG   rH   rA   r'   r2   r9   r]   r,   ÚmaxÚstatÚst_mtimerL   Ú
setdefaultr	   r�   r‘   rR   Úitemsr   Ústrftimer”   ÚvaluesÚ
_CACHE_TTL)r    Únowr\   Úcachedr<   ÚfamiliesÚ
last_mtimerT   rO   r4   ÚcountÚnewestrb   Úfamr   Úresults                   r   Úget_all_familiesrª   Å   s)  € Ü
�.‰.Ó
€CØ�i�[Ð
!€CÜ× Ñ  Ó%€FÙ�#˜˜|Ñ,Ò,Ø�f‰~Ðä�yÓ!€DØ&(€HØ#%€JÜ Ó%ó FˆÜ˜RŸZ™Z›\Ó*ó 	FˆFØ—=‘=”? f§k¡k×&<Ñ&<¸SÔ&AØØ—;‘;×$Ñ$Ó&ˆDØ"‰MˆE�6Ø—^‘^Ó%ò �Ø—9‘9•; q§v¡v×'8Ñ'8¸Õ'=Ä(È1Ï6É6ÕBRØ˜Q‘J�EðÜ!$ V¨Q¯V©V«X×->Ñ->Ó!?™ð	ð ˜ŠzØØ×%Ñ% d¬J¸tÐQRÐbdÔ,eÓfˆCØ�OŠO˜uÑ$�OØ�w‰w˜c×/Ñ/Ñ/Ø×!Ñ!×(Ñ(¨¯©Ô1Ü" :§>¡>°$¸Ó#<¸fÓEˆJ�tÓò%	FðFð( "×'Ñ'Ó)ò Z‰ˆˆeØ�1‹9Ü+4°UÓ+;×+DÑ+DÐEXÓ+YˆH�T‰NÕ(ðZô �H—O‘OÓ%Ñ+WÐaeÔf€FØ$*¸#Ä
Ñ:JÑK„O�CÑØ€Møô #ò Úðús   Ä $IÉ	I 	ÉI 	Úkindc                 óø   — t        j                  d«      }t        | «      |› d|› �z  }d}|j                  «       r,|dz  }t        | «      |› d|› d|› �z  }|j                  «       rŒ,|j	                  dd¬«       |S )Nz%Y%m%d-%H%M%Sr8   rh   T©ÚparentsÚexist_ok)r—   rŸ   r&   rF   Ú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²   rm   c                 óL  — ||z  }|j                   j                  dd¬«       |j                  «       rJ|j                  |j                  › dt        t        j                  «       dz  «      › |j                  › �«      }t        j                  t        | «      t        |«      «       y )NTr­   r?   iè  )r|   r°   rF   Ú	with_namer}   Úintr—   r)   ÚshutilÚmoverY   )ry   r²   rm   Údests       r   Ú_move_to_trashr»   ø   sw   € Ø�3‰;€DØ‡K�K×Ñ˜d¨TÐÔ2Ø‡{�{„}Ø�~‰~ §¡ ¨1¬S´·±³¸tÑ1CÓ-DÐ,EÀdÇkÁkÀ]ÐSÓTˆÜ
‡K�K”�C“œ#˜d›)Õ$r   c                 ó¦  — t        |«       t        | ||«      }|€y	 |j                  t        | «      «      }t        | dt        |«      › �«      }t        |«       t        |||«       t        | «       t        j                  d| ||j                  «       y# t        $ r2 t        d«      |j                  j                  z  |j                  z  }Y Œ˜w xY w)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)rs   rv   ri   r#   rj   r   r|   r'   r´   r;   r…   r»   rŠ   r^   Úinfo)r    r4   r-   re   rm   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 Â8CÃCc                 óÚ  — d}d}t        | |«      D ]²  \  }}t        d„ |j                  d«      D «       «      }|€t        | dt	        |«      › �«      }|rt        |«      |j                  z  nt        d«      |j                  z  }t        j                  t        |dz  d«      j                  d	¬
«       t        |||«       ||z  }Œ´ |rt        | «       t        j                  d| ||«       |S )uR   Todas las carpetas de la familia (de todos los fotÃ³grafos) a UN lote restaurable.Nr   c              3   óB   K  — | ]  }|j                  «       sŒd –— Œ y­w©rh   N©r]   ©rC   rb   s     r   rE   z'delete_family_photos.<locals>.<genexpr>  s   è ø€ Ò@˜!°A·I±IµK”AÑ@ùó   ‚˜Ú*zfamily-r½   Úxr7   T©Úignore_errorsz-Colegio %s: %d ficheros a la papelera para %s)rV   ÚsumÚrglobr´   r;   r   r'   r¸   Úrmtreer~   r|   r»   rŠ   r^   r¾   )r    r4   r²   ÚdeletedÚphrO   r`   rm   s           r   Údelete_family_photosrÏ     sÚ   € à €EØ€GÜ! )¨TÓ2ò ‰
ˆˆFÜÑ@˜vŸ|™|¨CÓ0Ô@Ó@ˆØˆ=Ü$ Y°'¼)ÀD»/Ð9JÐ0KÓLˆEÙ(*Œd�2‹h˜Ÿ™Ò$´°Y³À&Ç+Á+Ñ0MˆÜ�‰”k &¨3¡,°Ó3×:Ñ:È$ÕOÜ�v˜u cÔ*Ø�5Ñ‰ðñ Ü! )Ô,Ü
‡K�KÐ?ÀÈGÐUYÔZØ€Nr   c           	      óþ  — t        | d«      }d}t        t        | «      «      D ]‚  }t        |j	                  «       «      D ]d  }|j                  «       sŒ|t        d„ |j                  d«      D «       «      z  }t        ||t        |j                  «      |j                  z  «       Œf Œ„ t        j                  t        j                  | z  d¬«       t        | «       t         j#                  d| ||j                  «       |S )uJ   VacÃ­a el colegio moviendo TODAS las familias a la papelera (recuperable).Úallr   c              3   óB   K  — | ]  }|j                  «       sŒd –— Œ y­wrÂ   rÃ   rÄ   s     r   rE   z$delete_all_photos.<locals>.<genexpr>,  s   è ø€ ÒG ¸1¿9¹9½;œ1ÑGùrÅ   rÆ   TrÈ   u<   Colegio %s: BORRADO TOTAL â€” %d ficheros a la papelera (%s))r´   rI   r#   ÚlistrH   rA   rÊ   rË   r»   r   r'   r¸   rÌ   r   r{   rŠ   r^   r_   )r    r²   rÍ   rT   rO   s        r   Údelete_all_photosrÔ   $  sÕ   € ä˜Y¨Ó.€EØ€GÜ¤¨IÓ 6Ó7ò GˆÜ˜2Ÿ:™:›<Ó(ò 	GˆFØ—=‘=”?ØØ”sÑG f§l¡l°3Ó&7ÔGÓGÑGˆGÜ˜6 5¬$¨r¯w©w«-¸&¿+¹+Ñ*EÕFñ		GðGô ‡M�M”&×#Ñ# iÑ/¸tÕDÜ˜iÔ(Ü
‡N�NÐQÐS\Ð^eÐgl×gqÑgqÔrØ€Nr   c                 óÔ   — | j                  dd«      }t        |«      dk  st        |d   «      dk7  rd| fS |d   |d   }}|d d › d|dd	 › d|d	d  › d
|d d › d|dd › d|dd	 › �|d   fS )Nr8   é   é   r   é   r7   rh   rg   é   ÚTú:)Úsplitrk   )r'   rl   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€AØ��ˆ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                 óx   — t        t        j                  «       | j                  «       j                  z
  dz  «      S )Ni€Q )r·   r—   r›   rœ   )r²   s    r   Ú_batch_age_daysrà   <  s)   € Ü”—	‘	“˜eŸj™j›l×3Ñ3Ñ3°uÑ<Ó=Ð=r   c                 ó²  — t        | «      }|j                  «       sg S g }|j                  «       D �]  }|j                  «       sŒ|j                  d«      D �cg c]  }|j	                  «       sŒ|‘Œ }}t        |j                  «      \  }}|j                  |j                  ||t        |«      t        t        d„ |D «       «      dz  d«      t        |j                  d«      D �ch c]  }|j                  «       sŒ|j                  ’Œ! c}«      d d t        dt        j                  t!        |«      z
  «      dœ«       �Œ t        |d	„ d
¬«      S c c}w c c}w )NrÆ   c              3   óP   K  — | ]  }|j                  «       j                  –— Œ  y ­wr   )r›   Úst_sizerÄ   s     r   rE   zlist_trash.<locals>.<genexpr>L  s   è ø€ Ò A°a §¡£×!1Õ!1Ñ Aùs   ‚$&i   rh   z*/*é   r   )Úidr«   Ú
deleted_atÚ
file_countÚsize_mbr¤   Úexpires_in_daysc                 ó   — | d   S )Nrå   r   ©Úes    r   r[   zlist_trash.<locals>.<lambda>P  s
   € ¨¨4©€ r   Tr•   )r&   rA   rH   rË   r]   rÞ   r'   rR   rk   ÚroundrÊ   rG   r�   rš   r   ÚTRASH_RETENTION_DAYSrà   )	r    ÚtrashÚentriesr²   rb   r`   ræ   r«   rƒ   s	            r   Ú
list_trashrñ   @  s  € Ü�yÓ!€EØ�<‰<Œ>Øˆ	Ø€GØ—‘“ó 
ˆØ�|‰|Œ~ØØ!ŸK™K¨Ó,Ö<�q°·	±	µ’Ð<ˆÐ<Ü'¨¯
©
Ó3Ñˆ
�DØ�‰Ø—*‘* d¸*ÔTWÐX]ÓT^ÜœSÑ A¸5Ô AÓAÀGÑKÈQÓOÜ°·
±
¸5Ó0AÖP¨1ÀQÇXÁXÅZ §£ÒPÓQÐRUÐSUÐVÜ" 1¤f×&AÑ&AÄOÐTYÓDZÑ&ZÓ[ñ	
ö 	ð
ô �'Ñ0¸$Ô?Ð?ùò =ùò
  Qs   ÁEÁ.EÃ$EÃ:EÚentry_idc                 óŒ  — t        |j                  d«      «       t        | «      }||z  j                  «       }	 |j	                  |j                  «       «       |j                  «       st        d|› �«      ‚d}t        |j                  d«      «      D ]Ü  }|j                  «       sŒ|j	                  |«      }|j                  d   dk(  r't        j                  t        |j                  dd Ž z  }nt        | «      |z  }|j                  j!                  d	d	¬
«       |j#                  «       rt$        j'                  d|«       Œ°t)        j*                  t-        |«      t-        |«      «       |dz  }ŒÞ t)        j.                  |d	¬«       t1        | «       t$        j3                  d| ||«       |S # t
        $ r t        d«      ‚w xY w)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½   rh   NTr­   z)Papelera: %s ya existe, no se sobrescriberÈ   z/Colegio %s: restaurados %d ficheros del lote %s)rs   Úlstripr&   ru   ri   rj   rA   rÓ   rË   r]   rl   r   r   r   r#   r|   r°   rF   r^   r_   r¸   r¹   rY   rÌ   rŠ   r¾   )r    rò   rï   r²   Úrestoredrb   rm   rº   s           r   Úrestore_trash_entryr÷   S  s€  € äˆx�‰˜sÓ#Ô$Ü�yÓ!€EØ�XÑ×&Ñ&Ó(€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ÈhÐX`ÔaØ€Oøô- ò 4ÜÐ2Ó3Ð3ð4ús   ºF. Æ.GÚretention_daysc                 óJ  — |€t         j                  n|}t        | «      }|j                  «       syd}|j	                  «       D ]]  }|j                  «       sŒt        |«      |k\  sŒ#|t        d„ |j                  d«      D «       «      z  }t        j                  |d¬«       Œ_ |S )uc   Borra DEFINITIVAMENTE los lotes mÃ¡s viejos que la retenciÃ³n (nunca mÃ¡s que la RGPD del colegio).r   c              3   óB   K  — | ]  }|j                  «       sŒd –— Œ y­wrÂ   rÃ   rÄ   s     r   rE   zpurge_trash.<locals>.<genexpr>|  s   è ø€ ÒE ¸¿¹½œ!ÑEùrÅ   rÆ   TrÈ   )
r   rî   r&   rA   rH   rà   rÊ   rË   r¸   rÌ   )r    rø   Údaysrï   Úpurgedr²   s         r   Úpurge_trashrý   s  sŒ   € à*8Ð*@Œ6×&Ò&Àn€DÜ�yÓ!€EØ�<‰<Œ>ØØ€FØ—‘“ò 5ˆØ�<‰<�>œo¨eÓ4¸Ó<Ø”cÑE U§[¡[°Ó%5ÔEÓEÑEˆFÜ�M‰M˜%¨tÖ4ð5ð €Mr   Ú	date_fromÚdate_toÚ	time_fromÚtime_toÚphotographerÚlimitztuple[List[dict], int]c                 ó   — t        | «      }|j                  «       sg dfS |s0|s.t        t        j                  «       «      j	                  d«      x}}g }t        |«      D �]y  }	|r|	j                  |k7  rŒ|	j                  «       D �]P  }
|
j                  «       r|
j                  j                  d«      rŒ0|
j                  «       D �]  }|j                  «       r0|j                  j                  d«      st        |j                  «      sŒE	 t        |j                  «       j                  «      }|j	                  d«      |j	                  d«      }}|r||k  s|r||kD  rŒš|r||k  s|r||kD  rŒ©|j                  |	j                  |
j                  j!                  «       |j                  t#        |j                  «      |j	                  d«      dœ«       �Œ �ŒS �Œ| |j%                  d„ d¬	«       |d
| t'        |«      fS # t        $ r Y �ŒGw xY w)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                 ó   — | d   S )Nr  r   rZ   s    r   r[   z%list_photos_by_date.<locals>.<lambda>§  s   € ˜1˜]Ñ+€ r   Tr•   N)r#   rF   r   r—   rŸ   rI   r'   rH   rA   r2   r]   r,   r›   rœ   rL   rR   r9   r3   Úsortrk   )r    rþ   rÿ   r   r  r  r  r<   rS   rT   rO   rb   ÚdtÚdayÚhms                  r   Úlist_photos_by_dater  ƒ  sÃ  € ô �yÓ!€DØ�;‰;Œ=Ø�1ˆuˆÙ™WÜ'¬¯	©	«Ó4×=Ñ=¸jÓIÐIˆ	�GØ€CÜ Ó%ó ˆÙ˜BŸG™G |Ò3ØØ—j‘j“ló 	ˆFØ—=‘=”? f§k¡k×&<Ñ&<¸SÔ&AØØ—^‘^Ó%ó �Ø—y‘y”{ a§f¡f×&7Ñ&7¸Ô&<ÄHÈQÏVÉVÔDTØðÜ" 1§6¡6£8×#4Ñ#4Ó5�Bð Ÿ+™+ jÓ1°2·;±;¸wÓ3G�R�Ù #¨	¢/±wÀ3ÈÂ=ØÙ " y¢.±gÀ"ÀwÂ,ØØ—
‘
Ø$&§G¡G¸¿¹×8IÑ8IÓ8KÐYZ×Y_ÑY_Ü& q§v¡vÓ.¸r¿{¹{ÐK^Ó?_ñö òò	ðð, ‡H�HÑ+°T€HÔ:Øˆv�ˆ;œ˜C›Ð Ð øô ò Úðús   Ä#H È 	H	ÈH	Útarget_codeÚtarget_photographerc           
      ó&  — |xs |}|||||fD ]  }t        |«       Œ t        | «      j                  «       }||z  |z  |z  j                  «       }	 |j                  |«       |j                  «       st        d|› d|› d|› �«      ‚||z  j                  «       }		 |	j                  |«       |	j                  «       st	        d|› �«      ‚t        |	|«      xs# |	|j                  «       j                  dd«      z  }
|
j                  dd¬«       |
|z  }|j                  «       rG|j                  |j                  › d	t        t!        j                   «       «      › |j"                  › �«      }t%        |«       t'        j(                  t+        |«      t+        |«      «       t-        | «       t.        j1                  d
| |||||
j2                  |j2                  «       |
j2                  S # t        $ r t	        d«      ‚w xY w# t        $ r t	        d«      ‚w xY w)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: rq   zUnknown target photographer: r6   r7   Tr­   r?   u1   Colegio %s: foto reasignada %s/%s/%s â†’ %s/%s/%s)rs   r#   ru   ri   rj   r]   ÚFileNotFoundErrorrA   rP   r9   r:   r°   rF   r¶   r}   r·   r—   r)   r…   r¸   r¹   rY   rŠ   r^   r¾   r'   )r    r  r4   r-   r  r  ro   r<   ry   Údest_pdrO   rº   s               r   Ú
move_photor  «  sù  € ð
 .Ò=°ÐØ˜t XÐ/BÀKÐPò ˆÜ�4Õðä�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Ô-Ø�HÑ€DØ‡{�{„}Ø�~‰~ §¡ ¨1¬S´·±³Ó-=Ð,>¸t¿{¹{¸mÐLÓMˆÜ�SÔÜ
‡K�K”�C“œ#˜d›)Ô$Ü˜iÔ(Ü
‡K�KÐCÀYÐP\Ð^bÐdlØ# V§[¡[°$·)±)ô=à�;‰;Ðøô+ ò 4ÜÐ2Ó3Ð3ð4ûô ò 4ÜÐ2Ó3Ð3ð4ús   ÁG# ÂG; Ç#G8Ç;Hr   )NNNNNi,  )FÚ__doc__ÚloggingÚrer¸   r—   r   Úpathlibr   Útypingr   r   r   Úcorer   Úmodels.modelsr	   Ú	getLoggerÚ__name__r^   Úzoneinfor
   ÚEVENT_TIMEZONEr   Ú__annotations__Ú	Exceptionr_   Úfloatr   ÚIMAGE_EXTENSIONSr*   r+   r%   rB   r¡   r   Údictr   rY   r#   r&   Úboolr,   r3   r;   rI   rP   ÚtuplerV   rd   rn   rs   rv   r·   rx   r~   r…   rŠ   rª   r´   r»   r¿   rÏ   rÔ   rÞ   rà   rñ   r÷   rý   r  r  rë   s   0r   ú<module>r$     sR  ðòó" Û 	Û Û Ý Ý ß 'Ñ 'å Ý $à	ˆ×	Ñ	˜8Ó	$€ðÝ!Ù#+¨F×,AÑ,AÓ#B€IÐ ÓBð7�Uð 7˜xó 7ð
 "(×!8Ñ!8Ö9˜Aˆa�g‰g�iÒ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   Á	H Á<H5È#H2È1H2