
    .~hk                        d dl Z d dlZd dlZd dlZd dl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 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 ddlm Z  ddl!m"Z"  ejF                  e$      Z% ejL                  d      Z'ddZ(d Z) G d dejT                        Z+ G d dejX                        Z- G d de+      Z. G d de-      Z/y)    N)apps)settings)ImproperlyConfigured)MultipleObjectsReturned)ObjectDoesNotExist)EmailMultiAlternatives)models)transaction)TemplateDoesNotExist)render_to_string)get_random_string)import_string)now   )	UserModel)UserModelString)_z^[a-f0-9]{40,64}$c                 F   t        t        dd      rpt        t        dd      }|st        d      t        j                  dd      }| xs |j
                  j                         } dj                  || j                        }|S t        t        d	t        j                        }|S )
aC  
    Return the email address by which mail is sent.
    If the `REGISTRATION_USE_SITE_EMAIL` setting is set, the `Site` object will
    provide the domain and the REGISTRATION_SITE_USER_EMAIL will provide the
    username. Otherwise the `REGISTRATION_DEFAULT_FROM_EMAIL` or
    `DEFAULT_FROM_EMAIL` settings are used.
    REGISTRATION_USE_SITE_EMAILFREGISTRATION_SITE_USER_EMAILNzPREGISTRATION_SITE_USER_EMAIL must be set when using REGISTRATION_USE_SITE_EMAIL.sitesSitez{}@{}REGISTRATION_DEFAULT_FROM_EMAIL)
getattrr   r   r   	get_modelobjectsget_currentformatdomainDEFAULT_FROM_EMAIL)site
user_emailr   
from_emails       \/var/www/peopleoo.sandbox-dev.co.uk/venv/lib/python3.12/site-packages/registration/models.pyget_from_emailr%   !   s     x6>X'EtL
&/1 1 ~~gv.1t||//1^^J<
  X'H%88:
    c                    t        t        dd      }|t        ||      z   }dj                  |j	                               }t        |j                  d            }t        ||      }t        ||||       }	t        t        dd      r	 t        ||      }
|	j                  |
d       |	j                          y# t        $ r Y w xY w)z&
    Function that sends an email
    !REGISTRATION_EMAIL_SUBJECT_PREFIX r!   REGISTRATION_EMAIL_HTMLT	text/htmlN)r   r   r   join
splitlinesr%   getr   attach_alternativer   send)addresses_toctx_dictsubject_templatebody_templatebody_html_templateprefixsubjectr#   message_txtemail_messagemessage_htmls              r$   
send_emailr;   8   s     XBBGF'(8(CCGggg((*+GV 45J"=#+-K +7K+5|EM x2D9	H+"H.L
 ,,\;G $ 		s   B5 5	C Cc                   B    e Zd ZdZd Zd
dZdddi fdZd ZddZd	 Z	y)RegistrationManagera  
    Custom manager for the ``RegistrationProfile`` model.

    The methods defined here provide shortcuts for account creation
    and activation (including generation and emailing of activation
    keys), and for cleaning out expired inactive accounts.

    c                     |j                   }d|_        d|_        t        j                         5  |j                          |j                          ddd       |r|S |S # 1 sw Y   xY w)z
        Activate the ``RegistrationProfile`` given as argument.
        User is able to login, as ``is_active`` is set to ``True``
        TN)user	is_active	activatedr
   atomicsave)selfprofiler!   get_profiler?   s        r$   	_activatezRegistrationManager._activate_   s^    
 || ! 	IIKLLN	 NK	 	s   !AA'c                    t         j                  |      rR	 | j                  |      }|j
                  r|j                  dfS |j                         s| j                  |||      dfS y# | j                  j                  $ r Y yw xY w)aL  
        Validate an activation key and activate the corresponding ``User`` if
        valid, returns a tuple of (``User``, ``activated``). The activated flag
        indicates if the user was newly activated or an error occurred.

        If the key is valid and has not expired, return the (``User``,
        ``True``) after activating.

        If the key is not valid or has expired, return (``User`` or ``False``,
        ``False``).

        If the key is valid but the ``User`` is already active,
        return (``User``, ``False``).

        If the key is valid but the ``User`` is inactive, return (``User``,
        ``False``).

        To prevent reactivation of an account which has been
        deactivated by site administrators, ``RegistrationProfile.activated``
        is set to ``True`` after successful activation.

        )activation_key)FFFT)		SHA256_REsearchr.   modelDoesNotExistrA   r?   activation_key_expiredrG   )rD   rI   r!   rF   rE   s        r$   activate_userz!RegistrationManager.activate_userp   s    6 N+&((.(A   
  e,,113wkBDII! ::** & &	&s   A) )BBNTc                 r   |2|j                  d      } t               di |}|j                  |       d|_        t	               |_        t        j                         5  |j                           | j                  |fi ||rt        j                  fd       ddd       |S # 1 sw Y   |S xY w)a  
        Create a new, inactive ``User``, generate a
        ``RegistrationProfile`` and email its activation key to the
        ``User``, returning the new ``User``.

        By default, an activation email will be sent to the new
        user. To disable this, pass ``send_email=False``.
        Additionally, if email is sent and ``request`` is supplied,
        it will be passed to the email template.

        NpasswordFc                  (     j                        S N)send_activation_email)registration_profilerequestr!   s   r$   <lambda>z:RegistrationManager.create_inactive_user.<locals>.<lambda>   s    0FFg' r&    )popr   set_passwordr@   datetime_nowdate_joinedr
   rB   rC   create_profile	on_commit)	rD   r!   new_userr;   rV   profile_info	user_inforQ   rU   s	    `  `   @r$   create_inactive_userz(RegistrationManager.create_inactive_user   s      }}Z0H"y{/Y/H!!(+"  ,~! 
	MMO#64#6#6$*($*  %%'
	 
	 s   "A B,,B6c                 z     | j                   dd|i|}d|vr|j                  d       |j                          |S )z
        Create a ``RegistrationProfile`` for a given
        ``User``, and return the ``RegistrationProfile``.

        The activation key for the ``RegistrationProfile`` will be a
        SHA256 hash, generated from a secure random string.

        r?   rI   F)rC   rX   )rL   create_new_activation_keyrC   )rD   r?   r`   rE   s       r$   r]   z"RegistrationManager.create_profile   sC     $**7$7,7</--5-9r&   c                     	 | j                  |      }|j                  s|j	                         ry|j                          |j                  ||       y# t        $ r Y yt        $ r Y yw xY w)zR
        Resets activation key for the user and resends activation email.
        )user__email__iexactFT)r.   r   r   rA   rN   rd   rT   )rD   emailr!   rV   rE   s        r$   resend_activation_mailz*RegistrationManager.resend_activation_mail   sn    	hh5h9G  > > @))+%%dG4 " 	& 		s   A 	A*A*)A*c                    | j                  t        j                  d      t        j                  d      z  d      }d}|D ]j  }	 |j                         rW|j                  }t
        j                  dj                  ||             	 |j                          |j                          |d	z  }l |S # t        j                  t        j                  f$ r/}t
        j                  dj                  ||             Y d}~Vd}~ww xY w# t               j                  $ r= t
        j                  d
j                  |             |j                          |d	z  }Y w xY w)a  
        Remove expired instances of ``RegistrationProfile`` and their
        associated ``User``s.

        Accounts to be deleted are identified by searching for instances of
        ``RegistrationProfile`` with expired activation keys and an
        ``activated`` field that is set to ``False``. If these conditions are
        met both the ``RegistrationProfile`` and the ``User`` objects will be
        deleted.

        It is recommended that this method be executed regularly as
        part of your routine site maintenance; this application
        provides a custom management command which will call this
        method, accessible as ``manage.py cleanupregistration``.

        Regularly clearing out accounts which have never been
        activated serves two useful purposes:

        1. It alleviates the occasional need to reset a
           ``RegistrationProfile`` and/or re-send an activation email
           when a user does not receive or does not act upon the
           initial activation email; since the account will be
           deleted, the user will be able to simply re-register and
           receive a new activation key.

        2. It prevents the possibility of a malicious user registering
           one or more accounts and never activating them (thus
           denying the use of those usernames to anyone else); since
           those accounts will be deleted, the usernames will become
           available for use again.

        If you have a troublesome ``User`` and wish to disable their
        account while keeping it in the database, simply delete the
        associated ``RegistrationProfile``; an inactive ``User`` which
        does not have an associated ``RegistrationProfile`` will not
        be deleted.

        F)user__is_activeNr?   )rA   r   z5Deleting expired Registration profile {} and user {}.z$Deletion of user {} is prevented: {}r   z(Deleting expired Registration profile {})filterr	   QrN   r?   loggerwarningr   deleteProtectedErrorRestrictedErrorerrorr   rM   )rD   profilesdeleted_countrE   r?   es         r$   delete_expired_usersz(RegistrationManager.delete_expired_users   s8   N ;;HHU+fhhD.AA  
  	#G#113"<<DNN#Z#a#abiko#pq]( "Q&M	#  #1163I3IJ ]%K%R%RSWYZ%[\\] ;++ #IPPQXYZ "#s>   AD	 B2)D2#D%C?:D?DDAEE)FrS   )
__name__
__module____qualname____doc__rG   rO   rb   r]   rh   rw   rX   r&   r$   r=   r=   U   s3    ".` 374%)#J$&;r&   r=   c                       e Zd ZdZ ej
                   e       ej                   ed            Z	 ej                   ed      d      Z ej                  d      Z e       Z G d	 d
      Zd ZddZd ZddZy)RegistrationProfileaT  
    A simple profile which stores an activation key for use during
    user account registration.

    Generally, you will not want to interact directly with instances
    of this model; the provided manager includes methods
    for creating and activating new accounts, as well as for cleaning
    out accounts which have never been activated.

    While it is possible to use this model as the value of the
    ``AUTH_PROFILE_MODULE`` setting, it's not recommended that you do
    so. This model's sole purpose is to store data temporarily during
    account registration and activation.

    r?   )	on_deleteverbose_namezactivation key@   )
max_lengthF)defaultc                   ,    e Zd Z ed      Z ed      Zy)RegistrationProfile.Metazregistration profilezregistration profilesN)rx   ry   rz   r   r   verbose_name_pluralrX   r&   r$   Metar   C  s    /0 78r&   r   c                      d| j                   z  S )NzRegistration information for %srk   )rD   s    r$   __str__zRegistrationProfile.__str__G  s    0499<<r&   c                     t        dt        j                        }t        j                  |j                               j                         | _        |r| j                          | j                  S )z:
        Create a new activation key for the user
            )lengthallowed_chars)	r   string	printablehashlibsha256encode	hexdigestrI   rC   )rD   rC   random_strings      r$   rd   z-RegistrationProfile.create_new_activation_keyJ  sZ     *V%5%57%nn  "$$-IK 	 IIK"""r&   c                     t        j                  t        j                        }| j                  j
                  |z   }| j                  xs |t               k  S )aJ  
        Determine whether this ``RegistrationProfile``'s activation
        key has expired, returning a boolean -- ``True`` if the key
        has expired.

        Key expiration is determined by a two-step process:

        1. If the user has already activated, ``self.activated`` will
           be ``True``. Re-activating is not permitted, and so this
           method returns ``True`` in this case.

        2. Otherwise, the date the user signed up is incremented by
           the number of days specified in the setting
           ``ACCOUNT_ACTIVATION_DAYS`` (which should be the number of
           days after signup during which a user is allowed to
           activate their account); if the result is less than or
           equal to the current date, the key has expired and this
           method returns ``True``.

        days)datetime	timedeltar   ACCOUNT_ACTIVATION_DAYSr?   r\   rA   r[   )rD   max_expiry_daysexpiration_dates      r$   rN   z*RegistrationProfile.activation_key_expiredX  sG    * #,,113))///A~~BLN!BBr&   Nc                 X   t        t        dd      }t        t        dd      }t        t        dd      }| j                  | j                  t        j                  |d}t        t        dd	      }|t        |||
      z   }d	j                  |j                               }t        |      }	t        |||
      }
t        ||
|	| j                  j                  g      }t        t        dd      r!	 t        |||
      }|j                  |d       |j                          y# t        $ r Y w xY w)a  
        Send an activation email to the user associated with this
        ``RegistrationProfile``.

        The activation email will use the following templates,
        which can be overridden by setting ACTIVATION_EMAIL_SUBJECT,
        ACTIVATION_EMAIL_BODY, and ACTIVATION_EMAIL_HTML appropriately:

        ``registration/activation_email_subject.txt``
            This template will be used for the subject line of the
            email. Because it is used as the subject line of an email,
            this template's output **must** be only a single line of
            text; output longer than one line will be forcibly joined
            into only a single line.

        ``registration/activation_email.txt``
            This template will be used for the text body of the email.

        ``registration/activation_email.html``
            This template will be used for the html body of the email.

        These templates will each receive the following context
        variables:

        ``user``
            The new user account

        ``activation_key``
            The activation key for the new account.

        ``expiration_days``
            The number of days remaining during which the account may
            be activated.

        ``site``
            An object representing the site on which the user
            registered; depending on whether ``django.contrib.sites``
            is installed, this may be an instance of either
            ``django.contrib.sites.models.Site`` (if the sites
            application is installed) or
            ``django.contrib.sites.requests.RequestSite`` (if
            not). Consult the documentation for the Django sites
            framework for details regarding these objects' interfaces.

        ``request``
            Optional Django's ``HttpRequest`` object from view.
            If supplied will be passed to the template for better
            flexibility via ``RequestContext``.
        ACTIVATION_EMAIL_SUBJECTz)registration/activation_email_subject.txtACTIVATION_EMAIL_BODYz!registration/activation_email.txtACTIVATION_EMAIL_HTMLz"registration/activation_email.html)r?   rI   expiration_daysr!   r(   r)   )rV   r*   Tr+   N)r   r   r?   rI   r   r   r,   r-   r%   r   rg   r/   r   r0   )rD   r!   rV   activation_email_subjectactivation_email_bodyactivation_email_htmlr2   r6   r7   r#   r8   r9   r:   s                r$   rT   z)RegistrationProfile.send_activation_emailr  s@   d $+85O+V$X  '2I(K!M '2I(L!N II"11'??	
 #FK+$h
 

 ''',,./#D)
&'<'/B /w/9DIIOO;LN 86=L/)8W F
 00{K ( s   ,D 	D)(D))TrS   )rx   ry   rz   r{   r	   OneToOneFieldr   CASCADEr   r?   	CharFieldrI   BooleanFieldrA   r=   r   r   r   rd   rN   rT   rX   r&   r$   r}   r}   (  s       6..vYD
 &V%%a(8&9bIN###E2I!#G9 9=#C4Vr&   r}   c                   (    e Zd Zd Zd ZddZddZy)SupervisedRegistrationManagerc                     t        j                  t        j                        }| j                  xr | j
                  j                  }|xs$ | j
                  j                  |z   t               k  S )aE  
        Determine whether this ``RegistrationProfile``'s activation
        key has expired, returning a boolean -- ``True`` if the key
        has expired.

        Key expiration is determined by a two-step process:

        1. If the user has already activated, ``self.activated`` and
        `self.user.is_active`` will be ``True``.  Re-activating is not
        permitted, and so this method returns ``True`` in this case.

        2. Otherwise, the date the user signed up is incremented by the number
        of days specified in the setting ``ACCOUNT_ACTIVATION_DAYS`` (which
        should be the number of days after signup during which a user is
        allowed to activate their account); if the result is less than or equal
        to the current date, the key has expired and this method returns
        ``True``.
        r   )	r   r   r   r   rA   r?   r@   r\   r[   )rD   r   is_activateds      r$   rN   z4SupervisedRegistrationManager.activation_key_expired  sX    & #,,113 ~~=$))*=*=Y		 5 5 G<> YZr&   c                     |j                   j                  s(|j                  s| j                  |j                   |       d|_        |j	                          |r|S |j                   S )z
        Activate the ``SupervisedRegistrationProfile`` given as argument.

        Send an email to the site administrators to approve the user.

        User is not able to login yet, as ``is_active`` is not yet ``True``
        T)r?   r@   rA   send_admin_approve_emailrC   )rD   rE   r!   rF   s       r$   rG   z'SupervisedRegistrationManager._activate  sR     ||%%g.?.?))',,= !N<<r&   Nc                    	 t         j                  j                  |      }|j                  r"|j                  j
                  r|j                  S |j                  rd|j                  _        ny|j                  j                          |j                  ||       |r|S |j                  S # | j                  j                  $ r Y yw xY w)a  
        Approve the ``SupervisedRegistrationProfile``
        object with the given ``profile_id``.

        If the id is valid, return the ``User``
        after approving.

        If the id is not valid, return ``False``.

        If the id is valid but the ``User`` is already active,
        return ``User``.

        If the id is valid but the ``SupervisedRegistrationProfile``
        object is not activated, return ``False``.
        )idTF)
SupervisedRegistrationProfiler   r.   rA   r?   r@   rC   !send_admin_approve_complete_emailrL   rM   )rD   
profile_idr!   rF   rV   rE   s         r$   admin_approve_userz0SupervisedRegistrationManager.admin_approve_user  s     	3;;??:?NG  <<))"<<'
   )-&LL55dGD||#zz&& 		s$   AB+ B+ //B+ B+ +CCc                    t        t        dd      }t        t        dd      }t        t        dd      }||j                  j                  |d}t        t        dd	      }t	        |t
              rt        |      }	 |	       }
n|xs t        t        d
d	      }
|st        j                  dt               |
st        d      |
D cg c]  }|d   	 }
}t        |
||||       y	c c}w )aM  
        Send an approval email to the site administrators to
        approve this user.

        The approval email will use the following templates,
        which can be overridden by setting APPROVAL_EMAIL_SUBJECT,
        APPROVAL_EMAIL_BODY, and APPROVAL_EMAIL_HTML appropriately:

        ``registration/admin_approve_email_subject.txt``
            This template will be used for the subject line of the
            email. Because it is used as the subject line of an email,
            this template's output **must** be only a single line of
            text; output longer than one line will be forcibly joined
            into only a single line.

        ``registration/admin_approve_email.txt``
            This template will be used for the text body of the email.

        ``registration/admin_approve_email.html``
            This template will be used for the html body of the email.

        These templates will each receive the following context
        variables:

        ``user``
            The new user account

        ``profile_id``
            The id of the associated``SupervisedRegistrationProfile``
            object.

        ``site``
            An object representing the site on which the user
            registered; depending on whether ``django.contrib.sites``
            is installed, this may be an instance of either
            ``django.contrib.sites.models.Site`` (if the sites
            application is installed) or
            ``django.contrib.sites.requests.RequestSite`` (if
            not). Consult the documentation for the Django sites
            framework for details regarding these objects' interfaces.

        ``request``
            Optional Django's ``HttpRequest`` object from view.
            If supplied will be passed to the template for better
            flexibility via ``RequestContext``.
        ADMIN_APPROVAL_EMAIL_SUBJECTz,registration/admin_approve_email_subject.txtADMIN_APPROVAL_EMAIL_BODYz$registration/admin_approve_email.txtADMIN_APPROVAL_EMAIL_HTMLz%registration/admin_approve_email.html)r?   r   r!   REGISTRATION_ADMINSNADMINSzkNo registration admin defined in settings.REGISTRATION_ADMINS. Using settings.ADMINS for the admin approvalz|Using the admin_approval registration backend requires at least one admin in settings.ADMINS or settings.REGISTRATION_ADMINSr   )r   r   registrationprofiler   
isinstancestrr   warningswarnUserWarningr   r;   )rD   r?   r!   rV   admin_approve_email_subjectadmin_approve_email_bodyadmin_approve_email_htmlr2   registration_adminsadmins_getteradminsadmins               r$   r   z6SupervisedRegistrationManager.send_admin_approve_email$  s
   ` '.*:'
#
 $+'2$
 
 $+'3$
  2255

 &h0EtL)3/)*=>M"_F(MGHh,MF"MM J &' &34 4
 )//u%(//H9$&>	
 0s   C")FNrS   )rx   ry   rz   rN   rG   r   r   rX   r&   r$   r   r     s    [4 *&PZ
r&   r   c                   "    e Zd Z e       ZddZy)r   Nc                     t        t        dd      }t        t        dd      }t        t        dd      }| j                  |d}t        | j                  j                  g||||       y)	a*  
        Send an "approval is complete" email to the user associated with this
        ``SupervisedRegistrationProfile``.

        The email will use the following templates,
        which can be overridden by settings APPROVAL_COMPLETE_EMAIL_SUBJECT,
        APPROVAL_COMPLETE_EMAIL_BODY, and APPROVAL_COMPLETE_EMAIL_HTML appropriately:

        ``registration/admin_approve_complete_email_subject.txt``
            This template will be used for the subject line of the
            email. Because it is used as the subject line of an email,
            this template's output **must** be only a single line of
            text; output longer than one line will be forcibly joined
            into only a single line.

        ``registration/admin_approve_complete_email.txt``
            This template will be used for the text body of the email.

        ``registration/admin_approve_complete_email.html``
            This template will be used for the text body of the email.

        These templates will each receive the following context
        variables:

        ``user``
            The new user account

        ``site``
            An object representing the site on which the user
            registered; depending on whether ``django.contrib.sites``
            is installed, this may be an instance of either
            ``django.contrib.sites.models.Site`` (if the sites
            application is installed) or
            ``django.contrib.sites.requests.RequestSite`` (if
            not). Consult the documentation for the Django sites
            framework for details regarding these objects' interfaces.

        ``request``
            Optional Django's ``HttpRequest`` object from view.
            If supplied will be passed to the template for better
            flexibility via ``RequestContext``.
        APPROVAL_COMPLETE_EMAIL_SUBJECTz5registration/admin_approve_complete_email_subject.txtAPPROVAL_COMPLETE_EMAIL_BODYz-registration/admin_approve_complete_email.txtAPPROVAL_COMPLETE_EMAIL_HTMLz.registration/admin_approve_complete_email.html)r?   r!   N)r   r   r?   r;   rg   )rD   r!   rV   $admin_approve_complete_email_subject!admin_approve_complete_email_body!admin_approve_complete_email_htmlr2   s          r$   r   z?SupervisedRegistrationProfile.send_admin_approve_complete_email  s|    V 077C0E, -44;-=) -44<->)
 II
 	YY__x0--		
r&   rS   )rx   ry   rz   r   r   r   rX   r&   r$   r   r     s    
 ,-G>
r&   r   rS   )0r   r   loggingrer   r   django.appsr   django.confr   django.core.exceptionsr   r   r   django.core.mailr   	django.dbr	   r
   django.templater   django.template.loaderr   django.utils.cryptor   django.utils.module_loadingr   django.utils.timezoner   r[   usersr   r   utilsr   	getLoggerrx   rn   compilerJ   r%   r;   Managerr=   Modelr}   r   r   rX   r&   r$   <module>r      s       	      7 : 5 3  ! 0 3 1 5 5  " 			8	$ BJJ*+	.:P&.. Pf`&,, `Fs
$7 s
lE
$7 E
r&   