diff --git a/fiesta/apps/sections/templates/sections/university_form.html b/fiesta/apps/fiestaforms/templates/fiestaforms/parts/ajax-form-container.html similarity index 76% rename from fiesta/apps/sections/templates/sections/university_form.html rename to fiesta/apps/fiestaforms/templates/fiestaforms/parts/ajax-form-container.html index c82712df..997829db 100644 --- a/fiesta/apps/sections/templates/sections/university_form.html +++ b/fiesta/apps/fiestaforms/templates/fiestaforms/parts/ajax-form-container.html @@ -1,4 +1,4 @@ -{# TODO: with support for title it's best to generalize it #} +{# TODO: support for title #}
diff --git a/fiesta/apps/sections/migrations/0021_alter_sectionuniversity_section_and_more.py b/fiesta/apps/sections/migrations/0021_alter_sectionuniversity_section_and_more.py new file mode 100644 index 00000000..fb9746ec --- /dev/null +++ b/fiesta/apps/sections/migrations/0021_alter_sectionuniversity_section_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2023-11-15 12:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('universities', '0003_alter_faculty_created_alter_faculty_university_and_more'), + ('sections', '0020_alter_section_created_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='sectionuniversity', + name='section', + field=models.ForeignKey(db_index=False, on_delete=django.db.models.deletion.RESTRICT, related_name='section_universities', to='sections.section', verbose_name='ESN section'), + ), + migrations.AlterField( + model_name='sectionuniversity', + name='university', + field=models.ForeignKey(db_index=False, on_delete=django.db.models.deletion.CASCADE, related_name='university_sections', to='universities.university', verbose_name='university'), + ), + ] diff --git a/fiesta/apps/sections/models/section.py b/fiesta/apps/sections/models/section.py index 3b22c168..98c8e9e6 100644 --- a/fiesta/apps/sections/models/section.py +++ b/fiesta/apps/sections/models/section.py @@ -143,12 +143,14 @@ class SectionUniversity(BaseTimestampedModel): "sections.Section", on_delete=models.RESTRICT, verbose_name=_("ESN section"), + related_name="section_universities", db_index=False, ) university = models.ForeignKey( "universities.University", on_delete=models.CASCADE, verbose_name=_("university"), + related_name="university_sections", db_index=False, ) diff --git a/fiesta/apps/sections/tables/faculties.py b/fiesta/apps/sections/tables/faculties.py index 98e29d7b..66bd0043 100644 --- a/fiesta/apps/sections/tables/faculties.py +++ b/fiesta/apps/sections/tables/faculties.py @@ -1,13 +1,18 @@ from __future__ import annotations from django.urls import reverse +from django.utils.translation import gettext_lazy as _ from django_tables2 import Column, tables from apps.universities.models import Faculty class UniversityFacultiesTable(tables.Table): - name = Column() + name = Column( + linkify=("sections:update-section-faculty", {"pk": tables.Accessor("pk")}), + # TODO: probably extract to constant in fiestatables + attrs={"a": {"x-data": lambda: "modal($el.href)", "x-bind": "bind"}}, + ) abbr = Column() members_count = Column( @@ -16,6 +21,10 @@ class UniversityFacultiesTable(tables.Table): internationals_count = Column( linkify=lambda record: reverse("sections:section-internationals") + f"?user__profile__faculty={record.pk}", ) + users_count = Column( + verbose_name=_("Total count*"), + attrs={"th": {"title": _("Including people from other sections.")}}, + ) class Meta: model = Faculty @@ -29,3 +38,5 @@ class Meta: ) attrs = dict(tbody={"hx-disable": True}) + + empty_text = _("No related faculties.") diff --git a/fiesta/apps/sections/templates/sections/universities.html b/fiesta/apps/sections/templates/sections/universities.html index 045a9728..46ca4548 100644 --- a/fiesta/apps/sections/templates/sections/universities.html +++ b/fiesta/apps/sections/templates/sections/universities.html @@ -26,11 +26,17 @@ {% for university, table in object_list|zip:tables %}
-

{{ university.name }}

- {# #} - +

+ {{ university.name }} + change +

+ {% translate "Add faculty" %}
{% render_table table %}
diff --git a/fiesta/apps/sections/urls.py b/fiesta/apps/sections/urls.py index be0e2245..8a251d91 100644 --- a/fiesta/apps/sections/urls.py +++ b/fiesta/apps/sections/urls.py @@ -18,12 +18,21 @@ SetupPluginFormView, ) from apps.sections.views.stats import SectionStatsView -from apps.sections.views.universities import NewSectionUniversityView, SectionUniversitiesView +from apps.sections.views.universities import ( + NewSectionFacultyView, + NewSectionUniversityView, + SectionUniversitiesView, + UpdateSectionFacultyView, + UpdateSectionUniversityView, +) register_model_converter(Section, field="space_slug", base=SlugConverter) urlpatterns = [ path("universities", SectionUniversitiesView.as_view(), name="section-universities"), path("universities/new", NewSectionUniversityView.as_view(), name="new-section-university"), + path("universities/", UpdateSectionUniversityView.as_view(), name="update-section-university"), + path("universities//faculties/new", NewSectionFacultyView.as_view(), name="new-section-faculty"), + path("universities/faculties/", UpdateSectionFacultyView.as_view(), name="update-section-faculty"), path("section-members", SectionMembersView.as_view(), name="section-members"), path("section-internationals", SectionInternationalsView.as_view(), name="section-internationals"), path("section-stats", SectionStatsView.as_view(), name="section-stats"), diff --git a/fiesta/apps/sections/views/universities.py b/fiesta/apps/sections/views/universities.py index 0a49aa1b..aeaa9b6b 100644 --- a/fiesta/apps/sections/views/universities.py +++ b/fiesta/apps/sections/views/universities.py @@ -3,9 +3,10 @@ from django.contrib.messages.views import SuccessMessageMixin from django.db import transaction from django.db.models import Count -from django.urls import reverse_lazy +from django.shortcuts import get_object_or_404 +from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ -from django.views.generic import CreateView +from django.views.generic import CreateView, UpdateView from apps.fiestaforms.views.htmx import HtmxFormMixin from apps.fiestatables.views.tables import FiestaMultiTableView @@ -13,7 +14,8 @@ from apps.sections.tables.faculties import UniversityFacultiesTable from apps.sections.views.mixins.membership import EnsurePrivilegedUserViewMixin from apps.sections.views.mixins.section_space import EnsureInSectionSpaceViewMixin -from apps.universities.forms import UniversityForm +from apps.universities.forms import FacultyForm, UniversityForm +from apps.universities.models import Faculty, University from apps.utils.models.query import Q from apps.utils.views import AjaxViewMixin @@ -28,7 +30,7 @@ class NewSectionUniversityView( ): form_class = UniversityForm template_name = "fiestaforms/pages/card_page_for_ajax_form.html" - ajax_template_name = "sections/university_form.html" + ajax_template_name = "fiestaforms/parts/ajax-form-container.html" success_url = reverse_lazy("sections:section-universities") success_message = _("University created successfully") @@ -50,6 +52,85 @@ def form_valid(self, form): return response +class UpdateSectionUniversityView( + EnsureInSectionSpaceViewMixin, + EnsurePrivilegedUserViewMixin, + HtmxFormMixin, + AjaxViewMixin, + SuccessMessageMixin, + UpdateView, +): + form_class = UniversityForm + template_name = "fiestaforms/pages/card_page_for_ajax_form.html" + ajax_template_name = "fiestaforms/parts/ajax-form-container.html" + + success_url = reverse_lazy("sections:section-universities") + success_message = _("University changed successfully") + + def get_queryset(self): + return University.objects.filter(university_sections__section=self.request.in_space_of_section) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form_url"] = reverse("sections:update-section-university", kwargs={"pk": self.object.pk}) + return context + + +class NewSectionFacultyView( + EnsureInSectionSpaceViewMixin, + EnsurePrivilegedUserViewMixin, + HtmxFormMixin, + AjaxViewMixin, + SuccessMessageMixin, + CreateView, +): + form_class = FacultyForm + template_name = "fiestaforms/pages/card_page_for_ajax_form.html" + ajax_template_name = "fiestaforms/parts/ajax-form-container.html" + + success_url = reverse_lazy("sections:section-universities") + success_message = _("Faculty created successfully") + + university: University = None + + def dispatch(self, request, *args, **kwargs): + self.university = get_object_or_404(University, pk=kwargs.get("pk")) + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form_url"] = reverse("sections:new-section-faculty", kwargs={"pk": self.university.pk}) + return context + + def form_valid(self, form): + form.instance.university = self.university + return super().form_valid(form) + + +class UpdateSectionFacultyView( + EnsureInSectionSpaceViewMixin, + EnsurePrivilegedUserViewMixin, + HtmxFormMixin, + AjaxViewMixin, + SuccessMessageMixin, + UpdateView, +): + form_class = FacultyForm + template_name = "fiestaforms/pages/card_page_for_ajax_form.html" + ajax_template_name = "fiestaforms/parts/ajax-form-container.html" + + success_url = reverse_lazy("sections:section-universities") + success_message = _("Faculty changed successfully") + + def get_queryset(self): + return Faculty.objects.filter(university__university_sections__section=self.request.in_space_of_section) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form_url"] = reverse("sections:update-section-faculty", kwargs={"pk": self.object.pk}) + return context + + class SectionUniversitiesView( EnsureInSectionSpaceViewMixin, EnsurePrivilegedUserViewMixin, @@ -89,6 +170,10 @@ def get_tables(self): faculty_user_profiles__user__memberships__role=SectionMembership.Role.INTERNATIONAL, ), ), + users_count=Count( + "faculty_user_profiles", + distinct=True, + ), ), ) for university in self.object_list diff --git a/fiesta/apps/universities/forms.py b/fiesta/apps/universities/forms.py index 5f8771cb..132c6e27 100644 --- a/fiesta/apps/universities/forms.py +++ b/fiesta/apps/universities/forms.py @@ -1,7 +1,5 @@ from __future__ import annotations -from django.forms import HiddenInput - from apps.fiestaforms.forms import BaseModelForm from apps.universities.models import Faculty, University @@ -22,9 +20,4 @@ class Meta: fields = ( "name", "abbr", - "university", ) - - widgets = { - "university": HiddenInput, - }