diff --git a/apps/users/managers.py b/apps/users/managers.py index a1be585..a3760f4 100644 --- a/apps/users/managers.py +++ b/apps/users/managers.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import BaseUserManager from typing import TYPE_CHECKING if TYPE_CHECKING: - from apps.users.models import User # noqa: F401 + from apps.users.models import User class UserManager(BaseUserManager["User"]): @@ -16,11 +16,11 @@ class UserManager(BaseUserManager["User"]): user.save(using=self._db) return user - def create_user(self, email_address: str, password: str | None = None, **extra_fields): # type: ignore[override] + def create_user(self, email_address: str, password: str | None = None, **extra_fields): extra_fields.setdefault("is_staff", False) return self._create_user(email_address, password, **extra_fields) - def create_superuser(self, email_address: str, password: str | None = None, **extra_fields): # type: ignore[override] + def create_superuser(self, email_address: str, password: str | None = None, **extra_fields): extra_fields.setdefault("is_staff", True) if extra_fields.get("is_staff") is not True: raise ValueError("Superuser must have is_staff=True.") diff --git a/apps/users/migrations/0001_initial.py b/apps/users/migrations/0001_initial.py index 6666953..8db7b58 100644 --- a/apps/users/migrations/0001_initial.py +++ b/apps/users/migrations/0001_initial.py @@ -1,8 +1,6 @@ -# Generated by Django 5.2.8 on 2025-11-18 23:09 +# Generated by Django 5.2.8 on 2025-12-06 21:33 -import django.db.models.deletion import uuid -from django.conf import settings from django.db import migrations, models @@ -23,16 +21,18 @@ class Migration(migrations.Migration): ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')), - ('id', models.AutoField(primary_key=True, serialize=False)), - ('user_uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='User UUID')), + ('id', models.AutoField(primary_key=True, serialize=False, verbose_name='User ID')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='User UUID')), ('email_address', models.EmailField(max_length=255, unique=True, verbose_name='Email Address')), - ('username', models.CharField(max_length=25, unique=True, verbose_name='Username')), ('first_name', models.CharField(max_length=255, verbose_name='First Name')), ('last_name', models.CharField(max_length=255, verbose_name='Last Name')), ('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Date of Birth')), + ('bio', models.TextField(blank=True, default='')), + ('timezone', models.CharField(blank=True, default='UTC', max_length=16)), + ('avatar_url', models.URLField(blank=True)), ('is_active', models.BooleanField(default=True, verbose_name='Account Active')), ('is_staff', models.BooleanField(default=False, verbose_name='Account Admin')), - ('is_verified', models.BooleanField(default=False, verbose_name='Account Verified')), + ('role', models.CharField(choices=[('manager', 'Manager'), ('employee', 'Employee')], default='employee', max_length=50, verbose_name='Role')), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), ], @@ -41,21 +41,4 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Users', }, ), - migrations.CreateModel( - name='UserProfile', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('display_name', models.CharField(blank=True, max_length=150)), - ('bio', models.TextField(blank=True)), - ('timezone', models.CharField(blank=True, max_length=64)), - ('avatar_url', models.URLField(blank=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.AddConstraint( - model_name='user', - constraint=models.UniqueConstraint(fields=('username',), name='unique_username'), - ), ] diff --git a/apps/users/migrations/0002_remove_userprofile_user_remove_user_unique_username_and_more.py b/apps/users/migrations/0002_remove_userprofile_user_remove_user_unique_username_and_more.py deleted file mode 100644 index 38098db..0000000 --- a/apps/users/migrations/0002_remove_userprofile_user_remove_user_unique_username_and_more.py +++ /dev/null @@ -1,57 +0,0 @@ -# Generated by Django 5.2.8 on 2025-11-19 14:22 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='userprofile', - name='user', - ), - migrations.RemoveConstraint( - model_name='user', - name='unique_username', - ), - migrations.RenameField( - model_name='user', - old_name='user_uuid', - new_name='uuid', - ), - migrations.RemoveField( - model_name='user', - name='is_verified', - ), - migrations.RemoveField( - model_name='user', - name='username', - ), - migrations.AddField( - model_name='user', - name='avatar_url', - field=models.URLField(blank=True), - ), - migrations.AddField( - model_name='user', - name='bio', - field=models.TextField(blank=True, default=''), - ), - migrations.AddField( - model_name='user', - name='timezone', - field=models.CharField(blank=True, default='UTC', max_length=16), - ), - migrations.AlterField( - model_name='user', - name='id', - field=models.AutoField(primary_key=True, serialize=False, verbose_name='User ID'), - ), - migrations.DeleteModel( - name='UserProfile', - ), - ] diff --git a/apps/users/models.py b/apps/users/models.py index 1ddc754..b659710 100644 --- a/apps/users/models.py +++ b/apps/users/models.py @@ -8,6 +8,7 @@ from django.db.models import ( EmailField, UUIDField, Model, + TextChoices, TextField, URLField, ) @@ -29,6 +30,10 @@ class TimeStampMixin(Model): class User(AbstractBaseUser, TimeStampMixin, PermissionsMixin): + class Roles(TextChoices): + MANAGER = 'manager', _("Manager") + EMPLOYEE = 'employee', _("Employee") + id = AutoField(verbose_name = _("User ID"), primary_key = True) uuid = UUIDField(verbose_name = _("User UUID"), default = uuid4, editable = False) @@ -44,6 +49,8 @@ class User(AbstractBaseUser, TimeStampMixin, PermissionsMixin): is_active = BooleanField(verbose_name = _("Account Active"), default = True) is_staff = BooleanField(verbose_name = _("Account Admin"), default = False) + role = CharField(verbose_name = _("Role"), max_length = 50, choices = Roles.choices, default = Roles.EMPLOYEE) + USERNAME_FIELD = 'email_address' EMAIL_FIELD = 'email_address' REQUIRED_FIELDS = ['first_name', 'last_name', 'date_of_birth'] diff --git a/apps/users/serializers.py b/apps/users/serializers.py index 11097ea..802c3c6 100644 --- a/apps/users/serializers.py +++ b/apps/users/serializers.py @@ -5,4 +5,4 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'uuid', 'email_address', 'first_name', 'last_name', 'bio', 'timezone', 'avatar_url'] + fields = ['id', 'uuid', 'email_address', 'first_name', 'last_name', 'bio', 'timezone', 'avatar_url', 'role', 'date_of_birth', 'created_at', 'updated_at']