Compare commits

...

9 Commits

Author SHA1 Message Date
afbdf221c3 # User view refactoring
* refactors majority of user views into class based views
* introduces BaseModalFormView and BaseView for even more generic usage
* renames url identifier user:index into user:detail for more clarity
2025-10-15 17:09:40 +02:00
be9f6f1b7e # Identifier Generator View EcoAccount refactoring
* refactors identifier generator view for ecoaccount
* simplifies base identifier generator view even further
2025-10-15 16:46:07 +02:00
80e8925a63 # Identifier Generator View Compensation refactoring
* refactors identifier generator view for compensation
2025-10-15 16:42:42 +02:00
c597e1934b # Identifier Generator View refactoring
* refactors identifier generator view for interventions
* simplifies same view for ema
2025-10-15 16:40:35 +02:00
a44d8658d4 # NewId Generator Ema refactoring
* introduces BaseNewIdentifierGeneratorView class
* refactors new identifier generator view for ema
2025-10-15 16:29:05 +02:00
bb71c0fcc8 # Index Ema refactoring
* refactors index view for ema
2025-10-15 16:14:03 +02:00
67acddf701 # Index EcoAccount refactoring
* refactors index view for eco account
2025-10-15 16:12:21 +02:00
21bb988d86 # Index Compensation refactoring
* refactors index view for compensations
2025-10-15 16:03:53 +02:00
1ceffccd40 # Index Intervention refactoring
* introduces BaseIndexView class
* refactors index view for interventions
2025-10-15 16:00:51 +02:00
16 changed files with 287 additions and 304 deletions

View File

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

View File

@ -8,8 +8,8 @@ Created on: 24.08.21
from django.urls import path
from compensation.autocomplete.eco_account import EcoAccountAutocomplete
from compensation.views.eco_account.eco_account import index_view, new_view, new_id_view, edit_view, remove_view, \
detail_view
from compensation.views.eco_account.eco_account import new_view, edit_view, remove_view, \
detail_view, EcoAccountIndexView, EcoAccountIdentifierGeneratorView
from compensation.views.eco_account.log import EcoAccountLogView
from compensation.views.eco_account.record import EcoAccountRecordView
from compensation.views.eco_account.report import report_view
@ -28,9 +28,9 @@ from compensation.views.eco_account.deduction import NewEcoAccountDeductionView,
app_name = "acc"
urlpatterns = [
path("", index_view, name="index"),
path("", EcoAccountIndexView.as_view(), name="index"),
path('new/', new_view, name='new'),
path('new/id', new_id_view, name='new-id'),
path('new/id', EcoAccountIdentifierGeneratorView.as_view(), name='new-id'),
path('<id>', detail_view, name='detail'),
path('<id>/log', EcoAccountLogView.as_view(), name='log'),
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.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Sum
from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
@ -28,37 +28,21 @@ from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
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, \
COMPENSATION_ADDED_TEMPLATE, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
@login_required
@any_group_check
def index_view(request: HttpRequest):
"""
Renders the index view for compensation
class CompensationIndexView(LoginRequiredMixin, BaseIndexView):
_TAB_TITLE = _("Compensations - Overview")
_INDEX_TABLE_CLS = CompensationTable
Args:
request (HttpRequest): The incoming request
Returns:
A rendered view
"""
template = "generic_index.html"
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)
def _get_queryset(self):
qs = 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"
)
return qs
@login_required
@ -131,23 +115,9 @@ def new_view(request: HttpRequest, intervention_id: str = None):
return render(request, template, context)
@login_required
@default_group_required
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
}
)
class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Compensation
_REDIRECT_URL_NAME = "compensation:index"
@login_required

View File

@ -7,7 +7,7 @@ Created on: 19.08.22
"""
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Sum
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
@ -24,36 +24,20 @@ from konova.settings import ETS_GROUP, DEFAULT_GROUP, ZB_GROUP
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, \
IDENTIFIER_REPLACED, DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
@login_required
@any_group_check
def index_view(request: HttpRequest):
"""
Renders the index view for eco accounts
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView):
_INDEX_TABLE_CLS = EcoAccountTable
_TAB_TITLE = _("Eco-account - Overview")
Args:
request (HttpRequest): The incoming request
Returns:
A rendered view
"""
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)
def _get_queryset(self):
qs = EcoAccount.objects.filter(
deleted=None,
).order_by(
"-modified__timestamp"
)
return qs
@login_required
@ -112,23 +96,9 @@ def new_view(request: HttpRequest):
return render(request, template, context)
@login_required
@default_group_required
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
}
)
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = EcoAccount
_REDIRECT_URL_NAME = "compensation:acc:index"
@login_required

View File

@ -10,7 +10,8 @@ from django.urls import path
from ema.views.action import NewEmaActionView, EditEmaActionView, RemoveEmaActionView
from ema.views.deadline import NewEmaDeadlineView, EditEmaDeadlineView, RemoveEmaDeadlineView
from ema.views.document import NewEmaDocumentView, EditEmaDocumentView, RemoveEmaDocumentView, GetEmaDocumentView
from ema.views.ema import index_view, new_view, new_id_view, detail_view, edit_view, remove_view
from ema.views.ema import new_view, detail_view, edit_view, remove_view, EmaIndexView, \
EmaIdentifierGeneratorView
from ema.views.log import EmaLogView
from ema.views.record import EmaRecordView
from ema.views.report import report_view
@ -20,9 +21,9 @@ from ema.views.state import NewEmaStateView, EditEmaStateView, RemoveEmaStateVie
app_name = "ema"
urlpatterns = [
path("", index_view, name="index"),
path("", EmaIndexView.as_view(), name="index"),
path("new/", new_view, name="new"),
path("new/id", new_id_view, name="new-id"),
path("new/id", EmaIdentifierGeneratorView.as_view(), name="new-id"),
path("<id>", detail_view, name="detail"),
path('<id>/log', EmaLogView.as_view(), name='log'),
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.auth.decorators import login_required
from django.db.models import Sum
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
@ -24,36 +24,21 @@ from konova.forms.modals import RemoveModalForm
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from konova.utils.message_templates import RECORDED_BLOCKS_EDIT, IDENTIFIER_REPLACED, FORM_INVALID, \
DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
DO_NOT_FORGET_TO_SHARE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE, MISSING_GROUP_PERMISSION
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
@login_required
def index_view(request: HttpRequest):
""" Renders the index view for EMAs
class EmaIndexView(LoginRequiredMixin, BaseIndexView):
_TAB_TITLE = _("EMAs - Overview")
_INDEX_TABLE_CLS = EmaTable
Args:
request (HttpRequest): The incoming request
Returns:
"""
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)
def _get_queryset(self):
qs = Ema.objects.filter(
deleted=None,
).order_by(
"-modified__timestamp"
)
return qs
@login_required
@ -111,23 +96,12 @@ def new_view(request: HttpRequest):
return render(request, template, context)
@login_required
@conservation_office_group_required
def new_id_view(request: HttpRequest):
""" JSON endpoint
class EmaIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Ema
_REDIRECT_URL_NAME = "ema:index"
Provides fetching of free identifiers for e.g. AJAX calls
"""
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
}
)
def _user_has_permission(self, user):
return user.is_ets_user()
@login_required

View File

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

View File

@ -7,6 +7,7 @@ Created on: 19.08.22
"""
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import JsonResponse, HttpRequest
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
@ -25,40 +26,22 @@ from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
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, \
GEOMETRIES_IGNORED_TEMPLATE
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView
@login_required
@any_group_check
def index_view(request: HttpRequest):
"""
Renders the index view for Interventions
class InterventionIndexView(LoginRequiredMixin, BaseIndexView):
_INDEX_TABLE_CLS = InterventionTable
_TAB_TITLE = _("Interventions - Overview")
Args:
request (HttpRequest): The incoming request
Returns:
A rendered view
"""
template = "generic_index.html"
# 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)
def _get_queryset(self):
qs = Intervention.objects.filter(
deleted=None,
).select_related(
"legal"
).order_by(
"-modified__timestamp"
)
return qs
@login_required
@ -117,23 +100,9 @@ def new_view(request: HttpRequest):
return render(request, template, context)
@login_required
@default_group_required
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
}
)
class InterventionIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
_MODEL_CLS = Intervention
_REDIRECT_URL_NAME = "intervention:index"
@login_required

View File

@ -5,6 +5,9 @@ Contact: michel.peltriaux@sgdnord.rlp.de
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:
@ -19,3 +22,19 @@ def format_german_float(num) -> str:
num (str): The number as german Gleitkommazahl
"""
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

98
konova/views/base.py Normal file
View File

@ -0,0 +1,98 @@
"""
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 %}
<a class="dropdown-item" target="_blank" href="{% url 'admin:index' %}">{% fa5_icon 'tools' %} {% trans 'Admin' %}</a>
{% endif %}
<a class="dropdown-item" href="{% url 'user:index' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a>
<a class="dropdown-item" href="{% url 'user:detail' %}">{% fa5_icon 'cogs' %} {% trans 'Settings' %}</a>
<a class="dropdown-item" href="{% url 'logout' %}">{% fa5_icon 'sign-out-alt' %} {% trans 'Logout' %}</a>
</div>
</li>

View File

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

View File

@ -26,7 +26,7 @@ class UserViewTestCase(BaseViewTestCase):
self.team.users.add(self.superuser)
self.team.admins.add(self.superuser)
# Prepare urls
self.index_url = reverse("user:index", args=())
self.index_url = reverse("user:detail", args=())
self.notification_url = reverse("user:notifications", args=())
self.api_token_url = reverse("user:api-token", args=())
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_caption, "")
self.assertEqual(form.action_url, reverse("user:notifications"))
self.assertEqual(form.cancel_redirect, reverse("user:index"))
self.assertEqual(form.cancel_redirect, reverse("user:detail"))
def test_save(self):
selected_notification = UserNotification.objects.first()

View File

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

View File

@ -1,8 +1,10 @@
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
@ -13,129 +15,108 @@ 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 any_group_check, login_required_modal
from konova.decorators import login_required_modal
@login_required
@any_group_check
def index_view(request: HttpRequest):
""" Renders the user's data index view
class UserDetailView(LoginRequiredMixin, BaseView):
_TAB_TITLE = _("User settings")
_TEMPLATE = "user/index.html"
Args:
request ():
Returns:
"""
template = "user/index.html"
context = {
"user": request.user,
TAB_TITLE_IDENTIFIER: _("User settings"),
}
context = BaseContext(request, context).context
return render(request, template, context)
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)
@login_required
@any_group_check
def notifications_view(request: HttpRequest):
""" Renders the notifications settings view
class NotificationsView(LoginRequiredMixin, BaseView):
_TEMPLATE = "user/notifications.html"
_TAB_TITLE = _("User notifications")
Args:
request ():
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)
Returns:
"""
template = "user/notifications.html"
user = request.user
form = UserNotificationForm(user=user, data=request.POST or None)
if request.method == "POST":
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:index")
elif request.method == "GET":
# Implicit
pass
else:
raise NotImplementedError
context = {
"user": user,
"form": form,
TAB_TITLE_IDENTIFIER: _("User notifications"),
}
context = BaseContext(request, context).context
return render(request, template, context)
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)
@login_required_modal
@login_required
def contact_view(request: HttpRequest, id: str):
""" Renders contact modal view of a users contact data
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
Args:
request (HttpRequest): The incoming request
id (str): The user's id
Returns:
Returns:
"""
user = get_object_or_404(User, id=id)
form = UserContactForm(request.POST or None, instance=user, request=request)
template = "modal/modal_form.html"
context = {
"form": form,
}
context = BaseContext(request, context).context
return render(
request,
template,
context
)
"""
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)
@login_required_modal
@login_required
def data_team_view(request: HttpRequest, id: str):
""" Renders team data
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
Args:
request (HttpRequest): The incoming request
id (str): The team's id
Returns:
Returns:
"""
team = get_object_or_404(Team, id=id)
form = TeamDataForm(request.POST or None, instance=team, request=request)
template = "modal/modal_form.html"
context = {
"form": form,
}
context = BaseContext(request, context).context
return render(
request,
template,
context
)
"""
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)
@login_required
def index_team_view(request: HttpRequest):
template = "user/team/index.html"
user = request.user
context = {
"teams": user.shared_teams,
"tab_title": _("Teams"),
}
context = BaseContext(request, context).context
return render(request, template, context)
class TeamIndexView(LoginRequiredMixin, BaseView):
_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