Skip to content
Snippets Groups Projects
Commit 1eab6c70 authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'copy-from-ticdesk' into 'master'

Reformat and cleanup

See merge request !1
parents 0a93d060 51e1353a
No related branches found
No related tags found
1 merge request!1Reformat and cleanup
Pipeline #56208 passed
Showing
with 1390 additions and 1298 deletions
......@@ -64,6 +64,8 @@ docs/_build/
# Generated files
aleksis/node_modules/
aleksis/static/
aleksis/whoosh_index/
poetry.lock
.coverage
.mypy_cache/
......@@ -72,3 +74,8 @@ htmlcov/
maintenance_mode_state.txt
media/
package-lock.json
# VSCode
.vscode/
.history/
*.code-workspace
include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
# - project: "AlekSIS/official/AlekSIS"
# file: /ci/test.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/docker/dist.yml
variables:
GIT_SUBMODULE_STRATEGY: recursive
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
FF_NETWORK_PER_BUILD: "true"
POETRY_REPOSITORIES_GITLAB_URL: "$CI_API_V4_URL/projects/${CI_PROJECT_ID}/packages/pypi"
POETRY_HTTP_BASIC_GITLAB_USERNAME: gitlab-ci-token
POETRY_HTTP_BASIC_GITLAB_PASSWORD: "$CI_JOB_TOKEN"
POETRY_PYPI_TOKEN_PYPI: "$TICDESK_PUBLISH_TOKEN"
deploy_gitlab:
interruptible: true
stage: publish
script:
- if [ x$CI_COMMIT_REF_NAME = x$CI_COMMIT_TAG ]; then
if ! [ "$(poetry version | cut -d" " -f2)" = $CI_COMMIT_REF_NAME ]; then
echo "Package version does not match tag. Aborting build of tag!" >/dev/fd/2 ;
exit 1 ;
fi ;
else
poetry version $(poetry version | cut -d" " -f2)+$(date --date=${CI_COMMIT_TIMESTAMP} +%Y%m%d%H%M%S).${CI_COMMIT_SHORT_SHA} ;
fi
- poetry publish -r gitlab
......@@ -16,7 +16,8 @@ Licence
::
Copyright © 2021 Dominik George <dominik.george@teckids.org>
Copyright © 2018, 2021 Dominik George <dominik.george@teckids.org>
Copyright © 2019, 2022 Tom Teichler <tom.teichler@teckids.org>
Licenced under the EUPL, version 1.2 or later
......@@ -32,6 +33,6 @@ AlekSIS® is a registered trademark of the AlekSIS open source project, represen
by Teckids e.V. Please refer to the `trademark policy`_ for hints on using the trademark
AlekSIS®.
.. _AlekSIS: https://edugit.org/AlekSIS/AlekSIS
.. _AlekSIS®: https://edugit.org/AlekSIS/AlekSIS
.. _European Union Public Licence: https://eupl.eu/
.. _trademark policy: https://aleksis.org/pages/about
......@@ -7,7 +7,10 @@ class DefaultConfig(AppConfig):
dist_name = "AlekSIS-App-Paweljong"
urls = {
"Repository": "https://edugit.org//hacknfun//AlekSIS-App-Paweljong",
"Repository": "https://edugit.org/Teckids/hacknfun/AlekSIS-App-Paweljong",
}
licence = "EUPL-1.2+"
copyright_info = (([2021], "Dominik George", "dominik.george@.org"),)
copyright_info = (
([2018, 2021], "Dominik George", "dominik.george@teckids.org"),
([2019, 2022], "Tom Teichler", "tom.teichler@teckids.org"),
)
......@@ -5,27 +5,27 @@ from material import Layout, Row
from aleksis.core.filters import MultipleCharFilter
from .models import EventRegistration, FeedbackAspect, Voucher
from .models import Event, EventRegistration, Terms, Voucher
class EventRegistrationFilter(FilterSet):
class Meta:
model = EventRegistration
fields = ["person", "event", "accept_sepa", "date_registred"]
fields = ["person", "event", "accept_sepa", "date_registered"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form.layout = Layout(
Row("person", "event"),
Row("accept_sepa", "date_registred"),
Row("accept_sepa", "date_registered"),
)
class VoucherFilter(FilterSet):
event = MultipleCharFilter(
[
"event__short_name__icontains",
"event__display_name__icontains",
],
label=_("Search by event"),
)
......@@ -48,7 +48,21 @@ class VoucherFilter(FilterSet):
self.form.layout = Layout(Row("event", "name"))
class FeedbackAspectsFilter(FilterSet):
class TermsFilter(FilterSet):
class Meta:
model = FeedbackAspect
fields = ["aspect"]
model = Terms
fields = ["title"]
class EventFilter(FilterSet):
class Meta:
model = Event
fields = ["display_name", "published", "place"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form.layout = Layout(
Row("display_name"),
Row("published", "place"),
)
This diff is collapsed.
This diff is collapsed.
......@@ -4,47 +4,6 @@ MENUS = {
"NAV_MENU_CORE": [
{
"name": _("Events"),
"url": "events",
"icon": "event",
},
{
"name": _("Vouchers"),
"url": "#",
"icon": "confirmation_number",
"root": True,
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"paweljong.view_vouchers_rule",
)
],
"submenu": [
{
"name": _("Voucher overview"),
"url": "vouchers",
"icon": "confirmation_number",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"paweljong.change_vouchers_rule",
)
],
},
{
"name": _("Create voucher"),
"url": "create_vouchers",
"icon": "post_add",
"validator": [
(
"aleksis.core.util.predicates.permission_validator",
"paweljong.create_vouchers_rule",
)
],
},
],
},
{
"name": _("Event management"),
"url": "#",
"icon": "event_note",
"root": True,
......@@ -56,24 +15,24 @@ MENUS = {
],
"submenu": [
{
"name": _("Create event"),
"url": "create_event",
"icon": "event_available",
"name": _("Vouchers"),
"url": "vouchers",
"icon": "confirmation_number",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"paweljong.create_events_rule",
"paweljong.view_vouchers_rule",
)
],
},
{
"name": _("Manage feedback aspects"),
"url": "feedback_aspects",
"icon": "rate_review",
"name": _("Terms"),
"url": "terms",
"icon": "gavel",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
"paweljong.view_feedback_aspects_rule",
"paweljong.view_terms_rule",
)
],
},
......@@ -89,9 +48,9 @@ MENUS = {
],
},
{
"name": _("Manage upcoming events"),
"name": _("Upcoming events"),
"url": "manage_events",
"icon": "change",
"icon": "edit",
"validators": [
(
"aleksis.core.util.predicates.permission_validator",
......@@ -100,7 +59,7 @@ MENUS = {
],
},
{
"name": _("Manage registrations"),
"name": _("Registrations"),
"url": "registrations",
"icon": "how_to_reg",
"validators": [
......
......@@ -11,7 +11,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('core', '0028_alter_globalpermissions_options'),
('core', '0035_preference_model_unique'),
('sites', '0002_alter_domain_unique'),
]
......@@ -80,7 +80,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('date_registred', models.DateTimeField(auto_now_add=True, verbose_name='Registration date')),
('date_registered', models.DateTimeField(auto_now_add=True, verbose_name='Registration date')),
('comment', models.TextField(blank=True, default='', verbose_name='Comment / remarks')),
('channel', models.CharField(blank=True, default='', max_length=255, verbose_name='Channel')),
('donation', models.PositiveIntegerField(blank=True, null=True, verbose_name='Donation')),
......
# Generated by Django 3.2.12 on 2022-02-13 14:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0002_event_website'),
]
operations = [
migrations.AlterField(
model_name='event',
name='feedback_aspects',
field=models.ManyToManyField(blank=True, null=True, related_name='event', to='paweljong.FeedbackAspect', verbose_name='Feedback aspects'),
),
]
# Generated by Django 3.2.12 on 2022-02-16 18:52
import ckeditor.fields
from django.db import migrations
import django_iban.fields
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0003_alter_event_feedback_aspects'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='website',
),
migrations.AddField(
model_name='event',
name='information',
field=ckeditor.fields.RichTextField(default='', verbose_name='Information about the event'),
preserve_default=False,
),
migrations.AlterField(
model_name='eventregistration',
name='iban',
field=django_iban.fields.IBANField(blank=True, enforce_database_constraint=True, max_length=34, null=True, verbose_name='IBAN (for SEPA direct debit)'),
),
]
# Generated by Django 3.2.12 on 2022-02-16 21:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0004_richtext_field_information'),
]
operations = [
migrations.AddField(
model_name='eventregistration',
name='medical_information',
field=models.TextField(blank=True, default='', verbose_name='Medical information / intolerances'),
),
]
# Generated by Django 3.2.12 on 2022-02-18 14:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0005_eventregistration_medical_information'),
]
operations = [
migrations.AlterModelOptions(
name='eventregistration',
options={'verbose_name': 'Event registration', 'verbose_name_plural': 'Event registrations'},
),
migrations.AddConstraint(
model_name='eventfeedback',
constraint=models.UniqueConstraint(fields=('person', 'event'), name='unique_person_feedback_per_event'),
),
migrations.AddConstraint(
model_name='eventregistration',
constraint=models.UniqueConstraint(fields=('person', 'event'), name='unique_person_registration_per_event'),
),
]
# Generated by Django 3.2.12 on 2022-02-20 15:24
import ckeditor.fields
import django.contrib.sites.managers
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('sites', '0002_alter_domain_unique'),
('paweljong', '0006_unique_constraints'),
]
operations = [
migrations.RemoveField(
model_name='eventregistration',
name='channel',
),
migrations.AddField(
model_name='eventregistration',
name='school',
field=models.CharField(default='', max_length=255, verbose_name='Name of school'),
preserve_default=False,
),
migrations.AddField(
model_name='eventregistration',
name='school_class',
field=models.CharField(default='', max_length=255, verbose_name='School class'),
preserve_default=False,
),
migrations.AddField(
model_name='eventregistration',
name='school_place',
field=models.CharField(default='', max_length=255, verbose_name='Place of the school'),
preserve_default=False,
),
migrations.AlterField(
model_name='event',
name='feedback_aspects',
field=models.ManyToManyField(blank=True, related_name='event', to='paweljong.FeedbackAspect', verbose_name='Feedback aspects'),
),
migrations.CreateModel(
name='Terms',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extended_data', models.JSONField(default=dict, editable=False)),
('title', models.CharField(max_length=255, verbose_name='Title')),
('term', ckeditor.fields.RichTextField(verbose_name='Term')),
('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
],
options={
'abstract': False,
},
managers=[
('objects', django.contrib.sites.managers.CurrentSiteManager()),
],
),
migrations.AddField(
model_name='event',
name='terms',
field=models.ManyToManyField(blank=True, related_name='event', to='paweljong.Terms', verbose_name='Terms'),
),
]
# Generated by Django 3.2.12 on 2022-02-20 16:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0007_terms'),
]
operations = [
migrations.RemoveField(
model_name='eventregistration',
name='accept_data',
),
migrations.RemoveField(
model_name='eventregistration',
name='accept_general_terms',
),
migrations.RemoveField(
model_name='eventregistration',
name='accept_terms',
),
]
# Generated by Django 3.2.12 on 2022-02-20 17:36
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0008_remove_terms_from_event'),
]
operations = [
migrations.RemoveField(
model_name='feedbackaspect',
name='site',
),
migrations.RemoveField(
model_name='event',
name='feedback_aspects',
),
migrations.DeleteModel(
name='EventFeedback',
),
migrations.DeleteModel(
name='FeedbackAspect',
),
]
# Generated by Django 3.2.12 on 2022-02-20 21:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0009_remove_feedback'),
]
operations = [
migrations.AddField(
model_name='terms',
name='confirmation_text',
field=models.TextField(default='', verbose_name='Confirmation text'),
preserve_default=False,
),
]
# Generated by Django 3.2.12 on 2022-02-20 22:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('paweljong', '0010_term_confirmation_text'),
]
operations = [
migrations.AddField(
model_name='eventregistration',
name='accepted_terms',
field=models.ManyToManyField(related_name='registrations', to='paweljong.Terms', verbose_name='Accepted terms'),
),
]
from django.utils.translation import gettext_lazy as _
from jsonstore import CharField
from aleksis.core.models import Person
# Additional fields for persons
Person.field(school=CharField(verbose_name=_("Name of school")))
Person.field(school_class=CharField(verbose_name=_("School class")))
Person.field(school_place=CharField(verbose_name=_("Place of the school")))
from datetime import datetime
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from ckeditor.fields import RichTextField
from django_iban.fields import IBANField
from aleksis.core.mixins import ExtensibleModel
from aleksis.core.models import Group, Person
from aleksis.core.util.core_helpers import generate_random_code
class FeedbackAspect(ExtensibleModel):
aspect = models.CharField(max_length=100)
class Terms(ExtensibleModel):
title = models.CharField(max_length=255, verbose_name=_("Title"))
term = RichTextField(verbose_name=_("Term"))
confirmation_text = models.TextField(verbose_name=_("Confirmation text"))
def __str__(self) -> str:
return self.aspect
return self.title
class Event(ExtensibleModel):
......@@ -33,85 +38,46 @@ class Event(ExtensibleModel):
# Other details
cost = models.IntegerField(verbose_name=_("Cost in €"))
max_participants = models.PositiveSmallIntegerField(verbose_name=_("Maximum participants"))
website = models.CharField(verbose_name=_("Website of event"), max_length=255)
# Feedback
feedback_aspects = models.ManyToManyField(
FeedbackAspect, verbose_name=_("Feedback aspects"), related_name="event"
)
information = RichTextField(verbose_name=_("Information about the event"))
terms = models.ManyToManyField(Terms, verbose_name=_("Terms"), related_name="event", blank=True)
def __str__(self) -> str:
return self.display_name
def can_register(self, request=None):
now = timezone.now()
now = datetime.today().date()
if request and request.user.is_authenticated:
if request.user.person in self.linked_group.members.all():
return False
if EventRegistration.objects.filter(person=request.user.person).exists():
return False
if (
Voucher.objects.filter(event=self, person=request.user.person, used=False).count()
> 0
):
return True
if self.group.members.count() >= self.max_participants:
if self.linked_group.members.count() >= self.max_participants:
return False
if self.date_registration:
return self.date_registration >= timezone.now()
return self.date_event > timezone.now()
return self.date_registration >= now
return self.date_event > now
@property
def booked_percentage(self):
return self.group.members.count() / self.max_participants * 100
return self.linked_group.members.count() / self.max_participants * 100
@property
def members_persons(self):
return self.group.members.all()
return self.linked_group.members.all()
@property
def owners_persons(self):
return self.group.owners.all()
class EventFeedback(ExtensibleModel):
class Meta:
verbose_name = _("Event feedback")
verbose_name_plural = _("Event feedbacks")
COMMENT_CHOICES = [
("first", _("Only first name")),
("first_age", _("First name and age")),
("first_last_age", _("First name, last name and age")),
]
LICENCE_CHOICES = [
("CC-BY-4.0+", _("Creative Commons with attribution, 4.0 or later")),
(
"CC-BY-SA-4.0+",
_(
"Creative Commons with attribution and distribution only"
"under the same conditions, 4.0 or later"
),
),
]
event = models.ForeignKey(
Event, on_delete=models.CASCADE, verbose_name=_("Event"), related_name="feedback"
)
person = models.ForeignKey(
Person, on_delete=models.CASCADE, verbose_name=_("Person"), related_name="feedback"
)
comment_private = models.TextField(verbose_name=_("Private comment"), blank=True)
comment_public = models.TextField(verbose_name=_("Public comment"), blank=True)
comment_public_info = models.CharField(
choices=COMMENT_CHOICES, verbose_name=_("Information in the comment"), max_length=255
)
photos = models.ImageField(verbose_name=_("Photos"), upload_to="feedback/", blank=True)
photos_licence = models.CharField(
choices=LICENCE_CHOICES, verbose_name=_("Photo licence"), max_length=255
)
return self.linked_group.owners.all()
class Voucher(ExtensibleModel):
......@@ -148,18 +114,26 @@ class Voucher(ExtensibleModel):
def __str__(self) -> str:
return self.code
def save(self, *args, **kwargs):
if not self.code:
self.code = generate_random_code(5, 3)
super().save(*args, **kwargs)
class EventRegistration(ExtensibleModel):
class Meta:
verbose_name = _("Registration")
verbose_name_plural = _("Registrations")
event = models.ForeignKey(Event, on_delete=models.CASCADE, verbose_name=_("Event"))
person = models.ForeignKey(Person, on_delete=models.CASCADE, verbose_name=_("Person"))
date_registred = models.DateTimeField(auto_now_add=True, verbose_name=_("Registration date"))
date_registered = models.DateTimeField(auto_now_add=True, verbose_name=_("Registration date"))
school = models.CharField(verbose_name=_("Name of school"), max_length=255)
school_class = models.CharField(verbose_name=_("School class"), max_length=255)
school_place = models.CharField(verbose_name=_("Place of the school"), max_length=255)
comment = models.TextField(verbose_name=_("Comment / remarks"), blank=True, default="")
channel = models.CharField(verbose_name=_("Channel"), max_length=255, blank=True, default="")
medical_information = models.TextField(
verbose_name=_("Medical information / intolerances"), blank=True, default=""
)
voucher = models.ForeignKey(
Voucher,
on_delete=models.CASCADE,
......@@ -168,19 +142,28 @@ class EventRegistration(ExtensibleModel):
null=True,
)
donation = models.PositiveIntegerField(verbose_name=_("Donation"), blank=True, null=True)
accepted_terms = models.ManyToManyField(
Terms,
verbose_name=_("Accepted terms"),
related_name="registrations",
)
accept_sepa = models.BooleanField(verbose_name=_("SEPA direct debit"))
iban = IBANField(
verbose_name=_("IBAN (for SEPA direct debit)"),
enforce_database_constraint=True,
null=True,
)
accept_terms = models.BooleanField(verbose_name=_("Delcaration of consent by parents"))
accept_data = models.BooleanField(verbose_name=_("Declaration of consent data protection"))
accept_general_terms = models.BooleanField(
verbose_name=_("Declatation of consent terms and condition")
blank=True,
)
def __str__(self) -> str:
return f"{self.event}, {self.person.first_name} {self.person.last_name}"
class Meta:
verbose_name = _("Event registration")
verbose_name_plural = _("Event registrations")
constraints = [
models.UniqueConstraint(
fields=["person", "event"], name="unique_person_registration_per_event"
)
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment