ruff rule DJ

Co-authored-by: Bartuccio Antoine <klmp200@users.noreply.github.com>
This commit is contained in:
thomas girod 2024-06-27 15:48:07 +02:00
parent f941435232
commit 2ac578c3ad
20 changed files with 537 additions and 516 deletions

View File

@ -61,6 +61,15 @@ class Company(models.Model):
class Meta:
verbose_name = _("company")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("accounting:co_edit", kwargs={"co_id": self.id})
def get_display_name(self):
return self.name
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -87,15 +96,6 @@ class Company(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("accounting:co_edit", kwargs={"co_id": self.id})
def get_display_name(self):
return self.name
def __str__(self):
return self.name
class BankAccount(models.Model):
name = models.CharField(_("name"), max_length=30)
@ -112,6 +112,12 @@ class BankAccount(models.Model):
verbose_name = _("Bank account")
ordering = ["club", "name"]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("accounting:bank_details", kwargs={"b_account_id": self.id})
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -125,12 +131,6 @@ class BankAccount(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("accounting:bank_details", kwargs={"b_account_id": self.id})
def __str__(self):
return self.name
class ClubAccount(models.Model):
name = models.CharField(_("name"), max_length=30)
@ -151,6 +151,12 @@ class ClubAccount(models.Model):
verbose_name = _("Club account")
ordering = ["bank_account", "name"]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("accounting:club_details", kwargs={"c_account_id": self.id})
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -188,12 +194,6 @@ class ClubAccount(models.Model):
def get_open_journal(self):
return self.journals.filter(closed=False).first()
def get_absolute_url(self):
return reverse("accounting:club_details", kwargs={"c_account_id": self.id})
def __str__(self):
return self.name
def get_display_name(self):
return _("%(club_account)s on %(bank_account)s") % {
"club_account": self.name,
@ -224,6 +224,12 @@ class GeneralJournal(models.Model):
verbose_name = _("General journal")
ordering = ["-start_date"]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("accounting:journal_details", kwargs={"j_id": self.id})
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -249,12 +255,6 @@ class GeneralJournal(models.Model):
def can_be_viewed_by(self, user):
return self.club_account.can_be_viewed_by(user)
def get_absolute_url(self):
return reverse("accounting:journal_details", kwargs={"j_id": self.id})
def __str__(self):
return self.name
def update_amounts(self):
self.amount = 0
self.effective_amount = 0
@ -356,6 +356,18 @@ class Operation(models.Model):
unique_together = ("number", "journal")
ordering = ["-number"]
def __str__(self):
return f"{self.amount} € | {self.date} | {self.accounting_type} | {self.done}"
def save(self, *args, **kwargs):
if self.number is None:
self.number = self.journal.operations.count() + 1
super().save(*args, **kwargs)
self.journal.update_amounts()
def get_absolute_url(self):
return reverse("accounting:journal_details", kwargs={"j_id": self.journal.id})
def __getattribute__(self, attr):
if attr == "target":
return self.get_target()
@ -409,12 +421,6 @@ class Operation(models.Model):
tar = Company.objects.filter(id=self.target_id).first()
return tar
def save(self):
if self.number is None:
self.number = self.journal.operations.count() + 1
super().save()
self.journal.update_amounts()
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -443,17 +449,6 @@ class Operation(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("accounting:journal_details", kwargs={"j_id": self.journal.id})
def __str__(self):
return "%d € | %s | %s | %s" % (
self.amount,
self.date,
self.accounting_type,
self.done,
)
class AccountingType(models.Model):
"""
@ -486,6 +481,12 @@ class AccountingType(models.Model):
verbose_name = _("accounting type")
ordering = ["movement_type", "code"]
def __str__(self):
return self.code + " - " + self.get_movement_type_display() + " - " + self.label
def get_absolute_url(self):
return reverse("accounting:type_list")
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -496,12 +497,6 @@ class AccountingType(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("accounting:type_list")
def __str__(self):
return self.code + " - " + self.get_movement_type_display() + " - " + self.label
class SimplifiedAccountingType(models.Model):
"""
@ -520,6 +515,15 @@ class SimplifiedAccountingType(models.Model):
verbose_name = _("simplified type")
ordering = ["accounting_type__movement_type", "accounting_type__code"]
def __str__(self):
return (
f"{self.get_movement_type_display()} "
f"- {self.accounting_type.code} - {self.label}"
)
def get_absolute_url(self):
return reverse("accounting:simple_type_list")
@property
def movement_type(self):
return self.accounting_type.movement_type
@ -527,18 +531,6 @@ class SimplifiedAccountingType(models.Model):
def get_movement_type_display(self):
return self.accounting_type.get_movement_type_display()
def get_absolute_url(self):
return reverse("accounting:simple_type_list")
def __str__(self):
return (
self.get_movement_type_display()
+ " - "
+ self.accounting_type.code
+ " - "
+ self.label
)
class Label(models.Model):
"""Label allow a club to sort its operations"""

View File

@ -15,7 +15,7 @@ class Migration(migrations.Migration):
name="owner_group",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
default=club.models.Club.get_default_owner_group,
default=club.models.get_default_owner_group,
related_name="owned_club",
to="core.Group",
),

View File

@ -40,6 +40,11 @@ from core.models import Group, MetaGroup, Notification, Page, RealGroup, SithFil
# Create your models here.
# This function prevents generating migration upon settings change
def get_default_owner_group():
return settings.SITH_GROUP_ROOT_ID
class Club(models.Model):
"""
The Club class, made as a tree to allow nice tidy organization
@ -74,10 +79,6 @@ class Club(models.Model):
)
address = models.CharField(_("address"), max_length=254)
# This function prevents generating migration upon settings change
def get_default_owner_group():
return settings.SITH_GROUP_ROOT_ID
owner_group = models.ForeignKey(
Group,
related_name="owned_club",
@ -105,6 +106,34 @@ class Club(models.Model):
class Meta:
ordering = ["name", "unix_name"]
def __str__(self):
return self.name
@transaction.atomic()
def save(self, *args, **kwargs):
old = Club.objects.filter(id=self.id).first()
creation = old is None
if not creation and old.unix_name != self.unix_name:
self._change_unixname(self.unix_name)
super().save(*args, **kwargs)
if creation:
board = MetaGroup(name=self.unix_name + settings.SITH_BOARD_SUFFIX)
board.save()
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
member.save()
subscribers = Group.objects.filter(
name=settings.SITH_MAIN_MEMBERS_GROUP
).first()
self.make_home()
self.home.edit_groups.set([board])
self.home.view_groups.set([member, subscribers])
self.home.save()
self.make_page()
cache.set(f"sith_club_{self.unix_name}", self)
def get_absolute_url(self):
return reverse("club:club_view", kwargs={"club_id": self.id})
@cached_property
def president(self):
return self.members.filter(
@ -183,28 +212,6 @@ class Club(models.Model):
self.page.parent = self.parent.page
self.page.save(force_lock=True)
@transaction.atomic()
def save(self, *args, **kwargs):
old = Club.objects.filter(id=self.id).first()
creation = old is None
if not creation and old.unix_name != self.unix_name:
self._change_unixname(self.unix_name)
super().save(*args, **kwargs)
if creation:
board = MetaGroup(name=self.unix_name + settings.SITH_BOARD_SUFFIX)
board.save()
member = MetaGroup(name=self.unix_name + settings.SITH_MEMBER_SUFFIX)
member.save()
subscribers = Group.objects.filter(
name=settings.SITH_MAIN_MEMBERS_GROUP
).first()
self.make_home()
self.home.edit_groups.set([board])
self.home.view_groups.set([member, subscribers])
self.home.save()
self.make_page()
cache.set(f"sith_club_{self.unix_name}", self)
def delete(self, *args, **kwargs):
# Invalidate the cache of this club and of its memberships
for membership in self.members.ongoing().select_related("user"):
@ -212,12 +219,6 @@ class Club(models.Model):
cache.delete(f"sith_club_{self.unix_name}")
super().delete(*args, **kwargs)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("club:club_view", kwargs={"club_id": self.id})
def get_display_name(self):
return self.name
@ -373,14 +374,21 @@ class Membership(models.Model):
def __str__(self):
return (
self.club.name
+ " - "
+ self.user.username
+ " - "
+ str(settings.SITH_CLUB_ROLES[self.role])
+ str(" - " + str(_("past member")) if self.end_date is not None else "")
f"{self.club.name} - {self.user.username} "
f"- {settings.SITH_CLUB_ROLES[self.role]} "
f"- {str(_('past member')) if self.end_date is not None else ''}"
)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.end_date is None:
cache.set(f"membership_{self.club_id}_{self.user_id}", self)
else:
cache.set(f"membership_{self.club_id}_{self.user_id}", "not_member")
def get_absolute_url(self):
return reverse("club:club_members", kwargs={"club_id": self.club_id})
def is_owned_by(self, user):
"""
Method to see if that object can be super edited by the given user
@ -400,16 +408,6 @@ class Membership(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("club:club_members", kwargs={"club_id": self.club_id})
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if self.end_date is None:
cache.set(f"membership_{self.club_id}_{self.user_id}", self)
else:
cache.set(f"membership_{self.club_id}_{self.user_id}", "not_member")
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
cache.delete(f"membership_{self.club_id}_{self.user_id}")
@ -451,6 +449,26 @@ class Mailing(models.Model):
on_delete=models.CASCADE,
)
def __str__(self):
return "%s - %s" % (self.club, self.email_full)
def save(self, *args, **kwargs):
if not self.is_moderated:
for user in (
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
.first()
.users.all()
):
if not user.notifications.filter(
type="MAILING_MODERATION", viewed=False
).exists():
Notification(
user=user,
url=reverse("com:mailing_admin"),
type="MAILING_MODERATION",
).save(*args, **kwargs)
super().save(*args, **kwargs)
def clean(self):
if Mailing.objects.filter(email=self.email).exists():
raise ValidationError(_("This mailing list already exists."))
@ -488,26 +506,6 @@ class Mailing(models.Model):
resp += sub.fetch_format()
return resp
def save(self):
if not self.is_moderated:
for user in (
RealGroup.objects.filter(id=settings.SITH_GROUP_COM_ADMIN_ID)
.first()
.users.all()
):
if not user.notifications.filter(
type="MAILING_MODERATION", viewed=False
).exists():
Notification(
user=user,
url=reverse("com:mailing_admin"),
type="MAILING_MODERATION",
).save()
super().save()
def __str__(self):
return "%s - %s" % (self.club, self.email_full)
class MailingSubscription(models.Model):
"""
@ -535,6 +533,9 @@ class MailingSubscription(models.Model):
class Meta:
unique_together = (("user", "email", "mailing"),)
def __str__(self):
return "(%s) - %s : %s" % (self.mailing, self.get_username, self.email)
def clean(self):
if not self.user and not self.email:
raise ValidationError(_("At least user or email is required"))
@ -577,6 +578,3 @@ class MailingSubscription(models.Model):
def fetch_format(self):
return self.get_email + " "
def __str__(self):
return "(%s) - %s : %s" % (self.mailing, self.get_username, self.email)

View File

@ -46,14 +46,14 @@ class Sith(models.Model):
weekmail_destinations = models.TextField(_("weekmail destinations"), default="")
version = utils.get_git_revision_short_hash()
def __str__(self):
return "⛩ Sith ⛩"
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_com_admin
def __str__(self):
return "⛩ Sith ⛩"
NEWS_TYPES = [
("NOTICE", _("Notice")),
@ -90,23 +90,6 @@ class News(models.Model):
on_delete=models.CASCADE,
)
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_com_admin or user == self.author
def can_be_edited_by(self, user):
return user.is_com_admin
def can_be_viewed_by(self, user):
return self.is_moderated or user.is_com_admin
def get_absolute_url(self):
return reverse("com:news_detail", kwargs={"news_id": self.id})
def get_full_url(self):
return "https://%s%s" % (settings.SITH_URL, self.get_absolute_url())
def __str__(self):
return "%s: %s" % (self.type, self.title)
@ -124,6 +107,23 @@ class News(models.Model):
param="1",
).save()
def get_absolute_url(self):
return reverse("com:news_detail", kwargs={"news_id": self.id})
def get_full_url(self):
return "https://%s%s" % (settings.SITH_URL, self.get_absolute_url())
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_com_admin or user == self.author
def can_be_edited_by(self, user):
return user.is_com_admin
def can_be_viewed_by(self, user):
return self.is_moderated or user.is_com_admin
def news_notification_callback(notif):
count = (
@ -185,6 +185,9 @@ class Weekmail(models.Model):
class Meta:
ordering = ["-id"]
def __str__(self):
return f"Weekmail {self.id} (sent: {self.sent}) - {self.title}"
def send(self):
"""
Send the weekmail to all users with the receive weekmail option opt-in.
@ -240,9 +243,6 @@ class Weekmail(models.Model):
"""
return "http://" + settings.SITH_URL + static("com/img/weekmail_footerP22.png")
def __str__(self):
return "Weekmail %s (sent: %s) - %s" % (self.id, self.sent, self.title)
def is_owned_by(self, user):
if user.is_anonymous:
return False
@ -273,18 +273,21 @@ class WeekmailArticle(models.Model):
)
rank = models.IntegerField(_("rank"), default=-1)
def __str__(self):
return "%s - %s (%s)" % (self.title, self.author, self.club)
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_com_admin
def __str__(self):
return "%s - %s (%s)" % (self.title, self.author, self.club)
class Screen(models.Model):
name = models.CharField(_("name"), max_length=128)
def __str__(self):
return self.name
def active_posters(self):
now = timezone.now()
return self.posters.filter(is_moderated=True, date_begin__lte=now).filter(
@ -296,9 +299,6 @@ class Screen(models.Model):
return False
return user.is_com_admin
def __str__(self):
return "%s" % (self.name)
class Poster(models.Model):
name = models.CharField(
@ -328,6 +328,9 @@ class Poster(models.Model):
on_delete=models.CASCADE,
)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.is_moderated:
for u in (
@ -360,6 +363,3 @@ class Poster(models.Model):
@property
def page(self):
return self.club.page
def __str__(self):
return self.name

View File

@ -16,7 +16,7 @@ class Migration(migrations.Migration):
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
verbose_name="owner group",
default=core.models.Page.get_default_owner_group,
default=core.models.get_default_owner_group,
related_name="owned_page",
to="core.Group",
),

View File

@ -845,12 +845,15 @@ class Preferences(models.Model):
_("get a notification for every refilling"), default=False
)
def get_display_name(self):
return self.user.get_display_name()
def __str__(self):
return f"Preferences of {self.user}"
def get_absolute_url(self):
return self.user.get_absolute_url()
def get_display_name(self):
return self.user.get_display_name()
def get_directory(instance, filename):
return ".{0}/{1}".format(instance.get_parent_path(), filename)
@ -928,6 +931,31 @@ class SithFile(models.Model):
class Meta:
verbose_name = _("file")
def __str__(self):
return self.get_parent_path() + "/" + self.name
def save(self, *args, **kwargs):
sas = SithFile.objects.filter(id=settings.SITH_SAS_ROOT_DIR_ID).first()
self.is_in_sas = sas in self.get_parent_list() or self == sas
copy_rights = False
if self.id is None:
copy_rights = True
super().save(*args, **kwargs)
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()
):
Notification(
user=u,
url=reverse("sas:moderation"),
type="SAS_MODERATION",
param="1",
).save()
def can_be_managed_by(self, user: User) -> bool:
"""
Tell if the user can manage the file (edit, delete, etc.) or not.
@ -1033,28 +1061,6 @@ class SithFile(models.Model):
if self.is_file and (self.file is None or self.file == ""):
raise ValidationError(_("You must provide a file"))
def save(self, *args, **kwargs):
sas = SithFile.objects.filter(id=settings.SITH_SAS_ROOT_DIR_ID).first()
self.is_in_sas = sas in self.get_parent_list() or self == sas
copy_rights = False
if self.id is None:
copy_rights = True
super().save(*args, **kwargs)
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()
):
Notification(
user=u,
url=reverse("sas:moderation"),
type="SAS_MODERATION",
param="1",
).save()
def apply_rights_recursively(self, *, only_folders=False):
children = self.children.all()
if only_folders:
@ -1189,9 +1195,6 @@ class SithFile(models.Model):
def get_download_url(self):
return reverse("core:download", kwargs={"file_id": self.id})
def __str__(self):
return self.get_parent_path() + "/" + self.name
class LockError(Exception):
"""There was a lock error on the object"""
@ -1211,6 +1214,11 @@ class NotLocked(LockError):
pass
# This function prevents generating migration upon settings change
def get_default_owner_group():
return settings.SITH_GROUP_ROOT_ID
class Page(models.Model):
"""
The page class to build a Wiki
@ -1250,10 +1258,6 @@ class Page(models.Model):
# playing with a Page object, use get_full_name() instead!
_full_name = models.CharField(_("page name"), max_length=255, blank=True)
# This function prevents generating migration upon settings change
def get_default_owner_group():
return settings.SITH_GROUP_ROOT_ID
owner_group = models.ForeignKey(
Group,
related_name="owned_page",
@ -1286,6 +1290,38 @@ class Page(models.Model):
("change_prop_page", "Can change the page's properties (groups, ...)"),
)
def __str__(self):
return self.get_full_name()
def save(self, *args, **kwargs):
"""
Performs some needed actions before and after saving a page in database
"""
locked = kwargs.pop("force_lock", False)
if not locked:
locked = self.is_locked()
if not locked:
raise NotLocked("The page is not locked and thus can not be saved")
self.full_clean()
if not self.id:
super().save(
*args, **kwargs
) # Save a first time to correctly set _full_name
# This reset the _full_name just before saving to maintain a coherent field quicker for queries than the
# recursive method
# It also update all the children to maintain correct names
self._full_name = self.get_full_name()
for c in self.children.all():
c.save()
super().save(*args, **kwargs)
self.unset_lock()
def get_absolute_url(self):
"""
This is needed for black magic powered UpdateView's children
"""
return reverse("core:page", kwargs={"page_name": self._full_name})
@staticmethod
def get_page_by_full_name(name):
"""
@ -1293,9 +1329,6 @@ class Page(models.Model):
"""
return Page.objects.filter(_full_name=name).first()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def clean(self):
"""
Cleans up only the name for the moment, but this can be used to make any treatment before saving the object
@ -1333,29 +1366,6 @@ class Page(models.Model):
p = p.parent
return l
def save(self, *args, **kwargs):
"""
Performs some needed actions before and after saving a page in database
"""
locked = kwargs.pop("force_lock", False)
if not locked:
locked = self.is_locked()
if not locked:
raise NotLocked("The page is not locked and thus can not be saved")
self.full_clean()
if not self.id:
super().save(
*args, **kwargs
) # Save a first time to correctly set _full_name
# This reset the _full_name just before saving to maintain a coherent field quicker for queries than the
# recursive method
# It also update all the children to maintain correct names
self._full_name = self.get_full_name()
for c in self.children.all():
c.save()
super().save(*args, **kwargs)
self.unset_lock()
def is_locked(self):
"""
Is True if the page is locked, False otherwise
@ -1415,15 +1425,6 @@ class Page(models.Model):
return self.lock_user
raise NotLocked("The page is not locked and thus can not return its user")
def get_absolute_url(self):
"""
This is needed for black magic powered UpdateView's children
"""
return reverse("core:page", kwargs={"page_name": self._full_name})
def __str__(self):
return self.get_full_name()
def get_full_name(self):
"""
Computes the real full_name of the page based on its name and its parent's name
@ -1480,15 +1481,22 @@ class PageRev(models.Model):
class Meta:
ordering = ["date"]
def __str__(self):
return str(self.__dict__)
def save(self, *args, **kwargs):
if self.revision is None:
self.revision = self.page.revisions.all().count() + 1
super().save(*args, **kwargs)
# Don't forget to unlock, otherwise, people will have to wait for the page's timeout
self.page.unset_lock()
def get_absolute_url(self):
"""
This is needed for black magic powered UpdateView's children
"""
return reverse("core:page", kwargs={"page_name": self.page._full_name})
def __str__(self):
return str(self.__dict__)
def __getattribute__(self, attr):
if attr == "owner_group":
return self.page.owner_group
@ -1504,13 +1512,6 @@ class PageRev(models.Model):
def can_be_edited_by(self, user):
return self.page.can_be_edited_by(user)
def save(self, *args, **kwargs):
if self.revision is None:
self.revision = self.page.revisions.all().count() + 1
super().save(*args, **kwargs)
# Don't forget to unlock, otherwise, people will have to wait for the page's timeout
self.page.unset_lock()
class Notification(models.Model):
user = models.ForeignKey(
@ -1529,15 +1530,6 @@ class Notification(models.Model):
return self.get_type_display() % self.param
return self.get_type_display()
def callback(self):
# Get the callback defined in settings to update existing
# notifications
mod_name, func_name = settings.SITH_PERMANENT_NOTIFICATIONS[self.type].rsplit(
".", 1
)
mod = importlib.import_module(mod_name)
getattr(mod, func_name)(self)
def save(self, *args, **kwargs):
if not self.id and self.type in settings.SITH_PERMANENT_NOTIFICATIONS:
old_notif = self.user.notifications.filter(type=self.type).last()
@ -1547,6 +1539,15 @@ class Notification(models.Model):
return
super().save(*args, **kwargs)
def callback(self):
# Get the callback defined in settings to update existing
# notifications
mod_name, func_name = settings.SITH_PERMANENT_NOTIFICATIONS[self.type].rsplit(
".", 1
)
mod = importlib.import_module(mod_name)
getattr(mod, func_name)(self)
class Gift(models.Model):
label = models.CharField(_("label"), max_length=255)
@ -1585,8 +1586,8 @@ class OperationLog(models.Model):
_("operation type"), max_length=40, choices=settings.SITH_LOG_OPERATION_TYPE
)
def is_owned_by(self, user):
return user.is_root
def __str__(self):
return "%s - %s - %s" % (self.operation_type, self.label, self.operator)
def is_owned_by(self, user):
return user.is_root

View File

@ -18,7 +18,15 @@ from counter.models import (
class BillingInfoForm(forms.ModelForm):
class Meta:
model = BillingInfo
exclude = ["customer"]
fields = [
"first_name",
"last_name",
"address_1",
"address_2",
"zip_code",
"city",
"country",
]
class StudentCardForm(forms.ModelForm):

View File

@ -62,6 +62,19 @@ class Customer(models.Model):
def __str__(self):
return "%s - %s" % (self.user.username, self.account_id)
def save(self, *args, allow_negative=False, is_selling=False, **kwargs):
"""
is_selling : tell if the current action is a selling
allow_negative : ignored if not a selling. Allow a selling to put the account in negative
Those two parameters avoid blocking the save method of a customer if his account is negative
"""
if self.amount < 0 and (is_selling and not allow_negative):
raise ValidationError(_("Not enough money"))
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("core:user_account", kwargs={"user_id": self.user.pk})
@property
def can_record(self):
return self.recorded_products > -settings.SITH_ECOCUP_LIMIT
@ -128,16 +141,6 @@ class Customer(models.Model):
account = cls.objects.create(user=user, account_id=account_id)
return account, True
def save(self, *args, allow_negative=False, is_selling=False, **kwargs):
"""
is_selling : tell if the current action is a selling
allow_negative : ignored if not a selling. Allow a selling to put the account in negative
Those two parameters avoid blocking the save method of a customer if his account is negative
"""
if self.amount < 0 and (is_selling and not allow_negative):
raise ValidationError(_("Not enough money"))
super().save(*args, **kwargs)
def recompute_amount(self):
refillings = self.refillings.aggregate(sum=Sum(F("amount")))["sum"]
self.amount = refillings if refillings is not None else 0
@ -150,9 +153,6 @@ class Customer(models.Model):
self.amount -= purchases
self.save()
def get_absolute_url(self):
return reverse("core:user_account", kwargs={"user_id": self.user.pk})
def get_full_url(self):
return "".join(["https://", settings.SITH_URL, self.get_absolute_url()])
@ -178,6 +178,9 @@ class BillingInfo(models.Model):
city = models.CharField(_("City"), max_length=50)
country = CountryField(blank_label=_("Country"))
def __str__(self):
return f"{self.first_name} {self.last_name}"
def to_3dsv2_xml(self) -> str:
"""
Convert the data from this model into a xml usable
@ -199,9 +202,6 @@ class BillingInfo(models.Model):
xml = dict2xml(data, wrap="Billing", newlines=False)
return '<?xml version="1.0" encoding="UTF-8" ?>' + xml
def __str__(self):
return f"{self.first_name} {self.last_name}"
class ProductType(models.Model):
"""
@ -222,6 +222,12 @@ class ProductType(models.Model):
verbose_name = _("product type")
ordering = ["-priority", "name"]
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("counter:producttype_list")
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -232,12 +238,6 @@ class ProductType(models.Model):
return True
return False
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("counter:producttype_list")
class Product(models.Model):
"""
@ -282,6 +282,12 @@ class Product(models.Model):
class Meta:
verbose_name = _("product")
def __str__(self):
return "%s (%s)" % (self.name, self.code)
def get_absolute_url(self):
return reverse("counter:product_list")
@property
def is_record_product(self):
return settings.SITH_ECOCUP_CONS == self.id
@ -302,9 +308,6 @@ class Product(models.Model):
return True
return False
def get_absolute_url(self):
return reverse("counter:product_list")
def can_be_sold_to(self, user: User) -> bool:
"""
Check if whether the user given in parameter has the right to buy
@ -329,9 +332,6 @@ class Product(models.Model):
def profit(self):
return self.selling_price - self.purchase_price
def __str__(self):
return "%s (%s)" % (self.name, self.code)
class CounterQuerySet(models.QuerySet):
def annotate_has_barman(self, user: User) -> CounterQuerySet:
@ -388,13 +388,6 @@ class Counter(models.Model):
class Meta:
verbose_name = _("counter")
def __getattribute__(self, name):
if name == "edit_groups":
return Group.objects.filter(
name=self.club.unix_name + settings.SITH_BOARD_SUFFIX
).all()
return object.__getattribute__(self, name)
def __str__(self):
return self.name
@ -403,6 +396,13 @@ class Counter(models.Model):
return reverse("eboutic:main")
return reverse("counter:details", kwargs={"counter_id": self.id})
def __getattribute__(self, name):
if name == "edit_groups":
return Group.objects.filter(
name=self.club.unix_name + settings.SITH_BOARD_SUFFIX
).all()
return object.__getattribute__(self, name)
def is_owned_by(self, user):
if user.is_anonymous:
return False
@ -629,16 +629,6 @@ class Refilling(models.Model):
self.customer.user.get_display_name(),
)
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_owner(self.counter) and self.payment_method != "CARD"
def delete(self, *args, **kwargs):
self.customer.amount -= self.amount
self.customer.save()
super().delete(*args, **kwargs)
def save(self, *args, **kwargs):
if not self.date:
self.date = timezone.now()
@ -663,6 +653,16 @@ class Refilling(models.Model):
).save()
super().save(*args, **kwargs)
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_owner(self.counter) and self.payment_method != "CARD"
def delete(self, *args, **kwargs):
self.customer.amount -= self.amount
self.customer.save()
super().delete(*args, **kwargs)
class Selling(models.Model):
"""
@ -723,59 +723,6 @@ class Selling(models.Model):
self.customer.user.get_display_name(),
)
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_owner(self.counter) and self.payment_method != "CARD"
def can_be_viewed_by(self, user):
if (
not hasattr(self, "customer") or self.customer is None
): # Customer can be set to Null
return False
return user == self.customer.user
def delete(self, *args, **kwargs):
if self.payment_method == "SITH_ACCOUNT":
self.customer.amount += self.quantity * self.unit_price
self.customer.save()
super().delete(*args, **kwargs)
def send_mail_customer(self):
event = self.product.eticket.event_title or _("Unknown event")
subject = _("Eticket bought for the event %(event)s") % {"event": event}
message_html = _(
"You bought an eticket for the event %(event)s.\nYou can download it directly from this link %(eticket)s.\nYou can also retrieve all your e-tickets on your account page %(url)s."
) % {
"event": event,
"url": "".join(
(
'<a href="',
self.customer.get_full_url(),
'">',
self.customer.get_full_url(),
"</a>",
)
),
"eticket": "".join(
(
'<a href="',
self.get_eticket_full_url(),
'">',
self.get_eticket_full_url(),
"</a>",
)
),
}
message_txt = _(
"You bought an eticket for the event %(event)s.\nYou can download it directly from this link %(eticket)s.\nYou can also retrieve all your e-tickets on your account page %(url)s."
) % {
"event": event,
"url": self.customer.get_full_url(),
"eticket": self.get_eticket_full_url(),
}
self.customer.user.email_user(subject, message_txt, html_message=message_html)
def save(self, *args, allow_negative=False, **kwargs):
"""
allow_negative : Allow this selling to use more money than available for this user
@ -858,6 +805,59 @@ class Selling(models.Model):
except:
pass
def is_owned_by(self, user):
if user.is_anonymous:
return False
return user.is_owner(self.counter) and self.payment_method != "CARD"
def can_be_viewed_by(self, user):
if (
not hasattr(self, "customer") or self.customer is None
): # Customer can be set to Null
return False
return user == self.customer.user
def delete(self, *args, **kwargs):
if self.payment_method == "SITH_ACCOUNT":
self.customer.amount += self.quantity * self.unit_price
self.customer.save()
super().delete(*args, **kwargs)
def send_mail_customer(self):
event = self.product.eticket.event_title or _("Unknown event")
subject = _("Eticket bought for the event %(event)s") % {"event": event}
message_html = _(
"You bought an eticket for the event %(event)s.\nYou can download it directly from this link %(eticket)s.\nYou can also retrieve all your e-tickets on your account page %(url)s."
) % {
"event": event,
"url": "".join(
(
'<a href="',
self.customer.get_full_url(),
'">',
self.customer.get_full_url(),
"</a>",
)
),
"eticket": "".join(
(
'<a href="',
self.get_eticket_full_url(),
'">',
self.get_eticket_full_url(),
"</a>",
)
),
}
message_txt = _(
"You bought an eticket for the event %(event)s.\nYou can download it directly from this link %(eticket)s.\nYou can also retrieve all your e-tickets on your account page %(url)s."
) % {
"event": event,
"url": self.customer.get_full_url(),
"eticket": self.get_eticket_full_url(),
}
self.customer.user.email_user(subject, message_txt, html_message=message_html)
def get_eticket_full_url(self):
eticket_url = reverse("counter:eticket_pdf", kwargs={"selling_id": self.id})
return "".join(["https://", settings.SITH_URL, eticket_url])
@ -926,6 +926,14 @@ class CashRegisterSummary(models.Model):
def __str__(self):
return "At %s by %s - Total: %s" % (self.counter, self.user, self.get_total())
def save(self, *args, **kwargs):
if not self.id:
self.date = timezone.now()
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("counter:cash_summary_list")
def __getattribute__(self, name):
if name[:5] == "check":
checks = self.items.filter(check=True).order_by("value").all()
@ -978,14 +986,6 @@ class CashRegisterSummary(models.Model):
t += it.quantity * it.value
return t
def save(self, *args, **kwargs):
if not self.id:
self.date = timezone.now()
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("counter:cash_summary_list")
class CashRegisterSummaryItem(models.Model):
cash_summary = models.ForeignKey(
@ -1005,6 +1005,9 @@ class CashRegisterSummaryItem(models.Model):
class Meta:
verbose_name = _("cash register summary item")
def __str__(self):
return str(self.value)
class Eticket(models.Model):
"""
@ -1027,16 +1030,16 @@ class Eticket(models.Model):
secret = models.CharField(_("secret"), max_length=64, unique=True)
def __str__(self):
return "%s" % (self.product.name)
def get_absolute_url(self):
return reverse("counter:eticket_list")
return self.product.name
def save(self, *args, **kwargs):
if not self.id:
self.secret = base64.b64encode(os.urandom(32))
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("counter:eticket_list")
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -1064,6 +1067,21 @@ class StudentCard(models.Model):
UID_SIZE = 14
uid = models.CharField(
_("uid"), max_length=UID_SIZE, unique=True, validators=[MinLengthValidator(4)]
)
customer = models.ForeignKey(
Customer,
related_name="student_cards",
verbose_name=_("student cards"),
null=False,
blank=False,
on_delete=models.CASCADE,
)
def __str__(self):
return self.uid
@staticmethod
def is_valid(uid):
return (
@ -1080,15 +1098,3 @@ class StudentCard(models.Model):
if isinstance(obj, User):
return StudentCard.can_create(self.customer, obj)
return False
uid = models.CharField(
_("uid"), max_length=14, unique=True, validators=[MinLengthValidator(4)]
)
customer = models.ForeignKey(
Customer,
related_name="student_cards",
verbose_name=_("student cards"),
null=False,
blank=False,
on_delete=models.CASCADE,
)

View File

@ -56,6 +56,9 @@ class Basket(models.Model):
)
date = models.DateTimeField(_("date"), auto_now=True)
def __str__(self):
return f"{self.user}'s basket ({self.items.all().count()} items)"
def add_product(self, p: Product, q: int = 1):
"""
Given p an object of the Product model and q an integer,
@ -207,9 +210,6 @@ class Basket(models.Model):
data.append(("PBX_HMAC", pbx_hmac.hexdigest().upper()))
return data
def __str__(self):
return "%s's basket (%d items)" % (self.user, self.items.all().count())
class Invoice(models.Model):
"""
@ -226,6 +226,9 @@ class Invoice(models.Model):
date = models.DateTimeField(_("date"), auto_now=True)
validated = models.BooleanField(_("validated"), default=False)
def __str__(self):
return f"{self.user} - {self.get_total()} - {self.date}"
def get_total(self) -> float:
total = self.items.aggregate(
total=Sum(F("quantity") * F("product_unit_price"))
@ -268,9 +271,6 @@ class Invoice(models.Model):
self.validated = True
self.save()
def __str__(self):
return "%s - %s - %s" % (self.user, self.get_total(), self.date)
class AbstractBaseItem(models.Model):
product_id = models.IntegerField(_("product id"))

View File

@ -163,16 +163,16 @@ class ElectionList(models.Model):
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def can_be_edited_by(self, user):
return user.can_edit(self.election)
def delete(self):
def delete(self, *args, **kwargs):
for candidature in self.candidatures.all():
candidature.delete()
super().delete()
def __str__(self):
return self.title
super().delete(*args, **kwargs)
class Candidature(models.Model):
@ -201,6 +201,9 @@ class Candidature(models.Model):
on_delete=models.CASCADE,
)
def __str__(self):
return f"{self.role.title} : {self.user.username}"
def delete(self):
for vote in self.votes.all():
vote.delete()
@ -209,9 +212,6 @@ class Candidature(models.Model):
def can_be_edited_by(self, user):
return (user == self.user) or user.can_edit(self.role.election)
def __str__(self):
return "%s : %s" % (self.role.title, self.user.username)
class Vote(models.Model):
"""

View File

@ -14,7 +14,7 @@ class Migration(migrations.Migration):
name="edit_groups",
field=models.ManyToManyField(
blank=True,
default=forum.models.Forum.get_default_edit_group,
default=forum.models.get_default_edit_group,
related_name="editable_forums",
to="core.Group",
),
@ -24,7 +24,7 @@ class Migration(migrations.Migration):
name="view_groups",
field=models.ManyToManyField(
blank=True,
default=forum.models.Forum.get_default_view_group,
default=forum.models.get_default_view_group,
related_name="viewable_forums",
to="core.Group",
),

View File

@ -20,6 +20,7 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from __future__ import annotations
from datetime import datetime
from itertools import chain
@ -37,6 +38,15 @@ from club.models import Club
from core.models import Group, User
# Those functions prevent generating migration upon settings changes
def get_default_edit_group():
return [settings.SITH_GROUP_OLD_SUBSCRIBERS_ID]
def get_default_view_group():
return [settings.SITH_GROUP_PUBLIC_ID]
class Forum(models.Model):
"""
The Forum class, made as a tree to allow nice tidy organization
@ -46,13 +56,6 @@ class Forum(models.Model):
view_groups allows some groups to view a forum
"""
# Those functions prevent generating migration upon settings changes
def get_default_edit_group():
return [settings.SITH_GROUP_OLD_SUBSCRIBERS_ID]
def get_default_view_group():
return [settings.SITH_GROUP_PUBLIC_ID]
id = models.AutoField(primary_key=True, db_index=True)
name = models.CharField(_("name"), max_length=64)
description = models.CharField(_("description"), max_length=512, default="")
@ -98,8 +101,8 @@ class Forum(models.Model):
class Meta:
ordering = ["number"]
def clean(self):
self.check_loop()
def __str__(self):
return self.name
def save(self, *args, **kwargs):
copy_rights = False
@ -109,6 +112,12 @@ class Forum(models.Model):
if copy_rights:
self.copy_rights()
def get_absolute_url(self):
return reverse("forum:view_forum", kwargs={"forum_id": self.id})
def clean(self):
self.check_loop()
def set_topic_number(self):
self._topic_number = self.get_topic_number()
self.save()
@ -166,11 +175,11 @@ class Forum(models.Model):
return True
try:
m = Forum._club_memberships[self.id][user.id]
except:
except KeyError:
m = self.owner_club.get_membership_for(user)
try:
Forum._club_memberships[self.id][user.id] = m
except:
except KeyError:
Forum._club_memberships[self.id] = {}
Forum._club_memberships[self.id][user.id] = m
if m:
@ -187,9 +196,6 @@ class Forum(models.Model):
objs.append(cur)
cur = cur.parent
def __str__(self):
return "%s" % (self.name)
def get_full_name(self):
return "/".join(
chain.from_iterable(
@ -197,9 +203,6 @@ class Forum(models.Model):
)
)
def get_absolute_url(self):
return reverse("forum:view_forum", kwargs={"forum_id": self.id})
@cached_property
def parent_list(self):
return self.get_parent_list()
@ -256,11 +259,17 @@ class ForumTopic(models.Model):
class Meta:
ordering = ["-_last_message__date"]
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.forum.set_topic_number() # Recompute the cached value
self.forum.set_last_message()
def get_absolute_url(self):
return reverse("forum:view_topic", kwargs={"topic_id": self.id})
def is_owned_by(self, user):
return self.forum.is_owned_by(user)
@ -270,23 +279,15 @@ class ForumTopic(models.Model):
def can_be_viewed_by(self, user):
return user.can_view(self.forum)
def __str__(self):
return "%s" % (self.title)
def get_absolute_url(self):
return reverse("forum:view_topic", kwargs={"topic_id": self.id})
def get_first_unread_message(self, user):
try:
msg = (
def get_first_unread_message(self, user: User) -> ForumMessage | None:
if not hasattr(user, "forum_infos"):
return None
return (
self.messages.exclude(readers=user)
.filter(date__gte=user.forum_infos.last_read_date)
.order_by("id")
.first()
)
return msg
except:
return None
@cached_property
def last_message(self):
@ -332,6 +333,9 @@ class ForumMessage(models.Model):
self.topic._message_number = self.topic.messages.count()
self.topic.save()
def get_absolute_url(self):
return reverse("forum:view_message", kwargs={"message_id": self.id})
def is_first_in_topic(self):
return bool(self.id == self.topic.messages.order_by("date").first().id)
@ -356,9 +360,6 @@ class ForumMessage(models.Model):
def can_be_moderated_by(self, user):
return self.topic.forum.is_owned_by(user) or user.id == self.author.id
def get_absolute_url(self):
return reverse("forum:view_message", kwargs={"message_id": self.id})
def get_url(self):
return (
self.topic.get_absolute_url()
@ -378,11 +379,10 @@ class ForumMessage(models.Model):
)
def mark_as_read(self, user):
try: # Need the try/except because of AnonymousUser
if user.is_anonymous:
return
if not self.is_read(user):
self.readers.add(user)
except:
pass
def is_read(self, user):
return (self.date < user.forum_infos.last_read_date) or (
@ -413,6 +413,9 @@ class ForumMessageMeta(models.Model):
date = models.DateTimeField(_("date"), default=timezone.now)
action = models.CharField(_("action"), choices=MESSAGE_META_ACTIONS, max_length=16)
def __str__(self):
return f"{self.user.nick_name} ({self.date})"
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.message._deleted = self.message.is_deleted()

View File

@ -127,6 +127,9 @@ class GalaxyLane(models.Model):
default=0,
)
def __str__(self):
return f"{self.star1} -> {self.star2} ({self.distance})"
class StarDict(TypedDict):
id: int

View File

@ -37,6 +37,12 @@ class Launderette(models.Model):
class Meta:
verbose_name = _("Launderette")
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("launderette:launderette_list")
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -63,12 +69,6 @@ class Launderette(models.Model):
def can_be_viewed_by(self, user):
return user.is_subscribed
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("launderette:launderette_list")
def get_machine_list(self):
return Machine.objects.filter(launderette_id=self.id)
@ -98,6 +98,15 @@ class Machine(models.Model):
class Meta:
verbose_name = _("Machine")
def __str__(self):
return "%s %s" % (self._meta.verbose_name, self.name)
def get_absolute_url(self):
return reverse(
"launderette:launderette_admin",
kwargs={"launderette_id": self.launderette.id},
)
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
@ -112,15 +121,6 @@ class Machine(models.Model):
return True
return False
def __str__(self):
return "%s %s" % (self._meta.verbose_name, self.name)
def get_absolute_url(self):
return reverse(
"launderette:launderette_admin",
kwargs={"launderette_id": self.launderette.id},
)
class Token(models.Model):
name = models.CharField(_("name"), max_length=5)
@ -148,6 +148,12 @@ class Token(models.Model):
unique_together = ("name", "launderette", "type")
ordering = ["type", "name"]
def __str__(self):
return (
f"{self.__class__._meta.verbose_name} {self.get_type_display()} "
f"#{self.name} ({self.launderette.name})"
)
def save(self, *args, **kwargs):
if self.name == "":
raise DataError(_("Token name can not be blank"))
@ -168,18 +174,6 @@ class Token(models.Model):
return True
return False
def __str__(self):
return (
self.__class__._meta.verbose_name
+ " "
+ self.get_type_display()
+ " #"
+ self.name
+ " ("
+ self.launderette.name
+ ")"
)
def is_avaliable(self):
if not self.borrow_date and not self.user:
return True
@ -214,9 +208,6 @@ class Slot(models.Model):
verbose_name = _("Slot")
ordering = ["start_date"]
def is_owned_by(self, user):
return user == self.user
def __str__(self):
return "User: %s - Date: %s - Type: %s - Machine: %s - Token: %s" % (
self.user,
@ -225,3 +216,6 @@ class Slot(models.Model):
self.machine.name,
self.token,
)
def is_owned_by(self, user):
return user == self.user

View File

@ -141,6 +141,12 @@ class UV(models.Model):
default=0,
)
def __str__(self):
return self.code
def get_absolute_url(self):
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.id})
def is_owned_by(self, user):
"""
Can be created by superuser, root or pedagogy admin user
@ -160,9 +166,6 @@ class UV(models.Model):
return int(sum(comments.values_list(field, flat=True)) / comments.count())
def get_absolute_url(self):
return reverse("pedagogy:uv_detail", kwargs={"uv_id": self.id})
def has_user_already_commented(self, user):
"""
Help prevent multiples comments from the same user
@ -194,9 +197,6 @@ class UV(models.Model):
def grade_work_load_average(self):
return self.__grade_average_generic("grade_work_load")
def __str__(self):
return self.code
class UVComment(models.Model):
"""
@ -252,6 +252,14 @@ class UVComment(models.Model):
)
publish_date = models.DateTimeField(_("publish date"), blank=True)
def __str__(self):
return f"{self.uv} - {self.author}"
def save(self, *args, **kwargs):
if self.publish_date is None:
self.publish_date = timezone.now()
super().save(*args, **kwargs)
def is_owned_by(self, user):
"""
Is owned by a pedagogy admin, a superuser or the author himself
@ -265,14 +273,6 @@ class UVComment(models.Model):
"""
return self.reports.exists()
def __str__(self):
return "%s - %s" % (self.uv, self.author)
def save(self, *args, **kwargs):
if self.publish_date is None:
self.publish_date = timezone.now()
super().save(*args, **kwargs)
class UVResult(models.Model):
"""
@ -303,6 +303,9 @@ class UVResult(models.Model):
validators=[validators.RegexValidator("[AP][0-9]{3}")],
)
def __str__(self):
return f"{self.user.username} ; {self.uv.code} ; {self.grade}"
class UVCommentReport(models.Model):
"""
@ -323,6 +326,9 @@ class UVCommentReport(models.Model):
)
reason = models.TextField(_("reason"))
def __str__(self):
return f"{self.reporter.username} : {self.reason}"
@cached_property
def uv(self):
return self.comment.uv

View File

@ -70,7 +70,19 @@ optional = true
version = "1.4.25"
[tool.ruff.lint]
select = ["I", "A", "F401", "UP008", "UP009"]
select = [
"I", # isort
"B",
"A", # shadowing of Python builtins
"F401", # unused import
"DJ", # django-specific rules,
"UP008", # Use super() instead of super(__class__, self)
"UP009" # utf-8 encoding declaration is unnecessary
]
ignore = [
"DJ001", # null=True in CharField/TextField. this one would require a migration
]
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "sith.settings"

View File

@ -149,10 +149,10 @@ class ShoppingListItem(models.Model):
)
def __str__(self):
return "%s - %s" % (self.name, self.shopping_lists.first())
def can_be_viewed_by(self, user):
return user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)
return f"{self.name} - {self.shopping_lists.first()}"
def get_absolute_url(self):
return reverse("stock:shoppinglist_list")
def can_be_viewed_by(self, user):
return user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)

View File

@ -22,6 +22,7 @@ from django.contrib.auth.forms import PasswordResetForm
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from core.models import User
@ -65,26 +66,11 @@ class Subscription(models.Model):
class Meta:
ordering = ["subscription_start"]
def clean(self):
try:
for s in (
Subscription.objects.filter(member=self.member)
.exclude(pk=self.pk)
.all()
):
if (
s.is_valid_now()
and s.subscription_end
- timedelta(weeks=settings.SITH_SUBSCRIPTION_END)
> date.today()
):
raise ValidationError(
_("You can not subscribe many time for the same period")
)
except: # This should not happen, because the form should have handled the data before, but sadly, it still
# calls the model validation :'(
# TODO see SubscriptionForm's clean method
raise ValidationError(_("Subscription error"))
def __str__(self):
if hasattr(self, "member") and self.member is not None:
return f"{self.member.username} - {self.pk}"
else:
return f"No user - {self.pk}"
def save(self, *args, **kwargs):
super().save()
@ -105,11 +91,20 @@ class Subscription(models.Model):
def get_absolute_url(self):
return reverse("core:user_edit", kwargs={"user_id": self.member.pk})
def __str__(self):
if hasattr(self, "member") and self.member is not None:
return self.member.username + " - " + str(self.pk)
else:
return "No user - " + str(self.pk)
def clean(self):
today = timezone.now().date()
active_subscriptions = Subscription.objects.exclude(pk=self.pk).filter(
subscription_start__gte=today, subscription_end__lte=today
)
for s in active_subscriptions:
if (
s.is_valid_now()
and s.subscription_end - timedelta(weeks=settings.SITH_SUBSCRIPTION_END)
> date.today()
):
raise ValidationError(
_("You can not subscribe many time for the same period")
)
@staticmethod
def compute_start(d: date = None, duration: int = 1, user: User = None) -> date:

View File

@ -83,6 +83,9 @@ class Trombi(models.Model):
def __str__(self):
return str(self.club.name)
def get_absolute_url(self):
return reverse("trombi:detail", kwargs={"trombi_id": self.id})
def clean(self):
if self.subscription_deadline > self.comments_deadline:
raise ValidationError(
@ -92,9 +95,6 @@ class Trombi(models.Model):
)
)
def get_absolute_url(self):
return reverse("trombi:detail", kwargs={"trombi_id": self.id})
def is_owned_by(self, user):
return user.can_edit(self.club)
@ -192,6 +192,9 @@ class TrombiComment(models.Model):
content = models.TextField(_("content"), default="")
is_moderated = models.BooleanField(_("is the comment moderated"), default=False)
def __str__(self):
return f"{self.author} : {self.content}"
def can_be_viewed_by(self, user):
if user.id == self.target.user.id:
return False
@ -220,8 +223,8 @@ class TrombiClubMembership(models.Model):
def __str__(self):
return "%s - %s - %s (%s)" % (self.user, self.club, self.role, self.start)
def can_be_edited_by(self, user):
return user.id == self.user.user.id or user.can_edit(self.user.trombi)
def get_absolute_url(self):
return reverse("trombi:profile")
def can_be_edited_by(self, user):
return user.id == self.user.user.id or user.can_edit(self.user.trombi)