Ë
    Ì¨jT  ã                  ó,  — d Z ddlmZ ddlZddlmZmZmZ ddlmZm	Z	m
Z
mZmZ ddlmZ ddlmZmZ dd	lmZmZmZmZmZmZmZmZmZmZmZmZmZm Z  dd
l!m"Z"m#Z#m$Z$ ddl%m&Z&  edg¬«      Z'dZ( G d„ de«      Z) G d„ de«      Z* G d„ de«      Z+d$d„Z,e'j[                  d«       e	e$«      fd%d„«       Z.e'j[                  d«       e	e$«       e	e«      fd&d„«       Z/e'ja                  d«       e	e$«       e	e«      fd'd„«       Z1e'j[                  d«       e	e$«       e	e«      fd(d„«       Z2e'ja                  d«      d e	e$«       e	e«      fd)d„«       Z3d*d„Z4e'ja                  d «       e	e$«      fd+d!„«       Z5e'j[                  d"«       e	e$«      fd,d#„«       Z6y)-zSign-in, sign-out, invites.é    )ÚannotationsN)ÚUTCÚdatetimeÚ	timedelta)Ú	APIRouterÚDependsÚHTTPExceptionÚRequestÚResponse)Ú
Connection)Ú	BaseModelÚFieldé   )ÚUserÚcheck_throttleÚclear_throttleÚcreate_sessionÚcurrent_userÚdestroy_sessionÚhash_passwordÚload_membershipsÚ
me_payloadÚrecord_failureÚrequire_adminÚrequire_centerÚ
token_hashÚverify_password)ÚfetchallÚfetchoneÚget_conn)Úget_settingsÚauth)Útagsé   c                  ó"   — e Zd ZU ded<   ded<   y)ÚLoginInÚstrÚemailÚpasswordN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    ú-/var/www/avy-guidance/api/app/routers/auth.pyr&   r&   #   s   … ØƒJØ„Mr/   r&   c                  óf   — e Zd ZU  edd¬«      Zded<   dZded<    ed	d
¬«      Zded<   dZded<   y)ÚInviteIné   éþ   ©Ú
min_lengthÚ
max_lengthr'   r(   Nú
int | NoneÚ	center_idÚ
forecasterz^(center_admin|forecaster)$)ÚdefaultÚpatternz
str | NoneÚroleFÚboolÚis_admin)	r*   r+   r,   r   r(   r-   r9   r=   r?   r.   r/   r0   r2   r2   (   s9   … Ù !°Ô4€Eˆ3Ó4Ø €IˆzÓ Ù \Ð;XÔY€Dˆ*ÓYØ€HˆdÔr/   r2   c                  ó@   — e Zd ZU ded<    edd¬«      Zded<   ded<   y)	ÚAcceptInr'   Útokené   éx   r5   Únamer)   N)r*   r+   r,   r-   r   rE   r.   r/   r0   rA   rA   /   s   … ØƒJÙ ¨sÔ3€Dˆ#Ó3Ø„Mr/   rA   c           	     óR   — t        | d|f«      }t        di |¤|t        | |«      dœ¤ŽS )Nz9SELECT id, email, name, is_admin FROM users WHERE id = %s)ÚcsrfÚmembershipsr.   )r   r   r   )ÚconnÚuser_idrG   Úrows       r0   Ú_userrL   5   s2   € Ü
�4ÐTÐW^ÐV`Ó
a€CÜÑN�#ÐN˜DÔ.>¸tÀWÓ.MÓNÐNr/   z/auth/loginc                óÚ  — |j                   r|j                   j                  nd› d| j                  j                  «       j	                  «       › �}t        |«       t        |d| j                  j                  «       f«      }|r|d   rt        |d   | j                  «      st        |«       t        dd«      ‚t        |«       t        ||d   |«      }t        |t        ||d   |«      «      S )NÚ?ú:zBSELECT id, password_hash FROM users WHERE email = %s AND is_activeÚpassword_hashi‘  zIncorrect email or passwordÚid)ÚclientÚhostr(   ÚstripÚlowerr   r   r   r)   r   r	   r   r   r   rL   )ÚbodyÚrequestÚresponserI   ÚkeyÚuserrG   s          r0   Úloginr[   :   sÔ   € à$+§N¢NˆW�^‰^× Ò ¸Ð<¸A¸d¿j¹j×>NÑ>NÓ>P×>VÑ>VÓ>XÐ=YÐ
Z€CÜ�3ÔÜØÐRÐUY×U_ÑU_×UeÑUeÓUgÐTió€Dñ �t˜OÒ,´OÀDÈÑDYÐ[_×[hÑ[hÔ4iÜ�sÔÜ˜CÐ!>Ó?Ð?Ü�3ÔÜ˜$  T¡
¨HÓ5€DÜ�dœE $¨¨T©
°DÓ9Ó:Ð:r/   z/auth/logoutc                ó$   — t        || |«       ddiS )NÚokT)r   )rW   rX   rI   rZ   s       r0   Úlogoutr^   I   s   € ä�D˜' 8Ô,Ø�$ˆ<Ðr/   z/auth/mec                ó   — t        | |«      S )N)r   )rI   rZ   s     r0   Úmer`   O   s   € ä�d˜DÓ!Ð!r/   z/invitesc           
     óF  — | j                   rt        |«       n0| j                  €t        dd«      ‚t	        || j                  d¬«       t        j                  d«      }t        j                  t        «      t        t        ¬«      z   }|j                  dt        |«      | j                  j                  «       | j                  | j                  r| j                   nd | j                   |j"                  |f«       t%        «       j&                  j)                  d«      › d	|› �|d
œS )Ni¦  zChoose a center for the inviteT©Úadminé    )Údaysz‰INSERT INTO invites (token_hash, email, center_id, role, is_admin, created_by, expires_at)
           VALUES (%s, %s, %s, %s, %s, %s, %s)ú/z/invite/)ÚurlÚ
expires_at)r?   r   r9   r	   r   ÚsecretsÚtoken_urlsafer   Únowr   r   ÚINVITE_DAYSÚexecuter   r(   rT   r=   rQ   r!   Úpublic_base_urlÚrstrip)rV   rI   rZ   rB   Úexpiress        r0   Úcreate_inviterq   T   sê   € à‡}‚}Ü�dÕØ	�‰Ð	Ü˜CÐ!AÓBÐBä�t˜TŸ^™^°4Õ8Ü×!Ñ! "Ó%€EÜ�l‰lœ3Ó¤)´Ô"=Ñ=€GØ‡L�Lð	2ä	�EÓ	˜DŸJ™J×,Ñ,Ó.°·±ÈTÏ^Ê^ÀÇ	Â	ÐaeÐgk×gtÑgtÐvz×v}Ñv}ð  @Gð  	Hôô
 #“n×4Ñ4×;Ñ;¸CÓ@ÐAÀÈ%ÈÐQÐahÑiÐir/   c                ól   — | €t        |«       t        |d«      S t        || d¬«       t        |d| f«      S )Nz€SELECT id, email, center_id, role, is_admin, created_at, expires_at, accepted_at FROM invites ORDER BY created_at DESC LIMIT 200Trb   z‹SELECT id, email, center_id, role, is_admin, created_at, expires_at, accepted_at FROM invites WHERE center_id = %s ORDER BY created_at DESC)r   r   r   )r9   rI   rZ   s      r0   Úlist_invitesrs   f   sN   € àÐÜ�dÔÜ˜ð  aó  bð  	bÜ�4˜¨$Õ/ÜØð 	VØ	ˆóð r/   c                ó˜   — t        | dt        |«      f«      }|r$|d   s|d   t        j                  t        «      k  rt        dd«      ‚|S )Nz}SELECT i.*, c.name AS center_name FROM invites i LEFT JOIN centers c ON c.id = i.center_id
           WHERE i.token_hash = %sÚaccepted_atrh   i”  z+This invite link is invalid or has expired.)r   r   r   rk   r   r	   )rI   rB   Úinvs      r0   Ú_valid_inviterw   s   sS   € Ü
Øð	&ä	�EÓ	Ðó	€Cñ �#�mÒ$¨¨LÑ(9¼H¿L¹LÌÓ<MÒ(MÜ˜CÐ!NÓOÐOØ€Jr/   z/invites/{token}c                ó@   — t        || «      }|d   |d   |d   |d   dœS )Nr(   Úcenter_namer=   r?   )r(   ry   r=   r?   )rw   )rB   rI   rv   s      r0   Ú
get_inviterz      s2   € ä
˜˜eÓ
$€CØ˜‘\°#°mÑ2DÈcÐRXÉkÐgjÐkuÑgvÑwÐwr/   z/auth/accept-invitec           	     ó   — t        || j                  «      }t        |d|d   f«      }|r8|d   }|j                  dt	        | j
                  «      | j                  |f«       n7t        |d|d   | j                  t	        | j
                  «      |d   f«      d   }|d   r|j                  d|f«       |d   r|j                  d	||d   |d
   xs df«       |j                  d||d   f«       t        |||«      }t        |t        |||«      «      S )Nz%SELECT id FROM users WHERE email = %sr(   rQ   z<UPDATE users SET password_hash = %s, name = %s WHERE id = %sz]INSERT INTO users (email, name, password_hash, is_admin) VALUES (%s, %s, %s, %s) RETURNING idr?   z.UPDATE users SET is_admin = true WHERE id = %sr9   z™INSERT INTO memberships (user_id, center_id, role) VALUES (%s, %s, %s)
               ON CONFLICT (user_id, center_id) DO UPDATE SET role = EXCLUDED.roler=   r:   zKUPDATE invites SET accepted_at = now(), accepted_user_id = %s WHERE id = %s)
rw   rB   r   rm   r   r)   rE   r   r   rL   )rV   rX   rI   rv   ÚexistingrJ   rG   s          r0   Úaccept_inviter}   …   s2  € ä
˜˜dŸj™jÓ
)€CÜ˜ÐEÈÈGÉÀÓW€HÙØ˜4‘.ˆØ�‰ÐSÔVcÐdh×dqÑdqÓVrÐtx×t}Ñt}ð  @Gð  VHõ  	IäØØkØ�‰\˜4Ÿ9™9¤m°D·M±MÓ&BÀCÈ
ÁOÐTó
ð ñ	ˆð
 ˆ:‚Ø�‰ÐEÈÀzÔRØ
ˆ;ÒØ�‰ðVà�c˜+Ñ&¨¨F©Ò(C°|ÐDô	
ð
 	‡L�LÐ^ÐahÐjmÐnrÑjsÐ`tÔuÜ˜$ ¨Ó2€DÜ�dœE $¨°Ó6Ó7Ð7r/   )rI   r   rJ   ÚintrG   r'   Úreturnr   )rV   r&   rW   r
   rX   r   rI   r   )rW   r
   rX   r   rI   r   rZ   r   )rI   r   rZ   r   )rV   r2   rI   r   rZ   r   )r9   r8   rI   r   rZ   r   )rI   r   rB   r'   r   Údict)rB   r'   rI   r   )rV   rA   rX   r   rI   r   )7Ú__doc__Ú
__future__r   ri   r   r   r   Úfastapir   r   r	   r
   r   Úpsycopgr   Úpydanticr   r   r"   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Údbr   r   r    Úsettingsr!   Úrouterrl   r&   r2   rA   rL   Úpostr[   r^   Úgetr`   rq   rs   rw   rz   r}   r.   r/   r0   ú<module>r‹      s®  ðÙ !å "ã ß -Ñ -ç HÕ HÝ ß %÷÷ ÷ ÷ ÷  .Ñ -Ý #á	˜˜Ô	!€Ø€ôˆiô ô
ˆyô ôˆyô óOð
 ‡�ˆ]ÓÙRYÐZbÓRcó ;ó ð;ð ‡�ˆ^ÓÙDKÈHÓDUÑdkÐlxÓdyó ó ðð
 ‡�ˆJÓÙ! (Ó+¹'À,Ó:Oó "ó ð"ð ‡�ˆZÓÙ5<¸XÓ5FÑU\Ð]iÓUjó jó ðjð" ‡�ˆJÓØ)-Á'È(ÓBSÑbiÐjvÓbwó 	ó ð	ó	ð ‡�ÐÓÙ.5°hÓ.?ó xó  ðxð
 ‡�Ð"Ó#ÙIPÐQYÓIZó 8ó $ñ8r/   