Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions trojstenid/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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),
),
]
19 changes: 15 additions & 4 deletions trojstenid/schools/models.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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"]
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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.")
Expand Down Expand Up @@ -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(),
}
42 changes: 37 additions & 5 deletions trojstenid/schools/templates/settings/school_list.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
{% extends "settings_base.html" %}
{% load forms %}

{% block title %}Školy - {{ block.super }}{% endblock %}

{% block content %}
<div class="mx-auto max-w-2xl">
<h2 class="text-xl font-bold text-gray-900">Informácie o školách</h2>

<form class="mt-6 space-y-6" method="post">
{% csrf_token %}
{% if current_school_record.needs_confirmation %}
<div class="rounded-md text-amber-800 bg-amber-50 p-4 mt-6 space-y-2">
<p>
<b>Skontroluj si prosím aktuálnosť údajov</b>
</p>
<p>
Podľa zadaných údajov navštevuješ tento školský rok
<strong>
{{ current_school_record.get_current_year_display }}
({{ current_school_record.school_type.short }})
</strong>
na škole <strong>{{ current_school_record.school }}</strong>.
</p>
<p>
Je to správne?
</p>
<div class="grid grid-cols-2 gap-2">
<a href="{% url 'account_school_create' %}" class="btn btn-blue">
<span data-icon="mdi:edit" class="iconify size-5"></span>
Zmeniť informácie o škole
</a>
<form method="POST" action="{% url 'account_school_verify' %}">
{% csrf_token %}
<button type="submit" class="btn btn-green">
<span data-icon="mdi:check-decagram" class="iconify size-5"></span>
Údaje sú aktuálne
</button>
</form>
</div>
</div>
{% endif %}

<div class="mt-6 space-y-6">
<div class="rounded-sm border overflow-hidden divide-y">
{% for record in object_list %}
<div class="p-4 flex justify-between items-center flex-wrap gap-y-2">
Expand Down Expand Up @@ -37,7 +66,10 @@ <h2 class="text-xl font-bold text-gray-900">Informácie o školách</h2>

<p class="text-gray-600 text-sm -mt-4">Pre zmenu historických dát kontaktuj <a href="mailto:info@trojsten.sk" class="link">info@trojsten.sk</a>.</p>

<a href="{% url 'account_school_create' %}" class="btn btn-blue">Zmeniť informácie o škole</a>
</form>
<a href="{% url 'account_school_create' %}" class="btn btn-blue">
<span data-icon="mdi:edit" class="iconify size-5"></span>
Zmeniť informácie o škole
</a>
</div>
</div>
{% endblock content %}
6 changes: 6 additions & 0 deletions trojstenid/schools/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
18 changes: 18 additions & 0 deletions trojstenid/schools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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"

Expand Down
4 changes: 2 additions & 2 deletions trojstenid/users/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -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",
Expand Down
Loading