Skip to content
Snippets Groups Projects
Commit 1ab80c3e authored by Nadja Geisler's avatar Nadja Geisler :sunny:
Browse files

Merge 'main' into komasolver fork

parents ba8704fb e70f6062
No related branches found
No related tags found
1 merge request!261[WIP] compatibility with koma solver import/export
Pipeline #275677 failed
Showing
with 557 additions and 440 deletions
uwsgi==2.0.25.1
uwsgi==2.0.28
image: python:3.10
image: python:3.11
services:
- mysql
......@@ -26,22 +26,18 @@ cache:
- pip install pylint-gitlab pylint-django
- mysql --version
check:
migrations:
extends: .before_script_template
script:
- ./Utils/check.sh --all
- source venv/bin/activate
- ./manage.py makemigrations --dry-run --check
test:
extends: .before_script_template
script:
- source venv/bin/activate
- echo "GRANT ALL on *.* to '${MYSQL_USER}';"| mysql -u root --password="${MYSQL_ROOT_PASSWORD}" -h mysql
- pip install pytest-cov unittest-xml-reporting beautifulsoup4
- pip install pytest-cov unittest-xml-reporting
- coverage run --source='.' manage.py test --settings AKPlanning.settings_ci
after_script:
- source venv/bin/activate
- coverage report
- coverage xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
......@@ -56,8 +52,6 @@ lint:
extends: .before_script_template
stage: test
script:
- source venv/bin/activate
- pip install beautifulsoup4
- pylint --load-plugins pylint_django --django-settings-module=AKPlanning.settings_ci --rcfile pylintrc --exit-zero --output-format=text AK* | tee /tmp/pylint.txt
- sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
- pylint --load-plugins pylint_django --django-settings-module=AKPlanning.settings_ci --rcfile pylintrc --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter AK* > codeclimate.json
......
import zoneinfo
from django.apps import apps
from django.test import TestCase, override_settings
from django.test import override_settings, TestCase
from django.urls import reverse
from django.utils.timezone import now
from AKDashboard.models import DashboardButton
from AKModel.models import Event, AK, AKCategory
from AKModel.models import AK, AKCategory, Event
from AKModel.tests.test_views import BasicViewTests
......@@ -13,6 +14,7 @@ class DashboardTests(TestCase):
"""
Specific Dashboard Tests
"""
@classmethod
def setUpTestData(cls):
"""
......@@ -62,7 +64,7 @@ class DashboardTests(TestCase):
# History should be empty
response = self.client.get(url)
self.assertQuerysetEqual(response.context["recent_changes"], [])
self.assertQuerySetEqual(response.context["recent_changes"], [])
AK.objects.create(
name="Test AK",
......
This diff is collapsed.
# Generated by Django 4.2.13 on 2025-03-03 19:59
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('AKModel', '0062_interest_no_history'),
]
operations = [
migrations.AlterField(
model_name='ak',
name='name',
field=models.CharField(help_text='Name of the AK', max_length=256, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Name'),
),
migrations.AlterField(
model_name='ak',
name='short_name',
field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+')], verbose_name='Short Name'),
),
migrations.AlterField(
model_name='akowner',
name='name',
field=models.CharField(help_text='Name to identify an AK owner by', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Nickname'),
),
migrations.AlterField(
model_name='historicalak',
name='name',
field=models.CharField(help_text='Name of the AK', max_length=256, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+'), django.core.validators.RegexValidator(message='Must contain at least one letter or digit', regex='[\\w\\s]+')], verbose_name='Name'),
),
migrations.AlterField(
model_name='historicalak',
name='short_name',
field=models.CharField(blank=True, help_text='Name displayed in the schedule', max_length=64, validators=[django.core.validators.RegexValidator(inverse_match=True, message='May not contain quotation marks', regex='[\'\\"´`]+')], verbose_name='Short Name'),
),
]
# Generated by Django 5.1.6 on 2025-03-04 14:16
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('AKModel', '0063_field_validators'),
('AKModel', '0063_merge_0061_event_export_slot_0062_interest_no_history'),
]
operations = [
]
......@@ -4,10 +4,11 @@ import json
import math
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any, Iterable, Generator
from typing import Any, Generator, Iterable
from django.db import models, transaction
from django.apps import apps
from django.core.validators import RegexValidator
from django.db import models, transaction
from django.db.models import Count
from django.urls import reverse_lazy
from django.utils import timezone
......@@ -16,6 +17,15 @@ from django.utils.translation import gettext_lazy as _
from simple_history.models import HistoricalRecords
from timezone_field import TimeZoneField
# Custom validators to be used for some of the fields
# Prevent inclusion of the quotation marks ' " ´ `
# This may be necessary to prevent javascript issues
no_quotation_marks_validator = RegexValidator(regex=r"['\"´`]+", inverse_match=True,
message=_('May not contain quotation marks'))
# Enforce that the field contains of at least one letter or digit (and not just special characters
# This prevents issues when autogenerating slugs from that field
slugable_validator = RegexValidator(regex=r"[\w\s]+", message=_('Must contain at least one letter or digit'))
@dataclass
class OptimizerTimeslot:
......@@ -47,6 +57,7 @@ class OptimizerTimeslot:
def __repr__(self) -> str:
return f"({self.avail.simplified}, {self.idx}, {self.constraints})"
TimeslotBlock = list[OptimizerTimeslot]
......@@ -133,7 +144,8 @@ class Event(models.Model):
interest_start = models.DateTimeField(verbose_name=_('Interest Window Start'), blank=True, null=True,
help_text=
_('Opening time for expression of interest. When left blank, no interest indication will be possible.'))
_('Opening time for expression of interest. When left blank, no interest '
'indication will be possible.'))
interest_end = models.DateTimeField(verbose_name=_('Interest Window End'), blank=True, null=True,
help_text=_('Closing time for expression of interest.'))
......@@ -157,7 +169,6 @@ class Event(models.Model):
'when this event is exported for the solver.'
))
contact_email = models.EmailField(verbose_name=_("Contact email address"), blank=True,
help_text=_("An email address that is displayed on every page "
"and can be used for all kinds of questions"))
......@@ -191,7 +202,7 @@ class Event(models.Model):
event = Event.objects.filter(active=True).order_by('start').first()
# No active event? Return the next event taking place
if event is None:
event = Event.objects.order_by('start').filter(start__gt=datetime.now()).first()
event = Event.objects.order_by('start').filter(start__gt=datetime.now().astimezone()).first()
return event
def get_categories_with_aks(self, wishes_seperately=False,
......@@ -646,7 +657,9 @@ class Event(models.Model):
class AKOwner(models.Model):
""" An AKOwner describes the person organizing/holding an AK.
"""
name = models.CharField(max_length=64, verbose_name=_('Nickname'), help_text=_('Name to identify an AK owner by'))
name = models.CharField(max_length=64, verbose_name=_('Nickname'),
validators=[no_quotation_marks_validator, slugable_validator],
help_text=_('Name to identify an AK owner by'))
slug = models.SlugField(max_length=64, blank=True, verbose_name=_('Slug'), help_text=_('Slug for URL generation'))
institution = models.CharField(max_length=128, blank=True, verbose_name=_('Institution'), help_text=_('Uni etc.'))
link = models.URLField(blank=True, verbose_name=_('Web Link'), help_text=_('Link to Homepage'))
......@@ -725,8 +738,8 @@ class AKCategory(models.Model):
description = models.TextField(blank=True, verbose_name=_("Description"),
help_text=_("Short description of this AK Category"))
present_by_default = models.BooleanField(blank=True, default=True, verbose_name=_("Present by default"),
help_text=_("Present AKs of this category by default "
"if AK owner did not specify whether this AK should be presented?"))
help_text=_("Present AKs of this category by default if AK owner did not "
"specify whether this AK should be presented?"))
event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'),
help_text=_('Associated event'))
......@@ -822,8 +835,10 @@ class AKType(models.Model):
class AK(models.Model):
""" An AK is a slot-based activity to be scheduled during an event.
"""
name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK'))
name = models.CharField(max_length=256, verbose_name=_('Name'), help_text=_('Name of the AK'),
validators=[no_quotation_marks_validator, slugable_validator])
short_name = models.CharField(max_length=64, blank=True, verbose_name=_('Short Name'),
validators=[no_quotation_marks_validator],
help_text=_('Name displayed in the schedule'))
description = models.TextField(blank=True, verbose_name=_('Description'), help_text=_('Description of the AK'))
......@@ -997,7 +1012,7 @@ class AK(models.Model):
return reverse_lazy('submit:ak_detail', kwargs={'event_slug': self.event.slug, 'pk': self.id})
return self.edit_url
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
def save(self, *args, force_insert=False, force_update=False, using=None, update_fields=None):
# Auto-Generate Link if not set yet
if self.link == "":
link = self.event.base_url + self.name.replace(" ", "_")
......@@ -1006,7 +1021,8 @@ class AK(models.Model):
# Tell Django that we have updated the link field
if update_fields is not None:
update_fields = {"link"}.union(update_fields)
super().save(force_insert, force_update, using, update_fields)
super().save(*args,
force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class Room(models.Model):
......@@ -1161,7 +1177,7 @@ class AKSlot(models.Model):
def overlaps(self, other: "AKSlot"):
"""
Check wether two slots overlap
Check whether two slots overlap
:param other: second slot to compare with
:return: true if they overlap, false if not:
......@@ -1169,13 +1185,14 @@ class AKSlot(models.Model):
"""
return self.start < other.end <= self.end or self.start <= other.start < self.end
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
def save(self, *args, force_insert=False, force_update=False, using=None, update_fields=None):
# Make sure duration is not longer than the event
if update_fields is None or 'duration' in update_fields:
event_duration = self.event.end - self.event.start
event_duration_hours = event_duration.days * 24 + event_duration.seconds // 3600
self.duration = min(self.duration, event_duration_hours)
super().save(force_insert, force_update, using, update_fields)
super().save(*args,
force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
def as_json_dict(self) -> dict[str, Any]:
"""Return a json representation of the AK object of this slot.
......@@ -1256,6 +1273,7 @@ class AKSlot(models.Model):
return data
class AKOrgaMessage(models.Model):
"""
Model representing confidential messages to the organizers/scheduling people, belonging to a certain AK
......@@ -1288,6 +1306,7 @@ class ConstraintViolation(models.Model):
Depending on the type, different fields (references to other models) will be filled. Each violation should always
be related to an event and at least on other instance of a causing entity
"""
class Meta:
verbose_name = _('Constraint Violation')
verbose_name_plural = _('Constraint Violations')
......@@ -1505,6 +1524,7 @@ class DefaultSlot(models.Model):
Model representing a default slot,
i.e., a prefered slot to use for typical AKs in the schedule to guarantee enough breaks etc.
"""
class Meta:
verbose_name = _('Default Slot')
verbose_name_plural = _('Default Slots')
......@@ -1517,7 +1537,8 @@ class DefaultSlot(models.Model):
help_text=_('Associated event'))
primary_categories = models.ManyToManyField(to=AKCategory, verbose_name=_('Primary categories'), blank=True,
help_text=_('Categories that should be assigned to this slot primarily'))
help_text=_(
'Categories that should be assigned to this slot primarily'))
@property
def start_simplified(self) -> str:
......
from datetime import timedelta
from datetime import datetime, timedelta
from django.conf import settings
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.datetime_safe import datetime
from django.views.generic import ListView, DetailView
from django.views.generic import DetailView, ListView
from AKModel.models import AKSlot, Room, AKTrack
from AKModel.metaviews.admin import FilterByEventSlugMixin
from AKModel.models import AKSlot, AKTrack, Room
class PlanIndexView(FilterByEventSlugMixin, ListView):
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-27 15:13+0000\n"
"POT-Creation-Date: 2025-03-04 14:49+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -107,7 +107,6 @@ msgid "Event Status"
msgstr "Event-Status"
#: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:113
#: AKScheduling/views.py:50
msgid "Scheduling"
msgstr "Scheduling"
......@@ -240,7 +239,6 @@ msgstr[1] ""
" "
#: AKScheduling/templates/admin/AKScheduling/unscheduled.html:7
#: AKScheduling/views.py:25
msgid "Unscheduled AK Slots"
msgstr "Noch nicht geschedulte AK-Slots"
......@@ -248,22 +246,10 @@ msgstr "Noch nicht geschedulte AK-Slots"
msgid "Count"
msgstr "Anzahl"
#: AKScheduling/views.py:91
msgid "Constraint violations for"
msgstr "Constraintverletzungen für"
#: AKScheduling/views.py:106
msgid "AKs requiring special attention for"
msgstr "AKs die besondere Aufmerksamkeit erfordern für"
#: AKScheduling/views.py:152
msgid "Interest updated"
msgstr "Interesse aktualisiert"
#: AKScheduling/views.py:166
msgid "Enter interest"
msgstr "Interesse eingeben"
#: AKScheduling/views.py:210
msgid "Wishes"
msgstr "Wünsche"
......@@ -319,6 +305,15 @@ msgstr "Standardverfügbarkeiten für {count} AKs angelegt"
msgid "Constraint Violations"
msgstr "Constraintverletzungen"
#~ msgid "Constraint violations for"
#~ msgstr "Constraintverletzungen für"
#~ msgid "AKs requiring special attention for"
#~ msgstr "AKs die besondere Aufmerksamkeit erfordern für"
#~ msgid "Enter interest"
#~ msgstr "Interesse eingeben"
#~ msgid "Bitte AK auswählen"
#~ msgstr "Please sel"
......
from datetime import datetime
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.utils.datetime_safe import datetime
from AKModel.models import AK
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-02-27 15:13+0000\n"
"POT-Creation-Date: 2025-03-04 14:49+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -109,21 +109,25 @@ msgstr "AK-Wunsch"
#: AKSubmission/templates/AKSubmission/ak_detail.html:186
#, python-format
msgid ""
"This AK currently takes place for another <span v-html=\"timeUntilEnd\">"
"%(featured_slot_remaining)s</span> minute(s) in %(room)s.&nbsp;"
"This AK currently takes place for another <span v-"
"html=\"timeUntilEnd\">%(featured_slot_remaining)s</span> minute(s) in "
"%(room)s.&nbsp;"
msgstr ""
"Dieser AK findet noch <span v-html=\"timeUntilEnd\">"
"%(featured_slot_remaining)s</span> Minute(n) in %(room)s statt.&nbsp;\n"
"Dieser AK findet noch <span v-"
"html=\"timeUntilEnd\">%(featured_slot_remaining)s</span> Minute(n) in "
"%(room)s statt.&nbsp;\n"
" "
#: AKSubmission/templates/AKSubmission/ak_detail.html:189
#, python-format
msgid ""
"This AK starts in <span v-html=\"timeUntilStart\">"
"%(featured_slot_remaining)s</span> minute(s) in %(room)s.&nbsp;"
"This AK starts in <span v-"
"html=\"timeUntilStart\">%(featured_slot_remaining)s</span> minute(s) in "
"%(room)s.&nbsp;"
msgstr ""
"Dieser AK beginnt in <span v-html=\"timeUntilStart\">"
"%(featured_slot_remaining)s</span> Minute(n) in %(room)s.&nbsp;\n"
"Dieser AK beginnt in <span v-"
"html=\"timeUntilStart\">%(featured_slot_remaining)s</span> Minute(n) in "
"%(room)s.&nbsp;\n"
" "
#: AKSubmission/templates/AKSubmission/ak_detail.html:194
......@@ -274,7 +278,7 @@ msgstr "Die Ergebnisse dieses AKs vorstellen"
msgid "Intends to submit a resolution"
msgstr "Beabsichtigt eine Resolution einzureichen"
#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:84
#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:82
msgid "All AKs"
msgstr "Alle AKs"
......@@ -400,81 +404,80 @@ msgstr ""
msgid "Submit"
msgstr "Eintragen"
#: AKSubmission/views.py:127
#: AKSubmission/views.py:125
msgid "Wishes"
msgstr "Wünsche"
#: AKSubmission/views.py:127
#: AKSubmission/views.py:125
msgid "AKs one would like to have"
msgstr ""
"AKs die sich gewünscht wurden, aber bei denen noch nicht klar ist, wer sie "
"macht. Falls du dir das vorstellen kannst, trag dich einfach ein"
#: AKSubmission/views.py:169
#: AKSubmission/views.py:167
msgid "Currently planned AKs"
msgstr "Aktuell geplante AKs"
#: AKSubmission/views.py:233
msgid "AKs with Track"
msgstr "AK mit Track"
#: AKSubmission/views.py:302
#: AKSubmission/views.py:305
msgid "Event inactive. Cannot create or update."
msgstr "Event inaktiv. Hinzufügen/Bearbeiten nicht möglich."
#: AKSubmission/views.py:327
#: AKSubmission/views.py:330
msgid "AK successfully created"
msgstr "AK erfolgreich angelegt"
#: AKSubmission/views.py:400
#: AKSubmission/views.py:404
msgid "AK successfully updated"
msgstr "AK erfolgreich aktualisiert"
#: AKSubmission/views.py:451
#: AKSubmission/views.py:455
#, python-brace-format
msgid "Added '{owner}' as new owner of '{ak.name}'"
msgstr "'{owner}' als neue Leitung von '{ak.name}' hinzugefügt"
#: AKSubmission/views.py:555
#: AKSubmission/views.py:558
msgid "No user selected"
msgstr "Keine Person ausgewählt"
#: AKSubmission/views.py:571
#: AKSubmission/views.py:574
msgid "Person Info successfully updated"
msgstr "Personen-Info erfolgreich aktualisiert"
#: AKSubmission/views.py:607
#: AKSubmission/views.py:610
msgid "AK Slot successfully added"
msgstr "AK-Slot erfolgreich angelegt"
#: AKSubmission/views.py:626
#: AKSubmission/views.py:629
msgid "You cannot edit a slot that has already been scheduled"
msgstr "Bereits geplante AK-Slots können nicht mehr bearbeitet werden"
#: AKSubmission/views.py:636
#: AKSubmission/views.py:639
msgid "AK Slot successfully updated"
msgstr "AK-Slot erfolgreich aktualisiert"
#: AKSubmission/views.py:654
#: AKSubmission/views.py:657
msgid "You cannot delete a slot that has already been scheduled"
msgstr "Bereits geplante AK-Slots können nicht mehr gelöscht werden"
#: AKSubmission/views.py:664
#: AKSubmission/views.py:667
msgid "AK Slot successfully deleted"
msgstr "AK-Slot erfolgreich angelegt"
#: AKSubmission/views.py:676
#: AKSubmission/views.py:679
msgid "Messages"
msgstr "Nachrichten"
#: AKSubmission/views.py:686
#: AKSubmission/views.py:689
msgid "Delete all messages"
msgstr "Alle Nachrichten löschen"
#: AKSubmission/views.py:713
#: AKSubmission/views.py:716
msgid "Message to organizers successfully saved"
msgstr "Nachricht an die Organisator*innen erfolgreich gespeichert"
#~ msgid "AKs with Track"
#~ msgstr "AK mit Track"
#~ msgid ""
#~ "Due to technical reasons, the link you entered was truncated to a length "
#~ "of 200 characters"
......
from datetime import timedelta
from datetime import datetime, timedelta
from django.test import TestCase
from django.urls import reverse_lazy
from django.utils.datetime_safe import datetime
from AKModel.models import AK, AKSlot, Event
from AKModel.tests.test_views import BasicViewTests
......@@ -147,7 +146,8 @@ class ModelViewTests(BasicViewTests, TestCase):
add_redirect_url = reverse_lazy(f"{self.APP_NAME}:submit_ak", kwargs={'event_slug': 'kif42', 'owner_slug': 'a'})
response = self.client.post(select_url, {'owner_id': 1})
self.assertRedirects(response, add_redirect_url, status_code=302, target_status_code=200,
msg_prefix=f"Dispatch redirect to ak submission page failed (should go to {add_redirect_url})")
msg_prefix=f"Dispatch redirect to ak submission page failed "
f"(should go to {add_redirect_url})")
def test_orga_message_submission(self):
"""
......@@ -201,7 +201,8 @@ class ModelViewTests(BasicViewTests, TestCase):
# Test indication outside of indication window -> HTTP 403, counter not increased
response = self.client.post(interest_api_url)
self.assertEqual(response.status_code, 403,
"API end point still reachable even though interest indication window ended ({interest_api_url})")
"API end point still reachable even though interest indication window ended "
"({interest_api_url})")
self.assertEqual(AK.objects.get(pk=1).interest_counter, ak_interest_counter + 1,
"Counter was increased even though interest indication window ended")
......@@ -249,7 +250,8 @@ class ModelViewTests(BasicViewTests, TestCase):
event2 = Event.objects.create(name='Event without requirements',
slug='no_req',
start=datetime.now(), end=datetime.now(),
start=datetime.now().astimezone(event.timezone),
end=datetime.now().astimezone(event.timezone),
active=True)
form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2})
self.assertNotIn('requirements', form2.fields,
......@@ -266,7 +268,8 @@ class ModelViewTests(BasicViewTests, TestCase):
event2 = Event.objects.create(name='Event without types',
slug='no_types',
start=datetime.now(), end=datetime.now(),
start=datetime.now().astimezone(event.timezone),
end=datetime.now().astimezone(event.timezone),
active=True)
form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2})
self.assertNotIn('types', form2.fields,
......
from datetime import timedelta
from math import floor
from abc import ABC, abstractmethod
from datetime import datetime, timedelta
from math import floor
from django.apps import apps
from django.conf import settings
......@@ -8,19 +8,17 @@ from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.utils.datetime_safe import datetime
from django.utils.translation import gettext_lazy as _
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.views.generic import CreateView, DeleteView, DetailView, ListView, TemplateView, UpdateView
from AKModel.availability.models import Availability
from AKModel.metaviews import status_manager
from AKModel.metaviews.status import TemplateStatusWidget
from AKModel.models import AK, AKCategory, AKOwner, AKSlot, AKTrack, AKOrgaMessage
from AKModel.metaviews.admin import EventSlugMixin, FilterByEventSlugMixin
from AKModel.metaviews.status import TemplateStatusWidget
from AKModel.models import AK, AKCategory, AKOrgaMessage, AKOwner, AKSlot, AKTrack
from AKSubmission.api import ak_interest_indication_active
from AKSubmission.forms import AKWishForm, AKOwnerForm, AKSubmissionForm, AKDurationForm, AKOrgaMessageForm, \
AKForm
from AKSubmission.forms import AKDurationForm, AKForm, AKOrgaMessageForm, AKOwnerForm, AKSubmissionForm, AKWishForm
class SubmissionErrorNotConfiguredView(EventSlugMixin, TemplateView):
......@@ -183,10 +181,13 @@ class AKListByCategoryView(AKOverviewView):
This view inherits from :class:`AKOverviewView`, but produces only one list instead of a tabbed one.
"""
def dispatch(self, request, *args, **kwargs):
# Override dispatching
# Needed to handle the checking whether the category exists
self.category = get_object_or_404(AKCategory, pk=kwargs['category_pk']) # pylint: disable=attribute-defined-outside-init,line-too-long
# noinspection PyAttributeOutsideInit
# pylint: disable=attribute-defined-outside-init
self.category = get_object_or_404(AKCategory, pk=kwargs['category_pk'])
return super().dispatch(request, *args, **kwargs)
def get_active_category_name(self, context):
......@@ -209,6 +210,7 @@ class AKListByTrackView(AKOverviewView):
This view inherits from :class:`AKOverviewView` and there will be one list per category
-- but only AKs of a certain given track will be included in them.
"""
def dispatch(self, request, *args, **kwargs):
# Override dispatching
# Needed to handle the checking whether the track exists
......@@ -292,6 +294,7 @@ class EventInactiveRedirectMixin:
Will add a message explaining why the action was not performed to the user
and then redirect to start page of the submission component
"""
def get_error_message(self):
"""
Error message to display after redirect (can be adjusted by this method)
......@@ -351,6 +354,7 @@ class AKSubmissionView(AKAndAKWishSubmissionView):
Extends :class:`AKAndAKWishSubmissionView`
"""
def get_initial(self):
# Load initial values for the form
# Used to directly add the first owner and the event this AK will belong to
......@@ -500,7 +504,6 @@ class AKOwnerDispatchView(ABC, EventSlugMixin, View):
:rtype: HttpResponseRedirect
"""
def post(self, request, *args, **kwargs):
# This view is solely meant to handle POST requests
# Perform dispatching based on the submitted owner_id
......
......@@ -10,7 +10,7 @@ setup.
### System Requirements
* Python 3.10+ incl. development tools
* Python 3.11+ incl. development tools
* Virtualenv
* pdflatex & beamer
class (`texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-fonts-extra texlive-luatex`)
......@@ -37,7 +37,7 @@ Python requirements are listed in ``requirements.txt``. They can be installed wi
### Manual Setup
1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.10``
1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.11``
1. activate virtualenv ``source venv/bin/activate``
1. install python requirements ``pip install -r requirements.txt``
1. setup necessary database tables etc. ``python manage.py migrate``
......@@ -68,7 +68,7 @@ is not stored in any repository or similar, and disable DEBUG mode (``settings.p
1. create a folder, e.g. ``mkdir /srv/AKPlanning/``
1. change to the new directory ``cd /srv/AKPlanning/``
1. clone this repository ``git clone URL .``
1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.10``
1. setup a virtual environment using the proper python version ``virtualenv venv -p python3.11``
1. activate virtualenv ``source venv/bin/activate``
1. update tools ``pip install --upgrade setuptools pip wheel``
1. install python requirements ``pip install -r requirements.txt``
......
......@@ -8,14 +8,20 @@ if [ -z ${VIRTUAL_ENV+x} ]; then
fi
# enable really all warnings, some of them are silenced by default
if [[ "$@" == *"--all"* ]]; then
for arg in "$@"; do
if [[ "$arg" == "--all" ]]; then
export PYTHONWARNINGS=all
fi
done
# in case of checking production setup
if [[ "$@" == *"--prod"* ]]; then
for arg in "$@"; do
if [[ "$arg" == "--prod" ]]; then
export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production
./manage.py check --deploy
fi
done
# check the setup
./manage.py check
./manage.py makemigrations --dry-run --check
......@@ -10,7 +10,7 @@ rm -rf venv/
# Setup Python Environment
# Requires: Virtualenv, appropriate Python installation
virtualenv venv -p python3.10
virtualenv venv -p python3.11
source venv/bin/activate
pip install --upgrade setuptools pip wheel
pip install -r requirements.txt
......
#!/usr/bin/env bash
# Test the AKPlanning setup
# execute as Utils/test.sh
# activate virtualenv when necessary
if [ -z ${VIRTUAL_ENV+x} ]; then
source venv/bin/activate
fi
# enable really all warnings, some of them are silenced by default
for arg in "$@"; do
if [[ "$arg" == "--all" ]]; then
export PYTHONWARNINGS=all
fi
done
# in case of checking production setup
for arg in "$@"; do
if [[ "$arg" == "--prod" ]]; then
export DJANGO_SETTINGS_MODULE=AKPlanning.settings_production
./manage.py test --deploy
fi
done
# run tests
./manage.py test
......@@ -19,7 +19,7 @@ fi
mkdir -p backups/
python manage.py dumpdata --indent=2 > "backups/$(date +"%Y%m%d%H%M")_datadump.json" --traceback
git pull
# git pull
pip install --upgrade setuptools pip wheel
pip install --upgrade -r requirements.txt
......
Django==4.2.13
django-bootstrap5==24.2
fontawesomefree==6.5.1 # Makes static files (css, fonts) available locally
Django==5.1.6
django-betterforms==2.0.0
django-bootstrap-datepicker-plus==5.0.5
django-bootstrap5==25.1
django-compressor==4.5.1
django-debug-toolbar==5.0.1
django-fontawesome-6==1.0.0.0 # Provides an icon field for models and forms as well as handy shortcuts to render icons
django-split-settings==1.3.1
django-timezone-field==6.1.0
djangorestframework==3.15.1
django-simple-history==3.5.0
django-libsass==0.9
django-registration-redux==2.13
django-debug-toolbar==4.3.0
django-bootstrap-datepicker-plus==5.0.5
django-simple-history==3.8.0
django-split-settings==1.3.2
django-tex==1.1.10
django-csp==3.8
django-compressor==4.4
django-libsass==0.9
django-betterforms==2.0.0
mysqlclient==2.2.0 # for production deployment
tzdata==2024.1
django-timezone-field==7.1
django_csp==3.8
djangorestframework==3.15.2
fontawesomefree==6.6.0 # Makes static files (css, fonts) available locally
# mysqlclient==2.2.7 # for production deployment
tzdata==2025.1
# Tests
beautifulsoup4==4.13.3
lxml==5.3.1
# Documentation
sphinxcontrib-django==2.5
Sphinx==8.2.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-apidoc==0.5.0
sphinxcontrib-django==2.5.0
recommonmark==0.7.1
django-docs==0.3.3
sphinx-rtd-theme==2.0.0
sphinx==7.3.7
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment