22from django .contrib .auth .base_user import BaseUserManager
33from django .contrib .auth .models import AbstractUser
44from django .db import models
5+ from django .dispatch import Signal
56from django .utils .crypto import get_random_string , salted_hmac
67from django .utils .translation import gettext_lazy as _
78
1112 from django .db .models import EmailField as CIEmailField
1213
1314
15+ AnonymizeUserSignal = Signal ()
16+ """
17+ Signal that is emitted when a user and all their data should be anonymized.
18+
19+ Usage::
20+
21+ from mailauth.contrib.user.models import AnonymizeUserSignal
22+
23+ @receiver(AnonymizeUserSignal)
24+ def anonymize_user(sender, user, **kwargs):
25+ # Do something with related user data
26+ user.related_model.delete()
27+
28+ """
29+
30+
1431class EmailUserManager (BaseUserManager ):
1532 use_in_migrations = True
1633
@@ -50,7 +67,9 @@ class AbstractEmailUser(AbstractUser):
5067 username = None
5168 password = None
5269
53- email = CIEmailField (_ ("email address" ), unique = True , db_index = True )
70+ email = CIEmailField (
71+ _ ("email address" ), blank = True , null = True , unique = True , db_index = True
72+ )
5473 """Unique and case insensitive to serve as a better username."""
5574
5675 session_salt = models .CharField (
@@ -67,6 +86,9 @@ def has_usable_password(self):
6786
6887 class Meta (AbstractUser .Meta ):
6988 abstract = True
89+ permissions = [
90+ ("anonymize" , "Can anonymize user" ),
91+ ]
7092
7193 def _legacy_get_session_auth_hash (self ):
7294 # RemovedInDjango40Warning: pre-Django 3.1 hashes will be invalid.
@@ -92,6 +114,27 @@ def get_session_auth_hash(self):
92114 algorithm = algorithm ,
93115 ).hexdigest ()
94116
117+ def anonymize (self , commit = True ):
118+ """
119+ Anonymize the user data for privacy purposes.
120+
121+ This method will erase the email address, the email hash, the password.
122+ You may overwrite this method to add additional fields to anonymize::
123+
124+ class MyUser(AbstractEmailUser):
125+ def anonymize(self, commit=True):
126+ super().anonymize(commit=False) # do not commit yet
127+ self.phone_number = None
128+ if commit:
129+ self.save()
130+ """
131+ self .email = None
132+ self .first_name = ""
133+ self .last_name = ""
134+ if commit :
135+ self .save (update_fields = ["email" , "first_name" , "last_name" ])
136+ AnonymizeUserSignal .send (sender = self .__class__ , user = self )
137+
95138
96139delattr (AbstractEmailUser , "password" )
97140
0 commit comments