mirror of
https://github.com/ae-utbm/sith.git
synced 2024-12-22 15:51:19 +00:00
Merge pull request #691 from ae-utbm/update-django
Update django (3.2 => 4.2)
This commit is contained in:
commit
47fec973bc
@ -207,11 +207,11 @@ class Club(models.Model):
|
||||
cache.set(f"sith_club_{self.unix_name}", self)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
# Invalidate the cache of this club and of its memberships
|
||||
for membership in self.members.ongoing().select_related("user"):
|
||||
cache.delete(f"membership_{self.id}_{membership.user.id}")
|
||||
cache.delete(f"sith_club_{self.unix_name}")
|
||||
super().delete(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -46,6 +46,8 @@ class ClubTest(TestCase):
|
||||
def setUpTestData(cls):
|
||||
# subscribed users - initial members
|
||||
cls.skia = User.objects.get(username="skia")
|
||||
# by default, Skia is in the AE, which creates side effect
|
||||
cls.skia.memberships.all().delete()
|
||||
cls.richard = User.objects.get(username="rbatsbak")
|
||||
cls.comptable = User.objects.get(username="comptable")
|
||||
cls.sli = User.objects.get(username="sli")
|
||||
@ -62,38 +64,32 @@ class ClubTest(TestCase):
|
||||
cls.public = User.objects.get(username="public")
|
||||
|
||||
cls.ae = Club.objects.filter(pk=SITH_MAIN_CLUB_ID)[0]
|
||||
|
||||
def setUp(self):
|
||||
# by default, Skia is in the AE, which creates side effect
|
||||
self.skia.memberships.all().delete()
|
||||
|
||||
# create a fake club
|
||||
self.club = Club.objects.create(
|
||||
cls.club = Club.objects.create(
|
||||
name="Fake Club",
|
||||
unix_name="fake-club",
|
||||
address="5 rue de la République, 90000 Belfort",
|
||||
)
|
||||
self.members_url = reverse(
|
||||
"club:club_members", kwargs={"club_id": self.club.id}
|
||||
)
|
||||
cls.members_url = reverse("club:club_members", kwargs={"club_id": cls.club.id})
|
||||
a_month_ago = now() - timedelta(days=30)
|
||||
yesterday = now() - timedelta(days=1)
|
||||
Membership.objects.create(
|
||||
club=self.club, user=self.skia, start_date=a_month_ago, role=3
|
||||
club=cls.club, user=cls.skia, start_date=a_month_ago, role=3
|
||||
)
|
||||
Membership.objects.create(club=self.club, user=self.richard, role=1)
|
||||
Membership.objects.create(club=cls.club, user=cls.richard, role=1)
|
||||
Membership.objects.create(
|
||||
club=self.club, user=self.comptable, start_date=a_month_ago, role=10
|
||||
club=cls.club, user=cls.comptable, start_date=a_month_ago, role=10
|
||||
)
|
||||
|
||||
# sli was a member but isn't anymore
|
||||
Membership.objects.create(
|
||||
club=self.club,
|
||||
user=self.sli,
|
||||
club=cls.club,
|
||||
user=cls.sli,
|
||||
start_date=a_month_ago,
|
||||
end_date=yesterday,
|
||||
role=2,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
cache.clear()
|
||||
|
||||
|
||||
@ -176,14 +172,11 @@ class MembershipQuerySetTest(ClubTest):
|
||||
# should delete the subscriptions of skia and comptable
|
||||
self.club.members.ongoing().board().delete()
|
||||
|
||||
assert (
|
||||
cache.get(f"membership_{mem_skia.club_id}_{mem_skia.user_id}")
|
||||
== "not_member"
|
||||
)
|
||||
assert (
|
||||
cache.get(f"membership_{mem_comptable.club_id}_{mem_comptable.user_id}")
|
||||
== "not_member",
|
||||
)
|
||||
for membership in (mem_skia, mem_comptable):
|
||||
cached_mem = cache.get(
|
||||
f"membership_{membership.club_id}_{membership.user_id}"
|
||||
)
|
||||
assert cached_mem == "not_member"
|
||||
|
||||
|
||||
class ClubModelTest(ClubTest):
|
||||
|
19
core/migrations/0038_alter_preferences_receive_weekmail.py
Normal file
19
core/migrations/0038_alter_preferences_receive_weekmail.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2 on 2024-06-26 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("core", "0037_auto_20211105_1708"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="preferences",
|
||||
name="receive_weekmail",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="receive the Weekmail"
|
||||
),
|
||||
),
|
||||
]
|
@ -162,8 +162,9 @@
|
||||
<div>
|
||||
{% trans %}Not subscribed{% endtrans %}
|
||||
{% if user.is_board_member %}
|
||||
<a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">{% trans %}New subscription{% endtrans
|
||||
%}</a>
|
||||
<a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">
|
||||
{% trans %}New subscription{% endtrans %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -133,8 +133,9 @@
|
||||
</p>
|
||||
{%- elif user.is_root -%}
|
||||
<p>
|
||||
<a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">{%- trans -%}Change user password{%-
|
||||
endtrans -%}</a>
|
||||
<a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">
|
||||
{%- trans -%}Change user password{%- endtrans -%}
|
||||
</a>
|
||||
</p>
|
||||
{%- endif -%}
|
||||
|
||||
|
@ -28,6 +28,7 @@ from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils import timezone
|
||||
from PIL import ExifTags
|
||||
from PIL.Image import Resampling
|
||||
|
||||
|
||||
def get_git_revision_short_hash() -> str:
|
||||
@ -109,7 +110,8 @@ def resize_image(im, edge, format):
|
||||
(w, h) = im.size
|
||||
(width, height) = scale_dimension(w, h, long_edge=edge)
|
||||
content = BytesIO()
|
||||
im = im.resize((width, height), PIL.Image.ANTIALIAS)
|
||||
# use the lanczos filter for antialiasing
|
||||
im = im.resize((width, height), Resampling.LANCZOS)
|
||||
try:
|
||||
im.save(
|
||||
fp=content,
|
||||
|
@ -2,9 +2,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from datetime import timezone
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -17,7 +17,9 @@ class Migration(migrations.Migration):
|
||||
field=models.DateTimeField(
|
||||
verbose_name="activity time",
|
||||
auto_now=True,
|
||||
default=datetime.datetime(2016, 8, 26, 17, 5, 31, 202824, tzinfo=utc),
|
||||
default=datetime.datetime(
|
||||
2016, 8, 26, 17, 5, 31, 202824, tzinfo=timezone.utc
|
||||
),
|
||||
),
|
||||
preserve_default=False,
|
||||
)
|
||||
|
@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2 on 2024-06-26 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [("counter", "0020_auto_20221215_1709")]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="cashregistersummaryitem",
|
||||
old_name="check",
|
||||
new_name="is_check",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="cashregistersummaryitem",
|
||||
name="is_check",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="True if this is a bank check, else False",
|
||||
verbose_name="check",
|
||||
),
|
||||
),
|
||||
]
|
@ -19,8 +19,8 @@ import base64
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Optional, Tuple
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from typing import Tuple
|
||||
|
||||
from dict2xml import dict2xml
|
||||
from django.conf import settings
|
||||
@ -534,7 +534,7 @@ class Counter(models.Model):
|
||||
.order_by("-perm_sum")
|
||||
)
|
||||
|
||||
def get_top_customers(self, since: Optional[date] = None) -> QuerySet:
|
||||
def get_top_customers(self, since: datetime | date | None = None) -> QuerySet:
|
||||
"""
|
||||
Return a QuerySet querying the money spent by customers of this counter
|
||||
since the specified date, ordered by descending amount of money spent.
|
||||
@ -543,9 +543,13 @@ class Counter(models.Model):
|
||||
- the full name (first name + last name) of the customer
|
||||
- the nickname of the customer
|
||||
- the amount of money spent by the customer
|
||||
|
||||
:param since: timestamp from which to perform the calculation
|
||||
"""
|
||||
if since is None:
|
||||
since = get_start_of_semester()
|
||||
if isinstance(since, date):
|
||||
since = datetime(since.year, since.month, since.day, tzinfo=timezone.utc)
|
||||
return (
|
||||
self.sellings.filter(date__gte=since)
|
||||
.annotate(
|
||||
@ -568,19 +572,18 @@ class Counter(models.Model):
|
||||
.order_by("-selling_sum")
|
||||
)
|
||||
|
||||
def get_total_sales(self, since=None) -> CurrencyField:
|
||||
def get_total_sales(self, since: datetime | date | None = None) -> CurrencyField:
|
||||
"""
|
||||
Compute and return the total turnover of this counter
|
||||
since the date specified in parameter (by default, since the start of the current
|
||||
semester)
|
||||
:param since: timestamp from which to perform the calculation
|
||||
:type since: datetime | date | None
|
||||
:return: Total revenue earned at this counter
|
||||
"""
|
||||
if since is None:
|
||||
since = get_start_of_semester()
|
||||
if isinstance(since, date):
|
||||
since = datetime.combine(since, datetime.min.time())
|
||||
since = datetime(since.year, since.month, since.day, tzinfo=timezone.utc)
|
||||
total = self.sellings.filter(date__gte=since).aggregate(
|
||||
total=Sum(F("quantity") * F("unit_price"), output_field=CurrencyField())
|
||||
)["total"]
|
||||
@ -927,25 +930,25 @@ class CashRegisterSummary(models.Model):
|
||||
if name[:5] == "check":
|
||||
checks = self.items.filter(check=True).order_by("value").all()
|
||||
if name == "ten_cents":
|
||||
return self.items.filter(value=0.1, check=False).first()
|
||||
return self.items.filter(value=0.1, is_check=False).first()
|
||||
elif name == "twenty_cents":
|
||||
return self.items.filter(value=0.2, check=False).first()
|
||||
return self.items.filter(value=0.2, is_check=False).first()
|
||||
elif name == "fifty_cents":
|
||||
return self.items.filter(value=0.5, check=False).first()
|
||||
return self.items.filter(value=0.5, is_check=False).first()
|
||||
elif name == "one_euro":
|
||||
return self.items.filter(value=1, check=False).first()
|
||||
return self.items.filter(value=1, is_check=False).first()
|
||||
elif name == "two_euros":
|
||||
return self.items.filter(value=2, check=False).first()
|
||||
return self.items.filter(value=2, is_check=False).first()
|
||||
elif name == "five_euros":
|
||||
return self.items.filter(value=5, check=False).first()
|
||||
return self.items.filter(value=5, is_check=False).first()
|
||||
elif name == "ten_euros":
|
||||
return self.items.filter(value=10, check=False).first()
|
||||
return self.items.filter(value=10, is_check=False).first()
|
||||
elif name == "twenty_euros":
|
||||
return self.items.filter(value=20, check=False).first()
|
||||
return self.items.filter(value=20, is_check=False).first()
|
||||
elif name == "fifty_euros":
|
||||
return self.items.filter(value=50, check=False).first()
|
||||
return self.items.filter(value=50, is_check=False).first()
|
||||
elif name == "hundred_euros":
|
||||
return self.items.filter(value=100, check=False).first()
|
||||
return self.items.filter(value=100, is_check=False).first()
|
||||
elif name == "check_1":
|
||||
return checks[0] if 0 < len(checks) else None
|
||||
elif name == "check_2":
|
||||
@ -993,7 +996,11 @@ class CashRegisterSummaryItem(models.Model):
|
||||
)
|
||||
value = CurrencyField(_("value"))
|
||||
quantity = models.IntegerField(_("quantity"), default=0)
|
||||
check = models.BooleanField(_("check"), default=False)
|
||||
is_check = models.BooleanField(
|
||||
_("check"),
|
||||
default=False,
|
||||
help_text=_("True if this is a bank check, else False"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("cash register summary item")
|
||||
|
@ -1204,35 +1204,35 @@ class CashRegisterSummaryForm(forms.Form):
|
||||
cash_summary=summary,
|
||||
value=cd["check_1_value"],
|
||||
quantity=cd["check_1_quantity"],
|
||||
check=True,
|
||||
is_check=True,
|
||||
).save()
|
||||
if cd["check_2_quantity"]:
|
||||
CashRegisterSummaryItem(
|
||||
cash_summary=summary,
|
||||
value=cd["check_2_value"],
|
||||
quantity=cd["check_2_quantity"],
|
||||
check=True,
|
||||
is_check=True,
|
||||
).save()
|
||||
if cd["check_3_quantity"]:
|
||||
CashRegisterSummaryItem(
|
||||
cash_summary=summary,
|
||||
value=cd["check_3_value"],
|
||||
quantity=cd["check_3_quantity"],
|
||||
check=True,
|
||||
is_check=True,
|
||||
).save()
|
||||
if cd["check_4_quantity"]:
|
||||
CashRegisterSummaryItem(
|
||||
cash_summary=summary,
|
||||
value=cd["check_4_value"],
|
||||
quantity=cd["check_4_quantity"],
|
||||
check=True,
|
||||
is_check=True,
|
||||
).save()
|
||||
if cd["check_5_quantity"]:
|
||||
CashRegisterSummaryItem(
|
||||
cash_summary=summary,
|
||||
value=cd["check_5_value"],
|
||||
quantity=cd["check_5_quantity"],
|
||||
check=True,
|
||||
is_check=True,
|
||||
).save()
|
||||
if summary.items.count() < 1:
|
||||
summary.delete()
|
||||
|
@ -2,12 +2,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from datetime import timezone
|
||||
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -226,7 +226,9 @@ class Migration(migrations.Migration):
|
||||
"last_read_date",
|
||||
models.DateTimeField(
|
||||
verbose_name="last read date",
|
||||
default=datetime.datetime(1999, 1, 1, 0, 0, tzinfo=utc),
|
||||
default=datetime.datetime(
|
||||
1999, 1, 1, 0, 0, tzinfo=timezone.utc
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
|
File diff suppressed because it is too large
Load Diff
27
pedagogy/migrations/0003_alter_uv_language.py
Normal file
27
pedagogy/migrations/0003_alter_uv_language.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Generated by Django 4.2 on 2024-06-26 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("pedagogy", "0002_auto_20190827_2251"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="uv",
|
||||
name="language",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("FR", "French"),
|
||||
("EN", "English"),
|
||||
("DE", "German"),
|
||||
("SP", "Spanish"),
|
||||
],
|
||||
default="FR",
|
||||
max_length=10,
|
||||
verbose_name="language",
|
||||
),
|
||||
),
|
||||
]
|
29
poetry.lock
generated
29
poetry.lock
generated
@ -413,19 +413,19 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "3.2.25"
|
||||
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
|
||||
version = "4.2.13"
|
||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"},
|
||||
{file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"},
|
||||
{file = "Django-4.2.13-py3-none-any.whl", hash = "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a"},
|
||||
{file = "Django-4.2.13.tar.gz", hash = "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
asgiref = ">=3.3.2,<4"
|
||||
pytz = "*"
|
||||
sqlparse = ">=0.2.2"
|
||||
asgiref = ">=3.6.0,<4"
|
||||
sqlparse = ">=0.3.1"
|
||||
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
argon2 = ["argon2-cffi (>=19.1.0)"]
|
||||
@ -1776,6 +1776,17 @@ files = [
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2024.1"
|
||||
description = "Provider of IANA time zone data"
|
||||
optional = false
|
||||
python-versions = ">=2"
|
||||
files = [
|
||||
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
||||
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.2.2"
|
||||
@ -1842,4 +1853,4 @@ filelock = ">=3.4"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10,<3.12"
|
||||
content-hash = "7f807b6216c032932ac20e2bdac462c7a2c4e8db328cdd3536281d6fbc009776"
|
||||
content-hash = "b090426042093af41cfbbced92a1a47bf0834ce88865dc7f51d0b7b04fda99a7"
|
||||
|
@ -21,7 +21,7 @@ license = "GPL-3.0-only"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10,<3.12" # Version is held back by mistune
|
||||
Django = "^3.2"
|
||||
Django = "^4.2.13"
|
||||
Pillow = "^9.2"
|
||||
mistune = "^0.8.4"
|
||||
django-jinja = "^2.10"
|
||||
|
@ -187,6 +187,7 @@ TEMPLATES = [
|
||||
},
|
||||
},
|
||||
]
|
||||
FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
|
||||
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
"default": {
|
||||
@ -248,8 +249,6 @@ TIME_ZONE = "Europe/Paris"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
|
||||
@ -690,7 +689,6 @@ if DEBUG:
|
||||
"sith.toolbar_debug.TemplatesPanel",
|
||||
"debug_toolbar.panels.cache.CachePanel",
|
||||
"debug_toolbar.panels.signals.SignalsPanel",
|
||||
"debug_toolbar.panels.logging.LoggingPanel",
|
||||
"debug_toolbar.panels.redirects.RedirectsPanel",
|
||||
]
|
||||
SASS_INCLUDE_FOLDERS = ["core/static/"]
|
||||
|
Loading…
Reference in New Issue
Block a user