mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 07:41:14 +00:00
Merge pull request #929 from ae-utbm/user-model
Migrate User parent class from AbstractBaseUser to AbstractUser
This commit is contained in:
commit
ddeb12f08c
@ -216,7 +216,7 @@ class TestOperation(TestCase):
|
|||||||
self.journal.operations.filter(target_label="Le fantome du jour").exists()
|
self.journal.operations.filter(target_label="Le fantome du jour").exists()
|
||||||
)
|
)
|
||||||
|
|
||||||
def test__operation_simple_accounting(self):
|
def test_operation_simple_accounting(self):
|
||||||
sat = SimplifiedAccountingType.objects.all().first()
|
sat = SimplifiedAccountingType.objects.all().first()
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse("accounting:op_new", args=[self.journal.id]),
|
reverse("accounting:op_new", args=[self.journal.id]),
|
||||||
@ -237,15 +237,14 @@ class TestOperation(TestCase):
|
|||||||
"done": False,
|
"done": False,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertFalse(response.status_code == 403)
|
assert response.status_code != 403
|
||||||
self.assertTrue(self.journal.operations.filter(amount=23).exists())
|
assert self.journal.operations.filter(amount=23).exists()
|
||||||
response_get = self.client.get(
|
response_get = self.client.get(
|
||||||
reverse("accounting:journal_details", args=[self.journal.id])
|
reverse("accounting:journal_details", args=[self.journal.id])
|
||||||
)
|
)
|
||||||
self.assertTrue(
|
assert "<td>Le fantome de l'aurore</td>" in str(response_get.content)
|
||||||
"<td>Le fantome de l'aurore</td>" in str(response_get.content)
|
|
||||||
)
|
assert (
|
||||||
self.assertTrue(
|
|
||||||
self.journal.operations.filter(amount=23)
|
self.journal.operations.filter(amount=23)
|
||||||
.values("accounting_type")
|
.values("accounting_type")
|
||||||
.first()["accounting_type"]
|
.first()["accounting_type"]
|
||||||
|
@ -215,17 +215,14 @@ class JournalTabsMixin(TabedViewMixin):
|
|||||||
return _("Journal")
|
return _("Journal")
|
||||||
|
|
||||||
def get_list_of_tabs(self):
|
def get_list_of_tabs(self):
|
||||||
tab_list = []
|
return [
|
||||||
tab_list.append(
|
|
||||||
{
|
{
|
||||||
"url": reverse(
|
"url": reverse(
|
||||||
"accounting:journal_details", kwargs={"j_id": self.object.id}
|
"accounting:journal_details", kwargs={"j_id": self.object.id}
|
||||||
),
|
),
|
||||||
"slug": "journal",
|
"slug": "journal",
|
||||||
"name": _("Journal"),
|
"name": _("Journal"),
|
||||||
}
|
},
|
||||||
)
|
|
||||||
tab_list.append(
|
|
||||||
{
|
{
|
||||||
"url": reverse(
|
"url": reverse(
|
||||||
"accounting:journal_nature_statement",
|
"accounting:journal_nature_statement",
|
||||||
@ -233,9 +230,7 @@ class JournalTabsMixin(TabedViewMixin):
|
|||||||
),
|
),
|
||||||
"slug": "nature_statement",
|
"slug": "nature_statement",
|
||||||
"name": _("Statement by nature"),
|
"name": _("Statement by nature"),
|
||||||
}
|
},
|
||||||
)
|
|
||||||
tab_list.append(
|
|
||||||
{
|
{
|
||||||
"url": reverse(
|
"url": reverse(
|
||||||
"accounting:journal_person_statement",
|
"accounting:journal_person_statement",
|
||||||
@ -243,9 +238,7 @@ class JournalTabsMixin(TabedViewMixin):
|
|||||||
),
|
),
|
||||||
"slug": "person_statement",
|
"slug": "person_statement",
|
||||||
"name": _("Statement by person"),
|
"name": _("Statement by person"),
|
||||||
}
|
},
|
||||||
)
|
|
||||||
tab_list.append(
|
|
||||||
{
|
{
|
||||||
"url": reverse(
|
"url": reverse(
|
||||||
"accounting:journal_accounting_statement",
|
"accounting:journal_accounting_statement",
|
||||||
@ -253,9 +246,8 @@ class JournalTabsMixin(TabedViewMixin):
|
|||||||
),
|
),
|
||||||
"slug": "accounting_statement",
|
"slug": "accounting_statement",
|
||||||
"name": _("Accounting statement"),
|
"name": _("Accounting statement"),
|
||||||
}
|
},
|
||||||
)
|
]
|
||||||
return tab_list
|
|
||||||
|
|
||||||
|
|
||||||
class JournalCreateView(CanCreateMixin, CreateView):
|
class JournalCreateView(CanCreateMixin, CreateView):
|
||||||
|
@ -3,19 +3,6 @@ from __future__ import unicode_literals
|
|||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
from club.models import Club
|
|
||||||
from core.operations import PsqlRunOnly
|
|
||||||
|
|
||||||
|
|
||||||
def generate_club_pages(apps, schema_editor):
|
|
||||||
def recursive_generate_club_page(club):
|
|
||||||
club.make_page()
|
|
||||||
for child in Club.objects.filter(parent=club).all():
|
|
||||||
recursive_generate_club_page(child)
|
|
||||||
|
|
||||||
for club in Club.objects.filter(parent=None).all():
|
|
||||||
recursive_generate_club_page(club)
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [("core", "0024_auto_20170906_1317"), ("club", "0010_club_logo")]
|
dependencies = [("core", "0024_auto_20170906_1317"), ("club", "0010_club_logo")]
|
||||||
@ -48,11 +35,4 @@ class Migration(migrations.Migration):
|
|||||||
null=True,
|
null=True,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PsqlRunOnly(
|
|
||||||
"SET CONSTRAINTS ALL IMMEDIATE", reverse_sql=migrations.RunSQL.noop
|
|
||||||
),
|
|
||||||
migrations.RunPython(generate_club_pages),
|
|
||||||
PsqlRunOnly(
|
|
||||||
migrations.RunSQL.noop, reverse_sql="SET CONSTRAINTS ALL IMMEDIATE"
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -31,14 +31,14 @@ from django.core.cache import cache
|
|||||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||||
from django.core.validators import RegexValidator, validate_email
|
from django.core.validators import RegexValidator, validate_email
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Exists, OuterRef, Q
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import localdate
|
from django.utils.timezone import localdate
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from core.models import Group, MetaGroup, Notification, Page, RealGroup, SithFile, User
|
from core.models import Group, MetaGroup, Notification, Page, SithFile, User
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
@ -438,19 +438,18 @@ class Mailing(models.Model):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.is_moderated:
|
if not self.is_moderated:
|
||||||
for user in (
|
unread_notif_subquery = Notification.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
user=OuterRef("pk"), type="MAILING_MODERATION", viewed=False
|
||||||
.first()
|
)
|
||||||
.users.all()
|
for user in User.objects.filter(
|
||||||
|
~Exists(unread_notif_subquery),
|
||||||
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
|
||||||
):
|
):
|
||||||
if not user.notifications.filter(
|
Notification(
|
||||||
type="MAILING_MODERATION", viewed=False
|
user=user,
|
||||||
).exists():
|
url=reverse("com:mailing_admin"),
|
||||||
Notification(
|
type="MAILING_MODERATION",
|
||||||
user=user,
|
).save(*args, **kwargs)
|
||||||
url=reverse("com:mailing_admin"),
|
|
||||||
type="MAILING_MODERATION",
|
|
||||||
).save(*args, **kwargs)
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
@ -34,7 +34,7 @@ from django.utils import timezone
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
from core.models import Notification, Preferences, RealGroup, User
|
from core.models import Notification, Preferences, User
|
||||||
|
|
||||||
|
|
||||||
class Sith(models.Model):
|
class Sith(models.Model):
|
||||||
@ -108,17 +108,15 @@ class News(models.Model):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
for u in (
|
for user in User.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID]
|
||||||
.first()
|
|
||||||
.users.all()
|
|
||||||
):
|
):
|
||||||
Notification(
|
Notification.objects.create(
|
||||||
user=u,
|
user=user,
|
||||||
url=reverse("com:news_admin_list"),
|
url=reverse("com:news_admin_list"),
|
||||||
type="NEWS_MODERATION",
|
type="NEWS_MODERATION",
|
||||||
param="1",
|
param="1",
|
||||||
).save()
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("com:news_detail", kwargs={"news_id": self.id})
|
return reverse("com:news_detail", kwargs={"news_id": self.id})
|
||||||
@ -336,16 +334,14 @@ class Poster(models.Model):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.is_moderated:
|
if not self.is_moderated:
|
||||||
for u in (
|
for user in User.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID]
|
||||||
.first()
|
|
||||||
.users.all()
|
|
||||||
):
|
):
|
||||||
Notification(
|
Notification.objects.create(
|
||||||
user=u,
|
user=user,
|
||||||
url=reverse("com:poster_moderate_list"),
|
url=reverse("com:poster_moderate_list"),
|
||||||
type="POSTER_MODERATION",
|
type="POSTER_MODERATION",
|
||||||
).save()
|
)
|
||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self, *args, **kwargs):
|
def clean(self, *args, **kwargs):
|
||||||
|
@ -23,7 +23,7 @@ from django.utils.translation import gettext as _
|
|||||||
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
from com.models import News, Poster, Sith, Weekmail, WeekmailArticle
|
from com.models import News, Poster, Sith, Weekmail, WeekmailArticle
|
||||||
from core.models import AnonymousUser, RealGroup, User
|
from core.models import AnonymousUser, Group, User
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
@ -49,9 +49,7 @@ class TestCom(TestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
cls.skia = User.objects.get(username="skia")
|
cls.skia = User.objects.get(username="skia")
|
||||||
cls.com_group = RealGroup.objects.filter(
|
cls.com_group = Group.objects.get(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||||
id=settings.SITH_GROUP_COM_ADMIN_ID
|
|
||||||
).first()
|
|
||||||
cls.skia.groups.set([cls.com_group])
|
cls.skia.groups.set([cls.com_group])
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
52
com/views.py
52
com/views.py
@ -28,7 +28,7 @@ from smtplib import SMTPRecipientsRefused
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import PermissionDenied, ValidationError
|
from django.core.exceptions import PermissionDenied, ValidationError
|
||||||
from django.db.models import Max
|
from django.db.models import Exists, Max, OuterRef
|
||||||
from django.forms.models import modelform_factory
|
from django.forms.models import modelform_factory
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
@ -42,7 +42,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
|||||||
|
|
||||||
from club.models import Club, Mailing
|
from club.models import Club, Mailing
|
||||||
from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
|
from com.models import News, NewsDate, Poster, Screen, Sith, Weekmail, WeekmailArticle
|
||||||
from core.models import Notification, RealGroup, User
|
from core.models import Notification, User
|
||||||
from core.views import (
|
from core.views import (
|
||||||
CanCreateMixin,
|
CanCreateMixin,
|
||||||
CanEditMixin,
|
CanEditMixin,
|
||||||
@ -278,21 +278,18 @@ class NewsEditView(CanEditMixin, UpdateView):
|
|||||||
else:
|
else:
|
||||||
self.object.is_moderated = False
|
self.object.is_moderated = False
|
||||||
self.object.save()
|
self.object.save()
|
||||||
for u in (
|
unread_notif_subquery = Notification.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
user=OuterRef("pk"), type="NEWS_MODERATION", viewed=False
|
||||||
.first()
|
)
|
||||||
.users.all()
|
for user in User.objects.filter(
|
||||||
|
~Exists(unread_notif_subquery),
|
||||||
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
|
||||||
):
|
):
|
||||||
if not u.notifications.filter(
|
Notification.objects.create(
|
||||||
type="NEWS_MODERATION", viewed=False
|
user=user,
|
||||||
).exists():
|
url=self.object.get_absolute_url(),
|
||||||
Notification(
|
type="NEWS_MODERATION",
|
||||||
user=u,
|
)
|
||||||
url=reverse(
|
|
||||||
"com:news_detail", kwargs={"news_id": self.object.id}
|
|
||||||
),
|
|
||||||
type="NEWS_MODERATION",
|
|
||||||
).save()
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
@ -323,19 +320,18 @@ class NewsCreateView(CanCreateMixin, CreateView):
|
|||||||
self.object.is_moderated = True
|
self.object.is_moderated = True
|
||||||
self.object.save()
|
self.object.save()
|
||||||
else:
|
else:
|
||||||
for u in (
|
unread_notif_subquery = Notification.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
user=OuterRef("pk"), type="NEWS_MODERATION", viewed=False
|
||||||
.first()
|
)
|
||||||
.users.all()
|
for user in User.objects.filter(
|
||||||
|
~Exists(unread_notif_subquery),
|
||||||
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
|
||||||
):
|
):
|
||||||
if not u.notifications.filter(
|
Notification.objects.create(
|
||||||
type="NEWS_MODERATION", viewed=False
|
user=user,
|
||||||
).exists():
|
url=reverse("com:news_admin_list"),
|
||||||
Notification(
|
type="NEWS_MODERATION",
|
||||||
user=u,
|
)
|
||||||
url=reverse("com:news_admin_list"),
|
|
||||||
type="NEWS_MODERATION",
|
|
||||||
).save()
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,19 +261,19 @@ class Command(BaseCommand):
|
|||||||
User.groups.through.objects.bulk_create(
|
User.groups.through.objects.bulk_create(
|
||||||
[
|
[
|
||||||
User.groups.through(
|
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(
|
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(
|
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(
|
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(
|
User.groups.through(
|
||||||
realgroup_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
|
group_id=settings.SITH_GROUP_SAS_ADMIN_ID, user=skia
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -11,7 +11,7 @@ from django.utils.timezone import localdate, make_aware, now
|
|||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
|
||||||
from club.models import Club, Membership
|
from club.models import Club, Membership
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from counter.models import (
|
from counter.models import (
|
||||||
Counter,
|
Counter,
|
||||||
Customer,
|
Customer,
|
||||||
@ -225,9 +225,7 @@ class Command(BaseCommand):
|
|||||||
ae = Club.objects.get(unix_name="ae")
|
ae = Club.objects.get(unix_name="ae")
|
||||||
other_clubs = random.sample(list(Club.objects.all()), k=3)
|
other_clubs = random.sample(list(Club.objects.all()), k=3)
|
||||||
groups = list(
|
groups = list(
|
||||||
RealGroup.objects.filter(
|
Group.objects.filter(name__in=["Subscribers", "Old subscribers", "Public"])
|
||||||
name__in=["Subscribers", "Old subscribers", "Public"]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
counters = list(
|
counters = list(
|
||||||
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette", "Eboutic"])
|
Counter.objects.filter(name__in=["Foyer", "MDE", "La Gommette", "Eboutic"])
|
||||||
|
@ -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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -30,19 +30,13 @@ import string
|
|||||||
import unicodedata
|
import unicodedata
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from pathlib import Path
|
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.conf import settings
|
||||||
from django.contrib.auth.models import AbstractBaseUser, UserManager
|
from django.contrib.auth.models import AbstractUser, UserManager
|
||||||
from django.contrib.auth.models import (
|
from django.contrib.auth.models import AnonymousUser as AuthAnonymousUser
|
||||||
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 (
|
|
||||||
Group as AuthGroup,
|
|
||||||
)
|
|
||||||
from django.contrib.auth.models import (
|
|
||||||
GroupManager as AuthGroupManager,
|
|
||||||
)
|
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
@ -242,7 +236,7 @@ class CustomUserManager(UserManager.from_queryset(UserQuerySet)):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractBaseUser):
|
class User(AbstractUser):
|
||||||
"""Defines the base user class, useable in every app.
|
"""Defines the base user class, useable in every app.
|
||||||
|
|
||||||
This is almost the same as the auth module AbstractUser since it inherits from it,
|
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
|
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)
|
first_name = models.CharField(_("first name"), max_length=64)
|
||||||
last_name = models.CharField(_("last name"), max_length=64)
|
last_name = models.CharField(_("last name"), max_length=64)
|
||||||
email = models.EmailField(_("email address"), unique=True)
|
email = models.EmailField(_("email address"), unique=True)
|
||||||
date_of_birth = models.DateField(_("date of birth"), blank=True, null=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)
|
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)
|
last_update = models.DateTimeField(_("last update"), auto_now=True)
|
||||||
is_superuser = models.BooleanField(
|
groups = models.ManyToManyField(
|
||||||
_("superuser"),
|
Group,
|
||||||
default=False,
|
verbose_name=_("groups"),
|
||||||
help_text=_("Designates whether this user is a superuser. "),
|
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(
|
home = models.OneToOneField(
|
||||||
"SithFile",
|
"SithFile",
|
||||||
related_name="home_of",
|
related_name="home_of",
|
||||||
@ -401,8 +366,6 @@ class User(AbstractBaseUser):
|
|||||||
|
|
||||||
objects = CustomUserManager()
|
objects = CustomUserManager()
|
||||||
|
|
||||||
USERNAME_FIELD = "username"
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.get_display_name()
|
return self.get_display_name()
|
||||||
|
|
||||||
@ -422,22 +385,23 @@ class User(AbstractBaseUser):
|
|||||||
settings.BASE_DIR / f"core/static/core/img/promo_{self.promo}.png"
|
settings.BASE_DIR / f"core/static/core/img/promo_{self.promo}.png"
|
||||||
).exists()
|
).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
|
@cached_property
|
||||||
def was_subscribed(self) -> bool:
|
def was_subscribed(self) -> bool:
|
||||||
|
if "is_subscribed" in self.__dict__ and self.is_subscribed:
|
||||||
|
# if the user is currently subscribed, he is an old subscriber too
|
||||||
|
# if the property has already been cached, avoid another request
|
||||||
|
return True
|
||||||
return self.subscriptions.exists()
|
return self.subscriptions.exists()
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def is_subscribed(self) -> bool:
|
def is_subscribed(self) -> bool:
|
||||||
s = self.subscriptions.filter(
|
if "was_subscribed" in self.__dict__ and not self.was_subscribed:
|
||||||
|
# if the user never subscribed, he cannot be a subscriber now.
|
||||||
|
# if the property has already been cached, avoid another request
|
||||||
|
return False
|
||||||
|
return self.subscriptions.filter(
|
||||||
subscription_start__lte=timezone.now(), subscription_end__gte=timezone.now()
|
subscription_start__lte=timezone.now(), subscription_end__gte=timezone.now()
|
||||||
)
|
).exists()
|
||||||
return s.exists()
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def account_balance(self):
|
def account_balance(self):
|
||||||
@ -599,11 +563,6 @@ class User(AbstractBaseUser):
|
|||||||
"date_of_birth": self.date_of_birth,
|
"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):
|
def get_short_name(self):
|
||||||
"""Returns the short name for the user."""
|
"""Returns the short name for the user."""
|
||||||
if self.nick_name:
|
if self.nick_name:
|
||||||
@ -982,13 +941,11 @@ class SithFile(models.Model):
|
|||||||
if copy_rights:
|
if copy_rights:
|
||||||
self.copy_rights()
|
self.copy_rights()
|
||||||
if self.is_in_sas:
|
if self.is_in_sas:
|
||||||
for u in (
|
for user in User.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_SAS_ADMIN_ID)
|
groups__id__in=[settings.SITH_GROUP_SAS_ADMIN_ID]
|
||||||
.first()
|
|
||||||
.users.all()
|
|
||||||
):
|
):
|
||||||
Notification(
|
Notification(
|
||||||
user=u,
|
user=user,
|
||||||
url=reverse("sas:moderation"),
|
url=reverse("sas:moderation"),
|
||||||
type="SAS_MODERATION",
|
type="SAS_MODERATION",
|
||||||
param="1",
|
param="1",
|
||||||
|
@ -118,7 +118,9 @@ class TestUserRegistration:
|
|||||||
response = client.post(reverse("core:register"), valid_payload)
|
response = client.post(reverse("core:register"), valid_payload)
|
||||||
|
|
||||||
assert response.status_code == 200
|
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()))
|
assertInHTML(error_html, str(response.content.decode()))
|
||||||
|
|
||||||
def test_register_fail_with_not_existing_email(
|
def test_register_fail_with_not_existing_email(
|
||||||
|
@ -14,7 +14,7 @@ from PIL import Image
|
|||||||
from pytest_django.asserts import assertNumQueries
|
from pytest_django.asserts import assertNumQueries
|
||||||
|
|
||||||
from core.baker_recipes import board_user, old_subscriber_user, subscriber_user
|
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 sas.models import Picture
|
||||||
from sith import settings
|
from sith import settings
|
||||||
|
|
||||||
@ -26,12 +26,10 @@ class TestImageAccess:
|
|||||||
[
|
[
|
||||||
lambda: baker.make(User, is_superuser=True),
|
lambda: baker.make(User, is_superuser=True),
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
||||||
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)],
|
|
||||||
),
|
),
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)]
|
||||||
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID)],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,7 @@ from wsgiref.util import FileWrapper
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db.models import Exists, OuterRef
|
||||||
from django.forms.models import modelform_factory
|
from django.forms.models import modelform_factory
|
||||||
from django.http import Http404, HttpRequest, HttpResponse
|
from django.http import Http404, HttpRequest, HttpResponse
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
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.detail import SingleObjectMixin
|
||||||
from django.views.generic.edit import DeleteView, FormMixin, UpdateView
|
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 (
|
from core.views import (
|
||||||
AllowFragment,
|
AllowFragment,
|
||||||
CanEditMixin,
|
CanEditMixin,
|
||||||
@ -159,19 +160,18 @@ class AddFilesForm(forms.Form):
|
|||||||
% {"file_name": f, "msg": repr(e)},
|
% {"file_name": f, "msg": repr(e)},
|
||||||
)
|
)
|
||||||
if notif:
|
if notif:
|
||||||
for u in (
|
unread_notif_subquery = Notification.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
|
user=OuterRef("pk"), type="FILE_MODERATION", viewed=False
|
||||||
.first()
|
)
|
||||||
.users.all()
|
for user in User.objects.filter(
|
||||||
|
~Exists(unread_notif_subquery),
|
||||||
|
groups__id__in=[settings.SITH_GROUP_COM_ADMIN_ID],
|
||||||
):
|
):
|
||||||
if not u.notifications.filter(
|
Notification.objects.create(
|
||||||
type="FILE_MODERATION", viewed=False
|
user=user,
|
||||||
).exists():
|
url=reverse("core:file_moderation"),
|
||||||
Notification(
|
type="FILE_MODERATION",
|
||||||
user=u,
|
)
|
||||||
url=reverse("core:file_moderation"),
|
|
||||||
type="FILE_MODERATION",
|
|
||||||
).save()
|
|
||||||
|
|
||||||
|
|
||||||
class FileListView(ListView):
|
class FileListView(ListView):
|
||||||
|
@ -167,9 +167,7 @@ class RegisteringForm(UserCreationForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ("first_name", "last_name", "email")
|
fields = ("first_name", "last_name", "email")
|
||||||
field_classes = {
|
field_classes = {"email": AntiSpamEmailField}
|
||||||
"email": AntiSpamEmailField,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class UserProfileForm(forms.ModelForm):
|
class UserProfileForm(forms.ModelForm):
|
||||||
|
@ -23,9 +23,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
|||||||
|
|
||||||
from core.models import RealGroup, User
|
from core.models import RealGroup, User
|
||||||
from core.views import CanCreateMixin, CanEditMixin, DetailFormView
|
from core.views import CanCreateMixin, CanEditMixin, DetailFormView
|
||||||
from core.views.widgets.select import (
|
from core.views.widgets.select import AutoCompleteSelectMultipleUser
|
||||||
AutoCompleteSelectMultipleUser,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Forms
|
# Forms
|
||||||
|
|
||||||
|
@ -1,38 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from core.models import User
|
|
||||||
from counter.models import Counter, Customer, Product, Selling
|
|
||||||
|
|
||||||
|
|
||||||
def balance_ecocups(apps, schema_editor):
|
|
||||||
for customer in Customer.objects.all():
|
|
||||||
customer.recorded_products = 0
|
|
||||||
for selling in customer.buyings.filter(
|
|
||||||
product__id__in=[settings.SITH_ECOCUP_CONS, settings.SITH_ECOCUP_DECO]
|
|
||||||
).all():
|
|
||||||
if selling.product.is_record_product:
|
|
||||||
customer.recorded_products += selling.quantity
|
|
||||||
elif selling.product.is_unrecord_product:
|
|
||||||
customer.recorded_products -= selling.quantity
|
|
||||||
if customer.recorded_products < -settings.SITH_ECOCUP_LIMIT:
|
|
||||||
qt = -(customer.recorded_products + settings.SITH_ECOCUP_LIMIT)
|
|
||||||
cons = Product.objects.get(id=settings.SITH_ECOCUP_CONS)
|
|
||||||
Selling(
|
|
||||||
label=_("Ecocup regularization"),
|
|
||||||
product=cons,
|
|
||||||
unit_price=cons.selling_price,
|
|
||||||
club=cons.club,
|
|
||||||
counter=Counter.objects.filter(name="Foyer").first(),
|
|
||||||
quantity=qt,
|
|
||||||
seller=User.objects.get(id=0),
|
|
||||||
customer=customer,
|
|
||||||
).save(allow_negative=True)
|
|
||||||
customer.recorded_products += qt
|
|
||||||
customer.save()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@ -44,5 +12,4 @@ class Migration(migrations.Migration):
|
|||||||
name="recorded_products",
|
name="recorded_products",
|
||||||
field=models.IntegerField(verbose_name="recorded items", default=0),
|
field=models.IntegerField(verbose_name="recorded items", default=0),
|
||||||
),
|
),
|
||||||
migrations.RunPython(balance_ecocups),
|
|
||||||
]
|
]
|
||||||
|
@ -13,7 +13,7 @@ from PIL import Image
|
|||||||
from pytest_django.asserts import assertNumQueries
|
from pytest_django.asserts import assertNumQueries
|
||||||
|
|
||||||
from core.baker_recipes import board_user, subscriber_user
|
from core.baker_recipes import board_user, subscriber_user
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from counter.models import Product, ProductType
|
from counter.models import Product, ProductType
|
||||||
|
|
||||||
|
|
||||||
@ -51,16 +51,14 @@ def test_resize_product_icon(model):
|
|||||||
(
|
(
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User,
|
||||||
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)],
|
groups=[Group.objects.get(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)],
|
||||||
),
|
),
|
||||||
200,
|
200,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User,
|
||||||
groups=[
|
groups=[Group.objects.get(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)],
|
||||||
RealGroup.objects.get(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
200,
|
200,
|
||||||
),
|
),
|
||||||
|
@ -6,7 +6,7 @@ from model_bakery import baker, seq
|
|||||||
from ninja_extra.testing import TestClient
|
from ninja_extra.testing import TestClient
|
||||||
|
|
||||||
from core.baker_recipes import board_user, subscriber_user
|
from core.baker_recipes import board_user, subscriber_user
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from counter.api import ProductTypeController
|
from counter.api import ProductTypeController
|
||||||
from counter.models import ProductType
|
from counter.models import ProductType
|
||||||
|
|
||||||
@ -70,16 +70,14 @@ def test_move_above_product_type(product_types: list[ProductType]):
|
|||||||
(
|
(
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User,
|
||||||
groups=[RealGroup.objects.get(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)],
|
groups=[Group.objects.get(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)],
|
||||||
),
|
),
|
||||||
200,
|
200,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
lambda: baker.make(
|
lambda: baker.make(
|
||||||
User,
|
User,
|
||||||
groups=[
|
groups=[Group.objects.get(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)],
|
||||||
RealGroup.objects.get(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
200,
|
200,
|
||||||
),
|
),
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,26 +25,11 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
from core.models import User
|
|
||||||
|
|
||||||
|
|
||||||
def remove_multiples_comments_from_same_user(apps, schema_editor):
|
|
||||||
for user in User.objects.exclude(uv_comments=None).prefetch_related("uv_comments"):
|
|
||||||
for uv in user.uv_comments.values("uv").distinct():
|
|
||||||
last = (
|
|
||||||
user.uv_comments.filter(uv__id=uv["uv"])
|
|
||||||
.order_by("-publish_date")
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
user.uv_comments.filter(uv__id=uv["uv"]).exclude(pk=last.pk).delete()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [("pedagogy", "0001_initial")]
|
dependencies = [("pedagogy", "0001_initial")]
|
||||||
|
|
||||||
operations = [
|
# This migration contained just a RunPython operation
|
||||||
migrations.RunPython(
|
# Which has since been removed.
|
||||||
remove_multiples_comments_from_same_user,
|
# The migration itself is kept in order not to break the migration tree
|
||||||
reverse_code=migrations.RunPython.noop,
|
operations = []
|
||||||
)
|
|
||||||
]
|
|
||||||
|
@ -8,7 +8,7 @@ from model_bakery import baker
|
|||||||
from model_bakery.recipe import Recipe
|
from model_bakery.recipe import Recipe
|
||||||
|
|
||||||
from core.baker_recipes import subscriber_user
|
from core.baker_recipes import subscriber_user
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from pedagogy.models import UV
|
from pedagogy.models import UV
|
||||||
|
|
||||||
|
|
||||||
@ -80,9 +80,7 @@ class TestUVSearch(TestCase):
|
|||||||
subscriber_user.make(),
|
subscriber_user.make(),
|
||||||
baker.make(
|
baker.make(
|
||||||
User,
|
User,
|
||||||
groups=[
|
groups=[Group.objects.get(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)],
|
||||||
RealGroup.objects.get(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
# users that have right
|
# users that have right
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db.models import Exists, OuterRef
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.views.generic import (
|
from django.views.generic import (
|
||||||
@ -34,7 +35,7 @@ from django.views.generic import (
|
|||||||
UpdateView,
|
UpdateView,
|
||||||
)
|
)
|
||||||
|
|
||||||
from core.models import Notification, RealGroup
|
from core.models import Notification, User
|
||||||
from core.views import (
|
from core.views import (
|
||||||
CanCreateMixin,
|
CanCreateMixin,
|
||||||
CanEditPropMixin,
|
CanEditPropMixin,
|
||||||
@ -156,21 +157,19 @@ class UVCommentReportCreateView(CanCreateMixin, CreateView):
|
|||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
resp = super().form_valid(form)
|
resp = super().form_valid(form)
|
||||||
|
|
||||||
# Send a message to moderation admins
|
# Send a message to moderation admins
|
||||||
for user in (
|
unread_notif_subquery = Notification.objects.filter(
|
||||||
RealGroup.objects.filter(id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
user=OuterRef("pk"), type="PEDAGOGY_MODERATION", viewed=False
|
||||||
.first()
|
)
|
||||||
.users.all()
|
for user in User.objects.filter(
|
||||||
|
~Exists(unread_notif_subquery),
|
||||||
|
groups__id__in=[settings.SITH_GROUP_PEDAGOGY_ADMIN_ID],
|
||||||
):
|
):
|
||||||
if not user.notifications.filter(
|
Notification.objects.create(
|
||||||
type="PEDAGOGY_MODERATION", viewed=False
|
user=user,
|
||||||
).exists():
|
url=reverse("pedagogy:moderation"),
|
||||||
Notification(
|
type="PEDAGOGY_MODERATION",
|
||||||
user=user,
|
)
|
||||||
url=reverse("pedagogy:moderation"),
|
|
||||||
type="PEDAGOGY_MODERATION",
|
|
||||||
).save()
|
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from django.urls import reverse
|
|||||||
from django.utils.timezone import localtime, now
|
from django.utils.timezone import localtime, now
|
||||||
|
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from counter.models import Counter, Customer, Product, Refilling, Selling
|
from counter.models import Counter, Customer, Product, Refilling, Selling
|
||||||
from subscription.models import Subscription
|
from subscription.models import Subscription
|
||||||
|
|
||||||
@ -50,9 +50,9 @@ class TestMergeUser(TestCase):
|
|||||||
self.to_keep.address = "Jerusalem"
|
self.to_keep.address = "Jerusalem"
|
||||||
self.to_delete.parent_address = "Rome"
|
self.to_delete.parent_address = "Rome"
|
||||||
self.to_delete.address = "Rome"
|
self.to_delete.address = "Rome"
|
||||||
subscribers = RealGroup.objects.get(name="Subscribers")
|
subscribers = Group.objects.get(name="Subscribers")
|
||||||
mde_admin = RealGroup.objects.get(name="MDE admin")
|
mde_admin = Group.objects.get(name="MDE admin")
|
||||||
sas_admin = RealGroup.objects.get(name="SAS admin")
|
sas_admin = Group.objects.get(name="SAS admin")
|
||||||
self.to_keep.groups.add(subscribers.id)
|
self.to_keep.groups.add(subscribers.id)
|
||||||
self.to_delete.groups.add(mde_admin.id)
|
self.to_delete.groups.add(mde_admin.id)
|
||||||
self.to_keep.groups.add(sas_admin.id)
|
self.to_keep.groups.add(sas_admin.id)
|
||||||
|
@ -7,7 +7,7 @@ from model_bakery import baker
|
|||||||
from model_bakery.recipe import Recipe
|
from model_bakery.recipe import Recipe
|
||||||
|
|
||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||||
from core.models import RealGroup, SithFile, User
|
from core.models import Group, SithFile, User
|
||||||
from sas.baker_recipes import picture_recipe
|
from sas.baker_recipes import picture_recipe
|
||||||
from sas.models import Album, PeoplePictureRelation, Picture, PictureModerationRequest
|
from sas.models import Album, PeoplePictureRelation, Picture, PictureModerationRequest
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ class TestPictureRelation(TestSas):
|
|||||||
def test_delete_relation_with_authorized_users(self):
|
def test_delete_relation_with_authorized_users(self):
|
||||||
"""Test that deletion works as intended when called by an authorized user."""
|
"""Test that deletion works as intended when called by an authorized user."""
|
||||||
relation: PeoplePictureRelation = self.user_a.pictures.first()
|
relation: PeoplePictureRelation = self.user_a.pictures.first()
|
||||||
sas_admin_group = RealGroup.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
sas_admin_group = Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||||
sas_admin = baker.make(User, groups=[sas_admin_group])
|
sas_admin = baker.make(User, groups=[sas_admin_group])
|
||||||
root = baker.make(User, is_superuser=True)
|
root = baker.make(User, is_superuser=True)
|
||||||
for user in sas_admin, root, self.user_a:
|
for user in sas_admin, root, self.user_a:
|
||||||
@ -189,7 +189,7 @@ class TestPictureModeration(TestSas):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
super().setUpTestData()
|
super().setUpTestData()
|
||||||
cls.sas_admin = baker.make(
|
cls.sas_admin = 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)]
|
||||||
)
|
)
|
||||||
cls.picture = Picture.objects.filter(parent=cls.album_a)[0]
|
cls.picture = Picture.objects.filter(parent=cls.album_a)[0]
|
||||||
cls.picture.is_moderated = False
|
cls.picture.is_moderated = False
|
||||||
|
@ -23,7 +23,7 @@ from model_bakery import baker
|
|||||||
from pytest_django.asserts import assertInHTML, assertRedirects
|
from pytest_django.asserts import assertInHTML, assertRedirects
|
||||||
|
|
||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||||
from core.models import RealGroup, User
|
from core.models import Group, User
|
||||||
from sas.baker_recipes import picture_recipe
|
from sas.baker_recipes import picture_recipe
|
||||||
from sas.models import Album, Picture
|
from sas.models import Album, Picture
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ from sas.models import Album, Picture
|
|||||||
old_subscriber_user.make,
|
old_subscriber_user.make,
|
||||||
lambda: baker.make(User, is_superuser=True),
|
lambda: baker.make(User, is_superuser=True),
|
||||||
lambda: baker.make(
|
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),
|
lambda: baker.make(User),
|
||||||
],
|
],
|
||||||
@ -80,7 +80,7 @@ class TestSasModeration(TestCase):
|
|||||||
cls.to_moderate.is_moderated = False
|
cls.to_moderate.is_moderated = False
|
||||||
cls.to_moderate.save()
|
cls.to_moderate.save()
|
||||||
cls.moderator = baker.make(
|
cls.moderator = 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)]
|
||||||
)
|
)
|
||||||
cls.simple_user = subscriber_user.make()
|
cls.simple_user = subscriber_user.make()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user