# Refactoring team views
* refactors team views * split views.py into users.py and teams.py in users app * refactors method headers for _user_has_permission() * adds method and class comments and documentation to base view classes
This commit is contained in:
parent
bc2e901ca9
commit
f122778232
@ -59,7 +59,7 @@ class NewCompensationFormView(BaseNewSpatialLocatedObjectFormView):
|
|||||||
intervention = get_object_or_404(Intervention, id=intervention_id)
|
intervention = get_object_or_404(Intervention, id=intervention_id)
|
||||||
return intervention.is_shared_with(user)
|
return intervention.is_shared_with(user)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be an ets user
|
# User has to be an ets user
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ class EditCompensationFormView(BaseEditSpatialLocatedObjectFormView):
|
|||||||
_TEMPLATE = "compensation/form/view.html"
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
_REDIRECT_URL = "compensation:detail"
|
_REDIRECT_URL = "compensation:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be a default user
|
# User has to be a default user
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
@ -170,5 +170,5 @@ class RemoveCompensationView(LoginRequiredMixin, BaseRemoveModalFormView):
|
|||||||
_FORM_CLS = RemoveModalForm
|
_FORM_CLS = RemoveModalForm
|
||||||
_REDIRECT_URL = "compensation:index"
|
_REDIRECT_URL = "compensation:index"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class NewEcoAccountFormView(BaseNewSpatialLocatedObjectFormView):
|
|||||||
_TAB_TITLE = _("New Eco-Account")
|
_TAB_TITLE = _("New Eco-Account")
|
||||||
_REDIRECT_URL = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be a default user
|
# User has to be a default user
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class EditEcoAccountFormView(BaseEditSpatialLocatedObjectFormView):
|
|||||||
_TEMPLATE = "compensation/form/view.html"
|
_TEMPLATE = "compensation/form/view.html"
|
||||||
_REDIRECT_URL = "compensation:acc:detail"
|
_REDIRECT_URL = "compensation:acc:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be a default user
|
# User has to be a default user
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
@ -260,5 +260,5 @@ class RemoveEcoAccountView(LoginRequiredMixin, BaseRemoveModalFormView):
|
|||||||
_FORM_CLS = RemoveEcoAccountModalForm
|
_FORM_CLS = RemoveEcoAccountModalForm
|
||||||
_REDIRECT_URL = "compensation:acc:index"
|
_REDIRECT_URL = "compensation:acc:index"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class BasePaymentView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
url = super()._get_redirect_url(*args, **kwargs)
|
url = super()._get_redirect_url(*args, **kwargs)
|
||||||
return f"{url}#related_data"
|
return f"{url}#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,14 +16,14 @@ class NewEmaActionView(AbstractNewCompensationActionView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
class EditEmaActionView(AbstractEditCompensationActionView):
|
class EditEmaActionView(AbstractEditCompensationActionView):
|
||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -31,5 +31,5 @@ class RemoveEmaActionView(AbstractRemoveCompensationActionView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_ACCOUNT_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class NewEmaDeadlineView(AbstractNewDeadlineView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class EditEmaDeadlineView(AbstractEditDeadlineView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -30,5 +30,5 @@ class RemoveEmaDeadlineView(AbstractRemoveDeadlineView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
_REDIRECT_URL = _EMA_DETAIL_URL_NAME
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -16,14 +16,14 @@ class NewEmaDocumentView(AbstractNewDocumentView):
|
|||||||
_FORM_CLS = NewEmaDocumentModalForm
|
_FORM_CLS = NewEmaDocumentModalForm
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
class GetEmaDocumentView(AbstractGetDocumentView):
|
class GetEmaDocumentView(AbstractGetDocumentView):
|
||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_DOCUMENT_CLS = EmaDocument
|
_DOCUMENT_CLS = EmaDocument
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
class RemoveEmaDocumentView(AbstractRemoveDocumentView):
|
class RemoveEmaDocumentView(AbstractRemoveDocumentView):
|
||||||
@ -32,7 +32,7 @@ class RemoveEmaDocumentView(AbstractRemoveDocumentView):
|
|||||||
_FORM_CLS = RemoveEmaDocumentModalForm
|
_FORM_CLS = RemoveEmaDocumentModalForm
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
class EditEmaDocumentView(AbstractEditDocumentView):
|
class EditEmaDocumentView(AbstractEditDocumentView):
|
||||||
@ -41,5 +41,5 @@ class EditEmaDocumentView(AbstractEditDocumentView):
|
|||||||
_DOCUMENT_CLS = EmaDocument
|
_DOCUMENT_CLS = EmaDocument
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class NewEmaFormView(BaseNewSpatialLocatedObjectFormView):
|
|||||||
_TAB_TITLE = _("New EMA")
|
_TAB_TITLE = _("New EMA")
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be an ets user
|
# User has to be an ets user
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class EditEmaFormView(BaseEditSpatialLocatedObjectFormView):
|
|||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
_TAB_TITLE = _("Edit {}")
|
_TAB_TITLE = _("Edit {}")
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to be an ets user
|
# User has to be an ets user
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:index"
|
_REDIRECT_URL = "ema:index"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -112,5 +112,5 @@ class RemoveEmaView(LoginRequiredMixin, BaseRemoveModalFormView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:index"
|
_REDIRECT_URL = "ema:index"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -14,5 +14,5 @@ from konova.views.log import AbstractLogView
|
|||||||
class EmaLogView(LoginRequiredMixin, AbstractLogView):
|
class EmaLogView(LoginRequiredMixin, AbstractLogView):
|
||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -16,5 +16,5 @@ class EmaResubmissionView(AbstractResubmissionView):
|
|||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
action_url = "ema:resubmission-create"
|
action_url = "ema:resubmission-create"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -17,5 +17,5 @@ class EmaShareFormView(AbstractShareFormView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
@ -14,7 +14,7 @@ class NewEmaStateView(AbstractNewCompensationStateView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class EditEmaStateView(AbstractEditCompensationStateView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
|
|
||||||
@ -30,5 +30,5 @@ class RemoveEmaStateView(AbstractRemoveCompensationStateView):
|
|||||||
_MODEL_CLS = Ema
|
_MODEL_CLS = Ema
|
||||||
_REDIRECT_URL = "ema:detail"
|
_REDIRECT_URL = "ema:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class InterventionCheckView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
_MSG_SUCCESS = _("Check performed")
|
_MSG_SUCCESS = _("Check performed")
|
||||||
_REDIRECT_URL = "intervention:detail"
|
_REDIRECT_URL = "intervention:detail"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_zb_user()
|
return user.is_zb_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class BaseRevocationView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
@ -63,7 +63,7 @@ class GetRevocationDocumentView(LoginRequiredMixin, BaseView):
|
|||||||
return redirect("intervention:detail", id=doc.instance.id)
|
return redirect("intervention:detail", id=doc.instance.id)
|
||||||
return get_document(doc)
|
return get_document(doc)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
|||||||
@ -20,6 +20,12 @@ ENTRY_REMOVE_MISSING_PERMISSION = _("Only conservation or registration office us
|
|||||||
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
|
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
|
||||||
CHECK_STATE_RESET = _("Status of Checked reset")
|
CHECK_STATE_RESET = _("Status of Checked reset")
|
||||||
|
|
||||||
|
# USER | TEAM
|
||||||
|
TEAM_ADDED = _("New team added")
|
||||||
|
TEAM_EDITED = _("Team edited")
|
||||||
|
TEAM_REMOVED = _("Team removed")
|
||||||
|
TEAM_LEFT = _("Left Team")
|
||||||
|
|
||||||
# REMOVED
|
# REMOVED
|
||||||
GENERIC_REMOVED_TEMPLATE = _("{} removed")
|
GENERIC_REMOVED_TEMPLATE = _("{} removed")
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class AbstractCompensationActionView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from abc import abstractmethod
|
|||||||
from bootstrap_modal_forms.mixins import is_ajax
|
from bootstrap_modal_forms.mixins import is_ajax
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.http import HttpRequest, JsonResponse, HttpResponseRedirect
|
from django.http import HttpRequest, JsonResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -24,18 +25,37 @@ from konova.utils.message_templates import MISSING_GROUP_PERMISSION, DATA_UNSHAR
|
|||||||
|
|
||||||
|
|
||||||
class BaseView(View):
|
class BaseView(View):
|
||||||
_TEMPLATE: str = "CHANGE_ME"
|
""" An abstract base view
|
||||||
_TAB_TITLE: str = "CHANGE_ME"
|
|
||||||
_REDIRECT_URL: str = "CHANGE_ME"
|
This class represents the root of all views on this project. It defines private variables which have to be used
|
||||||
_REDIRECT_URL_ERROR: str = "home"
|
by inheriting classes for proper generic inheriting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TEMPLATE: str = "CHANGE_ME" # Path to template file
|
||||||
|
_TAB_TITLE: str = "CHANGE_ME" # Title displayed on browser tab
|
||||||
|
_REDIRECT_URL: str = "CHANGE_ME" # Default URL to redirect after processing (notation as django url "namespace:endpoint")
|
||||||
|
_REDIRECT_URL_ERROR: str = "home" # Default URL to redirect in case of an error (same notation)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
""" Dispatching requests before forwarding them into GET or POST endpoints.
|
||||||
|
|
||||||
|
Defines basic checks which need to be done before a user can get access to any view inheriting from
|
||||||
|
this class.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
request = check_user_is_in_any_group(request)
|
request = check_user_is_in_any_group(request)
|
||||||
|
|
||||||
if not self._user_has_permission(request.user):
|
if not self._user_has_permission(request.user, **kwargs):
|
||||||
messages.info(request, MISSING_GROUP_PERMISSION)
|
messages.info(request, MISSING_GROUP_PERMISSION)
|
||||||
return redirect(reverse(self._REDIRECT_URL_ERROR))
|
return redirect(reverse(self._REDIRECT_URL_ERROR))
|
||||||
|
|
||||||
@ -46,37 +66,68 @@ class BaseView(View):
|
|||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" Has to be implemented properly by inheriting classes
|
""" Checks whether the user has permission to get this view rendered.
|
||||||
|
|
||||||
|
If no specific check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user ():
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
has_permission (bool): Whether the user has permission to see this view
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("User permission not checked!")
|
raise NotImplementedError("User permission not checked!")
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
""" Has to be implemented properly by inheriting classes
|
""" Checks whether the user has shared access to this object.
|
||||||
|
|
||||||
|
If no shared-access-check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user ():
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
has_shared_access (bool): Whether the user has shared access
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("Shared access not checked!")
|
raise NotImplementedError("Shared access not checked!")
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL
|
||||||
|
|
||||||
|
By default the method simply returns the pre-defined redirect URL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
return self._REDIRECT_URL
|
return self._REDIRECT_URL
|
||||||
|
|
||||||
def _get_redirect_url_error(self, *args, **kwargs):
|
def _get_redirect_url_error(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL in error cases
|
||||||
|
|
||||||
|
By default the method simply returns the pre-defined redirect URL for errors.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
return self._REDIRECT_URL_ERROR
|
return self._REDIRECT_URL_ERROR
|
||||||
|
|
||||||
class BaseModalFormView(BaseView):
|
class BaseModalFormView(BaseView):
|
||||||
_TEMPLATE = "modal/modal_form.html"
|
""" Abstract base view providing logic to perform most modal form based view renderings
|
||||||
|
|
||||||
|
"""
|
||||||
|
_TEMPLATE: str = "modal/modal_form.html"
|
||||||
_MODEL_CLS = None
|
_MODEL_CLS = None
|
||||||
_FORM_CLS = None
|
_FORM_CLS = None
|
||||||
_MSG_SUCCESS = None
|
_MSG_SUCCESS = None
|
||||||
@ -85,12 +136,45 @@ class BaseModalFormView(BaseView):
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
""" Checks whether the user has shared access to this object.
|
||||||
|
|
||||||
|
For objects inheriting from BaseObject class the method 'is_shared_with()' is a handy
|
||||||
|
wrapper for checking shared access. For any other circumstances this method should be overwritten
|
||||||
|
to provide custom shared-access-checking logic.
|
||||||
|
|
||||||
|
If no shared-access-check is needed, this method can be overwritten with a simple True returning.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The performing user
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
has_shared_access (bool): Whether the user has shared access
|
||||||
|
"""
|
||||||
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get("id"))
|
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get("id"))
|
||||||
return obj.is_shared_with(user)
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
def get(self, request: HttpRequest, id: str, *args, **kwargs):
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
obj = self._MODEL_CLS.objects.get(id=id)
|
""" GET endpoint for rendering a view holding a modal form
|
||||||
self._check_for_recorded_instance(obj)
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# If there is an id provided as mapped parameter from the URL take it ...
|
||||||
|
_id = kwargs.pop("id", None)
|
||||||
|
try:
|
||||||
|
# ... and try to resolve it into a record
|
||||||
|
obj = self._MODEL_CLS.objects.get(id=_id)
|
||||||
|
self._check_for_recorded_instance(obj)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
# ... If there is none, maybe we are currently processing
|
||||||
|
# the creation of a new object (therefore no id yet), so let's continue
|
||||||
|
obj = None
|
||||||
form = self._FORM_CLS(
|
form = self._FORM_CLS(
|
||||||
request.POST or None,
|
request.POST or None,
|
||||||
request.FILES or None,
|
request.FILES or None,
|
||||||
@ -104,9 +188,27 @@ class BaseModalFormView(BaseView):
|
|||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
return render(request, self._TEMPLATE, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
def post(self, request: HttpRequest, id: str, *args, **kwargs):
|
def post(self, request: HttpRequest, *args, **kwargs):
|
||||||
obj = self._MODEL_CLS.objects.get(id=id)
|
""" POST endpoint for processing form contents of a view
|
||||||
self._check_for_recorded_instance(obj)
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# If there is an id provided as mapped parameter from the URL take it ...
|
||||||
|
_id = kwargs.pop("id", None)
|
||||||
|
try:
|
||||||
|
# ... and try to resolve it into a record
|
||||||
|
obj = self._MODEL_CLS.objects.get(id=_id)
|
||||||
|
self._check_for_recorded_instance(obj)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
# ... If there is none, maybe we are currently processing
|
||||||
|
# the creation of a new object (therefore no id yet), so let's continue
|
||||||
|
obj = None
|
||||||
form = self._FORM_CLS(
|
form = self._FORM_CLS(
|
||||||
request.POST or None,
|
request.POST or None,
|
||||||
request.FILES or None,
|
request.FILES or None,
|
||||||
@ -114,13 +216,15 @@ class BaseModalFormView(BaseView):
|
|||||||
request=request,
|
request=request,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
# Get now the redirect url and take specifics of the obj into account for that.
|
||||||
|
# We do not do this after saving the form to avoid side effects due to possibly changed data
|
||||||
redirect_url = self._get_redirect_url(obj=obj)
|
redirect_url = self._get_redirect_url(obj=obj)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
# Modal forms send one POST for checking on data validity. This is used to evaluate possible errors
|
||||||
|
# on the form. The second POST (if no errors have been found) is the 'proper' one,
|
||||||
|
# which we want to process by saving/commiting of the data to the database.
|
||||||
if not is_ajax(request.META):
|
if not is_ajax(request.META):
|
||||||
# Modal forms send one POST for checking on data validity. This can be used to return possible errors
|
# Get now the success message and take specifics of the obj into account for that
|
||||||
# on the form. A second POST (if no errors occurs) is sent afterward and needs to process the
|
|
||||||
# saving/commiting of the data to the database. is_ajax() performs this check. The first request is
|
|
||||||
# an ajax call, the second is a regular form POST.
|
|
||||||
msg_success = self._get_msg_success(obj=obj, *args, **kwargs)
|
msg_success = self._get_msg_success(obj=obj, *args, **kwargs)
|
||||||
form.save()
|
form.save()
|
||||||
messages.success(
|
messages.success(
|
||||||
@ -136,20 +240,41 @@ class BaseModalFormView(BaseView):
|
|||||||
return render(request, self._TEMPLATE, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant redirect URL (if needed)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Reversed redirect url
|
||||||
|
"""
|
||||||
obj = kwargs.get("obj", None)
|
obj = kwargs.get("obj", None)
|
||||||
assert obj is not None
|
if obj:
|
||||||
return reverse(self._REDIRECT_URL, args=(obj.id,))
|
return reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
else:
|
||||||
|
return reverse(self._REDIRECT_URL)
|
||||||
|
|
||||||
def _get_msg_success(self, *args, **kwargs):
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
|
""" Getter to construct a more specific, data dependant success message
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
return self._MSG_SUCCESS
|
return self._MSG_SUCCESS
|
||||||
|
|
||||||
def _check_for_recorded_instance(self, obj):
|
def _check_for_recorded_instance(self, obj):
|
||||||
""" Checks if the object on this view is recorded and runs some special logic if yes
|
""" Checks if the object on this view is recorded and runs some special logic if so
|
||||||
|
|
||||||
If the instance is recorded, the view should provide some information about why the user can not edit anything.
|
If the instance is recorded, the view should provide some information about why the user can not edit anything.
|
||||||
|
This behaviour is only intended to mask any form for instances based on the BaseObject class.
|
||||||
|
|
||||||
There are situations where the form should be rendered regularly,
|
There are situations where the form should be rendered regularly, despite the instance being recorded,
|
||||||
e.g deduction forms for (recorded) eco accounts.
|
e.g. for rendering deduction form contents on (recorded) eco accounts.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
@ -162,29 +287,32 @@ class BaseModalFormView(BaseView):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if obj.is_recorded:
|
if obj.is_recorded:
|
||||||
self._block_form()
|
# Replace default template with a blocking one
|
||||||
|
self._TEMPLATE = "form/recorded_no_edit.html"
|
||||||
|
|
||||||
def _block_form(self):
|
|
||||||
"""
|
|
||||||
Overwrites template, providing no actions
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
self._TEMPLATE = "form/recorded_no_edit.html"
|
|
||||||
|
|
||||||
class BaseIndexView(BaseView):
|
class BaseIndexView(BaseView):
|
||||||
""" Base class for index views
|
""" Abstract base class for index views
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_TEMPLATE = "generic_index.html"
|
_TEMPLATE: str = "generic_index.html"
|
||||||
_INDEX_TABLE_CLS = None
|
_INDEX_TABLE_CLS = None
|
||||||
_REDIRECT_URL = "home"
|
_REDIRECT_URL: str = "home"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get(self, request: HttpRequest):
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering index views
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
qs = self._get_queryset()
|
qs = self._get_queryset()
|
||||||
table = self._INDEX_TABLE_CLS(
|
table = self._INDEX_TABLE_CLS(
|
||||||
request=request,
|
request=request,
|
||||||
@ -199,9 +327,14 @@ class BaseIndexView(BaseView):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _get_queryset(self):
|
def _get_queryset(self):
|
||||||
|
""" Generic getter for the queryset of objects which shall be processed on this view
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# No specific permissions needed for opening base index view
|
# No specific permissions needed for opening base index view
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -228,7 +361,7 @@ class BaseIdentifierGeneratorView(BaseView):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
""" Should be overwritten in inheriting classes!
|
""" Should be overwritten in inheriting classes!
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -245,6 +378,9 @@ class BaseIdentifierGeneratorView(BaseView):
|
|||||||
|
|
||||||
|
|
||||||
class BaseFormView(BaseView):
|
class BaseFormView(BaseView):
|
||||||
|
""" Abstract base class for rendering form views
|
||||||
|
|
||||||
|
"""
|
||||||
_MODEL_CLS = None
|
_MODEL_CLS = None
|
||||||
_FORM_CLS = None
|
_FORM_CLS = None
|
||||||
|
|
||||||
@ -252,18 +388,21 @@ class BaseFormView(BaseView):
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _get_additional_context(self, **kwargs):
|
def _get_additional_context(self, **kwargs):
|
||||||
"""
|
""" Getter for additional data, which is needed to properly render the current view
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs ():
|
**kwargs ():
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
context (dict): Additional context data for rendering
|
||||||
"""
|
"""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class BaseSpatialLocatedObjectFormView(LoginRequiredMixin, BaseFormView):
|
class BaseSpatialLocatedObjectFormView(LoginRequiredMixin, BaseFormView):
|
||||||
|
""" Abstract base view for processing objects with spatial data
|
||||||
|
|
||||||
|
"""
|
||||||
_GEOMETRY_FORM_CLS = SimpleGeomForm
|
_GEOMETRY_FORM_CLS = SimpleGeomForm
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -271,8 +410,11 @@ class BaseSpatialLocatedObjectFormView(LoginRequiredMixin, BaseFormView):
|
|||||||
|
|
||||||
|
|
||||||
class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
||||||
|
""" Base view for creating new spatial data related to objects
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
"""
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# User has to have default privilege to call this endpoint
|
# User has to have default privilege to call this endpoint
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
@ -280,10 +422,21 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
# There is no shared access control since nothing exists yet
|
# There is no shared access control since nothing exists yet
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get(self, request: HttpRequest, **kwargs):
|
def get(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering a form view where object data and spatial data are processed
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First initialize the regular object form and the geometry form based on request-bound data
|
||||||
form: BaseForm = self._FORM_CLS(None, **kwargs, user=request.user)
|
form: BaseForm = self._FORM_CLS(None, **kwargs, user=request.user)
|
||||||
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, user=request.user, read_only=False)
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, user=request.user, read_only=False)
|
||||||
|
|
||||||
|
# Get some additional context and put everything into the rendering pipeline
|
||||||
context = self._get_additional_context()
|
context = self._get_additional_context()
|
||||||
context = BaseContext(request, additional_context=context).context
|
context = BaseContext(request, additional_context=context).context
|
||||||
context.update(
|
context.update(
|
||||||
@ -295,16 +448,30 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
)
|
)
|
||||||
return render(request, self._TEMPLATE, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
def post(self, request: HttpRequest, **kwargs):
|
def post(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
""" POST endpoint for processing object and spatial data provided by forms
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First initialize the regular object form and the geometry form based on request-bound data
|
||||||
form: BaseForm = self._FORM_CLS(request.POST or None, **kwargs, user=request.user)
|
form: BaseForm = self._FORM_CLS(request.POST or None, **kwargs, user=request.user)
|
||||||
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, user=request.user, read_only=False)
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, user=request.user, read_only=False)
|
||||||
|
|
||||||
|
# Only continue if both forms are without errors
|
||||||
if form.is_valid() and geom_form.is_valid():
|
if form.is_valid() and geom_form.is_valid():
|
||||||
obj = form.save(request.user, geom_form)
|
obj = form.save(request.user, geom_form)
|
||||||
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
generated_identifier = form.cleaned_data.get("identifier", None)
|
generated_identifier = form.cleaned_data.get("identifier", None)
|
||||||
|
|
||||||
|
# There is a rare chance that an identifier has been taken already between sending the form and processing
|
||||||
|
# the data. If the identifier can not be used anymore, we have to inform the user that another identifier
|
||||||
|
# had to be generated
|
||||||
if generated_identifier != obj.identifier:
|
if generated_identifier != obj.identifier:
|
||||||
messages.info(
|
messages.info(
|
||||||
request,
|
request,
|
||||||
@ -314,12 +481,18 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
messages.success(request, _("{} added").format(obj.identifier))
|
messages.success(request, _("{} added").format(obj.identifier))
|
||||||
|
# Very complex geometries have to be simplified automatically while processing the spatial data. If this
|
||||||
|
# is the case, the user has to be informed. (They might want to check whether the stored geometry still
|
||||||
|
# fits their needs)
|
||||||
if geom_form.has_geometry_simplified():
|
if geom_form.has_geometry_simplified():
|
||||||
messages.info(
|
messages.info(
|
||||||
request,
|
request,
|
||||||
GEOMETRY_SIMPLIFIED
|
GEOMETRY_SIMPLIFIED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# If certain parts of the geometry do not pass the quality check (e.g. way too small and therefore more like
|
||||||
|
# cutting errors) we need to inform the user that some parts have been removed/ignored while storing the
|
||||||
|
# geometry
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
||||||
if num_ignored_geometries > 0:
|
if num_ignored_geometries > 0:
|
||||||
messages.info(
|
messages.info(
|
||||||
@ -329,6 +502,7 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
|
|
||||||
return redirect(obj_redirect_url)
|
return redirect(obj_redirect_url)
|
||||||
else:
|
else:
|
||||||
|
# Something was not properly entered on the forms, so we have to inform the user
|
||||||
context = self._get_additional_context()
|
context = self._get_additional_context()
|
||||||
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
messages.error(request, FORM_INVALID, extra_tags="danger",)
|
||||||
|
|
||||||
@ -344,15 +518,30 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
|
|
||||||
|
|
||||||
class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
||||||
|
""" Base view for editing new spatial data related to objects
|
||||||
|
|
||||||
|
"""
|
||||||
_TAB_TITLE = _("Edit {}")
|
_TAB_TITLE = _("Edit {}")
|
||||||
|
|
||||||
def get(self, request: HttpRequest, id: str):
|
def get(self, request: HttpRequest, id: str, *args, **kwargs):
|
||||||
|
""" GET endpoint for rendering a form view where object data and spatial data are processed
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The id of the object (not the geometry)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# First fetch the object identified by the id
|
||||||
obj = get_object_or_404(
|
obj = get_object_or_404(
|
||||||
self._MODEL_CLS,
|
self._MODEL_CLS,
|
||||||
id=id
|
id=id
|
||||||
)
|
)
|
||||||
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
|
# Check whether the object is recorded. If so - we can redirect the user and inform about the un-editability
|
||||||
|
# of this entry
|
||||||
if obj.is_recorded:
|
if obj.is_recorded:
|
||||||
messages.info(
|
messages.info(
|
||||||
request,
|
request,
|
||||||
@ -360,9 +549,11 @@ class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
)
|
)
|
||||||
return redirect(obj_redirect_url)
|
return redirect(obj_redirect_url)
|
||||||
|
|
||||||
|
# Seems like the object is not recorded. Good - initialize the forms based on the obj and request-bound data
|
||||||
form: BaseForm = self._FORM_CLS(None, instance=obj, user=request.user)
|
form: BaseForm = self._FORM_CLS(None, instance=obj, user=request.user)
|
||||||
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, instance=obj, read_only=False)
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(None, instance=obj, read_only=False)
|
||||||
|
|
||||||
|
# Get additional context for rendering and put everything in the rendering pipeline
|
||||||
context = self._get_additional_context()
|
context = self._get_additional_context()
|
||||||
context = BaseContext(request, additional_context=context).context
|
context = BaseContext(request, additional_context=context).context
|
||||||
context.update(
|
context.update(
|
||||||
@ -374,13 +565,33 @@ class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
)
|
)
|
||||||
return render(request, self._TEMPLATE, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
def post(self, request: HttpRequest, id: str):
|
def post(self, request: HttpRequest, id: str, *args, **kwargs):
|
||||||
|
""" POST endpoint for processing object and spatial data provided by forms
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The incoming request
|
||||||
|
id (str): The object's id
|
||||||
|
*args ():
|
||||||
|
**kwargs ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
obj = get_object_or_404(
|
obj = get_object_or_404(
|
||||||
self._MODEL_CLS,
|
self._MODEL_CLS,
|
||||||
id=id
|
id=id
|
||||||
)
|
)
|
||||||
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
obj_redirect_url = reverse(self._REDIRECT_URL, args=(obj.id,))
|
||||||
|
|
||||||
|
# If the object is recorded, we abort the processing directly and inform the user
|
||||||
|
if obj.is_recorded:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
RECORDED_BLOCKS_EDIT
|
||||||
|
)
|
||||||
|
return redirect(obj_redirect_url)
|
||||||
|
|
||||||
|
# Initialize forms with obj and request-bound data
|
||||||
form: BaseForm = self._FORM_CLS(request.POST or None, instance=obj, user=request.user)
|
form: BaseForm = self._FORM_CLS(request.POST or None, instance=obj, user=request.user)
|
||||||
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, instance=obj, read_only=False)
|
geom_form: SimpleGeomForm = self._GEOMETRY_FORM_CLS(request.POST or None, instance=obj, read_only=False)
|
||||||
|
|
||||||
@ -388,12 +599,18 @@ class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
obj = form.save(request.user, geom_form)
|
obj = form.save(request.user, geom_form)
|
||||||
messages.success(request, _("{} edited").format(obj.identifier))
|
messages.success(request, _("{} edited").format(obj.identifier))
|
||||||
|
|
||||||
|
# Very complex geometries have to be simplified automatically while processing the spatial data. If this
|
||||||
|
# is the case, the user has to be informed. (They might want to check whether the stored geometry still
|
||||||
|
# fits their needs)
|
||||||
if geom_form.has_geometry_simplified():
|
if geom_form.has_geometry_simplified():
|
||||||
messages.info(
|
messages.info(
|
||||||
request,
|
request,
|
||||||
GEOMETRY_SIMPLIFIED
|
GEOMETRY_SIMPLIFIED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# If certain parts of the geometry do not pass the quality check (e.g. way too small and therefore more like
|
||||||
|
# cutting errors) we need to inform the user that some parts have been removed/ignored while storing the
|
||||||
|
# geometry
|
||||||
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
num_ignored_geometries = geom_form.get_num_geometries_ignored()
|
||||||
if num_ignored_geometries > 0:
|
if num_ignored_geometries > 0:
|
||||||
messages.info(
|
messages.info(
|
||||||
@ -420,5 +637,5 @@ class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView):
|
|||||||
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get('id', None))
|
obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get('id', None))
|
||||||
return obj.is_shared_with(user)
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class AbstractNewDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class AbstractEditDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
|
|
||||||
@ -57,5 +57,5 @@ class AbstractRemoveDeadlineView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -28,7 +28,7 @@ class AbstractDeductionView(BaseModalFormView):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _user_has_permission(self, user) -> bool:
|
def _user_has_permission(self, user, **kwargs) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
@ -42,7 +42,7 @@ class BaseDetailView(LoginRequiredMixin, BaseView):
|
|||||||
# Access to an entry's detail view is not restricted by the state of being-shared or not
|
# Access to an entry's detail view is not restricted by the state of being-shared or not
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# Detail views have no restrictions
|
# Detail views have no restrictions
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class AbstractNewDocumentView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ class AbstractGetDocumentView(LoginRequiredMixin, BaseView):
|
|||||||
def post(self, request, id: str, doc_id: str):
|
def post(self, request, id: str, doc_id: str):
|
||||||
return self.get(request, id, doc_id)
|
return self.get(request, id, doc_id)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
@ -80,7 +80,7 @@ class AbstractRemoveDocumentView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
return super()._get_redirect_url(*args, **kwargs) + "#related_data"
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_msg_success(self, *args, **kwargs):
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
@ -100,7 +100,7 @@ class AbstractEditDocumentView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
|||||||
@ -110,7 +110,7 @@ class GeomParcelsView(BaseView):
|
|||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -160,5 +160,5 @@ class GeomParcelsContentView(BaseView):
|
|||||||
def _user_has_shared_access(self, user, **kwargs):
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -74,7 +74,7 @@ class HomeView(LoginRequiredMixin, BaseView):
|
|||||||
context = BaseContext(request, additional_context).context
|
context = BaseContext(request, additional_context).context
|
||||||
return render(request, self._TEMPLATE, context)
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# No specific permission needed for home view
|
# No specific permission needed for home view
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -46,5 +46,5 @@ class AbstractLogView(BaseView):
|
|||||||
obj = get_object_or_404(self._MODEL_CLS, id=obj_id)
|
obj = get_object_or_404(self._MODEL_CLS, id=obj_id)
|
||||||
return obj.is_shared_with(user)
|
return obj.is_shared_with(user)
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class AbstractRecordView(BaseModalFormView):
|
|||||||
_FORM_CLS = RecordModalForm
|
_FORM_CLS = RecordModalForm
|
||||||
_MSG_SUCCESS = None
|
_MSG_SUCCESS = None
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_ets_user()
|
return user.is_ets_user()
|
||||||
|
|
||||||
def _get_msg_success(self, *args, **kwargs):
|
def _get_msg_success(self, *args, **kwargs):
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class BaseRemoveModalFormView(BaseModalFormView):
|
|||||||
_MSG_SUCCESS = GENERIC_REMOVED_TEMPLATE
|
_MSG_SUCCESS = GENERIC_REMOVED_TEMPLATE
|
||||||
_REDIRECT_URL = None
|
_REDIRECT_URL = None
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class BaseReportView(BaseView):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# Reports do not need specific permissions to be callable
|
# Reports do not need specific permissions to be callable
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class AbstractResubmissionView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _check_for_recorded_instance(self, obj):
|
def _check_for_recorded_instance(self, obj):
|
||||||
|
|||||||
@ -60,7 +60,7 @@ class AbstractShareByTokenView(LoginRequiredMixin, BaseView):
|
|||||||
)
|
)
|
||||||
return redirect("home")
|
return redirect("home")
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
# No permissions are needed to get shared access via token
|
# No permissions are needed to get shared access via token
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -77,5 +77,5 @@ class AbstractShareFormView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class AbstractCompensationStateView(LoginRequiredMixin, BaseModalFormView):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
def _user_has_permission(self, user, **kwargs):
|
||||||
return user.is_default_user()
|
return user.is_default_user()
|
||||||
|
|
||||||
def _get_redirect_url(self, *args, **kwargs):
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
|||||||
12
user/urls.py
12
user/urls.py
@ -11,7 +11,9 @@ from user.autocomplete.share import ShareUserAutocomplete, ShareTeamAutocomplete
|
|||||||
from user.autocomplete.team import TeamAdminAutocomplete
|
from user.autocomplete.team import TeamAdminAutocomplete
|
||||||
from user.views.api_token import APITokenView, new_api_token_view
|
from user.views.api_token import APITokenView, new_api_token_view
|
||||||
from user.views.propagate import PropagateUserView
|
from user.views.propagate import PropagateUserView
|
||||||
from user.views.views import *
|
from user.views.teams import TeamIndexView, NewTeamView, TeamDetailModalView, EditTeamView, RemoveTeamView, \
|
||||||
|
LeaveTeamView
|
||||||
|
from user.views.users import UserDetailView, NotificationsView, ContactView
|
||||||
|
|
||||||
app_name = "user"
|
app_name = "user"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -22,11 +24,11 @@ urlpatterns = [
|
|||||||
path("token/api/new", new_api_token_view, name="api-token-new"),
|
path("token/api/new", new_api_token_view, name="api-token-new"),
|
||||||
path("contact/<id>", ContactView.as_view(), name="contact"),
|
path("contact/<id>", ContactView.as_view(), name="contact"),
|
||||||
path("team/", TeamIndexView.as_view(), name="team-index"),
|
path("team/", TeamIndexView.as_view(), name="team-index"),
|
||||||
path("team/new", new_team_view, name="team-new"),
|
path("team/new", NewTeamView.as_view(), name="team-new"),
|
||||||
path("team/<id>", TeamDetailModalView.as_view(), name="team-data"),
|
path("team/<id>", TeamDetailModalView.as_view(), name="team-data"),
|
||||||
path("team/<id>/edit", edit_team_view, name="team-edit"),
|
path("team/<id>/edit", EditTeamView.as_view(), name="team-edit"),
|
||||||
path("team/<id>/remove", remove_team_view, name="team-remove"),
|
path("team/<id>/remove", RemoveTeamView.as_view(), name="team-remove"),
|
||||||
path("team/<id>/leave", leave_team_view, name="team-leave"),
|
path("team/<id>/leave", LeaveTeamView.as_view(), name="team-leave"),
|
||||||
|
|
||||||
# Autocomplete urls
|
# Autocomplete urls
|
||||||
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
||||||
|
|||||||
105
user/views/teams.py
Normal file
105
user/views/teams.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Created on: 05.11.25
|
||||||
|
|
||||||
|
"""
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.http import Http404, HttpRequest
|
||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from konova.contexts import BaseContext
|
||||||
|
from konova.utils.message_templates import TEAM_LEFT, TEAM_REMOVED, TEAM_EDITED, TEAM_ADDED
|
||||||
|
from konova.views.base import BaseModalFormView
|
||||||
|
from user.forms.modals.team import LeaveTeamModalForm, RemoveTeamModalForm, EditTeamModalForm, NewTeamModalForm
|
||||||
|
from user.forms.team import TeamDataForm
|
||||||
|
from user.models import Team
|
||||||
|
from user.views.users import UserBaseView
|
||||||
|
|
||||||
|
|
||||||
|
class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView):
|
||||||
|
_FORM_CLS = TeamDataForm
|
||||||
|
_MODEL_CLS = Team
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# No specific constraints
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# No specific constraints
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TeamIndexView(LoginRequiredMixin, UserBaseView):
|
||||||
|
_TEMPLATE = "user/team/index.html"
|
||||||
|
_TAB_TITLE = _("Teams")
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
user = request.user
|
||||||
|
context = {
|
||||||
|
"teams": user.shared_teams,
|
||||||
|
"tab_title": self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTeamView(LoginRequiredMixin, BaseModalFormView):
|
||||||
|
_REDIRECT_URL = "user:team-index"
|
||||||
|
_MODEL_CLS = Team
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# Nothing to check here - just pass the test
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# Nothing to check here - just pass the test
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_redirect_url(self, *args, **kwargs):
|
||||||
|
return reverse(self._REDIRECT_URL)
|
||||||
|
|
||||||
|
class NewTeamView(BaseTeamView):
|
||||||
|
_FORM_CLS = NewTeamModalForm
|
||||||
|
_MSG_SUCCESS = TEAM_ADDED
|
||||||
|
|
||||||
|
class EditTeamView(BaseTeamView):
|
||||||
|
_FORM_CLS = EditTeamModalForm
|
||||||
|
_MSG_SUCCESS = TEAM_EDITED
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
team = get_object_or_404(Team, id=kwargs.get("id"))
|
||||||
|
user_is_admin = team.is_user_admin(user)
|
||||||
|
if not user_is_admin:
|
||||||
|
# If user is not an admin, we act as if there is no such team on the database
|
||||||
|
raise Http404()
|
||||||
|
return user_is_admin
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveTeamView(BaseTeamView):
|
||||||
|
_FORM_CLS = RemoveTeamModalForm
|
||||||
|
_MSG_SUCCESS = TEAM_REMOVED
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
team_id = kwargs.get("id")
|
||||||
|
team = get_object_or_404(Team, id=team_id)
|
||||||
|
user_is_admin = team.is_user_admin(user)
|
||||||
|
if not user_is_admin:
|
||||||
|
raise Http404()
|
||||||
|
return True
|
||||||
|
|
||||||
|
class LeaveTeamView(BaseTeamView):
|
||||||
|
_FORM_CLS = LeaveTeamModalForm
|
||||||
|
_MSG_SUCCESS = TEAM_LEFT
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
team_id = kwargs.get("id")
|
||||||
|
team = get_object_or_404(self._MODEL_CLS, id=team_id)
|
||||||
|
is_user_team_member = team.users.filter(id=user.id).exists()
|
||||||
|
if not is_user_team_member:
|
||||||
|
raise Http404()
|
||||||
|
return True
|
||||||
81
user/views/users.py
Normal file
81
user/views/users.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
||||||
|
from konova.views.base import BaseView, BaseModalFormView
|
||||||
|
from user.forms.modals.user import UserContactForm
|
||||||
|
from user.forms.user import UserNotificationForm
|
||||||
|
from user.models import User
|
||||||
|
from django.http import HttpRequest
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from konova.contexts import BaseContext
|
||||||
|
|
||||||
|
|
||||||
|
class UserBaseView(BaseView):
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class UserDetailView(LoginRequiredMixin, UserBaseView):
|
||||||
|
_TEMPLATE = "user/index.html"
|
||||||
|
_TAB_TITLE = _("User settings")
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
context = {
|
||||||
|
"user": request.user,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationsView(LoginRequiredMixin, UserBaseView):
|
||||||
|
_TEMPLATE = "user/notifications.html"
|
||||||
|
_TAB_TITLE = _("User notifications")
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
user = request.user
|
||||||
|
form = UserNotificationForm(user=user, data=None)
|
||||||
|
context = {
|
||||||
|
"user": user,
|
||||||
|
"form": form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
def post(self, request: HttpRequest):
|
||||||
|
user = request.user
|
||||||
|
form = UserNotificationForm(user=user, data=request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_("Notifications edited")
|
||||||
|
)
|
||||||
|
return redirect("user:detail")
|
||||||
|
context = {
|
||||||
|
"user": user,
|
||||||
|
"form": form,
|
||||||
|
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, self._TEMPLATE, context)
|
||||||
|
|
||||||
|
|
||||||
|
class ContactView(LoginRequiredMixin, BaseModalFormView):
|
||||||
|
_FORM_CLS = UserContactForm
|
||||||
|
_MODEL_CLS = User
|
||||||
|
|
||||||
|
def _user_has_shared_access(self, user, **kwargs):
|
||||||
|
# No specific constraints
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _user_has_permission(self, user, **kwargs):
|
||||||
|
# No specific constraints
|
||||||
|
return True
|
||||||
@ -1,206 +0,0 @@
|
|||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
|
|
||||||
from konova.views.base import BaseView, BaseModalFormView
|
|
||||||
from user.forms.modals.team import NewTeamModalForm, EditTeamModalForm, RemoveTeamModalForm, LeaveTeamModalForm
|
|
||||||
from user.forms.modals.user import UserContactForm
|
|
||||||
from user.forms.team import TeamDataForm
|
|
||||||
from user.forms.user import UserNotificationForm
|
|
||||||
from user.models import User, Team
|
|
||||||
from django.http import HttpRequest, Http404
|
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
from konova.contexts import BaseContext
|
|
||||||
from konova.decorators import login_required_modal
|
|
||||||
|
|
||||||
|
|
||||||
class UserBaseView(BaseView):
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class UserDetailView(LoginRequiredMixin, UserBaseView):
|
|
||||||
_TEMPLATE = "user/index.html"
|
|
||||||
_TAB_TITLE = _("User settings")
|
|
||||||
|
|
||||||
def get(self, request: HttpRequest):
|
|
||||||
context = {
|
|
||||||
"user": request.user,
|
|
||||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
|
|
||||||
class NotificationsView(LoginRequiredMixin, UserBaseView):
|
|
||||||
_TEMPLATE = "user/notifications.html"
|
|
||||||
_TAB_TITLE = _("User notifications")
|
|
||||||
|
|
||||||
def get(self, request: HttpRequest):
|
|
||||||
user = request.user
|
|
||||||
form = UserNotificationForm(user=user, data=None)
|
|
||||||
context = {
|
|
||||||
"user": user,
|
|
||||||
"form": form,
|
|
||||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
def post(self, request: HttpRequest):
|
|
||||||
user = request.user
|
|
||||||
form = UserNotificationForm(user=user, data=request.POST)
|
|
||||||
if form.is_valid():
|
|
||||||
form.save()
|
|
||||||
messages.success(
|
|
||||||
request,
|
|
||||||
_("Notifications edited")
|
|
||||||
)
|
|
||||||
return redirect("user:detail")
|
|
||||||
context = {
|
|
||||||
"user": user,
|
|
||||||
"form": form,
|
|
||||||
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
|
|
||||||
class ContactView(LoginRequiredMixin, BaseModalFormView):
|
|
||||||
def get(self, request: HttpRequest, id: str):
|
|
||||||
""" Renders contact modal view of a users contact data
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The user's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
user = get_object_or_404(User, id=id)
|
|
||||||
form = UserContactForm(request.POST or None, instance=user, request=request)
|
|
||||||
context = {
|
|
||||||
"form": form,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
|
||||||
# No specific constraints
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
|
||||||
# No specific constraints
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView):
|
|
||||||
def get(self, request: HttpRequest, id: str):
|
|
||||||
""" Renders team data
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The team's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
team = get_object_or_404(Team, id=id)
|
|
||||||
form = TeamDataForm(request.POST or None, instance=team, request=request)
|
|
||||||
context = {
|
|
||||||
"form": form,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
def _user_has_shared_access(self, user, **kwargs):
|
|
||||||
# No specific constraints
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _user_has_permission(self, user):
|
|
||||||
# No specific constraints
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class TeamIndexView(LoginRequiredMixin, UserBaseView):
|
|
||||||
_TEMPLATE = "user/team/index.html"
|
|
||||||
_TAB_TITLE = _("Teams")
|
|
||||||
|
|
||||||
def get(self, request: HttpRequest):
|
|
||||||
user = request.user
|
|
||||||
context = {
|
|
||||||
"teams": user.shared_teams,
|
|
||||||
"tab_title": self._TAB_TITLE,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, self._TEMPLATE, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
def new_team_view(request: HttpRequest):
|
|
||||||
form = NewTeamModalForm(request.POST or None, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
_("New team added"),
|
|
||||||
redirect_url=reverse("user:team-index")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
def edit_team_view(request: HttpRequest, id: str):
|
|
||||||
team = get_object_or_404(Team, id=id)
|
|
||||||
user_is_admin = team.is_user_admin(request.user)
|
|
||||||
if not user_is_admin:
|
|
||||||
raise Http404()
|
|
||||||
form = EditTeamModalForm(request.POST or None, instance=team, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
_("Team edited"),
|
|
||||||
redirect_url=reverse("user:team-index")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
def remove_team_view(request: HttpRequest, id: str):
|
|
||||||
team = get_object_or_404(Team, id=id)
|
|
||||||
user_is_admin = team.is_user_admin(request.user)
|
|
||||||
if not user_is_admin:
|
|
||||||
raise Http404()
|
|
||||||
form = RemoveTeamModalForm(request.POST or None, instance=team, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
_("Team removed"),
|
|
||||||
redirect_url=reverse("user:team-index")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required_modal
|
|
||||||
@login_required
|
|
||||||
def leave_team_view(request: HttpRequest, id: str):
|
|
||||||
team = get_object_or_404(Team, id=id)
|
|
||||||
user = request.user
|
|
||||||
|
|
||||||
is_user_team_member = team.users.filter(id=user.id).exists()
|
|
||||||
if not is_user_team_member:
|
|
||||||
messages.info(
|
|
||||||
request,
|
|
||||||
_("You are not a member of this team")
|
|
||||||
)
|
|
||||||
return redirect("user:team-index")
|
|
||||||
|
|
||||||
form = LeaveTeamModalForm(request.POST or None, instance=team, request=request)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
_("Left Team"),
|
|
||||||
redirect_url=reverse("user:team-index")
|
|
||||||
)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user