diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 0584151..e9b0453 100644 Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index cbe4abe..ac4709e 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: wira-risk-management\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-09-09 14:20+0200\n" +"POT-Creation-Date: 2025-09-09 21:18+0200\n" "PO-Revision-Date: 2025-09-09 13:45+0200\n" "Last-Translator: Kevin Heyer \n" "Language-Team: German\n" @@ -40,73 +40,55 @@ msgstr "Risikomanagement" msgid "Risk" msgstr "Risiko" -#: risks/models.py:36 +#: risks/models.py:36 templates/risks/dashboard.html:85 msgid "Risks" msgstr "Risiken" #: risks/models.py:39 -#, fuzzy -#| msgid "Very low occurs less than once every 5 years" msgid "Very low – occurs less than once every 5 years" msgstr "Sehr niedrig – tritt seltener als einmal in fünf Jahren auf" #: risks/models.py:40 -#, fuzzy -#| msgid "Low once every 15 years" msgid "Low – once every 1–5 years" msgstr "Niedrig – einmal in 1–5 Jahren" #: risks/models.py:41 -#, fuzzy -#| msgid "Likely once per year or more" msgid "Likely – once per year or more" msgstr "Wahrscheinlich – einmal pro Jahr oder öfter" #: risks/models.py:42 -#, fuzzy -#| msgid "Very likely multiple times per year/monthly" msgid "Very likely – multiple times per year/monthly" msgstr "Sehr wahrscheinlich – mehrmals pro Jahr/monatlich" #: risks/models.py:45 -#, fuzzy -#| msgid "Low (< 1,000 minor operational impact)" msgid "Very Low (< 1,000 € – minor operational impact)" msgstr "Sehr Gering (< 1.000 € – geringe betriebliche Auswirkungen)" #: risks/models.py:46 -#, fuzzy -#| msgid "Medium (1,0005,000 local impact)" msgid "Low (1,000–5,000 € – local impact)" msgstr "Gering (1.000–5.000 € – lokale Auswirkungen)" #: risks/models.py:47 -#, fuzzy -#| msgid "High (5,00015,000 team-level impact)" msgid "High (5,000–15,000 € – team-level impact)" msgstr "Hoch (5.000–15.000 € – Auswirkungen auf Teamebene)" #: risks/models.py:48 -#, fuzzy -#| msgid "Severe (50,000100,000 regional impact)" msgid "Severe (50,000–100,000 € – regional impact)" msgstr "Schwerwiegend (50.000–100.000 € – regionale Auswirkungen)" #: risks/models.py:49 -#, fuzzy -#| msgid "Critical (> 100,000 existential threat)" msgid "Critical (> 100,000 € – existential threat)" msgstr "Kritisch (> 100.000 € – existenzielle Bedrohung)" -#: risks/models.py:52 +#: risks/models.py:52 templates/risks/dashboard.html:74 msgid "Confidentiality" msgstr "Vertraulichkeit" -#: risks/models.py:53 +#: risks/models.py:53 templates/risks/dashboard.html:79 msgid "Integrity" msgstr "Integrität" -#: risks/models.py:54 +#: risks/models.py:54 templates/risks/dashboard.html:84 msgid "Availability" msgstr "Verfügbarkeit" @@ -209,3 +191,35 @@ msgstr "Meldedatum" #: risks/models.py:255 msgid "Reported by" msgstr "Gemeldet von" + +#: templates/risks/dashboard.html:9 +msgid "Dashboard" +msgstr "Dashboard" + +#: templates/risks/dashboard.html:12 +msgid "Overview of Risks, Controls and Incidents" +msgstr "Übersicht der Risiken, Maßnahmen und Vorfälle" + +#: templates/risks/dashboard.html:25 +msgid "Total Risks" +msgstr "Restrisiken" + +#: templates/risks/dashboard.html:33 +msgid "Residual Risks Needing Review" +msgstr "Restrisiken ohne Verifizierung" + +#: templates/risks/dashboard.html:41 +msgid "Unread Notifications" +msgstr "Ungelesene Nachrichten" + +#: templates/risks/dashboard.html:48 +msgid "Controls by Status" +msgstr "Maßnahmen nach Status" + +#: templates/risks/dashboard.html:58 +msgid "Incidents by Status" +msgstr "Vorfälle nach Status" + +#: templates/risks/dashboard.html:68 +msgid "Risks by CIA" +msgstr "CIA Risiken" diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 84faae8..048571b 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-09-09 14:20+0200\n" +"POT-Creation-Date: 2025-09-09 21:18+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -46,7 +46,7 @@ msgstr "" msgid "Risk" msgstr "" -#: risks/models.py:36 +#: risks/models.py:36 templates/risks/dashboard.html:85 msgid "Risks" msgstr "" @@ -86,15 +86,15 @@ msgstr "" msgid "Critical (> 100,000 € – existential threat)" msgstr "" -#: risks/models.py:52 +#: risks/models.py:52 templates/risks/dashboard.html:74 msgid "Confidentiality" msgstr "" -#: risks/models.py:53 +#: risks/models.py:53 templates/risks/dashboard.html:79 msgid "Integrity" msgstr "" -#: risks/models.py:54 +#: risks/models.py:54 templates/risks/dashboard.html:84 msgid "Availability" msgstr "" @@ -197,3 +197,35 @@ msgstr "" #: risks/models.py:255 msgid "Reported by" msgstr "" + +#: templates/risks/dashboard.html:9 +msgid "Dashboard" +msgstr "" + +#: templates/risks/dashboard.html:12 +msgid "Overview of Risks, Controls and Incidents" +msgstr "" + +#: templates/risks/dashboard.html:25 +msgid "Total Risks" +msgstr "" + +#: templates/risks/dashboard.html:33 +msgid "Residual Risks Needing Review" +msgstr "" + +#: templates/risks/dashboard.html:41 +msgid "Unread Notifications" +msgstr "" + +#: templates/risks/dashboard.html:48 +msgid "Controls by Status" +msgstr "" + +#: templates/risks/dashboard.html:58 +msgid "Incidents by Status" +msgstr "" + +#: templates/risks/dashboard.html:68 +msgid "Risks by CIA" +msgstr "" diff --git a/risks/views.py b/risks/views.py index fab38da..1a994e7 100644 --- a/risks/views.py +++ b/risks/views.py @@ -2,10 +2,12 @@ from django.contrib.admin.models import LogEntry from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required from django.contrib.contenttypes.models import ContentType +from django.db.models import Count, Q from rest_framework import viewsets from rest_framework.permissions import IsAuthenticated from django.shortcuts import render, get_object_or_404 -from .models import Risk, Control, ResidualRisk, AuditLog, Incident +from collections import Counter +from .models import Risk, Control, ResidualRisk, AuditLog, Incident, Notification from .serializers import ControlSerializer, RiskSerializer, ResidualRiskSerializer, UserSerializer, AuditSerializer, IncidentSerializer User = get_user_model() @@ -93,13 +95,9 @@ class IncidentViewSet(viewsets.ModelViewSet): instance._changed_by = self.request.user # --------------------------------------------------------------------------- -# Web +# Web => Risks, Controls, Incidents # --------------------------------------------------------------------------- -@login_required -def dashboard(request): - return render(request, "risks/dashboard.html") - @login_required def stats(request): return render(request, "risks/statistics.html") @@ -220,3 +218,49 @@ def show_incident(request, id): ).order_by("-action_time") return render(request, "risks/item_incident.html", {"incident": incident, "logs": logs}) + +# --------------------------------------------------------------------------- +# Web => Dashboard +# --------------------------------------------------------------------------- + +@login_required +def dashboard(request): + # Risikoübersicht + risks_total = Risk.objects.count() + risks_by_level = Risk.objects.values('level').annotate(count=Count('id')) + + # CIA-Zähler für MultiSelectField + risks_cia = Risk.objects.values_list('cia', flat=True) + cia_counter = Counter() + for cia_list in risks_cia: + if isinstance(cia_list, list): # MultiSelectField gibt Liste zurück + for c in cia_list: + cia_counter[c] += 1 + elif cia_list: # Falls irgendwie noch ein String drin ist + cia_counter[cia_list] += 1 + + # Residualrisiken + residual_review_required = ResidualRisk.objects.filter(review_required=True).count() + + # Kontrollen + controls_by_status = Control.objects.values('status').annotate(count=Count('id')) + + # Incidents + incidents_status = Incident.objects.values('status').annotate(count=Count('id')) + + # Benachrichtigungen + notifications_unread = Notification.objects.filter(user=request.user, read=False).count() + + print(type(cia_counter), cia_counter) + + # Context für Template + context = { + 'risks_total': risks_total, + 'risks_by_level': risks_by_level, + 'risks_by_cia': dict(cia_counter), # <-- hier Counter in dict umwandeln + 'residual_review_required': residual_review_required, + 'controls_by_status': controls_by_status, + 'incidents_status': incidents_status, + 'notifications_unread': notifications_unread, + } + return render(request, 'risks/dashboard.html', context) diff --git a/static/css/design.css b/static/css/design.css index dcbc5d7..b29d3a4 100644 --- a/static/css/design.css +++ b/static/css/design.css @@ -141,4 +141,23 @@ .content li+li { margin: 0 !important; +} + + +/* DARK MODE */ + +/* static/css/custom.css */ +body.dark-mode { + background-color: #121212; + color: #f5f5f5; +} + +body.dark-mode .box { + background-color: #1e1e1e; + color: #f5f5f5; +} + +/* Optional: Buttons, Links etc. anpassen */ +body.dark-mode a { + color: #bb86fc; } \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index e9fea9d..7be4056 100644 --- a/templates/base.html +++ b/templates/base.html @@ -27,17 +27,10 @@