WIP: 490_View_refactoring #491

Draft
mpeltriaux wants to merge 33 commits from 490_View_refactoring into master
10 changed files with 148 additions and 114 deletions
Showing only changes of commit 242730435e - Show all commits

View File

View File

@ -117,7 +117,7 @@ def new_view(request: HttpRequest, intervention_id: str = None):
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Compensation _MODEL_CLS = Compensation
_REDIRECT_URL_NAME = "compensation:index" _REDIRECT_URL = "compensation:index"
@login_required @login_required

View File

@ -5,54 +5,28 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 19.08.22 Created on: 19.08.22
""" """
from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import Http404 from django.http import Http404
from django.utils.decorators import method_decorator
from compensation.models import EcoAccount from compensation.models import EcoAccount
from konova.decorators import default_group_required, login_required_modal
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
class NewEcoAccountDeductionView(AbstractNewDeductionView): class NewEcoAccountDeductionView(LoginRequiredMixin, AbstractNewDeductionView):
model = EcoAccount _MODEL = EcoAccount
redirect_url = "compensation:acc:detail" _REDIRECT_URL = "compensation:acc:detail"
@method_decorator(login_required_modal)
@method_decorator(login_required)
@method_decorator(default_group_required)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def _custom_check(self, obj): def _custom_check(self, obj):
# New deductions can only be created if the eco account has been recorded
if not obj.recorded: if not obj.recorded:
raise Http404() raise Http404()
class EditEcoAccountDeductionView(AbstractEditDeductionView): class EditEcoAccountDeductionView(LoginRequiredMixin, AbstractEditDeductionView):
def _custom_check(self, obj): _MODEL = EcoAccount
pass _REDIRECT_URL = "compensation:acc:detail"
model = EcoAccount
redirect_url = "compensation:acc:detail"
@method_decorator(login_required_modal)
@method_decorator(login_required)
@method_decorator(default_group_required)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
class RemoveEcoAccountDeductionView(AbstractRemoveDeductionView): class RemoveEcoAccountDeductionView(LoginRequiredMixin, AbstractRemoveDeductionView):
def _custom_check(self, obj): _MODEL = EcoAccount
pass _REDIRECT_URL = "compensation:acc:detail"
model = EcoAccount
redirect_url = "compensation:acc:detail"
@method_decorator(login_required_modal)
@method_decorator(login_required)
@method_decorator(default_group_required)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)

View File

@ -98,7 +98,7 @@ def new_view(request: HttpRequest):
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = EcoAccount _MODEL_CLS = EcoAccount
_REDIRECT_URL_NAME = "compensation:acc:index" _REDIRECT_URL = "compensation:acc:index"
@login_required @login_required

View File

@ -98,7 +98,7 @@ def new_view(request: HttpRequest):
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Ema _MODEL_CLS = Ema
_REDIRECT_URL_NAME = "ema:index" _REDIRECT_URL = "ema:index"
def _user_has_permission(self, user): def _user_has_permission(self, user):
return user.is_ets_user() return user.is_ets_user()

View File

@ -5,51 +5,22 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 19.08.22 Created on: 19.08.22
""" """
from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
from intervention.models import Intervention from intervention.models import Intervention
from konova.decorators import default_group_required, shared_access_required
from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView from konova.views.deduction import AbstractNewDeductionView, AbstractEditDeductionView, AbstractRemoveDeductionView
class NewInterventionDeductionView(AbstractNewDeductionView): class NewInterventionDeductionView(LoginRequiredMixin, AbstractNewDeductionView):
def _custom_check(self, obj): _MODEL = Intervention
pass _REDIRECT_URL = "intervention:detail"
model = Intervention
redirect_url = "intervention:detail"
@method_decorator(login_required)
@method_decorator(default_group_required)
@method_decorator(shared_access_required(Intervention, "id"))
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
class EditInterventionDeductionView(AbstractEditDeductionView): class EditInterventionDeductionView(LoginRequiredMixin, AbstractEditDeductionView):
def _custom_check(self, obj): _MODEL = Intervention
pass _REDIRECT_URL = "intervention:detail"
model = Intervention
redirect_url = "intervention:detail"
@method_decorator(login_required)
@method_decorator(default_group_required)
@method_decorator(shared_access_required(Intervention, "id"))
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
class RemoveInterventionDeductionView(AbstractRemoveDeductionView): class RemoveInterventionDeductionView(LoginRequiredMixin, AbstractRemoveDeductionView):
def _custom_check(self, obj): _MODEL = Intervention
pass _REDIRECT_URL = "intervention:detail"
model = Intervention
redirect_url = "intervention:detail"
@method_decorator(login_required)
@method_decorator(default_group_required)
@method_decorator(shared_access_required(Intervention, "id"))
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)

View File

@ -102,7 +102,7 @@ def new_view(request: HttpRequest):
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Intervention _MODEL_CLS = Intervention
_REDIRECT_URL_NAME = "intervention:index" _REDIRECT_URL = "intervention:index"
@login_required @login_required

View File

@ -14,21 +14,57 @@ from django.views import View
from konova.contexts import BaseContext from konova.contexts import BaseContext
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.general import check_user_is_in_any_group from konova.utils.general import check_user_is_in_any_group
from konova.utils.message_templates import MISSING_GROUP_PERMISSION from konova.utils.message_templates import MISSING_GROUP_PERMISSION, DATA_UNSHARED
class BaseView(View): class BaseView(View):
_TEMPLATE: str = "CHANGE_ME" _TEMPLATE: str = "CHANGE_ME"
_TAB_TITLE: str = "CHANGE_ME" _TAB_TITLE: str = "CHANGE_ME"
_REDIRECT_URL: str = "CHANGE_ME"
_REDIRECT_URL_ERROR: str = "home"
class Meta: class Meta:
abstract = True abstract = True
def dispatch(self, request, *args, **kwargs):
if not self._user_has_permission(request.user):
messages.info(request, MISSING_GROUP_PERMISSION)
return redirect(reverse(self._REDIRECT_URL_ERROR))
if not self._user_has_shared_access(request.user, **kwargs):
messages.info(request, DATA_UNSHARED)
return redirect(reverse(self._REDIRECT_URL_ERROR))
return super().dispatch(request, *args, **kwargs)
def _user_has_permission(self, user):
""" Has to be implemented properly by inheriting classes
Args:
user ():
Returns:
"""
return False
def _user_has_shared_access(self, user, **kwargs):
""" Has to be implemented properly by inheriting classes
Args:
user ():
Returns:
"""
return False
class BaseModalFormView(BaseView): class BaseModalFormView(BaseView):
_TEMPLATE = "modal/modal_form.html" _TEMPLATE = "modal/modal_form.html"
_TAB_TITLE = None _TAB_TITLE = None
class Meta:
abstract = True
class BaseIndexView(BaseView): class BaseIndexView(BaseView):
""" Base class for index views """ Base class for index views
@ -36,6 +72,7 @@ class BaseIndexView(BaseView):
""" """
_TEMPLATE = "generic_index.html" _TEMPLATE = "generic_index.html"
_INDEX_TABLE_CLS = None _INDEX_TABLE_CLS = None
_REDIRECT_URL = "home"
class Meta: class Meta:
abstract = True abstract = True
@ -61,20 +98,22 @@ class BaseIndexView(BaseView):
def _get_queryset(self): def _get_queryset(self):
raise NotImplementedError raise NotImplementedError
def _user_has_permission(self, user):
# No specific permissions needed for opening base index view
return True
class BaseIdentifierGeneratorView(View): def _user_has_shared_access(self, user, **kwargs):
# No specific constraints for shared access of index views
return True
class BaseIdentifierGeneratorView(BaseView):
_MODEL_CLS = None _MODEL_CLS = None
_REDIRECT_URL_NAME: str = "home" _REDIRECT_URL: str = "home"
class Meta: class Meta:
abstract = True abstract = True
def dispatch(self, request, *args, **kwargs):
if not self._user_has_permission(request.user):
messages.info(request, MISSING_GROUP_PERMISSION)
return redirect(reverse(self._REDIRECT_URL_NAME))
return super().dispatch(request, *args, **kwargs)
def get(self, request: HttpRequest): def get(self, request: HttpRequest):
tmp_obj = self._MODEL_CLS() tmp_obj = self._MODEL_CLS()
identifier = tmp_obj.generate_new_identifier() identifier = tmp_obj.generate_new_identifier()
@ -96,3 +135,7 @@ class BaseIdentifierGeneratorView(View):
""" """
return user.is_default_user() return user.is_default_user()
def _user_has_shared_access(self, user, **kwargs):
# No specific constraints for shared access
return True

View File

@ -6,30 +6,60 @@ Created on: 22.08.22
""" """
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404 from django.http import Http404, HttpRequest
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.urls import reverse from django.urls import reverse
from django.views import View
from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \ from intervention.forms.modals.deduction import NewEcoAccountDeductionModalForm, EditEcoAccountDeductionModalForm, \
RemoveEcoAccountDeductionModalForm RemoveEcoAccountDeductionModalForm
from konova.utils.message_templates import DEDUCTION_ADDED, DEDUCTION_EDITED, DEDUCTION_REMOVED, DEDUCTION_UNKNOWN from konova.utils.message_templates import DEDUCTION_ADDED, DEDUCTION_EDITED, DEDUCTION_REMOVED, DEDUCTION_UNKNOWN
from konova.views.base import BaseModalFormView
class AbstractDeductionView(View): class AbstractDeductionView(BaseModalFormView):
model = None _MODEL = None
redirect_url = None _REDIRECT_URL = None
def _custom_check(self, obj): def _custom_check(self, obj):
""" """
Can be used by inheriting classes to provide custom checks before further processing Can be used by inheriting classes to provide custom checks before further processing
""" """
raise NotImplementedError("Must be implemented in subclasses") pass
def _user_has_permission(self, user) -> bool:
"""
Args:
user ():
Returns:
"""
return user.is_default_user()
def _user_has_shared_access(self, user, **kwargs) -> bool:
""" A user has shared access on
Args:
user (User): The performing user
kwargs (dict): Parameters
Returns:
bool: True if the user has access to the requested object, False otherwise
"""
ret_val: bool = False
try:
obj = self._MODEL.objects.get(
id=kwargs.get("id")
)
ret_val = obj.is_shared_with(user)
except ObjectDoesNotExist:
ret_val = False
return ret_val
class AbstractNewDeductionView(AbstractDeductionView): class AbstractNewDeductionView(AbstractDeductionView):
class Meta: class Meta:
abstract = True abstract = True
@ -43,13 +73,13 @@ class AbstractNewDeductionView(AbstractDeductionView):
Returns: Returns:
""" """
obj = get_object_or_404(self.model, id=id) obj = get_object_or_404(self._MODEL, id=id)
self._custom_check(obj) self._custom_check(obj)
form = NewEcoAccountDeductionModalForm(request.POST or None, instance=obj, request=request) form = NewEcoAccountDeductionModalForm(request.POST or None, instance=obj, request=request)
return form.process_request( return form.process_request(
request, request,
msg_success=DEDUCTION_ADDED, msg_success=DEDUCTION_ADDED,
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data", redirect_url=reverse(self._REDIRECT_URL, args=(id,)) + "#related_data",
) )
def post(self, request, id: str): def post(self, request, id: str):
@ -57,10 +87,6 @@ class AbstractNewDeductionView(AbstractDeductionView):
class AbstractEditDeductionView(AbstractDeductionView): class AbstractEditDeductionView(AbstractDeductionView):
def _custom_check(self, obj):
pass
class Meta: class Meta:
abstract = True abstract = True
@ -75,7 +101,7 @@ class AbstractEditDeductionView(AbstractDeductionView):
Returns: Returns:
""" """
obj = get_object_or_404(self.model, id=id) obj = get_object_or_404(self._MODEL, id=id)
self._custom_check(obj) self._custom_check(obj)
try: try:
eco_deduction = obj.deductions.get(id=deduction_id) eco_deduction = obj.deductions.get(id=deduction_id)
@ -87,7 +113,7 @@ class AbstractEditDeductionView(AbstractDeductionView):
return form.process_request( return form.process_request(
request=request, request=request,
msg_success=DEDUCTION_EDITED, msg_success=DEDUCTION_EDITED,
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data" redirect_url=reverse(self._REDIRECT_URL, args=(id,)) + "#related_data"
) )
def post(self, request, id: str, deduction_id: str): def post(self, request, id: str, deduction_id: str):
@ -95,10 +121,6 @@ class AbstractEditDeductionView(AbstractDeductionView):
class AbstractRemoveDeductionView(AbstractDeductionView): class AbstractRemoveDeductionView(AbstractDeductionView):
def _custom_check(self, obj):
pass
class Meta: class Meta:
abstract = True abstract = True
@ -113,7 +135,7 @@ class AbstractRemoveDeductionView(AbstractDeductionView):
Returns: Returns:
""" """
obj = get_object_or_404(self.model, id=id) obj = get_object_or_404(self._MODEL, id=id)
self._custom_check(obj) self._custom_check(obj)
try: try:
eco_deduction = obj.deductions.get(id=deduction_id) eco_deduction = obj.deductions.get(id=deduction_id)
@ -124,7 +146,7 @@ class AbstractRemoveDeductionView(AbstractDeductionView):
return form.process_request( return form.process_request(
request=request, request=request,
msg_success=DEDUCTION_REMOVED, msg_success=DEDUCTION_REMOVED,
redirect_url=reverse(self.redirect_url, args=(id,)) + "#related_data" redirect_url=reverse(self._REDIRECT_URL, args=(id,)) + "#related_data"
) )
def post(self, request, id: str, deduction_id: str): def post(self, request, id: str, deduction_id: str):

View File

@ -18,9 +18,17 @@ from konova.contexts import BaseContext
from konova.decorators import login_required_modal from konova.decorators import login_required_modal
class UserDetailView(LoginRequiredMixin, BaseView): class UserBaseView(BaseView):
_TAB_TITLE = _("User settings") 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" _TEMPLATE = "user/index.html"
_TAB_TITLE = _("User settings")
def get(self, request: HttpRequest): def get(self, request: HttpRequest):
context = { context = {
@ -31,7 +39,7 @@ class UserDetailView(LoginRequiredMixin, BaseView):
return render(request, self._TEMPLATE, context) return render(request, self._TEMPLATE, context)
class NotificationsView(LoginRequiredMixin, BaseView): class NotificationsView(LoginRequiredMixin, UserBaseView):
_TEMPLATE = "user/notifications.html" _TEMPLATE = "user/notifications.html"
_TAB_TITLE = _("User notifications") _TAB_TITLE = _("User notifications")
@ -84,6 +92,14 @@ class ContactView(LoginRequiredMixin, BaseModalFormView):
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, self._TEMPLATE, 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): class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView):
def get(self, request: HttpRequest, id: str): def get(self, request: HttpRequest, id: str):
@ -104,8 +120,16 @@ class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView):
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, self._TEMPLATE, context) return render(request, self._TEMPLATE, context)
def _user_has_shared_access(self, user, **kwargs):
# No specific constraints
return True
class TeamIndexView(LoginRequiredMixin, BaseView): def _user_has_permission(self, user):
# No specific constraints
return True
class TeamIndexView(LoginRequiredMixin, UserBaseView):
_TEMPLATE = "user/team/index.html" _TEMPLATE = "user/team/index.html"
_TAB_TITLE = _("Teams") _TAB_TITLE = _("Teams")