diff --git a/trojstenid/app.css b/trojstenid/app.css index 130dc6b..7d8f46b 100644 --- a/trojstenid/app.css +++ b/trojstenid/app.css @@ -37,15 +37,19 @@ } .btn-blue { - @apply bg-blue-500 hover:bg-blue-600 focus-visible:outline-blue-600; + @apply bg-blue-500 hover:bg-blue-600 focus-visible:outline-blue-600; } .btn-black { - @apply bg-gray-900 hover:bg-gray-800 focus-visible:outline-gray-800; + @apply bg-gray-900 hover:bg-gray-800 focus-visible:outline-gray-800; } .btn-red { - @apply bg-red-500 hover:bg-red-600 focus-visible:outline-red-600; + @apply bg-red-500 hover:bg-red-600 focus-visible:outline-red-600; +} + +.btn-green { + @apply bg-green-600 hover:bg-green-700 focus-visible:outline-green-700; } .link { diff --git a/trojstenid/schools/migrations/0004_userschoolrecord_created_at_and_more.py b/trojstenid/schools/migrations/0004_userschoolrecord_created_at_and_more.py new file mode 100644 index 0000000..72164a8 --- /dev/null +++ b/trojstenid/schools/migrations/0004_userschoolrecord_created_at_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 5.2.16 on 2026-09-06 16:09 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ( + "trojstenid_schools", + "0003_alter_school_options_alter_schooltype_options_and_more", + ), + ] + + operations = [ + migrations.AddField( + model_name="userschoolrecord", + name="created_at", + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name="userschoolrecord", + name="updated_at", + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AlterField( + model_name="userschoolrecord", + name="created_at", + field=models.DateTimeField(auto_now_add=True), + ), + migrations.AlterField( + model_name="userschoolrecord", + name="updated_at", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/trojstenid/schools/models.py b/trojstenid/schools/models.py index df167e3..14b4cc5 100644 --- a/trojstenid/schools/models.py +++ b/trojstenid/schools/models.py @@ -1,5 +1,5 @@ from datetime import date, timedelta -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar from django.conf import settings from django.contrib.postgres.fields import ArrayField @@ -28,7 +28,7 @@ def __str__(self) -> str: return self.name -class SchoolQuerySet(models.QuerySet): +class SchoolQuerySet(models.QuerySet["School"]): def search(self, query: str): return self.filter( Q(name__unaccent__icontains=query) | Q(address__unaccent__icontains=query) @@ -43,7 +43,9 @@ class School(models.Model): types = models.ManyToManyField(SchoolType) is_selectable = models.BooleanField(default=True) - objects: SchoolQuerySet = SchoolQuerySet.as_manager() # pyright:ignore + objects: ClassVar[SchoolQuerySet] = ( + SchoolQuerySet.as_manager() + ) # ty: ignore[invalid-assignment] class Meta: ordering = ["eduid", "name"] @@ -107,7 +109,10 @@ class UserSchoolRecord(models.Model): start_year = models.PositiveIntegerField(default=0) end_date = models.DateField(blank=True, null=True) - objects: "UserSchoolRecordManager" = UserSchoolRecordManager() # pyright: ignore + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + objects: ClassVar["UserSchoolRecordManager"] = UserSchoolRecordManager() class Meta: ordering = ["user_id", "start_date"] @@ -141,6 +146,11 @@ def is_active(self): return False return True + def needs_confirmation(self): + return date_to_academic_year(self.updated_at) < date_to_academic_year( + timezone.now() + ) + def clean(self): if self.end_date and self.start_date >= self.end_date: raise ValidationError("Dátum nástupu musí byť skôr ako dátum ukončenia.") @@ -170,4 +180,5 @@ def to_dict(self) -> dict[str, Any]: "current_year": self.get_current_year(), "current_year_display": self.get_current_year_display(), "school_type": self.school_type.identifier, + "updated_at": self.updated_at.isoformat(), } diff --git a/trojstenid/schools/templates/settings/school_list.html b/trojstenid/schools/templates/settings/school_list.html index b4e3ebf..cac118d 100644 --- a/trojstenid/schools/templates/settings/school_list.html +++ b/trojstenid/schools/templates/settings/school_list.html @@ -1,5 +1,4 @@ {% extends "settings_base.html" %} -{% load forms %} {% block title %}Školy - {{ block.super }}{% endblock %} @@ -7,9 +6,39 @@

Informácie o školách

-
- {% csrf_token %} + {% if current_school_record.needs_confirmation %} +
+

+ Skontroluj si prosím aktuálnosť údajov +

+

+ Podľa zadaných údajov navštevuješ tento školský rok + + {{ current_school_record.get_current_year_display }} + ({{ current_school_record.school_type.short }}) + + na škole {{ current_school_record.school }}. +

+

+ Je to správne? +

+
+ + + Zmeniť informácie o škole + + + {% csrf_token %} + + +
+
+ {% endif %} +
{% for record in object_list %}
@@ -37,7 +66,10 @@

Informácie o školách

Pre zmenu historických dát kontaktuj info@trojsten.sk.

- Zmeniť informácie o škole - + + + Zmeniť informácie o škole + +
{% endblock content %} diff --git a/trojstenid/schools/urls.py b/trojstenid/schools/urls.py index 03441da..61b5322 100644 --- a/trojstenid/schools/urls.py +++ b/trojstenid/schools/urls.py @@ -3,11 +3,17 @@ from trojstenid.schools.views import ( SchoolRecordCreateView, SchoolRecordListView, + SchoolRecordVerifyView, SchoolSearchView, ) urlpatterns = [ path("accounts/school/", SchoolRecordListView.as_view(), name="account_school"), + path( + "accounts/school/verify/", + SchoolRecordVerifyView.as_view(), + name="account_school_verify", + ), path( "accounts/school/create/", SchoolRecordCreateView.as_view(), diff --git a/trojstenid/schools/views.py b/trojstenid/schools/views.py index 5432991..40e5f8b 100644 --- a/trojstenid/schools/views.py +++ b/trojstenid/schools/views.py @@ -8,6 +8,7 @@ from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property +from django.views import View from django.views.generic import FormView, ListView, TemplateView from trojstenid.schools.forms import SchoolRecordForm @@ -23,6 +24,13 @@ def get_queryset(self) -> QuerySet[Any]: "school", "school_type" ) + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + assert isinstance(self.request.user, User) + + ctx = super().get_context_data(**kwargs) + ctx["current_school_record"] = self.request.user.get_current_school_record() + return ctx + class SchoolRecordCreateView(LoginRequiredMixin, FormView): template_name = "settings/school_create.html" @@ -87,6 +95,16 @@ def save_record(self, form: SchoolRecordForm, record: UserSchoolRecord): return HttpResponseRedirect(reverse("account_school")) +class SchoolRecordVerifyView(LoginRequiredMixin, View): + http_method_names = ["post"] + + def post(self, request): + record = request.user.get_current_school_record() + if record is not None: + record.save() + return HttpResponseRedirect(reverse("account_school")) + + class SchoolSearchView(LoginRequiredMixin, TemplateView): template_name = "settings/school_search.html" diff --git a/trojstenid/users/serializers.py b/trojstenid/users/serializers.py index 172ac73..afff824 100644 --- a/trojstenid/users/serializers.py +++ b/trojstenid/users/serializers.py @@ -12,7 +12,7 @@ def to_representation(self, instance): class EmailAddressSerializer(serializers.ModelSerializer): - class Meta: # type:ignore + class Meta: model = EmailAddress fields = ["email", "verified", "primary"] @@ -25,7 +25,7 @@ class UserSerializer(serializers.ModelSerializer): emails = EmailAddressSerializer(many=True, source="emailaddress_set") avatar = serializers.SerializerMethodField() - class Meta: # type:ignore + class Meta: model = User fields = [ "id",