
    &6jMo              	       >   S SK JrJrJrJr  S SKJr  S SKJr  S SK	J
r
  S SKJr  S SKJrJr  S SKJr  S SKJr  S S	KJr  S S
KJr  S SKJr  S SKJr  S SKJrJrJrJ r J!r!J"r"  S SK#J#r#J$r$  S SK%J&r&  S SK'r'S SK(r(S SK)J*r*  S SK+J,r,J-r-  \'R\                  " \/5      r0S8S\S\14S jjr2S\34S jr4S\5S\5\6   4S jr7S\S\5\6   4S jr8 S8S\S\1S\1S\14S jjr9 " S S \,5      r: " S! S"\,5      r;\" S#S$/S%9r<\<R{                  S&5      \" \
5      4S'\:S\4S( jj5       r>\<R{                  S)5      \" \
5      4S'\;S\4S* jj5       r?\<R{                  S+5      \" 5       \" \
5      4S,\S\4S- jj5       r@\<R{                  S.5      \" \5      \" \
5      4S\1S/\&S\4S0 jj5       rA\<R{                  S15      \" \5      \" \
5      4S2\1S/\&S\4S3 jj5       rB\<R                  S45      \" \5      \" \
5      4S/\&S\4S5 jj5       rD\<R{                  S65      \" 5       \" \
5      4S,\S\4S7 jj5       rEg)9    )	APIRouterDependsstatusHTTPException)JSONResponse)OAuth2PasswordRequestForm)get_db)Session)funcor_)AuthenticationClass)RolClass)
AuditClass)EmailServiceClass)get_current_active_user)users_rol_period_clause)RolModelProfessionalModelProfessionalTeachingCourseModelSchoolModel	UserModelUsersRolModel)datetime	timedelta)	UserLoginN)quote)	BaseModelFielddbuser_idc           
         U R                  [        R                  [        R                  [        R                  [        R
                  5      R                  [        [        R                  [        R                  :H  5      R                  [        R                  U:H  [        [        R                  S:H  [        R                  R                  S 5      [        R                  S:H  5      [        [        R                  S:H  [        R                  R                  S 5      [        R                  S:H  5      [        USS95      R                  [        R                  R!                  5       5      R#                  5       n[%        U5      $ )Nr      r"   bypass_global_rol_ids)queryr   idrolcustomer_id	school_idjoinr   rol_idfilterr    r   deleted_status_idis_r   order_byascall!_dedupe_roles_for_login_selection)r   r    period_yearrowss       TC:\Users\jesus\Desktop\proyecto_pie360\backend\app\backend\routes\authentications.py_active_user_rolesr7       s   
KKLL  		
 
m]11X[[@	A	!!W,//14//33D9$$)
 **a/**..t4q 
 $KtL

 
(++//#	$	/ 	2 -T22    returnc                 b    [        U =(       d    S5      R                  5       R                  5       $ )N )strstriplower)rol_texts    r6   _normalize_rol_display_keyr@   =   s#    x~2$$&,,..r8   	role_rowsc                    0 nU  H#  n[        UR                  5      nX1;  d  M  X!U'   M%     [        UR                  5       S S9n0 nU H#  n[	        UR
                  5      nXe;  d  M  X%U'   M%     [        UR                  5       S S9nU Vs/ s H2  nUR                  UR
                  UR                  UR                  S.PM4     sn$ s  snf )uU  
Asignaciones en users_rols pueden apuntar a varios registros en rols con el mismo nombre
(clones por colegio). Para /select-role debe haber una sola opción por rol lógico.
Representante estable: menor RolModel.id entre los que el usuario tiene activos en users_rols.
La lista siguiente de colegios ya filtra por RolModel.rol coincidente.
c                 ,    [        U R                  5      $ Nintr'   xs    r6   <lambda>3_dedupe_roles_for_login_selection.<locals>.<lambda>M   s    QTTr8   keyc                 ,    [        U R                  5      $ rD   rE   rG   s    r6   rI   rJ   S   s    SYr8   r,   r(   r)   r*   )rF   r'   sortedvaluesr@   r(   r)   r*   )rA   by_rol_table_idrridunique_rowsby_namerL   ordereds           r6   r3   r3   A   s     O!$$i%#$C   //17JKKG(/CL  W^^%+>?G  A dd55==		
   s   9C	rolesc           	      D   U Vs1 s H  n[        UR                  SS5      5      iM      nnSU;   a  SU;  a  U R                  [        5      R	                  [        R
                  S:H  [        [        R                  S:H  [        R                  R                  S 5      5      5      R                  5       nU(       a`  UR                  [        UR
                  5      UR                  =(       d    SUR                  UR                  S.5        UR                  S S9  U$ s  snf )	Nr,   r      r"   zSuper AdministradorrN   c                 8    [        U R                  SS5      5      $ )Nr,   r   )rF   getrG   s    r6   rI   8_ensure_superadmin_if_admin_equivalent.<locals>.<lambda>s   s    Sx);%<r8   rK   )rF   r[   r&   r   r-   r'   r   r.   r/   firstappendr(   r)   r*   sort)r   rW   rR   role_idssuperadmin_rows        r6   &_ensure_superadmin_if_admin_equivalentrb   _   s    167AAEE(A&'H7H}(*HHXVq H..!3X5O5O5S5STX5YZ UW 	 LL!."3"34)--F1F#1#=#=!/!9!9	 JJ<J=L) 8s   %Dr)   r,   c                    U R                  [        5      R                  [        R                  U:H  [        R                  S:H  5      nUS;   a  / $ U R                  [
        5      R                  [
        R                  U:H  [        [
        R                  S:H  [
        R                  R                  S 5      5      5      R                  5       nU(       d  / $ [        U5      S:X  a  UR                  5       nGOU R                  [
        R                  5      R                  [        [        R                  [
        R                  :H  5      R                  [        R                   U:H  [        [        R                  S:H  [        R                  R                  S 5      5      [
        R                  U:H  [
        R"                  UR"                  :H  [        [
        R                  S:H  [
        R                  R                  S 5      5      [
        R                  R%                  S 5      ['        USS95      R)                  5       R                  5       nU V	s/ s H!  o(       d  M  U	S   c  M  [        U	S   5      PM#     n
n	U
(       a=  UR                  [        R                  R+                  U
5      5      R                  5       nONUR                  (       a;  UR                  [        R                  UR                  :H  5      R                  5       nO/ nU Vs/ s H  nUR                  UR                  UR                  UR,                  UR.                  UR0                  UR2                  UR4                  (       a  UR4                  R7                  S5      OS UR8                  (       a  UR8                  R7                  S5      OS S.	PM     sn$ s  sn	f s  snf )Nr   )r   NrY   r#   r$   %Y-%m-%d %H:%M:%S)	r'   r)   r.   school_nameschool_addressdirector_namecommunity_school_password
added_dateupdated_date)r&   r   r-   r)   r.   r   r'   r   r/   r]   rF   r2   r*   r+   r   r,   r    r(   isnotr   distinctin_re   rf   rg   rh   ri   strftimerj   )r   r)   r,   r    r4   
base_queryrol_rowr5   same_role_school_idsrH   allowed_idsss               r6   #_available_schools_for_current_rolert   w   s    +&--;.%%*J 	 		KK6!**a/1K1K1O1OPT1UV

 
  	 6{a~~
 HHX''(T-!5!5!DEV%%0M33q8-:Y:Y:]:]^b:cd$$3+H..!3X5O5O5S5STX5YZ""((.'4P XZSU 	 +?Y*>Q!y!ys1Q4y*>Y$$[^^%7%7%DEIIKD$$[^^w7H7H%HIMMODD  A $$==!"!4!4==..__)*)D)DHI!,,//0CDZ^LMNNANN334GH`d
	
   Zs   
OO%OB4Oc                   0    \ rS rSr% \" SSSS9r\\S'   Srg)	ForgotPasswordBody   .      
min_length
max_lengthemail N)	__name__
__module____qualname____firstlineno__r   r}   r<   __annotations____static_attributes__r~   r8   r6   rv   rv      s    sqS9E39r8   rv   c                   H    \ rS rSr% \" SSS9r\\S'   \" SSSS9r\\S	'   S
r	g)ResetPasswordBody   .
   )r{   token      rz   new_passwordr~   N)
r   r   r   r   r   r   r<   r   r   r   r~   r8   r6   r   r      s&    sr*E3*caC@L#@r8   r   z/authenticationsAuthentications)prefixtagsz/forgot-passwordbodyc                    U R                   R                  5       R                  5       nSSS.n UR                  [        5      R                  [        R                  " [        R                   5      U:H  [        R                  S:H  5      R                  5       nU(       Ga  UR                   =(       d    SR                  5       (       a  [        U5      nUR                  UR                  5      u  pg[        R                  " S5      =(       d    SR                  S5      nU S	[        USS
9 3n	[!        5       n
U
R#                  U	UR$                  =(       d    SR                  5       =(       d    SUS9nU
R'                  UR                   R                  5       SUSU	 3S9nU(       d  [(        R+                  S5        [1        [2        R4                  US9$ ! [,         a    [(        R/                  S5         N9f = f)u   
Recuperación de contraseña: siempre responde igual (no revela si el correo existe).
Si el usuario existe y SMTP está configurado, envía correo HTML con enlace JWT.
   ub   Si el correo está registrado en Pie360, recibirás instrucciones para restablecer tu contraseña.)r   messager   r;   FRONTEND_PUBLIC_URLzhttp://localhost:5173/z/reset-password?token=)safeN)	reset_url	user_nameexpires_minutesu"   Pie360 — Restablecer contraseñau@   Restablece tu contraseña abriendo este enlace en el navegador:
)
text_plainzLforgot-password: usuario encontrado pero no se pudo enviar el correo (SMTP).z7forgot-password: error interno (no expuesto al cliente)status_codecontent)r}   r=   r>   r&   r   r-   r   r.   r]   r   create_password_reset_tokenr'   osgetenvrstripr   r   password_reset_email_html	full_name	send_htmlloggerwarning	Exception	exceptionr   r   HTTP_200_OK)r   r   
email_normgenericuserauthr   minutes_usedbaser   mailerhtmlsents                r6   forgot_passwordr      s    !!#))+JwG
 THHYV

9??+z9++q0 UW 	 TZZ%2,,..&r*D"&"B"B477"KEII34O8OWWX[\D& 6uU7L6MNI&(F33#>>/R668@D , 4 D
 ##

  "4^_h^ij	 $ D b F$6$6HH  TRSTs   FG G54G5z/reset-passwordc           	      "    [        U5      nUR                  U R                  R                  5       5      nUR	                  [
        5      R                  [
        R                  U:H  [
        R                  S:H  5      R                  5       nU(       d  [        [        R                  SSSS.S9$ UR                  U R                  5      Ul        [         R"                  " 5       Ul        UR'                  5         [        [        R(                  SSSS.S9$ ! [*         a6  n[        UR,                  UR,                  UR.                  SS.S9s SnA$ SnAf[0         a2  n[        [        R2                  S	S
[5        U5       3SS.S9s SnA$ SnAff = f)uU   Restablece contraseña con el token recibido por correo (JWT purpose=password_reset).r     u@   No se pudo restablecer la contraseña. Solicita un nuevo enlace.Nr   r   datar   r   u&   Contraseña actualizada correctamente.  u%   Error al restablecer la contraseña: )r   decode_password_reset_tokenr   r=   r&   r   r-   r'   r.   r]   r   r   HTTP_400_BAD_REQUESTgenerate_bcrypt_hashr   hashed_passwordr   utcnowrj   commitr   r   r   detailr   HTTP_500_INTERNAL_SERVER_ERRORr<   )r   r   r   r    r   es         r6   reset_passwordr      sX   )
"2&224::3C3C3EFHHYVILLG+Y-H-HA-MNUW 	
 "77!a    $889J9JK$OO-
		**C
 	
  
 }}4P
 	
  
==B3q6(K
 	

s7   B+D .A%D 
F+E	FF'F	F	Fz/login	form_datac                     [        U5      R                  U R                  U R                  5      nUS   n[	        U[        US   5      5      n[        X5      nU(       d
  [        SSS9e[        U5      S:  a  [        SS9n[        U5      R                  [        US	   5      S
UR                  S5      S [        R                  " 5       R                  S.U5      n0 SU_SUS   _SUS   _SS
_SUR                  S5      _SS _SS _SS_S/ _SS _SUS   _S	US	   _SS_SUR!                  5       _SS_SU_nGOL[        US
   S   5      nU(       a  [#        U5      R                  U5      OS n	Sn
[%        U	[&        5      (       a  SU	;   a  U	S   R                  SS5      n
[%        U	[&        5      (       a8  U	R                  S5      (       a"  U	R                  S0 5      R                  S/ 5      O/ nUR                  S5      nS nS n[        SS9n[        US	   5      UUUS S [        R                  " 5       R                  S.n[        U5      R                  X5      nUUS   US   UUUUU
US US   US	   SUR!                  5       S S!.n [)        U5      R+                  US   UR                  S5      S"9  [1        [2        R4                  S$S%US&.S'9$ ! [,         a!  n[/        S#[        U5       35         S nANBS nAff = f! [         a6  n[1        UR6                  UR6                  UR8                  S S&.S'9s S nA$ S nAf[,         a2  n[1        [2        R:                  S(S)[        U5       3S S&.S'9s S nA$ S nAff = f)*N	user_datar'   i  z#El usuario no tiene roles asignadosr   r   r"    minutesr}   r   r)   )subr,   r)   r*   r4   access_tokenr    rutr,   r*   schoolr(   r;   permissionsprofessional_teaching_courser   
token_typebearer
expires_inrequires_role_selectionTavailable_rolesrol_datar   r,   r)   r*   teaching_id	course_idr4   Fr   r    r   r,   r)   r*   r   r(   r   r   r   r}   r   r   r   )r    r,   u(   Error guardando registro de auditoría: r   zLogin successfulr   r   r   Internal server error: )r   authenticate_userusernamepasswordr7   rF   rb   r   lenr   create_tokenr<   r[   r   nowyeartotal_secondsr   
isinstancedictr   storer   printr   r   r   r   r   r   )r   r   r   r   
user_rolestoken_expiresr   r   chosen_rol_id
rol_resultrol_namer   r)   r*   school_data
token_dataaudit_errorr   s                     r6   loginr   )  s   r
"2&889K9KYM_M_`%	'C	$,@A
;BK
C8]^^ z?Q%g6M'+88y12#,==#?!%#+<<>#6#6 	E9T? y' !	
 y}}]; T $ r r / Y{3 7+ h m99; *4  ":!D&  
1h 78M<I"))-8tJH*d++
j0H%j155eR@S]^hjnSoSot~  uC  uC  DN  uO  uO*..R8<<]BO  UWK#--6KIK%g6M9W-.'*&#!'||~22J (+88SE %$T? ''*&%*04&{3"7+&+99;+0D$	QrN  !$xx) !  **-
 	
  	Q<S=M<NOPP	Q  
--88
 	
  
==4SVH=
 	

sZ   JK: +K 0K: 
K7K2-K: 2K77K: :
M4+L5/M45M4'M/)M4/M4z/select-role/{rol_id}session_userc                 f    UR                  [        5      R                  [        R                  UR                  :H  5      R                  [	        [        R
                  S:H  [        R
                  R                  S 5      5      5      R                  5       nU(       d
  [        SSS9eUR                  [        R                  5      R                  [        R                  UR                  :H  [        R                  U :H  [	        [        R
                  S:H  [        R
                  R                  S 5      [        R                  S:H  5      [        [        USS 5      SS95      R                  5       nU(       d  [        U 5      S:X  a  UR                  [        R                  5      R                  [        R                  UR                  :H  [        R                  S	:H  [	        [        R
                  S:H  [        R
                  R                  S 5      5      [        [        USS 5      SS95      R                  5       nU(       d
  [        S
SS9eO
[        S
SS9e[        U5      R!                  U 5      nSn/ n[#        U[$        5      (       a0  SU;   a*  US   R!                  SS5      nUS   R!                  S/ 5      nS n	S n
['        SS9n[        USS 5      nUc  [(        R*                  " 5       R,                  n[/        U5      R1                  [3        UR4                  5      [        U 5      UR6                  U	S S US.U5      nUUR                  UR8                  [        U 5      UR6                  U	U
UUS UR:                  UR4                  SUR=                  5       SS.n[?        [@        RB                  SSUS.S9$ ! [         a6  n[?        URD                  URD                  URF                  S S.S9s S nA$ S nAf[H         a2  n[?        [@        RJ                  SS[3        U5       3S S.S9s S nA$ S nAff = f)Nr     User not foundr   r"   r4   r#   r$   rY     zRol no asignado a este usuarior;   r   r(   r   r   r   r   r   Fr   r   zRole selected successfullyr   r   r   r   )&r&   r   r-   r'   r   r.   r/   r]   r   r   r    r,   r   getattrrF   r   r[   r   r   r   r   r   r   r   r   r<   r}   r)   r   r   r   r   r   r   r   r   r   r   )r,   r   r   user_rowrel	admin_relr   r   r   r*   r   r   py_tokr   r   r   s                   r6   select_roler     s   h
HHYVILLLOO34VC	33q8):U:U:Y:YZ^:_`aUW	 	 C8HII HH]%%&V%%4$$.!33q8!3377=!((A-
 (L->VZ UW 	  6{aHH]--.V%--<%,,1M;;q@-BaBaBeBefjBkl/#L-F^b	 UW  !'C@`aa ! $<\]]b\%%f-
j$''J*,D!*-11%<H$Z044]BGK 	!'2}d;>\\^((F#B'448>>*f+'33&#!% 
 "{{<<&k#//"!&,0!++^^"'557',
$ **"/KUYZ
 	
  
 }}4P
 	
  
=="1HQ/Q[_`
 	

s0   N3N6 6
P0 +O1+P01P0>'P+%P0+P0z/select-school/{school_id}r*   c                 v	  ^   UR                  [        5      R                  [        R                  UR                  :H  5      R                  [	        [        R
                  S:H  [        R
                  R                  S 5      5      5      R                  5       nU(       d
  [        SSS9e[        [        USS5      =(       d    S5      nUR                  nU(       a  [        U5      R                  U5      OS nSn/ n[        U[        5      (       a0  SU;   a*  US   R                  SS5      nUS   R                  S	/ 5      n[!        X%U[        UR                  5      [        US
S 5      5      n	[#        U 4S jU	 5       S 5      n
U
(       d  [%        [&        R(                  SSS S.S9$ U
nS nS nS nS nUS;  Ga  UR+                  5       S:w  Ga  UR                  [,        R                  5      R                  [,        R.                  UR                  :H  5      R1                  [,        R                  R3                  5       5      R                  5       nU(       a  [        US   5      OS nUb  UR                  [4        5      R                  [4        R6                  U:H  [4        R
                  S:H  5      R                  5       nU(       a  UR8                  nUR:                  nUR                  UR6                  UR8                  UR:                  UR<                  (       a  UR<                  R?                  S5      OS UR@                  (       a  UR@                  R?                  S5      OS S.n[C        SS9n[        US
S 5      nUc  [D        RF                  " 5       RH                  n[K        URL                  5      UUT UUUS.n[O        U5      RQ                  UU5      nURS                  5       nUUR                  URT                  Ub  UOSUT UUUUUURV                  URL                  SUS.n[%        [&        RX                  SSUS.S9$ ! [         a6  n[%        URZ                  URZ                  UR\                  S S.S9s S nA$ S nAf[^         a2  n[%        [&        R`                  SS[K        U5       3S S.S9s S nA$ S nAff = f)Nr   r   r   r   r,   r;   r   r(   r   r4   c              3   b   >#    U  H$  n[        US    5      [        T5      :X  d  M   Uv   M&     g7f)r'   N)rF   ).0rs   r*   s     r6   	<genexpr> select_school.<locals>.<genexpr>'  s&     Y!#ag,#i.:XAAs   /	/r   z4School not found or does not belong to your customerr   r   )r"   rY   coordinadorrd   )r'   professional_idr   r   ri   rj   r   r   r   r   )r   r    r   r,   r)   r*   r   r(   r   r  r   r   r}   r   r   r   zSchool selected successfullyr   r   )1r&   r   r-   r'   r   r.   r/   r]   r   rF   r   r)   r   r[   r   r   rt   nextr   r   HTTP_404_NOT_FOUNDr>   r   r    r0   descr   r  r   r   ri   rn   rj   r   r   r   r   r<   r}   r   r   r   r   r   r   r   r   r   r   )r*   r   r   r   user_rol_idr)   r   r   r   allowed_schoolsr   school_dictr   ptc_teaching_idptc_course_idprofessional_id_valprof_pkptcr   r   r   r   expires_in_secondsr   r   s   `                        r6   select_schoolr    s0   F
HHYVILLLOO34VC	33q8):U:U:Y:YZ^:_`aUW	 	 C8HII',!<AB** 7BXb\%%k2t
j$''J*,D!*-11%<H$Z044]BGK=[#hkk*:GLR_ae<f
 YY[_`"55!U   " (,$"f$)9])J *--.)11X[[@A+..3356	  6=#gaj/$".hh>?FF3CCGZZ3EEJ %' 
 &)ooO$'MMM!ff+.+>+>'*%(]]VYVdVdcnn&=&=>Q&RjnZ]ZjZj(8(8(A(ABU(Vpt40 "'2}d;>\\^((Fx~~&!&"*&!

 $B'44ZO*88: "{{<<%0%<k!&"!&2,H!++^^",
$ **9
 	
  
--88
 	
  
==4SVH=
 	

s7   F P> $JP> >
R8+Q93R89R8'R3-R83R8z/available-schoolsc                     [        [        U SS5      =(       d    S5      n[        [        U SS5      =(       d    S5      nUS::  d  US::  a  [        [        R                  SS/ S.S9$ [        XU[        U R                  5      [        U SS 5      5      n[        [        R                  S	S
US.S9$ ! [         a2  n[        [        R                  SS[        U5       3/ S.S9s S nA$ S nAff = f)Nr)   r   r,   r   u0   Rol o cliente inválido para seleccionar colegior   r   r4   r   OKr   r   )rF   r   r   r   r   rt   r'   r   r   r   r<   )r   r   r)   r  r   r   s         r6   available_schoolsr    s    
',qAFQG',!<AB!{a/"77#&3eoqr 
 3[#loo*>Vcei@j
 **"tTB
 	
  
=="1HQ/Q[]^
 	

s%   A%B0 (AB0 0
C,:'C'!C,'C,z/logoutc           	      L    [        U5      R                  U R                  U R                  5      n[	        SS9nUS   n[        U5      R                  S[        US   5      0U5      nUUR                  S5      UR                  S5      SS	.n[        [        R                  S
SUS.S9$ ! [         a6  n[        UR                  UR                  UR                  S S.S9s S nA$ S nAf[         a2  n[        [        R                  SS[        U5       3S S.S9s S nA$ S nAff = f)Nr   r   r   r   r}   r   r,   r   )r   r   r,   r   r   zLogout successfulr   r   r   r   )r   r   r   r   r   r   r<   r[   r   r   r   r   r   r   r   r   )r   r   r   access_token_expiresudaccess_token_jwtr   r   s           r6   logoutr    s(   &
"2&889K9KYM_M_`(9+.r2??BwKHX@Y[op -66%=ffX&"	
 **.
 	
  
--88
 	
  
==4SVH=
 	

s0   B&B) )
D#3+C$D#$D#1'DD#D#rD   )Ffastapir   r   r   r   fastapi.responsesr   fastapi.securityr   app.backend.db.databaser	   sqlalchemy.ormr
   
sqlalchemyr   r   (app.backend.classes.authentication_classr   app.backend.classes.rol_classr   app.backend.classes.audit_classr   app.backend.classes.email_classr   app.backend.auth.auth_userr   "app.backend.utils.users_rol_periodr   app.backend.db.modelsr   r   r   r   r   r   r   r   app.backend.schemasr   loggingr   urllib.parser   pydanticr   r   	getLoggerr   r   rF   r7   r<   r@   listr   r3   rb   rt   rv   r   authenticationspostr   r   r   r   r  r[   r  r  r~   r8   r6   <module>r,     s   = = * 6 * "   H 2 6 = > F  ) )  	  % 
		8	$37 3S 3:/C / $t* <w tDz 2 KO@@!@+.@9<@F: :A	 A
 
	 ()<CFO -I, -I' -I *-I` '(:A&/ +
* +
 +
 )+
\ h18'RX/ s
. s
 s
  s
l -.7>?V7Wgnougv i
 i
9 i
]d i
 /i
V 23<CD[<\lstzl{ G
S G
	 G
bi G
 4G
T )*078O0P`ghn`o 
I 
V] 
 +
. i 29)7SY? '
/ '
 '
 !'
r8   