Coverage for src/accounts/managers/user_credential.py: 47%
60 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
1"""
2This module defines the custom user manager for the UserCredential model.
3The manager extends Django's BaseUserManager to provide custom user creation
4methods that work with our email-based authentication system.
5"""
7from django.contrib.auth.base_user import BaseUserManager
8from django.contrib.auth.hashers import make_password
9from django.contrib import auth
12class UserCredentialManager(BaseUserManager):
13 """
14 Custom user manager for the UserCredential model.
16 This manager extends Django's BaseUserManager to provide custom user creation
17 methods that work with our email-based authentication system. It handles:
18 - User creation with email as primary identifier
19 - Password hashing and security
21 The manager is used by Django's authentication system and provides
22 the methods needed for user creation, management, and queries.
23 """
25 use_in_migrations = True
27 def _create_user_object(self, email, password, **extra_fields):
28 """
29 Create a user object without saving it to the database.
31 This is a private method that creates the user object in memory
32 but doesn't save it. It's used by other methods that need to
33 create users with different save strategies (sync/async).
35 Args:
36 email: User's email address (primary identifier)
37 password: User's password (will be hashed)
38 **extra_fields: Additional fields for the user model
40 Returns:
41 UserCredential object (not saved to database)
43 Raises:
44 ValueError: If email is not provided
45 """
46 if not email:
47 raise ValueError('The given email must be set')
49 email = self.normalize_email(email)
50 user = self.model(email=email, **extra_fields)
51 user.password = make_password(password)
53 return user
55 def _create_user(self, email, password, **extra_fields):
56 """
57 Create and save a regular user to the database.
59 This is a private method that creates a user object and saves it
60 to the database synchronously. It's used by create_user().
62 Args:
63 email: User's email address
64 password: User's password
65 **extra_fields: Additional fields for the user model
67 Returns:
68 Saved UserCredential object
69 """
70 user = self._create_user_object(email, password, **extra_fields)
71 user.save(using=self._db)
73 return user
75 async def _acreate_user(self, email, password, **extra_fields):
76 """
77 Create and save a regular user to the database asynchronously.
79 This is an async version of _create_user for use in async Django
80 applications. It provides the same functionality but uses async/await.
82 Args:
83 email: User's email address
84 password: User's password
85 **extra_fields: Additional fields for the user model
87 Returns:
88 Saved UserCredential object
89 """
90 user = self._create_user_object(email, password, **extra_fields)
91 await user.asave(using=self._db)
93 return user
95 def create_user(self, email, password, **extra_fields):
96 """
97 Create and save a regular user.
99 This is the main method for creating regular users. It sets default
100 values for staff and superuser flags and calls the private creation method.
102 Args:
103 email: User's email address
104 password: User's password
105 **extra_fields: Additional fields for the user model
107 Returns:
108 Saved UserCredential object
110 Example:
111 user = UserCredential.objects.create_user(
112 email='user@example.com',
113 password='secure_password',
114 username='john_doe'
115 )
116 """
117 extra_fields.setdefault('is_staff', False)
118 extra_fields.setdefault('is_superuser', False)
120 return self._create_user(email, password, **extra_fields)
122 create_user.alters_data = True
124 async def acreate_user(self, email, password, **extra_fields):
125 """
126 Create and save a regular user asynchronously.
128 Async version of create_user for use in async Django applications.
130 Args:
131 email: User's email address
132 password: User's password
133 **extra_fields: Additional fields for the user model
135 Returns:
136 Saved UserCredential object
137 """
138 extra_fields.setdefault('is_staff', False)
139 extra_fields.setdefault('is_superuser', False)
141 return await self._acreate_user(email, password, **extra_fields)
143 acreate_user.alters_data = True
145 def create_superuser(self, email, password, **extra_fields):
146 """
147 Create and save a superuser.
149 This method creates a user with administrative privileges. It ensures
150 that superusers have the proper staff and superuser flags set.
152 Args:
153 email: User's email address
154 password: User's password
155 **extra_fields: Additional fields for the user model
157 Returns:
158 Saved UserCredential object with admin privileges
160 Raises:
161 ValueError: If is_staff or is_superuser is not True
163 Example:
164 admin = UserCredential.objects.create_superuser(
165 email='admin@example.com',
166 password='admin_password'
167 )
168 """
169 extra_fields.setdefault('is_staff', True)
170 extra_fields.setdefault('is_superuser', True)
172 if extra_fields.get('is_staff') is not True:
173 raise ValueError('Superuser must have is_staff=True.')
175 if extra_fields.get('is_superuser') is not True:
176 raise ValueError('Superuser must have is_superuser=True.')
178 return self._create_user(email, password, **extra_fields)
180 create_superuser.alters_data = True
182 async def acreate_superuser(self, email, password, **extra_fields):
183 """
184 Create and save a superuser asynchronously.
186 Async version of create_superuser for use in async Django applications.
188 Args:
189 email: User's email address
190 password: User's password
191 **extra_fields: Additional fields for the user model
193 Returns:
194 Saved UserCredential object with admin privileges
196 Raises:
197 ValueError: If is_staff or is_superuser is not True
198 """
199 extra_fields.setdefault('is_staff', True)
200 extra_fields.setdefault('is_superuser', True)
202 if extra_fields.get('is_staff') is not True:
203 raise ValueError('Superuser must have is_staff=True.')
205 if extra_fields.get('is_superuser') is not True:
206 raise ValueError('Superuser must have is_superuser=True.')
208 return await self._acreate_user(email, password, **extra_fields)
210 acreate_superuser.alters_data = True
212 def with_perm(
213 self,
214 perm,
215 is_active=True,
216 include_superusers=True,
217 backend=None,
218 obj=None,
219 ):
220 """
221 Return users with the specified permission.
223 This method filters users based on their permissions. It's useful
224 for finding users with specific capabilities or roles.
226 Args:
227 perm: Permission string (e.g., 'auth.add_user')
228 is_active: Whether to include only active users
229 include_superusers: Whether to include superusers
230 backend: Authentication backend to use
231 obj: Object to check permissions against
233 Returns:
234 QuerySet of users with the specified permission
236 Raises:
237 ValueError: If multiple backends are configured and backend not specified
238 TypeError: If backend is not a string
239 """
240 if backend is None:
241 backends = auth._get_backends(return_tuples=True)
243 if len(backends) == 1:
244 backend, _ = backends[0]
245 else:
246 raise ValueError(
247 'You have multiple authentication backends configured and '
248 'therefore must provide the `backend` argument.'
249 )
251 elif not isinstance(backend, str):
252 raise TypeError(
253 'backend must be a dotted import path string (got %r).'
254 % backend
255 )
256 else:
257 backend = auth.load_backend(backend)
259 if hasattr(backend, 'with_perm'):
260 return backend.with_perm(
261 perm,
262 is_active=is_active,
263 include_superusers=include_superusers,
264 obj=obj,
265 )
267 return self.none()