1+ import hashlib
2+
13from django .conf import settings
24from django .contrib .auth .base_user import BaseUserManager
35from django .contrib .auth .models import AbstractUser
46from django .db import models
7+ from django .dispatch import Signal
58from django .utils .crypto import get_random_string , salted_hmac
69from django .utils .translation import gettext_lazy as _
710
1114 from django .db .models import EmailField as CIEmailField
1215
1316
17+ AnonymizeUserSignal = Signal ()
18+ """
19+ Signal that is emitted when a user and all their data should be anonymized.
20+
21+ Usage::
22+
23+ from mailauth.contrib.user.models import AnonymizeUserSignal
24+
25+ @receiver(AnonymizeUserSignal)
26+ def anonymize_user(sender, user, **kwargs):
27+ # Do something with related user data
28+ user.related_model.delete()
29+
30+ """
31+
32+
1433class EmailUserManager (BaseUserManager ):
1534 use_in_migrations = True
1635
@@ -50,7 +69,9 @@ class AbstractEmailUser(AbstractUser):
5069 username = None
5170 password = None
5271
53- email = CIEmailField (_ ("email address" ), unique = True , db_index = True )
72+ email = CIEmailField (
73+ _ ("email address" ), blank = True , null = True , unique = True , db_index = True
74+ )
5475 """Unique and case insensitive to serve as a better username."""
5576
5677 session_salt = models .CharField (
@@ -67,6 +88,9 @@ def has_usable_password(self):
6788
6889 class Meta (AbstractUser .Meta ):
6990 abstract = True
91+ permissions = [
92+ ("anonymize" , "Can anonymize user" ),
93+ ]
7094
7195 def _legacy_get_session_auth_hash (self ):
7296 # RemovedInDjango40Warning: pre-Django 3.1 hashes will be invalid.
@@ -92,6 +116,27 @@ def get_session_auth_hash(self):
92116 algorithm = algorithm ,
93117 ).hexdigest ()
94118
119+ def anonymize (self , commit = True ):
120+ """
121+ Anonymize the user data for privacy purposes.
122+
123+ This method will erase the email address, the email hash, the password.
124+ You may overwrite this method to add additional fields to anonymize::
125+
126+ class MyUser(AbstractEmailUser):
127+ def anonymize(self, commit=True):
128+ super().anonymize(commit=False) # do not commit yet
129+ self.phone_number = None
130+ if commit:
131+ self.save()
132+ """
133+ self .email = None
134+ self .first_name = ""
135+ self .last_name = ""
136+ if commit :
137+ self .save (update_fields = ["email" , "first_name" , "last_name" ])
138+ AnonymizeUserSignal .send (sender = self .__class__ , user = self )
139+
95140
96141delattr (AbstractEmailUser , "password" )
97142
0 commit comments