fix(users): require mobile for superuser creation
Some checks failed
Backend CI/CD / test (push) Has been cancelled
Backend CI/CD / deploy (push) Has been cancelled

This commit is contained in:
2026-06-11 21:20:59 +03:30
parent 13ea129d3a
commit 41f9be4c7e
3 changed files with 49 additions and 7 deletions

View File

@@ -14,6 +14,7 @@ from core.admin import SoftDeleteListFilter, BaseModelAdmin
class UserAdminForm(forms.ModelForm): class UserAdminForm(forms.ModelForm):
mobile = forms.CharField(required=True)
bio = forms.CharField(widget=SimpleMDEEditor(), required=False) bio = forms.CharField(widget=SimpleMDEEditor(), required=False)
student_id = forms.CharField(required=False) student_id = forms.CharField(required=False)
@@ -25,13 +26,13 @@ class UserAdminForm(forms.ModelForm):
class UserAdmin(BaseUserAdmin, BaseModelAdmin, ImportExportModelAdmin): class UserAdmin(BaseUserAdmin, BaseModelAdmin, ImportExportModelAdmin):
form = UserAdminForm form = UserAdminForm
resource_class = UserResource resource_class = UserResource
list_display = ('email', 'username', 'university', 'is_email_verified', 'date_joined') list_display = ('email', 'mobile', 'username', 'university', 'is_email_verified', 'is_mobile_verified', 'date_joined')
list_filter = ('is_email_verified', 'is_staff', 'year_of_study', SoftDeleteListFilter) list_filter = ('is_email_verified', 'is_mobile_verified', 'is_staff', 'year_of_study', SoftDeleteListFilter)
search_fields = ('email', 'username', 'student_id', 'first_name', 'last_name') search_fields = ('email', 'mobile', 'username', 'student_id', 'first_name', 'last_name')
ordering = ('-date_joined',) ordering = ('-date_joined',)
fieldsets = ( fieldsets = (
('Auth Credentials', {'fields': ('username', 'email', 'password')}), ('Auth Credentials', {'fields': ('username', 'email', 'mobile', 'password')}),
('Personal info', { ('Personal info', {
'fields': ('first_name', 'last_name', 'student_id', 'university', 'year_of_study', 'major', 'bio', 'profile_picture') 'fields': ('first_name', 'last_name', 'student_id', 'university', 'year_of_study', 'major', 'bio', 'profile_picture')
}), }),
@@ -43,6 +44,9 @@ class UserAdmin(BaseUserAdmin, BaseModelAdmin, ImportExportModelAdmin):
('Email Verification', { ('Email Verification', {
'fields': ('is_email_verified', 'email_verification_token', 'email_verification_sent_at') 'fields': ('is_email_verified', 'email_verification_token', 'email_verification_sent_at')
}), }),
('Mobile Verification', {
'fields': ('is_mobile_verified',)
}),
('Password Reset', { ('Password Reset', {
'fields': ('password_reset_token', 'password_reset_token_expires_at'), 'fields': ('password_reset_token', 'password_reset_token_expires_at'),
'classes': ('collapse',) 'classes': ('collapse',)
@@ -57,7 +61,7 @@ class UserAdmin(BaseUserAdmin, BaseModelAdmin, ImportExportModelAdmin):
'Step 1', 'Step 1',
{ {
'classes': ('wide',), 'classes': ('wide',),
'fields': ('email', 'student_id', 'password1', 'password2', 'usable_password'), 'fields': ('email', 'mobile', 'student_id', 'password1', 'password2', 'usable_password'),
}, },
), ),
) )

View File

@@ -0,0 +1,18 @@
import apps.users.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("users", "0007_user_is_mobile_verified_user_mobile_alter_user_email_and_more"),
]
operations = [
migrations.AlterModelManagers(
name="user",
managers=[
("objects", apps.users.models.UserManager()),
],
),
]

View File

@@ -1,4 +1,4 @@
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser, UserManager as DjangoUserManager
from django.utils import timezone from django.utils import timezone
from django.db import models from django.db import models
@@ -14,6 +14,24 @@ from core.models import BaseModel
from apps.users.email_identity import normalize_email_identity, normalize_mobile_number from apps.users.email_identity import normalize_email_identity, normalize_mobile_number
class UserManager(DjangoUserManager):
def _normalize_required_mobile(self, mobile):
normalized = normalize_mobile_number(mobile)
if not normalized:
raise ValueError("The mobile number must be set")
return normalized
def create_user(self, username, email=None, password=None, **extra_fields):
extra_fields["mobile"] = self._normalize_required_mobile(extra_fields.get("mobile"))
return super().create_user(username, email=email, password=password, **extra_fields)
def create_superuser(self, username, email=None, password=None, **extra_fields):
extra_fields["mobile"] = self._normalize_required_mobile(extra_fields.get("mobile"))
extra_fields.setdefault("is_active", True)
extra_fields.setdefault("is_mobile_verified", True)
return super().create_superuser(username, email=email, password=password, **extra_fields)
class University(BaseModel): class University(BaseModel):
code = models.CharField(max_length=64, unique=True) code = models.CharField(max_length=64, unique=True)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
@@ -69,7 +87,9 @@ class User(AbstractUser, BaseModel):
password_reset_token_expires_at = models.DateTimeField(null=True, blank=True) password_reset_token_expires_at = models.DateTimeField(null=True, blank=True)
USERNAME_FIELD = 'username' USERNAME_FIELD = 'username'
REQUIRED_FIELDS = [] REQUIRED_FIELDS = ['mobile']
objects = UserManager()
class Meta: class Meta:
db_table = 'users' db_table = 'users'