mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-12 04:49:25 +00:00
Mise à jour d'avril (#643)
This commit is contained in:
14
core/apps.py
14
core/apps.py
@ -25,6 +25,7 @@
|
||||
import sys
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.core.cache import cache
|
||||
from django.core.signals import request_started
|
||||
|
||||
|
||||
@ -33,26 +34,17 @@ class SithConfig(AppConfig):
|
||||
verbose_name = "Core app of the Sith"
|
||||
|
||||
def ready(self):
|
||||
from core.models import User
|
||||
from club.models import Club
|
||||
from forum.models import Forum
|
||||
import core.signals
|
||||
|
||||
def clear_cached_groups(**kwargs):
|
||||
User._group_ids = {}
|
||||
User._group_name = {}
|
||||
cache.clear()
|
||||
|
||||
def clear_cached_memberships(**kwargs):
|
||||
User._club_memberships = {}
|
||||
Club._memberships = {}
|
||||
Forum._club_memberships = {}
|
||||
|
||||
print("Connecting signals!", file=sys.stderr)
|
||||
request_started.connect(
|
||||
clear_cached_groups, weak=False, dispatch_uid="clear_cached_groups"
|
||||
)
|
||||
request_started.connect(
|
||||
clear_cached_memberships,
|
||||
weak=False,
|
||||
dispatch_uid="clear_cached_memberships",
|
||||
)
|
||||
# TODO: there may be a need to add more cache clearing
|
||||
|
@ -39,6 +39,5 @@ class Command(compilemessages.Command):
|
||||
"""
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
os.chdir("sith")
|
||||
super(Command, self).handle(*args, **options)
|
||||
|
@ -60,7 +60,7 @@ class Command(BaseCommand):
|
||||
|
||||
def compilescss(self, file):
|
||||
print("compiling %s" % file)
|
||||
with (open(file.replace(".scss", ".css"), "w")) as newfile:
|
||||
with open(file.replace(".scss", ".css"), "w") as newfile:
|
||||
newfile.write(self.compile(file))
|
||||
|
||||
def removescss(self, file):
|
||||
@ -68,7 +68,6 @@ class Command(BaseCommand):
|
||||
os.remove(file)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
if os.path.isdir(settings.STATIC_ROOT):
|
||||
print("---- Compiling scss files ---")
|
||||
self.exec_on_folder(settings.STATIC_ROOT, self.compilescss)
|
||||
|
@ -155,12 +155,10 @@ class Command(BaseCommand):
|
||||
Counter(name="Eboutic", club=main_club, type="EBOUTIC").save()
|
||||
Counter(name="AE", club=main_club, type="OFFICE").save()
|
||||
|
||||
home_root.view_groups.set(
|
||||
[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first()]
|
||||
)
|
||||
club_root.view_groups.set(
|
||||
[Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first()]
|
||||
)
|
||||
ae_members = Group.objects.get(name=settings.SITH_MAIN_MEMBERS_GROUP)
|
||||
|
||||
home_root.view_groups.set([ae_members])
|
||||
club_root.view_groups.set([ae_members])
|
||||
home_root.save()
|
||||
club_root.save()
|
||||
|
||||
@ -220,9 +218,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
skia.set_password("plop")
|
||||
skia.save()
|
||||
skia.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
skia.view_groups = [ae_members.id]
|
||||
skia.save()
|
||||
skia_profile_path = (
|
||||
root_path
|
||||
@ -261,9 +257,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
public.set_password("plop")
|
||||
public.save()
|
||||
public.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
public.view_groups = [ae_members.id]
|
||||
public.save()
|
||||
# Adding user Subscriber
|
||||
subscriber = User(
|
||||
@ -277,9 +271,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
subscriber.set_password("plop")
|
||||
subscriber.save()
|
||||
subscriber.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
subscriber.view_groups = [ae_members.id]
|
||||
subscriber.save()
|
||||
# Adding user old Subscriber
|
||||
old_subscriber = User(
|
||||
@ -293,9 +285,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
old_subscriber.set_password("plop")
|
||||
old_subscriber.save()
|
||||
old_subscriber.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
old_subscriber.view_groups = [ae_members.id]
|
||||
old_subscriber.save()
|
||||
# Adding user Counter admin
|
||||
counter = User(
|
||||
@ -309,9 +299,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
counter.set_password("plop")
|
||||
counter.save()
|
||||
counter.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
counter.view_groups = [ae_members.id]
|
||||
counter.groups.set(
|
||||
[
|
||||
Group.objects.filter(id=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||
@ -332,9 +320,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
comptable.set_password("plop")
|
||||
comptable.save()
|
||||
comptable.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
comptable.view_groups = [ae_members.id]
|
||||
comptable.groups.set(
|
||||
[
|
||||
Group.objects.filter(id=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
@ -355,9 +341,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
u.set_password("plop")
|
||||
u.save()
|
||||
u.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
u.view_groups = [ae_members.id]
|
||||
u.save()
|
||||
# Adding user Richard Batsbak
|
||||
richard = User(
|
||||
@ -394,9 +378,7 @@ Welcome to the wiki page!
|
||||
richard_profile.save()
|
||||
richard.profile_pict = richard_profile
|
||||
richard.save()
|
||||
richard.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
richard.view_groups = [ae_members.id]
|
||||
richard.save()
|
||||
# Adding syntax help page
|
||||
p = Page(name="Aide_sur_la_syntaxe")
|
||||
@ -428,7 +410,7 @@ Welcome to the wiki page!
|
||||
default_subscription = "un-semestre"
|
||||
# Root
|
||||
s = Subscription(
|
||||
member=User.objects.filter(pk=root.pk).first(),
|
||||
member=root,
|
||||
subscription_type=default_subscription,
|
||||
payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0],
|
||||
)
|
||||
@ -528,7 +510,7 @@ Welcome to the wiki page!
|
||||
Club(
|
||||
name="Woenzel'UT", unix_name="woenzel", address="Woenzel", parent=guyut
|
||||
).save()
|
||||
Membership(user=skia, club=main_club, role=3, description="").save()
|
||||
Membership(user=skia, club=main_club, role=3).save()
|
||||
troll = Club(
|
||||
name="Troll Penché",
|
||||
unix_name="troll",
|
||||
@ -855,9 +837,7 @@ Welcome to the wiki page!
|
||||
)
|
||||
sli.set_password("plop")
|
||||
sli.save()
|
||||
sli.view_groups = [
|
||||
Group.objects.filter(name=settings.SITH_MAIN_MEMBERS_GROUP).first().id
|
||||
]
|
||||
sli.view_groups = [ae_members.id]
|
||||
sli.save()
|
||||
sli_profile_path = (
|
||||
root_path
|
||||
@ -934,7 +914,6 @@ Welcome to the wiki page!
|
||||
Membership(
|
||||
user=comunity,
|
||||
club=bar_club,
|
||||
start_date=timezone.now(),
|
||||
role=settings.SITH_CLUB_ROLES_ID["Board member"],
|
||||
).save()
|
||||
# Adding user tutu
|
||||
|
@ -22,9 +22,6 @@ from django.core.management import call_command
|
||||
class Command(BaseCommand):
|
||||
help = "Set up a new instance of the Sith AE"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("--prod", action="store_true")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
root_path = os.path.dirname(
|
||||
os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
|
||||
@ -40,7 +37,4 @@ class Command(BaseCommand):
|
||||
except Exception as e:
|
||||
repr(e)
|
||||
call_command("migrate")
|
||||
if options["prod"]:
|
||||
call_command("populate", "--prod")
|
||||
else:
|
||||
call_command("populate")
|
||||
call_command("populate")
|
||||
|
@ -12,7 +12,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("auth", "0006_require_contenttypes_0002")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0002_auto_20160831_0144")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0003_auto_20160902_1914")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0004_user_godfathers")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0005_auto_20161105_1035")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0006_auto_20161108_1703")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import core.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0008_sithfile_asked_for_removal")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0009_auto_20161120_1155")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import core.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0010_sithfile_is_in_sas")]
|
||||
|
||||
operations = [
|
||||
|
@ -8,7 +8,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0011_auto_20161124_0848")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0012_notification")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0013_auto_20161209_2338")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0014_auto_20161210_0009")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0015_sithfile_moderator")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0016_auto_20161212_1922")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0017_auto_20161220_1626")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0018_auto_20161224_0211")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0019_preferences_receive_weekmail")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0020_auto_20170324_0917")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0021_auto_20170822_1529")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0022_auto_20170822_2232")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0023_auto_20170902_1226")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0024_auto_20170906_1317")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0025_auto_20170919_1521")]
|
||||
|
||||
operations = [
|
||||
|
@ -8,7 +8,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0026_auto_20170926_1512")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0027_gift")]
|
||||
|
||||
operations = [
|
||||
|
@ -7,7 +7,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0028_auto_20171216_2044")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0029_auto_20180426_2013")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0030_auto_20190704_1500")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0031_auto_20190906_1615")]
|
||||
|
||||
operations = [
|
||||
|
@ -5,7 +5,6 @@ from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0032_auto_20190909_0043")]
|
||||
|
||||
operations = [
|
||||
|
@ -6,7 +6,6 @@ import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0033_auto_20191006_0049"),
|
||||
]
|
||||
|
@ -4,7 +4,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0034_operationlog"),
|
||||
]
|
||||
|
@ -4,7 +4,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0035_auto_20200216_1743")]
|
||||
|
||||
operations = [
|
||||
|
@ -4,7 +4,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0036_auto_20211001_0248")]
|
||||
|
||||
operations = [
|
||||
|
341
core/models.py
341
core/models.py
@ -23,12 +23,12 @@
|
||||
#
|
||||
#
|
||||
import importlib
|
||||
from typing import Union, Optional, List
|
||||
|
||||
from django.db import models
|
||||
from django.core.cache import cache
|
||||
from django.core.mail import send_mail
|
||||
from django.contrib.auth.models import (
|
||||
AbstractBaseUser,
|
||||
PermissionsMixin,
|
||||
UserManager,
|
||||
Group as AuthGroup,
|
||||
GroupManager as AuthGroupManager,
|
||||
@ -40,7 +40,7 @@ from django.core import validators
|
||||
from django.core.exceptions import ValidationError, PermissionDenied
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.db import models, transaction
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
from django.utils.html import escape
|
||||
from django.utils.functional import cached_property
|
||||
@ -50,7 +50,7 @@ from core import utils
|
||||
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
from datetime import datetime, timedelta, date
|
||||
from datetime import timedelta, date
|
||||
|
||||
import unicodedata
|
||||
|
||||
@ -90,14 +90,24 @@ class Group(AuthGroup):
|
||||
"""
|
||||
return reverse("core:group_list")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
cache.set(f"sith_group_{self.id}", self)
|
||||
cache.set(f"sith_group_{self.name.replace(' ', '_')}", self)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
cache.delete(f"sith_group_{self.id}")
|
||||
cache.delete(f"sith_group_{self.name.replace(' ', '_')}")
|
||||
|
||||
|
||||
class MetaGroup(Group):
|
||||
"""
|
||||
MetaGroups are dynamically created groups.
|
||||
Generaly used with clubs where creating a club creates two groups:
|
||||
Generally used with clubs where creating a club creates two groups:
|
||||
|
||||
* club-SITH_BOARD_SUFFIX
|
||||
* club-SITH_MEMBER_SUFFIX
|
||||
* club-SITH_BOARD_SUFFIX
|
||||
* club-SITH_MEMBER_SUFFIX
|
||||
"""
|
||||
|
||||
#: Assign a manager in a way that MetaGroup.objects only return groups with is_meta=False
|
||||
@ -110,6 +120,32 @@ class MetaGroup(Group):
|
||||
super(MetaGroup, self).__init__(*args, **kwargs)
|
||||
self.is_meta = True
|
||||
|
||||
@cached_property
|
||||
def associated_club(self):
|
||||
"""
|
||||
Return the group associated with this meta group
|
||||
|
||||
The result of this function is cached
|
||||
|
||||
:return: The associated club if it exists, else None
|
||||
:rtype: club.models.Club | None
|
||||
"""
|
||||
from club.models import Club
|
||||
|
||||
if self.name.endswith(settings.SITH_BOARD_SUFFIX):
|
||||
# replace this with str.removesuffix as soon as Python
|
||||
# is upgraded to 3.10
|
||||
club_name = self.name[: -len(settings.SITH_BOARD_SUFFIX)]
|
||||
elif self.name.endswith(settings.SITH_MEMBER_SUFFIX):
|
||||
club_name = self.name[: -len(settings.SITH_MEMBER_SUFFIX)]
|
||||
else:
|
||||
return None
|
||||
club = cache.get(f"sith_club_{club_name}")
|
||||
if club is None:
|
||||
club = Club.objects.filter(unix_name=club_name).first()
|
||||
cache.set(f"sith_club_{club_name}", club)
|
||||
return club
|
||||
|
||||
|
||||
class RealGroup(Group):
|
||||
"""
|
||||
@ -134,6 +170,43 @@ def validate_promo(value):
|
||||
)
|
||||
|
||||
|
||||
def get_group(*, pk: int = None, name: str = None) -> Optional[Group]:
|
||||
"""
|
||||
Search for a group by its primary key or its name.
|
||||
Either one of the two must be set.
|
||||
|
||||
The result is cached for the default duration (should be 5 minutes).
|
||||
|
||||
:param pk: The primary key of the group
|
||||
:param name: The name of the group
|
||||
:return: The group if it exists, else None
|
||||
:raises ValueError: If no group matches the criteria
|
||||
"""
|
||||
if pk is None and name is None:
|
||||
raise ValueError("Either pk or name must be set")
|
||||
if name is not None:
|
||||
name = name.replace(" ", "_") # avoid errors with memcached backend
|
||||
pk_or_name: Union[str, int] = pk if pk is not None else name
|
||||
group = cache.get(f"sith_group_{pk_or_name}")
|
||||
if group == "not_found":
|
||||
# Using None as a cache value is a little bit tricky,
|
||||
# so we use a special string to represent None
|
||||
return None
|
||||
elif group is not None:
|
||||
return group
|
||||
# if this point is reached, the group is not in cache
|
||||
if pk is not None:
|
||||
group = Group.objects.filter(pk=pk).first()
|
||||
else:
|
||||
group = Group.objects.filter(name=name).first()
|
||||
if group is not None:
|
||||
cache.set(f"sith_group_{group.id}", group)
|
||||
cache.set(f"sith_group_{group.name.replace(' ', '_')}", group)
|
||||
else:
|
||||
cache.set(f"sith_group_{pk_or_name}", "not_found")
|
||||
return group
|
||||
|
||||
|
||||
class User(AbstractBaseUser):
|
||||
"""
|
||||
Defines the base user class, useable in every app
|
||||
@ -295,7 +368,6 @@ class User(AbstractBaseUser):
|
||||
objects = UserManager()
|
||||
|
||||
USERNAME_FIELD = "username"
|
||||
# REQUIRED_FIELDS = ['email']
|
||||
|
||||
def promo_has_logo(self):
|
||||
return utils.file_exist("./core/static/core/img/promo_%02d.png" % self.promo)
|
||||
@ -336,94 +408,72 @@ class User(AbstractBaseUser):
|
||||
else:
|
||||
return 0
|
||||
|
||||
_club_memberships = {}
|
||||
_group_names = {}
|
||||
_group_ids = {}
|
||||
def is_in_group(self, *, pk: int = None, name: str = None) -> bool:
|
||||
"""
|
||||
Check if this user is in the given group.
|
||||
Either a group id or a group name must be provided.
|
||||
If both are passed, only the id will be considered.
|
||||
|
||||
def is_in_group(self, group_name):
|
||||
"""If the user is in the group passed in argument (as string or by id)"""
|
||||
group_id = 0
|
||||
g = None
|
||||
if isinstance(group_name, int): # Handle the case where group_name is an ID
|
||||
if group_name in User._group_ids.keys():
|
||||
g = User._group_ids[group_name]
|
||||
else:
|
||||
g = Group.objects.filter(id=group_name).first()
|
||||
User._group_ids[group_name] = g
|
||||
else:
|
||||
if group_name in User._group_names.keys():
|
||||
g = User._group_names[group_name]
|
||||
else:
|
||||
g = Group.objects.filter(name=group_name).first()
|
||||
User._group_names[group_name] = g
|
||||
if g:
|
||||
group_name = g.name
|
||||
group_id = g.id
|
||||
The group will be fetched using the given parameter.
|
||||
If no group is found, return False.
|
||||
If a group is found, check if this user is in the latter.
|
||||
|
||||
:return: True if the user is the group, else False
|
||||
"""
|
||||
if pk is not None:
|
||||
group: Optional[Group] = get_group(pk=pk)
|
||||
elif name is not None:
|
||||
group: Optional[Group] = get_group(name=name)
|
||||
else:
|
||||
raise ValueError("You must either provide the id or the name of the group")
|
||||
if group is None:
|
||||
return False
|
||||
if group_id == settings.SITH_GROUP_PUBLIC_ID:
|
||||
if group.id == settings.SITH_GROUP_PUBLIC_ID:
|
||||
return True
|
||||
if group_id == settings.SITH_GROUP_SUBSCRIBERS_ID:
|
||||
if group.id == settings.SITH_GROUP_SUBSCRIBERS_ID:
|
||||
return self.is_subscribed
|
||||
if group_id == settings.SITH_GROUP_OLD_SUBSCRIBERS_ID:
|
||||
if group.id == settings.SITH_GROUP_OLD_SUBSCRIBERS_ID:
|
||||
return self.was_subscribed
|
||||
if (
|
||||
group_name == settings.SITH_MAIN_MEMBERS_GROUP
|
||||
): # We check the subscription if asked
|
||||
return self.is_subscribed
|
||||
if group_name[-len(settings.SITH_BOARD_SUFFIX) :] == settings.SITH_BOARD_SUFFIX:
|
||||
name = group_name[: -len(settings.SITH_BOARD_SUFFIX)]
|
||||
if name in User._club_memberships.keys():
|
||||
mem = User._club_memberships[name]
|
||||
else:
|
||||
from club.models import Club
|
||||
|
||||
c = Club.objects.filter(unix_name=name).first()
|
||||
mem = c.get_membership_for(self)
|
||||
User._club_memberships[name] = mem
|
||||
if mem:
|
||||
return mem.role > settings.SITH_MAXIMUM_FREE_ROLE
|
||||
return False
|
||||
if (
|
||||
group_name[-len(settings.SITH_MEMBER_SUFFIX) :]
|
||||
== settings.SITH_MEMBER_SUFFIX
|
||||
):
|
||||
name = group_name[: -len(settings.SITH_MEMBER_SUFFIX)]
|
||||
if name in User._club_memberships.keys():
|
||||
mem = User._club_memberships[name]
|
||||
else:
|
||||
from club.models import Club
|
||||
|
||||
c = Club.objects.filter(unix_name=name).first()
|
||||
mem = c.get_membership_for(self)
|
||||
User._club_memberships[name] = mem
|
||||
if mem:
|
||||
if group.id == settings.SITH_GROUP_ROOT_ID:
|
||||
return self.is_root
|
||||
if group.is_meta:
|
||||
# check if this group is associated with a club
|
||||
group.__class__ = MetaGroup
|
||||
club = group.associated_club
|
||||
if club is None:
|
||||
return False
|
||||
membership = club.get_membership_for(self)
|
||||
if membership is None:
|
||||
return False
|
||||
if group.name.endswith(settings.SITH_MEMBER_SUFFIX):
|
||||
return True
|
||||
return False
|
||||
if group_id == settings.SITH_GROUP_ROOT_ID and self.is_superuser:
|
||||
return membership.role > settings.SITH_MAXIMUM_FREE_ROLE
|
||||
return group in self.cached_groups
|
||||
|
||||
@property
|
||||
def cached_groups(self) -> List[Group]:
|
||||
"""
|
||||
Get the list of groups this user is in.
|
||||
The result is cached for the default duration (should be 5 minutes)
|
||||
:return: A list of all the groups this user is in
|
||||
"""
|
||||
groups = cache.get(f"user_{self.id}_groups")
|
||||
if groups is None:
|
||||
groups = list(self.groups.all())
|
||||
cache.set(f"user_{self.id}_groups", groups)
|
||||
return groups
|
||||
|
||||
@cached_property
|
||||
def is_root(self) -> bool:
|
||||
if self.is_superuser:
|
||||
return True
|
||||
return group_name in self.cached_groups_names
|
||||
|
||||
@cached_property
|
||||
def cached_groups_names(self):
|
||||
return [g.name for g in self.groups.all()]
|
||||
|
||||
@cached_property
|
||||
def is_root(self):
|
||||
return (
|
||||
self.is_superuser
|
||||
or self.groups.filter(id=settings.SITH_GROUP_ROOT_ID).exists()
|
||||
)
|
||||
root_id = settings.SITH_GROUP_ROOT_ID
|
||||
return any(g.id == root_id for g in self.cached_groups)
|
||||
|
||||
@cached_property
|
||||
def is_board_member(self):
|
||||
from club.models import Club
|
||||
|
||||
return (
|
||||
Club.objects.filter(unix_name=settings.SITH_MAIN_CLUB["unix_name"])
|
||||
.first()
|
||||
.has_rights_in_club(self)
|
||||
)
|
||||
main_club = settings.SITH_MAIN_CLUB["unix_name"]
|
||||
return self.is_in_group(name=main_club + settings.SITH_BOARD_SUFFIX)
|
||||
|
||||
@cached_property
|
||||
def can_read_subscription_history(self):
|
||||
@ -434,8 +484,8 @@ class User(AbstractBaseUser):
|
||||
|
||||
for club in Club.objects.filter(
|
||||
id__in=settings.SITH_CAN_READ_SUBSCRIPTION_HISTORY
|
||||
).all():
|
||||
if club.has_rights_in_club(self):
|
||||
):
|
||||
if club in self.clubs_with_rights:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -443,10 +493,8 @@ class User(AbstractBaseUser):
|
||||
def can_create_subscription(self):
|
||||
from club.models import Club
|
||||
|
||||
for club in Club.objects.filter(
|
||||
id__in=settings.SITH_CAN_CREATE_SUBSCRIPTIONS
|
||||
).all():
|
||||
if club.has_rights_in_club(self):
|
||||
for club in Club.objects.filter(id__in=settings.SITH_CAN_CREATE_SUBSCRIPTIONS):
|
||||
if club in self.clubs_with_rights:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -464,11 +512,11 @@ class User(AbstractBaseUser):
|
||||
|
||||
@cached_property
|
||||
def is_banned_alcohol(self):
|
||||
return self.is_in_group(settings.SITH_GROUP_BANNED_ALCOHOL_ID)
|
||||
return self.is_in_group(pk=settings.SITH_GROUP_BANNED_ALCOHOL_ID)
|
||||
|
||||
@cached_property
|
||||
def is_banned_counter(self):
|
||||
return self.is_in_group(settings.SITH_GROUP_BANNED_COUNTER_ID)
|
||||
return self.is_in_group(pk=settings.SITH_GROUP_BANNED_COUNTER_ID)
|
||||
|
||||
@cached_property
|
||||
def age(self) -> int:
|
||||
@ -598,9 +646,9 @@ class User(AbstractBaseUser):
|
||||
"""
|
||||
if hasattr(obj, "is_owned_by") and obj.is_owned_by(self):
|
||||
return True
|
||||
if hasattr(obj, "owner_group") and self.is_in_group(obj.owner_group.name):
|
||||
if hasattr(obj, "owner_group") and self.is_in_group(pk=obj.owner_group.id):
|
||||
return True
|
||||
if self.is_superuser or self.is_in_group(settings.SITH_GROUP_ROOT_ID):
|
||||
if self.is_root:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -611,8 +659,8 @@ class User(AbstractBaseUser):
|
||||
if hasattr(obj, "can_be_edited_by") and obj.can_be_edited_by(self):
|
||||
return True
|
||||
if hasattr(obj, "edit_groups"):
|
||||
for g in obj.edit_groups.all():
|
||||
if self.is_in_group(g.name):
|
||||
for pk in obj.edit_groups.values_list("pk", flat=True):
|
||||
if self.is_in_group(pk=pk):
|
||||
return True
|
||||
if isinstance(obj, User) and obj == self:
|
||||
return True
|
||||
@ -627,15 +675,15 @@ class User(AbstractBaseUser):
|
||||
if hasattr(obj, "can_be_viewed_by") and obj.can_be_viewed_by(self):
|
||||
return True
|
||||
if hasattr(obj, "view_groups"):
|
||||
for g in obj.view_groups.all():
|
||||
if self.is_in_group(g.name):
|
||||
for pk in obj.view_groups.values_list("pk", flat=True):
|
||||
if self.is_in_group(pk=pk):
|
||||
return True
|
||||
if self.can_edit(obj):
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_be_edited_by(self, user):
|
||||
return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user.is_root
|
||||
return user.is_root or user.is_board_member
|
||||
|
||||
def can_be_viewed_by(self, user):
|
||||
return (user.was_subscribed and self.is_subscriber_viewable) or user.is_root
|
||||
@ -656,10 +704,6 @@ class User(AbstractBaseUser):
|
||||
escape(self.get_display_name()),
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def subscribed(self):
|
||||
return self.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP)
|
||||
|
||||
@cached_property
|
||||
def preferences(self):
|
||||
try:
|
||||
@ -682,17 +726,16 @@ class User(AbstractBaseUser):
|
||||
|
||||
@cached_property
|
||||
def clubs_with_rights(self):
|
||||
return [
|
||||
m.club.id
|
||||
for m in self.memberships.filter(
|
||||
models.Q(end_date__isnull=True) | models.Q(end_date__gte=timezone.now())
|
||||
).all()
|
||||
if m.club.has_rights_in_club(self)
|
||||
]
|
||||
"""
|
||||
:return: the list of clubs where the user has rights
|
||||
:rtype: list[club.models.Club]
|
||||
"""
|
||||
memberships = self.memberships.ongoing().board().select_related("club")
|
||||
return [m.club for m in memberships]
|
||||
|
||||
@cached_property
|
||||
def is_com_admin(self):
|
||||
return self.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)
|
||||
return self.is_in_group(pk=settings.SITH_GROUP_COM_ADMIN_ID)
|
||||
|
||||
|
||||
class AnonymousUser(AuthAnonymousUser):
|
||||
@ -747,21 +790,18 @@ class AnonymousUser(AuthAnonymousUser):
|
||||
def favorite_topics(self):
|
||||
raise PermissionDenied
|
||||
|
||||
def is_in_group(self, group_name):
|
||||
def is_in_group(self, *, pk: int = None, name: str = None) -> bool:
|
||||
"""
|
||||
The anonymous user is only the public group
|
||||
The anonymous user is only in the public group
|
||||
"""
|
||||
group_id = 0
|
||||
if isinstance(group_name, int): # Handle the case where group_name is an ID
|
||||
g = Group.objects.filter(id=group_name).first()
|
||||
if g:
|
||||
group_name = g.name
|
||||
group_id = g.id
|
||||
else:
|
||||
return False
|
||||
if group_id == settings.SITH_GROUP_PUBLIC_ID:
|
||||
return True
|
||||
return False
|
||||
allowed_id = settings.SITH_GROUP_PUBLIC_ID
|
||||
if pk is not None:
|
||||
return pk == allowed_id
|
||||
elif name is not None:
|
||||
group = get_group(name=name)
|
||||
return group is not None and group.id == allowed_id
|
||||
else:
|
||||
raise ValueError("You must either provide the id or the name of the group")
|
||||
|
||||
def is_owner(self, obj):
|
||||
return False
|
||||
@ -879,14 +919,44 @@ class SithFile(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("file")
|
||||
|
||||
def is_owned_by(self, user):
|
||||
if hasattr(self, "profile_of") and user.is_in_group(
|
||||
settings.SITH_MAIN_BOARD_GROUP
|
||||
def can_be_managed_by(self, user: User) -> bool:
|
||||
"""
|
||||
Tell if the user can manage the file (edit, delete, etc.) or not.
|
||||
Apply the following rules:
|
||||
- If the file is not in the SAS nor in the profiles directory, it can be "managed" by anyone -> return True
|
||||
- If the file is in the SAS, only the SAS admins (or roots) can manage it -> return True if the user is in the SAS admin group or is a root
|
||||
- If the file is in the profiles directory, only the roots can manage it -> return True if the user is a root
|
||||
|
||||
:returns: True if the file is managed by the SAS or within the profiles directory, False otherwise
|
||||
"""
|
||||
|
||||
# If the file is not in the SAS nor in the profiles directory, it can be "managed" by anyone
|
||||
profiles_dir = SithFile.objects.filter(name="profiles").first()
|
||||
if not self.is_in_sas and not profiles_dir in self.get_parent_list():
|
||||
return True
|
||||
|
||||
# If the file is in the SAS, only the SAS admins (or roots) can manage it
|
||||
if self.is_in_sas and (
|
||||
user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) or user.is_root
|
||||
):
|
||||
return True
|
||||
if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID):
|
||||
|
||||
# If the file is in the profiles directory, only the roots can manage it
|
||||
if profiles_dir in self.get_parent_list() and (
|
||||
user.is_root or user.is_board_member
|
||||
):
|
||||
return True
|
||||
if self.is_in_sas and user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID):
|
||||
|
||||
return False
|
||||
|
||||
def is_owned_by(self, user):
|
||||
if user.is_anonymous:
|
||||
return False
|
||||
if hasattr(self, "profile_of") and user.is_board_member:
|
||||
return True
|
||||
if user.is_com_admin:
|
||||
return True
|
||||
if self.is_in_sas and user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID):
|
||||
return True
|
||||
return user.id == self.owner.id
|
||||
|
||||
@ -956,7 +1026,7 @@ class SithFile(models.Model):
|
||||
|
||||
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()
|
||||
self.is_in_sas = sas in self.get_parent_list() or self == sas
|
||||
copy_rights = False
|
||||
if self.id is None:
|
||||
copy_rights = True
|
||||
@ -1090,12 +1160,6 @@ class SithFile(models.Model):
|
||||
|
||||
return Album.objects.filter(id=self.id).first()
|
||||
|
||||
def __str__(self):
|
||||
if self.is_folder:
|
||||
return _("Folder: ") + self.name
|
||||
else:
|
||||
return _("File: ") + self.name
|
||||
|
||||
def get_parent_list(self):
|
||||
l = []
|
||||
p = self.parent
|
||||
@ -1176,6 +1240,7 @@ class Page(models.Model):
|
||||
# Attention: this field may not be valid until you call save(). It's made for fast query, but don't rely on it when
|
||||
# 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
|
||||
@ -1492,6 +1557,8 @@ class Gift(models.Model):
|
||||
return self.label
|
||||
|
||||
def is_owned_by(self, user):
|
||||
if user.is_anonymous:
|
||||
return False
|
||||
return user.is_board_member or user.is_root
|
||||
|
||||
|
||||
|
17
core/signals.py
Normal file
17
core/signals.py
Normal file
@ -0,0 +1,17 @@
|
||||
from django.core.cache import cache
|
||||
from django.db.models.signals import m2m_changed
|
||||
from django.dispatch import receiver
|
||||
|
||||
from core.models import User
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=User.groups.through, dispatch_uid="user_groups_changed")
|
||||
def user_groups_changed(sender, instance: User, **kwargs):
|
||||
"""
|
||||
Clear the cached clubs of the user
|
||||
"""
|
||||
# As a m2m relationship doesn't live within the model
|
||||
# but rather on an intermediary table, there is no
|
||||
# model method to override, meaning we must use
|
||||
# a signal to invalidate the cache when a user is removed from a club
|
||||
cache.delete(f"user_{instance.id}_groups")
|
@ -43,7 +43,7 @@ nav.navbar {
|
||||
justify-content: center;
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
|
||||
> .menu,
|
||||
> .link {
|
||||
box-sizing: border-box;
|
||||
@ -85,6 +85,22 @@ nav.navbar {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
> .menu > .head,
|
||||
> .link {
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.link:hover,
|
||||
.menu:hover {
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
> .menu:hover > .content,
|
||||
> .menu > .head:hover + .content,
|
||||
> .menu > .content:hover {
|
||||
@ -130,5 +146,5 @@ nav.navbar {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@
|
||||
{% if not file.home_of and not file.home_of_club and file.parent %}
|
||||
<p><a href="{{ url('core:file_delete', file_id=file.id, popup=popup) }}">{% trans %}Delete{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
|
||||
{% if user.is_com_admin %}
|
||||
<p><a href="{{ url('core:file_moderate', file_id=file.id) }}">{% trans %}Moderate{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -67,7 +67,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if profile.mailing_subscriptions.exists() and (profile.id == user.id or user.is_root or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID)) %}
|
||||
{% if
|
||||
profile.mailing_subscriptions.exists()
|
||||
and (profile.id == user.id or user.is_root or user.is_com_admin)
|
||||
%}
|
||||
<h4>{% trans %}Subscribed mailing lists{% endtrans %}</h4>
|
||||
{% for sub in profile.mailing_subscriptions.all() %}
|
||||
<p>{{ sub.mailing.email }} <a href="{{ url('club:mailing_subscription_delete', mailing_subscription_id=sub.id) }}">{% trans %}Unsubscribe{% endtrans %}</a></p>
|
||||
|
@ -136,7 +136,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% if user.memberships.filter(end_date=None).exists() or user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user == profile or user.is_in_group(settings.SITH_BAR_MANAGER_BOARD_GROUP) %}
|
||||
{% if
|
||||
user == profile
|
||||
or user.memberships.ongoing().exists()
|
||||
or user.is_board_member
|
||||
or user.is_in_group(name=settings.SITH_BAR_MANAGER_BOARD_GROUP)
|
||||
%}
|
||||
{# if the user is member of a club, he can view the subscription state #}
|
||||
<hr>
|
||||
{% if profile.is_subscribed %}
|
||||
|
@ -35,7 +35,7 @@
|
||||
{%- else -%}
|
||||
<em>{% trans %}To edit your profile picture, ask a member of the AE{% endtrans %}</em>
|
||||
{%- endif -%}
|
||||
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.profile_pict.id -%}
|
||||
{%- if user.is_board_member and form.instance.profile_pict.id -%}
|
||||
<a href="{{ url('core:file_delete', file_id=form.instance.profile_pict.id, popup='') }}">
|
||||
{%- trans -%}Delete{%- endtrans -%}
|
||||
</a>
|
||||
@ -55,7 +55,7 @@
|
||||
<div class="profile-picture-edit">
|
||||
<p>{{ form["avatar_pict"].label }}</p>
|
||||
{{ form["avatar_pict"] }}
|
||||
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.avatar_pict.id -%}
|
||||
{%- if user.is_board_member and form.instance.avatar_pict.id -%}
|
||||
<a href="{{ url('core:file_delete', file_id=form.instance.avatar_pict.id, popup='') }}">
|
||||
{%- trans -%}Delete{%- endtrans -%}
|
||||
</a>
|
||||
@ -75,7 +75,7 @@
|
||||
<div class="profile-picture-edit">
|
||||
<p>{{ form["scrub_pict"].label }}</p>
|
||||
{{ form["scrub_pict"] }}
|
||||
{%- if user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) and form.instance.scrub_pict.id -%}
|
||||
{%- if user.is_board_member and form.instance.scrub_pict.id -%}
|
||||
<a href="{{ url('core:file_delete', file_id=form.instance.scrub_pict.id, popup='') }}">
|
||||
{%- trans -%}Delete{%-endtrans -%}
|
||||
</a>
|
||||
|
@ -35,18 +35,21 @@
|
||||
{% endif %}
|
||||
|
||||
{% set is_admin_on_a_counter = false %}
|
||||
{% for b in settings.SITH_COUNTER_BARS if user.is_in_group(b[1] + " admin") %}
|
||||
{% for b in settings.SITH_COUNTER_BARS if user.is_in_group(name=b[1] + " admin") %}
|
||||
{% set is_admin_on_a_counter = true %}
|
||||
{% endfor %}
|
||||
|
||||
{% if
|
||||
user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID) or user.is_root
|
||||
or is_admin_on_a_counter
|
||||
is_admin_on_a_counter
|
||||
or user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||
%}
|
||||
<div>
|
||||
<h4>{% trans %}Counters{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID) or user.is_root %}
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_COUNTER_ADMIN_ID)
|
||||
%}
|
||||
<li><a href="{{ url('counter:admin_list') }}">{% trans %}General counters management{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:product_list') }}">{% trans %}Products management{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('counter:producttype_list') }}">{% trans %}Product types management{% endtrans %}</a></li>
|
||||
@ -57,7 +60,7 @@
|
||||
</ul>
|
||||
<ul>
|
||||
{% for b in settings.SITH_COUNTER_BARS %}
|
||||
{% if user.is_in_group(b[1]+" admin") %}
|
||||
{% if user.is_in_group(name=b[1]+" admin") %}
|
||||
{% set c = Counter.objects.filter(id=b[0]).first() %}
|
||||
|
||||
<li class="rows counter">
|
||||
@ -85,13 +88,16 @@
|
||||
{% endif %}
|
||||
|
||||
{% if
|
||||
user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root
|
||||
or user.memberships.filter(end_date=None).filter(role__gte=7).all() | length > 10
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or user.memberships.ongoing().filter(role__gte=7).count() > 10
|
||||
%}
|
||||
<div>
|
||||
<h4>{% trans %}Accounting{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_root %}
|
||||
{% if user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
%}
|
||||
<li><a href="{{ url('accounting:refound_account') }}">{% trans %}Refound Account{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('accounting:bank_list') }}">{% trans %}General accounting{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('accounting:co_list') }}">{% trans %}Company list{% endtrans %}</a></li>
|
||||
@ -118,11 +124,15 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user.is_root %}
|
||||
{% if
|
||||
user.is_root
|
||||
or user.is_com_admin
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID)
|
||||
%}
|
||||
<div>
|
||||
<h4>{% trans %}Communication{% endtrans %}</h4>
|
||||
<ul>
|
||||
{% if user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) or user.is_root %}
|
||||
{% if user.is_com_admin or user.is_root %}
|
||||
<li><a href="{{ url('com:weekmail_article') }}">{% trans %}Create weekmail article{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('com:weekmail') }}">{% trans %}Weekmail{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('com:weekmail_destinations') }}">{% trans %}Weekmail destinations{% endtrans %}</a></li>
|
||||
@ -135,7 +145,7 @@
|
||||
<li><a href="{{ url('com:poster_list') }}">{% trans %}Posters{% endtrans %}</a></li>
|
||||
<li><a href="{{ url('com:screen_list') }}">{% trans %}Screens{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_in_group(settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
||||
{% if user.is_in_group(pk=settings.SITH_GROUP_SAS_ADMIN_ID) %}
|
||||
<li><a href="{{ url('sas:moderation') }}">{% trans %}Moderate pictures{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@ -153,7 +163,10 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID) or user.is_root %}
|
||||
{% if
|
||||
user.is_root
|
||||
or user.is_in_group(pk=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
%}
|
||||
<div>
|
||||
<h4>{% trans %}Pedagogy{% endtrans %}</h4>
|
||||
<ul>
|
||||
|
201
core/tests.py
201
core/tests.py
@ -15,13 +15,18 @@
|
||||
#
|
||||
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.core.management import call_command
|
||||
from django.utils.timezone import now
|
||||
|
||||
from core.models import User, Group, Page
|
||||
from club.models import Membership
|
||||
from core.models import User, Group, Page, AnonymousUser
|
||||
from core.markdown import markdown
|
||||
from sith import settings
|
||||
|
||||
"""
|
||||
to run these tests :
|
||||
@ -30,11 +35,9 @@ to run these tests :
|
||||
|
||||
|
||||
class UserRegistrationTest(TestCase):
|
||||
def setUp(self):
|
||||
try:
|
||||
Group.objects.create(name="root")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
User.objects.all().delete()
|
||||
|
||||
def test_register_user_form_ok(self):
|
||||
"""
|
||||
@ -282,19 +285,8 @@ class MarkdownTest(TestCase):
|
||||
|
||||
class PageHandlingTest(TestCase):
|
||||
def setUp(self):
|
||||
self.root_group = Group.objects.create(name="root")
|
||||
u = User(
|
||||
username="root",
|
||||
last_name="",
|
||||
first_name="Bibou",
|
||||
email="ae.info@utbm.fr",
|
||||
date_of_birth="1942-06-12",
|
||||
is_superuser=True,
|
||||
is_staff=True,
|
||||
)
|
||||
u.set_password("plop")
|
||||
u.save()
|
||||
self.client.login(username="root", password="plop")
|
||||
self.root_group = Group.objects.get(name="Root")
|
||||
|
||||
def test_create_page_ok(self):
|
||||
"""
|
||||
@ -321,12 +313,20 @@ class PageHandlingTest(TestCase):
|
||||
"""
|
||||
Should create a page correctly
|
||||
"""
|
||||
# remove all other pages to make sure there is no side effect
|
||||
Page.objects.all().delete()
|
||||
self.client.post(
|
||||
reverse("core:page_new"), {"parent": "", "name": "guy", "owner_group": "1"}
|
||||
reverse("core:page_new"),
|
||||
{"parent": "", "name": "guy", "owner_group": str(self.root_group.id)},
|
||||
)
|
||||
page = Page.objects.first()
|
||||
response = self.client.post(
|
||||
reverse("core:page_new"),
|
||||
{"parent": "1", "name": "bibou", "owner_group": "1"},
|
||||
{
|
||||
"parent": str(page.id),
|
||||
"name": "bibou",
|
||||
"owner_group": str(self.root_group.id),
|
||||
},
|
||||
)
|
||||
response = self.client.get(
|
||||
reverse("core:page", kwargs={"page_name": "guy/bibou"})
|
||||
@ -392,9 +392,6 @@ http://git.an
|
||||
|
||||
|
||||
class UserToolsTest(TestCase):
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
def test_anonymous_user_unauthorized(self):
|
||||
response = self.client.get(reverse("core:user_tools"))
|
||||
self.assertEqual(response.status_code, 403)
|
||||
@ -432,13 +429,12 @@ class UserToolsTest(TestCase):
|
||||
|
||||
|
||||
class FileHandlingTest(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.subscriber = User.objects.get(username="subscriber")
|
||||
|
||||
def setUp(self):
|
||||
try:
|
||||
call_command("populate")
|
||||
self.subscriber = User.objects.filter(username="subscriber").first()
|
||||
self.client.login(username="subscriber", password="plop")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.client.login(username="subscriber", password="plop")
|
||||
|
||||
def test_create_folder_home(self):
|
||||
response = self.client.post(
|
||||
@ -466,3 +462,150 @@ class FileHandlingTest(TestCase):
|
||||
)
|
||||
self.assertTrue(response.status_code == 200)
|
||||
self.assertTrue("ls</a>" in str(response.content))
|
||||
|
||||
|
||||
class UserIsInGroupTest(TestCase):
|
||||
"""
|
||||
Test that the User.is_in_group() and AnonymousUser.is_in_group()
|
||||
work as intended
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
from club.models import Club
|
||||
|
||||
cls.root_group = Group.objects.get(name="Root")
|
||||
cls.public = Group.objects.get(name="Public")
|
||||
cls.subscribers = Group.objects.get(name="Subscribers")
|
||||
cls.old_subscribers = Group.objects.get(name="Old subscribers")
|
||||
cls.accounting_admin = Group.objects.get(name="Accounting admin")
|
||||
cls.com_admin = Group.objects.get(name="Communication admin")
|
||||
cls.counter_admin = Group.objects.get(name="Counter admin")
|
||||
cls.banned_alcohol = Group.objects.get(name="Banned from buying alcohol")
|
||||
cls.banned_counters = Group.objects.get(name="Banned from counters")
|
||||
cls.banned_subscription = Group.objects.get(name="Banned to subscribe")
|
||||
cls.sas_admin = Group.objects.get(name="SAS admin")
|
||||
cls.club = Club.objects.create(
|
||||
name="Fake Club",
|
||||
unix_name="fake-club",
|
||||
address="Fake address",
|
||||
)
|
||||
cls.main_club = Club.objects.get(id=1)
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.toto = User.objects.create(
|
||||
username="toto", first_name="a", last_name="b", email="a.b@toto.fr"
|
||||
)
|
||||
self.skia = User.objects.get(username="skia")
|
||||
|
||||
def assert_in_public_group(self, user):
|
||||
self.assertTrue(user.is_in_group(pk=self.public.id))
|
||||
self.assertTrue(user.is_in_group(name=self.public.name))
|
||||
|
||||
def assert_in_club_metagroups(self, user, club):
|
||||
meta_groups_board = club.unix_name + settings.SITH_BOARD_SUFFIX
|
||||
meta_groups_members = club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||
self.assertFalse(user.is_in_group(name=meta_groups_board))
|
||||
self.assertFalse(user.is_in_group(name=meta_groups_members))
|
||||
|
||||
def assert_only_in_public_group(self, user):
|
||||
self.assert_in_public_group(user)
|
||||
for group in (
|
||||
self.root_group,
|
||||
self.banned_counters,
|
||||
self.accounting_admin,
|
||||
self.sas_admin,
|
||||
self.subscribers,
|
||||
self.old_subscribers,
|
||||
):
|
||||
self.assertFalse(user.is_in_group(pk=group.pk))
|
||||
self.assertFalse(user.is_in_group(name=group.name))
|
||||
meta_groups_board = self.club.unix_name + settings.SITH_BOARD_SUFFIX
|
||||
meta_groups_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||
self.assertFalse(user.is_in_group(name=meta_groups_board))
|
||||
self.assertFalse(user.is_in_group(name=meta_groups_members))
|
||||
|
||||
def test_anonymous_user(self):
|
||||
"""
|
||||
Test that anonymous users are only in the public group
|
||||
"""
|
||||
user = AnonymousUser()
|
||||
self.assert_only_in_public_group(user)
|
||||
|
||||
def test_not_subscribed_user(self):
|
||||
"""
|
||||
Test that users who never subscribed are only in the public group
|
||||
"""
|
||||
self.assert_only_in_public_group(self.toto)
|
||||
|
||||
def test_wrong_parameter_fail(self):
|
||||
"""
|
||||
Test that when neither the pk nor the name argument is given,
|
||||
the function raises a ValueError
|
||||
"""
|
||||
with self.assertRaises(ValueError):
|
||||
self.toto.is_in_group()
|
||||
|
||||
def test_number_queries(self):
|
||||
"""
|
||||
Test that the number of db queries is stable
|
||||
and that less queries are made when making a new call
|
||||
"""
|
||||
# make sure Skia is in at least one group
|
||||
self.skia.groups.add(Group.objects.first().pk)
|
||||
skia_groups = self.skia.groups.all()
|
||||
|
||||
group_in = skia_groups.first()
|
||||
cache.clear()
|
||||
# Test when the user is in the group
|
||||
with self.assertNumQueries(2):
|
||||
self.skia.is_in_group(pk=group_in.id)
|
||||
with self.assertNumQueries(0):
|
||||
self.skia.is_in_group(pk=group_in.id)
|
||||
|
||||
ids = skia_groups.values_list("pk", flat=True)
|
||||
group_not_in = Group.objects.exclude(pk__in=ids).first()
|
||||
cache.clear()
|
||||
# Test when the user is not in the group
|
||||
with self.assertNumQueries(2):
|
||||
self.skia.is_in_group(pk=group_not_in.id)
|
||||
with self.assertNumQueries(0):
|
||||
self.skia.is_in_group(pk=group_not_in.id)
|
||||
|
||||
def test_cache_properly_cleared_membership(self):
|
||||
"""
|
||||
Test that when the membership of a user end,
|
||||
the cache is properly invalidated
|
||||
"""
|
||||
membership = Membership.objects.create(
|
||||
club=self.club, user=self.toto, end_date=None
|
||||
)
|
||||
meta_groups_members = self.club.unix_name + settings.SITH_MEMBER_SUFFIX
|
||||
cache.clear()
|
||||
self.assertTrue(self.toto.is_in_group(name=meta_groups_members))
|
||||
self.assertEqual(
|
||||
membership, cache.get(f"membership_{self.club.id}_{self.toto.id}")
|
||||
)
|
||||
membership.end_date = now() - timedelta(minutes=5)
|
||||
membership.save()
|
||||
cached_membership = cache.get(f"membership_{self.club.id}_{self.toto.id}")
|
||||
self.assertEqual(cached_membership, "not_member")
|
||||
self.assertFalse(self.toto.is_in_group(name=meta_groups_members))
|
||||
|
||||
def test_cache_properly_cleared_group(self):
|
||||
"""
|
||||
Test that when a user is removed from a group,
|
||||
the is_in_group_method return False when calling it again
|
||||
"""
|
||||
self.toto.groups.add(self.com_admin.pk)
|
||||
self.assertTrue(self.toto.is_in_group(pk=self.com_admin.pk))
|
||||
|
||||
self.toto.groups.remove(self.com_admin.pk)
|
||||
self.assertFalse(self.toto.is_in_group(pk=self.com_admin.pk))
|
||||
|
||||
def test_not_existing_group(self):
|
||||
"""
|
||||
Test that searching for a not existing group
|
||||
returns False
|
||||
"""
|
||||
self.assertFalse(self.skia.is_in_group(name="This doesn't exist"))
|
||||
|
@ -35,11 +35,13 @@ def get_git_revision_short_hash() -> str:
|
||||
"""
|
||||
Return the short hash of the current commit
|
||||
"""
|
||||
return (
|
||||
subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
|
||||
.decode("ascii")
|
||||
.strip()
|
||||
)
|
||||
try:
|
||||
output = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
|
||||
if isinstance(output, bytes):
|
||||
return output.decode("ascii").strip()
|
||||
return output.strip()
|
||||
except subprocess.CalledProcessError:
|
||||
return ""
|
||||
|
||||
|
||||
def get_start_of_semester(d=date.today()):
|
||||
|
@ -162,7 +162,6 @@ class GenericContentPermissionMixinBuilder(View):
|
||||
return cls.permission_function(obj, user)
|
||||
|
||||
def dispatch(self, request, *arg, **kwargs):
|
||||
|
||||
if hasattr(self, "get_object") and callable(self.get_object):
|
||||
self.object = self.get_object()
|
||||
if not self.get_permission_function(self.object, request.user):
|
||||
|
@ -23,7 +23,7 @@ from django.views.generic.detail import SingleObjectMixin
|
||||
from django.forms.models import modelform_factory
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.http import HttpResponse
|
||||
from django.http import Http404, HttpResponse
|
||||
from wsgiref.util import FileWrapper
|
||||
from django.urls import reverse
|
||||
from django.core.exceptions import PermissionDenied
|
||||
@ -34,7 +34,12 @@ import os
|
||||
from ajax_select import make_ajax_field
|
||||
|
||||
from core.models import SithFile, RealGroup, Notification
|
||||
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, can_view, not_found
|
||||
from core.views import (
|
||||
CanViewMixin,
|
||||
CanEditMixin,
|
||||
CanEditPropMixin,
|
||||
can_view,
|
||||
)
|
||||
from counter.models import Counter
|
||||
|
||||
|
||||
@ -58,6 +63,11 @@ def send_file(request, file_id, file_class=SithFile, file_attr="file"):
|
||||
raise PermissionDenied
|
||||
name = f.__getattribute__(file_attr).name
|
||||
filepath = os.path.join(settings.MEDIA_ROOT, name)
|
||||
|
||||
# check if file exists on disk
|
||||
if not os.path.exists(filepath.encode("utf-8")):
|
||||
raise Http404()
|
||||
|
||||
with open(filepath.encode("utf-8"), "rb") as filename:
|
||||
wrapper = FileWrapper(filename)
|
||||
response = HttpResponse(wrapper, content_type=f.mime_type)
|
||||
@ -152,6 +162,13 @@ class FileEditView(CanEditMixin, UpdateView):
|
||||
template_name = "core/file_edit.jinja"
|
||||
context_object_name = "file"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if not self.object.can_be_managed_by(request.user):
|
||||
raise PermissionDenied
|
||||
|
||||
return super(FileEditView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_form_class(self):
|
||||
fields = ["name", "is_moderated"]
|
||||
if self.object.is_file:
|
||||
@ -197,6 +214,13 @@ class FileEditPropView(CanEditPropMixin, UpdateView):
|
||||
context_object_name = "file"
|
||||
form_class = FileEditPropForm
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if not self.object.can_be_managed_by(request.user):
|
||||
raise PermissionDenied
|
||||
|
||||
return super(FileEditPropView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super(FileEditPropView, self).get_form(form_class)
|
||||
form.fields["parent"].queryset = SithFile.objects.filter(is_folder=True)
|
||||
@ -269,6 +293,9 @@ class FileView(CanViewMixin, DetailView, FormMixin):
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.form = self.get_form()
|
||||
if not self.object.can_be_managed_by(request.user):
|
||||
raise PermissionDenied
|
||||
|
||||
if "clipboard" not in request.session.keys():
|
||||
request.session["clipboard"] = []
|
||||
return super(FileView, self).get(request, *args, **kwargs)
|
||||
@ -316,6 +343,13 @@ class FileDeleteView(CanEditPropMixin, DeleteView):
|
||||
template_name = "core/file_delete_confirm.jinja"
|
||||
context_object_name = "file"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
if not self.object.can_be_managed_by(request.user):
|
||||
raise PermissionDenied
|
||||
|
||||
return super(FileDeleteView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
self.object.file.delete() # Doing it here or overloading delete() is the same, so let's do it here
|
||||
if "next" in self.request.GET.keys():
|
||||
|
@ -82,6 +82,11 @@ class PageRevView(CanViewMixin, DetailView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
res = super(PageRevView, self).dispatch(request, *args, **kwargs)
|
||||
self.object = self.get_object()
|
||||
|
||||
if self.object is None:
|
||||
return redirect("core:page_create", page_name=self.kwargs["page_name"])
|
||||
|
||||
if self.object.need_club_redirection:
|
||||
return redirect(
|
||||
"club:club_view_rev", club_id=self.object.club.id, rev_id=kwargs["rev"]
|
||||
|
@ -31,6 +31,7 @@ from django.utils import html
|
||||
from django.views.generic import ListView, TemplateView
|
||||
from django.conf import settings
|
||||
from django.utils.text import slugify
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
import json
|
||||
|
||||
@ -51,12 +52,15 @@ class NotificationList(ListView):
|
||||
model = Notification
|
||||
template_name = "core/notification_list.jinja"
|
||||
|
||||
def get_queryset(self):
|
||||
def get_queryset(self) -> QuerySet[Notification]:
|
||||
if self.request.user.is_anonymous:
|
||||
return Notification.objects.none()
|
||||
# TODO: Bulk update in django 2.2
|
||||
if "see_all" in self.request.GET.keys():
|
||||
for n in self.request.user.notifications.filter(viewed=False):
|
||||
n.viewed = True
|
||||
n.save()
|
||||
|
||||
return self.request.user.notifications.order_by("-date")[:20]
|
||||
|
||||
|
||||
|
@ -254,10 +254,11 @@ class UserTabsMixin(TabedViewMixin):
|
||||
if user.customer and (
|
||||
user == self.request.user
|
||||
or self.request.user.is_in_group(
|
||||
settings.SITH_GROUP_ACCOUNTING_ADMIN_ID
|
||||
pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID
|
||||
)
|
||||
or self.request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
name=settings.SITH_BAR_MANAGER["unix_name"]
|
||||
+ settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or self.request.user.is_root
|
||||
):
|
||||
@ -320,7 +321,7 @@ class UserPicturesView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
last_album = None
|
||||
for picture in picture_qs:
|
||||
album = picture.parent
|
||||
if album.id != last_album:
|
||||
if album.id != last_album and album not in kwargs["albums"]:
|
||||
kwargs["albums"].append(album)
|
||||
kwargs["pictures"][album.id] = []
|
||||
last_album = album.id
|
||||
@ -413,6 +414,7 @@ class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
||||
self.graph = pgv.AGraph(strict=False, directed=True)
|
||||
family = set()
|
||||
self.level = 1
|
||||
|
||||
# Since the tree isn't very deep, we can build it recursively
|
||||
def crawl_family(user):
|
||||
if self.level > self.depth:
|
||||
@ -487,9 +489,9 @@ class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
||||
|
||||
if not (
|
||||
profile == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
name=settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or request.user.is_root
|
||||
):
|
||||
@ -717,8 +719,12 @@ class UserPreferencesView(UserTabsMixin, CanEditMixin, UpdateView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super(UserPreferencesView, self).get_context_data(**kwargs)
|
||||
if not hasattr(self.object, "trombi_user"):
|
||||
|
||||
if not (
|
||||
hasattr(self.object, "trombi_user") and self.request.user.trombi_user.trombi
|
||||
):
|
||||
kwargs["trombi_form"] = UserTrombiForm()
|
||||
|
||||
if hasattr(self.object, "customer"):
|
||||
kwargs["student_card_form"] = StudentCardForm()
|
||||
return kwargs
|
||||
@ -771,9 +777,9 @@ class UserAccountBase(UserTabsMixin, DetailView):
|
||||
res = super(UserAccountBase, self).dispatch(request, *arg, **kwargs)
|
||||
if (
|
||||
self.object == request.user
|
||||
or request.user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(pk=settings.SITH_GROUP_ACCOUNTING_ADMIN_ID)
|
||||
or request.user.is_in_group(
|
||||
settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
name=settings.SITH_BAR_MANAGER["unix_name"] + settings.SITH_BOARD_SUFFIX
|
||||
)
|
||||
or request.user.is_root
|
||||
):
|
||||
|
Reference in New Issue
Block a user