Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • AlekSIS/official/AlekSIS-App-Chronos
  • sunweaver/AlekSIS-App-Chronos
  • sggua/AlekSIS-App-Chronos
  • tincmeKdenka/AlekSIS-App-Chronos
  • ligquamacti/AlekSIS-App-Chronos
  • 1crotatilhe/AlekSIS-App-Chronos
  • 1compluningi/AlekSIS-App-Chronos
  • starwardcarfi/AlekSIS-App-Chronos
  • ceohecholeg/AlekSIS-App-Chronos
  • 7quecontranchi/AlekSIS-App-Chronos
  • 8evsubcesza/AlekSIS-App-Chronos
  • unscinKibdzu/AlekSIS-App-Chronos
  • delucPchondmu/AlekSIS-App-Chronos
13 results
Show changes
Commits on Source (20)
Showing
with 423 additions and 378 deletions
......@@ -4,11 +4,11 @@
"dependencies": {
"@intlify/eslint-plugin-vue-i18n": "^2.0.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-vue": "^9.7.0",
"prettier": "^2.8.1",
"stylelint": "^14.14.0",
"prettier": "^3.0.0",
"stylelint": "^15.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^29.0.0"
"stylelint-config-standard": "^34.0.0"
}
}
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*.py[cod]
__pycache__/
# Distribution / packaging
*.egg
*.egg-info/
.Python
.eggs/
.installed.cfg
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
pip-log.txt
# Translations
*.mo
......@@ -39,22 +39,56 @@ local_settings.py
# Environments
.env
.venv
ENV/
env/
venv/
ENV/
# Editors
*~
DEADJOE
\#*#
# IntelliJ
.idea
.idea/
# VSCode
.vscode/
.history/
*.code-workspace
# Database
db.sqlite3
# Sphinx
docs/_build/
# Test
.tox/
# TeX
*.aux
# Generated files
/cache
/node_modules
.dev-js/node_modules
/static/
/whoosh_index/
.vite
.dev-js/.yarn
.dev-js/.pnp.cjs
.dev-js/.pnp.loader.mjs
# Lock files
poetry.lock
package-lock.json
yarn.lock
.dev-js/yarn.lock
# Tests
.coverage
.mypy_cache/
.tox/
htmlcov/
# Data
maintenance_mode_state.txt
media/
......@@ -89,3 +89,6 @@ yarn.lock
# Do not check/reformat generated files
aleksis/core/util/licenses.json
.vite/
.pnp.cjs
.pnp.loader.mjs
from typing import Sequence
from collections.abc import Sequence
from django.db.models import Count, Q
from django.forms import RadioSelect
......
from django.utils.translation import gettext as _
from material import Fieldset
from aleksis.core.forms import AnnouncementForm, EditGroupForm
AnnouncementForm.add_node_to_layout(Fieldset(_("Options for timetables"), "show_in_timetables"))
EditGroupForm.add_node_to_layout(Fieldset(_("Optional data for timetables"), "subject_id"))
from collections.abc import Iterable
from datetime import date, datetime, timedelta
from enum import Enum
from typing import Dict, Iterable, List, Optional, Union
from typing import TYPE_CHECKING, Optional, Union
from django.contrib.sites.managers import CurrentSiteManager as _CurrentSiteManager
from django.db import models
from django.db.models import ExpressionWrapper, F, Func, Q, QuerySet, Value
from django.db.models.fields import DateField
......@@ -11,10 +11,17 @@ from django.db.models.functions import Concat
from calendarweek import CalendarWeek
from aleksis.apps.chronos.util.date import week_weekday_from_date, week_weekday_to_date
from aleksis.core.managers import DateRangeQuerySetMixin, SchoolTermRelatedQuerySet
from aleksis.core.managers import (
AlekSISBaseManagerWithoutMigrations,
DateRangeQuerySetMixin,
SchoolTermRelatedQuerySet,
)
from aleksis.core.models import Group, Person
from aleksis.core.util.core_helpers import get_site_preferences
if TYPE_CHECKING:
from .models import Holiday, LessonPeriod, Room, ValidityRange
class ValidityRangeQuerySet(QuerySet, DateRangeQuerySetMixin):
"""Custom query set for validity ranges."""
......@@ -65,10 +72,6 @@ class ValidityRangeRelatedQuerySet(QuerySet):
return None
class CurrentSiteManager(_CurrentSiteManager):
use_in_migrations = False
class TimetableType(Enum):
"""Enum for different types of timetables."""
......@@ -81,7 +84,7 @@ class TimetableType(Enum):
return cls.__members__.get(s.upper())
class LessonPeriodManager(CurrentSiteManager):
class LessonPeriodManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to lesson periods."""
def get_queryset(self):
......@@ -106,7 +109,7 @@ class LessonPeriodManager(CurrentSiteManager):
)
class LessonSubstitutionManager(CurrentSiteManager):
class LessonSubstitutionManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to lesson substitutions."""
def get_queryset(self):
......@@ -132,7 +135,7 @@ class LessonSubstitutionManager(CurrentSiteManager):
)
class SupervisionManager(CurrentSiteManager):
class SupervisionManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to supervisions."""
def get_queryset(self):
......@@ -150,7 +153,7 @@ class SupervisionManager(CurrentSiteManager):
)
class SupervisionSubstitutionManager(CurrentSiteManager):
class SupervisionSubstitutionManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to supervision substitutions."""
def get_queryset(self):
......@@ -170,7 +173,7 @@ class SupervisionSubstitutionManager(CurrentSiteManager):
)
class EventManager(CurrentSiteManager):
class EventManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to events."""
def get_queryset(self):
......@@ -189,7 +192,7 @@ class EventManager(CurrentSiteManager):
)
class ExtraLessonManager(CurrentSiteManager):
class ExtraLessonManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to extra lessons."""
def get_queryset(self):
......@@ -207,7 +210,7 @@ class ExtraLessonManager(CurrentSiteManager):
)
class BreakManager(CurrentSiteManager):
class BreakManager(AlekSISBaseManagerWithoutMigrations):
"""Manager adding specific methods to breaks."""
def get_queryset(self):
......@@ -402,7 +405,7 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
return lesson_periods
def group_by_validity(self) -> Dict["ValidityRange", List["LessonPeriod"]]:
def group_by_validity(self) -> dict["ValidityRange", list["LessonPeriod"]]:
"""Group lesson periods by validity range as dictionary."""
lesson_periods_by_validity = {}
for lesson_period in self:
......@@ -635,7 +638,7 @@ class AbsenceQuerySet(DateRangeQuerySetMixin, SchoolTermRelatedQuerySet):
class HolidayQuerySet(QuerySet, DateRangeQuerySetMixin):
"""QuerySet with custom query methods for holidays."""
def get_all_days(self) -> List[date]:
def get_all_days(self) -> list[date]:
"""Get all days included in the selected holidays."""
holiday_days = []
for holiday in self:
......
# Generated by Django 3.0.5 on 2020-05-04 14:16
import django.contrib.postgres.fields.jsonb
import django.contrib.sites.managers
import django.db.models.deletion
from django.db import migrations, models
import calendarweek.calendarweek
import colorfield.fields
import aleksis.core.managers
import aleksis.apps.chronos.managers
......@@ -17,7 +18,6 @@ class Migration(migrations.Migration):
dependencies = [
("core", "0001_initial"),
("sites", "0002_alter_domain_unique"),
]
operations = [
......@@ -49,7 +49,7 @@ class Migration(migrations.Migration):
),
"managed": False,
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="Break",
......@@ -80,7 +80,7 @@ class Migration(migrations.Migration):
"verbose_name_plural": "Breaks",
"ordering": ["after_period"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="Lesson",
......@@ -119,7 +119,7 @@ class Migration(migrations.Migration):
aleksis.apps.chronos.managers.GroupPropertiesMixin,
aleksis.apps.chronos.managers.TeacherPropertiesMixin,
),
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="LessonPeriod",
......@@ -236,22 +236,13 @@ class Migration(migrations.Migration):
),
("time_start", models.TimeField(verbose_name="Start time")),
("time_end", models.TimeField(verbose_name="End time")),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Time period",
"verbose_name_plural": "Time periods",
"ordering": ["weekday", "period"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="SupervisionSubstitution",
......@@ -272,15 +263,6 @@ class Migration(migrations.Migration):
),
),
("date", models.DateField(verbose_name="Date")),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
(
"supervision",
models.ForeignKey(
......@@ -338,22 +320,13 @@ class Migration(migrations.Migration):
"colour_bg",
colorfield.fields.ColorField(default="#FFFFFF", max_length=18),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Supervision area",
"verbose_name_plural": "Supervision areas",
"ordering": ["name"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.AddField(
model_name="supervision",
......@@ -375,16 +348,6 @@ class Migration(migrations.Migration):
verbose_name="Break",
),
),
migrations.AddField(
model_name="supervision",
name="site",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
migrations.AddField(
model_name="supervision",
name="teacher",
......@@ -443,22 +406,13 @@ class Migration(migrations.Migration):
verbose_name="Background colour",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Subject",
"verbose_name_plural": "Subjects",
"ordering": ["name", "short_name"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="Room",
......@@ -485,22 +439,13 @@ class Migration(migrations.Migration):
),
),
("name", models.CharField(max_length=255, verbose_name="Long name")),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Room",
"verbose_name_plural": "Rooms",
"ordering": ["name", "short_name"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="LessonSubstitution",
......@@ -560,15 +505,6 @@ class Migration(migrations.Migration):
verbose_name="Room",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
(
"subject",
models.ForeignKey(
......@@ -622,16 +558,6 @@ class Migration(migrations.Migration):
verbose_name="Room",
),
),
migrations.AddField(
model_name="lessonperiod",
name="site",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
migrations.AddField(
model_name="lesson",
name="periods",
......@@ -642,16 +568,6 @@ class Migration(migrations.Migration):
verbose_name="Periods",
),
),
migrations.AddField(
model_name="lesson",
name="site",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
migrations.AddField(
model_name="lesson",
name="subject",
......@@ -696,15 +612,6 @@ class Migration(migrations.Migration):
"comments",
models.TextField(blank=True, null=True, verbose_name="Comments"),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Holiday",
......@@ -770,15 +677,6 @@ class Migration(migrations.Migration):
verbose_name="Room",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
(
"subject",
models.ForeignKey(
......@@ -856,22 +754,13 @@ class Migration(migrations.Migration):
verbose_name="End period",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Exam",
"verbose_name_plural": "Exams",
"ordering": ["date"],
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="Event",
......@@ -929,15 +818,6 @@ class Migration(migrations.Migration):
related_name="events", to="chronos.Room", verbose_name="Rooms"
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
(
"teachers",
models.ManyToManyField(
......@@ -980,16 +860,6 @@ class Migration(migrations.Migration):
verbose_name="Time period before break ends",
),
),
migrations.AddField(
model_name="break",
name="site",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
migrations.CreateModel(
name="AbsenceReason",
fields=[
......@@ -1018,21 +888,12 @@ class Migration(migrations.Migration):
blank=True, max_length=255, null=True, verbose_name="Name"
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
],
options={
"verbose_name": "Absence reason",
"verbose_name_plural": "Absence reasons",
},
managers=[("objects", django.contrib.sites.managers.CurrentSiteManager()),],
managers=[("objects", aleksis.core.managers.AlekSISBaseManager()),],
),
migrations.CreateModel(
name="Absence",
......@@ -1111,15 +972,6 @@ class Migration(migrations.Migration):
verbose_name="Room",
),
),
(
"site",
models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
(
"teacher",
models.ForeignKey(
......
......@@ -43,7 +43,6 @@ def migrate_lesson(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("core", "0002_school_term"),
("sites", "0002_alter_domain_unique"),
("chronos", "0001_initial"),
]
......@@ -186,16 +185,6 @@ class Migration(migrations.Migration):
verbose_name="School term",
),
),
migrations.AddField(
model_name="validityrange",
name="site",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.CASCADE,
to="sites.Site",
),
),
migrations.AddField(
model_name="lesson",
name="validity",
......
......@@ -48,7 +48,7 @@ class Migration(migrations.Migration):
),
migrations.AddConstraint(
model_name='absencereason',
constraint=models.UniqueConstraint(fields=('site_id', 'short_name'), name='unique_short_name_per_site_absence_reason'),
constraint=models.UniqueConstraint(fields=('short_name',), name='unique_short_name_per_site_absence_reason'),
),
migrations.AddConstraint(
model_name='break',
......@@ -60,19 +60,19 @@ class Migration(migrations.Migration):
),
migrations.AddConstraint(
model_name='room',
constraint=models.UniqueConstraint(fields=('site_id', 'short_name'), name='unique_short_name_per_site_room'),
constraint=models.UniqueConstraint(fields=('short_name',), name='unique_short_name_per_site_room'),
),
migrations.AddConstraint(
model_name='subject',
constraint=models.UniqueConstraint(fields=('site_id', 'short_name'), name='unique_short_name_per_site_subject'),
constraint=models.UniqueConstraint(fields=('short_name',), name='unique_short_name_per_site_subject'),
),
migrations.AddConstraint(
model_name='subject',
constraint=models.UniqueConstraint(fields=('site_id', 'name'), name='unique_name_per_site'),
constraint=models.UniqueConstraint(fields=('name',), name='unique_name_per_site'),
),
migrations.AddConstraint(
model_name='supervisionarea',
constraint=models.UniqueConstraint(fields=('site_id', 'short_name'), name='unique_short_name_per_site_supervision_area'),
constraint=models.UniqueConstraint(fields=('short_name',), name='unique_short_name_per_site_supervision_area'),
),
migrations.AddConstraint(
model_name='timeperiod',
......
......@@ -29,7 +29,6 @@ class Migration(migrations.Migration):
},
bases=('resint.livedocument',),
managers=[
('objects', aleksis.core.managers.PolymorphicCurrentSiteManager()),
],
),
]
# Generated by Django 4.2.3 on 2023-07-27 13:35
import aleksis.core.managers
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('chronos', '0013_move_room_to_core'),
]
operations = [
migrations.AddField(
model_name='absence',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='absencereason',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='break',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='event',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='exam',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='extralesson',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='holiday',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='lesson',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='lessonperiod',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='lessonsubstitution',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='subject',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='supervision',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='supervisionarea',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='supervisionsubstitution',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='timeperiod',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
migrations.AddField(
model_name='validityrange',
name='managed_by_app_label',
field=models.CharField(blank=True, editable=False, max_length=255, verbose_name='App label of app responsible for managing this instance'),
),
]
# Generated by Django 4.2.9 on 2024-01-09 15:08
import colorfield.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('chronos', '0014_add_managed_by_app_label'),
]
operations = [
migrations.AlterModelManagers(
name='absencereason',
managers=[
],
),
migrations.AlterModelManagers(
name='subject',
managers=[
],
),
migrations.AlterModelManagers(
name='supervisionarea',
managers=[
],
),
migrations.RemoveConstraint(
model_name='absencereason',
name='unique_short_name_per_site_absence_reason',
),
migrations.RemoveConstraint(
model_name='break',
name='unique_short_name_per_site_break',
),
migrations.RemoveConstraint(
model_name='subject',
name='unique_short_name_per_site_subject',
),
migrations.RemoveConstraint(
model_name='supervisionarea',
name='unique_short_name_per_site_supervision_area',
),
] + [
migrations.RunSQL(
f"ALTER TABLE chronos_{model_name} drop column if exists site_id;"
) for model_name in
[
"absence",
"absencereason",
"automaticplan",
"break",
"event",
"exam",
"extralesson",
"holiday",
"lesson",
"lessonperiod",
"lessonsubstitution",
"subject",
"supervision",
"supervisionarea",
"supervisionsubstitution",
"timeperiod",
"validityrange"
]
] + [
migrations.AlterField(
model_name='absence',
name='comment',
field=models.TextField(blank=True, default='', verbose_name='Comment'),
preserve_default=False,
),
migrations.AlterField(
model_name='absencereason',
name='name',
field=models.CharField(blank=True, default='', max_length=255, verbose_name='Name'),
preserve_default=False,
),
migrations.AlterField(
model_name='absencereason',
name='short_name',
field=models.CharField(max_length=255, unique=True, verbose_name='Short name'),
),
migrations.AlterField(
model_name='event',
name='title',
field=models.CharField(blank=True, default='', max_length=255, verbose_name='Title'),
preserve_default=False,
),
migrations.AlterField(
model_name='extralesson',
name='comment',
field=models.CharField(blank=True, default='', max_length=255, verbose_name='Comment'),
preserve_default=False,
),
migrations.AlterField(
model_name='holiday',
name='comments',
field=models.TextField(blank=True, default='', verbose_name='Comments'),
preserve_default=False,
),
migrations.AlterField(
model_name='lessonsubstitution',
name='comment',
field=models.TextField(blank=True, default='', verbose_name='Comment'),
preserve_default=False,
),
migrations.AlterField(
model_name='subject',
name='colour_bg',
field=colorfield.fields.ColorField(blank=True, default='', image_field=None, max_length=25, samples=None, verbose_name='Background colour'),
),
migrations.AlterField(
model_name='subject',
name='colour_fg',
field=colorfield.fields.ColorField(blank=True, default='', image_field=None, max_length=25, samples=None, verbose_name='Foreground colour'),
),
migrations.AlterField(
model_name='subject',
name='short_name',
field=models.CharField(max_length=255, unique=True, verbose_name='Short name'),
),
migrations.AlterField(
model_name='supervisionarea',
name='colour_bg',
field=colorfield.fields.ColorField(default='#FFFFFF', image_field=None, max_length=25, samples=None),
),
migrations.AlterField(
model_name='supervisionarea',
name='colour_fg',
field=colorfield.fields.ColorField(default='#000000', image_field=None, max_length=25, samples=None),
),
migrations.AlterField(
model_name='supervisionarea',
name='short_name',
field=models.CharField(max_length=255, unique=True, verbose_name='Short name'),
),
migrations.AlterField(
model_name='timeperiod',
name='weekday',
field=models.PositiveSmallIntegerField(choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], verbose_name='Week day'),
),
migrations.AddConstraint(
model_name='break',
constraint=models.UniqueConstraint(fields=('validity', 'short_name'), name='unique_short_name_per_validity_break'),
),
]
......@@ -7,7 +7,7 @@ from django.utils.translation import gettext as _
from calendarweek import CalendarWeek
from aleksis.apps.chronos.util.date import week_weekday_to_date
from aleksis.core.managers import CurrentSiteManagerWithoutMigrations
from aleksis.core.managers import AlekSISBaseManagerWithoutMigrations
from aleksis.core.mixins import ExtensibleModel
from .managers import ValidityRangeRelatedQuerySet
......@@ -16,7 +16,7 @@ from .managers import ValidityRangeRelatedQuerySet
class ValidityRangeRelatedExtensibleModel(ExtensibleModel):
"""Add relation to validity range."""
objects = CurrentSiteManagerWithoutMigrations.from_queryset(ValidityRangeRelatedQuerySet)()
objects = AlekSISBaseManagerWithoutMigrations.from_queryset(ValidityRangeRelatedQuerySet)()
validity = models.ForeignKey(
"chronos.ValidityRange",
......
......@@ -4,14 +4,13 @@ from typing import Optional, Union
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _
from jsonstore import BooleanField
from reversion.models import Revision
from aleksis.core.models import Announcement, Group, Person
from aleksis.core.util.core_helpers import get_site_preferences
from .managers import TimetableType
from .models import Lesson, LessonPeriod, Subject
from .models import Lesson, LessonPeriod
from .util.change_tracker import timetable_data_changed
from .util.notifications import send_notifications_for_object
......@@ -134,15 +133,10 @@ def previous_lesson(self, lesson_period: "LessonPeriod", day: date) -> Union["Le
def for_timetables(cls):
"""Return all announcements that should be shown in timetable views."""
return cls.objects.filter(show_in_timetables=True)
return cls.objects.all()
Announcement.class_method(for_timetables)
Announcement.field(
show_in_timetables=BooleanField(verbose_name=_("Show announcement in timetable views?"))
)
Group.foreign_key("subject", Subject, related_name="groups")
# Dynamically add extra permissions to Group and Person models in core
# Note: requires migrate afterwards
......
This diff is collapsed.
from __future__ import annotations
from typing import Optional, Union
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
......@@ -12,8 +10,8 @@ from .models import LessonPeriod, Supervision
def _title_attr_from_lesson_or_supervision_state(
record: Optional[Union[LessonPeriod, Supervision]] = None,
table: Optional[Union[LessonsTable, SupervisionsTable]] = None,
record: LessonPeriod | Supervision | None = None,
table: LessonsTable | SupervisionsTable | None = None,
) -> str:
"""Return HTML title depending on lesson or supervision state."""
if record.get_substitution():
......@@ -26,7 +24,7 @@ def _title_attr_from_lesson_or_supervision_state(
class SubstitutionColumn(tables.Column):
def render(self, value, record: Optional[Union[LessonPeriod, Supervision]] = None):
def render(self, value, record: LessonPeriod | Supervision | None = None):
if record.get_substitution():
return (
format_html(
......@@ -48,7 +46,7 @@ class SubstitutionColumn(tables.Column):
class LessonStatusColumn(tables.Column):
def render(self, record: Optional[Union[LessonPeriod, Supervision]] = None):
def render(self, record: LessonPeriod | Supervision | None = None):
if record.get_substitution():
return (
format_html(
......
......@@ -32,26 +32,26 @@ class NotificationTests(TransactionTestCase):
)
self.teacher_a = Person.objects.create(
first_name="Teacher", last_name="A", short_name="A", email="test@example.org"
first_name="Teacher", last_name="A", short_name="A", email="test1@example.org"
)
self.teacher_b = Person.objects.create(
first_name="Teacher", last_name="B", short_name="B", email="test@example.org"
first_name="Teacher", last_name="B", short_name="B", email="test2@example.org"
)
self.student_a = Person.objects.create(
first_name="Student", last_name="A", email="test@example.org"
first_name="Student", last_name="A", email="test3@example.org"
)
self.student_b = Person.objects.create(
first_name="Student", last_name="B", email="test@example.org"
first_name="Student", last_name="B", email="test4@example.org"
)
self.student_c = Person.objects.create(
first_name="Student", last_name="C", email="test@example.org"
first_name="Student", last_name="C", email="test5@example.org"
)
self.student_d = Person.objects.create(
first_name="Student", last_name="D", email="test@example.org"
first_name="Student", last_name="D", email="test6@example.org"
)
self.student_e = Person.objects.create(
first_name="Student", last_name="E", email="test@example.org"
first_name="Student", last_name="E", email="test7@example.org"
)
self.group_a = Group.objects.create(
......
from collections import OrderedDict
from datetime import date
from typing import List, Tuple, Union
from typing import Union
from django.apps import apps
......@@ -113,10 +113,7 @@ def build_timetable(
# Get events
events = Event.objects
if is_week:
events = events.in_week(date_ref)
else:
events = events.on_day(date_ref)
events = events.in_week(date_ref) if is_week else events.on_day(date_ref)
events = events.only(
"id",
......@@ -161,19 +158,13 @@ def build_timetable(
# If daily timetable for person, skip other weekdays
continue
if weekday == weekday_from:
# If start day, use start period
period_from = period_from_first_weekday
else:
# If not start day, use min period
period_from = TimePeriod.period_min
# If start day, use start period else use min period
period_from = (
period_from_first_weekday if weekday == weekday_from else TimePeriod.period_min
)
if weekday == weekday_to:
# If end day, use end period
period_to = period_to_last_weekday
else:
# If not end day, use max period
period_to = TimePeriod.period_max
# If end day, use end period else use max period
period_to = period_to_last_weekday if weekday == weekday_to else TimePeriod.periox_max
for period in range(period_from, period_to + 1):
# The following events are possibly replacing some lesson periods
......@@ -203,10 +194,7 @@ def build_timetable(
if type_ == TimetableType.TEACHER:
# Get matching supervisions
if not is_week:
week = CalendarWeek.from_date(date_ref)
else:
week = date_ref
week = CalendarWeek.from_date(date_ref) if not is_week else date_ref
supervisions = (
Supervision.objects.in_week(week)
.all()
......@@ -275,9 +263,8 @@ def build_timetable(
if (
period in supervisions_per_period_after
and weekday not in holidays_per_weekday
):
if weekday in supervisions_per_period_after[period]:
col = supervisions_per_period_after[period][weekday]
) and weekday in supervisions_per_period_after[period]:
col = supervisions_per_period_after[period][weekday]
cols.append(col)
row["cols"] = cols
......@@ -336,7 +323,7 @@ def build_timetable(
)
lesson_period.replaced_by_event = replaced_by_event
if not replaced_by_event or (
replaced_by_event and not type_ == TimetableType.GROUP
replaced_by_event and type_ != TimetableType.GROUP
):
col.append(lesson_period)
......@@ -393,7 +380,7 @@ def build_timetable(
return rows
def build_substitutions_list(wanted_day: date) -> List[dict]:
def build_substitutions_list(wanted_day: date) -> list[dict]:
rows = []
subs = LessonSubstitution.objects.on_day(wanted_day).order_by(
......@@ -466,10 +453,7 @@ def build_substitutions_list(wanted_day: date) -> List[dict]:
events = Event.objects.on_day(wanted_day).annotate_day(wanted_day)
for event in events:
if event.groups.all():
sort_a = event.group_names
else:
sort_a = f"Z.{event.teacher_names}"
sort_a = event.group_names if event.groups.all() else f"Z.{event.teacher_names}"
row = {
"type": "event",
......@@ -489,8 +473,8 @@ def build_substitutions_list(wanted_day: date) -> List[dict]:
def build_weekdays(
base: List[Tuple[int, str]], wanted_week: CalendarWeek, with_holidays: bool = True
) -> List[dict]:
base: list[tuple[int, str]], wanted_week: CalendarWeek, with_holidays: bool = True
) -> list[dict]:
if with_holidays:
holidays_per_weekday = Holiday.in_week(wanted_week)
......
from typing import Any, Optional, Type
from typing import Any, Optional
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
......@@ -41,7 +41,7 @@ class TimetableDataChangeTracker:
"""Helper class for tracking changes in timetable models by using signals."""
@classmethod
def get_models(cls) -> list[Type[Model]]:
def get_models(cls) -> list[type[Model]]:
"""Return all models that should be tracked."""
from aleksis.apps.chronos.models import (
Event,
......@@ -70,7 +70,7 @@ class TimetableDataChangeTracker:
if f.many_to_many
}
self.m2m_fields.update(m2m_fields)
for through_model, field in m2m_fields.items():
for through_model, _field in m2m_fields.items():
m2m_changed.connect(self._handle_m2m_changed, sender=through_model, weak=False)
transaction.on_commit(self.close)
......@@ -87,24 +87,24 @@ class TimetableDataChangeTracker:
else:
self.changes[key].changed_fields.update(change.changed_fields)
def _handle_save(self, sender: Type[Model], instance: Model, created: bool, **kwargs):
def _handle_save(self, sender: type[Model], instance: Model, created: bool, **kwargs):
"""Handle the save signal."""
change = TimetableChange(instance, created=created)
if not created:
change.changed_fields = instance.tracker.changed()
self._add_change(change)
def _handle_delete(self, sender: Type[Model], instance: Model, **kwargs):
def _handle_delete(self, sender: type[Model], instance: Model, **kwargs):
"""Handle the delete signal."""
change = TimetableChange(instance, deleted=True)
self._add_change(change)
def _handle_m2m_changed(
self,
sender: Type[Model],
sender: type[Model],
instance: Model,
action: str,
model: Type[Model],
model: type[Model],
pk_set: set,
**kwargs,
):
......@@ -127,7 +127,7 @@ class TimetableDataChangeTracker:
post_save.disconnect(self._handle_save, sender=model)
pre_delete.disconnect(self._handle_delete, sender=model)
for through_model, field in self.m2m_fields.items():
for through_model, _field in self.m2m_fields.items():
m2m_changed.disconnect(self._handle_m2m_changed, sender=through_model)
timetable_data_changed.send(sender=self, changes=self.changes)
......
......@@ -190,7 +190,7 @@ def get_substitutions_context_data(
if is_print:
next_day = wanted_day
for i in range(day_number):
for _i in range(day_number):
day_contexts[next_day] = {"day": next_day}
next_day = TimePeriod.get_next_relevant_day(next_day + timedelta(days=1))
else:
......@@ -200,9 +200,7 @@ def get_substitutions_context_data(
subs = build_substitutions_list(day)
day_contexts[day]["substitutions"] = subs
day_contexts[day]["announcements"] = (
Announcement.for_timetables().on_date(day).filter(show_in_timetables=True)
)
day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day)
if show_header_box:
subs = LessonSubstitution.objects.on_day(day).order_by(
......