Make core.User inherit from AbstractUser instead of AbstractBaseUser

This commit is contained in:
imperosol
2024-11-20 17:10:57 +01:00
parent 8d6609566f
commit 8c660e9856
20 changed files with 215 additions and 212 deletions

View File

@ -261,19 +261,19 @@ class Command(BaseCommand):
User.groups.through.objects.bulk_create(
[
User.groups.through(
realgroup_id=settings.SITH_GROUP_COUNTER_ADMIN_ID, user=counter
group_id=settings.SITH_GROUP_COUNTER_ADMIN_ID, user=counter
),
User.groups.through(
realgroup_id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID, user=comptable
group_id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID, user=comptable
),
User.groups.through(
realgroup_id=settings.SITH_GROUP_COM_ADMIN_ID, user=comunity
group_id=settings.SITH_GROUP_COM_ADMIN_ID, user=comunity
),
User.groups.through(
realgroup_id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID, user=tutu
group_id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID, user=tutu
),
User.groups.through(
realgroup_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
group_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
),
]
)

View File

@ -11,7 +11,7 @@ from django.utils.timezone import localdate, make_aware, now
from faker import Faker
from club.models import Club, Membership
from core.models import RealGroup, User
from core.models import Group, User
from counter.models import (
Counter,
Customer,
@ -225,9 +225,7 @@ class Command(BaseCommand):
ae = Club.objects.get(unix_name="ae")
other_clubs = random.sample(list(Club.objects.all()), k=3)
groups = list(
RealGroup.objects.filter(
name__in=["Subscribers", "Old subscribers", "Public"]
)
Group.objects.filter(name__in=["Subscribers", "Old subscribers", "Public"])
)
counters = list(
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette", "Eboutic"])

View File

@ -0,0 +1,82 @@
# Generated by Django 4.2.16 on 2024-11-20 16:22
import django.contrib.auth.validators
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("core", "0039_alter_user_managers"),
]
operations = [
migrations.AlterModelOptions(
name="user",
options={"verbose_name": "user", "verbose_name_plural": "users"},
),
migrations.AddField(
model_name="user",
name="user_permissions",
field=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",
),
),
migrations.AlterField(
model_name="user",
name="date_joined",
field=models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
migrations.AlterField(
model_name="user",
name="is_superuser",
field=models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
migrations.AlterField(
model_name="user",
name="username",
field=models.CharField(
error_messages={"unique": "A user with that username already exists."},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[django.contrib.auth.validators.UnicodeUsernameValidator()],
verbose_name="username",
),
),
migrations.AlterField(
model_name="user",
name="groups",
field=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",
),
),
migrations.AlterField(
model_name="user",
name="groups",
field=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="users",
to="core.group",
verbose_name="groups",
),
),
]

View File

@ -30,19 +30,13 @@ import string
import unicodedata
from datetime import timedelta
from pathlib import Path
from typing import TYPE_CHECKING, Any, Optional, Self
from typing import TYPE_CHECKING, Optional, Self
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, UserManager
from django.contrib.auth.models import (
AnonymousUser as AuthAnonymousUser,
)
from django.contrib.auth.models import (
Group as AuthGroup,
)
from django.contrib.auth.models import (
GroupManager as AuthGroupManager,
)
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.models import AnonymousUser as AuthAnonymousUser
from django.contrib.auth.models import Group as AuthGroup
from django.contrib.auth.models import GroupManager as AuthGroupManager
from django.contrib.staticfiles.storage import staticfiles_storage
from django.core import validators
from django.core.cache import cache
@ -242,7 +236,7 @@ class CustomUserManager(UserManager.from_queryset(UserQuerySet)):
pass
class User(AbstractBaseUser):
class User(AbstractUser):
"""Defines the base user class, useable in every app.
This is almost the same as the auth module AbstractUser since it inherits from it,
@ -253,51 +247,22 @@ class User(AbstractBaseUser):
Required fields: email, first_name, last_name, date_of_birth
"""
username = models.CharField(
_("username"),
max_length=254,
unique=True,
help_text=_(
"Required. 254 characters or fewer. Letters, digits and ./+/-/_ only."
),
validators=[
validators.RegexValidator(
r"^[\w.+-]+$",
_(
"Enter a valid username. This value may contain only "
"letters, numbers "
"and ./+/-/_ characters."
),
)
],
error_messages={"unique": _("A user with that username already exists.")},
)
first_name = models.CharField(_("first name"), max_length=64)
last_name = models.CharField(_("last name"), max_length=64)
email = models.EmailField(_("email address"), unique=True)
date_of_birth = models.DateField(_("date of birth"), blank=True, null=True)
nick_name = models.CharField(_("nick name"), max_length=64, null=True, blank=True)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_("Designates whether the user can log into this admin site."),
)
is_active = models.BooleanField(
_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. "
"Unselect this instead of deleting accounts."
),
)
date_joined = models.DateField(_("date joined"), auto_now_add=True)
last_update = models.DateTimeField(_("last update"), auto_now=True)
is_superuser = models.BooleanField(
_("superuser"),
default=False,
help_text=_("Designates whether this user is a superuser. "),
groups = models.ManyToManyField(
Group,
verbose_name=_("groups"),
help_text=_(
"The groups this user belongs to. A user will get all permissions "
"granted to each of their groups."
),
related_name="users",
blank=True,
)
groups = models.ManyToManyField(RealGroup, related_name="users", blank=True)
home = models.OneToOneField(
"SithFile",
related_name="home_of",
@ -401,8 +366,6 @@ class User(AbstractBaseUser):
objects = CustomUserManager()
USERNAME_FIELD = "username"
def __str__(self):
return self.get_display_name()
@ -422,12 +385,6 @@ class User(AbstractBaseUser):
settings.BASE_DIR / f"core/static/core/img/promo_{self.promo}.png"
).exists()
def has_module_perms(self, package_name: str) -> bool:
return self.is_active
def has_perm(self, perm: str, obj: Any = None) -> bool:
return self.is_active and self.is_superuser
@cached_property
def was_subscribed(self) -> bool:
return self.subscriptions.exists()
@ -599,11 +556,6 @@ class User(AbstractBaseUser):
"date_of_birth": self.date_of_birth,
}
def get_full_name(self):
"""Returns the first_name plus the last_name, with a space in between."""
full_name = "%s %s" % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"""Returns the short name for the user."""
if self.nick_name:
@ -982,13 +934,11 @@ class SithFile(models.Model):
if copy_rights:
self.copy_rights()
if self.is_in_sas:
for u in (
RealGroup.objects.filter(id=settings.SITH_GROUP_SAS_ADMIN_ID)
.first()
.users.all()
for user in User.objects.filter(
groups__id__in=[settings.SITH_GROUP_SAS_ADMIN_ID]
):
Notification(
user=u,
user=user,
url=reverse("sas:moderation"),
type="SAS_MODERATION",
param="1",

View File

@ -118,7 +118,9 @@ class TestUserRegistration:
response = client.post(reverse("core:register"), valid_payload)
assert response.status_code == 200
error_html = "<li>Un objet User avec ce champ Adresse email existe déjà.</li>"
error_html = (
"<li>Un objet Utilisateur avec ce champ Adresse email existe déjà.</li>"
)
assertInHTML(error_html, str(response.content.decode()))
def test_register_fail_with_not_existing_email(

View File

@ -14,7 +14,7 @@ from PIL import Image
from pytest_django.asserts import assertNumQueries
from core.baker_recipes import board_user, old_subscriber_user, subscriber_user
from core.models import Group, RealGroup, SithFile, User
from core.models import Group, SithFile, User
from sas.models import Picture
from sith import settings
@ -26,12 +26,10 @@ class TestImageAccess:
[
lambda: baker.make(User, is_superuser=True),
lambda: baker.make(
User,
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)],
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
),
lambda: baker.make(
User,
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)],
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)]
),
],
)

View File

@ -21,6 +21,7 @@ from wsgiref.util import FileWrapper
from django import forms
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db.models import Exists, OuterRef
from django.forms.models import modelform_factory
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect
@ -31,7 +32,7 @@ from django.views.generic import DetailView, ListView
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import DeleteView, FormMixin, UpdateView
from core.models import Notification, RealGroup, SithFile, User
from core.models import Notification, SithFile, User
from core.views import (
AllowFragment,
CanEditMixin,
@ -159,19 +160,18 @@ class AddFilesForm(forms.Form):
% {"file_name": f, "msg": repr(e)},
)
if notif:
for u in (
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
.first()
.users.all()
unread_notif_subquery = Notification.objects.filter(
user=OuterRef("pk"), type="FILE_MODERATION", viewed=False
)
for user in User.objects.filter(
~Exists(unread_notif_subquery),
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
):
if not u.notifications.filter(
type="FILE_MODERATION", viewed=False
).exists():
Notification(
user=u,
url=reverse("core:file_moderation"),
type="FILE_MODERATION",
).save()
Notification.objects.create(
user=user,
url=reverse("core:file_moderation"),
type="FILE_MODERATION",
)
class FileListView(ListView):

View File

@ -167,9 +167,7 @@ class RegisteringForm(UserCreationForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email")
field_classes = {
"email": AntiSpamEmailField,
}
field_classes = {"email": AntiSpamEmailField}
class UserProfileForm(forms.ModelForm):

View File

@ -23,9 +23,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView
from core.models import RealGroup, User
from core.views import CanCreateMixin, CanEditMixin, DetailFormView
from core.views.widgets.select import (
AutoCompleteSelectMultipleUser,
)
from core.views.widgets.select import AutoCompleteSelectMultipleUser
# Forms