Organization tenancy and frontend #16

Merged
rixx merged 26 commits from 6-organizations into main 2025-03-21 12:32:53 +00:00
4 changed files with 51 additions and 22 deletions
Showing only changes of commit 31003c5c76 - Show all commits

View file

@ -9,10 +9,12 @@
{% partialdef org-name %} {% partialdef org-name %}
<td> <td>
{{ form.instance.name }} {{ form.instance.name }}
{% if has_change_permission %}
<button class="btn btn-primary" <button class="btn btn-primary"
hx-get="{{ request.path }}?fragment=org-name-edit&hx-single-field=name" hx-get="{{ request.path }}?fragment=org-name-edit&hx-single-field=name"
hx-target="closest td" hx-target="closest td"
hx-swap="outerHTML">{% translate "Edit" %}</button> hx-swap="outerHTML">{% translate "Edit" %}</button>
{% endif %}
</td> </td>
{% endpartialdef org-name %} {% endpartialdef org-name %}
{% partialdef org-name-edit %} {% partialdef org-name-edit %}

View file

@ -1,18 +1,18 @@
from django.conf import settings from django.conf import settings
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.views.generic import TemplateView, UpdateView from django.views.generic import TemplateView
from servala.core.models import User from servala.core.models import User
from servala.frontend.forms.profile import UserProfileForm from servala.frontend.forms.profile import UserProfileForm
from servala.frontend.views.mixins import HtmxMixin from servala.frontend.views.mixins import HtmxUpdateView
class IndexView(TemplateView): class IndexView(TemplateView):
template_name = "frontend/index.html" template_name = "frontend/index.html"
class ProfileView(HtmxMixin, UpdateView): class ProfileView(HtmxUpdateView):
template_name = "frontend/profile.html" template_name = "frontend/profile.html"
form_class = UserProfileForm form_class = UserProfileForm
success_url = reverse_lazy("frontend:profile") success_url = reverse_lazy("frontend:profile")

View file

@ -1,14 +1,34 @@
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.views.generic import TemplateView from django.views.generic import UpdateView
from rules.contrib.views import AutoPermissionRequiredMixin
class HtmxMixin(TemplateView): class HtmxUpdateView(AutoPermissionRequiredMixin, UpdateView):
fragments = [] fragments = []
@cached_property @cached_property
def is_htmx(self): def is_htmx(self):
return self.request.headers.get("HX-Request") return self.request.headers.get("HX-Request")
@property
def permission_type(self):
if self.request.method == "POST" or getattr(
self, "_test_write_permission", False
):
return "change"
return "view"
def has_change_permission(self):
self._test_write_permission = True
permission = self.get_permission_required()[0]
self._test_write_permission = False
return self.request.user.has_perm(permission, self.get_permission_object())
def get_context_data(self, **kwargs):
result = super().get_context_data(**kwargs)
result["has_change_permission"] = self.has_change_permission()
return result
def _get_fragment(self): def _get_fragment(self):
if self.request.method == "POST": if self.request.method == "POST":
fragment = self.request.POST.get("fragment") fragment = self.request.POST.get("fragment")

View file

@ -1,14 +1,16 @@
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.views.generic import FormView, TemplateView, UpdateView from django.views.generic import CreateView, DetailView
from rules.contrib.views import AutoPermissionRequiredMixin
from servala.core.models import Organization from servala.core.models import Organization
from servala.frontend.forms import OrganizationForm from servala.frontend.forms import OrganizationForm
from servala.frontend.views.mixins import HtmxMixin from servala.frontend.views.mixins import HtmxUpdateView
class OrganizationCreateView(FormView): class OrganizationCreateView(AutoPermissionRequiredMixin, CreateView):
form_class = OrganizationForm form_class = OrganizationForm
model = Organization
template_name = "frontend/organizations/create.html" template_name = "frontend/organizations/create.html"
def form_valid(self, form): def form_valid(self, form):
@ -18,27 +20,32 @@ class OrganizationCreateView(FormView):
return redirect(instance.urls.base) return redirect(instance.urls.base)
class OrganizationDashboardView(TemplateView): class OrganizationViewMixin:
template_name = "frontend/organizations/dashboard.html"
class OrganizationUpdateView(HtmxMixin, UpdateView):
template_name = "frontend/organizations/update.html"
form_class = OrganizationForm
fragments = ("org-name", "org-name-edit")
model = Organization model = Organization
context_object_name = "organization" context_object_name = "organization"
def get_success_url(self): @cached_property
return self.request.path def organization(self):
return self.request.organization
def get_object(self): def get_object(self):
return self.request.organization return self.organization
@cached_property @cached_property
def object(self): def object(self):
return self.get_object() return self.get_object()
def form_valid(self, form):
form.save() class OrganizationDashboardView(
return super().form_valid(form) AutoPermissionRequiredMixin, OrganizationViewMixin, DetailView
):
template_name = "frontend/organizations/dashboard.html"
class OrganizationUpdateView(OrganizationViewMixin, HtmxUpdateView):
template_name = "frontend/organizations/update.html"
form_class = OrganizationForm
fragments = ("org-name", "org-name-edit")
def get_success_url(self):
return self.request.path