§
    ÔŸ’jZ.  ã            	      óØ  — d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	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 dd	lmZ dd
lmZ  ej        d¦  «        Z eddg¬¦  «        Z e¦   «         Z ed¬¦  «        Z ee¦  «        fdId„Z dJd„Z! G d„ de¦  «        Z" G d„ de¦  «        Z# G d„ d e¦  «        Z$ G d!„ d"e¦  «        Z%e &                    d#¦  «        dKd'„¦   «         Z'e &                    d(¦  «        dLd*„¦   «         Z(e &                    d+¦  «         e	e ¦  «        fdMd-„¦   «         Z)e *                    d.¦  «        dNdOd2„¦   «         Z+e *                    d3¦  «        dNdPd4„¦   «         Z,e *                    d5¦  «         ed6d7¬8¦  «        dfdQd<„¦   «         Z-e *                    d=¦  «         e	e ¦  «        fdRd>„¦   «         Z.e *                    d? e	 e!d@dAg¦  «        ¦  «        g¬B¦  «        dSdD„¦   «         Z/e &                    d? e	 e!d@dAg¦  «        ¦  «        g¬B¦  «        dTdE„¦   «         Z0e 1                    dF e	 e!d@g¦  «        ¦  «        g¬B¦  «        dUdH„¦   «         Z2dS )VzDAuthentication & User Account API router for Google OAuth 2.0 & JWT.é    )ÚannotationsN)ÚAny)Ú	APIRouterÚDependsÚHTTPExceptionÚQueryÚRequestÚResponseÚSecurity)Újsonable_encoder)ÚHTMLResponseÚRedirectResponse)ÚHTTPAuthorizationCredentialsÚ
HTTPBearer)Ú	BaseModel)ÚAuthServicezdscons.auth.routerz/v1/authzAuthentication & User Accounts)ÚprefixÚtagsF)Ú
auto_errorÚrequestr	   Úcredentialsú#HTTPAuthorizationCredentials | NoneÚreturnúdict[str, Any]c                ó¤  — d}|r|j         r|j         }nÓ| j                             d¦  «        r| j                             d¦  «        }nž| j                             d¦  «        r| j                             d¦  «        }ni| j                             d¦  «        r| j                             d¦  «        }n4| j                             d¦  «        r| j                             d¦  «        }|st	          dd¬¦  «        ‚|d	k    r8t          t          j        d
d¦  «        dk    rt	          dd¬¦  «        ‚ddddddœS t                               |¦  «        S )zCDependency checking Bearer JWT from header, query param, or cookie.NÚtokenÚdscons_jwt_tokenÚdscons_tokenÚaccess_tokené‘  uR   YÃªu cáº§u xÃ¡c thá»±c. Vui lÃ²ng Ä‘Äƒng nháº­p hoáº·c truyá»�n Token xÃ¡c thá»±c.©Ústatus_codeÚdetailzdev-test-tokenÚapp_envÚdevelopmentÚ
productionuO   MÃ£ xÃ¡c thá»±c khÃ´ng há»£p lá»‡ trÃªn mÃ´i trÆ°á»�ng váº­n hÃ nh thá»±c táº¿.zusr-admin-01zadmin@dscons.vnÚ
superadminu   Ban GiÃ¡m Ä�á»‘c DSCons)ÚsubÚuser_idÚemailÚroleÚ	full_name)	r   Úquery_paramsÚgetÚcookiesr   ÚgetattrÚauth_serviceÚsettingsÚdecode_jwt_token)r   r   r   s      ú*C:\Projects\DSCons\app\api\routers\auth.pyÚget_current_userr5   "   sƒ  € ð
 €EØð 	4�{Ô.ð 	4ØÔ'ˆˆØ	Ô	×	!Ò	! 'Ñ	*Ô	*ð 4ØÔ$×(Ò(¨Ñ1Ô1ˆˆØ	Œ×	Ò	Ð/Ñ	0Ô	0ð 4Ø”×#Ò#Ð$6Ñ7Ô7ˆˆØ	Œ×	Ò	˜^Ñ	,Ô	,ð 4Ø”×#Ò# NÑ3Ô3ˆˆØ	Œ×	Ò	˜^Ñ	,Ô	,ð 4Ø”×#Ò# NÑ3Ô3ˆàð 
ÝØØgð
ñ 
ô 
ð 	
ð Ð Ò Ð Ý•<Ô(¨)°]ÑCÔCÀ|ÒSÐSÝØØhðñ ô ð ð
 "Ø%Ø&Ø Ø2ð
ð 
ð 	
õ ×(Ò(¨Ñ/Ô/Ð/ó    Úallowed_rolesú	list[str]c                ó<   ‡ — t          t          ¦  «        fdˆ fd„}|S )z%Role-based access control dependency.Úcurrent_userr   r   c                óv   •— |                       dd¦  «        }|‰vr|dk    rt          dd‰› d|› �¬¦  «        ‚| S )Nr+   Úviewerr'   i“  uN   TÃ i khoáº£n khÃ´ng Ä‘á»§ quyá»�n háº¡n. YÃªu cáº§u má»™t trong cÃ¡c quyá»�n: u   , quyá»�n hiá»‡n táº¡i: r!   )r.   r   )r:   Ú	user_roler7   s     €r4   Úrole_checkerz"require_role.<locals>.role_checkerN   sy   ø€ ð !×$Ò$ V¨XÑ6Ô6ˆ	Ø˜MÐ)Ð)¨i¸<Ò.GÐ.GÝØð [Ðhuð  [ð  [ð  PYð  [ð  [ðñ ô ð ð Ðr6   ©r:   r   r   r   )r   r5   )r7   r>   s   ` r4   Úrequire_roler@   K   s<   ø€ õ (/Õ/?Ñ'@Ô'@ð	ð 	ð 	ð 	ð 	ð 	ð 	ð Ðr6   c                  ó2   — e Zd ZU ded<   ded<   dZded<   dS )ÚEmailLoginRequestÚstrr*   ÚpasswordNú
str | Noner,   )Ú__name__Ú
__module__Ú__qualname__Ú__annotations__r,   © r6   r4   rB   rB   _   s5   € € € € € € Ø€J€J�JØ€M€M�MØ €IÐ Ð Ð Ñ Ð Ð r6   rB   c                  óN   — e Zd ZU ded<   ded<   dZded<   dZded<   dZded	<   dS )
ÚCreateUserRequestrC   r*   rD   NrE   r,   r<   r+   Úlinked_employee_id)rF   rG   rH   rI   r,   r+   rM   rJ   r6   r4   rL   rL   e   sX   € € € € € € Ø€J€J�JØ€M€M�MØ €IÐ Ð Ð Ñ Ø€DÐÐÐÑØ%)ÐÐ)Ð)Ð)Ñ)Ð)Ð)r6   rL   c                  ó$   — e Zd ZU ded<   ded<   dS )ÚChangePasswordRequestrC   Úold_passwordÚnew_passwordN©rF   rG   rH   rI   rJ   r6   r4   rO   rO   m   s*   € € € € € € ØÐÐÑØÐÐÑÐÐr6   rO   c                  ó   — e Zd ZU ded<   dS )ÚUpdateUserRoleRequestrC   r+   NrR   rJ   r6   r4   rT   rT   r   s   € € € € € € Ø€I€I�I€I€Ir6   rT   z/loginÚreqÚresponser
   c           	     óÄ   — t                                | j        | j        | j        ¬¦  «        }|                     d¦  «        }|r|                     d|ddddd¬	¦  «         |S )
uW   Ä�Äƒng nháº­p báº£o máº­t báº±ng email vÃ  máº­t kháº©u vá»›i HttpOnly Cookie an toÃ n.)r*   rD   r,   r   r   TÚlaxFé€:	 ú/©ÚkeyÚvalueÚhttponlyÚsamesiteÚsecureÚmax_ageÚpath)r1   Úauthenticate_email_userr*   rD   r,   r.   Ú
set_cookie)rU   rV   Úresr   s       r4   Úemail_loginrf   y   s�   € õ ×
.Ò
.ØŒiØ”Ø”-ð /ñ ô €Cð
 �GŠG�NÑ#Ô#€EØð 	
Ø×ÒØ"ØØØØØØð 	ñ 	
ô 	
ð 	
ð €Jr6   z/logoutúdict[str, str]c                ó–   — |                       dd¬¦  «         |                       dd¬¦  «         |                       dd¬¦  «         dddœS )	u1   Ä�Äƒng xuáº¥t vÃ  xÃ³a phiÃªn cookie xÃ¡c thá»±c.r   rZ   )r\   rb   r   r   Úsuccessu0   Ä�Ã£ Ä‘Äƒng xuáº¥t an toÃ n khá»�i há»‡ thá»‘ng.)ÚstatusÚmessage)Údelete_cookie)rV   s    r4   Úlogoutrm   �   s_   € ð ×ÒÐ1¸ÐÑ<Ô<Ð<Ø×Ò˜~°CÐÑ8Ô8Ð8Ø×Ò˜~°CÐÑ8Ô8Ð8ØÐ,^Ð_Ð_Ð_r6   z/change-passwordr:   c                óÊ   — |                      d¦  «        p|                      d¦  «        }|st          dd¬¦  «        ‚t                               || j        | j        ¬¦  «        S )u>   Thay Ä‘á»•i máº­t kháº©u tÃ i khoáº£n ngÆ°á»�i dÃ¹ng an toÃ n.r)   r(   r    u7   KhÃ´ng xÃ¡c Ä‘á»‹nh Ä‘Æ°á»£c danh tÃ­nh ngÆ°á»�i dÃ¹ng.r!   )r)   rP   rQ   )r.   r   r1   Úchange_user_passwordrP   rQ   )rU   r:   r)   s      r4   Úchange_passwordrp   ˜   s}   € ð
 ×Ò˜yÑ)Ô)ÐD¨\×-=Ò-=¸eÑ-DÔ-D€GØð 
ÝØÐ$]ð
ñ 
ô 
ð 	
õ ×,Ò,ØØÔ%ØÔ%ð -ñ ô ð r6   z/google/loginÚredirect_urirE   r   c                óZ   — t                                | ¬¦  «        }t          |d¬¦  «        S )uP   Chuyá»ƒn hÆ°á»›ng trá»±c tiáº¿p tá»›i mÃ n hÃ¬nh Ä‘Äƒng nháº­p Google OAuth 2.0.©rq   i3  )Úurlr"   )r1   Úget_google_auth_urlr   )rq   Ú	login_urls     r4   Úredirect_to_google_loginrw   ©   s-   € õ ×0Ò0¸lÐ0ÑKÔK€IÝ 	°sÐ;Ñ;Ô;Ð;r6   z/google/login-urlc                ó<   — dt                                | ¬¦  «        iS )ub   Láº¥y Ä‘Æ°á»�ng dáº«n URL chuyá»ƒn hÆ°á»›ng ngÆ°á»�i dÃ¹ng Ä‘áº¿n mÃ n hÃ¬nh Ä‘Äƒng nháº­p Google.rv   rs   )r1   ru   rs   s    r4   Úget_google_login_urlry   °   s    € ð �×9Ò9À|Ð9ÑTÔTÐUÐUr6   z/google/callback.zAuthorization code from Google)ÚdescriptionÚcoderC   r   c              ƒ  ó  K  — t                                | |¬¦  «        ƒ d{V —†}t          j        t	          |d         ¦  «        d¬¦  «        }t          d|d                              dd¦  «        › d	|d         d
         › d|d         d         › d|d         d                              ¦   «         › d|d         dd…         › d|d         › d|d         › d|› d�¦  «        }|                     d|d         ddddd¬¦  «         |S )ua   Callback endpoint tiáº¿p nháº­n authorization code tá»« Google sau khi ngÆ°á»�i dÃ¹ng Ä‘á»“ng Ã½.)r{   rq   NÚuserF)Úensure_asciiuã  
    <!DOCTYPE html>
    <html lang="vi">
    <head>
        <meta charset="UTF-8">
        <title>Ä�Äƒng nháº­p thÃ nh cÃ´ng - DSCons ERP</title>
        <style>
            body { font-family: 'Segoe UI', sans-serif; background: #0f172a; color: #f8fafc; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
            .card { background: #1e293b; padding: 2rem; border-radius: 12px; box-shadow: 0 10px 25px rgba(0,0,0,0.5); text-align: center; max-width: 450px; border: 1px solid #334155; }
            .btn { background: #0284c7; color: white; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; text-decoration: none; display: inline-block; margin-top: 15px; }
            .btn:hover { background: #0369a1; }
            .avatar { width: 80px; height: 80px; border-radius: 50%; border: 3px solid #0284c7; margin-bottom: 1rem; }
        </style>
    </head>
    <body>
        <div class="card">
            <img src="Ú
avatar_urlÚ u:   " class="avatar" alt="Avatar">
            <h2>Xin chÃ o, r,   z5!</h2>
            <p style="color: #94a3b8;">Email: r*   uQ   </p>
            <p><strong>Vai trÃ² ERP:</strong> <span style="color: #38bdf8;">r+   ze</span></p>
            <p style="font-size: 0.85rem; color: #64748b; word-break: break-all;">Token: r   é   u¯   ...</p>
            <a href="/dashboard" class="btn">VÃ o Báº£ng Ä�iá»�u Khiá»ƒn ERP</a>
        </div>
        <script>
            localStorage.setItem('dscons_jwt_token', 'z6');
            localStorage.setItem('dscons_token', 'zC');
            localStorage.setItem('dscons_user', JSON.stringify(z{));
            setTimeout(() => window.location.href = '/dashboard', 1200);
        </script>
    </body>
    </html>
    r   TrX   rY   rZ   r[   )	r1   Úexchange_google_codeÚjsonÚdumpsr   r   r.   Úupperrd   )r{   rq   ÚresultÚ	user_jsonÚresps        r4   Úgoogle_auth_callbackr‰   ¶   s—  è è € õ  ×4Ò4Ø ð 5ñ ô ð ð ð ð ð ð €Fõ ”
Õ+¨F°6¬NÑ;Ô;È%ÐPÑPÔP€IÝð ð  ˜f”~×)Ò)¨,¸Ñ;Ô;ð!ð ð" # 6œN¨;Ô7ð#ð ð$ 06°f¬~¸gÔ/Fð%ð ð& NTÐTZÌ^Ð\bÔMc×MiÒMiÑMkÔMkð'ð ð( [aÐaoÔZpÐqtÐrtÐqtÔZuð)ð ð0 8>¸nÔ7Mð1ð ð2 4:¸.Ô3Ið3ð ð4 AJð5ð ð ñ 	ô 	€Dð@ 	‡O‚OØØ�^Ô$ØØØØØð ñ ô ð ð €Kr6   z/mec                ó   — | S )uO   Láº¥y thÃ´ng tin tÃ i khoáº£n vÃ  quyá»�n háº¡n hiá»‡n táº¡i tá»« Bearer Token.rJ   )r:   s    r4   Úget_current_user_profiler‹   ì   s
   € ð
 Ðr6   z/usersr'   Údirector)Údependenciesúlist[dict[str, Any]]c                 ó.  — t                                ¦   «         5 } |                      ¦   «         5 }|                     d¦  «         |                     ¦   «         cddd¦  «         cddd¦  «         S # 1 swxY w Y   	 ddd¦  «         dS # 1 swxY w Y   dS )um   Liá»‡t kÃª toÃ n bá»™ tÃ i khoáº£n ngÆ°á»�i dÃ¹ng vÃ  vai trÃ² trong há»‡ thá»‘ng (Chá»‰ Admin/GiÃ¡m Ä‘á»‘c).aŸ  
                SELECT u.id, u.email, u.full_name, u.avatar_url, u.role, u.is_active, u.last_login_at,
                       u.failed_login_attempts, u.locked_until, u.password_changed_at,
                       e.employee_code, e.department, e.job_title
                FROM erp_users u
                LEFT JOIN employees e ON u.linked_employee_id = e.id
                ORDER BY u.created_at DESC;
            N)r1   Úget_connectionÚcursorÚexecuteÚfetchall)ÚconnÚcurs     r4   Ú
list_usersr–   ÷   s,  € õ 
×	$Ò	$Ñ	&Ô	&ð 
"¨$Ø�[Š[‰]Œ]ð 		"˜cØ�KŠKð ñ ô ð ð —<’<‘>”>ð		"ð 		"ð 		"ð 		"ñ 		"ô 		"ð 		"ð
"ð 
"ð 
"ð 
"ñ 
"ô 
"ð 
"ð 
"ð		"ð 		"ð 		"ð 		"øøøð 		"ð 		"ð 		"ð 		"ð 		"ð
"ð 
"ð 
"ñ 
"ô 
"ð 
"ð 
"ð 
"ð 
"ð 
"ð 
"ð 
"øøøð 
"ð 
"ð 
"ð 
"ð 
"ð 
"s4   šB
¯)A1ÁB
Á1A5	Á5B
Á8A5	Á9B
Â
BÂBc                ór   — t                                | j        | j        | j        | j        | j        ¬¦  «        S )uZ   Táº¡o tÃ i khoáº£n ngÆ°á»�i dÃ¹ng má»›i cÃ³ phÃ¢n quyá»�n (Chá»‰ SuperAdmin/GiÃ¡m Ä‘á»‘c).)r*   rD   r,   r+   rM   )r1   Úcreate_user_accountr*   rD   r,   r+   rM   )rU   s    r4   Úcreate_userr™     s;   € õ ×+Ò+ØŒiØ”Ø”-ØŒXØÔ1ð ,ñ ô ð r6   z/users/{user_id}/roler)   c                óÊ  — t                                ¦   «         5 }|                     ¦   «         5 }|                     d|j        | f¦  «         |                     ¦   «         }|st          dd¬¦  «        ‚|                     ¦   «          dt          |d         ¦  «        |d         dœcd	d	d	¦  «         cd	d	d	¦  «         S # 1 swxY w Y   	 d	d	d	¦  «         d	S # 1 swxY w Y   d	S )
u=   PhÃ¢n quyá»�n vai trÃ² cho ngÆ°á»�i dÃ¹ng (Chá»‰ SuperAdmin).zMUPDATE erp_users SET role = %s, updated_at = NOW() WHERE id = %s RETURNING *;i”  u/   KhÃ´ng tÃ¬m tháº¥y tÃ i khoáº£n ngÆ°á»�i dÃ¹ng.r!   ri   Úidr+   )rj   r)   Únew_roleN)	r1   r�   r‘   r’   r+   Úfetchoner   ÚcommitrC   )r)   rU   r”   r•   r}   s        r4   Úupdate_user_rolerŸ     s‹  € õ
 
×	$Ò	$Ñ	&Ô	&ð ¨$Ø�[Š[‰]Œ]ð 	˜cØ�KŠKØ_Ø”˜7Ð#ñô ð ð —<’<‘>”>ˆDØð Ý#Ø #Ð,]ðñ ô ð ð �KŠK‰MŒMˆMà#Ý˜t Dœz™?œ?Ø  œLðð ð	ð 	ð 	ð 	ñ 	ô 	ð 	ðð ð ð ñ ô ð ð ð	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s5   šC¯A7B?Â&CÂ?C	ÃCÃC	ÃCÃCÃC)r   r	   r   r   r   r   )r7   r8   )rU   rB   rV   r
   r   r   )rV   r
   r   rg   )rU   rO   r:   r   r   r   )N)rq   rE   r   r   )rq   rE   r   rg   )r{   rC   rq   rE   r   r   r?   )r   rŽ   )rU   rL   r   r   )r)   rC   rU   rT   r   r   )3Ú__doc__Ú
__future__r   rƒ   ÚloggingÚtypingr   Úfastapir   r   r   r   r	   r
   r   Úfastapi.encodersr   Úfastapi.responsesr   r   Úfastapi.securityr   r   Úpydanticr   Úapp.services.auth_servicer   Ú	getLoggerÚloggerÚrouterr1   Úsecurityr5   r@   rB   rL   rO   rT   Úpostrf   rm   rp   r.   rw   ry   r‰   r‹   r–   r™   ÚputrŸ   rJ   r6   r4   ú<module>r°      s¾  ðØ JÐ Jà "Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø Ð Ð Ð Ð Ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð .Ð -Ð -Ð -Ð -Ð -Ø <Ð <Ð <Ð <Ð <Ð <Ð <Ð <Ø EÐ EÐ EÐ EÐ EÐ EÐ EÐ EØ Ð Ð Ð Ð Ð à 1Ð 1Ð 1Ð 1Ð 1Ð 1à	ˆÔ	Ð/Ñ	0Ô	0€Ø	ˆ˜*Ð,LÐ+MÐ	NÑ	NÔ	N€Øˆ{‰}Œ}€Øˆ: Ð'Ñ'Ô'€ð 8@°xÀÑ7IÔ7Ið&0ð &0ð &0ð &0ð &0ðRð ð ð ð(!ð !ð !ð !ð !˜	ñ !ô !ð !ð*ð *ð *ð *ð *˜	ñ *ô *ð *ðð ð ð ð ˜Iñ ô ð ð
ð ð ð ð ˜Iñ ô ð ð ‡‚ˆXÑÔðð ð ñ Ôðð* ‡‚ˆYÑÔð`ð `ð `ñ Ôð`ð ‡‚ÐÑ Ô à?F¸wÐGWÑ?XÔ?Xðð ð ð ñ !Ô ðð  ‡‚ˆOÑÔð<ð <ð <ð <ñ Ôð<ð ‡‚ÐÑ Ô ðVð Vð Vð Vñ !Ô ðVð
 ‡‚ÐÑÔà��cÐ'GÐHÑHÔHØ#ð2ð 2ð 2ð 2ñ  Ôð2ðj ‡‚ˆEÑÔà#* 7Ð+;Ñ#<Ô#<ðð ð ð ñ Ôðð ‡‚ˆH G G¨L¨L¸,È
Ð9SÑ,TÔ,TÑ$UÔ$UÐ#V€ÑWÔWð"ð "ð "ñ XÔWð"ð ‡‚ˆX W W¨\¨\¸<ÈÐ:TÑ-UÔ-UÑ%VÔ%VÐ$W€ÑXÔXðð ð ñ YÔXðð ‡‚Ø¨7¨7°<°<ÀÀÑ3OÔ3OÑ+PÔ+PÐ*Qð ñ ô ðð ð ñô ðð ð r6   