diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 86e88a880f855e8a9a0f7557085dcf42e20124a4..dcdec3c5956617ba23b75766c5d49aea6e9aed7a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,4 +10,4 @@ include: - project: "AlekSIS/official/AlekSIS" file: /ci/build/dist.yml - project: "AlekSIS/official/AlekSIS" - file: /ci/deploy/pypi.yml + file: /ci/publish/pypi.yml diff --git a/aleksis/apps/alsijil/actions.py b/aleksis/apps/alsijil/actions.py index ee7cf0e7925cd9a11c6b7b98fbcc00b8a32667f9..04681948e8f5e9d0e607fc7edf77b4520c91d003 100644 --- a/aleksis/apps/alsijil/actions.py +++ b/aleksis/apps/alsijil/actions.py @@ -1,4 +1,13 @@ -from typing import Callable +from typing import Callable, Sequence + +from django.contrib import messages +from django.contrib.humanize.templatetags.humanize import apnumber +from django.http import HttpRequest +from django.template.loader import get_template +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ + +from aleksis.core.models import Notification from django.utils.translation import gettext_lazy as _ @@ -24,3 +33,46 @@ def delete_personal_note(modeladmin, request, queryset): delete_personal_note.short_description = _("Delete") + +def send_request_to_check_entry(modeladmin, request: HttpRequest, selected_items: Sequence[dict]): + """Send notifications to the teachers of the selected register objects. + + Action for use with ``RegisterObjectTable`` and ``RegisterObjectActionForm``. + """ + # Group class register entries by teachers so each teacher gets just one notification + grouped_by_teachers = {} + for entry in selected_items: + teachers = entry["register_object"].get_teachers().all() + for teacher in teachers: + grouped_by_teachers.setdefault(teacher, []) + grouped_by_teachers[teacher].append(entry) + + template = get_template("alsijil/notifications/check.html") + for teacher, items in grouped_by_teachers.items(): + msg = template.render({"items": items}) + + title = _("{} asks you to check some class register entries.").format( + request.user.person.addressing_name + ) + + n = Notification( + title=title, + description=msg, + sender=request.user.person.addressing_name, + recipient=teacher, + link=request.build_absolute_uri(reverse("overview_me")), + ) + n.save() + + count_teachers = len(grouped_by_teachers.keys()) + count_items = len(selected_items) + messages.success( + request, + _( + "We have successfully sent notifications to " + "{count_teachers} persons for {count_items} lessons." + ).format(count_teachers=apnumber(count_teachers), count_items=apnumber(count_items)), + ) + + +send_request_to_check_entry.short_description = _("Ask teacher to check data") diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py index 9da0b467715a98bd9017fdaa77a058b33d50728d..190a9a4442444f14ea752a28deaa382476f8693a 100644 --- a/aleksis/apps/alsijil/forms.py +++ b/aleksis/apps/alsijil/forms.py @@ -1,8 +1,11 @@ -from datetime import datetime +from datetime import datetime, timedelta +from typing import Optional, Sequence from django import forms from django.core.exceptions import ValidationError from django.db.models import Count, Q +from django.http import HttpRequest +from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget, Select2Widget @@ -10,13 +13,14 @@ from guardian.shortcuts import get_objects_for_user from material import Fieldset, Layout, Row from aleksis.apps.chronos.managers import TimetableType +from aleksis.apps.chronos.models import Subject, TimePeriod +from aleksis.core.forms import ActionForm, ListActionForm +from aleksis.core.models import Group, Person, SchoolTerm from aleksis.apps.chronos.models import TimePeriod -from aleksis.core.forms import ActionForm -from aleksis.core.models import Group, Person from aleksis.core.util.core_helpers import get_site_preferences from aleksis.core.util.predicates import check_global_permission -from .actions import delete_personal_note, mark_as_excuse_type_generator, mark_as_excused +from .actions import delete_personal_note, mark_as_excuse_type_generator, mark_as_excused, send_request_to_check_entry from .models import ( ExcuseType, ExtraMark, @@ -263,3 +267,66 @@ class GroupRoleAssignmentEditForm(forms.ModelForm): class Meta: model = GroupRoleAssignment fields = ["date_start", "date_end"] + + +class FilterRegisterObjectForm(forms.Form): + """Form for filtering register objects in ``RegisterObjectTable``.""" + + layout = Layout( + Row("school_term", "date_start", "date_end"), Row("has_documentation", "group", "subject") + ) + school_term = forms.ModelChoiceField(queryset=None, label=_("School term")) + has_documentation = forms.NullBooleanField(label=_("Has lesson documentation")) + group = forms.ModelChoiceField(queryset=None, label=_("Group"), required=False) + subject = forms.ModelChoiceField(queryset=None, label=_("Subject"), required=False) + date_start = forms.DateField(label=_("Start date")) + date_end = forms.DateField(label=_("End date")) + + @classmethod + def get_initial(cls): + date_end = timezone.now().date() + date_start = date_end - timedelta(days=30) + return { + "school_term": SchoolTerm.current, + "date_start": date_start, + "date_end": date_end, + } + + def __init__( + self, + request: HttpRequest, + *args, + for_person: bool = True, + groups: Optional[Sequence[Group]] = None, + **kwargs + ): + self.request = request + person = self.request.user.person + + kwargs["initial"] = self.get_initial() + super().__init__(*args, **kwargs) + + self.fields["school_term"].queryset = SchoolTerm.objects.all() + + if not groups and for_person: + groups = Group.objects.filter( + Q(lessons__teachers=person) + | Q(lessons__lesson_periods__substitutions__teachers=person) + | Q(events__teachers=person) + | Q(extra_lessons__teachers=person) + ) + elif not for_person: + groups = Group.objects.all() + self.fields["group"].queryset = groups + + # Filter subjects by selectable groups + subject_qs = Subject.objects.filter( + Q(lessons__groups__in=groups) | Q(extra_lessons__groups__in=groups) + ).distinct() + self.fields["subject"].queryset = subject_qs + + +class RegisterObjectActionForm(ListActionForm): + """Action form for managing register objects for use with ``RegisterObjectTable``.""" + + actions = [send_request_to_check_entry] diff --git a/aleksis/apps/alsijil/locale/ar/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/ar/LC_MESSAGES/django.po index 8da31faa2922186eec9eb72699931daaea647dd9..b5ad8e4119ee7698a5ea81258b708ecd4266a2fd 100644 --- a/aleksis/apps/alsijil/locale/ar/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/ar/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\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" @@ -18,106 +18,120 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" -#: data_checks.py:15 +#: actions.py:30 +msgid "{} asks you to check some class register entries." +msgstr "" + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "" + +#: actions.py:54 +msgid "Ask teacher to check data" +msgstr "" + +#: data_checks.py:12 msgid "Delete object" msgstr "" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "" -#: data_checks.py:36 +#: data_checks.py:33 msgid "Reset personal note to defaults" msgstr "" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "" -#: data_checks.py:49 +#: data_checks.py:46 msgid "The personal note is related to a cancelled lesson." msgstr "" -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "" -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "" -#: data_checks.py:112 +#: data_checks.py:100 msgid "The lesson documentation is on holidays." msgstr "" -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "" -#: data_checks.py:148 +#: data_checks.py:134 msgid "The personal note is on holidays." msgstr "" -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "" -#: data_checks.py:177 +#: data_checks.py:163 msgid "The personal note is marked as excused, but not as absent." msgstr "" -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "" -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "" -#: forms.py:135 +#: forms.py:140 msgid "Start period" msgstr "" -#: forms.py:136 +#: forms.py:141 msgid "End period" msgstr "" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -126,25 +140,40 @@ msgstr "" msgid "Excused" msgstr "" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 msgid "Excuse type" msgstr "" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "" + +#: forms.py:271 +msgid "Has lesson documentation" +msgstr "" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "" @@ -175,13 +204,18 @@ msgstr "" msgid "Assign group role" msgstr "" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 msgid "Excuse types" msgstr "" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -191,7 +225,7 @@ msgstr "" msgid "Extra marks" msgstr "" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "" @@ -252,6 +286,7 @@ msgstr "" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -284,7 +319,8 @@ msgstr "" msgid "Lesson documentation" msgstr "" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 msgid "Lesson documentations" msgstr "" @@ -345,72 +381,84 @@ msgstr "" msgid "Can list all personal note filters" msgstr "" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "" -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." msgstr "" -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "" -#: preferences.py:76 +#: preferences.py:85 msgid "Allow teachers to add data for lessons in holidays" msgstr "" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" msgstr "" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "" + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -525,13 +573,13 @@ msgid "%(period)s. period" msgstr "" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "" @@ -585,7 +633,7 @@ msgid "Late persons:" msgstr "" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -620,16 +668,16 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 msgid "Class register: person" msgstr "" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -637,36 +685,36 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 msgid "Unexcused absences" msgstr "" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "" -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -675,34 +723,34 @@ msgstr "" msgid "Absences" msgstr "" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "" @@ -728,13 +776,6 @@ msgstr "" msgid "Period" msgstr "" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -864,6 +905,10 @@ msgstr "" msgid "Stop" msgstr "" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -921,6 +966,22 @@ msgstr "" msgid "e" msgstr "" +#: templates/alsijil/partials/objects_table.html:4 +msgid "Lesson filter" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:9 +msgid "Update filters" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:22 +msgid "Lesson table" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "" @@ -1096,93 +1157,93 @@ msgid "Yes" msgstr "" #: templates/alsijil/print/full_register.html:373 -msgid "Lesson documentation for week" +msgid "Week" msgstr "" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "" -#: views.py:211 +#: views.py:225 msgid "The lesson documentation has been saved." msgstr "" -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "" -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "" -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "" -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "" -#: views.py:979 +#: views.py:1009 msgid "The personal note has been deleted." msgstr "" -#: views.py:1001 +#: views.py:1031 msgid "The extra mark has been created." msgstr "" -#: views.py:1013 +#: views.py:1043 msgid "The extra mark has been saved." msgstr "" -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "" -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "" -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "" -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "" -#: views.py:1089 +#: views.py:1119 msgid "The group role has been created." msgstr "" -#: views.py:1101 +#: views.py:1131 msgid "The group role has been saved." msgstr "" -#: views.py:1112 +#: views.py:1142 msgid "The group role has been deleted." msgstr "" -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 msgid "The group role has been assigned." msgstr "" -#: views.py:1196 +#: views.py:1226 msgid "The group role assignment has been saved." msgstr "" -#: views.py:1217 +#: views.py:1247 msgid "The group role assignment has been stopped." msgstr "" -#: views.py:1230 +#: views.py:1260 msgid "The group role assignment has been deleted." msgstr "" diff --git a/aleksis/apps/alsijil/locale/de_DE/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/de_DE/LC_MESSAGES/django.po index ebc7585d5e3169d011ccd0674c05b5f873c6237c..5247bd092a59ccad53f8068a2af2377227cf17c8 100644 --- a/aleksis/apps/alsijil/locale/de_DE/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/de_DE/LC_MESSAGES/django.po @@ -7,11 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" -"PO-Revision-Date: 2021-02-24 18:54+0000\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\n" +"PO-Revision-Date: 2021-03-18 14:35+0000\n" "Last-Translator: Jonathan Weth <teckids@jonathanweth.de>\n" -"Language-Team: German <https://translate.edugit.org/projects/aleksis/" -"aleksis-app-alsijil/de/>\n" +"Language-Team: German <https://translate.edugit.org/projects/aleksis/aleksis-app-alsijil/de/>\n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,106 +18,124 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.4\n" -#: data_checks.py:15 +#: actions.py:30 +#, fuzzy +#| msgid "{} wants you to check some class register entries." +msgid "{} asks you to check some class register entries." +msgstr "{} bittet Sie, einige Klassenbucheinträge zu überprüfen." + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "Wir haben erfolgreich Benachrichtigungen an {count_teachers} Personen für {count_items} Stunden gesendet." + +#: actions.py:54 +#, fuzzy +#| msgid "Notify teacher to check data" +msgid "Ask teacher to check data" +msgstr "Lehrkraft bitten, die Daten zu überprüfen" + +#: data_checks.py:12 msgid "Delete object" msgstr "Objekt löschen" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "Aktuelle Gruppen setzen" -#: data_checks.py:36 +#: data_checks.py:33 msgid "Reset personal note to defaults" msgstr "Persönliche Notiz zurücksetzen" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "Sicherstellen, dass es keine persönlichen Notizen in ausgefallenen Stunden gibt" -#: data_checks.py:49 +#: data_checks.py:46 msgid "The personal note is related to a cancelled lesson." msgstr "Die persönliche Notiz ist einer ausgefallenen Stunde zugeordnet." -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "Sicherstellen, dass \"groups_of_person\" für alle persönlichen Notizen gesetzt ist" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "Die persönliche Notiz hat keine Gruppe in \"groups_of_person\"." -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "Sicherstellen, dass es keine ausgefüllten Stundendokumentationen in den Ferien gibt" -#: data_checks.py:112 +#: data_checks.py:100 msgid "The lesson documentation is on holidays." msgstr "Die Stundendokumentation ist in den Ferien." -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "Sicherstellen, dass es keine ausgefüllten persönlichen Notizen in den Ferien gibt" -#: data_checks.py:148 +#: data_checks.py:134 msgid "The personal note is on holidays." msgstr "Die persönliche Notiz ist in den Ferien." -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "Sicherstellen, dass es keine entschuldigten persönlichen Notizen ohne eine Absenz gibt" -#: data_checks.py:177 +#: data_checks.py:163 msgid "The personal note is marked as excused, but not as absent." msgstr "Die persönliche Notiz ist als entschuldigt, aber nicht als abwesend markiert." -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "Hausaufgabe zur nächsten Stunde" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "Gruppe" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "Lehrkraft" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "Es kann nur entweder eine Gruppe oder eine Lehrkraft ausgewählt werden." -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "Startdatum" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "Enddatum" -#: forms.py:135 +#: forms.py:140 msgid "Start period" msgstr "Startstunde" -#: forms.py:136 +#: forms.py:141 msgid "End period" msgstr "Endstunde" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "Abwesend" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -127,25 +144,40 @@ msgstr "Abwesend" msgid "Excused" msgstr "Entschuldigt" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 msgid "Excuse type" msgstr "Entschuldigungsart" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "Bemerkungen" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "Person" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "Schuljahr" + +#: forms.py:271 +msgid "Has lesson documentation" +msgstr "Hat eine Stunden-Dokumentation" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "Fach" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "Klassenbuch" @@ -176,13 +208,18 @@ msgstr "Meine Schülerinnen und Schüler" msgid "Assign group role" msgstr "Gruppenrolle zuweisen" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "Alle Stunden" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 msgid "Excuse types" msgstr "Entschuldigungsarten" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -192,7 +229,7 @@ msgstr "Entschuldigungsarten" msgid "Extra marks" msgstr "Zusätzliche Markierungen" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "Gruppenrollen verwalten" @@ -253,6 +290,7 @@ msgstr "Persönliche Notiz" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -285,7 +323,8 @@ msgstr "Gruppennotiz" msgid "Lesson documentation" msgstr "Stunden-Dokumentation" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 msgid "Lesson documentations" msgstr "Stunden-Dokumentationen" @@ -346,76 +385,84 @@ msgstr "Kann eine Absenz registrieren" msgid "Can list all personal note filters" msgstr "Kann alle Filter für persönliche Notizen anzeigen" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "Blockiere das Hinzufügen von persönlichen Notizen für ausgefallene Stunden" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "Erlaube Nutzern, ihre eigenen persönlichen Notizen zu sehen" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "Erlaube Primärgruppeninhabern Absenzen in der Zukunft für Mitglieder ihrer Gruppen zu registrieren" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "Erlaube den Ursprungslehrkräften, ihre Stunden zu bearbeiten, obwohl sie vertreten worden sind" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "Daten von der ersten Stunde zu weiteren folgenden Stunden übernehmen" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "Dies wird die Daten nur übernehmen, wenn die Daten in den Folgestunden leer sind." -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." -msgstr "" -"Persönliche Notizen in alle folgenden Unterrichtsstunden am gleichen Tag " -"übernehmen." +msgstr "Persönliche Notizen in alle folgenden Unterrichtsstunden am gleichen Tag übernehmen." -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "Erlaube Lehrkräften, Unterrichtsstunden bereits am gleichen Tag und nicht erst zu Beginn der Stunde zu öffnen" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "Unterrichtsstunden in der Vergangenheit werden nicht durch diese Einstellung beeinflusst, sie können immer geöffnet werden." -#: preferences.py:76 +#: preferences.py:85 msgid "Allow teachers to add data for lessons in holidays" msgstr "Lehrkräften erlauben, Daten für Stunden in den Ferien hinzuzufügen" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" -msgstr "" -"Erlaube Gruppenbesitzern, Gruppenrollen für Eltern von Gruppenmitgliedern " -"zuzuweisen" +msgstr "Erlaube Gruppenbesitzern, Gruppenrollen für Eltern von Gruppenmitgliedern zuzuweisen" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "Zugewiesene Gruppenrollen in der Wochenansicht zeigen" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "Nur Wochenansicht von Gruppen" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "Zugewiesene Gruppenrollen in der Stundenansicht anzeigen" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "Einträge pro Seite in der Stundentabelle" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "Jede Seite muss mindestens einen Eintrag anzeigen." + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "Bearbeiten" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "Löschen" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -540,13 +587,13 @@ msgid "%(period)s. period" msgstr "%(period)s. Stunde" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "Veranstaltung" @@ -606,7 +653,7 @@ msgid "Late persons:" msgstr "Verspätete Personen:" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -650,16 +697,16 @@ msgstr "" " Diese Stunde ist in den Ferien und kann somit nicht bearbeitet werden.\n" " " -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 msgid "Class register: person" msgstr "Klassenbuch: Person" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "Zurück" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -670,36 +717,36 @@ msgstr "" " Klassenbuchübersicht für %(person)s\n" " " -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 msgid "Unexcused absences" msgstr "Unentschuldigte Fehlzeiten" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "Markiere als" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "Notiz löschen" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "Es gibt keine unentschuldigten Unterrichtsstunden." -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "Statistiken zu Fehlzeiten, Verspätungen und Bemerkungen" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -708,34 +755,34 @@ msgstr "Statistiken zu Fehlzeiten, Verspätungen und Bemerkungen" msgid "Absences" msgstr "Fehlstunden" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "davon" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "Unentschuldigt" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "Relevante persönliche Notizen" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "Woche %(week)s" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "Alle als markieren" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "%(late)s' verspätet" @@ -763,13 +810,6 @@ msgstr "" msgid "Period" msgstr "Stunde" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "Fach" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -902,8 +942,7 @@ msgid "" " " msgstr "" "\n" -" Sie können zusätzliche Aktionen für jede Gruppenrollenzuweisung " -"aufrufen, \n" +" Sie können zusätzliche Aktionen für jede Gruppenrollenzuweisung aufrufen, \n" "wenn Sie auf den Namen der entsprechenden Person klicken.\n" " " @@ -911,6 +950,10 @@ msgstr "" msgid "Stop" msgstr "Beenden" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "Bitte prüfen Sie, ob die folgenden Klassenbucheinträge komplett und richtig sind:" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -968,6 +1011,22 @@ msgstr "Vertretung" msgid "e" msgstr "e" +#: templates/alsijil/partials/objects_table.html:4 +msgid "Lesson filter" +msgstr "Stundenfilter" + +#: templates/alsijil/partials/objects_table.html:9 +msgid "Update filters" +msgstr "Filter aktualisieren" + +#: templates/alsijil/partials/objects_table.html:22 +msgid "Lesson table" +msgstr "Stundentabelle" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "Ausführen" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "Keine Schülerinnen und Schüler verfügbar." @@ -1157,99 +1216,109 @@ msgid "Yes" msgstr "Ja" #: templates/alsijil/print/full_register.html:373 -msgid "Lesson documentation for week" -msgstr "Unterrichtsdokumentation für Woche" +msgid "Week" +msgstr "Woche" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "Notizen" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" "Sie haben eine ungültige Stunde ausgewählt oder es\n" " läuft momentan keine Stunde." -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "Ihnen ist es nicht erlaubt, eine Eintragung für eine Unterrichtsstunde in der Zukunft vorzunehmen." -#: views.py:211 +#: views.py:225 msgid "The lesson documentation has been saved." msgstr "Die Stunden-Dokumentation wurde gespeichert." -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "Die persönlichen Notizen wurden gespeichert." -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "Die Fehlzeiten wurden als entschuldigt markiert." -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "Die Fehlzeit wurde als entschuldigt markiert." -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "Die Abwesenheit wurde gespeichert." -#: views.py:979 +#: views.py:1009 msgid "The personal note has been deleted." msgstr "Die persönliche Notiz wurde gelöscht." -#: views.py:1001 +#: views.py:1031 msgid "The extra mark has been created." msgstr "Die zusätzliche Markierung wurde erstellt." -#: views.py:1013 +#: views.py:1043 msgid "The extra mark has been saved." msgstr "Die zusätzliche Markierung wurde gespeichert." -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "Die zusätzliche Markierung wurde gelöscht." -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "Die Entschuldigungsart wurde erstellt." -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "Die Entschuldigunsart wurde gespeichert." -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "Die Entschuldigungsart wurde gelöscht." -#: views.py:1089 +#: views.py:1119 msgid "The group role has been created." msgstr "Die Gruppenrolle wurde erstellt." -#: views.py:1101 +#: views.py:1131 msgid "The group role has been saved." msgstr "Die Gruppenrolle wurde gespeichert." -#: views.py:1112 +#: views.py:1142 msgid "The group role has been deleted." msgstr "Die Gruppenrolle wurde gelöscht." -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 msgid "The group role has been assigned." msgstr "Die Gruppenrolle wurde zugewiesen." -#: views.py:1196 +#: views.py:1226 msgid "The group role assignment has been saved." msgstr "Die Gruppenrollenzuweisung wurde gespeichert." -#: views.py:1217 +#: views.py:1247 msgid "The group role assignment has been stopped." msgstr "Die Gruppenrollenzuweisung wurde beendet." -#: views.py:1230 +#: views.py:1260 msgid "The group role assignment has been deleted." msgstr "Die Gruppenrollenzuweisung wurde gelöscht." +#~ msgid "" +#~ "Week\n" +#~ " %(week)s" +#~ msgstr "" +#~ "Woche \n" +#~ "%(week)s" + +#~ msgid "Lesson documentation for week" +#~ msgstr "Unterrichtsdokumentation für Woche" + #~ msgid "" #~ "\n" #~ " Previous %(subject)s lesson\n" @@ -1292,9 +1361,6 @@ msgstr "Die Gruppenrollenzuweisung wurde gelöscht." #~ msgid "All personal note filters" #~ msgstr "Alle Filter für persönliche Notizen" -#~ msgid "Add filter" -#~ msgstr "Filter hinzufügen" - #~ msgid "Update personal note filter" #~ msgstr "Filter für persönliche Notizen aktualisieren" diff --git a/aleksis/apps/alsijil/locale/fr/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/fr/LC_MESSAGES/django.po index e935c9c08453dd3472ab7f8c06a150e022b5e31c..dc04646f1e122369278568740845251cb865c206 100644 --- a/aleksis/apps/alsijil/locale/fr/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\n" "PO-Revision-Date: 2020-07-26 14:08+0000\n" "Last-Translator: Marlene Grundey <grundema@katharineum.de>\n" "Language-Team: French <https://translate.edugit.org/projects/aleksis/aleksis-app-alsijil/fr/>\n" @@ -18,120 +18,134 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 4.0.1\n" -#: data_checks.py:15 +#: actions.py:30 +msgid "{} asks you to check some class register entries." +msgstr "" + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "" + +#: actions.py:54 +msgid "Ask teacher to check data" +msgstr "" + +#: data_checks.py:12 msgid "Delete object" msgstr "" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "" -#: data_checks.py:36 +#: data_checks.py:33 #, fuzzy #| msgid "Relevant personal notes" msgid "Reset personal note to defaults" msgstr "Notes personnelles importantes" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "" -#: data_checks.py:49 +#: data_checks.py:46 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The personal note is related to a cancelled lesson." msgstr "Documentation de cours pour la semaine calendrier" -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "" -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "" -#: data_checks.py:112 +#: data_checks.py:100 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The lesson documentation is on holidays." msgstr "Documentation de cours pour la semaine calendrier" -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "" -#: data_checks.py:148 +#: data_checks.py:134 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The personal note is on holidays." msgstr "Documentation de cours pour la semaine calendrier" -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "" -#: data_checks.py:177 +#: data_checks.py:163 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The personal note is marked as excused, but not as absent." msgstr "Documentation de cours pour la semaine calendrier" -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "Groupe" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "Profs" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "" -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "Date de début" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "Date de fin" -#: forms.py:135 +#: forms.py:140 #, fuzzy #| msgid "From period" msgid "Start period" msgstr "De la période" -#: forms.py:136 +#: forms.py:141 #, fuzzy #| msgid "From period" msgid "End period" msgstr "De la période" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "Absent(e)" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -140,7 +154,7 @@ msgstr "Absent(e)" msgid "Excused" msgstr "Excusé" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 #, fuzzy @@ -148,19 +162,36 @@ msgstr "Excusé" msgid "Excuse type" msgstr "Excusé" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "Remarque" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "Personne" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "" + +#: forms.py:271 +#, fuzzy +#| msgid "Lesson documentation" +msgid "Has lesson documentation" +msgstr "Documentation de cours" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "Sujet" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "Registre de la classe" @@ -197,7 +228,12 @@ msgstr "" msgid "Assign group role" msgstr "Personnes en groupe" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 #, fuzzy @@ -205,7 +241,7 @@ msgstr "Personnes en groupe" msgid "Excuse types" msgstr "Excusé" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -215,7 +251,7 @@ msgstr "Excusé" msgid "Extra marks" msgstr "" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "" @@ -290,6 +326,7 @@ msgstr "Notes personnelles" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -324,7 +361,8 @@ msgstr "Groupe" msgid "Lesson documentation" msgstr "Documentation de cours" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 #, fuzzy #| msgid "Lesson documentation" msgid "Lesson documentations" @@ -399,74 +437,86 @@ msgstr "Registre de Absence" msgid "Can list all personal note filters" msgstr "Liste de filtres de notes personnelles" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "" -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." msgstr "" -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "" -#: preferences.py:76 +#: preferences.py:85 #, fuzzy #| msgid "Teachers and lessons in group" msgid "Allow teachers to add data for lessons in holidays" msgstr "Profs et cours en groupe" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" msgstr "" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "" + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -598,13 +648,13 @@ msgid "%(period)s. period" msgstr "De la période" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "" @@ -662,7 +712,7 @@ msgid "Late persons:" msgstr "" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -707,18 +757,18 @@ msgstr "" " Il n' y a pas des cours pour le groupe sélectionné, les profs, le salle ou le temps.\n" " " -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 #, fuzzy #| msgid "Class register" msgid "Class register: person" msgstr "Registre de la classe" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -726,38 +776,38 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 #, fuzzy #| msgid "Unexcused" msgid "Unexcused absences" msgstr "injustifié(e)" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "" -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -766,34 +816,34 @@ msgstr "" msgid "Absences" msgstr "Absences" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "injustifié(e)" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "Notes personnelles importantes" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "" @@ -819,13 +869,6 @@ msgstr "" msgid "Period" msgstr "Période" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "Sujet" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -969,6 +1012,10 @@ msgstr "" msgid "Stop" msgstr "" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -1028,6 +1075,28 @@ msgstr "" msgid "e" msgstr "e" +#: templates/alsijil/partials/objects_table.html:4 +#, fuzzy +#| msgid "Lesson start" +msgid "Lesson filter" +msgstr "Début de cours" + +#: templates/alsijil/partials/objects_table.html:9 +#, fuzzy +#| msgid "Personal note filters" +msgid "Update filters" +msgstr "Filtres de notes personnelles" + +#: templates/alsijil/partials/objects_table.html:22 +#, fuzzy +#| msgid "Lesson start" +msgid "Lesson table" +msgstr "Début de cours" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "" @@ -1210,120 +1279,125 @@ msgstr "Oui" #: templates/alsijil/print/full_register.html:373 #, fuzzy -#| msgid "Lesson documentation for calendar week" -msgid "Lesson documentation for week" -msgstr "Documentation de cours pour la semaine calendrier" +#| msgid "Week view" +msgid "Week" +msgstr "Vue de semaine" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "Notes" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "" -#: views.py:211 +#: views.py:225 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The lesson documentation has been saved." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "" -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "" -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "" -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "" -#: views.py:979 +#: views.py:1009 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The personal note has been deleted." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1001 +#: views.py:1031 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The extra mark has been created." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1013 +#: views.py:1043 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The extra mark has been saved." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "" -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "" -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "" -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "" -#: views.py:1089 +#: views.py:1119 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role has been created." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1101 +#: views.py:1131 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role has been saved." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1112 +#: views.py:1142 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role has been deleted." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role has been assigned." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1196 +#: views.py:1226 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role assignment has been saved." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1217 +#: views.py:1247 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role assignment has been stopped." msgstr "Documentation de cours pour la semaine calendrier" -#: views.py:1230 +#: views.py:1260 #, fuzzy #| msgid "Lesson documentation for calendar week" msgid "The group role assignment has been deleted." msgstr "Documentation de cours pour la semaine calendrier" +#, fuzzy +#~| msgid "Lesson documentation for calendar week" +#~ msgid "Lesson documentation for week" +#~ msgstr "Documentation de cours pour la semaine calendrier" + #~ msgid "Personal note filters" #~ msgstr "Filtres de notes personnelles" @@ -1343,11 +1417,6 @@ msgstr "Documentation de cours pour la semaine calendrier" #~ msgid "All personal note filters" #~ msgstr "Filtres de notes personnelles" -#, fuzzy -#~| msgid "Personal note filters" -#~ msgid "Update personal note filter" -#~ msgstr "Filtres de notes personnelles" - #, fuzzy #~| msgid "Personal note filters" #~ msgid "Create personal note filter" diff --git a/aleksis/apps/alsijil/locale/la/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/la/LC_MESSAGES/django.po index ada9240dfcf86e89cfbf1799fdfff0271223e755..1876deb1661e1ead85c5ba1be9828bc06feb04ef 100644 --- a/aleksis/apps/alsijil/locale/la/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/la/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\n" "PO-Revision-Date: 2020-07-26 14:08+0000\n" "Last-Translator: Julian <leuckerj@gmail.com>\n" "Language-Team: Latin <https://translate.edugit.org/projects/aleksis/aleksis-app-alsijil/la/>\n" @@ -18,106 +18,120 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.0.1\n" -#: data_checks.py:15 +#: actions.py:30 +msgid "{} asks you to check some class register entries." +msgstr "" + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "" + +#: actions.py:54 +msgid "Ask teacher to check data" +msgstr "" + +#: data_checks.py:12 msgid "Delete object" msgstr "" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "" -#: data_checks.py:36 +#: data_checks.py:33 msgid "Reset personal note to defaults" msgstr "" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "" -#: data_checks.py:49 +#: data_checks.py:46 msgid "The personal note is related to a cancelled lesson." msgstr "" -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "" -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "" -#: data_checks.py:112 +#: data_checks.py:100 msgid "The lesson documentation is on holidays." msgstr "" -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "" -#: data_checks.py:148 +#: data_checks.py:134 msgid "The personal note is on holidays." msgstr "" -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "" -#: data_checks.py:177 +#: data_checks.py:163 msgid "The personal note is marked as excused, but not as absent." msgstr "" -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "Grex" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "" -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "" -#: forms.py:135 +#: forms.py:140 msgid "Start period" msgstr "" -#: forms.py:136 +#: forms.py:141 msgid "End period" msgstr "" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -126,25 +140,40 @@ msgstr "" msgid "Excused" msgstr "" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 msgid "Excuse type" msgstr "" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "Persona" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "" + +#: forms.py:271 +msgid "Has lesson documentation" +msgstr "" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "" @@ -177,13 +206,18 @@ msgstr "" msgid "Assign group role" msgstr "" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 msgid "Excuse types" msgstr "" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -193,7 +227,7 @@ msgstr "" msgid "Extra marks" msgstr "" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "" @@ -258,6 +292,7 @@ msgstr "Persona" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -292,7 +327,8 @@ msgstr "Grex" msgid "Lesson documentation" msgstr "" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 msgid "Lesson documentations" msgstr "" @@ -359,72 +395,84 @@ msgstr "" msgid "Can list all personal note filters" msgstr "" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "" -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." msgstr "" -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "" -#: preferences.py:76 +#: preferences.py:85 msgid "Allow teachers to add data for lessons in holidays" msgstr "" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" msgstr "" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "" + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -539,13 +587,13 @@ msgid "%(period)s. period" msgstr "" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "" @@ -599,7 +647,7 @@ msgid "Late persons:" msgstr "" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -634,16 +682,16 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 msgid "Class register: person" msgstr "" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -651,36 +699,36 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 msgid "Unexcused absences" msgstr "" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "" -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -689,34 +737,34 @@ msgstr "" msgid "Absences" msgstr "" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "" @@ -742,13 +790,6 @@ msgstr "" msgid "Period" msgstr "" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -880,6 +921,10 @@ msgstr "" msgid "Stop" msgstr "" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -937,6 +982,22 @@ msgstr "" msgid "e" msgstr "" +#: templates/alsijil/partials/objects_table.html:4 +msgid "Lesson filter" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:9 +msgid "Update filters" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:22 +msgid "Lesson table" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "" @@ -1114,94 +1175,94 @@ msgid "Yes" msgstr "" #: templates/alsijil/print/full_register.html:373 -msgid "Lesson documentation for week" +msgid "Week" msgstr "" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "" -#: views.py:211 +#: views.py:225 msgid "The lesson documentation has been saved." msgstr "" -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "" -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "" -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "" -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "" -#: views.py:979 +#: views.py:1009 msgid "The personal note has been deleted." msgstr "" -#: views.py:1001 +#: views.py:1031 msgid "The extra mark has been created." msgstr "" -#: views.py:1013 +#: views.py:1043 msgid "The extra mark has been saved." msgstr "" -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "" -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "" -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "" -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "" -#: views.py:1089 +#: views.py:1119 msgid "The group role has been created." msgstr "" -#: views.py:1101 +#: views.py:1131 msgid "The group role has been saved." msgstr "" -#: views.py:1112 +#: views.py:1142 msgid "The group role has been deleted." msgstr "" -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 msgid "The group role has been assigned." msgstr "" -#: views.py:1196 +#: views.py:1226 msgid "The group role assignment has been saved." msgstr "" -#: views.py:1217 +#: views.py:1247 msgid "The group role assignment has been stopped." msgstr "" -#: views.py:1230 +#: views.py:1260 msgid "The group role assignment has been deleted." msgstr "" diff --git a/aleksis/apps/alsijil/locale/nb_NO/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/nb_NO/LC_MESSAGES/django.po index 1d73f150d6c8255824d4236d25ea064757b0779d..2bf61f8695e2f97b8d0f8581ffd9b2c1c63def34 100644 --- a/aleksis/apps/alsijil/locale/nb_NO/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/nb_NO/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\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" @@ -17,106 +17,120 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: data_checks.py:15 +#: actions.py:30 +msgid "{} asks you to check some class register entries." +msgstr "" + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "" + +#: actions.py:54 +msgid "Ask teacher to check data" +msgstr "" + +#: data_checks.py:12 msgid "Delete object" msgstr "" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "" -#: data_checks.py:36 +#: data_checks.py:33 msgid "Reset personal note to defaults" msgstr "" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "" -#: data_checks.py:49 +#: data_checks.py:46 msgid "The personal note is related to a cancelled lesson." msgstr "" -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "" -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "" -#: data_checks.py:112 +#: data_checks.py:100 msgid "The lesson documentation is on holidays." msgstr "" -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "" -#: data_checks.py:148 +#: data_checks.py:134 msgid "The personal note is on holidays." msgstr "" -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "" -#: data_checks.py:177 +#: data_checks.py:163 msgid "The personal note is marked as excused, but not as absent." msgstr "" -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "" -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "" -#: forms.py:135 +#: forms.py:140 msgid "Start period" msgstr "" -#: forms.py:136 +#: forms.py:141 msgid "End period" msgstr "" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -125,25 +139,40 @@ msgstr "" msgid "Excused" msgstr "" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 msgid "Excuse type" msgstr "" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "" + +#: forms.py:271 +msgid "Has lesson documentation" +msgstr "" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "" @@ -174,13 +203,18 @@ msgstr "" msgid "Assign group role" msgstr "" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 msgid "Excuse types" msgstr "" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -190,7 +224,7 @@ msgstr "" msgid "Extra marks" msgstr "" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "" @@ -251,6 +285,7 @@ msgstr "" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -283,7 +318,8 @@ msgstr "" msgid "Lesson documentation" msgstr "" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 msgid "Lesson documentations" msgstr "" @@ -344,72 +380,84 @@ msgstr "" msgid "Can list all personal note filters" msgstr "" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "" -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." msgstr "" -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "" -#: preferences.py:76 +#: preferences.py:85 msgid "Allow teachers to add data for lessons in holidays" msgstr "" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" msgstr "" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "" + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -524,13 +572,13 @@ msgid "%(period)s. period" msgstr "" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "" @@ -584,7 +632,7 @@ msgid "Late persons:" msgstr "" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -619,16 +667,16 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 msgid "Class register: person" msgstr "" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -636,36 +684,36 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 msgid "Unexcused absences" msgstr "" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "" -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -674,34 +722,34 @@ msgstr "" msgid "Absences" msgstr "" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "" @@ -727,13 +775,6 @@ msgstr "" msgid "Period" msgstr "" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -863,6 +904,10 @@ msgstr "" msgid "Stop" msgstr "" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -920,6 +965,22 @@ msgstr "" msgid "e" msgstr "" +#: templates/alsijil/partials/objects_table.html:4 +msgid "Lesson filter" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:9 +msgid "Update filters" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:22 +msgid "Lesson table" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "" @@ -1095,93 +1156,93 @@ msgid "Yes" msgstr "" #: templates/alsijil/print/full_register.html:373 -msgid "Lesson documentation for week" +msgid "Week" msgstr "" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "" -#: views.py:211 +#: views.py:225 msgid "The lesson documentation has been saved." msgstr "" -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "" -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "" -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "" -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "" -#: views.py:979 +#: views.py:1009 msgid "The personal note has been deleted." msgstr "" -#: views.py:1001 +#: views.py:1031 msgid "The extra mark has been created." msgstr "" -#: views.py:1013 +#: views.py:1043 msgid "The extra mark has been saved." msgstr "" -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "" -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "" -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "" -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "" -#: views.py:1089 +#: views.py:1119 msgid "The group role has been created." msgstr "" -#: views.py:1101 +#: views.py:1131 msgid "The group role has been saved." msgstr "" -#: views.py:1112 +#: views.py:1142 msgid "The group role has been deleted." msgstr "" -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 msgid "The group role has been assigned." msgstr "" -#: views.py:1196 +#: views.py:1226 msgid "The group role assignment has been saved." msgstr "" -#: views.py:1217 +#: views.py:1247 msgid "The group role assignment has been stopped." msgstr "" -#: views.py:1230 +#: views.py:1260 msgid "The group role assignment has been deleted." msgstr "" diff --git a/aleksis/apps/alsijil/locale/tr_TR/LC_MESSAGES/django.po b/aleksis/apps/alsijil/locale/tr_TR/LC_MESSAGES/django.po index 1d73f150d6c8255824d4236d25ea064757b0779d..2bf61f8695e2f97b8d0f8581ffd9b2c1c63def34 100644 --- a/aleksis/apps/alsijil/locale/tr_TR/LC_MESSAGES/django.po +++ b/aleksis/apps/alsijil/locale/tr_TR/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-24 12:02+0100\n" +"POT-Creation-Date: 2021-03-21 14:38+0100\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" @@ -17,106 +17,120 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: data_checks.py:15 +#: actions.py:30 +msgid "{} asks you to check some class register entries." +msgstr "" + +#: actions.py:48 +#, python-brace-format +msgid "We have successfully sent notifications to {count_teachers} persons for {count_items} lessons." +msgstr "" + +#: actions.py:54 +msgid "Ask teacher to check data" +msgstr "" + +#: data_checks.py:12 msgid "Delete object" msgstr "" -#: data_checks.py:25 +#: data_checks.py:22 msgid "Set current groups" msgstr "" -#: data_checks.py:36 +#: data_checks.py:33 msgid "Reset personal note to defaults" msgstr "" -#: data_checks.py:48 +#: data_checks.py:45 msgid "Ensure that there are no personal notes in cancelled lessons" msgstr "" -#: data_checks.py:49 +#: data_checks.py:46 msgid "The personal note is related to a cancelled lesson." msgstr "" -#: data_checks.py:76 +#: data_checks.py:73 msgid "Ensure that 'groups_of_person' is set for every personal note" msgstr "" -#: data_checks.py:77 +#: data_checks.py:74 msgid "The personal note has no group in 'groups_of_person'." msgstr "" -#: data_checks.py:111 +#: data_checks.py:99 msgid "Ensure that there are no filled out lesson documentations on holidays" msgstr "" -#: data_checks.py:112 +#: data_checks.py:100 msgid "The lesson documentation is on holidays." msgstr "" -#: data_checks.py:147 +#: data_checks.py:133 msgid "Ensure that there are no filled out personal notes on holidays" msgstr "" -#: data_checks.py:148 +#: data_checks.py:134 msgid "The personal note is on holidays." msgstr "" -#: data_checks.py:176 +#: data_checks.py:162 msgid "Ensure that there are no excused personal notes without an absence" msgstr "" -#: data_checks.py:177 +#: data_checks.py:163 msgid "The personal note is marked as excused, but not as absent." msgstr "" -#: forms.py:36 +#: forms.py:41 msgid "Homework for the next lesson" msgstr "" -#: forms.py:61 forms.py:185 templates/alsijil/print/full_register.html:199 +#: forms.py:66 forms.py:190 forms.py:272 +#: templates/alsijil/print/full_register.html:199 msgid "Group" msgstr "" -#: forms.py:64 templates/alsijil/print/full_register.html:170 +#: forms.py:69 templates/alsijil/print/full_register.html:170 #: templates/alsijil/print/full_register.html:201 msgid "Teacher" msgstr "" -#: forms.py:79 +#: forms.py:84 msgid "You can't select a group and a teacher both." msgstr "" -#: forms.py:133 models.py:397 +#: forms.py:138 forms.py:274 models.py:397 #: templates/alsijil/group_role/assigned_list.html:64 msgid "Start date" msgstr "" -#: forms.py:134 models.py:401 +#: forms.py:139 forms.py:275 models.py:401 #: templates/alsijil/group_role/assigned_list.html:65 msgid "End date" msgstr "" -#: forms.py:135 +#: forms.py:140 msgid "Start period" msgstr "" -#: forms.py:136 +#: forms.py:141 msgid "End period" msgstr "" -#: forms.py:137 templates/alsijil/absences/register_confirm.html:52 +#: forms.py:142 templates/alsijil/absences/register_confirm.html:52 #: templates/alsijil/class_register/lesson.html:261 -#: templates/alsijil/class_register/person.html:218 +#: templates/alsijil/class_register/person.html:234 #: templates/alsijil/class_register/week_view.html:342 #: templates/alsijil/print/full_register.html:75 #: templates/alsijil/print/full_register.html:312 msgid "Absent" msgstr "" -#: forms.py:138 templates/alsijil/absences/register_confirm.html:56 +#: forms.py:143 templates/alsijil/absences/register_confirm.html:56 #: templates/alsijil/class_register/lesson.html:263 -#: templates/alsijil/class_register/person.html:97 -#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:113 +#: templates/alsijil/class_register/person.html:242 #: templates/alsijil/partials/mark_as_buttons.html:2 #: templates/alsijil/partials/mark_as_buttons.html:3 #: templates/alsijil/partials/persons_with_stats.html:74 @@ -125,25 +139,40 @@ msgstr "" msgid "Excused" msgstr "" -#: forms.py:140 models.py:62 models.py:199 +#: forms.py:145 models.py:62 models.py:199 #: templates/alsijil/class_register/lesson.html:264 #: templates/alsijil/class_register/lesson.html:305 msgid "Excuse type" msgstr "" -#: forms.py:145 templates/alsijil/class_register/lesson.html:266 +#: forms.py:150 templates/alsijil/class_register/lesson.html:266 #: templates/alsijil/class_register/lesson.html:326 #: templates/alsijil/print/full_register.html:314 msgid "Remarks" msgstr "" -#: forms.py:195 templates/alsijil/absences/register.html:9 +#: forms.py:200 templates/alsijil/absences/register.html:9 #: templates/alsijil/class_register/lesson.html:260 #: templates/alsijil/group_role/assigned_list.html:63 msgid "Person" msgstr "" -#: menus.py:6 preferences.py:8 templates/alsijil/print/full_register.html:16 +#: forms.py:270 +msgid "School term" +msgstr "" + +#: forms.py:271 +msgid "Has lesson documentation" +msgstr "" + +#: forms.py:273 templates/alsijil/class_register/week_view.html:106 +#: templates/alsijil/class_register/week_view.html:202 +#: templates/alsijil/print/full_register.html:169 +#: templates/alsijil/print/full_register.html:200 +msgid "Subject" +msgstr "" + +#: menus.py:6 preferences.py:9 templates/alsijil/print/full_register.html:16 msgid "Class register" msgstr "" @@ -174,13 +203,18 @@ msgstr "" msgid "Assign group role" msgstr "" -#: menus.py:82 models.py:63 templates/alsijil/excuse_type/list.html:8 +#: menus.py:82 templates/alsijil/class_register/all_objects.html:5 +#: templates/alsijil/class_register/all_objects.html:8 +msgid "All lessons" +msgstr "" + +#: menus.py:93 models.py:63 templates/alsijil/excuse_type/list.html:8 #: templates/alsijil/excuse_type/list.html:9 #: templates/alsijil/partials/legend.html:26 msgid "Excuse types" msgstr "" -#: menus.py:93 models.py:204 models.py:361 +#: menus.py:104 models.py:204 models.py:361 #: templates/alsijil/class_register/lesson.html:265 #: templates/alsijil/extra_mark/list.html:8 #: templates/alsijil/extra_mark/list.html:9 @@ -190,7 +224,7 @@ msgstr "" msgid "Extra marks" msgstr "" -#: menus.py:104 +#: menus.py:115 msgid "Manage group roles" msgstr "" @@ -251,6 +285,7 @@ msgstr "" #: models.py:239 templates/alsijil/class_register/lesson.html:114 #: templates/alsijil/class_register/lesson.html:251 +#: templates/alsijil/class_register/person.html:31 #: templates/alsijil/class_register/week_view.html:71 #: templates/alsijil/class_register/week_view.html:317 msgid "Personal notes" @@ -283,7 +318,8 @@ msgstr "" msgid "Lesson documentation" msgstr "" -#: models.py:328 templates/alsijil/class_register/week_view.html:68 +#: models.py:328 templates/alsijil/class_register/person.html:27 +#: templates/alsijil/class_register/week_view.html:68 msgid "Lesson documentations" msgstr "" @@ -344,72 +380,84 @@ msgstr "" msgid "Can list all personal note filters" msgstr "" -#: preferences.py:16 +#: preferences.py:17 msgid "Block adding personal notes for cancelled lessons" msgstr "" -#: preferences.py:24 +#: preferences.py:25 msgid "Allow users to view their own personal notes" msgstr "" -#: preferences.py:33 +#: preferences.py:34 msgid "Allow primary group owners to register future absences for students in their groups" msgstr "" #: preferences.py:43 +msgid "Allow original teachers to edit their lessons although they are substituted" +msgstr "" + +#: preferences.py:52 msgid "Carry over data from first lesson period to the following lesson periods in lessons over multiple periods" msgstr "" -#: preferences.py:46 +#: preferences.py:55 msgid "This will carry over data only if the data in the following periods are empty." msgstr "" -#: preferences.py:54 +#: preferences.py:63 msgid "Carry over personal notes to all following lesson periods on the same day." msgstr "" -#: preferences.py:63 +#: preferences.py:72 msgid "Allow teachers to open lesson periods on the same day and not just at the beginning of the period" msgstr "" -#: preferences.py:67 +#: preferences.py:76 msgid "Lessons in the past are not affected by this setting, you can open them whenever you want." msgstr "" -#: preferences.py:76 +#: preferences.py:85 msgid "Allow teachers to add data for lessons in holidays" msgstr "" -#: preferences.py:85 +#: preferences.py:94 msgid "Allow group owners to assign group roles to the parents of the group's members" msgstr "" -#: preferences.py:94 +#: preferences.py:103 msgid "Show assigned group roles in week view" msgstr "" -#: preferences.py:95 +#: preferences.py:104 msgid "Only week view of groups" msgstr "" -#: preferences.py:103 +#: preferences.py:112 msgid "Show assigned group roles in lesson view" msgstr "" -#: tables.py:17 tables.py:37 tables.py:62 +#: preferences.py:122 +msgid "Items per page in lessons table" +msgstr "" + +#: preferences.py:126 +msgid "Each page must show at least one item." +msgstr "" + +#: tables.py:19 tables.py:39 tables.py:64 #: templates/alsijil/group_role/partials/assignment_options.html:13 msgid "Edit" msgstr "" -#: tables.py:23 tables.py:43 tables.py:68 -#: templates/alsijil/class_register/person.html:260 +#: tables.py:25 tables.py:45 tables.py:70 +#: templates/alsijil/class_register/person.html:276 #: templates/alsijil/group_role/partials/assignment_options.html:29 msgid "Delete" msgstr "" #: templates/alsijil/absences/register.html:5 #: templates/alsijil/absences/register.html:6 -#: templates/alsijil/class_register/person.html:30 +#: templates/alsijil/class_register/person.html:46 #: templates/alsijil/class_register/week_view.html:332 #: templates/alsijil/partials/persons_with_stats.html:115 msgid "Register absence" @@ -524,13 +572,13 @@ msgid "%(period)s. period" msgstr "" #: templates/alsijil/class_register/lesson.html:56 -#: templates/alsijil/class_register/person.html:190 +#: templates/alsijil/class_register/person.html:206 #: templates/alsijil/class_register/week_view.html:151 #: templates/alsijil/class_register/week_view.html:214 #: templates/alsijil/class_register/week_view.html:268 #: templates/alsijil/partials/lesson_status_icon.html:16 #: templates/alsijil/print/full_register.html:335 -#: templates/alsijil/print/full_register.html:415 +#: templates/alsijil/print/full_register.html:415 util/alsijil_helpers.py:316 msgid "Event" msgstr "" @@ -584,7 +632,7 @@ msgid "Late persons:" msgstr "" #: templates/alsijil/class_register/lesson.html:262 -#: templates/alsijil/class_register/person.html:109 +#: templates/alsijil/class_register/person.html:125 #: templates/alsijil/partials/persons_with_stats.html:17 #: templates/alsijil/partials/persons_with_stats.html:34 #: templates/alsijil/partials/persons_with_stats.html:91 @@ -619,16 +667,16 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:8 +#: templates/alsijil/class_register/person.html:5 msgid "Class register: person" msgstr "" -#: templates/alsijil/class_register/person.html:16 +#: templates/alsijil/class_register/person.html:13 #: templates/alsijil/class_register/students_list.html:10 msgid "Back" msgstr "" -#: templates/alsijil/class_register/person.html:19 +#: templates/alsijil/class_register/person.html:16 #, python-format msgid "" "\n" @@ -636,36 +684,36 @@ msgid "" " " msgstr "" -#: templates/alsijil/class_register/person.html:36 +#: templates/alsijil/class_register/person.html:52 #: templates/alsijil/partials/legend.html:14 msgid "Unexcused absences" msgstr "" -#: templates/alsijil/class_register/person.html:45 -#: templates/alsijil/class_register/person.html:64 -#: templates/alsijil/class_register/person.html:201 -#: templates/alsijil/class_register/person.html:248 +#: templates/alsijil/class_register/person.html:61 +#: templates/alsijil/class_register/person.html:80 +#: templates/alsijil/class_register/person.html:217 +#: templates/alsijil/class_register/person.html:264 msgid "Mark as" msgstr "" -#: templates/alsijil/class_register/person.html:48 -#: templates/alsijil/class_register/person.html:67 -#: templates/alsijil/class_register/person.html:204 -#: templates/alsijil/class_register/person.html:210 -#: templates/alsijil/class_register/person.html:251 -#: templates/alsijil/class_register/person.html:257 +#: templates/alsijil/class_register/person.html:64 +#: templates/alsijil/class_register/person.html:83 +#: templates/alsijil/class_register/person.html:220 +#: templates/alsijil/class_register/person.html:226 +#: templates/alsijil/class_register/person.html:267 +#: templates/alsijil/class_register/person.html:273 msgid "Delete note" msgstr "" -#: templates/alsijil/class_register/person.html:77 +#: templates/alsijil/class_register/person.html:93 msgid "There are no unexcused lessons." msgstr "" -#: templates/alsijil/class_register/person.html:82 +#: templates/alsijil/class_register/person.html:98 msgid "Statistics on absences, tardiness and remarks" msgstr "" -#: templates/alsijil/class_register/person.html:91 +#: templates/alsijil/class_register/person.html:107 #: templates/alsijil/partials/legend.html:10 #: templates/alsijil/partials/persons_with_stats.html:16 #: templates/alsijil/partials/persons_with_stats.html:26 @@ -674,34 +722,34 @@ msgstr "" msgid "Absences" msgstr "" -#: templates/alsijil/class_register/person.html:95 +#: templates/alsijil/class_register/person.html:111 #: templates/alsijil/print/full_register.html:274 msgid "thereof" msgstr "" -#: templates/alsijil/class_register/person.html:105 +#: templates/alsijil/class_register/person.html:121 #: templates/alsijil/partials/persons_with_stats.html:86 #: templates/alsijil/print/full_register.html:81 #: templates/alsijil/print/full_register.html:283 msgid "Unexcused" msgstr "" -#: templates/alsijil/class_register/person.html:126 +#: templates/alsijil/class_register/person.html:142 #: templates/alsijil/print/full_register.html:304 msgid "Relevant personal notes" msgstr "" -#: templates/alsijil/class_register/person.html:142 +#: templates/alsijil/class_register/person.html:158 #, python-format msgid "Week %(week)s" msgstr "" -#: templates/alsijil/class_register/person.html:150 -#: templates/alsijil/class_register/person.html:168 +#: templates/alsijil/class_register/person.html:166 +#: templates/alsijil/class_register/person.html:184 msgid "Mark all as" msgstr "" -#: templates/alsijil/class_register/person.html:233 +#: templates/alsijil/class_register/person.html:249 #, python-format msgid "%(late)s' late" msgstr "" @@ -727,13 +775,6 @@ msgstr "" msgid "Period" msgstr "" -#: templates/alsijil/class_register/week_view.html:106 -#: templates/alsijil/class_register/week_view.html:202 -#: templates/alsijil/print/full_register.html:169 -#: templates/alsijil/print/full_register.html:200 -msgid "Subject" -msgstr "" - #: templates/alsijil/class_register/week_view.html:107 #: templates/alsijil/class_register/week_view.html:231 msgid "Teachers" @@ -863,6 +904,10 @@ msgstr "" msgid "Stop" msgstr "" +#: templates/alsijil/notifications/check.html:1 +msgid "Please check if the following class register entries are complete and correct:" +msgstr "" + #: templates/alsijil/partials/absences.html:6 #: templates/alsijil/partials/persons_with_stats.html:27 #: templates/alsijil/partials/persons_with_stats.html:44 @@ -920,6 +965,22 @@ msgstr "" msgid "e" msgstr "" +#: templates/alsijil/partials/objects_table.html:4 +msgid "Lesson filter" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:9 +msgid "Update filters" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:22 +msgid "Lesson table" +msgstr "" + +#: templates/alsijil/partials/objects_table.html:31 +msgid "Execute" +msgstr "" + #: templates/alsijil/partials/persons_with_stats.html:7 msgid "No students available." msgstr "" @@ -1095,93 +1156,93 @@ msgid "Yes" msgstr "" #: templates/alsijil/print/full_register.html:373 -msgid "Lesson documentation for week" +msgid "Week" msgstr "" #: templates/alsijil/print/full_register.html:383 msgid "Notes" msgstr "" -#: views.py:96 +#: views.py:108 msgid "You either selected an invalid lesson or there is currently no lesson in progress." msgstr "" -#: views.py:129 +#: views.py:141 msgid "You are not allowed to create a lesson documentation for a lesson in the future." msgstr "" -#: views.py:211 +#: views.py:225 msgid "The lesson documentation has been saved." msgstr "" -#: views.py:245 +#: views.py:259 msgid "The personal notes have been saved." msgstr "" -#: views.py:766 +#: views.py:782 msgid "The absences have been marked as excused." msgstr "" -#: views.py:781 +#: views.py:797 msgid "The absence has been marked as excused." msgstr "" -#: views.py:958 +#: views.py:988 msgid "The absence has been saved." msgstr "" -#: views.py:979 +#: views.py:1009 msgid "The personal note has been deleted." msgstr "" -#: views.py:1001 +#: views.py:1031 msgid "The extra mark has been created." msgstr "" -#: views.py:1013 +#: views.py:1043 msgid "The extra mark has been saved." msgstr "" -#: views.py:1024 +#: views.py:1054 msgid "The extra mark has been deleted." msgstr "" -#: views.py:1045 +#: views.py:1075 msgid "The excuse type has been created." msgstr "" -#: views.py:1057 +#: views.py:1087 msgid "The excuse type has been saved." msgstr "" -#: views.py:1068 +#: views.py:1098 msgid "The excuse type has been deleted." msgstr "" -#: views.py:1089 +#: views.py:1119 msgid "The group role has been created." msgstr "" -#: views.py:1101 +#: views.py:1131 msgid "The group role has been saved." msgstr "" -#: views.py:1112 +#: views.py:1142 msgid "The group role has been deleted." msgstr "" -#: views.py:1145 views.py:1177 +#: views.py:1175 views.py:1207 msgid "The group role has been assigned." msgstr "" -#: views.py:1196 +#: views.py:1226 msgid "The group role assignment has been saved." msgstr "" -#: views.py:1217 +#: views.py:1247 msgid "The group role assignment has been stopped." msgstr "" -#: views.py:1230 +#: views.py:1260 msgid "The group role assignment has been deleted." msgstr "" diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py index a7e6c8407ba49cf537bc728ffe2794a2a9bb01db..fe720477001be6e5992a71ac62b66fad00186780 100644 --- a/aleksis/apps/alsijil/menus.py +++ b/aleksis/apps/alsijil/menus.py @@ -78,6 +78,17 @@ MENUS = { ), ], }, + { + "name": _("All lessons"), + "url": "all_register_objects", + "icon": "list", + "validators": [ + ( + "aleksis.core.util.predicates.permission_validator", + "alsijil.view_register_objects_list", + ), + ], + }, { "name": _("Excuse types"), "url": "excuse_types", diff --git a/aleksis/apps/alsijil/migrations/0008_global_permissions.py b/aleksis/apps/alsijil/migrations/0008_global_permissions.py index 609fc703c60cee7770c06d819b06b309a22c56af..8974e8062f6e7915a9b901bcbf374ae13b846517 100644 --- a/aleksis/apps/alsijil/migrations/0008_global_permissions.py +++ b/aleksis/apps/alsijil/migrations/0008_global_permissions.py @@ -20,6 +20,7 @@ class Migration(migrations.Migration): options={ 'permissions': (('view_week', 'Can view week overview'), ('register_absence', 'Can register absence'), ('list_personal_note_filters', 'Can list all personal note filters')), 'managed': False, + 'default_permissions': (), }, managers=[ ('objects', django.contrib.sites.managers.CurrentSiteManager()), diff --git a/aleksis/apps/alsijil/migrations/0012_unique_relation.py b/aleksis/apps/alsijil/migrations/0012_unique_relation.py new file mode 100644 index 0000000000000000000000000000000000000000..6604e74121fb6881abc726b60e7d46846228c9d2 --- /dev/null +++ b/aleksis/apps/alsijil/migrations/0012_unique_relation.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.7 on 2021-03-21 17:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('chronos', '0004_substitution_extra_lesson_year'), + ('alsijil', '0011_tardiness_positive'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='lessondocumentation', + unique_together={('lesson_period', 'week', 'year', 'event', 'extra_lesson')}, + ), + migrations.AlterUniqueTogether( + name='personalnote', + unique_together={('lesson_period', 'week', 'year', 'event', 'extra_lesson')}, + ), + ] diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py index 9eeec915822ad4d49babb50614fba8f27de40202..e0bdb6c2ab21c80cd7932768d95d3a769e1a6f8e 100644 --- a/aleksis/apps/alsijil/model_extensions.py +++ b/aleksis/apps/alsijil/model_extensions.py @@ -1,9 +1,8 @@ from datetime import date from typing import Dict, Iterable, Iterator, Optional, Union -from django.db.models import Exists, OuterRef, Q, QuerySet +from django.db.models import Exists, FilteredRelation, OuterRef, Q, QuerySet from django.db.models.aggregates import Count, Sum -from django.db.models.expressions import Subquery from django.urls import reverse from django.utils.translation import gettext as _ @@ -386,59 +385,45 @@ def generate_person_list_with_class_register_statistics( if persons is None: persons = self.members.all() - # Build reusable Q objects for filtering by school term and by groups - # Necessary for the following annotations - school_term_q = ( - Q(personal_notes__lesson_period__lesson__validity__school_term=self.school_term) - | Q(personal_notes__extra_lesson__school_term=self.school_term) - | Q(personal_notes__event__school_term=self.school_term) + lesson_periods = LessonPeriod.objects.filter( + lesson__validity__school_term=self.school_term + ).filter(Q(lesson__groups=self) | Q(lesson__groups__parent_groups=self)) + extra_lessons = ExtraLesson.objects.filter(school_term=self.school_term).filter( + Q(groups=self) | Q(groups__parent_groups=self) ) - groups_q = ( - Q(personal_notes__lesson_period__lesson__groups=self) - | Q(personal_notes__lesson_period__lesson__groups__parent_groups=self) - | Q(personal_notes__extra_lesson__groups=self) - | Q(personal_notes__extra_lesson__groups__parent_groups=self) - | Q(personal_notes__event__groups=self) - | Q(personal_notes__event__groups__parent_groups=self) + events = Event.objects.filter(school_term=self.school_term).filter( + Q(groups=self) | Q(groups__parent_groups=self) ) - persons = persons.filter(personal_notes__groups_of_person=self).filter(school_term_q).distinct() - + persons = persons.select_related("primary_group", "primary_group__school_term") persons = persons.annotate( - absences_count=Count( + filtered_personal_notes=FilteredRelation( "personal_notes", - filter=Q(personal_notes__absent=True) & school_term_q & groups_q, - distinct=True, + condition=( + Q(personal_notes__event__in=events) + | Q(personal_notes__lesson_period__in=lesson_periods) + | Q(personal_notes__extra_lesson__in=extra_lessons) + ), + ) + ).annotate( + absences_count=Count( + "filtered_personal_notes", filter=Q(filtered_personal_notes__absent=True), ), excused=Count( - "personal_notes", + "filtered_personal_notes", filter=Q( - personal_notes__absent=True, - personal_notes__excused=True, - personal_notes__excuse_type__isnull=True, - ) - & school_term_q - & groups_q, - distinct=True, + filtered_personal_notes__absent=True, + filtered_personal_notes__excused=True, + filtered_personal_notes__excuse_type__isnull=True, + ), ), unexcused=Count( - "personal_notes", - filter=Q(personal_notes__absent=True, personal_notes__excused=False) - & school_term_q - & groups_q, - distinct=True, - ), - tardiness=Subquery( - Person.objects.filter(school_term_q & groups_q) - .filter(pk=OuterRef("pk"),) - .distinct() - .annotate(tardiness=Sum("personal_notes__late")) - .values("tardiness") + "filtered_personal_notes", + filter=Q(filtered_personal_notes__absent=True, filtered_personal_notes__excused=False), ), + tardiness=Sum("filtered_personal_notes__late"), tardiness_count=Count( - "personal_notes", - filter=~Q(personal_notes__late=0) & school_term_q & groups_q, - distinct=True, + "filtered_personal_notes", filter=Q(filtered_personal_notes__late__gt=0), ), ) @@ -446,9 +431,8 @@ def generate_person_list_with_class_register_statistics( persons = persons.annotate( **{ extra_mark.count_label: Count( - "personal_notes", - filter=Q(personal_notes__extra_marks=extra_mark) & school_term_q & groups_q, - distinct=True, + "filtered_personal_notes", + filter=Q(filtered_personal_notes__extra_marks=extra_mark), ) } ) @@ -457,11 +441,11 @@ def generate_person_list_with_class_register_statistics( persons = persons.annotate( **{ excuse_type.count_label: Count( - "personal_notes__absent", - filter=Q(personal_notes__absent=True, personal_notes__excuse_type=excuse_type,) - & school_term_q - & groups_q, - distinct=True, + "filtered_personal_notes__absent", + filter=Q( + filtered_personal_notes__absent=True, + filtered_personal_notes__excuse_type=excuse_type, + ), ) } ) diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py index d826f8e0ec559308507cdb2aa98fd1575f44cb01..d7bcb239d7d35e26c479c4f6582c31d429b1725f 100644 --- a/aleksis/apps/alsijil/models.py +++ b/aleksis/apps/alsijil/models.py @@ -31,7 +31,7 @@ from aleksis.apps.alsijil.managers import ( from aleksis.apps.chronos.managers import GroupPropertiesMixin from aleksis.apps.chronos.mixins import WeekRelatedMixin from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod, TimePeriod -from aleksis.core.mixins import ExtensibleModel +from aleksis.core.mixins import ExtensibleModel, GlobalPermissionModel from aleksis.core.models import SchoolTerm from aleksis.core.util.core_helpers import get_site_preferences from aleksis.core.util.model_helpers import ICONS @@ -277,6 +277,7 @@ class PersonalNote(RegisterObjectRelatedMixin, ExtensibleModel): check=lesson_related_constraint_q, name="one_relation_only_personal_note" ) ] + unique_together = ["lesson_period", "week", "year", "event", "extra_lesson"] class LessonDocumentation(RegisterObjectRelatedMixin, ExtensibleModel): @@ -364,6 +365,7 @@ class LessonDocumentation(RegisterObjectRelatedMixin, ExtensibleModel): check=lesson_related_constraint_q, name="one_relation_only_lesson_documentation", ) ] + unique_together = ["lesson_period", "week", "year", "event", "extra_lesson"] class ExtraMark(ExtensibleModel): @@ -445,7 +447,7 @@ class GroupRoleAssignment(GroupPropertiesMixin, ExtensibleModel): verbose_name_plural = _("Group role assignments") -class AlsijilGlobalPermissions(ExtensibleModel): +class AlsijilGlobalPermissions(GlobalPermissionModel): class Meta: managed = False permissions = ( diff --git a/aleksis/apps/alsijil/preferences.py b/aleksis/apps/alsijil/preferences.py index 98cdcc7104271ed1ee9d5e8a8313cd87cee57bc8..3ad751865f0534a156fd8ea7f9bfc0b558a467f8 100644 --- a/aleksis/apps/alsijil/preferences.py +++ b/aleksis/apps/alsijil/preferences.py @@ -1,7 +1,8 @@ +from django.core.exceptions import ValidationError from django.utils.translation import gettext as _ from dynamic_preferences.preferences import Section -from dynamic_preferences.types import BooleanPreference +from dynamic_preferences.types import BooleanPreference, IntegerPreference from aleksis.core.registries import person_preferences_registry, site_preferences_registry @@ -34,6 +35,14 @@ class RegisterAbsenceAsPrimaryGroupOwner(BooleanPreference): ) +@site_preferences_registry.register +class EditLessonDocumentationAsOriginalTeacher(BooleanPreference): + section = alsijil + name = "edit_lesson_documentation_as_original_teacher" + default = True + verbose_name = _("Allow original teachers to edit their lessons although they are substituted") + + @site_preferences_registry.register class CarryOverDataToNextPeriods(BooleanPreference): section = alsijil @@ -101,3 +110,17 @@ class ShowGroupRolesInLessonView(BooleanPreference): name = "group_roles_in_lesson_view" default = True verbose_name = _("Show assigned group roles in lesson view") + + +@person_preferences_registry.register +class RegisterObjectsTableItemsPerPage(IntegerPreference): + """Preference how many items are shown per page in ``RegisterObjectTable``.""" + + section = alsijil + name = "register_objects_table_items_per_page" + default = 100 + verbose_name = _("Items per page in lessons table") + + def validate(self, value): + if value < 1: + raise ValidationError(_("Each page must show at least one item.")) diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py index f36db7aa5a3b532d2b143c109c7daf089391c96a..1a8a06adc1033d690d0b20cfbbe92869621767bc 100644 --- a/aleksis/apps/alsijil/rules.py +++ b/aleksis/apps/alsijil/rules.py @@ -1,6 +1,8 @@ from rules import add_perm +from aleksis.core.models import Group from aleksis.core.util.predicates import ( + has_any_object, has_global_perm, has_object_perm, has_person, @@ -15,6 +17,7 @@ from .util.predicates import ( is_group_member, is_group_owner, is_group_role_assignment_group_owner, + is_lesson_original_teacher, is_lesson_parent_group_owner, is_lesson_participant, is_lesson_teacher, @@ -23,6 +26,7 @@ from .util.predicates import ( is_owner_of_any_group, is_person_group_owner, is_person_primary_group_owner, + is_personal_note_lesson_original_teacher, is_personal_note_lesson_parent_group_owner, is_personal_note_lesson_teacher, is_teacher, @@ -32,6 +36,7 @@ from .util.predicates import ( view_register_object_predicate = has_person & ( is_none # View is opened as "Current lesson" | is_lesson_teacher + | is_lesson_original_teacher | is_lesson_participant | is_lesson_parent_group_owner | has_global_perm("alsijil.view_lesson") @@ -46,6 +51,7 @@ add_perm("alsijil.view_lesson_menu", has_person) view_lesson_personal_notes_predicate = view_register_object_predicate & ( ~is_lesson_participant | is_lesson_teacher + | is_lesson_original_teacher | has_global_perm("alsijil.view_personalnote") | has_lesson_group_object_perm("core.view_personalnote_group") ) @@ -54,6 +60,10 @@ add_perm("alsijil.view_register_object_personalnote", view_lesson_personal_notes # Edit personal note edit_lesson_personal_note_predicate = view_lesson_personal_notes_predicate & ( is_lesson_teacher + | ( + is_lesson_original_teacher + & is_site_preference_set("alsijil", "edit_lesson_documentation_as_original_teacher") + ) | has_global_perm("alsijil.change_personalnote") | has_lesson_group_object_perm("core.edit_personalnote_group") ) @@ -63,6 +73,7 @@ add_perm("alsijil.edit_register_object_personalnote", edit_lesson_personal_note_ view_personal_note_predicate = has_person & ( (is_own_personal_note & is_site_preference_set("alsijil", "view_own_personal_notes")) | is_personal_note_lesson_teacher + | is_personal_note_lesson_original_teacher | is_personal_note_lesson_parent_group_owner | has_global_perm("alsijil.view_personalnote") | has_personal_note_group_perm("core.view_personalnote_group") @@ -72,6 +83,10 @@ add_perm("alsijil.view_personalnote", view_personal_note_predicate) # Edit personal note edit_personal_note_predicate = view_personal_note_predicate & ( ~is_own_personal_note + & ~( + is_personal_note_lesson_original_teacher + | ~is_site_preference_set("alsijil", "edit_lesson_documentation_as_original_teacher") + ) | has_global_perm("alsijil.view_personalnote") | has_personal_note_group_perm("core.edit_personalnote_group") ) @@ -84,6 +99,10 @@ add_perm("alsijil.view_lessondocumentation", view_lesson_documentation_predicate # Edit lesson documentation edit_lesson_documentation_predicate = view_register_object_predicate & ( is_lesson_teacher + | ( + is_lesson_original_teacher + & is_site_preference_set("alsijil", "edit_lesson_documentation_as_original_teacher") + ) | has_global_perm("alsijil.change_lessondocumentation") | has_lesson_group_object_perm("core.edit_lessondocumentation_group") ) @@ -241,13 +260,22 @@ add_perm("alsijil.delete_grouprole", delete_group_role_predicate) view_assigned_group_roles_predicate = ( is_group_owner - | is_lesson_teacher - | is_lesson_parent_group_owner | has_global_perm("alsjil.assign_grouprole") - | has_object_perm("alsijil.assign_grouprole") + | has_object_perm("core.assign_grouprole") ) add_perm("alsijil.view_assigned_grouproles", view_assigned_group_roles_predicate) +view_assigned_group_roles_register_object_predicate = ( + is_lesson_teacher + | is_lesson_original_teacher + | is_lesson_parent_group_owner + | has_global_perm("alsjil.assign_grouprole") +) +add_perm( + "alsijil.view_assigned_grouproles_for_register_object", + view_assigned_group_roles_register_object_predicate, +) + assign_group_role_person_predicate = is_person_group_owner | has_global_perm( "alsjil.assign_grouprole" ) @@ -273,3 +301,9 @@ delete_group_role_assignment_predicate = ( has_global_perm("alsjil.assign_grouprole") | is_group_role_assignment_group_owner ) add_perm("alsijil.delete_grouproleassignment", delete_group_role_assignment_predicate) + +view_register_objects_list_predicate = has_person & ( + has_any_object("core.view_full_register_group", Group) + | has_global_perm("core.view_full_register") +) +add_perm("alsijil.view_register_objects_list", view_register_objects_list_predicate) diff --git a/aleksis/apps/alsijil/static/css/alsijil/full_register.css b/aleksis/apps/alsijil/static/css/alsijil/full_register.css index 9a3dc493aa468c989ed766817436d20b40cd0bff..0584c12ee4e266f43fe8d34c8003d37d4a09815c 100644 --- a/aleksis/apps/alsijil/static/css/alsijil/full_register.css +++ b/aleksis/apps/alsijil/static/css/alsijil/full_register.css @@ -25,7 +25,7 @@ tr.lessons-day-first { border-top: 3px solid rgba(0, 0, 0, 0.3); } -th.lessons-day-head, td.rotate, th.rotate { +td.rotate, th.rotate { text-align: center; transform: rotate(-90deg); } diff --git a/aleksis/apps/alsijil/tables.py b/aleksis/apps/alsijil/tables.py index 7cc76996c2a265b051b98244f2a9ee9d0710c7d3..1a71b901c64f6684a344474687bb247c2f1438bb 100644 --- a/aleksis/apps/alsijil/tables.py +++ b/aleksis/apps/alsijil/tables.py @@ -6,7 +6,7 @@ import django_tables2 as tables from django_tables2.utils import A from aleksis.apps.chronos.models import Event, LessonPeriod -from aleksis.core.tables import MaterializeCheckboxColumn +from aleksis.core.util.tables import SelectColumn from .models import PersonalNote @@ -87,14 +87,14 @@ class GroupRoleTable(tables.Table): class PersonalNoteTable(tables.Table): - selected = MaterializeCheckboxColumn( + selected = SelectColumn( attrs={"input": {"name": "selected_objects"}}, accessor=A("pk") ) date = tables.Column( verbose_name=_("Date"), accessor=A("date_formatted"), order_by=A("day_start") ) period = tables.Column( - verbose_name=_("Period"), accessor=A("period_formatted"), order_by=A("period") + verbose_name=_("Period"), accessor=A("period_formatted"), order_by=A("order_period") ) groups = tables.Column(verbose_name=_("Groups"), accessor=A("register_object__group_names")) teachers = tables.Column( @@ -104,6 +104,7 @@ class PersonalNoteTable(tables.Table): verbose_name=_("Subject"), accessor=A("register_object__get_subject__name") ) absent = tables.Column() + late = tables.Column() excused = tables.Column(verbose_name=_("Excuse")) extra_marks = tables.Column(verbose_name="Extra marks", accessor=A("extra_marks__all")) @@ -122,7 +123,7 @@ class PersonalNoteTable(tables.Table): def render_absent(self, value): return render_to_string( "components/materialize-chips.html", dict(content="Absent", classes="red white-text") - ) + ) if value else "–" def render_excused(self, value, record): if record.absent: @@ -133,7 +134,7 @@ class PersonalNoteTable(tables.Table): context = dict(content=record.excuse_type.name, classes="green white-text") badge = render_to_string("components/materialize-chips.html", context) return badge - return "" + return "–" def render_late(self, value): if value: @@ -159,3 +160,51 @@ class PersonalNoteTable(tables.Table): model = PersonalNote fields = () template_name = "django_tables2/materialize.html" + + +def _get_link(value, record): + return record["register_object"].get_alsijil_url(record.get("week")) + + +class RegisterObjectTable(tables.Table): + """Table to show all register objects in an overview. + + .. warning:: + Works only with ``generate_list_of_all_register_objects``. + """ + + class Meta: + attrs = {"class": "highlight responsive-table"} + + status = tables.Column(accessor="register_object") + date = tables.Column(order_by="date_sort", linkify=_get_link) + period = tables.Column(order_by="period_sort", linkify=_get_link) + groups = tables.Column(linkify=_get_link) + teachers = tables.Column(linkify=_get_link) + subject = tables.Column(linkify=_get_link) + topic = tables.Column(linkify=_get_link) + homework = tables.Column(linkify=_get_link) + group_note = tables.Column(linkify=_get_link) + + def render_status(self, value, record): + return render_to_string( + "alsijil/partials/lesson_status_icon.html", + dict( + week=record.get("week"), + has_documentation=record.get("has_documentation", False), + substitution=record.get("substitution"), + register_object=value, + ), + ) + + +class RegisterObjectSelectTable(RegisterObjectTable): + """Table to show all register objects with multi-select support. + + More information at ``RegisterObjectTable`` + """ + + selected = SelectColumn() + + class Meta(RegisterObjectTable.Meta): + sequence = ("selected", "...") diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html b/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html new file mode 100644 index 0000000000000000000000000000000000000000..b5e57e0ee276ab395ebd824327c7584a063dba63 --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/all_objects.html @@ -0,0 +1,19 @@ +{# -*- engine:django -*- #} +{% extends "core/base.html" %} +{% load i18n rules static django_tables2 material_form %} + +{% block browser_title %}{% blocktrans %}All lessons{% endblocktrans %}{% endblock %} + +{% block page_title %} + {% blocktrans %}All lessons{% endblocktrans %} +{% endblock %} + +{% block extra_head %} + {{ block.super }} + <link rel="stylesheet" href="{% static 'css/alsijil/alsijil.css' %}"/> +{% endblock %} + +{% block content %} + {% include "alsijil/partials/objects_table.html" %} + <script src="{% static "js/multi_select.js" %}"></script> +{% endblock %} diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html index f21d7686acb763c6f63942dcab91517020b7e0e2..13e781bfb24e3dab3184aa0145dadde7dffd3987 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html @@ -114,11 +114,13 @@ <a href="#personal-notes">{% trans "Personal notes" %}</a> </li> {% endif %} - {% has_perm "alsijil.view_lessondocumentation" user register_object.prev as can_view_prev_lesson_documentation %} - {% if register_object.prev.get_lesson_documentation and can_view_prev_lesson_documentation %} - <li class="tab"> - <a href="#previous-lesson">{% trans "Previous lesson" %}</a> - </li> + {% if prev_lesson %} + {% has_perm "alsijil.view_lessondocumentation" user prev_lesson as can_view_prev_lesson_documentation %} + {% if prev_lesson.get_lesson_documentation and can_view_prev_lesson_documentation %} + <li class="tab"> + <a href="#previous-lesson">{% trans "Previous lesson" %}</a> + </li> + {% endif %} {% endif %} {% if group_roles %} <li class="tab"> @@ -172,7 +174,7 @@ </div> </div> - {% with prev_lesson=register_object.prev prev_doc=prev_lesson.get_lesson_documentation %} + {% with prev_doc=prev_lesson.get_lesson_documentation %} {% with absences=prev_lesson.get_absences tardinesses=prev_lesson.get_tardinesses extra_marks=prev_lesson.get_extra_marks %} {% has_perm "alsijil.view_lessondocumentation" user prev_lesson as can_view_prev_lesson_documentation %} {% if prev_doc and can_view_prev_lesson_documentation %} diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html index a0041c196982dc8438c1e5cfaadcc6c8cceff9ee..223fc557697686ff392fe27ffe066c12cd81abc8 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html @@ -1,12 +1,6 @@ {# -*- engine:django -*- #} {% extends "core/base.html" %} -{% load rules %} -{% load data_helpers %} -{% load week_helpers %} -{% load i18n %} -{% load material_form %} -{% load static %} -{% load render_table from django_tables2 %} +{% load rules data_helpers week_helpers i18n material_form static django_tables2 %} {% block extra_head %} <link rel="stylesheet" href="{% static "css/alsijil/person.css" %}"> @@ -20,7 +14,7 @@ {% has_perm "alsijil.view_my_students" user as has_students %} {% if has_students %} <a href="{% url "my_students" %}" - class="btn-flat primary-color-text waves-light waves-effect"> + class="btn-flat primary-color-text waves-light waves-effect"> <i class="material-icons left">chevron_left</i> {% trans "Back" %} </a> {% endif %} @@ -30,16 +24,38 @@ {% endblock %} {% block content %} - {% has_perm "alsijil.edit_person_overview_personalnote" user person as can_mark_all_as_excused %} - {% has_perm "alsijil.register_absence" user person as can_register_absence %} - {% if can_register_absence %} - <a class="btn primary-color waves-effect waves-light" href="{% url "register_absence" person.pk %}"> - <i class="material-icons left">rate_review</i> - {% trans "Register absence" %} - </a> + <div class="row"> + <div class="col s12"> + <ul class="tabs"> + {% if register_object_table %} + <li class="tab"> + <a href="#lesson-documentations">{% trans "Lesson documentations" %}</a> + </li> + {% endif %} + <li class="tab"> + <a href="#personal-notes">{% trans "Personal notes" %}</a> + </li> + {% if stats %} + <li class="tab col s6"><a href="#overview" class="active">{% trans "Overview" %}</a></li> + <li class="tab col s6"><a href="#statistics">{% trans "Statistics" %}</a></li> + {% endif %} + </ul> + {% if register_object_table %} + <div class="col s12" id="lesson-documentations"> + {% include "alsijil/partials/objects_table.html" with table=register_object_table filter_form=filter_form %} + </div> {% endif %} + <div class="col s12" id="personal-notes"> + {% has_perm "alsijil.edit_person_overview_personalnote" user person as can_mark_all_as_excused %} + {% has_perm "alsijil.register_absence" user person as can_register_absence %} + {% if can_register_absence %} + <a class="btn primary-color waves-effect waves-light" href="{% url "register_absence" person.pk %}"> + <i class="material-icons left">rate_review</i> + {% trans "Register absence" %} + </a> + {% endif %} + - <div class="row"> {% if stats %} <div class="col s12"> <ul class="tabs"> @@ -52,9 +68,9 @@ <h5>{% trans "Unexcused absences" %}</h5> - {# {% for note in unexcused_absences %}#} + {# {% for note in unexcused_absences %}#} {# {% weekday_to_date note.calendar_week note.lesson_period.period.weekday as note_date %}#} - {# <li class="collection-item">#} + {# <li class="collection-item">#} {# {% has_perm "alsijil.edit_personalnote" user note as can_edit_personal_note %}#} {# {% if can_edit_personal_note %}#} {# <label class="left">#} @@ -62,43 +78,43 @@ {# form="excuse-multiple-form" class="filled-in"/>#} {# <span></span>#} {# </label>#} - {# <form action="" method="post" class="right hide-on-small-only">#} + {# <form action="" method="post" class="right hide-on-small-only">#} {# {% csrf_token %}#} {# {% trans "Mark as" %}#} - {# <input type="hidden" value="{{ note.pk }}" name="personal_note">#} + {# <input type="hidden" value="{{ note.pk }}" name="personal_note">#} {# {% include "alsijil/partials/mark_as_buttons.html" %}#} - {# <a class="btn-flat red-text" title="{% trans "Delete note" %}"#} - {# href="{% url "delete_personal_note" note.pk %}">#} - {# <i class="material-icons center">cancel</i>#} - {# </a>#} - {# </form>#} + {# <a class="btn-flat red-text" title="{% trans "Delete note" %}"#} + {# href="{% url "delete_personal_note" note.pk %}">#} + {# <i class="material-icons center">cancel</i>#} + {# </a>#} + {# </form>#} {# {% endif %}#} - {# <i class="material-icons left red-text">warning</i>#} - {# <p class="no-margin">#} - {# <a href="{% url note.register_object.alsijil_url note.year note.week note.lesson_period.pk %}">{{ note_date }}, {{ note.lesson_period }}</a>#} - {# </p>#} + {# <i class="material-icons left red-text">warning</i>#} + {# <p class="no-margin">#} + {# <a href="{% url note.register_object.alsijil_url note.year note.week note.lesson_period.pk %}">{{ note_date }}, {{ note.lesson_period }}</a>#} + {# </p>#} {# {% if note.remarks %}#} - {# <p class="no-margin"><em>{{ note.remarks }}</em></p>#} + {# <p class="no-margin"><em>{{ note.remarks }}</em></p>#} {# {% endif %}#} {# {% if can_edit_personal_note %}#} - {# <form action="" method="post" class="hide-on-med-and-up">#} + {# <form action="" method="post" class="hide-on-med-and-up">#} {# {% csrf_token %}#} {# {% trans "Mark as" %}#} - {# <input type="hidden" value="{{ note.pk }}" name="personal_note">#} + {# <input type="hidden" value="{{ note.pk }}" name="personal_note">#} {# {% include "alsijil/partials/mark_as_buttons.html" %}#} - {# <a class="btn-flat red-text" title="{% trans "Delete note" %}"#} - {# href="{% url "delete_personal_note" note.pk %}">#} - {# <i class="material-icons center">cancel</i>#} - {# </a>#} - {# </form>#} + {# <a class="btn-flat red-text" title="{% trans "Delete note" %}"#} + {# href="{% url "delete_personal_note" note.pk %}">#} + {# <i class="material-icons center">cancel</i>#} + {# </a>#} + {# </form>#} {# {% endif %}#} - {# </li>#} - {# {% empty %}#} - {# <li class="collection-item avatar valign-wrapper">#} - {# <i class="material-icons left circle green white-text">check</i>#} - {# <span class="title">{% trans "There are no unexcused lessons." %}</span>#} - {# </li>#} - {# {% endfor %}#} + {# </li>#} + {# {% empty %}#} + {# <li class="collection-item avatar valign-wrapper">#} + {# <i class="material-icons left circle green white-text">check</i>#} + {# <span class="title">{% trans "There are no unexcused lessons." %}</span>#} + {# </li>#} + {# {% endfor %}#} </ul> {% if stats %} <h5>{% trans "Statistics on absences, tardiness and remarks" %}</h5> @@ -152,147 +168,149 @@ <button type="submit" class="btn waves-effect waves-light">Enter</button> {% render_table personal_notes_table %} </form> - <ul class="collapsible"> - <li> - <div> - <ul> - {% for note in personal_notes %} - {% ifchanged note.school_term %}</ul></div></li> - <li {% if forloop.first %}class="active"{% endif %}> - <div class="collapsible-header"><i - class="material-icons">date_range</i>{{ note.school_term }}</div> - <div class="collapsible-body"> - <ul class="collection"> - {% endifchanged %} + <ul class="collapsible"> + <li> + <div> + <ul> + {% for note in personal_notes %} + {% ifchanged note.school_term %}</ul></div></li> + <li {% if forloop.first %}class="active"{% endif %}> + <div class="collapsible-header"><i + class="material-icons">date_range</i>{{ note.school_term }}</div> + <div class="collapsible-body"> + <ul class="collection"> + {% endifchanged %} - {% ifchanged note.week %} - <li class="collection-item"> - <strong>{% blocktrans with week=note.calendar_week.week %}Week {{ week }}{% endblocktrans %}</strong> - </li> - {% endifchanged %} - {% ifchanged note.date %} - <li class="collection-item"> - {% if can_mark_all_as_excused and note.date %} - <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;"> - {% csrf_token %} - {% trans "Mark all as" %} - <input type="hidden" value="{{ note.date|date:"Y-m-d" }}" name="date"> - {% include "alsijil/partials/mark_as_buttons.html" %} - </form> - {% endif %} - <i class="material-icons left">schedule</i> - - {% if note.date %} - {{ note.date }} - {% else %} - {{ note.register_object.date_start }} - {{ note.register_object.period_from.period }}.–{{ note.register_object.date_end }} - {{ note.register_object.period_to.period }}. - {% endif %} - - {% if can_mark_all_as_excused and note.date %} - <form action="" method="post" class="hide-on-med-and-up"> - {% csrf_token %} - {% trans "Mark all as" %} - <input type="hidden" value="{{ note.date|date:"Y-m-d" }}" name="date"> - {% include "alsijil/partials/mark_as_buttons.html" %} - </form> - {% endif %} - </li> - {% endifchanged %} + {% ifchanged note.week %} + <li class="collection-item"> + <strong>{% blocktrans with week=note.calendar_week.week %}Week {{ week }}{% endblocktrans %}</strong> + </li> + {% endifchanged %} + {% ifchanged note.date %} + <li class="collection-item"> + {% if can_mark_all_as_excused and note.date %} + <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;"> + {% csrf_token %} + {% trans "Mark all as" %} + <input type="hidden" value="{{ note.date|date:"Y-m-d" }}" name="date"> + {% include "alsijil/partials/mark_as_buttons.html" %} + </form> + {% endif %} + <i class="material-icons left">schedule</i> - <li class="collection-item"> - <div class="row no-margin"> - <div class="col s2 m1"> - {% if note.register_object.period %} - {{ note.register_object.period.period }}. - {% endif %} - </div> - - <div class="col s10 m4"> - <i class="material-icons left">event_note</i> - <a href="{{ note.get_absolute_url }}"> - {% if note.register_object.get_subject %} - {{ note.register_object.get_subject.name }} + {% if note.date %} + {{ note.date }} {% else %} - {% trans "Event" %} ({{ note.register_object.title }}) - {% endif %}<br/> - {{ note.register_object.teacher_names }} - </a> - </div> + {{ note.register_object.date_start }} + {{ note.register_object.period_from.period }}.–{{ note.register_object.date_end }} + {{ note.register_object.period_to.period }}. + {% endif %} - <div class="col s12 m7 no-padding"> - {% has_perm "alsijil.edit_personalnote" user note as can_edit_personal_note %} - {% if note.absent and not note.excused and can_edit_personal_note %} - <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;"> - {% csrf_token %} - {% trans "Mark as" %} - <input type="hidden" value="{{ note.pk }}" name="personal_note"> - {% include "alsijil/partials/mark_as_buttons.html" %} - <a class="btn-flat red-text" title="{% trans "Delete note" %}" - href="{% url "delete_personal_note" note.pk %}"> - <i class="material-icons center">cancel</i> - </a> - </form> - {% elif can_edit_personal_note %} - <a class="btn-flat red-text right hide-on-small-only" title="{% trans "Delete note" %}" - href="{% url "delete_personal_note" note.pk %}"> - <i class="material-icons center">cancel</i> - </a> - {% endif %} + {% if can_mark_all_as_excused and note.date %} + <form action="" method="post" class="hide-on-med-and-up"> + {% csrf_token %} + {% trans "Mark all as" %} + <input type="hidden" value="{{ note.date|date:"Y-m-d" }}" name="date"> + {% include "alsijil/partials/mark_as_buttons.html" %} + </form> + {% endif %} + </li> + {% endifchanged %} - {% if note.absent %} - <div class="chip red white-text"> - {% trans 'Absent' %} - </div> - {% endif %} - {% if note.excused %} - <div class="chip green white-text"> - {% if note.excuse_type %} - {{ note.excuse_type.name }} - {% else %} - {% trans 'Excused' %} + <li class="collection-item"> + <div class="row no-margin"> + <div class="col s2 m1"> + {% if note.register_object.period %} + {{ note.register_object.period.period }}. {% endif %} </div> - {% endif %} - {% if note.late %} - <div class="chip orange white-text"> - {% blocktrans with late=note.late %}{{ late }}' late{% endblocktrans %} + <div class="col s10 m4"> + <i class="material-icons left">event_note</i> + <a href="{{ note.get_absolute_url }}"> + {% if note.register_object.get_subject %} + {{ note.register_object.get_subject.name }} + {% else %} + {% trans "Event" %} ({{ note.register_object.title }}) + {% endif %}<br/> + {{ note.register_object.teacher_names }} + </a> </div> - {% endif %} - {% for extra_mark in note.extra_marks.all %} - <div class="chip">{{ extra_mark.name }}</div> - {% endfor %} + <div class="col s12 m7 no-padding"> + {% has_perm "alsijil.edit_personalnote" user note as can_edit_personal_note %} + {% if note.absent and not note.excused and can_edit_personal_note %} + <form action="" method="post" class="right hide-on-small-only" style="margin-top: -7px;"> + {% csrf_token %} + {% trans "Mark as" %} + <input type="hidden" value="{{ note.pk }}" name="personal_note"> + {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> + </form> + {% elif can_edit_personal_note %} + <a class="btn-flat red-text right hide-on-small-only" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> + {% endif %} - <em>{{ note.remarks }}</em> + {% if note.absent %} + <div class="chip red white-text"> + {% trans 'Absent' %} + </div> + {% endif %} + {% if note.excused %} + <div class="chip green white-text"> + {% if note.excuse_type %} + {{ note.excuse_type.name }} + {% else %} + {% trans 'Excused' %} + {% endif %} + </div> + {% endif %} - </div> - <div class="col s12 hide-on-med-and-up"> - {% if note.absent and not note.excused and can_edit_personal_note %} - <form action="" method="post"> - {% csrf_token %} - {% trans "Mark as" %} - <input type="hidden" value="{{ note.pk }}" name="personal_note"> - {% include "alsijil/partials/mark_as_buttons.html" %} - <a class="btn-flat red-text" title="{% trans "Delete note" %}" - href="{% url "delete_personal_note" note.pk %}"> - <i class="material-icons center">cancel</i> - </a> - </form> - {% elif can_edit_personal_note %} - <a class="btn-flat red-text" title="{% trans "Delete note" %}" - href="{% url "delete_personal_note" note.pk %}"> - <i class="material-icons left">cancel</i> - {% trans "Delete" %} - </a> - {% endif %} - </div> - </li> - {% endfor %} - </li> - </ul> - </div> + {% if note.late %} + <div class="chip orange white-text"> + {% blocktrans with late=note.late %}{{ late }}' late{% endblocktrans %} + </div> + {% endif %} + + {% for extra_mark in note.extra_marks.all %} + <div class="chip">{{ extra_mark.name }}</div> + {% endfor %} + + <em>{{ note.remarks }}</em> + + </div> + <div class="col s12 hide-on-med-and-up"> + {% if note.absent and not note.excused and can_edit_personal_note %} + <form action="" method="post"> + {% csrf_token %} + {% trans "Mark as" %} + <input type="hidden" value="{{ note.pk }}" name="personal_note"> + {% include "alsijil/partials/mark_as_buttons.html" %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons center">cancel</i> + </a> + </form> + {% elif can_edit_personal_note %} + <a class="btn-flat red-text" title="{% trans "Delete note" %}" + href="{% url "delete_personal_note" note.pk %}"> + <i class="material-icons left">cancel</i> + {% trans "Delete" %} + </a> + {% endif %} + </div> + </li> + {% endfor %} + </li> + </ul> + </div> + </div> + </div> </div> {% endblock %} diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html index 1f2531a89d5279286e47bd88230e5ec1763b342f..8c83accaf9b7cfc9e07a2b05c16961d3f959fd75 100644 --- a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html +++ b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html @@ -333,11 +333,13 @@ </a> {% endif %} </h5> - <p> - {% for assignment in person.person.group_roles.all %} - {% include "alsijil/group_role/chip.html" with role=assignment.role small=assignment.date_range %} - {% endfor %} - </p> + {% if group_roles %} + <p> + {% for assignment in person.person.group_roles.all %} + {% include "alsijil/group_role/chip.html" with role=assignment.role small=assignment.date_range %} + {% endfor %} + </p> + {% endif %} <p class="card-text"> {% trans "Absent" %}: {{ person.person.absences_count }} ({{ person.person.unexcused_count }} {% trans "unexcused" %}) diff --git a/aleksis/apps/alsijil/templates/alsijil/notifications/check.html b/aleksis/apps/alsijil/templates/alsijil/notifications/check.html new file mode 100644 index 0000000000000000000000000000000000000000..d76a1a0a5abfc6fb8b7722d5a4cf16ff927f069a --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/notifications/check.html @@ -0,0 +1,4 @@ +{% load i18n %}{% trans "Please check if the following class register entries are complete and correct:" %} +{% for entry in items %} +- {{ entry.register_object }} ({{ entry.date }}) +{% endfor %} \ No newline at end of file diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html index ceff8c1a17ea0452b1f013d759dbee7edfd6c630..52f55e9723c3b9650bcd09f63725467a75f8993d 100644 --- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html +++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html @@ -2,7 +2,7 @@ {% now_datetime as now_dt %} -{% if register_object.has_documentation %} +{% if has_documentation or register_object.has_documentation %} <i class="material-icons green{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Data complete" %}" title="{% trans "Data complete" %}">check_circle</i> {% elif not register_object.period %} {% period_to_time_start week register_object.raw_period_from_on_day as time_start %} @@ -19,13 +19,13 @@ {% period_to_time_start week register_object.period as time_start %} {% period_to_time_end week register_object.period as time_end %} - {% if register_object.get_substitution.cancelled %} + {% if substitution.cancelled or register_object.get_substitution.cancelled %} <i class="material-icons red{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Lesson cancelled" %}" title="{% trans "Lesson cancelled" %}">cancel</i> {% elif now_dt > time_end %} <i class="material-icons red{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Missing data" %}" title="{% trans "Missing data" %}">history</i> {% elif now_dt > time_start and now_dt < time_end %} <i class="material-icons orange{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Pending" %}" title="{% trans "Pending" %}">more_horiz</i> - {% elif register_object.get_substitution %} + {% elif substitution or register_object.get_substitution %} <i class="material-icons orange{% firstof color_suffix "-text"%} tooltipped {{ css_class }}" data-position="bottom" data-tooltip="{% trans "Substitution" %}" title="{% trans "Substitution" %}">update</i> {% endif %} {% endif %} diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html b/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html new file mode 100644 index 0000000000000000000000000000000000000000..f13e6043935b6fe5b1e91915158cc12d39a8f2e0 --- /dev/null +++ b/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html @@ -0,0 +1,43 @@ +{% load i18n material_form django_tables2 %} +<div class="card"> + <div class="card-content"> + <div class="card-title">{% trans "Lesson filter" %}</div> + <form action="" method="get"> + {% form form=filter_form %}{% endform %} + <button type="submit" class="btn waves-effect waves-light"> + <i class="material-icons left">refresh</i> + {% trans "Update filters" %} + </button> + </form> + </div> +</div> + +{% if table %} + <div class="card"> + <div class="card-content"> + <form action="" method="post"> + {% csrf_token %} + <div class="row"> + <div class="col s12 {% if action_form %}m4 l4 xl6{% endif %}"> + <div class="card-title">{% trans "Lesson table" %}</div> + </div> + {% if action_form %} + <div class="col s12 m8 l8 xl6"> + <div class="col s12 m8"> + {% form form=action_form %}{% endform %} + </div> + <div class="col s12 m4"> + <button type="submit" class="btn waves-effect waves-primary"> + {% trans "Execute" %} + <i class="material-icons right">send</i> + </button> + </div> + </div> + {% endif %} + </div> + {% render_table table %} + + </form> + </div> + </div> +{% endif %} diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html index ca2d801d60cf9657be5378c38abf5903304a2ed7..1f8b6132fa0dee3033c7ea466e872e2ffd61fa64 100644 --- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html +++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html @@ -370,7 +370,7 @@ {% endfor %} {% for week in weeks %} - <h4>{% trans 'Lesson documentation for week' %} {{ week.week }}</h4> + <h4>{% trans 'Week' %} {{ week.week }}: {{ week.0 }}–{{ week.6 }}</h4> <table class="small-print"> <thead> @@ -401,7 +401,7 @@ {% endif %} "> {% if forloop.first %} - <th rowspan="{{ register_objects|length }}" class="lessons-day-head">{{ day }}</th> + <th rowspan="{{ register_objects|length }}" class="lessons-day-head">{{ day|date:"D" }}</th> {% endif %} <td class="lesson-pe"> {% if register_object.label_ != "event" %} @@ -473,7 +473,7 @@ </td> <td class="lesson-te"> {% if documentations.0.topic %} - {{ substitution.teachers.first.short_name|default:register_object.get_teachers.first.short_name }} + {{ register_object.get_teachers.first.short_name }} {% endif %} </td> </tr> diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py index 16ba0d0b9c5c4c976c26222a8542d3e96a93b1aa..8fb31b625ba068fc3c6ba731fe39155f9974d76e 100644 --- a/aleksis/apps/alsijil/urls.py +++ b/aleksis/apps/alsijil/urls.py @@ -100,4 +100,5 @@ urlpatterns = [ views.AssignGroupRoleMultipleView.as_view(), name="assign_group_role_multiple", ), + path("all/", views.AllRegisterObjectsView.as_view(), name="all_register_objects"), ] diff --git a/aleksis/apps/alsijil/util/alsijil_helpers.py b/aleksis/apps/alsijil/util/alsijil_helpers.py index 9aedcb24ea2c8dd2c529d273b701b082281786ea..20d1a94ab12811a2aa8e8b0664746bd4dbaed7bd 100644 --- a/aleksis/apps/alsijil/util/alsijil_helpers.py +++ b/aleksis/apps/alsijil/util/alsijil_helpers.py @@ -1,14 +1,19 @@ -from typing import List, Optional, Union +from datetime import date +from operator import itemgetter +from typing import Any, Dict, Iterable, List, Optional, Sequence, Union from django.db.models.expressions import Exists, OuterRef from django.db.models.query import Prefetch, QuerySet from django.db.models.query_utils import Q from django.http import HttpRequest +from django.utils.formats import date_format +from django.utils.translation import gettext as _ from calendarweek import CalendarWeek +from aleksis.apps.alsijil.forms import FilterRegisterObjectForm from aleksis.apps.alsijil.models import LessonDocumentation -from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod +from aleksis.apps.chronos.models import Event, ExtraLesson, Holiday, LessonPeriod from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk @@ -99,3 +104,277 @@ def register_objects_sorter(register_object: Union[LessonPeriod, Event, ExtraLes return register_object.period_from_on_day else: return 0 + + +def _filter_register_objects_by_dict( + filter_dict: Dict[str, Any], + register_objects: QuerySet[Union[LessonPeriod, Event, ExtraLesson]], + label_: str, +) -> QuerySet[Union[LessonPeriod, Event, ExtraLesson]]: + """Filter register objects by a dictionary generated through ``FilterRegisterObjectForm``.""" + if label_ == LessonPeriod.label_: + register_objects = register_objects.filter( + lesson__validity__school_term=filter_dict.get("school_term") + ) + else: + register_objects = register_objects.filter(school_term=filter_dict.get("school_term")) + register_objects = register_objects.distinct() + + if ( + filter_dict.get("date_start") + and filter_dict.get("date_end") + and label_ != LessonPeriod.label_ + ): + register_objects = register_objects.within_dates( + filter_dict.get("date_start"), filter_dict.get("date_end") + ) + + if filter_dict.get("person"): + if label_ == LessonPeriod.label_: + register_objects = register_objects.filter( + Q(lesson__teachers=filter_dict.get("person")) + | Q(substitutions__teachers=filter_dict.get("person")) + ) + else: + register_objects = register_objects.filter_teacher(filter_dict.get("person")) + + if filter_dict.get("group"): + register_objects = register_objects.filter_group(filter_dict.get("group")) + + if filter_dict.get("groups"): + register_objects = register_objects.filter_groups(filter_dict.get("groups")) + + if filter_dict.get("subject"): + if label_ == LessonPeriod.label_: + register_objects = register_objects.filter( + Q(lesson__subject=filter_dict.get("subject")) + | Q(substitutions__subject=filter_dict.get("subject")) + ) + elif label_ == Event.label_: + # As events have no subject, we exclude them at all + register_objects = register_objects.none() + else: + register_objects = register_objects.filter(subject=filter_dict.get("subject")) + + return register_objects + + +def _generate_dicts_for_lesson_periods( + filter_dict: Dict[str, Any], + lesson_periods: QuerySet[LessonPeriod], + documentations: Optional[Iterable[LessonDocumentation]] = None, + holiday_days: Optional[Sequence[date]] = None, +) -> List[Dict[str, Any]]: + """Generate a list of dicts for use with ``RegisterObjectTable``.""" + if not holiday_days: + holiday_days = [] + date_start = lesson_periods.first().lesson.validity.date_start + date_end = lesson_periods.last().lesson.validity.date_end + if ( + filter_dict["filter_date"] + and filter_dict.get("date_start") > date_start + and filter_dict.get("date_start") < date_end + ): + date_start = filter_dict.get("date_start") + if ( + filter_dict["filter_date"] + and filter_dict.get("date_end") < date_end + and filter_dict.get("date_end") > date_start + ): + date_end = filter_dict.get("date_end") + weeks = CalendarWeek.weeks_within(date_start, date_end) + + register_objects = [] + for lesson_period in lesson_periods: + for week in weeks: + day = week[lesson_period.period.weekday] + + # Skip all lesson periods in holidays + if day in holiday_days: + continue + # Ensure that the lesson period is in filter range and validity range + if ( + lesson_period.lesson.validity.date_start + <= day + <= lesson_period.lesson.validity.date_end + ) and ( + not filter_dict.get("filter_date") + or (filter_dict.get("date_start") <= day <= filter_dict.get("date_end")) + ): + sub = lesson_period.get_substitution() + + # Skip lesson period if the person isn't a teacher + # or substitution teacher of this lesson period + if filter_dict.get("person") and ( + filter_dict.get("person") not in lesson_period.lesson.teachers.all() and not sub + ): + continue + + teachers = lesson_period.teacher_names + if ( + filter_dict.get("subject") + and filter_dict.get("subject") != lesson_period.get_subject() + ): + continue + + # Filter matching documentations and annotate if they exist + filtered_documentations = list( + filter( + lambda d: d.week == week.week + and d.year == week.year + and d.lesson_period_id == lesson_period.pk, + documentations + if documentations is not None + else lesson_period.documentations.all(), + ) + ) + has_documentation = bool(filtered_documentations) + + if filter_dict.get( + "has_documentation" + ) is not None and has_documentation != filter_dict.get("has_documentation"): + continue + + # Build table entry + entry = { + "pk": f"lesson_period_{lesson_period.pk}_{week.year}_{week.week}", + "week": week, + "has_documentation": has_documentation, + "substitution": sub, + "register_object": lesson_period, + "date": date_format(day), + "date_sort": day, + "period": f"{lesson_period.period.period}.", + "period_sort": lesson_period.period.period, + "groups": lesson_period.lesson.group_names, + "teachers": teachers, + "subject": lesson_period.get_subject().name, + } + if has_documentation: + doc = filtered_documentations[0] + entry["topic"] = doc.topic + entry["homework"] = doc.homework + entry["group_note"] = doc.group_note + register_objects.append(entry) + return register_objects + + +def _generate_dicts_for_events_and_extra_lessons( + filter_dict: Dict[str, Any], + register_objects_start: Sequence[Union[Event, ExtraLesson]], + documentations: Optional[Iterable[LessonDocumentation]] = None, +) -> List[Dict[str, Any]]: + """Generate a list of dicts for use with ``RegisterObjectTable``.""" + register_objects = [] + for register_object in register_objects_start: + filtered_documentations = list( + filter( + lambda d: getattr(d, f"{register_object.label_}_id") == register_object.pk, + documentations + if documentations is not None + else register_object.documentations.all(), + ) + ) + has_documentation = bool(filtered_documentations) + + if filter_dict.get( + "has_documentation" + ) is not None and has_documentation != filter_dict.get("has_documentation"): + continue + + if isinstance(register_object, ExtraLesson): + day = date_format(register_object.day) + day_sort = register_object.day + period = f"{register_object.period.period}." + period_sort = register_object.period.period + else: + day = ( + f"{date_format(register_object.date_start)}" + f"–{date_format(register_object.date_end)}" + ) + day_sort = register_object.date_start + period = f"{register_object.period_from.period}.–{register_object.period_to.period}." + period_sort = register_object.period_from.period + + # Build table entry + entry = { + "pk": f"{register_object.label_}_{register_object.pk}", + "has_documentation": has_documentation, + "register_object": register_object, + "date": day, + "date_sort": day_sort, + "period": period, + "period_sort": period_sort, + "groups": register_object.group_names, + "teachers": register_object.teacher_names, + "subject": register_object.subject.name + if isinstance(register_object, ExtraLesson) + else _("Event"), + } + if has_documentation: + doc = filtered_documentations[0] + entry["topic"] = doc.topic + entry["homework"] = doc.homework + entry["group_note"] = doc.group_note + register_objects.append(entry) + + return register_objects + + +def generate_list_of_all_register_objects(filter_dict: Dict[str, Any]) -> List[Dict[str, Any]]: + """Generate a list of all register objects. + + This list can be filtered using ``filter_dict``. The following keys are supported: + - ``school_term`` (defaults to the current school term) + - ``date_start`` and ``date_end`` (defaults to the last thirty days) + - ``groups`` and/or ``groups`` + - ``person`` + - ``subject`` + """ + # Always force a value for school term, start and end date so that queries won't get too big + initial_filter_data = FilterRegisterObjectForm.get_initial() + filter_dict["school_term"] = filter_dict.get("school_term", initial_filter_data["school_term"]) + filter_dict["date_start"] = filter_dict.get("date_start", initial_filter_data["date_start"]) + filter_dict["date_end"] = filter_dict.get("date_end", initial_filter_data["date_end"]) + filter_dict["filter_date"] = bool(filter_dict.get("date_start")) and bool( + filter_dict.get("date_end") + ) + + # Get all holidays in the selected school term to sort all data in holidays out + holidays = Holiday.objects.within_dates( + filter_dict["school_term"].date_start, filter_dict["school_term"].date_end + ) + holiday_days = holidays.get_all_days() + + lesson_periods = _filter_register_objects_by_dict( + filter_dict, + LessonPeriod.objects.order_by("lesson__validity__date_start"), + LessonPeriod.label_, + ) + events = _filter_register_objects_by_dict( + filter_dict, Event.objects.exclude_holidays(holidays), Event.label_ + ) + extra_lessons = _filter_register_objects_by_dict( + filter_dict, ExtraLesson.objects.exclude_holidays(holidays), ExtraLesson.label_ + ) + + # Prefetch documentations for all register objects and substitutions for all lesson periods + # in order to prevent extra queries + documentations = LessonDocumentation.objects.not_empty().filter( + Q(event__in=events) + | Q(extra_lesson__in=extra_lessons) + | Q(lesson_period__in=lesson_periods) + ) + + if lesson_periods: + register_objects = _generate_dicts_for_lesson_periods( + filter_dict, lesson_periods, documentations, holiday_days + ) + register_objects += _generate_dicts_for_events_and_extra_lessons( + filter_dict, list(events) + list(extra_lessons), documentations + ) + + # Sort table entries by date and period and configure table + register_objects = sorted(register_objects, key=itemgetter("date_sort", "period_sort")) + return register_objects + return [] diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py index 5d87d14da98148d62202e181ceb1189519cbe869..628ae7ae5e0079fe402df9e44c84ef9c07a36877 100644 --- a/aleksis/apps/alsijil/util/predicates.py +++ b/aleksis/apps/alsijil/util/predicates.py @@ -1,13 +1,12 @@ from typing import Any, Union -from django.contrib.auth.models import Permission, User +from django.contrib.auth.models import User -from guardian.models import UserObjectPermission from rules import predicate from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod from aleksis.core.models import Group, Person -from aleksis.core.util.core_helpers import get_content_type_by_perm +from aleksis.core.util.predicates import check_object_permission from ..models import PersonalNote @@ -22,12 +21,25 @@ def is_none(user: User, obj: Any) -> bool: def is_lesson_teacher(user: User, obj: Union[LessonPeriod, Event, ExtraLesson]) -> bool: """Predicate for teachers of a lesson. - Checks whether the person linked to the user is a teacher - in the lesson or the substitution linked to the given LessonPeriod. + Checks whether the person linked to the user is a teacher in the register object. + If the register object is a lesson period and has a substitution linked, + this will **only** check if the person is one of the substitution teachers. + """ + if obj: + return user.person in obj.get_teachers().all() + return False + + +@predicate +def is_lesson_original_teacher(user: User, obj: Union[LessonPeriod, Event, ExtraLesson]) -> bool: + """Predicate for teachers of a lesson. + + Checks whether the person linked to the user is a teacher in the register object. + If the register object is a lesson period and has a substitution linked, + this will **also** check if the person is one of the substitution teachers. """ if obj: - sub = obj.get_substitution() if isinstance(obj, LessonPeriod) else None - if sub and sub in user.person.lesson_substitutions.all(): + if isinstance(obj, LessonPeriod) and user.person in obj.lesson.teachers.all(): return True return user.person in obj.get_teachers().all() return False @@ -115,16 +127,11 @@ def has_person_group_object_perm(perm: str): @predicate(name) def fn(user: User, obj: Person) -> bool: - ct = get_content_type_by_perm(perm) - permissions = Permission.objects.filter(content_type=ct, codename=perm) groups = obj.member_of.all() - qs = UserObjectPermission.objects.filter( - object_pk__in=list(groups.values_list("pk", flat=True)), - content_type=ct, - user=user, - permission__in=permissions, - ) - return qs.exists() + for group in groups: + if check_object_permission(user, perm, group, checker_obj=obj): + return True + return False return fn @@ -154,15 +161,9 @@ def has_lesson_group_object_perm(perm: str): def fn(user: User, obj: LessonPeriod) -> bool: if hasattr(obj, "lesson"): groups = obj.lesson.groups.all() - ct = get_content_type_by_perm(perm) - permissions = Permission.objects.filter(content_type=ct, codename=perm) - qs = UserObjectPermission.objects.filter( - object_pk__in=list(groups.values_list("pk", flat=True)), - content_type=ct, - user=user, - permission__in=permissions, - ) - return qs.exists() + for group in groups: + if check_object_permission(user, perm, group, checker_obj=obj): + return True return False return fn @@ -178,16 +179,10 @@ def has_personal_note_group_perm(perm: str): @predicate(name) def fn(user: User, obj: PersonalNote) -> bool: if hasattr(obj, "person"): - ct = get_content_type_by_perm(perm) - permissions = Permission.objects.filter(content_type=ct, codename=perm) groups = obj.person.member_of.all() - qs = UserObjectPermission.objects.filter( - object_pk__in=list(groups.values_list("pk", flat=True)), - content_type=ct, - user=user, - permission__in=permissions, - ) - return qs.exists() + for group in groups: + if check_object_permission(user, perm, group, checker_obj=obj): + return True return False return fn @@ -206,22 +201,35 @@ def is_own_personal_note(user: User, obj: PersonalNote) -> bool: @predicate def is_personal_note_lesson_teacher(user: User, obj: PersonalNote) -> bool: - """Predicate for teachers of a lesson referred to in the lesson period of a personal note. + """Predicate for teachers of a register object linked to a personal note. Checks whether the person linked to the user is a teacher - in the lesson or the substitution linked to the LessonPeriod of the given PersonalNote. + in the register object linked to the personal note. + If the register object is a lesson period and has a substitution linked, + this will **only** check if the person is one of the substitution teachers. """ if hasattr(obj, "register_object"): - if getattr(obj, "lesson_period", None): - sub = obj.lesson_period.get_substitution() - if sub and user.person in Person.objects.filter( - lesson_substitutions=obj.lesson_period.get_substitution() - ): - return True - return user.person in obj.register_object.get_teachers().all() + return False - return False + +@predicate +def is_personal_note_lesson_original_teacher(user: User, obj: PersonalNote) -> bool: + """Predicate for teachers of a register object linked to a personal note. + + Checks whether the person linked to the user is a teacher + in the register object linked to the personal note. + If the register object is a lesson period and has a substitution linked, + this will **also** check if the person is one of the substitution teachers. + """ + if hasattr(obj, "register_object"): + if ( + isinstance(obj.register_object, LessonPeriod) + and user.person in obj.lesson_period.lesson.teachers.all() + ): + return True + + return user.person in obj.register_object.get_teachers().all() return False diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py index 3891bfcb0c050612592a43c3dfcfbbea5278ee7c..edf9c1f892806dce1565ec352401a08434d073bf 100644 --- a/aleksis/apps/alsijil/views.py +++ b/aleksis/apps/alsijil/views.py @@ -4,7 +4,7 @@ from datetime import date, datetime, timedelta from typing import Any, Dict, Optional from django.core.exceptions import PermissionDenied -from django.db.models import Count, Exists, OuterRef, Prefetch, Q, Subquery, Sum +from django.db.models import Count, Exists, FilteredRelation, OuterRef, Prefetch, Q, Sum from django.db.models.expressions import Case, When from django.db.models.functions import Extract from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound @@ -13,12 +13,15 @@ from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.decorators import method_decorator from django.utils.translation import ugettext as _ +from django.views import View from django.views.decorators.cache import never_cache from django.views.generic import DetailView import reversion from calendarweek import CalendarWeek from django_tables2 import RequestConfig, SingleTableView +from guardian.core import ObjectPermissionChecker +from guardian.shortcuts import get_objects_for_user from reversion.views import RevisionMixin from rules.contrib.views import PermissionRequiredMixin, permission_required @@ -35,17 +38,20 @@ from aleksis.core.mixins import ( from aleksis.core.models import Group, Person, SchoolTerm from aleksis.core.util import messages from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional +from aleksis.core.util.predicates import check_global_permission from .forms import ( AssignGroupRoleForm, ExcuseTypeForm, ExtraMarkForm, + FilterRegisterObjectForm, GroupRoleAssignmentEditForm, GroupRoleForm, LessonDocumentationForm, PersonalNoteFormSet, PersonOverviewForm, RegisterAbsenceForm, + RegisterObjectActionForm, SelectForm, ) from .models import ( @@ -56,9 +62,17 @@ from .models import ( LessonDocumentation, PersonalNote, ) -from .tables import ExcuseTypeTable, ExtraMarkTable, GroupRoleTable, PersonalNoteTable +from .tables import ( + ExcuseTypeTable, + ExtraMarkTable, + GroupRoleTable, + PersonalNoteTable, + RegisterObjectSelectTable, + RegisterObjectTable, +) from .util.alsijil_helpers import ( annotate_documentations, + generate_list_of_all_register_objects, get_register_object_by_pk, get_timetable_instance_by_pk, register_objects_sorter, @@ -168,7 +182,9 @@ def register_object( # Group roles show_group_roles = request.user.person.preferences[ "alsijil__group_roles_in_lesson_view" - ] and request.user.has_perm("alsijil.view_assigned_grouproles", register_object) + ] and request.user.has_perm( + "alsijil.view_assigned_grouproles_for_register_object", register_object + ) if show_group_roles: groups = register_object.get_groups().all() group_roles = GroupRole.objects.with_assignments(date_of_lesson, groups) @@ -180,6 +196,14 @@ def register_object( request.POST or None, instance=lesson_documentation, prefix="lesson_documentation", ) + # Prefetch object permissions for all related groups of the register object + # because the object permissions are checked for all groups of the register object + # That has to be set as an attribute of the register object, + # so that the permission system can use the prefetched data. + checker = ObjectPermissionChecker(request.user) + checker.prefetch_perms(register_object.get_groups().all()) + register_object.set_object_permission_checker(checker) + # Create a formset that holds all personal notes for all persons in this lesson if not request.user.has_perm("alsijil.view_register_object_personalnote", register_object): persons = Person.objects.filter(pk=request.user.person.pk) @@ -383,46 +407,45 @@ def week_view( | Q(member_of__extra_lessons__in=extra_lessons_pk) ) - personal_notes_q = ( - Q( - personal_notes__week=wanted_week.week, - personal_notes__year=wanted_week.year, - personal_notes__lesson_period__in=lesson_periods_pk, - ) - | Q( - personal_notes__event__date_start__lte=wanted_week[6], - personal_notes__event__date_end__gte=wanted_week[0], - personal_notes__event__in=events_pk, - ) - | Q( - personal_notes__extra_lesson__week=wanted_week.week, - personal_notes__extra_lesson__year=wanted_week.year, - personal_notes__extra_lesson__in=extra_lessons_pk, + # Prefetch object permissions for persons and groups the persons are members of + # because the object permissions are checked for both persons and groups + checker = ObjectPermissionChecker(request.user) + checker.prefetch_perms(persons_qs) + checker.prefetch_perms(Group.objects.filter(members__in=persons_qs)) + + persons_qs = ( + Person.objects.filter(pk__in=persons_qs) + .select_related("primary_group") + .prefetch_related("primary_group__owners") + .annotate( + filtered_personal_notes=FilteredRelation( + "personal_notes", + condition=( + Q(personal_notes__event__in=events_pk) + | Q( + personal_notes__week=wanted_week.week, + personal_notes__year=wanted_week.year, + personal_notes__lesson_period__in=lesson_periods_pk, + ) + | Q(personal_notes__extra_lesson__in=extra_lessons_pk) + ), + ) ) - ) - - persons_qs = persons_qs.distinct().prefetch_related( - Prefetch( - "personal_notes", - queryset=PersonalNote.objects.filter( - Q( - week=wanted_week.week, - year=wanted_week.year, - lesson_period__in=lesson_periods_pk, - ) - | Q( - event__date_start__lte=wanted_week[6], - event__date_end__gte=wanted_week[0], - event__in=events_pk, - ) - | Q( - extra_lesson__week=wanted_week.week, - extra_lesson__year=wanted_week.year, - extra_lesson__in=extra_lessons_pk, - ) + .prefetch_related( + Prefetch( + "personal_notes", + queryset=PersonalNote.objects.filter( + Q(event__in=events_pk) + | Q( + week=wanted_week.week, + year=wanted_week.year, + lesson_period__in=lesson_periods_pk, + ) + | Q(extra_lesson__in=extra_lessons_pk) + ), ), - ), - "member_of__owners", + "member_of__owners", + ) ) # Annotate group roles @@ -435,27 +458,17 @@ def week_view( ) persons_qs = persons_qs.annotate( absences_count=Count( - "personal_notes", - filter=personal_notes_q & Q(personal_notes__absent=True,), - distinct=True, + "filtered_personal_notes", filter=Q(filtered_personal_notes__absent=True), ), unexcused_count=Count( - "personal_notes", - filter=personal_notes_q - & Q(personal_notes__absent=True, personal_notes__excused=False,), - distinct=True, - ), - tardiness_sum=Subquery( - Person.objects.filter(personal_notes_q) - .filter(pk=OuterRef("pk"),) - .distinct() - .annotate(tardiness_sum=Sum("personal_notes__late")) - .values("tardiness_sum") + "filtered_personal_notes", + filter=Q( + filtered_personal_notes__absent=True, filtered_personal_notes__excused=False + ), ), + tardiness_sum=Sum("filtered_personal_notes__late"), tardiness_count=Count( - "personal_notes", - filter=personal_notes_q & ~Q(personal_notes__late=0), - distinct=True, + "filtered_personal_notes", filter=Q(filtered_personal_notes__late__gt=0), ), ) @@ -463,9 +476,8 @@ def week_view( persons_qs = persons_qs.annotate( **{ extra_mark.count_label: Count( - "personal_notes", - filter=personal_notes_q & Q(personal_notes__extra_marks=extra_mark,), - distinct=True, + "filtered_personal_notes", + filter=Q(filtered_personal_notes__extra_marks=extra_mark), ) } ) @@ -477,6 +489,7 @@ def week_view( if note.lesson_period: note.lesson_period.annotate_week(wanted_week) personal_notes.append(note) + person.set_object_permission_checker(checker) persons.append({"person": person, "personal_notes": personal_notes}) else: persons = None @@ -633,7 +646,7 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse: (lesson_period, filtered_documentations, filtered_personal_notes, substitution) ) - persons = Person.objects.prefetch_related(None).select_related(None) + persons = group.members.prefetch_related(None).select_related(None) persons = group.generate_person_list_with_class_register_statistics(persons) prefetched_persons = [] @@ -679,7 +692,9 @@ def my_students(request: HttpRequest) -> HttpResponse: new_groups = [] for group in relevant_groups: - persons = group.generate_person_list_with_class_register_statistics() + persons = group.generate_person_list_with_class_register_statistics( + group.members.prefetch_related("primary_group__owners") + ) new_groups.append((group, persons)) context["groups"] = new_groups @@ -712,13 +727,18 @@ class StudentsList(PermissionRequiredMixin, DetailView): @permission_required( - "alsijil.view_person_overview", fn=objectgetter_optional(Person, "request.user.person", True), + "alsijil.view_person_overview", + fn=objectgetter_optional( + Person.objects.prefetch_related("member_of__owners"), "request.user.person", True + ), ) def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: context = {} - person = objectgetter_optional(Person, default="request.user.person", default_eval=True)( - request, id_ - ) + person = objectgetter_optional( + Person.objects.prefetch_related("member_of__owners"), + default="request.user.person", + default_eval=True, + )(request, id_) context["person"] = person person_personal_notes = ( @@ -731,6 +751,14 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp .annotate_date_range() ) + # Prefetch object permissions for groups the person is a member of + # because the object permissions are checked for all groups the person is a member of + # That has to be set as an attribute of the register object, + # so that the permission system can use the prefetched data. + checker = ObjectPermissionChecker(request.user) + checker.prefetch_perms(Group.objects.filter(members=person)) + person.set_object_permission_checker(checker) + if request.user.has_perm("alsijil.view_person_overview_personalnote", person): allowed_personal_notes = person_personal_notes.all() else: @@ -780,7 +808,11 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp "-school_term_start", "-order_year", "-order_week", "-order_weekday", "order_period", ) ) - context["personal_notes"] = personal_notes + personal_notes_list = [] + for note in personal_notes: + note.set_object_permission_checker(checker) + personal_notes_list.append(note) + context["personal_notes"] = personal_notes_list context["excuse_types"] = ExcuseType.objects.all() form = PersonOverviewForm(request, request.POST or None, queryset=PersonalNote.objects.all()) @@ -849,6 +881,20 @@ def overview_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResp context["excuse_types"] = excuse_types context["extra_marks"] = extra_marks + # Build filter with own form and logic as django-filter can't work with different models + filter_form = FilterRegisterObjectForm(request, request.GET or None, for_person=True) + filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {} + filter_dict["person"] = person + context["filter_form"] = filter_form + + register_objects = generate_list_of_all_register_objects(filter_dict) + if register_objects: + table = RegisterObjectTable(register_objects) + items_per_page = request.user.person.preferences[ + "alsijil__register_objects_table_items_per_page" + ] + RequestConfig(request, paginate={"per_page": items_per_page}).configure(table) + context["register_object_table"] = table return render(request, "alsijil/class_register/person.html", context) @@ -1187,3 +1233,51 @@ class GroupRoleAssignmentDeleteView( def get_success_url(self) -> str: pk = self.object.groups.first().pk return reverse("assigned_group_roles", args=[pk]) + + +class AllRegisterObjectsView(PermissionRequiredMixin, View): + """Provide overview of all register objects for coordinators.""" + + permission_required = "alsijil.view_register_objects_list" + + def get_context_data(self, request): + context = {} + # Filter selectable groups by permissions + groups = Group.objects.all() + if not check_global_permission(request.user, "alsijil.view_full_register"): + allowed_groups = get_objects_for_user( + self.request.user, "core.view_full_register_group", Group + ).values_list("pk", flat=True) + groups = groups.filter(Q(parent_groups__in=allowed_groups) | Q(pk__in=allowed_groups)) + + # Build filter with own form and logic as django-filter can't work with different models + filter_form = FilterRegisterObjectForm( + request, request.GET or None, for_person=False, groups=groups + ) + filter_dict = filter_form.cleaned_data if filter_form.is_valid() else {} + filter_dict["groups"] = groups + context["filter_form"] = filter_form + + register_objects = generate_list_of_all_register_objects(filter_dict) + + self.action_form = RegisterObjectActionForm(request, register_objects, request.POST or None) + context["action_form"] = self.action_form + + if register_objects: + self.table = RegisterObjectSelectTable(register_objects) + items_per_page = request.user.person.preferences[ + "alsijil__register_objects_table_items_per_page" + ] + RequestConfig(request, paginate={"per_page": items_per_page}).configure(self.table) + context["table"] = self.table + return context + + def get(self, request: HttpRequest) -> HttpResponse: + context = self.get_context_data(request) + return render(request, "alsijil/class_register/all_objects.html", context) + + def post(self, request: HttpRequest): + context = self.get_context_data(request) + if self.action_form.is_valid(): + self.action_form.execute() + return render(request, "alsijil/class_register/all_objects.html", context) diff --git a/poetry.lock b/poetry.lock index 6e29f0e33972376d464d3bde59c4aef6b06fdea4..180a0d6f032ff4be9daa5bd5b714366d8bad25b9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,7 +8,7 @@ python-versions = "*" [[package]] name = "aleksis-app-chronos" -version = "2.0a4.dev0+20210112212026.c6be335f" +version = "2.0a3+20210112211100.fd5b0bed" description = "AlekSIS (School Information System) — App ΧÏόνος (digital timetables)" category = "main" optional = false @@ -25,7 +25,7 @@ reference = "gitlab" [[package]] name = "aleksis-builddeps" -version = "1" +version = "2" description = "AlekSIS (School Information System) — Build/Dev dependencies for apps" category = "dev" optional = false @@ -33,6 +33,7 @@ python-versions = "*" [package.dependencies] black = ">=19.10b0,<20.0" +curlylint = ">=0.12.0,<0.13.0" django-stubs = ">=1.1,<2.0" flake8 = ">=3.7.9,<4.0.0" flake8-bandit = ">=2.1.2,<3.0.0" @@ -43,11 +44,11 @@ flake8-docstrings = ">=1.5.0,<2.0.0" flake8-fixme = ">=1.1.1,<2.0.0" flake8-isort = ">=4.0.0,<5.0.0" flake8-mypy = ">=17.8.0,<18.0.0" -flake8-rst-docstrings = ">=0.0.13,<0.0.14" +flake8-rst-docstrings = ">=0.0.14,<0.0.15" isort = ">=5.0.0,<6.0.0" pytest = ">=6.0,<7.0" pytest-cov = ">=2.8.1,<3.0.0" -pytest-django = ">=3.7,<4.0" +pytest-django = ">=4.1,<5.0" pytest-django-testing-postgresql = ">=0.1,<0.2" pytest-sugar = ">=0.9.2,<0.10.0" safety = ">=1.8.5,<2.0.0" @@ -76,7 +77,7 @@ Celery = {version = ">=5.0.0,<6.0.0", extras = ["django", "redis"]} celery-haystack-ng = ">=0.20,<0.21" celery-progress = ">=0.0.14,<0.0.15" colour = ">=0.1.5,<0.2.0" -Django = ">=3.0,<4.0" +Django = ">=3.1.7,<4.0.0" django-any-js = ">=1.0,<2.0" django-bleach = ">=0.6.1,<0.7.0" django-cachalot = ">=2.3.2,<3.0.0" @@ -109,6 +110,7 @@ django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]} django-polymorphic = ">=3.0.0,<4.0.0" django-prometheus = ">=2.1.0,<3.0.0" django-pwa = ">=1.0.8,<2.0.0" +django-redis = ">=4.12.1,<5.0.0" django-reversion = ">=3.0.7,<4.0.0" django-sass-processor = ">=0.8,<0.9" django_select2 = ">=7.1,<8.0" @@ -116,6 +118,7 @@ django-settings-context-processor = ">=0.2,<0.3" django-tables2 = ">=2.1,<3.0" django-templated-email = ">=2.3.0,<3.0.0" django-two-factor-auth = {version = ">=1.12.1,<2.0.0", extras = ["call", "phonenumbers", "sms", "yubikey"]} +django-uwsgi-ng = ">=1.0.2,<2.0.0" django_widget_tweaks = ">=1.4.5,<2.0.0" django-yarnpkg = ">=6.0,<7.0" dynaconf = {version = ">=3.1,<4.0", extras = ["ini", "toml", "yaml"]} @@ -127,7 +130,6 @@ license-expression = ">=1.2,<2.0" Pillow = ">=8.0,<9.0" psutil = ">=5.7.0,<6.0.0" psycopg2 = ">=2.8,<3.0" -python-memcached = ">=1.59,<2.0" requests = ">=2.22,<3.0" rules = ">=2.2,<3.0" spdx-license-list = ">=0.5.0,<0.6.0" @@ -178,6 +180,14 @@ python-versions = ">=3.5" [package.extras] tests = ["pytest", "pytest-asyncio"] +[[package]] +name = "asn1crypto" +version = "1.4.0" +description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "atomicwrites" version = "1.4.0" @@ -503,6 +513,24 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] toml = ["toml"] +[[package]] +name = "curlylint" +version = "0.12.2" +description = "{{ 🎀}} Experimental HTML templates linting for Jinja, Nunjucks, Django templates, Twig, Liquid" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +attrs = ">=17.2.0" +click = ">=6.5" +parsy = "1.1.0" +pathspec = ">=0.6,<1" +toml = ">=0.9.4" + +[package.extras] +dev = ["black (==19.10b0)", "flake8 (==3.8.4)", "mypy (==0.812)", "pytest (==6.2.2)", "coverage (==5.4)"] + [[package]] name = "decorator" version = "4.4.2" @@ -583,7 +611,7 @@ Django = ">=1.8" [[package]] name = "django-cachalot" -version = "2.3.3" +version = "2.3.4" description = "Caches your Django ORM queries and automatically invalidates them." category = "main" optional = false @@ -594,11 +622,11 @@ Django = ">=2" [[package]] name = "django-cache-memoize" -version = "0.1.7" +version = "0.1.8" description = "Django utility for a memoization decorator that uses the Django cache framework." category = "main" optional = false -python-versions = ">=3.4" +python-versions = ">=3.5" [package.extras] dev = ["flake8", "tox", "twine", "therapist", "black"] @@ -845,7 +873,7 @@ python-versions = "*" [[package]] name = "django-material" -version = "1.7.5" +version = "1.7.6" description = "Material design for django forms and admin" category = "main" optional = false @@ -856,7 +884,7 @@ six = "*" [[package]] name = "django-menu-generator-ng" -version = "1.2.1" +version = "1.2.3" description = "A straightforward menu generator for Django" category = "main" optional = false @@ -960,6 +988,18 @@ python-versions = "*" [package.dependencies] django = ">=1.8" +[[package]] +name = "django-redis" +version = "4.12.1" +description = "Full featured redis cache backend for Django." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +Django = ">=2.2" +redis = ">=3.0.0" + [[package]] name = "django-render-block" version = "0.8.1" @@ -996,7 +1036,7 @@ management-command = ["django-compressor (>=2.4)"] [[package]] name = "django-select2" -version = "7.6.1" +version = "7.7.0" description = "Select2 option fields for Django" category = "main" optional = false @@ -1058,7 +1098,7 @@ six = ">=1" [[package]] name = "django-timezone-field" -version = "4.1.1" +version = "4.1.2" description = "A Django app providing database and form fields for pytz timezone objects." category = "main" optional = false @@ -1096,6 +1136,17 @@ phonenumberslite = ["phonenumberslite (>=7.0.9,<8.99)"] sms = ["twilio (>=6.0)"] yubikey = ["django-otp-yubikey"] +[[package]] +name = "django-uwsgi-ng" +version = "1.1.1" +description = "uWSGI stuff for Django projects" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +uwsgi = ["uwsgi"] + [[package]] name = "django-widget-tweaks" version = "1.4.8" @@ -1142,7 +1193,7 @@ pipenv = ["pipenv"] [[package]] name = "dynaconf" -version = "3.1.2" +version = "3.1.4" description = "The dynamic configurator for your Python Project" category = "main" optional = false @@ -1164,7 +1215,7 @@ yaml = ["ruamel.yaml"] [[package]] name = "faker" -version = "6.5.0" +version = "7.0.1" description = "Faker is a Python package that generates fake data for you." category = "main" optional = false @@ -1176,17 +1227,17 @@ text-unidecode = "1.3" [[package]] name = "flake8" -version = "3.8.4" +version = "3.9.0" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "flake8-bandit" @@ -1241,7 +1292,7 @@ flake8 = "*" [[package]] name = "flake8-docstrings" -version = "1.5.0" +version = "1.6.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" category = "dev" optional = false @@ -1301,7 +1352,7 @@ flake8 = "*" [[package]] name = "flake8-rst-docstrings" -version = "0.0.13" +version = "0.0.14" description = "Python docstring reStructuredText (RST) validator" category = "dev" optional = false @@ -1313,14 +1364,14 @@ restructuredtext_lint = "*" [[package]] name = "gitdb" -version = "4.0.5" +version = "4.0.7" description = "Git Object Database" category = "dev" optional = false python-versions = ">=3.4" [package.dependencies] -smmap = ">=3.0.1,<4" +smmap = ">=3.0.1,<5" [[package]] name = "gitpython" @@ -1359,7 +1410,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "3.7.0" +version = "3.10.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -1371,7 +1422,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -1383,7 +1434,7 @@ python-versions = "*" [[package]] name = "ipython" -version = "7.21.0" +version = "7.22.0" description = "IPython: Productive Interactive Computing" category = "main" optional = false @@ -1402,7 +1453,7 @@ pygments = "*" traitlets = ">=4.2" [package.extras] -all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.14)", "pygments", "qtconsole", "requests", "testpath"] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.16)", "pygments", "qtconsole", "requests", "testpath"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -1410,7 +1461,7 @@ nbformat = ["nbformat"] notebook = ["notebook", "ipywidgets"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.16)"] [[package]] name = "ipython-genutils" @@ -1422,7 +1473,7 @@ python-versions = "*" [[package]] name = "isort" -version = "5.7.0" +version = "5.8.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -1565,7 +1616,7 @@ pyparsing = ">=2.0.2" [[package]] name = "parso" -version = "0.8.1" +version = "0.8.2" description = "A Python Parser" category = "main" optional = false @@ -1575,6 +1626,14 @@ python-versions = ">=3.6" qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] testing = ["docopt", "pytest (<6.0.0)"] +[[package]] +name = "parsy" +version = "1.1.0" +description = "easy-to-use parser combinators, for parsing in pure Python" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "pathspec" version = "0.8.1" @@ -1612,18 +1671,18 @@ ptyprocess = ">=0.5" [[package]] name = "pg8000" -version = "1.17.0" +version = "1.19.0" description = "PostgreSQL interface library" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] -scramp = "1.2.0" +scramp = "1.3.0" [[package]] name = "phonenumbers" -version = "8.12.18" +version = "8.12.20" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." category = "main" optional = false @@ -1639,7 +1698,7 @@ python-versions = "*" [[package]] name = "pillow" -version = "8.1.1" +version = "8.1.2" description = "Python Imaging Library (Fork)" category = "main" optional = false @@ -1672,7 +1731,7 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.16" +version = "3.0.18" description = "Library for building powerful interactive command lines in Python" category = "main" optional = false @@ -1718,7 +1777,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pycodestyle" -version = "2.6.0" +version = "2.7.0" description = "Python style guide checker" category = "dev" optional = false @@ -1734,18 +1793,18 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pydocstyle" -version = "5.1.1" +version = "6.0.0" description = "Python docstring style checker" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] snowballstemmer = "*" [[package]] name = "pyflakes" -version = "2.2.0" +version = "2.3.1" description = "passive checker of Python programs" category = "dev" optional = false @@ -1753,7 +1812,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.8.0" +version = "2.8.1" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false @@ -1819,18 +1878,18 @@ testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", [[package]] name = "pytest-django" -version = "3.10.0" +version = "4.1.0" description = "A Django plugin for pytest." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [package.dependencies] -pytest = ">=3.6" +pytest = ">=5.4.0" [package.extras] docs = ["sphinx", "sphinx-rtd-theme"] -testing = ["django", "django-configurations (>=2.0)", "six"] +testing = ["django", "django-configurations (>=2.0)"] [[package]] name = "pytest-django-testing-postgresql" @@ -1883,17 +1942,6 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" [package.dependencies] six = ">=1.5" -[[package]] -name = "python-memcached" -version = "1.59" -description = "Pure python memcached client" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -six = ">=1.4.0" - [[package]] name = "pytz" version = "2021.1" @@ -1941,7 +1989,7 @@ hiredis = ["hiredis (>=0.1.3)"] [[package]] name = "regex" -version = "2020.11.13" +version = "2021.3.17" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -1978,14 +2026,14 @@ docutils = ">=0.11,<1.0" [[package]] name = "ruamel.yaml" -version = "0.16.12" +version = "0.17.2" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" category = "main" optional = false -python-versions = "*" +python-versions = ">=3" [package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""} +"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.10\""} [package.extras] docs = ["ryd"] @@ -2023,11 +2071,14 @@ requests = "*" [[package]] name = "scramp" -version = "1.2.0" +version = "1.3.0" description = "An implementation of the SCRAM protocol." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" + +[package.dependencies] +asn1crypto = "1.4.0" [[package]] name = "selenium" @@ -2050,11 +2101,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "smmap" -version = "3.0.5" +version = "4.0.0" description = "A pure Python implementation of a sliding window memory map manager" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "snowballstemmer" @@ -2066,7 +2117,7 @@ python-versions = "*" [[package]] name = "soupsieve" -version = "2.2" +version = "2.2.1" description = "A modern CSS selector implementation for Beautiful Soup." category = "main" optional = false @@ -2082,7 +2133,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.5.1" +version = "3.5.3" description = "Python documentation generator" category = "dev" optional = false @@ -2290,7 +2341,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tqdm" -version = "4.58.0" +version = "4.59.0" description = "Fast, Extensible Progress Meter" category = "main" optional = false @@ -2298,6 +2349,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" [package.extras] dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] telegram = ["requests"] [[package]] @@ -2316,7 +2368,7 @@ test = ["pytest"] [[package]] name = "twilio" -version = "6.53.0" +version = "6.55.0" description = "Twilio API client and TwiML generator" category = "main" optional = false @@ -2346,16 +2398,16 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.3" +version = "1.26.4" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotlipy (>=0.6.0)"] [[package]] name = "vine" @@ -2394,15 +2446,15 @@ pycryptodome = "*" [[package]] name = "zipp" -version = "3.4.0" +version = "3.4.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" @@ -2415,19 +2467,99 @@ alabaster = [ {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] aleksis-app-chronos = [ - {file = "AlekSIS-App-Chronos-2.0a4.dev0+20210112212026.c6be335f.tar.gz", hash = "sha256:0a8e394881cf9092668175d7304e4a540e6d8f8157d85282fa0001b933ce2c7b"}, - {file = "AlekSIS_App_Chronos-2.0a4.dev0+20210112212026.c6be335f-py3-none-any.whl", hash = "sha256:8fb0386cbf2bb82b5895851c076f64827e670dddc847a56a7457df91f9d2f5c0"}, + {file = "AlekSIS-App-Chronos-2.0a3+20210112211100.fd5b0bed.tar.gz", hash = "sha256:4224276a1237b641f07be5eba47cd96c33128d195a2ff2e85abf4465570a0a20"}, + {file = "AlekSIS_App_Chronos-2.0a3+20210112211100.fd5b0bed-py3-none-any.whl", hash = "sha256:7ec9f8f69f1ff87d78ce11c94f583c94a5bfe1453fc43359717e7a8d287b207f"}, ] aleksis-builddeps = [ - {file = "AlekSIS-Builddeps-1.tar.gz", hash = "sha256:97a19597f422593cbdc438aabf17f95748126c8951df6ac7db7991fc99c108c4"}, + {file = "AlekSIS-Builddeps-2.tar.gz", hash = "sha256:fdf8b230ba4a690c279d99004316e84d7d9d72962768ca6b3205df54db9abaab"}, ] aleksis-core = [ {file = "AlekSIS-Core-2.0a5.dev0+20210215073735.26fabd33.tar.gz", hash = "sha256:e367f4f23061435d8df7492eea3658dcf26a429c9ac95d58923e82e80ed52dac"}, {file = "AlekSIS-Core-2.0a5.dev0+20210217102451.bbdb8454.tar.gz", hash = "sha256:77dfe5726d2014afae043320da8552526cfa850ecae1a316cd3f8f24bf955930"}, {file = "AlekSIS-Core-2.0a5.dev0+20210217123802.d23be3b6.tar.gz", hash = "sha256:1489d70f360d0edf46d84d141f01af3fe3f12332b0bc99921ad20a174b4c211b"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210221200356.d50b445b.tar.gz", hash = "sha256:47c2dd168483dcfca23ade2d454cc9f067634ce379d85d4ddc8d5fd4d4b65d4e"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210221211436.3e258294.tar.gz", hash = "sha256:3602ed8c09f3c51db5924cc8f51f698cca4335f3b06653f681df47b64e3b7da1"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210221214851.77df2d66.tar.gz", hash = "sha256:a1b8b82dd1ed1cfe7c3c10acb43717a029ea51bad100db3cbec2e991ea1aee27"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210301214636.9313d3a8.tar.gz", hash = "sha256:624beca820c7efa4b866de528a7d6c93f15c2b5ea7629963966dfbbba5d6ee90"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210302092500.d579eec2.tar.gz", hash = "sha256:478e84e14a760384322cc5a43bd53a03c5a8cf934053765cc210dcae0cb45852"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210306112033.ae230406.tar.gz", hash = "sha256:4e724e17d42930dc01a67c5089843b759aa8704b241503d530bccfcb2dc2f096"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210306112300.2621edcd.tar.gz", hash = "sha256:a4def611a8fc89369deae26e5735eb5acb5a40efad2f14016d92dac606adf331"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210306211151.69c211aa.tar.gz", hash = "sha256:32e442ba003c2ef0ed7b69a4aa859e3e00ee38864f862cb9968494d639171d57"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210308111437.730e6da9.tar.gz", hash = "sha256:52aad11ada1fdaeb407c4f749a5a526f009e766438b5699c8b77b6f18fbbf62a"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210308142119.cf471364.tar.gz", hash = "sha256:edeaec9790e1289cafcbaa27ad2e064605f0313adf932c80c622d468001f9a87"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210309213501.5b41df20.tar.gz", hash = "sha256:9eed02d084dbb37f1301894842adb4549d6f42af7defe4bdb99bae91f967db34"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210309222921.8b4224ff.tar.gz", hash = "sha256:6101f6389d6012db5e007fffb59fdde82cf38ff78edca8407acd2d5848349563"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210309234035.c2392a1e.tar.gz", hash = "sha256:e5dd5a204cf76f5370c27be71363e8b47f48659cde17978b4d4136d785d6bd1e"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210310125949.adc66e60.tar.gz", hash = "sha256:ba71727e20baef09d59ed0b0addb5a2cf6b2917daf184991c76e1bdd04cc261a"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210310202452.afc803dc.tar.gz", hash = "sha256:29080cb23a59ce665d6c767ad5fbb7ed4e1cb4956495949b4d3d70db13a70746"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210310221521.397943ef.tar.gz", hash = "sha256:3dff597a0cb93bacf76531fedc3b15f0404d388349752dd61f7de2a3cceb21f8"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210310223742.cedf3588.tar.gz", hash = "sha256:ca6e4a4bcd6e381ed1336ac86f84ccafda3d1506a9068068e56b9adf925929fd"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311073153.1c949fe3.tar.gz", hash = "sha256:097a821179953b6e9ac4c00993c3b12a88bb6f2ae83399fcbefa65fbc1ae590b"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311073429.6778e4bb.tar.gz", hash = "sha256:970878c6cae8e8987c3a51bd13c24c8ec53a584303bfe914898c121ad0d77f4b"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311095122.aa90950c.tar.gz", hash = "sha256:3535f55091f2ef3834f0b549d674e0aaba7950e2df3114feef5942f51cbe3ea5"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311095353.64baf50d.tar.gz", hash = "sha256:de616a27bd7306881df170dd358d6ef8b7be24c7f5eb31ab10965a4273b1ac95"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311101050.58e1e474.tar.gz", hash = "sha256:0e100fd572007a77143c6d19aaf6d3c51ba45e1c0a74638a3cb9602c15ce401b"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311212733.a2e0b6d6.tar.gz", hash = "sha256:7e03149df93fec5710ff9d38e434af304752d402cc0502ecb264d433116f98d4"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311213645.b8d4f1de.tar.gz", hash = "sha256:4ca115541314b7a3244f69a7604f1b613a57b4569df4cf3b30d8dbf75e7ebe1e"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311215117.b76d2158.tar.gz", hash = "sha256:1819e728f07a9a757ca0f7a2497a84b13dd21867af8fc4364f1841cdec860885"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311220040.fcbefd57.tar.gz", hash = "sha256:72659b6c748b7171707652d8d0f6fb5d56d7d9195a1265b85a2be7c932fd99b6"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311222329.9772853a.tar.gz", hash = "sha256:afa97ffc37503a142a22343fd7382c15ac7841c71621c338deb0621db3012699"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311223437.62f15f74.tar.gz", hash = "sha256:f5671b509cb88dc49c828c264b0160efd32a5db99c361e2be774208e55919e20"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311225158.bb38fba5.tar.gz", hash = "sha256:b6efbba1e6be1150a60c2a86d677409159f071047199ec3b7d4cc09f124ae86d"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210311233614.da1cc7d8.tar.gz", hash = "sha256:80da1d262ac2500bb7c28b9c553e0607428a4ad6d1f41ad7e8d08765b9bc95ac"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312213819.374a2d20.tar.gz", hash = "sha256:5df1677f29ee353614be7008a133bc40a6d1de252d4ecccfb8613b22eee814ef"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312214810.08ce55c2.tar.gz", hash = "sha256:4a58ba4c175aded90dc8ab8655285a706fa31ab2532d23c89f5f797d06d7763b"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312221923.9a9d4f05.tar.gz", hash = "sha256:af436fb37b670827f00c7ef8f8cc5c59bdb1748f2505a356dc0aed5009d966e0"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312224345.c1b0f4c9.tar.gz", hash = "sha256:1b084bc26a138fdc0e92cd8ba62204c546a76793fef1f4bcc101e9c148096722"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312224955.cc9f2628.tar.gz", hash = "sha256:d5bd60678172c5074b5aefb016d151a74ad4a088d78469fd09b77a6207b56db7"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210312230855.97e05eea.tar.gz", hash = "sha256:ceae9423c5c43eb995aa2ad03a6609990fd8cb123b46b2eb8138b58f32ac12d4"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210313132725.3605ee54.tar.gz", hash = "sha256:6c3c239a4743a465e95204ba852996ece6d720bb123d78ac1d47a75b9f8cae20"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210313160435.c82d3215.tar.gz", hash = "sha256:a23f23402617ba46ebcea1d6a777fafe059dcd8a69c7ccd894182688a7b850b1"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210313161819.9d2cb0bd.tar.gz", hash = "sha256:275ce23d7913f8bce566fc9ba70ebcb44e31d8264e571c8e631f49b842a041df"}, + {file = "AlekSIS-Core-2.0a5.dev0+20210313174148.4d6213ac.tar.gz", hash = "sha256:4ed9f1423ac72327d1b5d160fc3c3349d2c18a38e34df2ba394c31a8d25e846a"}, {file = "AlekSIS_Core-2.0a5.dev0+20210215073735.26fabd33-py3-none-any.whl", hash = "sha256:9dbe21e49d7aa24f02a6f86ea0c4be8f36bc869bf01382a5bd16271c76cdf2ab"}, {file = "AlekSIS_Core-2.0a5.dev0+20210217102451.bbdb8454-py3-none-any.whl", hash = "sha256:0c5359f23d48e3d8482c2e13c973f76ec314c0a11241186affaad0a7c8ed655d"}, {file = "AlekSIS_Core-2.0a5.dev0+20210217123802.d23be3b6-py3-none-any.whl", hash = "sha256:381bb46e98b9dd6dfef638ade1cbfe837dd7c72779b6250819f99897c7050c6d"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210221200356.d50b445b-py3-none-any.whl", hash = "sha256:9375fc896a88143afc986d6c7ab7f77a0bd778f4b72d3790f4f46b313ba7c03f"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210221211436.3e258294-py3-none-any.whl", hash = "sha256:7071cb659ce20697b6e9eb026d081e4f3d9e4ede6c62b24f7181a99a4bb0be87"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210221214851.77df2d66-py3-none-any.whl", hash = "sha256:894698ee102d58991978d6f1cf333dbb197f70901feaee8859b1543095ba9dba"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210301214636.9313d3a8-py3-none-any.whl", hash = "sha256:ebd62082af682f81074b016a0422152ada039f11857df23db40ee8d84422e3a0"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210302092500.d579eec2-py3-none-any.whl", hash = "sha256:055c70da7f1f3fb9a4a50b06e27e68e3733f24b1cc3e34a804acd3e55c2f6731"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210306112033.ae230406-py3-none-any.whl", hash = "sha256:9b8e15f43ee97b6e05d80e4cc01d488b020ee33eeb04bbf4fc60e7a1bbcab438"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210306112300.2621edcd-py3-none-any.whl", hash = "sha256:964a053acb5295e6244dec2e783b9a955da2f4b5a1b30835dbacd10f9eeb8f47"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210306211151.69c211aa-py3-none-any.whl", hash = "sha256:4c35e1649fdedede4a4e36dbffb27a77d3e69f427fe712e70df110bc8441981f"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210308111437.730e6da9-py3-none-any.whl", hash = "sha256:7bee3d792788d478f754faa7b9ea197b46bd6c6f246858f086ef6b21853c8880"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210308142119.cf471364-py3-none-any.whl", hash = "sha256:82ddab57126671530a238938939e8b8985d685afccb7b7d363a228964a51685b"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210309213501.5b41df20-py3-none-any.whl", hash = "sha256:652e33c528c82c06916deaf5ffeb788c24bc9b46b055f43c86e92dc927a64893"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210309222921.8b4224ff-py3-none-any.whl", hash = "sha256:f051f3f61e2b1df790d3e18d31e1afacf2fd1a22c81091c7da2e3013256c7ed8"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210309234035.c2392a1e-py3-none-any.whl", hash = "sha256:89e3bfd7d175963ca3038a81bf52f796ac37da4bd8981def5bd2aa87f0d30060"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210310125949.adc66e60-py3-none-any.whl", hash = "sha256:d8e18d8af8f7fc0e68975ed6b42d71c341c5255042644cc7720f2a4ca3ef948d"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210310202452.afc803dc-py3-none-any.whl", hash = "sha256:6c0c20fd334a59563eb40274bc0a3a9f3732f68cfb0cf982aa1f624f6266825e"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210310221521.397943ef-py3-none-any.whl", hash = "sha256:aa8a068a9eb8a0685b5269d32ff119857ce539c070976fd2dbbf05d034ac83f7"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210310223742.cedf3588-py3-none-any.whl", hash = "sha256:4e8a19d0a31827741a32282480fa081568b8bad83afd29b1003b503ec4015a54"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311073153.1c949fe3-py3-none-any.whl", hash = "sha256:4fe7fa9a38bc9c473658b922079ea7152443f779682e19b3cda3a8c1010ccd58"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311073429.6778e4bb-py3-none-any.whl", hash = "sha256:23936aff8530fc3289eb914606ba0a7156585e54160d1e449169c96c1bd90d1b"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311095122.aa90950c-py3-none-any.whl", hash = "sha256:7793c1d89ab5a05af3e3e8eccabcff609ee4ec004fca14af5010dc9d634f61ca"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311095353.64baf50d-py3-none-any.whl", hash = "sha256:7cc5e5868c6c1563c89837ab64e68bff5eb3fe15d8660f2e93ec3cbf4c3ec851"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311101050.58e1e474-py3-none-any.whl", hash = "sha256:5b0e2bc2752c1b5dfcfa98abf7343df6a921e3ae7e6ba813141888df9ae314f8"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311212733.a2e0b6d6-py3-none-any.whl", hash = "sha256:9b97666b557aaabc42da698c2449f970cb58fd2f8e2d973c9b8c8049c3d3748b"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311213645.b8d4f1de-py3-none-any.whl", hash = "sha256:1e92aed183828ba86b4dccdc326b78ffeda5f558136c24321797d85d368978ba"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311215117.b76d2158-py3-none-any.whl", hash = "sha256:e492ef81457add25c9cb99a23eecf928827fcd0083951fb7acf0de3683a27316"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311220040.fcbefd57-py3-none-any.whl", hash = "sha256:15696633aeb7ba89022bdd4d940939f22ca7ae66acf08e04f47bd4b90d15e0e6"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311222329.9772853a-py3-none-any.whl", hash = "sha256:e9031355358e664069fcc8d9f64218b0b68f930b6f2db0128a36e2cc748106a6"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311223437.62f15f74-py3-none-any.whl", hash = "sha256:d4159e919cfa838f0be540c9aa811c410855f9195c42dd8bcea687bdd311f90e"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311225158.bb38fba5-py3-none-any.whl", hash = "sha256:1096bae8a1f8bbaee3bb6a8b4dbecc2c977e31b1c943ec552f291803b212fab9"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210311233614.da1cc7d8-py3-none-any.whl", hash = "sha256:3105fd5dd87d24b9d026d444c47a5c1db150e834e153f45019767318ddbff631"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312213819.374a2d20-py3-none-any.whl", hash = "sha256:215d64e895c6f54ab5ee9c46dfad4c4389f2517597a93f6edf4b08541c89df7f"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312214810.08ce55c2-py3-none-any.whl", hash = "sha256:67edce22b4f2e3628821cba4d5ed501badb3fe5f6f9d8494e6a8768d0056b3f0"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312221923.9a9d4f05-py3-none-any.whl", hash = "sha256:cbffc550fa0f11fab82af623fc8377b1631b9ff784ee40a982f50a4503426c00"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312224345.c1b0f4c9-py3-none-any.whl", hash = "sha256:1a2ecce6da1a489863c092000c27ea035db8bfe2adcbe0c36adb0978eafa68f9"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312224955.cc9f2628-py3-none-any.whl", hash = "sha256:6a7e01a4f4d1be22a3e4cd4e082b99bc3341e769b3aa497d28b9b93fa6c59908"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210312230855.97e05eea-py3-none-any.whl", hash = "sha256:a46751afa4ba04c34fd3ae33033d635d8294fa8f3b79dcb40935fcce1b3d80ea"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210313132725.3605ee54-py3-none-any.whl", hash = "sha256:fef23a584a48d3430f71a52dcb7153d7337144073b96777c24d19308e47fbe38"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210313160435.c82d3215-py3-none-any.whl", hash = "sha256:93cad09fccff4255b7161ff23ee16310d0555719376ffe2ac6ce8d50a6479e09"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210313161819.9d2cb0bd-py3-none-any.whl", hash = "sha256:cb3c5f02262ddfea7ce2fd29fc9018367724ee486f3b746cae8b409fe97f2d3b"}, + {file = "AlekSIS_Core-2.0a5.dev0+20210313174148.4d6213ac-py3-none-any.whl", hash = "sha256:9cf7f69a6241d780a562d09041fa70428507529acb9cd4380cb0a5dd1b91c1b8"}, ] amqp = [ {file = "amqp-5.0.5-py3-none-any.whl", hash = "sha256:1e759a7f202d910939de6eca45c23a107f6b71111f41d1282c648e9ac3d21901"}, @@ -2445,6 +2577,10 @@ asgiref = [ {file = "asgiref-3.3.1-py3-none-any.whl", hash = "sha256:5ee950735509d04eb673bd7f7120f8fa1c9e2df495394992c73234d526907e17"}, {file = "asgiref-3.3.1.tar.gz", hash = "sha256:7162a3cb30ab0609f1a4c95938fd73e8604f63bdba516a7f7d64b83ff09478f0"}, ] +asn1crypto = [ + {file = "asn1crypto-1.4.0-py2.py3-none-any.whl", hash = "sha256:4bcdf33c861c7d40bdcd74d8e4dd7661aac320fcdf40b9a3f95b4ee12fde2fa8"}, + {file = "asn1crypto-1.4.0.tar.gz", hash = "sha256:f4f6e119474e58e04a2b1af817eb585b4fd72bdd89b998624712b5c99be7641c"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -2530,6 +2666,7 @@ click-repl = [ ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] colour = [ {file = "colour-0.1.5-py2.py3-none-any.whl", hash = "sha256:33f6db9d564fadc16e59921a56999b79571160ce09916303d35346dddc17978c"}, @@ -2592,6 +2729,10 @@ coverage = [ {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] +curlylint = [ + {file = "curlylint-0.12.2-py3-none-any.whl", hash = "sha256:98bc15609ce858387dd70a28c7ddda96e82d0f1cb8bf51b8902532ce0fc1a97e"}, + {file = "curlylint-0.12.2.tar.gz", hash = "sha256:76b557cf8d007bd92df2dae61a02e65f8aa2ff3e05c6398b1314d92692fbb0d8"}, +] decorator = [ {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, @@ -2620,12 +2761,12 @@ django-bulk-update = [ {file = "django_bulk_update-2.2.0-py2.py3-none-any.whl", hash = "sha256:49a403392ae05ea872494d74fb3dfa3515f8df5c07cc277c3dc94724c0ee6985"}, ] django-cachalot = [ - {file = "django-cachalot-2.3.3.tar.gz", hash = "sha256:ba3a6cabf834139196179c4f6d77409ae9170267ee8ce40e27bbf6c3f6733b2b"}, - {file = "django_cachalot-2.3.3-py3-none-any.whl", hash = "sha256:55f94e94f7000f5f6bd92188d3d7535cfdef79f2e697e36daf69cba8f435e156"}, + {file = "django-cachalot-2.3.4.tar.gz", hash = "sha256:cb984972a3dfe87e7d2a64a235dfcb74a1dc6a152b433e2ba0badb5c06e4bf3c"}, + {file = "django_cachalot-2.3.4-py3-none-any.whl", hash = "sha256:4062026e4d797896a49165b1227d525b3ce08e3ccf643d4659e833c554a77c4c"}, ] django-cache-memoize = [ - {file = "django-cache-memoize-0.1.7.tar.gz", hash = "sha256:5e96349b0159aec1eb79257199a1902ea3ed538231ce7b4fee12e563127ca657"}, - {file = "django_cache_memoize-0.1.7-py2.py3-none-any.whl", hash = "sha256:bc7f53725558244af62197d0125732d7ec88ecc1281a3a2f37d77ae1a8c269d3"}, + {file = "django-cache-memoize-0.1.8.tar.gz", hash = "sha256:f85ca71ddfe3d61d561d5a382736f83148fb75e542585e7028b65d6d3681ec85"}, + {file = "django_cache_memoize-0.1.8-py3-none-any.whl", hash = "sha256:81b00714b50917431ce12a4544e0630a70c86fed27755a82186efc2945b8f8b3"}, ] django-celery-beat = [ {file = "django-celery-beat-2.2.0.tar.gz", hash = "sha256:b8a13afb15e7c53fc04f4f847ac71a6d32088959aba701eb7c4a59f0c28ba543"}, @@ -2713,12 +2854,11 @@ django-maintenance-mode = [ {file = "django_maintenance_mode-0.15.1-py3-none-any.whl", hash = "sha256:8c45b400253076655562c99a2ffb88f8353fc1c84496c1b9de812cc8132aea6f"}, ] django-material = [ - {file = "django-material-1.7.5.tar.gz", hash = "sha256:d0df25b1d3ff629a4dfe2bc869550b25289f556940b45fd6d7c4897859446491"}, - {file = "django_material-1.7.5-py2.py3-none-any.whl", hash = "sha256:141bdd1b3ded91be8c77f6de687523d63df986a559ec3eb82cd33f4af7d5983b"}, + {file = "django-material-1.7.6.tar.gz", hash = "sha256:5488e8fe24069cc6682801692ad05293a4b60a637a87a31e0ebd9f3319cd371d"}, + {file = "django_material-1.7.6-py2.py3-none-any.whl", hash = "sha256:b5496505da7dd92f23ca694bc411c6bf0ff584fc30f4239d890ab29f9260160c"}, ] django-menu-generator-ng = [ - {file = "django-menu-generator-ng-1.2.1.tar.gz", hash = "sha256:06097f6611913a0770d633b6fc02cc83af1d427cc42a4048ceefe5f3a0f9d3ab"}, - {file = "django_menu_generator_ng-1.2.1-py3-none-any.whl", hash = "sha256:f62679938b71795909653fa520e11e462401eaf5bfacf3f2608d7585beedeb52"}, + {file = "django-menu-generator-ng-1.2.3.tar.gz", hash = "sha256:0c21a094b094add909655728b6b2d4a8baa5a2047da8f649be52589bea0e3ba2"}, ] django-middleware-global-request = [ {file = "django-middleware-global-request-0.1.2.tar.gz", hash = "sha256:f6490759bc9f7dbde4001709554e29ca715daf847f2222914b4e47117dca9313"}, @@ -2751,6 +2891,10 @@ django-pwa = [ {file = "django-pwa-1.0.10.tar.gz", hash = "sha256:07ed9dd57108838e3fe44b551a82032ca4ed76e31cb3c3e8d51604e0fe7e81e9"}, {file = "django_pwa-1.0.10-py3-none-any.whl", hash = "sha256:b1a2057b1e72c40c3a14beb90b958482da185f1d40a141fcae3d76580984b930"}, ] +django-redis = [ + {file = "django-redis-4.12.1.tar.gz", hash = "sha256:306589c7021e6468b2656edc89f62b8ba67e8d5a1c8877e2688042263daa7a63"}, + {file = "django_redis-4.12.1-py3-none-any.whl", hash = "sha256:1133b26b75baa3664164c3f44b9d5d133d1b8de45d94d79f38d1adc5b1d502e5"}, +] django-render-block = [ {file = "django-render-block-0.8.1.tar.gz", hash = "sha256:edbc5d444cc50f3eb3387cf17f6f1014bf19d6018f680861cdeae9e0306003fa"}, {file = "django_render_block-0.8.1-py3-none-any.whl", hash = "sha256:903969efd0949f750c5fe71affe6e6b1ea66d03005c102a67fda36d5b9f4e1e1"}, @@ -2763,8 +2907,8 @@ django-sass-processor = [ {file = "django-sass-processor-0.8.2.tar.gz", hash = "sha256:9b46a12ca8bdcb397d46fbcc49e6a926ff9f76a93c5efeb23b495419fd01fc7a"}, ] django-select2 = [ - {file = "django-select2-7.6.1.tar.gz", hash = "sha256:25362c5bafe082a19add598fb0a69e3239b94759691a0ac8e01ab7fba8e650ad"}, - {file = "django_select2-7.6.1-py2.py3-none-any.whl", hash = "sha256:dc6b6fa737b6ea0b673e27c218955dd51a3fb81b2b28af93ce87703b24f4faf8"}, + {file = "django-select2-7.7.0.tar.gz", hash = "sha256:26b4c59cbeba57aea1737187b930a83c8070788286b4236b13f7873c01b32684"}, + {file = "django_select2-7.7.0-py2.py3-none-any.whl", hash = "sha256:e56bfe3074d6b87524c5dbc139884c18c74a5e7324d66f0b93e42b6012ea0dc0"}, ] django-settings-context-processor = [ {file = "django-settings-context-processor-0.2.tar.gz", hash = "sha256:d37c853d69a3069f5abbf94c7f4f6fc0fac38bbd0524190cd5a250ba800e496a"}, @@ -2781,13 +2925,16 @@ django-templated-email = [ {file = "django-templated-email-2.3.0.tar.gz", hash = "sha256:536c4e5ae099eabfb9aab36087d4d7799948c654e73da55a744213d086d5bb33"}, ] django-timezone-field = [ - {file = "django-timezone-field-4.1.1.tar.gz", hash = "sha256:b5b587aabed8db66eb3453691522164915c1aa1b326d8ddeadc8832a8580faeb"}, - {file = "django_timezone_field-4.1.1-py3-none-any.whl", hash = "sha256:068dc2c9b11c2230e126f511a515609d46f8cc49278b293e7536be07997fe892"}, + {file = "django-timezone-field-4.1.2.tar.gz", hash = "sha256:cffac62452d060e365938aa9c9f7b72d70d8b26b9c60243bce227b35abd1b9df"}, + {file = "django_timezone_field-4.1.2-py3-none-any.whl", hash = "sha256:897c06e40b619cf5731a30d6c156886a7c64cba3a90364832148da7ef32ccf36"}, ] django-two-factor-auth = [ {file = "django-two-factor-auth-1.13.tar.gz", hash = "sha256:24c2850a687c86800f4aa4131b7cebadf56f35be04ca359c4990578df1cc249a"}, {file = "django_two_factor_auth-1.13-py2.py3-none-any.whl", hash = "sha256:afb60e62f22b1f29a568666c0444ab05cabe8acc4d7c54d833d67f7b50f842fd"}, ] +django-uwsgi-ng = [ + {file = "django-uwsgi-ng-1.1.1.tar.gz", hash = "sha256:777023fd291c5408f18e2ac4922faf25f161075699e11bf40f86dd90c9b9f1d4"}, +] django-widget-tweaks = [ {file = "django-widget-tweaks-1.4.8.tar.gz", hash = "sha256:9f91ca4217199b7671971d3c1f323a2bec71a0c27dec6260b3c006fa541bc489"}, {file = "django_widget_tweaks-1.4.8-py2.py3-none-any.whl", hash = "sha256:f80bff4a8a59b278bb277a405a76a8b9a884e4bae7a6c70e78a39c626cd1c836"}, @@ -2804,16 +2951,16 @@ dparse = [ {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"}, ] dynaconf = [ - {file = "dynaconf-3.1.2-py2.py3-none-any.whl", hash = "sha256:808adfe964f10695846dbf8dad7632e47fc3bc38860fd1887ed57dddffc4eff2"}, - {file = "dynaconf-3.1.2.tar.gz", hash = "sha256:9b34ab2f811a81755f5eb4beac77a69e1e0887528c7e37fc4bc83fed52dcf502"}, + {file = "dynaconf-3.1.4-py2.py3-none-any.whl", hash = "sha256:e6f383b84150b70fc439c8b2757581a38a58d07962aa14517292dcce1a77e160"}, + {file = "dynaconf-3.1.4.tar.gz", hash = "sha256:b2f472d83052f809c5925565b8a2ba76a103d5dc1dbb9748b693ed67212781b9"}, ] faker = [ - {file = "Faker-6.5.0-py3-none-any.whl", hash = "sha256:90b69e9e05d622edb2fa5ebfda7bef41c88675cace85e72689fde5b8723d00a3"}, - {file = "Faker-6.5.0.tar.gz", hash = "sha256:da395fe545f40d4366b82b1a02448847a4586bd2b28af393b3edbd1e45d1e0fc"}, + {file = "Faker-7.0.1-py3-none-any.whl", hash = "sha256:08c4cfbfd498c0e90aff6741771c01803d894013df858db6a573182c6a47951f"}, + {file = "Faker-7.0.1.tar.gz", hash = "sha256:20c6e4253b73ef2a783d38e085e7c8d8916295fff31c7403116d2af8f908f7ca"}, ] flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, + {file = "flake8-3.9.0-py2.py3-none-any.whl", hash = "sha256:12d05ab02614b6aee8df7c36b97d1a3b2372761222b19b58621355e82acddcff"}, + {file = "flake8-3.9.0.tar.gz", hash = "sha256:78873e372b12b093da7b5e5ed302e8ad9e988b38b063b61ad937f26ca58fc5f0"}, ] flake8-bandit = [ {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"}, @@ -2830,8 +2977,8 @@ flake8-django = [ {file = "flake8_django-1.1.1-py3-none-any.whl", hash = "sha256:c71da0e61b6119dae91cbffdbdb00f1d6ebe3f5d0c43f5bf136929997ab0b72d"}, ] flake8-docstrings = [ - {file = "flake8-docstrings-1.5.0.tar.gz", hash = "sha256:3d5a31c7ec6b7367ea6506a87ec293b94a0a46c0bce2bb4975b7f1d09b6f3717"}, - {file = "flake8_docstrings-1.5.0-py2.py3-none-any.whl", hash = "sha256:a256ba91bc52307bef1de59e2a009c3cf61c3d0952dbe035d6ff7208940c2edc"}, + {file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"}, + {file = "flake8_docstrings-1.6.0-py2.py3-none-any.whl", hash = "sha256:99cac583d6c7e32dd28bbfbef120a7c0d1b6dde4adb5a9fd441c4227a6534bde"}, ] flake8-fixme = [ {file = "flake8-fixme-1.1.1.tar.gz", hash = "sha256:50cade07d27a4c30d4f12351478df87339e67640c83041b664724bda6d16f33a"}, @@ -2850,11 +2997,11 @@ flake8-polyfill = [ {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, ] flake8-rst-docstrings = [ - {file = "flake8-rst-docstrings-0.0.13.tar.gz", hash = "sha256:b1b619d81d879b874533973ac04ee5d823fdbe8c9f3701bfe802bb41813997b4"}, + {file = "flake8-rst-docstrings-0.0.14.tar.gz", hash = "sha256:8f8bcb18f1408b506dd8ba2c99af3eac6128f6911d4bf6ff874b94caa70182a2"}, ] gitdb = [ - {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"}, - {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"}, + {file = "gitdb-4.0.7-py3-none-any.whl", hash = "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0"}, + {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"}, ] gitpython = [ {file = "GitPython-3.1.14-py3-none-any.whl", hash = "sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b"}, @@ -2873,23 +3020,24 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.7.0-py3-none-any.whl", hash = "sha256:c6af5dbf1126cd959c4a8d8efd61d4d3c83bddb0459a17e554284a077574b614"}, - {file = "importlib_metadata-3.7.0.tar.gz", hash = "sha256:24499ffde1b80be08284100393955842be4a59c7c16bbf2738aad0e464a8e0aa"}, + {file = "importlib_metadata-3.10.0-py3-none-any.whl", hash = "sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe"}, + {file = "importlib_metadata-3.10.0.tar.gz", hash = "sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a"}, ] iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] ipython = [ - {file = "ipython-7.21.0-py3-none-any.whl", hash = "sha256:34207ffb2f653bced2bc8e3756c1db86e7d93e44ed049daae9814fed66d408ec"}, - {file = "ipython-7.21.0.tar.gz", hash = "sha256:04323f72d5b85b606330b6d7e2dc8d2683ad46c3905e955aa96ecc7a99388e70"}, + {file = "ipython-7.22.0-py3-none-any.whl", hash = "sha256:c0ce02dfaa5f854809ab7413c601c4543846d9da81010258ecdab299b542d199"}, + {file = "ipython-7.22.0.tar.gz", hash = "sha256:9c900332d4c5a6de534b4befeeb7de44ad0cc42e8327fa41b7685abde58cec74"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] isort = [ - {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, - {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, + {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, + {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, ] jedi = [ {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, @@ -2950,11 +3098,6 @@ markupsafe = [ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] mccabe = [ @@ -2994,8 +3137,12 @@ packaging = [ {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] parso = [ - {file = "parso-0.8.1-py2.py3-none-any.whl", hash = "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410"}, - {file = "parso-0.8.1.tar.gz", hash = "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e"}, + {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, + {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, +] +parsy = [ + {file = "parsy-1.1.0-py3-none-any.whl", hash = "sha256:25bd5cea2954950ebbfdf71f8bdaf7fd45a5df5325fd36a1064be2204d9d4c94"}, + {file = "parsy-1.1.0.tar.gz", hash = "sha256:36173ba01a5372c7a1b32352cc73a279a49198f52252adf1c8c1ed41d1f94e8d"}, ] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, @@ -3013,51 +3160,51 @@ pexpect = [ {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, ] pg8000 = [ - {file = "pg8000-1.17.0-py3-none-any.whl", hash = "sha256:3276fe9cf38fee4fd4006c64d50fa621841b550f0f068d88b4694ee423188a5f"}, - {file = "pg8000-1.17.0.tar.gz", hash = "sha256:14198c5afeb289106e40ee6e5e4c0529c5369939f6ca588a028b371a75fe20dd"}, + {file = "pg8000-1.19.0-py3-none-any.whl", hash = "sha256:046095e79f7b8414acd6f38f1b069f1d9c93ab058c7b77a9f0df6c7d586cb5fc"}, + {file = "pg8000-1.19.0.tar.gz", hash = "sha256:11ec70c0b20ea440807e2c869940f1484eea93d71b435807b63856dd82b744dd"}, ] phonenumbers = [ - {file = "phonenumbers-8.12.18-py2.py3-none-any.whl", hash = "sha256:f60b1cc7b424cdadf5c291ed839d1c623a46ca1e4d0a04d3e85d1fdf754c1a26"}, - {file = "phonenumbers-8.12.18.tar.gz", hash = "sha256:0aa0f5e1382d292a7ff2f8bc08673126521461c7f908e0220756449a734d8fef"}, + {file = "phonenumbers-8.12.20-py2.py3-none-any.whl", hash = "sha256:7c2b26ee026f765a8032fc2a333b46fa1860445c7ce6df3b717b9f6985106084"}, + {file = "phonenumbers-8.12.20.tar.gz", hash = "sha256:ee5a8508c4a414262abad92ec33f050347f681973ed0fb36e98b52bfe159f6b8"}, ] pickleshare = [ {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] pillow = [ - {file = "Pillow-8.1.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:14415e9e28410232370615dbde0cf0a00e526f522f665460344a5b96973a3086"}, - {file = "Pillow-8.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:924fc33cb4acaf6267b8ca3b8f1922620d57a28470d5e4f49672cea9a841eb08"}, - {file = "Pillow-8.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:df534e64d4f3e84e8f1e1a37da3f541555d947c1c1c09b32178537f0f243f69d"}, - {file = "Pillow-8.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4fe74636ee71c57a7f65d7b21a9f127d842b4fb75511e5d256ace258826eb352"}, - {file = "Pillow-8.1.1-cp36-cp36m-win32.whl", hash = "sha256:3e759bcc03d6f39bc751e56d86bc87252b9a21c689a27c5ed753717a87d53a5b"}, - {file = "Pillow-8.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:292f2aa1ae5c5c1451cb4b558addb88c257411d3fd71c6cf45562911baffc979"}, - {file = "Pillow-8.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8211cac9bf10461f9e33fe9a3af6c5131f3fdd0d10672afc2abb2c70cf95c5ca"}, - {file = "Pillow-8.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d30f30c044bdc0ab8f3924e1eeaac87e0ff8a27e87369c5cac4064b6ec78fd83"}, - {file = "Pillow-8.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7094bbdecb95ebe53166e4c12cf5e28310c2b550b08c07c5dc15433898e2238e"}, - {file = "Pillow-8.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1022f8f6dc3c5b0dcf928f1c49ba2ac73051f576af100d57776e2b65c1f76a8d"}, - {file = "Pillow-8.1.1-cp37-cp37m-win32.whl", hash = "sha256:a7d690b2c5f7e4a932374615fedceb1e305d2dd5363c1de15961725fe10e7d16"}, - {file = "Pillow-8.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:436b0a2dd9fe3f7aa6a444af6bdf53c1eb8f5ced9ea3ef104daa83f0ea18e7bc"}, - {file = "Pillow-8.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:c448d2b335e21951416a30cd48d35588d122a912d5fe9e41900afacecc7d21a1"}, - {file = "Pillow-8.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:bb18422ad00c1fecc731d06592e99c3be2c634da19e26942ba2f13d805005cf2"}, - {file = "Pillow-8.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3ec87bd1248b23a2e4e19e774367fbe30fddc73913edc5f9b37470624f55dc1f"}, - {file = "Pillow-8.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:99ce3333b40b7a4435e0a18baad468d44ab118a4b1da0af0a888893d03253f1d"}, - {file = "Pillow-8.1.1-cp38-cp38-win32.whl", hash = "sha256:2f0d7034d5faae9a8d1019d152ede924f653df2ce77d3bba4ce62cd21b5f94ae"}, - {file = "Pillow-8.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:07872f1d8421db5a3fe770f7480835e5e90fddb58f36c216d4a2ac0d594de474"}, - {file = "Pillow-8.1.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:69da5b1d7102a61ce9b45deb2920a2012d52fd8f4201495ea9411d0071b0ec22"}, - {file = "Pillow-8.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a40d7d4b17db87f5b9a1efc0aff56000e1d0d5ece415090c102aafa0ccbe858"}, - {file = "Pillow-8.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:01bb0a34f1a6689b138c0089d670ae2e8f886d2666a9b2f2019031abdea673c4"}, - {file = "Pillow-8.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:43b3c859912e8bf754b3c5142df624794b18eb7ae07cfeddc917e1a9406a3ef2"}, - {file = "Pillow-8.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3b13d89d97b551e02549d1f0edf22bed6acfd6fd2e888cd1e9a953bf215f0e81"}, - {file = "Pillow-8.1.1-cp39-cp39-win32.whl", hash = "sha256:c143c409e7bc1db784471fe9d0bf95f37c4458e879ad84cfae640cb74ee11a26"}, - {file = "Pillow-8.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c5e3c36f02c815766ae9dd91899b1c5b4652f2a37b7a51609f3bd467c0f11fb"}, - {file = "Pillow-8.1.1-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:8cf77e458bd996dc85455f10fe443c0c946f5b13253773439bcbec08aa1aebc2"}, - {file = "Pillow-8.1.1-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:c10af40ee2f1a99e1ae755ab1f773916e8bca3364029a042cd9161c400416bd8"}, - {file = "Pillow-8.1.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:ff83dfeb04c98bb3e7948f876c17513a34e9a19fd92e292288649164924c1b39"}, - {file = "Pillow-8.1.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9af590adc1e46898a1276527f3cfe2da8048ae43fbbf9b1bf9395f6c99d9b47"}, - {file = "Pillow-8.1.1-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:172acfaf00434a28dddfe592d83f2980e22e63c769ff4a448ddf7b7a38ffd165"}, - {file = "Pillow-8.1.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:33fdbd4f5608c852d97264f9d2e3b54e9e9959083d008145175b86100b275e5b"}, - {file = "Pillow-8.1.1-pp37-pypy37_pp73-win32.whl", hash = "sha256:59445af66b59cc39530b4f810776928d75e95f41e945f0c32a3de4aceb93c15d"}, - {file = "Pillow-8.1.1.tar.gz", hash = "sha256:f6fc18f9c9c7959bf58e6faf801d14fafb6d4717faaf6f79a68c8bb2a13dcf20"}, + {file = "Pillow-8.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:5cf03b9534aca63b192856aa601c68d0764810857786ea5da652581f3a44c2b0"}, + {file = "Pillow-8.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f91b50ad88048d795c0ad004abbe1390aa1882073b1dca10bfd55d0b8cf18ec5"}, + {file = "Pillow-8.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5762ebb4436f46b566fc6351d67a9b5386b5e5de4e58fdaa18a1c83e0e20f1a8"}, + {file = "Pillow-8.1.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e2cd8ac157c1e5ae88b6dd790648ee5d2777e76f1e5c7d184eaddb2938594f34"}, + {file = "Pillow-8.1.2-cp36-cp36m-win32.whl", hash = "sha256:72027ebf682abc9bafd93b43edc44279f641e8996fb2945104471419113cfc71"}, + {file = "Pillow-8.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d1d6bca39bb6dd94fba23cdb3eeaea5e30c7717c5343004d900e2a63b132c341"}, + {file = "Pillow-8.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:90882c6f084ef68b71bba190209a734bf90abb82ab5e8f64444c71d5974008c6"}, + {file = "Pillow-8.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:89e4c757a91b8c55d97c91fa09c69b3677c227b942fa749e9a66eef602f59c28"}, + {file = "Pillow-8.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8c4e32218c764bc27fe49b7328195579581aa419920edcc321c4cb877c65258d"}, + {file = "Pillow-8.1.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a01da2c266d9868c4f91a9c6faf47a251f23b9a862dce81d2ff583135206f5be"}, + {file = "Pillow-8.1.2-cp37-cp37m-win32.whl", hash = "sha256:30d33a1a6400132e6f521640dd3f64578ac9bfb79a619416d7e8802b4ce1dd55"}, + {file = "Pillow-8.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:71b01ee69e7df527439d7752a2ce8fb89e19a32df484a308eca3e81f673d3a03"}, + {file = "Pillow-8.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:5a2d957eb4aba9d48170b8fe6538ec1fbc2119ffe6373782c03d8acad3323f2e"}, + {file = "Pillow-8.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:87f42c976f91ca2fc21a3293e25bd3cd895918597db1b95b93cbd949f7d019ce"}, + {file = "Pillow-8.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:15306d71a1e96d7e271fd2a0737038b5a92ca2978d2e38b6ced7966583e3d5af"}, + {file = "Pillow-8.1.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:71f31ee4df3d5e0b366dd362007740106d3210fb6a56ec4b581a5324ba254f06"}, + {file = "Pillow-8.1.2-cp38-cp38-win32.whl", hash = "sha256:98afcac3205d31ab6a10c5006b0cf040d0026a68ec051edd3517b776c1d78b09"}, + {file = "Pillow-8.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:328240f7dddf77783e72d5ed79899a6b48bc6681f8d1f6001f55933cb4905060"}, + {file = "Pillow-8.1.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:bead24c0ae3f1f6afcb915a057943ccf65fc755d11a1410a909c1fefb6c06ad1"}, + {file = "Pillow-8.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81b3716cc9744ffdf76b39afb6247eae754186838cedad0b0ac63b2571253fe6"}, + {file = "Pillow-8.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:63cd413ac52ee3f67057223d363f4f82ce966e64906aea046daf46695e3c8238"}, + {file = "Pillow-8.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:8565355a29655b28fdc2c666fd9a3890fe5edc6639d128814fafecfae2d70910"}, + {file = "Pillow-8.1.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:1940fc4d361f9cc7e558d6f56ff38d7351b53052fd7911f4b60cd7bc091ea3b1"}, + {file = "Pillow-8.1.2-cp39-cp39-win32.whl", hash = "sha256:46c2bcf8e1e75d154e78417b3e3c64e96def738c2a25435e74909e127a8cba5e"}, + {file = "Pillow-8.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:aeab4cd016e11e7aa5cfc49dcff8e51561fa64818a0be86efa82c7038e9369d0"}, + {file = "Pillow-8.1.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:74cd9aa648ed6dd25e572453eb09b08817a1e3d9f8d1bd4d8403d99e42ea790b"}, + {file = "Pillow-8.1.2-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:e5739ae63636a52b706a0facec77b2b58e485637e1638202556156e424a02dc2"}, + {file = "Pillow-8.1.2-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:903293320efe2466c1ab3509a33d6b866dc850cfd0c5d9cc92632014cec185fb"}, + {file = "Pillow-8.1.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:5daba2b40782c1c5157a788ec4454067c6616f5a0c1b70e26ac326a880c2d328"}, + {file = "Pillow-8.1.2-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:1f93f2fe211f1ef75e6f589327f4d4f8545d5c8e826231b042b483d8383e8a7c"}, + {file = "Pillow-8.1.2-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:6efac40344d8f668b6c4533ae02a48d52fd852ef0654cc6f19f6ac146399c733"}, + {file = "Pillow-8.1.2-pp37-pypy37_pp73-win32.whl", hash = "sha256:f36c3ff63d6fc509ce599a2f5b0d0732189eed653420e7294c039d342c6e204a"}, + {file = "Pillow-8.1.2.tar.gz", hash = "sha256:b07c660e014852d98a00a91adfbe25033898a9d90a8f39beb2437d22a203fc44"}, ] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -3068,8 +3215,8 @@ prometheus-client = [ {file = "prometheus_client-0.9.0.tar.gz", hash = "sha256:9da7b32f02439d8c04f7777021c304ed51d9ec180604700c1ba72a4d44dceb03"}, ] prompt-toolkit = [ - {file = "prompt_toolkit-3.0.16-py3-none-any.whl", hash = "sha256:62c811e46bd09130fb11ab759012a4ae385ce4fb2073442d1898867a824183bd"}, - {file = "prompt_toolkit-3.0.16.tar.gz", hash = "sha256:0fa02fa80363844a4ab4b8d6891f62dd0645ba672723130423ca4037b80c1974"}, + {file = "prompt_toolkit-3.0.18-py3-none-any.whl", hash = "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04"}, + {file = "prompt_toolkit-3.0.18.tar.gz", hash = "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"}, ] psutil = [ {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, @@ -3125,8 +3272,8 @@ py = [ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pycryptodome = [ {file = "pycryptodome-3.10.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1c5e1ca507de2ad93474be5cfe2bfa76b7cf039a1a32fc196f40935944871a06"}, @@ -3161,16 +3308,16 @@ pycryptodome = [ {file = "pycryptodome-3.10.1.tar.gz", hash = "sha256:3e2e3a06580c5f190df843cdb90ea28d61099cf4924334d5297a995de68e4673"}, ] pydocstyle = [ - {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"}, - {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"}, + {file = "pydocstyle-6.0.0-py3-none-any.whl", hash = "sha256:d4449cf16d7e6709f63192146706933c7a334af7c0f083904799ccb851c50f6d"}, + {file = "pydocstyle-6.0.0.tar.gz", hash = "sha256:164befb520d851dbcf0e029681b91f4f599c62c5cd8933fd54b1bfbd50e89e1f"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.8.0-py3-none-any.whl", hash = "sha256:b21b072d0ccdf29297a82a2363359d99623597b8a265b8081760e4d0f7153c88"}, - {file = "Pygments-2.8.0.tar.gz", hash = "sha256:37a13ba168a02ac54cc5891a42b1caec333e59b66addb7fa633ea8a6d73445c0"}, + {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"}, + {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"}, ] pyjwt = [ {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"}, @@ -3189,8 +3336,8 @@ pytest-cov = [ {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"}, ] pytest-django = [ - {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"}, - {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"}, + {file = "pytest-django-4.1.0.tar.gz", hash = "sha256:26f02c16d36fd4c8672390deebe3413678d89f30720c16efb8b2a6bf63b9041f"}, + {file = "pytest_django-4.1.0-py3-none-any.whl", hash = "sha256:10e384e6b8912ded92db64c58be8139d9ae23fb8361e5fc139d8e4f8fc601bc2"}, ] pytest-django-testing-postgresql = [ {file = "pytest-django-testing-postgresql-0.1.post0.tar.gz", hash = "sha256:78b0c58930084cb4393407b2e5a2a3b8734c627b841ecef7d62d39bbfb8e8a45"}, @@ -3206,10 +3353,6 @@ python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] -python-memcached = [ - {file = "python-memcached-1.59.tar.gz", hash = "sha256:a2e28637be13ee0bf1a8b6843e7490f9456fd3f2a4cb60471733c7b5d5557e4f"}, - {file = "python_memcached-1.59-py2.py3-none-any.whl", hash = "sha256:4dac64916871bd3550263323fc2ce18e1e439080a2d5670c594cf3118d99b594"}, -] pytz = [ {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, @@ -3246,47 +3389,47 @@ redis = [ {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] regex = [ - {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, - {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, - {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, - {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, - {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, - {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, - {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, - {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, - {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, - {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, - {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, - {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, - {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, + {file = "regex-2021.3.17-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b97ec5d299c10d96617cc851b2e0f81ba5d9d6248413cd374ef7f3a8871ee4a6"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:cb4ee827857a5ad9b8ae34d3c8cc51151cb4a3fe082c12ec20ec73e63cc7c6f0"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:633497504e2a485a70a3268d4fc403fe3063a50a50eed1039083e9471ad0101c"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a59a2ee329b3de764b21495d78c92ab00b4ea79acef0f7ae8c1067f773570afa"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f85d6f41e34f6a2d1607e312820971872944f1661a73d33e1e82d35ea3305e14"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4651f839dbde0816798e698626af6a2469eee6d9964824bb5386091255a1694f"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:39c44532d0e4f1639a89e52355b949573e1e2c5116106a395642cbbae0ff9bcd"}, + {file = "regex-2021.3.17-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3d9a7e215e02bd7646a91fb8bcba30bc55fd42a719d6b35cf80e5bae31d9134e"}, + {file = "regex-2021.3.17-cp36-cp36m-win32.whl", hash = "sha256:159fac1a4731409c830d32913f13f68346d6b8e39650ed5d704a9ce2f9ef9cb3"}, + {file = "regex-2021.3.17-cp36-cp36m-win_amd64.whl", hash = "sha256:13f50969028e81765ed2a1c5fcfdc246c245cf8d47986d5172e82ab1a0c42ee5"}, + {file = "regex-2021.3.17-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9d8d286c53fe0cbc6d20bf3d583cabcd1499d89034524e3b94c93a5ab85ca90"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:201e2619a77b21a7780580ab7b5ce43835e242d3e20fef50f66a8df0542e437f"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d47d359545b0ccad29d572ecd52c9da945de7cd6cf9c0cfcb0269f76d3555689"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ea2f41445852c660ba7c3ebf7d70b3779b20d9ca8ba54485a17740db49f46932"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:486a5f8e11e1f5bbfcad87f7c7745eb14796642323e7e1829a331f87a713daaa"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:18e25e0afe1cf0f62781a150c1454b2113785401ba285c745acf10c8ca8917df"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:a2ee026f4156789df8644d23ef423e6194fad0bc53575534101bb1de5d67e8ce"}, + {file = "regex-2021.3.17-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:4c0788010a93ace8a174d73e7c6c9d3e6e3b7ad99a453c8ee8c975ddd9965643"}, + {file = "regex-2021.3.17-cp37-cp37m-win32.whl", hash = "sha256:575a832e09d237ae5fedb825a7a5bc6a116090dd57d6417d4f3b75121c73e3be"}, + {file = "regex-2021.3.17-cp37-cp37m-win_amd64.whl", hash = "sha256:8e65e3e4c6feadf6770e2ad89ad3deb524bcb03d8dc679f381d0568c024e0deb"}, + {file = "regex-2021.3.17-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a0df9a0ad2aad49ea3c7f65edd2ffb3d5c59589b85992a6006354f6fb109bb18"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b98bc9db003f1079caf07b610377ed1ac2e2c11acc2bea4892e28cc5b509d8d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:808404898e9a765e4058bf3d7607d0629000e0a14a6782ccbb089296b76fa8fe"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:5770a51180d85ea468234bc7987f5597803a4c3d7463e7323322fe4a1b181578"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:976a54d44fd043d958a69b18705a910a8376196c6b6ee5f2596ffc11bff4420d"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:63f3ca8451e5ff7133ffbec9eda641aeab2001be1a01878990f6c87e3c44b9d5"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bcd945175c29a672f13fce13a11893556cd440e37c1b643d6eeab1988c8b209c"}, + {file = "regex-2021.3.17-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:3d9356add82cff75413bec360c1eca3e58db4a9f5dafa1f19650958a81e3249d"}, + {file = "regex-2021.3.17-cp38-cp38-win32.whl", hash = "sha256:f5d0c921c99297354cecc5a416ee4280bd3f20fd81b9fb671ca6be71499c3fdf"}, + {file = "regex-2021.3.17-cp38-cp38-win_amd64.whl", hash = "sha256:14de88eda0976020528efc92d0a1f8830e2fb0de2ae6005a6fc4e062553031fa"}, + {file = "regex-2021.3.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4c2e364491406b7888c2ad4428245fc56c327e34a5dfe58fd40df272b3c3dab3"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_i686.whl", hash = "sha256:8bd4f91f3fb1c9b1380d6894bd5b4a519409135bec14c0c80151e58394a4e88a"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:882f53afe31ef0425b405a3f601c0009b44206ea7f55ee1c606aad3cc213a52c"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:07ef35301b4484bce843831e7039a84e19d8d33b3f8b2f9aab86c376813d0139"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:360a01b5fa2ad35b3113ae0c07fb544ad180603fa3b1f074f52d98c1096fa15e"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:709f65bb2fa9825f09892617d01246002097f8f9b6dde8d1bb4083cf554701ba"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:c66221e947d7207457f8b6f42b12f613b09efa9669f65a587a2a71f6a0e4d106"}, + {file = "regex-2021.3.17-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c782da0e45aff131f0bed6e66fbcfa589ff2862fc719b83a88640daa01a5aff7"}, + {file = "regex-2021.3.17-cp39-cp39-win32.whl", hash = "sha256:dc9963aacb7da5177e40874585d7407c0f93fb9d7518ec58b86e562f633f36cd"}, + {file = "regex-2021.3.17-cp39-cp39-win_amd64.whl", hash = "sha256:a0d04128e005142260de3733591ddf476e4902c0c23c1af237d9acf3c96e1b38"}, + {file = "regex-2021.3.17.tar.gz", hash = "sha256:4b8a1fb724904139149a43e172850f35aa6ea97fb0545244dc0b805e0154ed68"}, ] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, @@ -3296,8 +3439,8 @@ restructuredtext-lint = [ {file = "restructuredtext_lint-1.3.2.tar.gz", hash = "sha256:d3b10a1fe2ecac537e51ae6d151b223b78de9fafdd50e5eb6b08c243df173c80"}, ] "ruamel.yaml" = [ - {file = "ruamel.yaml-0.16.12-py2.py3-none-any.whl", hash = "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5"}, - {file = "ruamel.yaml-0.16.12.tar.gz", hash = "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"}, + {file = "ruamel.yaml-0.17.2-py3-none-any.whl", hash = "sha256:0850def9ebca23b3a8c64c4b4115ebb6b364a10d49f89d289a26ee965e1e7d9d"}, + {file = "ruamel.yaml-0.17.2.tar.gz", hash = "sha256:8f1e15421668b9edf30ed02899f5f81aff9808a4271935776f61a99a569a13da"}, ] "ruamel.yaml.clib" = [ {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc"}, @@ -3331,8 +3474,8 @@ safety = [ {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"}, ] scramp = [ - {file = "scramp-1.2.0-py3-none-any.whl", hash = "sha256:74815c25aad1fe0b5fb994e96c3de63e8695164358a80138352aaadfa4760350"}, - {file = "scramp-1.2.0.tar.gz", hash = "sha256:d6865ed1d135ddb124a619d7cd3a5b505f69a7c92e248024dd7e48bc77752af5"}, + {file = "scramp-1.3.0-py3-none-any.whl", hash = "sha256:6d73eae03e7a3d647a8c36ca95dc8082fe56496db6f803b561ab231627022f82"}, + {file = "scramp-1.3.0.tar.gz", hash = "sha256:f56208b544387b98e9d39735cc054e273d060efcdf44bb4a20935180772d1ccf"}, ] selenium = [ {file = "selenium-3.141.0-py2.py3-none-any.whl", hash = "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c"}, @@ -3343,24 +3486,24 @@ six = [ {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] smmap = [ - {file = "smmap-3.0.5-py2.py3-none-any.whl", hash = "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714"}, - {file = "smmap-3.0.5.tar.gz", hash = "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"}, + {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"}, + {file = "smmap-4.0.0.tar.gz", hash = "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182"}, ] snowballstemmer = [ {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, ] soupsieve = [ - {file = "soupsieve-2.2-py3-none-any.whl", hash = "sha256:d3a5ea5b350423f47d07639f74475afedad48cf41c0ad7a82ca13a3928af34f6"}, - {file = "soupsieve-2.2.tar.gz", hash = "sha256:407fa1e8eb3458d1b5614df51d9651a1180ea5fedf07feb46e45d7e25e6d6cdd"}, + {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, + {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, ] spdx-license-list = [ {file = "spdx_license_list-0.5.2-py3-none-any.whl", hash = "sha256:1b338470c7b403dbecceca563a316382c7977516128ca6c1e8f7078e3ed6e7b0"}, {file = "spdx_license_list-0.5.2.tar.gz", hash = "sha256:952996f72ab807972dc2278bb9b91e5294767211e51f09aad9c0e2ff5b82a31b"}, ] sphinx = [ - {file = "Sphinx-3.5.1-py3-none-any.whl", hash = "sha256:e90161222e4d80ce5fc811ace7c6787a226b4f5951545f7f42acf97277bfc35c"}, - {file = "Sphinx-3.5.1.tar.gz", hash = "sha256:11d521e787d9372c289472513d807277caafb1684b33eb4f08f7574c405893a9"}, + {file = "Sphinx-3.5.3-py3-none-any.whl", hash = "sha256:3f01732296465648da43dec8fb40dc451ba79eb3e2cc5c6d79005fd98197107d"}, + {file = "Sphinx-3.5.3.tar.gz", hash = "sha256:ce9c228456131bab09a3d7d10ae58474de562a6f79abb3dc811ae401cf8c1abc"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.11.1.tar.gz", hash = "sha256:244ba6d3e2fdb854622f643c7763d6f95b6886eba24bec28e86edf205e4ddb20"}, @@ -3426,15 +3569,15 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tqdm = [ - {file = "tqdm-4.58.0-py2.py3-none-any.whl", hash = "sha256:2c44efa73b8914dba7807aefd09653ac63c22b5b4ea34f7a80973f418f1a3089"}, - {file = "tqdm-4.58.0.tar.gz", hash = "sha256:c23ac707e8e8aabb825e4d91f8e17247f9cc14b0d64dd9e97be0781e9e525bba"}, + {file = "tqdm-4.59.0-py2.py3-none-any.whl", hash = "sha256:9fdf349068d047d4cfbe24862c425883af1db29bcddf4b0eeb2524f6fbdb23c7"}, + {file = "tqdm-4.59.0.tar.gz", hash = "sha256:d666ae29164da3e517fcf125e41d4fe96e5bb375cd87ff9763f6b38b5592fe33"}, ] traitlets = [ {file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"}, {file = "traitlets-5.0.5.tar.gz", hash = "sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396"}, ] twilio = [ - {file = "twilio-6.53.0.tar.gz", hash = "sha256:f2de0b83e3a2092cb7dee5a90c972db174c3e50e057163ea8858b95423493f84"}, + {file = "twilio-6.55.0.tar.gz", hash = "sha256:766555e9f3bdfe9eb2fad9e2efa701f6f7644337a3f6b31a660293d2fbd54331"}, ] typed-ast = [ {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, @@ -3474,8 +3617,8 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ - {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, - {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, + {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, + {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, ] vine = [ {file = "vine-5.0.0-py2.py3-none-any.whl", hash = "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30"}, @@ -3494,6 +3637,6 @@ yubiotp = [ {file = "YubiOTP-1.0.0.post1.tar.gz", hash = "sha256:c13825f7b76a69afb92f19521f4dea9f5031d70f45123b505dc2e0ac03132065"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ]