mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-04 14:52:13 +02:00
Compare commits
1 Commits
django-5.2
...
family
Author | SHA1 | Date | |
---|---|---|---|
6c7d86185a |
0
apps/family/__init__.py
Normal file
0
apps/family/__init__.py
Normal file
3
apps/family/admin.py
Normal file
3
apps/family/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
11
apps/family/apps.py
Normal file
11
apps/family/apps.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class FamilyConfig(AppConfig):
|
||||||
|
name = 'family'
|
||||||
|
verbose_name = _('family')
|
0
apps/family/migrations/__init__.py
Normal file
0
apps/family/migrations/__init__.py
Normal file
165
apps/family/models.py
Normal file
165
apps/family/models.py
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
from django.db import models, transaction
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class Family(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_('name'),
|
||||||
|
unique=True
|
||||||
|
)
|
||||||
|
|
||||||
|
description = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_('description')
|
||||||
|
)
|
||||||
|
|
||||||
|
score = models.PositiveIntegerField(
|
||||||
|
verbose_name=_('score')
|
||||||
|
)
|
||||||
|
|
||||||
|
rank = models.PositiveIntegerField(
|
||||||
|
verbose_name=_('rank'),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Family')
|
||||||
|
verbose_name_plural = _('Families')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class FamilyMembership(models.Model):
|
||||||
|
user = models.OneToOneField(
|
||||||
|
User,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name=_('family_memberships'),
|
||||||
|
verbose_name=_('user'),
|
||||||
|
)
|
||||||
|
|
||||||
|
family = models.ForeignKey(
|
||||||
|
Family,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name=_('members'),
|
||||||
|
verbose_name=_('family'),
|
||||||
|
)
|
||||||
|
|
||||||
|
year = models.PositiveIntegerField(
|
||||||
|
verbose_name=_('year'),
|
||||||
|
default=timezone.now().year,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('family membership')
|
||||||
|
verbose_name_plural = _('family memberships')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return _('Family membership of {user} to {family}').format(user=self.user.username, family=self.family.name, )
|
||||||
|
|
||||||
|
|
||||||
|
class ChallengeCategory(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_('name'),
|
||||||
|
unique=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('challenge category')
|
||||||
|
verbose_name_plural = _('challenge categories')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Challenge(models.Model):
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_('name'),
|
||||||
|
)
|
||||||
|
|
||||||
|
description = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
verbose_name=_('description'),
|
||||||
|
)
|
||||||
|
|
||||||
|
points = models.PositiveIntegerField(
|
||||||
|
verbose_name=_('points'),
|
||||||
|
)
|
||||||
|
|
||||||
|
category = models.ForeignKey(
|
||||||
|
ChallengeCategory,
|
||||||
|
verbose_name=_('category'),
|
||||||
|
on_delete=models.PROTECT
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('challenge')
|
||||||
|
verbose_name_plural = _('challenges')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Achievement(models.Model):
|
||||||
|
challenge = models.ForeignKey(
|
||||||
|
Challenge,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
|
||||||
|
)
|
||||||
|
family = models.ForeignKey(
|
||||||
|
Family,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_('family'),
|
||||||
|
)
|
||||||
|
|
||||||
|
obtained_at = models.DateTimeField(
|
||||||
|
verbose_name=_('obtained at'),
|
||||||
|
default=timezone.now,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('achievement')
|
||||||
|
verbose_name_plural = _('achievements')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return _('Challenge {challenge} carried out by Family {family}').format(challenge=self.challenge.name, family=self.family.name, )
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
When saving, also grants points to the family
|
||||||
|
"""
|
||||||
|
self.family = Family.objects.select_for_update().get(pk=self.family_id)
|
||||||
|
challenge_points = self.challenge.points
|
||||||
|
is_new = self.pk is None
|
||||||
|
|
||||||
|
super.save(*args, **kwargs)
|
||||||
|
|
||||||
|
# Only grant points when getting a new achievement
|
||||||
|
if is_new:
|
||||||
|
self.family.refresh_from_db()
|
||||||
|
self.family.score += challenge_points
|
||||||
|
self.family._force_save = True
|
||||||
|
self.family.save()
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
When deleting, also removes points from the family
|
||||||
|
"""
|
||||||
|
# Get the family and challenge before deletion
|
||||||
|
self.family = Family.objects.select_for_update().get(pk=self.family_id)
|
||||||
|
challenge_points = self.challenge.points
|
||||||
|
|
||||||
|
# Delete the achievement
|
||||||
|
super().delete(*args, **kwargs)
|
||||||
|
|
||||||
|
# Remove points from the family
|
||||||
|
self.family.refresh_from_db()
|
||||||
|
self.family.score -= challenge_points
|
||||||
|
self.family._force_save = True
|
||||||
|
self.family.save()
|
3
apps/family/tests.py
Normal file
3
apps/family/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
3
apps/family/views.py
Normal file
3
apps/family/views.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
@ -70,6 +70,7 @@ INSTALLED_APPS = [
|
|||||||
# Note apps
|
# Note apps
|
||||||
'api',
|
'api',
|
||||||
'activity',
|
'activity',
|
||||||
|
'family',
|
||||||
'food',
|
'food',
|
||||||
'logs',
|
'logs',
|
||||||
'member',
|
'member',
|
||||||
@ -270,7 +271,7 @@ OAUTH2_PROVIDER = {
|
|||||||
'PKCE_REQUIRED': False, # PKCE (fix a breaking change of django-oauth-toolkit 2.0.0)
|
'PKCE_REQUIRED': False, # PKCE (fix a breaking change of django-oauth-toolkit 2.0.0)
|
||||||
'OIDC_ENABLED': True,
|
'OIDC_ENABLED': True,
|
||||||
'OIDC_RSA_PRIVATE_KEY':
|
'OIDC_RSA_PRIVATE_KEY':
|
||||||
os.getenv('OIDC_RSA_PRIVATE_KEY', '/var/secrets/oidc.key'),
|
os.getenv('OIDC_RSA_PRIVATE_KEY', 'CHANGE_ME_IN_ENV_SETTINGS').replace('\\n', '\n'), # for multilines
|
||||||
'SCOPES': { 'openid': "OpenID Connect scope" },
|
'SCOPES': { 'openid': "OpenID Connect scope" },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user