1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-27 03:58:40 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
17be896a99 [permission] Add PermissionVar model 2022-10-10 19:37:51 +02:00
a69573ccdb Fix permission that allows users to create OAuth2 apps
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2022-08-29 11:21:45 +02:00
14 changed files with 122 additions and 86 deletions

View File

@ -1,8 +1,6 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
import datetime
from django.utils import timezone
from django.utils.html import escape
from django.utils.safestring import mark_safe
@ -77,9 +75,6 @@ def get_row_class(record):
c += " table-info"
elif record.note.balance < 0:
c += " table-danger"
#MODE VIEUXCON=ON
if (datetime.datetime.utcnow().timestamp() - record.note.created_at.timestamp()) > 3600*24*365*3:
c += " font-weight-bold"
return c

View File

@ -223,13 +223,12 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
# Keep only users that have a note
note_qs = note_qs.filter(note__noteuser__isnull=False)
# if activity.activity_type.name != "Pot Vieux":
# # Keep only members
# note_qs = note_qs.filter(
# note__noteuser__user__memberships__club=activity.attendees_club,
# note__noteuser__user__memberships__date_start__lte=timezone.now(),
# note__noteuser__user__memberships__date_end__gte=timezone.now(),
# )
# Keep only members
note_qs = note_qs.filter(
note__noteuser__user__memberships__club=activity.attendees_club,
note__noteuser__user__memberships__date_start__lte=timezone.now(),
note__noteuser__user__memberships__date_end__gte=timezone.now(),
)
# Filter with permission backend
note_qs = note_qs.filter(PermissionBackend.filter_queryset(self.request, Alias, "view"))

View File

@ -1,5 +0,0 @@
from rest_framework.pagination import PageNumberPagination
class CustomPagination(PageNumberPagination):
page_size_query_param = 'page_size'

View File

@ -4,7 +4,7 @@
from django.contrib import admin
from note_kfet.admin import admin_site
from .models import Permission, PermissionMask, Role
from .models import Permission, PermissionVar, PermissionMask, Role
@admin.register(PermissionMask, site=admin_site)
@ -15,6 +15,14 @@ class PermissionMaskAdmin(admin.ModelAdmin):
list_display = ('description', 'rank', )
@admin.register(PermissionVar, site=admin_site)
class PermissionVarAdmin(admin.ModelAdmin):
"""
Admin customisation for PermissionVar
"""
list_display = ('name', 'description',)
@admin.register(Permission, site=admin_site)
class PermissionAdmin(admin.ModelAdmin):
"""

View File

@ -1967,7 +1967,7 @@
"note",
"transaction"
],
"query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]]",
"query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]]",
"type": "change",
"mask": 2,
"field": "valid",
@ -2607,7 +2607,7 @@
"note",
"transaction"
],
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]",
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]",
"type": "change",
"mask": 2,
"field": "valid",
@ -2623,7 +2623,7 @@
"note",
"transaction"
],
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}]",
"query": "[\"OR\", {\"source__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": true}, {\"destination__balance__gte\": {\"F\": [\"SUB\", [\"MUL\", [\"F\", \"amount\"], [\"F\", \"quantity\"]], 5000]}, \"valid\": false}]",
"type": "change",
"mask": 2,
"field": "invalidity_reason",
@ -2928,7 +2928,7 @@
"application"
],
"query": "{\"user\": [\"user\"]}",
"type": "create",
"type": "add",
"mask": 1,
"field": "",
"permanent": true,
@ -3114,10 +3114,10 @@
187,
188,
189,
190,
191,
195,
196
190,
191,
195,
196
]
}
},
@ -3159,8 +3159,8 @@
159,
160,
179,
189,
190
189,
190
]
}
},
@ -3310,10 +3310,10 @@
176,
177,
178,
188,
188,
183,
186,
187
186,
187
]
}
},
@ -3508,13 +3508,13 @@
187,
188,
189,
190,
191,
192,
193,
194,
195,
196
190,
191,
192,
193,
194,
195,
196
]
}
},

View File

@ -0,0 +1,22 @@
# Generated by Django 2.2.28 on 2022-10-10 17:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('permission', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='PermissionVar',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.SlugField(unique=True, verbose_name='name')),
('query', models.TextField(verbose_name='query')),
('description', models.CharField(blank=True, max_length=255, verbose_name='description')),
],
),
]

View File

@ -118,6 +118,25 @@ class PermissionMask(models.Model):
verbose_name_plural = _("permission masks")
class PermissionVar(models.Model):
name = models.SlugField(
unique=True,
blank=False,
verbose_name=_("name"),
)
query = models.TextField(
verbose_name=_("query"),
)
description = models.CharField(
max_length=255,
blank=True,
verbose_name=_("description"),
)
class Permission(models.Model):
PERMISSION_TYPES = [
@ -139,6 +158,7 @@ class Permission(models.Model):
# query -> ["AND", query, …] AND multiple queries
# | ["OR", query, …] OR multiple queries
# | ["NOT", query] Opposite of query
# | ["VAR", query] A var name as defined in PermissionVar
# query -> {key: value, …} A list of fields and values of a Q object
# key -> string A field name
# value -> int | string | bool | null Literal values
@ -150,6 +170,7 @@ class Permission(models.Model):
# | ["MUL", oper, …] Multiply F objects or literals
# | int | string | bool | null Literal values
# | ["F", string] A field
# | ["VAR", string] A var name as defined in PermissionVar
#
# Examples:
# Q(is_superuser=True) := {"is_superuser": true}
@ -215,6 +236,8 @@ class Permission(models.Model):
return functools.reduce(operator.mul, [Permission.compute_f(oper, **kwargs) for oper in oper[1:]])
elif oper[0] == 'F':
return F(oper[1])
elif oper[0] == 'VAR':
return compute_f(json.loads(PermissionVar.objects.get(name=oper[1]).query), **kwargs)
else:
field = kwargs[oper[0]]
for i in range(1, len(oper)):
@ -289,6 +312,8 @@ class Permission(models.Model):
return functools.reduce(operator.or_, [Permission._about(query, **kwargs) for query in query[1:]])
elif query[0] == 'NOT':
return ~Permission._about(query[1], **kwargs)
elif query[0] == 'VAR':
return Permission._about(json.loads(PermissionVar.objects.get(name=query[1]).query), **kwargs)
else:
return Q(pk=F("pk")) if Permission.compute_param(query, **kwargs) else ~Q(pk=F("pk"))
elif isinstance(query, dict):

View File

@ -310,8 +310,8 @@ class SogeCredit(models.Model):
amount = sum(transaction.total for transaction in self.transactions.all())
if 'wei' in settings.INSTALLED_APPS:
from wei.models import WEIMembership
if not WEIMembership.objects\
.filter(club__weiclub__year=self.credit_transaction.created_at.year, user=self.user).exists():
if not WEIMembership.objects.filter(club__weiclub__year=datetime.date.today().year, user=self.user)\
.exists():
# 80 € for people that don't go to WEI
amount += 8000
return amount
@ -329,18 +329,17 @@ class SogeCredit(models.Model):
bde_qs = Membership.objects.filter(user=self.user, club=bde, date_start__gte=bde.membership_start)
kfet_qs = Membership.objects.filter(user=self.user, club=kfet, date_start__gte=kfet.membership_start)
## Soge do not pay BDE and kfet memberships this year (2022-2023)
# if bde_qs.exists():
# m = bde_qs.get()
# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
# if m.transaction not in self.transactions.all():
# self.transactions.add(m.transaction)
#
# if kfet_qs.exists():
# m = kfet_qs.get()
# if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
# if m.transaction not in self.transactions.all():
# self.transactions.add(m.transaction)
if bde_qs.exists():
m = bde_qs.get()
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if kfet_qs.exists():
m = kfet_qs.get()
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if 'wei' in settings.INSTALLED_APPS:
from wei.models import WEIClub

View File

@ -14,17 +14,14 @@ from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInf
from ...models import WEIMembership
WORDS = [
'ABBA', 'After', 'Alcoolique anonyme', 'Ambiance festive', 'Années 2000', 'Apéro', 'Art',
'Baby foot billard biere pong', 'BBQ', 'Before', 'Bière pong', 'Bon enfant', 'Calme', 'Canapé',
'Chanson paillarde', 'Chanson populaire', 'Chartreuse', 'Cheerleader', 'Chill', 'Choré',
'Cinéma', 'Cocktail', 'Comédie musicle', 'Commercial', 'Copaing', 'Danse', 'Dancefloor',
'Electro', 'Fanfare', 'Gin tonic', 'Inclusif', 'Jazz', "Jeux d'alcool", 'Jeux de carte',
'Jeux de rôle', 'Jeux de société', 'JUL', 'Jus de fruit', 'Kfet', 'Kleptomanie assurée',
'LGBTQ+', 'Livre', 'Morning beer', 'Musique', 'NAPS', 'Paillettes', 'Pastis', 'Paté Hénaff',
'Peluche', 'Pena baiona', "Peu d'alcool", 'Pilier de bar', 'PMU', 'Poulpe', 'Punch', 'Rap',
'Réveil', 'Rock', 'Rugby', 'Sandwich', 'Serge', 'Shot', 'Sociable', 'Spectacle', 'Techno',
'Techno house', 'Thérapie Taxi', 'Tradition kchanaises', 'Troisième mi-temps', 'Turn up',
'Vodka', 'Vodka pomme', 'Volley', 'Vomi stratégique'
'13 organisé', '3ième mi temps', 'Années 2000', 'Apéro', 'BBQ', 'BP', 'Beauf', 'Binge drinking', 'Bon enfant',
'Cartouche', 'Catacombes', 'Chansons paillardes', 'Chansons populaires', 'Chanteur', 'Chartreuse', 'Chill',
'Core', 'DJ', 'Dancefloor', 'Danse', 'David Guetta', 'Disco', 'Eau de vie', 'Électro', 'Escalade', 'Familial',
'Fanfare', 'Fracassage', 'Féria', 'Hard rock', 'Hoeggarden', 'House', 'Huit-six', 'IPA', 'Inclusif', 'Inferno',
'Introverti', 'Jager bomb', 'Jazz', 'Jeux d\'alcool', 'Jeux de rôles', 'Jeux vidéo', 'Jul', 'Jus de fruit',
'Karaoké', 'LGBTQI+', 'Lady Gaga', 'Loup garou', 'Morning beer', 'Métal', 'Nuit blanche', 'Ovalie', 'Psychedelic',
'Pétanque', 'Rave', 'Reggae', 'Rhum', 'Ricard', 'Rock', 'Rosé', 'Rétro', 'Séducteur', 'Techno', 'Thérapie taxi',
'Théâtre', 'Trap', 'Turn up', 'Underground', 'Volley', 'Wati B', 'Zinédine Zidane',
]

View File

@ -252,7 +252,7 @@ REST_FRAMEWORK = {
'rest_framework.authentication.TokenAuthentication',
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
],
'DEFAULT_PAGINATION_CLASS': 'apps.api.pagination.CustomPagination',
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}

View File

@ -65,9 +65,7 @@ mark {
/* Last BDE colors */
.bg-primary {
/* background-color: rgb(18, 67, 4) !important; */
/* MODE VIEUXCON=ON */
background-color: rgb(0, 119, 139) !important;
background-color: rgb(102, 83, 105) !important;
}
html {
@ -83,14 +81,14 @@ body {
.btn-outline-primary:not(:disabled):not(.disabled).active,
.btn-outline-primary:not(:disabled):not(.disabled):active {
color: #fff;
background-color: rgb(0, 119, 139);
border-color: rgb(0, 119, 139);
background-color: rgb(102, 83, 105);
border-color: rgb(102, 83, 105);
}
.btn-outline-primary {
color: rgb(0, 119, 139);
color: rgb(102, 83, 105);
background-color: rgba(248, 249, 250, 0.9);
border-color: rgb(0, 119, 139);
border-color: rgb(102, 83, 105);
}
.turbolinks-progress-bar {
@ -101,35 +99,35 @@ body {
.btn-primary:not(:disabled):not(.disabled).active,
.btn-primary:not(:disabled):not(.disabled):active {
color: #fff;
background-color: rgb(0, 119, 139);
border-color: rgb(0, 119, 139);
background-color: rgb(102, 83, 105);
border-color: rgb(102, 83, 105);
}
.btn-primary {
color: rgba(248, 249, 250, 0.9);
background-color: rgb(0, 119, 139);
border-color: rgb(0, 119, 139);
background-color: rgb(102, 83, 105);
border-color: rgb(102, 83, 105);
}
.border-primary {
border-color: rgb(0,85, 102) !important;
border-color: rgb(115, 15, 115) !important;
}
a {
color: rgb(0, 119, 139);
color: rgb(102, 83, 105);
}
a:hover {
color: rgb(0, 171, 205);
color: rgb(200, 30, 200);
}
.form-control:focus {
box-shadow: 0 0 0 0.25rem rgba(0, 171, 205, 0.25);
border-color: rgb(0, 171, 205);
box-shadow: 0 0 0 0.25rem rgba(200, 30, 200, 0.25);
border-color: rgb(200, 30, 200);
}
.btn-outline-primary.focus {
box-shadow: 0 0 0 0.25rem rgba(0, 171, 205, 0.5);
box-shadow: 0 0 0 0.25rem rgba(200, 30, 200, 0.5);
}

View File

@ -96,13 +96,11 @@ function displayStyle (note) {
if (!note) { return '' }
const balance = note.balance
var css = ''
var ms_per_year = 31536000000 // 365 * 24 * 3600 * 1000
if (balance < -5000) { css += ' text-danger bg-dark' }
else if (balance < -1000) { css += ' text-danger' }
else if (balance < 0) { css += ' text-warning' }
if (!note.email_confirmed) { css += ' bg-primary' }
else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += ' bg-info' }
if (((Date.now() - Date.parse(note.created_at))/ms_per_year) > 3) { css += 'font-weight-bold' }
return css
}

View File

@ -23,11 +23,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% csrf_token %}
{{ form|crispy }}
{{ profile_form|crispy }}
{% comment "Soge not for membership (only WEI)" %} {{ soge_form|crispy }} {% endcomment %}
{{ soge_form|crispy }}
<button class="btn btn-success" type="submit">
{% trans "Sign up" %}
</button>
</form>
</div>
</div>
{% endblock %}
{% endblock %}