U
    ̖mhc                     @   s  d Z ddlZddlmZ ddlmZ ddlmZ ddlm	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mZ G dd deZG dd deZG dd deeeZG dd deZG dd deZG dd deZG dd deZG dd deZdS )aB  
Adtlas Accounts Models

This module contains the custom user authentication models for the Adtlas DAI Management System.
It implements a flexible role-based permission system with dynamic roles and comprehensive
user management capabilities.

Features:
    - Custom User model with email-based authentication
    - Dynamic Role system with hierarchical permissions
    - User profiles with detailed information
    - Activity tracking and session management
    - Department-based organization structure

Author: Adtlas Development Team
Version: 2.0.0
Last Updated: 2025-07-08
    N)models)reverse)timezone)RegexValidator)gettext_lazy)ContentType)AbstractUserPermissionsMixin
Permission)UserManager)	BaseModelTimeStampedModelc                   @   s   e Zd ZdZejddddZejddeddgd	d
Zej	dddZ
ejdejdddddZejdejdddddZejdddZG dd dZdd Zdd Zdd ZdS )
Departmentz
    Department model for organizing users within the company structure.
    Departments can have hierarchical relationships and specific permissions.
    d   Tz2Department name (e.g., 'Marketing', 'Sales', 'IT')
max_lengthunique	help_text   z^[A-Z]{2,20}$z#Code must be uppercase letters onlyz,Department code (e.g., 'MKT', 'SALES', 'IT')r   r   
validatorsr   z9Detailed description of the department's responsibilitiesblankr   selfchildrenz,Parent department for hierarchical structure	on_deletenullr   related_namer   zaccounts.UserZheaded_departmentszDepartment head/managerz+Whether this department is currently activedefaultr   c                   @   s   e Zd ZdZdgZdZdZdS )zDepartment.MetaZaccounts_departmentsnamer   ZDepartmentsN)__name__
__module____qualname__db_tableorderingverbose_nameverbose_name_plural r)   r)   0/var/www/html/Adtlas/src/apps/accounts/models.pyMetaQ   s   r+   c                 C   s   | j  d| j dS )N ())r!   coder   r)   r)   r*   __str__W   s    zDepartment.__str__c                 C   s0   t | j }| j D ]}||  q|S )z%Get all child departments recursively)listr   allextendget_all_children)r   r   childr)   r)   r*   r4   Z   s    zDepartment.get_all_childrenc                 C   s(   ddl m} | g|   }tjj|dS )z1Get all users in this department and its childrenr   )Q)Zprofile__department__in)django.db.modelsr6   r4   Userobjectsfilter)r   r6   Zdepartmentsr)   r)   r*   get_all_usersa   s    zDepartment.get_all_usersN)r"   r#   r$   __doc__r   	CharFieldr!   r   r.   	TextFielddescription
ForeignKeyCASCADEparentSET_NULLheadBooleanField	is_activer+   r0   r4   r;   r)   r)   r)   r*   r   "   sP   
		r   c                   @   s  e Zd ZdZddddgZejddeded	d
Zejdde	ddgddZ
ejdededdZejdedddZejdejdddddZejedededdZejdededdZejd ed!d"dZejd#d$d%ZG d&d' d'Zd(d) Zd*d+ Zd/d-d.Zd,S )0Rolez
    Role model for dynamic role management.
    
    This model allows creating custom roles with specific permissions
    that can be assigned to users for flexible access control.
    )systemzSystem Role)customzCustom Role)
departmentzDepartment Role)ZprojectzProject Roler   Tz	Role NamezGUnique name for the role (e.g., 'Campaign Manager', 'Analytics Viewer'))r   r   r'   r   2   z	^[a-z_]+$z,Code must be lowercase with underscores onlyz<Role code for programmatic access (e.g., 'campaign_manager')r   DescriptionzCDetailed description of the role's responsibilities and permissionsr   r'   r   r   rI   zType of role for categorizationr   choicesr    r   r   Zchild_roleszParent role for inheritancer   ZPermissionsz*Specific permissions assigned to this rolez	Is Activez%Whether this role is currently activer    r'   r      Priorityz*Role hierarchy level (1=highest, 5=lowest)Fz,Whether this is a default role for new usersr   c                   @   s(   e Zd ZedZedZdZddgZdS )z	Role.MetarG   ZRolesZaccounts_roleslevelr!   N)r"   r#   r$   _r'   r(   r%   r&   r)   r)   r)   r*   r+      s   r+   c                 C   s   | j  d| j dS )z"String representation of the role.z (Level r-   )r!   rS   r/   r)   r)   r*   r0      s    zRole.__str__c                 C   s(   t | j }| jr$|| j  |S )z9Get all permissions including inherited from parent roles)setpermissionsr2   parent_roleupdateget_all_permissions)r   rV   r)   r)   r*   rY      s    zRole.get_all_permissionsNc                 C   sH   |   }|D ]6}|r2|j|krB|jj|krB dS q|j|kr dS qdS )z%Check if role has specific permissionTF)rY   codenamecontent_type	app_label)r   Zpermission_codenamer\   rV   permr)   r)   r*   has_permission   s    
zRole.has_permission)N)r"   r#   r$   r<   Z
ROLE_TYPESr   r=   rT   r!   r   r.   r>   r?   	role_typer@   rA   rW   ManyToManyFieldr
   rV   rE   rF   PositiveIntegerFieldrS   
is_defaultr+   r0   rY   r^   r)   r)   r)   r*   rG   h   sz   

rG   c                       s  e Zd ZdZejeddddZejddddddZ	ejddd	d
Z
ejdddd
ZejdddZejdddZejdededdZejddededdZejddededdZejejddZejddddZejddddZejdddZejddddZejejddZejdd dZe Zd!Z d"d#d$gZ!G d%d& d&Z"d'd( Z#d)d* Z$d+d, Z%d-d. Z&d/d0 Z'd1d2 Z(d3d4 Z)d5d6 Z*d7d8 Z+d9d: Z,d;d< Z- fd=d>Z. fd?d@Z/dAdB Z0  Z1S )Cr8   a?  
    Custom User model with email-based authentication and enhanced features.
    
    This model replaces Django"s default User model and provides:
    - Email-based authentication
    - Enhanced profile information
    - Role-based access control
    - Activity tracking
    - Multi-factor authentication support
    zEmail AddressTz%User's email address (used for login))r   r      z&Optional username for display purposes)r   r   r   r   r   zUser's first namer   r   r   zUser's last namez8Designates whether this user should be treated as activer   Fz7Designates whether the user can log into the admin sitezIs Verifiedz$Whether the user's email is verifiedrP   zLast Login IPzIP address of last loginr   r   r'   r   zEmail Verified AtzWhen the email was verifiedz&Date when the user account was createdzLast time the user logged inr   r   r   z+Last time the user was active in the systemr   z+Number of consecutive failed login attemptszAccount lockout expiration timez"When the password was last changedz.Whether multi-factor authentication is enabledemailusername
first_name	last_namec                   @   sP   e Zd ZedZedZdZdgZej	dgdej	ddgdej	d	gdgZ
d
S )z	User.Metar8   ZUsersZaccounts_usersz-date_joinedrg   fieldsrF   is_verifieddate_joinedN)r"   r#   r$   rT   r'   r(   r%   r&   r   Indexindexesr)   r)   r)   r*   r+   I  s   r+   c                 C   s.   | j r(| jr(| j  d| j d| j dS | jS )N r,   r-   )ri   rj   rg   r/   r)   r)   r*   r0   T  s    zUser.__str__c                 C   s   | j  d| j  p| jS )zGet user"s full name.rq   )ri   rj   striprh   r/   r)   r)   r*   get_full_nameY  s    zUser.get_full_namec                 C   s   | j p
| jS )zGet user"s short name.)ri   rh   r/   r)   r)   r*   get_short_name]  s    zUser.get_short_namec                 C   s   | j rt | j k S dS )z)Check if the account is currently locked.F)account_locked_untilr   nowr/   r)   r)   r*   is_account_lockeda  s    zUser.is_account_lockedc                 C   s    d| _ d| _| jddgd dS )zUnlock the user account.Nr   ru   failed_login_attemptsupdate_fields)ru   rx   saver/   r)   r)   r*   unlock_accountg  s    zUser.unlock_accountc                 C   s   t jj| dddS )z+Get all active roles assigned to this user.T)Zuserrole__userZuserrole__is_activerF   )rG   r9   r:   r/   r)   r)   r*   	get_rolesm  s
    zUser.get_rolesc                 C   s   |   j|d S )z"Check if user has a specific role.)r.   )r}   r:   exists)r   Z	role_coder)   r)   r*   has_roleu  s    zUser.has_rolec                 C   s   |   d S )z%Get the user"s highest priority role.rS   )r}   order_byfirstr/   r)   r)   r*   get_highest_roley  s    zUser.get_highest_rolec                 C   s(   |   }|D ]}|d|r dS qdS )z(Check if user can access a specific app.viewTF)r}   r^   )r   r\   Zrolesroler)   r)   r*   can_access_app}  s
    zUser.can_access_appc                 C   s$   d| _ t | _| jddgd dS )zMark user"s email as verified.Trm   email_verified_atry   N)rm   r   rv   r   r{   r/   r)   r)   r*   verify_email  s    
zUser.verify_emailc                 C   s   || _ | jdgd dS )z$Update user"s last login IP address.last_login_ipry   N)r   r{   )r   
ip_addressr)   r)   r*   update_last_login_ip  s    zUser.update_last_login_ipc                    s    t    | jr| j | _dS )zValidate the model data.N)supercleanrg   lowerr/   	__class__r)   r*   r     s    
z
User.cleanc                    s   |    t j|| dS )z"Override save to add custom logic.N)
full_cleanr   r{   )r   argskwargsr   r)   r*   r{     s    z	User.savec                 C   s   t dd| jidS z-Return the absolute URL for the user profile.zaccounts:profilepk)r   )r   r   r/   r)   r)   r*   get_absolute_url  s    zUser.get_absolute_url)2r"   r#   r$   r<   r   
EmailFieldrT   rg   r=   rh   ri   rj   rE   rF   is_staffrm   GenericIPAddressFieldr   DateTimeFieldr   r   rv   rn   
last_loginlast_activityra   rx   ru   Zpassword_changed_atZmfa_enabledr   r9   USERNAME_FIELDREQUIRED_FIELDSr+   r0   rs   rt   rw   r|   r}   r   r   r   r   r   r   r{   r   __classcell__r)   r)   r   r*   r8      s   
r8   c                   @   s  e Zd ZdZejeejdededdZ	e
deddZejed	egd
ddeddZejeddddeddZejedddeddZejddededdZejedddeddZejedddeddZejdededd Zejeejddd!d"d#Zejd$dddd%d&Zejddd'd(Zejeejddd)d*d#Zejd$d+d,d-Zejd.d/d0d-Z ejd1d2d3d4gd5d6d7Z!ej"dd8d9Z#ej"d:ed;ed<d=Z$ej"ded>ed?d=Z%ejed@dAdedBdZ&ejedCdAdedDdZ'ejedEddedEdZ(ejedFddedGdZ)ejedHd1dedIdZ*ejedJddedJdZ+ejdddKdZ,ejd1ddLdZ-G dMdN dNZ.dOdP Z/dQdR Z0dSdT Z1dUdV Z2dWS )XProfilez
    Extended user profile model for additional user information.
    
    This model stores additional user data that doesn"t belong
    in the core User model, following the principle of separation of concerns.
    Zprofiler8   zAssociated user account)r   r   r'   r   z^\+?1?\d{9,15}$zRPhone number must be entered in the format: '+999999999'. Up to 15 digits allowed.)regexmessagezPhone Number   TzUser's phone number)r   r   r   r   r   ZAvatarzavatars/%Y/%m/zUser's profile picture)	upload_tor   r   r   Z	Biographyi  zUser's biography or descriptionrd   z
Birth DatezUser's birth datere   z	Job Titler   zUser job title or positionZCompanyzUser company or organizationZWebsitezUser's website URLrM   usersz"User department within the companyr   rK   zEmployee ID or staff number)r   r   r   r   r   zDate when the user was hiredrf   ZsubordinateszUser's direct managerUTCzUser's preferred timezone)r   r    r   
   enzUser's preferred languager   )lightzLight Theme)darkz
Dark Theme)autozAuto (System)r   zUser's preferred UI themerN   z Whether to receive notificationsr   FzSMS NotificationszReceive SMS notificationsrP   zEmail NotificationszReceive email notificationszAddress Line 1   zStreet addresszAddress Line 2zApartment, suite, etc.ZCityzState/ProvincezState or provincezPostal CodezZIP or postal codeZCountryzEmergency contact person namezEmergency contact phone numberc                   @   s&   e Zd ZedZedZdgZdZdS )zProfile.Metar   ZProfiles-created_atZaccounts_profileN)r"   r#   r$   rT   r'   r(   r&   r%   r)   r)   r)   r*   r+   s  s   r+   c                 C   s   d| j  p| j j S )z*String representation of the user profile.zProfile for )userrs   rg   r/   r)   r)   r*   r0   y  s    zProfile.__str__c                 C   s@   | j r<t  }|j| j j |j|jf| j j| j jfk  S dS )z,Calculate user"s age based on date of birth.N)Zdate_of_birthr   rv   dateyearmonthday)r   todayr)   r)   r*   get_age}  s    zProfile.get_agec                 C   s   | j r| j jS dS )z!Get avatar URL or default avatar.z!/static/images/default-avatar.png)avatarurlr/   r)   r)   r*   get_avatar_url  s    zProfile.get_avatar_urlc                 C   s   t dd| jjidS r   )r   r   r   r/   r)   r)   r*   r     s    zProfile.get_absolute_urlN)3r"   r#   r$   r<   r   OneToOneFieldr8   rA   rT   r   r   Zphone_regexr=   Zphone_number
ImageFieldr   r>   Zbio	DateFieldZ
birth_dateZ	job_titleZcompanyURLFieldZwebsiter@   r   rC   rJ   Zemployee_idZ	hire_datemanagerr   languageZthemerE   Znotifications_enabledZsms_notificationsZemail_notificationsZaddress_line1Zaddress_line2ZcitystateZpostal_codecountryZemergency_contact_nameZemergency_contact_phoner+   r0   r   r   r   r)   r)   r)   r*   r     sP  

		
	r   c                   @   s   e Zd ZdZejeejddZeje	ejddZ
ejeejdddddZejejd	d
Zejejdd
ZejddddZejddd
ZejdddZG dd dZdd Zdd ZdS )UserRolez
    Junction model for User-Role relationships with temporal aspects.
    Allows users to have multiple roles with validity periods.
    zUser assigned to this role)r   r   zRole assigned to the userTZassigned_roleszUser who assigned this roler   zWhen this role was assignedr   z'When this role assignment becomes validz!When this role assignment expiresrf   z0Whether this role assignment is currently activez+Additional notes about this role assignmentr   c                   @   s&   e Zd ZdZddgZdZdZdgZdS )zUserRole.MetaZaccounts_user_rolesr   r   z	User Rolez
User Rolesz-assigned_atN)r"   r#   r$   r%   unique_togetherr'   r(   r&   r)   r)   r)   r*   r+     s
   r+   c                 C   s    | j  p| j j d| jj S N - )r   rs   rg   r   r!   r/   r)   r)   r*   r0     s    zUserRole.__str__c                 C   s,   t  }| jo*| j|ko*| jdkp*| j|kS )z0Check if the role assignment is currently valid.N)r   rv   rF   
valid_fromvalid_until)r   rv   r)   r)   r*   is_valid  s    zUserRole.is_validN)r"   r#   r$   r<   r   r@   r8   rA   r   rG   r   rC   Zassigned_byr   r   rv   Zassigned_atr   r   rE   rF   r>   Znotesr+   r0   r   r)   r)   r)   r*   r     sV   r   c                   @   s   e Zd ZdZejeejdddZej	ddddZ
ejddd	d
ZejdddZej	ddddZejdddZejejddZejddZG dd dZdd Zdd ZdS )UserSessionzB
    Track user sessions for security and analytics purposes.
    sessionsz!User associated with this sessionr   r   r   (   TzDjango session keyr   zIP address of the sessionrf   Browser user agent stringr      z"Geographic location (if available)rd   z'Whether the session is currently activer   zLast activity timestampzWhen the session expiresr   c                   @   s   e Zd ZdZdZdZdgZdS )zUserSession.MetaZaccounts_user_sessionszUser SessionzUser Sessionsz-last_activityNr"   r#   r$   r%   r'   r(   r&   r)   r)   r)   r*   r+     s   r+   c                 C   s   | j j d| jd d  dS )Nr      z...)r   rg   session_keyr/   r)   r)   r*   r0     s    zUserSession.__str__c                 C   s   t  | jkS )z!Check if the session has expired.r   rv   
expires_atr/   r)   r)   r*   
is_expired  s    zUserSession.is_expiredN)r"   r#   r$   r<   r   r@   r8   rA   r   r=   r   r   r   r>   
user_agentlocationrE   rF   r   r   rv   r   r   r+   r0   r   r)   r)   r)   r*   r     sP   r   c                	   @   s   e Zd ZdZdddddddd	d
g	ZejeejdddZ	ej
deddZej
ddddZej
ddddZej
ddddZejedddZejddddZejdddZG dd dZd d! Zd"S )#UserActivityzA
    Track user activities for audit and analytics purposes.
    )loginLogin)logoutLogout)createCreate)readView)rX   Update)deleteDelete)exportExport)importImport)adminzAdmin ActionZ
activitieszUser who performed the actionr   r   zType of action performed)r   rO   r   rK   Tz$Type of object affected (model name)rd   zID of the affected objectr   z,String representation of the affected objectz#Additional details about the action)r    r   r   z.IP address from which the action was performedrf   r   r   c                   @   sJ   e Zd ZdZdZdZdgZejddgdejdgdejd	d
gdgZ	dS )zUserActivity.MetaZaccounts_user_activitieszUser ActivityzUser Activitiesr   r   actionrk   
created_atobject_type	object_idN)
r"   r#   r$   r%   r'   r(   r&   r   ro   rp   r)   r)   r)   r*   r+   E  s   r+   c                 C   s   | j j d| j d| j S r   )r   rg   r   r   r/   r)   r)   r*   r0   P  s    zUserActivity.__str__N)r"   r#   r$   r<   ZACTION_TYPESr   r@   r8   rA   r   r=   r   r   r   object_repr	JSONFielddictdetailsr   r   r>   r   r+   r0   r)   r)   r)   r*   r     sj   r   c                   @   s   e Zd ZdZejeejdddZej	e
jdddZejdd	Zejd
ddZejddddZG dd dZdd Zdd Zdd ZdS )PasswordResetTokenz7
    Secure password reset tokens with expiration.
    Zreset_tokenszUser requesting password resetr   TzUnique reset token)r    r   r   zWhen the token expiresr   FzWhether the token has been usedr   z)IP address from which reset was requestedrf   c                   @   s   e Zd ZdZdZdZdgZdS )zPasswordResetToken.MetaZaccounts_password_reset_tokenszPassword Reset TokenzPassword Reset Tokensr   Nr   r)   r)   r)   r*   r+   q  s   r+   c                 C   s   d| j j S )NzReset token for )r   rg   r/   r)   r)   r*   r0   w  s    zPasswordResetToken.__str__c                 C   s   t  | jkS )zCheck if the token has expired.r   r/   r)   r)   r*   r   z  s    zPasswordResetToken.is_expiredc                 C   s   | j  o|   S )z$Check if the token is valid for use.)is_usedr   r/   r)   r)   r*   r   ~  s    zPasswordResetToken.is_validN)r"   r#   r$   r<   r   r@   r8   rA   r   	UUIDFielduuiduuid4tokenr   r   rE   r   r   r   r+   r0   r   r   r)   r)   r)   r*   r   T  s8   r   ) r<   r   	django.dbr   django.urlsr   django.utilsr   Zdjango.core.validatorsr   django.utils.translationr   rT   "django.contrib.contenttypes.modelsr   django.contrib.auth.modelsr   r	   r
   Zapps.accounts.managersr   apps.common.modelsr   r   r   rG   r8   r   r   r   r   r   r)   r)   r)   r*   <module>   s(   Fo L pB8I