Compare commits

..

No commits in common. "afbdf221c3b0f31ec4ffbf509b2698ffd408983e" and "e5db7f6b13145267be8c29f18ed5affb11cf03ed" have entirely different histories.

16 changed files with 304 additions and 287 deletions

View File

@ -17,14 +17,14 @@ from compensation.views.compensation.action import NewCompensationActionView, Ed
RemoveCompensationActionView RemoveCompensationActionView
from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \ from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \
RemoveCompensationStateView RemoveCompensationStateView
from compensation.views.compensation.compensation import new_view, detail_view, edit_view, \ from compensation.views.compensation.compensation import index_view, new_view, new_id_view, detail_view, edit_view, \
remove_view, CompensationIndexView, CompensationIdentifierGeneratorView remove_view
from compensation.views.compensation.log import CompensationLogView from compensation.views.compensation.log import CompensationLogView
urlpatterns = [ urlpatterns = [
# Main compensation # Main compensation
path("", CompensationIndexView.as_view(), name="index"), path("", index_view, name="index"),
path('new/id', CompensationIdentifierGeneratorView.as_view(), name='new-id'), path('new/id', new_id_view, name='new-id'),
path('new/<intervention_id>', new_view, name='new'), path('new/<intervention_id>', new_view, name='new'),
path('new', new_view, name='new'), path('new', new_view, name='new'),
path('<id>', detail_view, name='detail'), path('<id>', detail_view, name='detail'),

View File

@ -8,8 +8,8 @@ Created on: 24.08.21
from django.urls import path from django.urls import path
from compensation.autocomplete.eco_account import EcoAccountAutocomplete from compensation.autocomplete.eco_account import EcoAccountAutocomplete
from compensation.views.eco_account.eco_account import new_view, edit_view, remove_view, \ from compensation.views.eco_account.eco_account import index_view, new_view, new_id_view, edit_view, remove_view, \
detail_view, EcoAccountIndexView, EcoAccountIdentifierGeneratorView detail_view
from compensation.views.eco_account.log import EcoAccountLogView from compensation.views.eco_account.log import EcoAccountLogView
from compensation.views.eco_account.record import EcoAccountRecordView from compensation.views.eco_account.record import EcoAccountRecordView
from compensation.views.eco_account.report import report_view from compensation.views.eco_account.report import report_view
@ -28,9 +28,9 @@ from compensation.views.eco_account.deduction import NewEcoAccountDeductionView,
app_name = "acc" app_name = "acc"
urlpatterns = [ urlpatterns = [
path("", EcoAccountIndexView.as_view(), name="index"), path("", index_view, name="index"),
path('new/', new_view, name='new'), path('new/', new_view, name='new'),
path('new/id', EcoAccountIdentifierGeneratorView.as_view(), name='new-id'), path('new/id', new_id_view, name='new-id'),
path('<id>', detail_view, name='detail'), path('<id>', detail_view, name='detail'),
path('<id>/log', EcoAccountLogView.as_view(), name='log'), path('<id>/log', EcoAccountLogView.as_view(), name='log'),
path('<id>/record', EcoAccountRecordView.as_view(), name='record'), path('<id>/record', EcoAccountRecordView.as_view(), name='record'),

View File

@ -7,8 +7,8 @@ Created on: 19.08.22
""" """
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum
from django.http import HttpRequest, JsonResponse from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, render, redirect from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse from django.urls import reverse
@ -28,21 +28,37 @@ from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \ from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \
RECORDED_BLOCKS_EDIT, CHECK_STATE_RESET, FORM_INVALID, PARAMS_INVALID, IDENTIFIER_REPLACED, \ RECORDED_BLOCKS_EDIT, CHECK_STATE_RESET, FORM_INVALID, PARAMS_INVALID, IDENTIFIER_REPLACED, \
COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
class CompensationIndexView(LoginRequiredMixin, BaseIndexView): @login_required
_TAB_TITLE = _("Compensations - Overview") @any_group_check
_INDEX_TABLE_CLS = CompensationTable def index_view(request: HttpRequest):
"""
Renders the index view for compensation
def _get_queryset(self): Args:
qs = Compensation.objects.filter( request (HttpRequest): The incoming request
deleted=None, # only show those which are not deleted individually
intervention__deleted=None, # and don't show the ones whose intervention has been deleted Returns:
).order_by( A rendered view
"-modified__timestamp" """
) template = "generic_index.html"
return qs compensations = Compensation.objects.filter(
deleted=None, # only show those which are not deleted individually
intervention__deleted=None, # and don't show the ones whose intervention has been deleted
).order_by(
"-modified__timestamp"
)
table = CompensationTable(
request=request,
queryset=compensations
)
context = {
"table": table,
TAB_TITLE_IDENTIFIER: _("Compensations - Overview"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required @login_required
@ -115,9 +131,23 @@ def new_view(request: HttpRequest, intervention_id: str = None):
return render(request, template, context) return render(request, template, context)
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): @login_required
_MODEL_CLS = Compensation @default_group_required
_REDIRECT_URL_NAME = "compensation:index" def new_id_view(request: HttpRequest):
""" JSON endpoint
Provides fetching of free identifiers for e.g. AJAX calls
"""
tmp = Compensation()
identifier = tmp.generate_new_identifier()
while Compensation.objects.filter(identifier=identifier).exists():
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"gen_data": identifier
}
)
@login_required @login_required

View File

@ -7,7 +7,7 @@ Created on: 19.08.22
""" """
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Sum
from django.http import HttpRequest, JsonResponse from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
@ -24,20 +24,36 @@ from konova.settings import ETS_GROUP, DEFAULT_GROUP, ZB_GROUP
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import CANCEL_ACC_RECORDED_OR_DEDUCTED, RECORDED_BLOCKS_EDIT, FORM_INVALID, \ from konova.utils.message_templates import CANCEL_ACC_RECORDED_OR_DEDUCTED, RECORDED_BLOCKS_EDIT, FORM_INVALID, \
IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView): @login_required
_INDEX_TABLE_CLS = EcoAccountTable @any_group_check
_TAB_TITLE = _("Eco-account - Overview") def index_view(request: HttpRequest):
"""
Renders the index view for eco accounts
def _get_queryset(self): Args:
qs = EcoAccount.objects.filter( request (HttpRequest): The incoming request
deleted=None,
).order_by( Returns:
"-modified__timestamp" A rendered view
) """
return qs template = "generic_index.html"
eco_accounts = EcoAccount.objects.filter(
deleted=None,
).order_by(
"-modified__timestamp"
)
table = EcoAccountTable(
request=request,
queryset=eco_accounts
)
context = {
"table": table,
TAB_TITLE_IDENTIFIER: _("Eco-account - Overview"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required @login_required
@ -96,9 +112,23 @@ def new_view(request: HttpRequest):
return render(request, template, context) return render(request, template, context)
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): @login_required
_MODEL_CLS = EcoAccount @default_group_required
_REDIRECT_URL_NAME = "compensation:acc:index" def new_id_view(request: HttpRequest):
""" JSON endpoint
Provides fetching of free identifiers for e.g. AJAX calls
"""
tmp = EcoAccount()
identifier = tmp.generate_new_identifier()
while EcoAccount.objects.filter(identifier=identifier).exists():
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"gen_data": identifier
}
)
@login_required @login_required

View File

@ -10,8 +10,7 @@ from django.urls import path
from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView
from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView
from ema.views.document import NewEmaDocumentView, EditEmaDocumentView, RemoveEmaDocumentView, GetEmaDocumentView from ema.views.document import NewEmaDocumentView, EditEmaDocumentView, RemoveEmaDocumentView, GetEmaDocumentView
from ema.views.ema import new_view, detail_view, edit_view, remove_view, EmaIndexView, \ from ema.views.ema import index_view, new_view, new_id_view, detail_view, edit_view, remove_view
EmaIdentifierGeneratorView
from ema.views.log import EmaLogView from ema.views.log import EmaLogView
from ema.views.record import EmaRecordView from ema.views.record import EmaRecordView
from ema.views.report import report_view from ema.views.report import report_view
@ -21,9 +20,9 @@ from ema.views.state import NewEmaStateView, EditEmaStateView, RemoveEmaStateVie
app_name = "ema" app_name = "ema"
urlpatterns = [ urlpatterns = [
path("", EmaIndexView.as_view(), name="index"), path("", index_view, name="index"),
path("new/", new_view, name="new"), path("new/", new_view, name="new"),
path("new/id", EmaIdentifierGeneratorView.as_view(), name="new-id"), path("new/id", new_id_view, name="new-id"),
path("<id>", detail_view, name="detail"), path("<id>", detail_view, name="detail"),
path('<id>/log', EmaLogView.as_view(), name='log'), path('<id>/log', EmaLogView.as_view(), name='log'),
path('<id>/edit', edit_view, name='edit'), path('<id>/edit', edit_view, name='edit'),

View File

@ -7,7 +7,7 @@ Created on: 19.08.22
""" """
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Sum
from django.http import HttpRequest, JsonResponse from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse from django.urls import reverse
@ -24,21 +24,36 @@ from konova.forms.modals import RemoveModalForm
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import RECORDED_BLOCKS_EDIT, IDENTIFIER_REPLACED, FORM_INVALID, \ from konova.utils.message_templates import RECORDED_BLOCKS_EDIT, IDENTIFIER_REPLACED, FORM_INVALID, \
DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, MISSING_GROUP_PERMISSION DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
class EmaIndexView(LoginRequiredMixin, BaseIndexView): @login_required
_TAB_TITLE = _("EMAs - Overview") def index_view(request: HttpRequest):
_INDEX_TABLE_CLS = EmaTable """ Renders the index view for EMAs
def _get_queryset(self): Args:
qs = Ema.objects.filter( request (HttpRequest): The incoming request
deleted=None,
).order_by( Returns:
"-modified__timestamp"
) """
return qs template = "generic_index.html"
emas = Ema.objects.filter(
deleted=None,
).order_by(
"-modified__timestamp"
)
table = EmaTable(
request,
queryset=emas
)
context = {
"table": table,
TAB_TITLE_IDENTIFIER: _("EMAs - Overview"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required @login_required
@ -96,12 +111,23 @@ def new_view(request: HttpRequest):
return render(request, template, context) return render(request, template, context)
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): @login_required
_MODEL_CLS = Ema @conservation_office_group_required
_REDIRECT_URL_NAME = "ema:index" def new_id_view(request: HttpRequest):
""" JSON endpoint
def _user_has_permission(self, user): Provides fetching of free identifiers for e.g. AJAX calls
return user.is_ets_user()
"""
tmp = Ema()
identifier = tmp.generate_new_identifier()
while Ema.objects.filter(identifier=identifier).exists():
identifier = tmp.generate_new_identifier()
return JsonResponse(
data={
"gen_data": identifier
}
)
@login_required @login_required

View File

@ -14,8 +14,7 @@ from intervention.views.deduction import NewInterventionDeductionView, EditInter
RemoveInterventionDeductionView RemoveInterventionDeductionView
from intervention.views.document import NewInterventionDocumentView, GetInterventionDocumentView, \ from intervention.views.document import NewInterventionDocumentView, GetInterventionDocumentView, \
RemoveInterventionDocumentView, EditInterventionDocumentView RemoveInterventionDocumentView, EditInterventionDocumentView
from intervention.views.intervention import new_view, detail_view, edit_view, remove_view, \ from intervention.views.intervention import index_view, new_view, new_id_view, detail_view, edit_view, remove_view
InterventionIndexView, InterventionIdentifierGeneratorView
from intervention.views.log import InterventionLogView from intervention.views.log import InterventionLogView
from intervention.views.record import InterventionRecordView from intervention.views.record import InterventionRecordView
from intervention.views.report import report_view from intervention.views.report import report_view
@ -26,9 +25,9 @@ from intervention.views.share import InterventionShareFormView, InterventionShar
app_name = "intervention" app_name = "intervention"
urlpatterns = [ urlpatterns = [
path("", InterventionIndexView.as_view(), name="index"), path("", index_view, name="index"),
path('new/', new_view, name='new'), path('new/', new_view, name='new'),
path('new/id', InterventionIdentifierGeneratorView.as_view(), name='new-id'), path('new/id', new_id_view, name='new-id'),
path('<id>', detail_view, name='detail'), path('<id>', detail_view, name='detail'),
path('<id>/log', InterventionLogView.as_view(), name='log'), path('<id>/log', InterventionLogView.as_view(), name='log'),
path('<id>/edit', edit_view, name='edit'), path('<id>/edit', edit_view, name='edit'),

View File

@ -7,7 +7,6 @@ Created on: 19.08.22
""" """
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse, HttpRequest from django.http import JsonResponse, HttpRequest
from django.shortcuts import get_object_or_404, render, redirect from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse from django.urls import reverse
@ -26,22 +25,40 @@ from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, RECORDED_BLOCKS_EDIT, \ from konova.utils.message_templates import DATA_CHECKED_PREVIOUSLY_TEMPLATE, RECORDED_BLOCKS_EDIT, \
CHECK_STATE_RESET, FORM_INVALID, IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, \ CHECK_STATE_RESET, FORM_INVALID, IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, \
GEOMETRIES_IGNORED_TEMPLATE GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
class InterventionIndexView(LoginRequiredMixin, BaseIndexView): @login_required
_INDEX_TABLE_CLS = InterventionTable @any_group_check
_TAB_TITLE = _("Interventions - Overview") def index_view(request: HttpRequest):
"""
Renders the index view for Interventions
def _get_queryset(self): Args:
qs = Intervention.objects.filter( request (HttpRequest): The incoming request
deleted=None,
).select_related( Returns:
"legal" A rendered view
).order_by( """
"-modified__timestamp" template = "generic_index.html"
)
return qs # Filtering by user access is performed in table filter inside InterventionTableFilter class
interventions = Intervention.objects.filter(
deleted=None, # not deleted
).select_related(
"legal"
).order_by(
"-modified__timestamp"
)
table = InterventionTable(
request=request,
queryset=interventions
)
context = {
"table": table,
TAB_TITLE_IDENTIFIER: _("Interventions - Overview"),
}
context = BaseContext(request, context).context
return render(request, template, context)
@login_required @login_required
@ -100,9 +117,23 @@ def new_view(request: HttpRequest):
return render(request, template, context) return render(request, template, context)
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): @login_required
_MODEL_CLS = Intervention @default_group_required
_REDIRECT_URL_NAME = "intervention:index" def new_id_view(request: HttpRequest):
""" JSON endpoint
Provides fetching of free identifiers for e.g. AJAX calls
"""
tmp_intervention = Intervention()
identifier = tmp_intervention.generate_new_identifier()
while Intervention.objects.filter(identifier=identifier).exists():
identifier = tmp_intervention.generate_new_identifier()
return JsonResponse(
data={
"gen_data": identifier
}
)
@login_required @login_required

View File

@ -5,9 +5,6 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 17.09.21 Created on: 17.09.21
""" """
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
from django.http import HttpRequest
def format_german_float(num) -> str: def format_german_float(num) -> str:
@ -22,19 +19,3 @@ def format_german_float(num) -> str:
num (str): The number as german Gleitkommazahl num (str): The number as german Gleitkommazahl
""" """
return format(num, "0,.2f").replace(",", "X").replace(".", ",").replace("X", ".") return format(num, "0,.2f").replace(",", "X").replace(".", ",").replace("X", ".")
def check_user_is_in_any_group(request: HttpRequest):
"""
Checks for any group membership. Adds a message in case of having none.
"""
user = request.user
# Inform user about missing group privileges!
groups = user.groups.all()
if not groups:
messages.info(
request,
_("+++ Attention: You are not part of any group. You won't be able to create, edit or do anything. Please contact an administrator. +++")
)
return request

View File

@ -1,98 +0,0 @@
"""
Author: Michel Peltriaux
Created on: 15.10.25
"""
from abc import abstractmethod
from django.contrib import messages
from django.http import HttpRequest, JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from konova.contexts import BaseContext
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.general import check_user_is_in_any_group
from konova.utils.message_templates import MISSING_GROUP_PERMISSION
class BaseView(View):
_TEMPLATE: str = "CHANGE_ME"
_TAB_TITLE: str = "CHANGE_ME"
class Meta:
abstract = True
class BaseModalFormView(BaseView):
_TEMPLATE = "modal/modal_form.html"
_TAB_TITLE = None
class BaseIndexView(BaseView):
""" Base class for index views
"""
_TEMPLATE = "generic_index.html"
_INDEX_TABLE_CLS = None
class Meta:
abstract = True
def dispatch(self, request, *args, **kwargs):
request = check_user_is_in_any_group(request)
return super().dispatch(request, *args, **kwargs)
def get(self, request: HttpRequest):
qs = self._get_queryset()
table = self._INDEX_TABLE_CLS(
request=request,
queryset=qs
)
context = {
"table": table,
TAB_TITLE_IDENTIFIER: self._TAB_TITLE,
}
context = BaseContext(request, context).context
return render(request, self._TEMPLATE, context)
@abstractmethod
def _get_queryset(self):
raise NotImplementedError
class BaseIdentifierGeneratorView(View):
_MODEL_CLS = None
_REDIRECT_URL_NAME: str = "home"
class Meta:
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):
tmp_obj = self._MODEL_CLS()
identifier = tmp_obj.generate_new_identifier()
while self._MODEL_CLS.objects.filter(identifier=identifier).exists():
identifier = tmp_obj.generate_new_identifier()
return JsonResponse(
data={
"gen_data": identifier
}
)
def _user_has_permission(self, user):
""" Should be overwritten in inheriting classes!
Args:
user ():
Returns:
"""
return user.is_default_user()

View File

@ -56,7 +56,7 @@
{% if user.is_staff or user.is_superuser %} {% if user.is_staff or user.is_superuser %}
<a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a> <a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a>
{% endif %} {% endif %}
<a class="dropdown-item" href="{% url 'user:detail' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a> <a class="dropdown-item" href="{% url 'user:index' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a>
<a class="dropdown-item" href="{% url 'logout' %}">{% fa5_icon 'sign-out-alt' %} {% trans 'Logout' %}</a> <a class="dropdown-item" href="{% url 'logout' %}">{% fa5_icon 'sign-out-alt' %} {% trans 'Logout' %}</a>
</div> </div>
</li> </li>

View File

@ -38,7 +38,7 @@ class UserNotificationForm(BaseForm):
self.form_title = _("Edit notifications") self.form_title = _("Edit notifications")
self.form_caption = _("") self.form_caption = _("")
self.action_url = reverse("user:notifications") self.action_url = reverse("user:notifications")
self.cancel_redirect = reverse("user:detail") self.cancel_redirect = reverse("user:index")
# Insert all notifications into form field by creating choices as tuples # Insert all notifications into form field by creating choices as tuples
notifications = UserNotification.objects.filter( notifications = UserNotification.objects.filter(

View File

@ -26,7 +26,7 @@ class UserViewTestCase(BaseViewTestCase):
self.team.users.add(self.superuser) self.team.users.add(self.superuser)
self.team.admins.add(self.superuser) self.team.admins.add(self.superuser)
# Prepare urls # Prepare urls
self.index_url = reverse("user:detail", args=()) self.index_url = reverse("user:index", args=())
self.notification_url = reverse("user:notifications", args=()) self.notification_url = reverse("user:notifications", args=())
self.api_token_url = reverse("user:api-token", args=()) self.api_token_url = reverse("user:api-token", args=())
self.contact_url = reverse("user:contact", args=(self.superuser.id,)) self.contact_url = reverse("user:contact", args=(self.superuser.id,))

View File

@ -233,7 +233,7 @@ class UserNotificationFormTestCase(BaseTestCase):
self.assertEqual(form.form_title, str(_("Edit notifications"))) self.assertEqual(form.form_title, str(_("Edit notifications")))
self.assertEqual(form.form_caption, "") self.assertEqual(form.form_caption, "")
self.assertEqual(form.action_url, reverse("user:notifications")) self.assertEqual(form.action_url, reverse("user:notifications"))
self.assertEqual(form.cancel_redirect, reverse("user:detail")) self.assertEqual(form.cancel_redirect, reverse("user:index"))
def test_save(self): def test_save(self):
selected_notification = UserNotification.objects.first() selected_notification = UserNotification.objects.first()

View File

@ -15,15 +15,15 @@ from user.views.views import *
app_name = "user" app_name = "user"
urlpatterns = [ urlpatterns = [
path("", UserDetailView.as_view(), name="detail"), path("", index_view, name="index"),
path("propagate/", PropagateUserView.as_view(), name="propagate"), path("propagate/", PropagateUserView.as_view(), name="propagate"),
path("notifications/", NotificationsView.as_view(), name="notifications"), path("notifications/", notifications_view, name="notifications"),
path("token/api", APITokenView.as_view(), name="api-token"), path("token/api", APITokenView.as_view(), name="api-token"),
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>", contact_view, name="contact"),
path("team/", TeamIndexView.as_view(), name="team-index"), path("team/", index_team_view, name="team-index"),
path("team/new", new_team_view, name="team-new"), path("team/new", new_team_view, name="team-new"),
path("team/<id>", TeamDetailModalView.as_view(), name="team-data"), path("team/<id>", data_team_view, name="team-data"),
path("team/<id>/edit", edit_team_view, name="team-edit"), path("team/<id>/edit", edit_team_view, name="team-edit"),
path("team/<id>/remove", remove_team_view, name="team-remove"), path("team/<id>/remove", remove_team_view, name="team-remove"),
path("team/<id>/leave", leave_team_view, name="team-leave"), path("team/<id>/leave", leave_team_view, name="team-leave"),

View File

@ -1,10 +1,8 @@
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse from django.urls import reverse
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER 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.team import NewTeamModalForm, EditTeamModalForm, RemoveTeamModalForm, LeaveTeamModalForm
from user.forms.modals.user import UserContactForm from user.forms.modals.user import UserContactForm
from user.forms.team import TeamDataForm from user.forms.team import TeamDataForm
@ -15,108 +13,129 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from konova.contexts import BaseContext from konova.contexts import BaseContext
from konova.decorators import login_required_modal from konova.decorators import any_group_check, login_required_modal
class UserDetailView(LoginRequiredMixin, BaseView): @login_required
_TAB_TITLE = _("User settings") @any_group_check
_TEMPLATE = "user/index.html" def index_view(request: HttpRequest):
""" Renders the user's data index view
def get(self, request: HttpRequest): Args:
context = { request ():
"user": request.user,
TAB_TITLE_IDENTIFIER: self._TAB_TITLE, Returns:
}
context = BaseContext(request, context).context """
return render(request, self._TEMPLATE, context) template = "user/index.html"
context = {
"user": request.user,
TAB_TITLE_IDENTIFIER: _("User settings"),
}
context = BaseContext(request, context).context
return render(request, template, context)
class NotificationsView(LoginRequiredMixin, BaseView): @login_required
_TEMPLATE = "user/notifications.html" @any_group_check
_TAB_TITLE = _("User notifications") def notifications_view(request: HttpRequest):
""" Renders the notifications settings view
def get(self, request: HttpRequest): Args:
user = request.user request ():
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): Returns:
user = request.user
form = UserNotificationForm(user=user, data=request.POST) """
template = "user/notifications.html"
user = request.user
form = UserNotificationForm(user=user, data=request.POST or None)
if request.method == "POST":
if form.is_valid(): if form.is_valid():
form.save() form.save()
messages.success( messages.success(
request, request,
_("Notifications edited") _("Notifications edited")
) )
return redirect("user:detail") return redirect("user:index")
context = { elif request.method == "GET":
"user": user, # Implicit
"form": form, pass
TAB_TITLE_IDENTIFIER: self._TAB_TITLE, else:
} raise NotImplementedError
context = BaseContext(request, context).context
return render(request, self._TEMPLATE, context) context = {
"user": user,
"form": form,
TAB_TITLE_IDENTIFIER: _("User notifications"),
}
context = BaseContext(request, context).context
return render(request, template, context)
class ContactView(LoginRequiredMixin, BaseModalFormView): @login_required_modal
def get(self, request: HttpRequest, id: str): @login_required
""" Renders contact modal view of a users contact data def contact_view(request: HttpRequest, id: str):
""" Renders contact modal view of a users contact data
Args: Args:
request (HttpRequest): The incoming request request (HttpRequest): The incoming request
id (str): The user's id id (str): The user's id
Returns: Returns:
""" """
user = get_object_or_404(User, id=id) user = get_object_or_404(User, id=id)
form = UserContactForm(request.POST or None, instance=user, request=request) form = UserContactForm(request.POST or None, instance=user, request=request)
context = { template = "modal/modal_form.html"
"form": form, context = {
} "form": form,
context = BaseContext(request, context).context }
return render(request, self._TEMPLATE, context) context = BaseContext(request, context).context
return render(
request,
template,
context
)
class TeamDetailModalView(LoginRequiredMixin, BaseModalFormView): @login_required_modal
def get(self, request: HttpRequest, id: str): @login_required
""" Renders team data def data_team_view(request: HttpRequest, id: str):
""" Renders team data
Args: Args:
request (HttpRequest): The incoming request request (HttpRequest): The incoming request
id (str): The team's id id (str): The team's id
Returns: Returns:
""" """
team = get_object_or_404(Team, id=id) team = get_object_or_404(Team, id=id)
form = TeamDataForm(request.POST or None, instance=team, request=request) form = TeamDataForm(request.POST or None, instance=team, request=request)
context = { template = "modal/modal_form.html"
"form": form, context = {
} "form": form,
context = BaseContext(request, context).context }
return render(request, self._TEMPLATE, context) context = BaseContext(request, context).context
return render(
request,
template,
context
)
class TeamIndexView(LoginRequiredMixin, BaseView): @login_required
_TEMPLATE = "user/team/index.html" def index_team_view(request: HttpRequest):
_TAB_TITLE = _("Teams") template = "user/team/index.html"
user = request.user
def get(self, request: HttpRequest): context = {
user = request.user "teams": user.shared_teams,
context = { "tab_title": _("Teams"),
"teams": user.shared_teams, }
"tab_title": self._TAB_TITLE, context = BaseContext(request, context).context
} return render(request, template, context)
context = BaseContext(request, context).context
return render(request, self._TEMPLATE, context)
@login_required_modal @login_required_modal