
    i|                        S SK Jr  S SK JrJrJrJrJrJrJ	r	  S SK
r
S SKrS SKrS SKJr  S SKJrJr  S SKrS SKrS SKJrJrJr  S SKJr  S SKJrJrJr  S S	K JrJrJrJ	r	Jr  S S
KJr  S SK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  S SKrS SKJr  S SK$r$S r% " S S5      r&S r'S r(S r)S r*SS jr+S r,SS jr-g)    )current_app)Flaskrender_templatesessionjsonifyrequestredirecturl_forN)Message)
save_Tokenconsultar_profile)ConfigHostSCHEME)wraps)datetime	timedeltatimezone)r   r   r	   r
   r   )r   )get_connection)MIMEMultipart)MIMEText)r   c                  :    [        [        R                  S   5      $ )N
SECRET_KEY)strappconfig     _C:\Users\victor.barrera\Documents\proyectos\elepV3\Elep\src\App\Security_Module\UserPassword.py<lambda>r        s    SL12r   c                   (    \ rS rSrSrS rSS jrSrg)EmailSender$   uK   
Clase para el envío de correos electrónicos sin depender de Flask-Mail.
c                 @    Xl         X l        X0l        X@l        XPl        g)u  
Inicializa el objeto EmailSender con configuración.

Args:
    mail_server: Servidor SMTP
    mail_port: Puerto SMTP
    mail_use_tls: Usar TLS para la conexión
    mail_username: Usuario para autenticación SMTP
    mail_password: Contraseña para autenticación SMTP
N)smtp_server	smtp_portuse_tlssender_emailsender_password)selfmail_server	mail_portmail_use_tlsmail_usernamemail_passwords         r   __init__EmailSender.__init__)   s      '"#),r   Nc                    U(       d  U(       d  [        S5      e[        U[        5      (       a  U/n[        S5      nX%S'   U R                  US'   SR                  U5      US'   U(       a  UR                  [        US5      5        U(       a  UR                  [        US5      5         [        R                  " U R                  U R                  5       nU R                  (       a  UR                  5         UR                  U R                  U R                  5        UR!                  U5        S	S	S	5        g
! , (       d  f       g
= f! ["         a6  n[%        SU 35        [%        [&        R(                  " 5       5         S	nAgS	nAff = f)uP  
Envía un correo electrónico.

Args:
    recipients: Lista de destinatarios o un solo destinatario
    subject: Asunto del correo
    html_content: Contenido HTML del correo (opcional)
    text_content: Contenido de texto plano del correo (opcional)
    
Returns:
    True si el correo se envió correctamente, False si hubo un error
z:Debe proporcionar contenido HTML o de texto para el correoalternativeSubjectFromz, ToplainhtmlNTError al enviar correo: F)
ValueError
isinstancer   r   r(   joinattachr   smtplibSMTPr%   r&   r'   starttlsloginr)   send_message	Exceptionprint	traceback
format_exc)r*   
recipientssubjecthtml_contenttext_contentmsgserveres           r   
send_emailEmailSender.send_email:   s4    LYZZ j#&&$J M* I''FIIj)D	 JJxg67 JJxf56	d..?6<<OO%T..0D0DE##C(	 @
  @?
  	,QC01)&&()	s7   )+E AD6-E 6
E E E 
F,FF)r(   r)   r&   r%   r'   )NN)__name__
__module____qualname____firstlineno____doc__r0   rN   __static_attributes__r   r   r   r"   r"   $   s    -"-r   r"   c                     [        U5      n[        U5      nU(       d  [        SS05      S4$ US   nUS   n[        R                  " [
        R                  5      [        SS9-   nUUUUR                  5       S.nUn	Un
Un[        S	[        [        5       5      5        [        S
[        5       5        [        R                  " U[        5       SS9n[        U[        5      (       a  UR!                  S5      n[#        X<5      nUc  [        SSU S305      S4$  [$         S[&         SU SU
 SU	 SU 3nU	nUUS.nSn[)        SUS9nSn [+        UU R,                  S   U/S9nUUl        UR1                  U5        SnU(       d  [        SS%05      S&4$ [        UUUS'.5      $ ! [2         a  n[        SU 35         [5        U R,                  S   U R,                  S    U R,                  S!   U R,                  S   U R,                  S"   5      nUR7                  UUUS#9n SnAN! [2         a2  n[        S$U 35        [        [8        R:                  " 5       5        e SnAff = fSnAff = f! [2         aV  n[        S(U S)35        [        S*[8        R:                  " 5        S)35        [        SS+[=        U5       305      S&4s SnA$ SnAff = f! [2         an  n[        S,U S)35        [        S-[        U5       S)35        [        S*[8        R:                  " 5        S)35        [        SS.[=        U5       305      S&4s SnA$ SnAff = f)/uD   
Genera un token JWT y envía un correo de activación al usuario.

errorz(No se pudo obtener el perfil del usuario  NombreEmail  minutesIDusernamerY   expzTipo de SECRET_KEY:zValor de SECRET_KEY:HS256	algorithmutf-8NEl usuario con ID  no existe en el sistemaz:///password_confirm?token=&userid=&email=&name=)activation_url	user_nameu   Configuración de passwordSecurity/UserPasswordemail.htmldataFMAIL_USERNAMEsenderrG   TzError al usar Flask-Mail: MAIL_SERVER	MAIL_PORTMAIL_USE_TLSMAIL_PASSWORD)rI   zError al usar EmailSender: u*   No se pudo enviar el correo de activación  tokentoken_id
email_sentu-   ===== Error al enviar correo de activación:  ========== Traceback completo: r9   z&===== Error en send_activation_email:    ===== Tipo de excepción: Error: )intr   r   r   nowr   utcr   	timestamprD   typer   jwtencoder;   bytesdecoder   r   r   r   r   r   r8   sendrC   r"   rN   rE   rF   r   )r   mailUserID_UserIDprofile_datarY   rZ   exp_timetoken_payloadrecipient_emailuser_idrm   rz   r{   rl   destinatariorp   asuntorI   r|   rK   rM   email_sendere2s                           r   send_activation_emailr   i   s   
|;W(0G%OPQSVVVh'W% <<-	$0GG%%'	
  	#T*,%78$jl3

L
 eU##LL)E f, -fX5MN  F	P &xs4&0HxX_W``ghwgxx~  @I  J  KN*L"0&D 2F ++LSWXL J$::o6 ,~ ( 		#!
2 )UVWY\\\ $(  9  21#67#.

=1

;/

>2

?3

?3$L ".!8!8$%1 "9 "J
 ! 7t<=)..01%D  	PA!FKL.y/C/C/E.FfMNG'?Ax%HIJCOO	P
  ;6qc@A*47)6:;*9+?+?+A*B&IJ73q6(!345s::;s   +K
 C(K
 0I' 	3F! <I' I' !
I$+I:A!H I'  
I*-IIII$$I' '
K1AK<K=K
 KK
 

MA#L=7M=Mc                      [         R                  " U [        5       S/S9nU$ ! [         R                   a     g[         R                   a     gf = f)u   
Verifica que un token JWT sea válido

Args:
    token: Token JWT a verificar
    
Returns:
    Datos del payload si es válido, None si no lo es
rb   )
algorithmsN)r   r   r   ExpiredSignatureErrorInvalidTokenError)rz   payloads     r   verify_tokenr      sK    **UJLgYG$$    s    # AAAc                 >   ^  T R                   " SS/S9U 4S j5       nU$ )Nz$/Tokensign/<UserID>/<Email>/<Nombre>GETmethodsc                 V  >  U (       a  U(       a  U(       d  [        S5        [        SS05      S4$ [        S5        [        R                  " [        R
                  5      [        SS9-   nU UUUS.n[        S	U S
35        TR                  R                  S5      (       d  [        S5        [        SS05      S4$ [        S5        [        R                  " U[        5       SS9n[        U[        5      (       a  UR                  S5      n[        S[        U5       SU S
35        [        S5        [!        X5      nUc"  [        SU  S35        [        SSU  S305      S4$ [        SU S
35        [        S5        [#        5       nUR%                  UUU US9n[        S5        [        UUUS.5      $ ! [&         an  n	[        S U	 S
35        [        S![        U	5       S
35        S"S Kn
[        S#U
R*                  " 5        S
35        [        SS$[-        U	5       305      S4s S n	A	$ S n	A	ff = f)%Nz%===== Error: Campos incompletos =====rW   z!Todos los campos son obligatorios  u*   ===== Iniciando generación de token =====r[   r\   r^   z===== Token payload preparado: r}   r   z,===== Error: SECRET_KEY no configurada =====u&   Configuración del servidor incompletarx   z ===== Iniciando jwt.encode =====rb   rc   re   z===== Token generado (tipo: z): z,===== Guardando token en base de datos =====z===== Error: El UserID z" no existe en la tabla Users =====rf   rg   rX   z===== Token guardado con ID: u*   ===== Enviando correo de activación =====)r   rm   r   rz   z%===== Preparando respuesta JSON =====ry   z===== Error en generar_token: r   r   r~   r   )rD   r   r   r   r   r   r   r   getr   r   r   r;   r   r   r   r   r"   r   rC   rE   rF   r   )r   rZ   rY   r   r   rz   r{   r   r|   rM   rE   r   s              r   generar_token!Token_sign.<locals>.generar_token   sJ   C	?f=>)LMNPSSS >?||HLL1Id4KKH! 	M 3M?&IJ ::>>,//DE)QRSUXXX45JJ!E %''W-0eSvNO@A!&0H /x7YZ[1&9QR    1(6BC>?&=L%;; % 	 < J 9:$(    	?21#V<=.tAwiv>?.y/C/C/E.FfMNGws1vh%7893>>	?s2   .F0 BF0 ;B$F0  AF0 0
H(:A#H#H(#H(route)r   r   s   ` r   
Token_signr      s/    YY5wGE? HE?L r   c                 6    U R                   " SS/S9S 5       nU$ )Nz	/activater   r   c            	         [         R                  R                  S5      n [         R                  R                  S5      n[         R                  R                  S5      n[         R                  R                  S5      nU (       a  U(       d
  [        SSS9$  Sn[	        5        nUR                  5       nUR                  XAU /5        UR                  5       nU(       d  [        SS	S9sS S S 5        $ Uu  ppU(       a  [        SS
S9sS S S 5        $ [        R                  " 5       U
:  a  [        SSS9sS S S 5        $  [        R                  " U [        5       S/SS0S9nSnUR                  X/5        SnUR                  X/5        UR                  5         [        SSU=(       d    UR                  SS5      S9sS S S 5        $ ! [        R                   a    [        SSS9s sS S S 5        $ [        R                   a    [        SSS9s sS S S 5        $ f = f! , (       d  f       g = f! [          a"  n[#        SU 35        [        SSS9s S nA$ S nAff = f)Nrz   useridemailnameSecurity/UserPassword.htmlu-   Enlace de activación inválido o incompleto.)message
                SELECT ActivationTokenID, Token, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
                Token no encontrado o inválido.u0   Este enlace de activación ya ha sido utilizado.u%   El enlace de activación ha expirado.rb   
verify_expTr   optionsEl token ha expirado.   Token inválido.
                    UPDATE ActivationTokens 
                    SET IsUsed = 1 
                    WHERE ActivationTokenID = ?
                z
                    UPDATE Users 
                    SET Status = 'ACTIVO' 
                    WHERE UserID = ?
                exitorY   Usuario)r   r   u   Error durante la activación: u,   Ha ocurrido un error durante la activación.)r   argsr   r   r   cursorexecutefetchoner   utcnowr   r   r   r   r   commitrC   rD   )rz   r   r   r   check_token_queryconnr   
token_datar{   db_token
expires_atis_useddecoded_tokenupdate_token_queryupdate_user_queryrM   s                   r   activate_account1activate_account_routes.<locals>.activate_accountK  sW      ),,""8,  )||'G"#?*Y[ [E	Z!  !T0E2BC#__.
!*+G2TV "! ;E7J *+G2df "!" ??$z1*+G2Y[% "!,F$'JJ"$+9!-t 4	%M&"
 1:>%!
 0)< ''C7+/+Y=3D3DXy3Y[o "!: 00 K*+G2IK K= "!@ ,, F*+G2DF FC "!@FA "!t  	Z21#67"#?*XZ Z	Zs   H) "AH&	H) 0H	H) "H1	H) <"GAH9	H) H!H"	H) ,H	H
	H) HH
H&"H) &H) )
I3I
IIr   )r   r   s     r   activate_account_routesr   J  s.    YY{UG,PZ -PZd r   c                    [        5       nUR                  5       nSnUR                  XP45        UR                  5       nU(       d  gSnUR                  Xq45        UR	                  5       nU(       d  gUR
                  n	U H  n
U
R                  nSnUR                  XU	45        UR	                  5       nU(       d  M=  Uu  pnnUS:X  a	  U(       a    gUS:X  a	  U(       a    gUS:X  a	  U(       a    gUS	:X  d  Mx  U(       d  M    g   g)
u   
Verifica si el usuario (user_id) tiene permiso de 'read', 'create',
'edit' o 'delete' sobre el m¨®dulo (module_name).

Retorna True/False.
z
        SELECT r.RoleID, r.RoleName
        FROM Roles r
        INNER JOIN UserRoles ur ON r.RoleID = ur.RoleID
        WHERE ur.UserID = ?
    FzO
        SELECT ModuleID
        FROM Modules
        WHERE ModuleName = ?
    z
            SELECT CanRead, CanCreate, CanEdit, CanDelete
            FROM RoleModules
            WHERE RoleID = ? AND ModuleID = ?
        readTcreateeditdelete)r   r   r   fetchallr   ModuleIDRoleID)r   module_nameactionr   r   sql_get_rolesrolessql_get_modulemod_row	module_idrowrole_idsql_check_permissionperm_rowcan_read
can_createcan_edit
can_deletes                     r   user_has_accessr     s     D[[]FM NN=*-OOE N
 NN>>2ooG  I ** 
 	+y-AB??$89A6H(Jh!jh!jj# ( r   c                 f    U R                   " SS/S9S 5       nU R                   " SS/S9S 5       nU$ )Nz/password_confirmr   r   c            
         [         R                  R                  S5      n [         R                  R                  S5      n[         R                  R                  S5      n[         R                  R                  S5      nU (       a  U(       d  [        SSSS9$  S	n[	        5        nUR                  5       nUR                  XAU /5        UR                  5       nU(       d  [        S
SSS9sSSS5        $ Uu  ppU(       a  [        SSSS9sSSS5        $ [        R                  " 5       U
:  a  [        SSSS9sSSS5        $  [        R                  " U [        5       S/SS0S9nU(       d  UR                  SS5      nU(       d  UR                  SS5      n[        SSU UUUS9sSSS5        $ ! [        R                   a    [        SSSS9s sSSS5        $ [        R                   a    [        SSSS9s sSSS5        $ f = f! , (       d  f       g= f! [         a#  n[!        SU 35        [        SSSS9s SnA$ SnAff = f)ub   
Muestra la página para confirmar/establecer la contraseña.
Verifica el token recibido por URL.
rz   r   r   r   r   F1   Enlace incompleto. Faltan parámetros necesarios.token_validerror_messager   zAccessDened.htmlr   N!Este enlace ya ha sido utilizado.El enlace ha expirado.rb   r   Tr   rY    r`   r   r   )r   rz   r   r   nombrezError al verificar el token: u8   Ha ocurrido un error durante la verificación del token.)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rC   rD   )rz   r   r   r   r   r   r   r   r{   r   r   r   r   rM   s                 r   password_confirm1password_confirm_routes.<locals>.password_confirm  sY      ),,""8,  )!!&)G"#?.30ce eC	l!  !T0E2BC#__.
!*+=E  aC  D "! ;E7J *+G6;8[] "!$ ??$z1*+G6;8PR' "!0L$'JJ"$+9!-t 4	%M "!.!2!28R!@  - 1 1*b A ''C26,1.5,1-35a "!L 00 Q*+G6;8OQ QO "!T ,, L*+G6;8JL LW "!TLU "!n  	l1!56"#?.30jl l	ls   H #AH(	H 2H	H #H5	H  AF+H!	H +G?
H	H G?3H4	H >G??H
HH H 
I H;5I ;I z/set_passwordPOSTc                  H    [         R                  " 5       n U (       d  [        SSS.5      S4$ U R                  S5      nU R                  S5      nU R                  S5      nU R                  S5      nU(       a  U(       a  U(       a  U(       d  [        SS	S.5      S4$ X4:w  a  [        SS
S.5      S4$ Sn[	        5        nUR                  5       nUR                  XRU/5        UR                  5       nU(       d  [        SSS.5      S4sSSS5        $ Uu  pnU(       a  [        SSS.5      S4sSSS5        $ [        R                  " 5       U
:  a  [        SSS.5      S4sSSS5        $ [        R                  " SS9n[        R                  " UR                  S5      U5      R                  S5      n[        SU 35        [        S[!        U5       S35        [!        U5      S:  a  [        SSS.5      S4sSSS5        $ SnUR                  XU/5        SnUR                  X/5        UR#                  5         [        SSSS.5      sSSS5        $ ! , (       d  f       g= f! [$         a4  n[        SU 35        [        SS['        U5       3S.5      S4s SnA$ SnAff = f)u=   
Recibe y procesa la contraseña establecida por el usuario.
FzNo se recibieron datos.successr   r   rz   userIdpasswordconfirmPasswordzFaltan datos requeridos.u   Las contraseñas no coinciden.z
                SELECT ActivationTokenID, ExpiresAt, IsUsed 
                FROM ActivationTokens 
                WHERE UserID = ? AND Token = ?
            u   Token no válido.Nr   r      )roundsre   u   Contraseña cifrada generada: zLongitud del hash: z caracteresrx   uE   Error interno: El hash de la contraseña excede el tamaño permitido.z
                    UPDATE Users 
                    SET PasswordHash = ?, Status = 'ACTIVO', LastLogin = GETDATE()
                    WHERE UserID = ?
                r   TuN   Contraseña establecida correctamente. Serás redirigido al inicio de sesión.z/login)r   r   r	   u$   Error al establecer la contraseña: )r   get_jsonr   r   r   r   r   r   r   r   bcryptgensalthashpwr   r   rD   lenr   rC   r   )rp   rz   r   r   confirm_passwordr   r   r   r   r{   r   r   salthashed_passwordr   r   rM   s                    r   set_password-password_confirm_routes.<locals>.set_password9  s   
S	p##%D5=VWXZ]]]HHW%Ehhx(Gxx
+H#xx(9:x?O5=WXY[^^^ +5=]^_addd!  !T0E2BC#__.
!"uAT#UVX[[ "! 1;-g "uAd#efhkk "! ??$z1"uAY#Z[]``! "!& ~~R0"(--0H$"O"V"VW^"_66GHI+C,@+AMN '#-"#(#j$  7 "!B%!
 0G2LM&"
 1:>#o (  e "!!p  	p8<=u;_`cde`f_g9hijlooo	ps   +I# A/I# I# 3I# ?A
I		I# I.	I# 8(I 	I# *BI7	I# AI	I# 
I I#  I# #
J!-)JJ!J!r   )r   r   r  s      r   password_confirm_routesr    sU    YY"UG4Sl 5Slj 	YY1Wp 2Wpr r   c                 z   ^ ^ T R                   " SS/S9U U4S j5       nT R                   " SS/S9S 5       n[        $ )Nz/auth/forgot-passwordr   r   c            
        >  [         R                  " 5       n U (       a  U R                  S5      (       d  [        SSS.5      S4$ U R                  S5      n[	        5        nUR                  5       nSnUR                  XA/5        UR                  5       nU(       d  [        SSS.5      sS	S	S	5        $ Uu  pgnS
n	UR                  X/5        UR                  5       n
SnUR                  X/5        UR                  5       nU(       aY  SR                  U Vs/ s H$  o(       d  M  UR                  5       (       d  M"  UPM&     sn5      nUR                  5       (       d  SnOSn[        R                  " 5       [        SS9-   nUUUSS.n[        R                  " U[        5       SS9nS
n	UR                  X/5        UR                  5       n
U
(       a  U
S   nSnUR                  UUUU/5        O5SnUR                  UUUU/5        UR                  5       nU(       a  US   OS	nUR!                  5         S	S	S	5        WnSnS["         SW SW SU SW 3
nUUUS.n [%        SU S9n['        UTR(                  S    U/S!9nUUl        TR-                  U5        [        SS"S.5      $ s  snf ! , (       d  f       N{= f! [.         aF  n[1        S#U 35        SS	Kn[1        UR4                  " 5       5        [        SS$S.5      S%4s S	nA$ S	nAff = f)&us   
Procesa la solicitud de recuperación de contraseña.
Genera un token y envía un correo electrónico al usuario.
r   Fu   Correo electrónico requeridor   r   z
                    SELECT UserID, Email, Status
                    FROM Users
                    WHERE Email = ?
                TuT   Si tu correo está registrado, recibirás un enlace para restablecer tu contraseña.Nz
                    SELECT ActivationTokenID 
                    FROM ActivationTokens 
                    WHERE UserID = ? AND IsUsed = 0
                z
                    SELECT FirstName, MiddleName, LastName, SecondLastName
                    FROM Profiles
                    WHERE UserID = ?
                 r      )hourspassword_reset)r_   r`   ra   r   rb   rc   r   z
                        UPDATE ActivationTokens
                        SET Token = ?, ExpiresAt = ?, CreatedAt = GETDATE(), IsUsed = 0
                        WHERE ActivationTokenID = ?
                    z
                        INSERT INTO ActivationTokens (UserID, Token, CreatedAt, ExpiresAt, IsUsed)
                        OUTPUT INSERTED.ActivationTokenID
                        VALUES (?, ?, GETDATE(), ?, 0)
                    u   Restaure su contraseñazhttp://rh   ri   rj   rk   )rl   rm   rz   rn   ro   rq   rr   ub   Se ha enviado un enlace para restablecer tu contraseña. Por favor, revisa tu correo electrónico.z(Error en solicitud de restablecimiento: uA   Error al procesar la solicitud. Por favor, inténtalo más tarde.rx   )r   r   r   r   r   r   r   r   r<   stripr   r   r   r   r   r   r   r   r   r   r   r8   r   rC   rD   rE   rF   )rp   r   r   r   check_query	user_datar   
user_emailstatusr   existing_tokentraer_nombre
user_data2partNombre_Completoexpiry_timer   	jwt_tokenr{   r   insert_token_queryr   r   r   rl   cuerpo_htmlrK   rM   rE   r   r   s                                r   request_password_reset8password_recovery_routes.<locals>.request_password_reset  sF   R	##%Dtxx005=\]^`cccHHW%E  !T
 {G4"OO-	 "#'#y$  "!& /8+V%!
 0)<!'!2 
 |Y7#__.
&)hh/etX\XbXbXd/e&fO +0022*3&/O 'oo/)!2DD " *&,	!  JJ!L%	%!
 0)<!'!2!  .a0H*&
 NN#5	;PX7YZ*&
 NN#5K7XY //+C),s1v$HA "F &L.F&tf,DYKxX_W``ghrgssy  {J  zK  LN #1,"D **KRVWK zz/2(>C #CH IIcN  i 0fS "!D  	<QC@A)&&() ^   		sj   AJ9 J9  A	J()	J9 3A#J(
J#
$J#
;J#
C2J(3A/J9 #J((
J62J9 9
L	;L>L	L	z/reset-passwordr   c                     [         R                  R                  S5      n [         R                  R                  S5      n[        SU  SU S35        U (       a  U(       d  [        S5        [	        SSS	S
9$  Sn[        5        nUR                  5       nUR                  X!U /5        UR                  5       nU(       dX  [        SU S35        UR                  SU/5        UR                  5       n[        SU SU S35        [	        SSSS
9sSSS5        $ Uu  pxp[        SU SU	 SU
 S35        U
(       a#  [        SU S35        [	        SSSS
9sSSS5        $ [        R                  " 5       nX:  a)  [        SU SU SU	 S35        [	        SSSS
9sSSS5        $  [        R                  " U [        5       S/SS0S9n[        S U S35        UR                  S!5      nU(       a)  US":w  a#  [        S#U S35        [	        SSS$S
9sSSS5        $ UR                  S%S&5      nS'nUR                  X/5        UR                  5       nU(       a  Uu  nnU(       d  UnOS&n[        S(U S)U S35        [        S15        [	        SSU UUUSS29sSSS5        $ ! [        R                   a-  n[        S*U S35        [	        S+SS,S
9s SnAsSSS5        $ SnAf[        R                    a-  n[        S-U S35        [	        S+SS.S
9s SnAsSSS5        $ SnAf["         aS  n[        S/U S35        S'nUR                  X/5        UR                  5       nU(       a
  Uu  nn SnANS0u  nn SnANSnAff = f! , (       d  f       g= f! ["         aN  n[        S3U S35        S4SKn[        UR&                  " 5       5        [	        S+SS5[)        U5       3S
9s SnA$ SnAff = f)6u^   
Muestra la página para establecer una nueva contraseña.
Verifica que el token sea válido.
rz   r   z!===== reset_password_page: token=z
, user_id=r}   z2===== Error: Falta token o user_id en la URL =====r   Fr   r   r   zB===== Error: Token no encontrado en la base de datos para user_id=zYSELECT ActivationTokenID, Token, ExpiresAt, IsUsed FROM ActivationTokens WHERE UserID = ?z&===== Tokens encontrados para user_id=z: r   Nz===== Token encontrado: ID=z	, expira=z, usado=z$===== Error: Token ya utilizado (ID=z) =====r   z ===== Error: Token expirado (ID=z). Actual: z
, Expira: r   rb   r   Tr   z'===== Token decodificado exitosamente: r   r
  z'===== Error: Tipo de token incorrecto: u   Tipo de token inválido.r`   r   z^
                        SELECT Email, Nombre FROM Users WHERE UserID = ?
                    z ===== Usuario encontrado: email=z	, nombre=z!===== Error: Token JWT expirado: zSecurity/AccessDened.htmlr   u"   ===== Error: Token JWT inválido: r   z!===== Error decodificando token: )r   r   u/   ===== Token válido, mostrando formulario =====)r   rz   r   r   r   is_password_resetz/===== Error inesperado en reset_password_page: r   u/   Ha ocurrido un error durante la verificación: )r   r   r   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   rC   rE   rF   r   )rz   r   r   r   r   r   
all_tokensr{   r   r   r   r   r   
token_typer   get_user_queryuser_rowdb_emailr   rM   rE   s                        r   reset_password_page5password_recovery_routes.<locals>.reset_password_page1  sM      ),,""8,1%
7)6RSGFG"#?,1.ac cy	j!  !T0E2BC#__.
!^_f^ggmnoNN#~  BI  AJ  K!'!2JB7)2j\Y_`a*+G496XZ "!  ;E7J3H:YzlRZ[bZccijk @
'RS*+G496Y[- "!6 oo'#<XJkRUQVV`ak`llrst*+G496NP= "!F</$'JJ"$+9!-t 4	%M CM?RXYZ "/!2!26!:J!j4D&D G
|SYZ[./K8=:T Vc "!l *--j"=E&N NN>9=%0H+3(&$$,E!#<UG9VHTZ[\6 GH&'C04*/,3*/+16:<G "!R 00 O=aSGH*+F496MO OW "!\ ,, J>qcHI*+F496HJ Ja "!f ! /=aSGH&N NN>9=%0H(0v(.v/g "!V  	jCA3fMN)&&()"#>,10_`cde`f_g.hj j		js   6N B	M0	N :M0	N 9M0	N A(J	N A J/M0	N M-&K?M- M0	N M-%L>M-?M0	N M-?M(M0M(#M0(M--M00
M>:N >N 
OAOOO)r   password_recovery_routes)r   r   r  r"  s   ``  r   r$  r$    sU    YY&9W :Wr 	YY 5'2Ij 3IjV $#r   )r   )N).flaskr   r   r   r   r   r   r   r	   r
   osr>   pytz
flask_mailr   &Consultas_SQL.Security.UserPasswordSQLr   r   r   rE   r   r   r   r   	functoolsr   r   r   r   r   Consultas_SQL.conexionr   email.mime.multipartr   email.mime.textr   secretsr   r"   r   r   r   r   r   r  r$  r   r   r   <module>r/     s   
 % T T T 	    R 
  ' '  2 2 F F   1 . $ F F 
 = 
 3
C CJA;H$HVTl@Dqfh$r   