diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py index b2fd7980f947bc3cbd76c6bb9a1b6a0465ffe959..abd45aabdee3f9d933376a0fc034f59218a8523f 100644 --- a/aleksis/core/forms.py +++ b/aleksis/core/forms.py @@ -10,7 +10,7 @@ from dynamic_preferences.forms import PreferenceForm from material import Fieldset, Layout, Row from .mixins import ExtensibleForm -from .models import Announcement, Group, GroupType, Person +from .models import AdditionalField, Announcement, Group, GroupType, Person from .registries import ( group_preferences_registry, person_preferences_registry, @@ -127,7 +127,7 @@ class EditGroupForm(ExtensibleForm): layout = Layout( Fieldset(_("Common data"), "name", "short_name", "group_type"), Fieldset(_("Persons"), "members", "owners", "parent_groups"), - Fieldset(_("Additional fields"), "additional_fields"), + Fieldset(_("Additional data"), "additional_fields"), ) class Meta: @@ -151,6 +151,7 @@ class EditGroupForm(ExtensibleForm): "parent_groups": ModelSelect2MultipleWidget( search_fields=["name__icontains", "short_name__icontains"] ), + "additional_fields": ModelSelect2MultipleWidget(search_fields=["title__icontains",]), } @@ -283,6 +284,14 @@ class GroupPreferenceForm(PreferenceForm): registry = group_preferences_registry +class EditAdditionalFieldForm(forms.ModelForm): + """Form to manage additional fields.""" + + class Meta: + model = AdditionalField + exclude = [] + + class EditGroupTypeForm(forms.ModelForm): """Form to manage group types.""" diff --git a/aleksis/core/menus.py b/aleksis/core/menus.py index 4767a8f3492c7401a22164fe25f54da4ec9fd702..c1b19bb3970eac18d756ec0eae6bdaf8ae285d07 100644 --- a/aleksis/core/menus.py +++ b/aleksis/core/menus.py @@ -186,6 +186,17 @@ MENUS = { ) ], }, + { + "name": _("Additional fields"), + "url": "additional_fields", + "icon": "style", + "validators": [ + ( + "aleksis.core.util.predicates.permission_validator", + "core.view_additionalfield", + ) + ], + }, ], }, ], diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py index 3325f136af03b52deb9be44f765cc82e2e832b70..4f97eafddf3cfdb9725cf0e9e0cde05ef83d1ad0 100644 --- a/aleksis/core/rules.py +++ b/aleksis/core/rules.py @@ -1,6 +1,6 @@ from rules import add_perm, always_allow -from .models import Announcement, Group, GroupType, Person +from .models import AdditionalField, Announcement, Group, GroupType, Person from .util.predicates import ( has_any_object, has_global_perm, @@ -195,6 +195,33 @@ change_group_preferences = has_person & ( ) add_perm("core.change_group_preferences", change_group_preferences) + +# Edit additional field +change_additional_field_predicate = has_person & ( + has_global_perm("core.change_additionalfield") | has_object_perm("core.change_additionalfield") +) +add_perm("core.change_additionalfield", change_additional_field_predicate) + +# Edit additional field +create_additional_field_predicate = has_person & ( + has_global_perm("core.create_additionalfield") | has_object_perm("core.create_additionalfield") +) +add_perm("core.create_additionalfield", create_additional_field_predicate) + + +# Delete additional field +delete_additional_field_predicate = has_person & ( + has_global_perm("core.delete_additionalfield") | has_object_perm("core.delete_additionalfield") +) +add_perm("core.delete_additionalfield", delete_additional_field_predicate) + +# View additional fields +view_additional_field_predicate = has_person & ( + has_global_perm("core.view_additionalfield") + | has_any_object("core.view_additionalfield", AdditionalField) +) +add_perm("core.view_additionalfield", view_additional_field_predicate) + # Edit group type change_group_type_predicate = has_person & ( has_global_perm("core.change_grouptype") | has_object_perm("core.change_grouptype") diff --git a/aleksis/core/tables.py b/aleksis/core/tables.py index ff8fd871e75e9b97453784928d65456c5f857e8b..6f7ba041457f11420cf9155ff0cc8ca5012fd9d1 100644 --- a/aleksis/core/tables.py +++ b/aleksis/core/tables.py @@ -24,6 +24,22 @@ class GroupsTable(tables.Table): short_name = tables.LinkColumn("group_by_id", args=[A("id")]) +class AdditionalFieldsTable(tables.Table): + """Table to list group types.""" + + class Meta: + attrs = {"class": "responsive-table hightlight"} + + title = tables.LinkColumn("edit_additional_field_by_id", args=[A("id")]) + delete = tables.LinkColumn( + "delete_additional_field_by_id", + args=[A("id")], + verbose_name=_("Delete"), + text=_("Delete"), + attrs={"a": {"class": "btn-flat waves-effect waves-red"}}, + ) + + class GroupTypesTable(tables.Table): """Table to list group types.""" diff --git a/aleksis/core/templates/core/additional_fields.html b/aleksis/core/templates/core/additional_fields.html new file mode 100644 index 0000000000000000000000000000000000000000..1ba2a77a32c528b8443f4dc5a4c201b5739414fe --- /dev/null +++ b/aleksis/core/templates/core/additional_fields.html @@ -0,0 +1,18 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} + +{% load i18n %} +{% load render_table from django_tables2 %} + +{% block browser_title %}{% blocktrans %}Additional fields{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Additional fields{% endblocktrans %}{% endblock %} + +{% block content %} + <a class="btn green waves-effect waves-light" href="{% url 'create_additional_field' %}"> + <i class="material-icons left">add</i> + {% trans "Create additional field" %} + </a> + + {% render_table additional_fields_table %} +{% endblock %} diff --git a/aleksis/core/templates/core/edit_additional_field.html b/aleksis/core/templates/core/edit_additional_field.html new file mode 100644 index 0000000000000000000000000000000000000000..b1487eb259b44f1425c950574f7df845d4e22129 --- /dev/null +++ b/aleksis/core/templates/core/edit_additional_field.html @@ -0,0 +1,17 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} +{% load material_form i18n %} + +{% block browser_title %}{% blocktrans %}Edit additional field{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}Edit additional field{% endblocktrans %}{% endblock %} + +{% block content %} + + <form method="post"> + {% csrf_token %} + {% form form=edit_additional_field_form %}{% endform %} + {% include "core/save_button.html" %} + </form> + +{% endblock %} diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py index 47cb1d63c85c41b562e54909d553febac99c7625..07736f7b8a7f5e2655e0a26d7444cc8c6f1f2c6c 100644 --- a/aleksis/core/urls.py +++ b/aleksis/core/urls.py @@ -27,7 +27,23 @@ urlpatterns = [ path("person/<int:id_>", views.person, name="person_by_id"), path("person/<int:id_>/edit", views.edit_person, name="edit_person_by_id"), path("groups", views.groups, name="groups"), + path("groups/additional_fields", views.additional_fields, name="additional_fields"), path("groups/child_groups/", views.groups_child_groups, name="groups_child_groups"), + path( + "groups/additional_field/<int:id_>/edit", + views.edit_additional_field, + name="edit_additional_field_by_id", + ), + path( + "groups/additional_field/create", + views.edit_additional_field, + name="create_additional_field", + ), + path( + "groups/additional_field/<int:id_>/delete", + views.delete_additional_field, + name="delete_additional_field_by_id", + ), path("group/create", views.edit_group, name="create_group"), path("group/<int:id_>", views.group, name="group_by_id"), path("group/<int:id_>/edit", views.edit_group, name="edit_group_by_id"), diff --git a/aleksis/core/views.py b/aleksis/core/views.py index b5415c45d293218ac64d7003c905350ea02eb3ad..45b15be491c57a71f0375d7a962c4ab398cbaa18 100644 --- a/aleksis/core/views.py +++ b/aleksis/core/views.py @@ -21,6 +21,7 @@ from .filters import GroupFilter from .forms import ( AnnouncementForm, ChildGroupsForm, + EditAdditionalFieldForm, EditGroupForm, EditGroupTypeForm, EditPersonForm, @@ -29,13 +30,21 @@ from .forms import ( PersonsAccountsFormSet, SitePreferenceForm, ) -from .models import Announcement, DashboardWidget, Group, GroupType, Notification, Person +from .models import ( + AdditionalField, + Announcement, + DashboardWidget, + Group, + GroupType, + Notification, + Person, +) from .registries import ( group_preferences_registry, person_preferences_registry, site_preferences_registry, ) -from .tables import GroupsTable, GroupTypesTable, PersonsTable +from .tables import AdditionalFieldsTable, GroupsTable, GroupTypesTable, PersonsTable from .util import messages from .util.apps import AppConfig from .util.core_helpers import objectgetter_optional @@ -458,6 +467,71 @@ def preferences( return render(request, "dynamic_preferences/form.html", context) +@permission_required( + "core.change_additionalfield", fn=objectgetter_optional(AdditionalField, None, False) +) +def edit_additional_field(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: + """View to edit or create a additional_field.""" + context = {} + + additional_field = objectgetter_optional(AdditionalField, None, False)(request, id_) + context["additional_field"] = additional_field + + if id_: + # Edit form for existing additional_field + edit_additional_field_form = EditAdditionalFieldForm( + request.POST or None, instance=additional_field + ) + else: + if request.user.has_perm("core.create_additionalfield"): + # Empty form to create a new additional_field + edit_additional_field_form = EditAdditionalFieldForm(request.POST or None) + else: + raise PermissionDenied() + + if request.method == "POST": + if edit_additional_field_form.is_valid(): + edit_additional_field_form.save(commit=True) + + messages.success(request, _("The additional_field has been saved.")) + + return redirect("additional_fields") + + context["edit_additional_field_form"] = edit_additional_field_form + + return render(request, "core/edit_additional_field.html", context) + + +@permission_required("core.view_additionalfield") +def additional_fields(request: HttpRequest) -> HttpResponse: + """List view for listing all additional fields.""" + context = {} + + # Get all additional fields + additional_fields = get_objects_for_user( + request.user, "core.view_additionalfield", AdditionalField + ) + + # Build table + additional_fields_table = AdditionalFieldsTable(additional_fields) + RequestConfig(request).configure(additional_fields_table) + context["additional_fields_table"] = additional_fields_table + + return render(request, "core/additional_fields.html", context) + + +@permission_required( + "core.delete_additionalfield", fn=objectgetter_optional(AdditionalField, None, False) +) +def delete_additional_field(request: HttpRequest, id_: int) -> HttpResponse: + """View to delete an additional field.""" + additional_field = objectgetter_optional(AdditionalField, None, False)(request, id_) + additional_field.delete() + messages.success(request, _("The additional field has been deleted.")) + + return redirect("additional_fields") + + @permission_required("core.change_grouptype", fn=objectgetter_optional(GroupType, None, False)) def edit_group_type(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: """View to edit or create a group_type."""