From 066a749363bc6b222a2a70b5639cc82854a11f55 Mon Sep 17 00:00:00 2001 From: Matthias Nagel Date: Wed, 1 Oct 2025 13:58:48 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Implementierung=20der=20Eltern-Funktion?= =?UTF-8?q?alit=C3=A4t=20zur=20Event-Teilnahmeverwaltung=20und=20Autocompl?= =?UTF-8?q?ete-Verbesserungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- accounts/__pycache__/admin.cpython-313.pyc | Bin 928 -> 1403 bytes accounts/admin.py | 9 ++- calendars/__pycache__/urls.cpython-313.pyc | Bin 1061 -> 1218 bytes calendars/__pycache__/views.cpython-313.pyc | Bin 4628 -> 5545 bytes calendars/urls.py | 1 + calendars/views.py | 24 +++++- dashboard/__pycache__/views.cpython-313.pyc | Bin 1460 -> 2299 bytes dashboard/templates/dashboard/dashboard.html | 44 ++++++++++- dashboard/views.py | 28 ++++--- db.sqlite3 | Bin 282624 -> 282624 bytes docs/traceback/trace5.log | 74 +++++++++++++++++++ 11 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 docs/traceback/trace5.log diff --git a/accounts/__pycache__/admin.cpython-313.pyc b/accounts/__pycache__/admin.cpython-313.pyc index 2cf9cb3ce2d8dac223d470611a2862f6c0e8d34e..181458ba38305904975e7beb301ee952955f613f 100644 GIT binary patch delta 744 zcmZ8e&1(}u6rY{lB%7~pVu&`iV6?V%u{K&L^iY%{1(SY~Q1KwF+h*5H*^e-@IkX_j zK?F}07f%X$tVeJ5)IY#Wk_rt2f`3A7yoeWPniWbP%&T*VgBaM+ zZG%dlq1#lcB2u^X9j&fo!|@1}5z&aJo8~GFo5--LM1?rX-lLI#q6#?8;w{Kk0t+)Q zvekdf;2o$4Wg$2@bIn1pA(YQw3K-?kdFo(48>BMeF(j}62+V*-Ljbrp%3SJ#t;3ZR z0CA9KJO|DO(l=Q&$e8m$g{!-8Dz8dZ+IEq1Rsj`t%fbovm?~0<7?w#zcXOMDgF<;h z`F!3l!3RyI4d}Ip4dS`>25aF$)ke|1HVGM-j7$QDL*54jG_YJ7+u+R}8-!)UYN8AQ|YRVLDB3*cc6 z(f`23$s&VSpqIGZTBMn^)^abEJ5G&tQe(Yna!+oL+`iLRrrUDiM1+&!UjU}Vt>Q@- zGcPX}0}vb*zMHX(iGkrUhyw#WP{!w38`Vo0wPF~R7=i_3n1jS%3J`R# zP%xV%vp#zfPr9(C$mAuAmqV&73lfV;GLth45=%1k^Ym>p^Gd9eGct2h;xkk1Al%fl z)VvZ1x45Lps<FEjgT n@=Siq)H`_sa}1XVP#q%>7jKySjd=~v2VQo5rbg}}A)pWdKD!ny diff --git a/calendars/__pycache__/views.cpython-313.pyc b/calendars/__pycache__/views.cpython-313.pyc index 4831890addc72acf50e46e67254747e0f2c13635..7bacaaa0dbddefb3b79a606ffcafcbdac42ed690 100644 GIT binary patch literal 5545 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 YynW&wkn%n$i}RBo*^h}vmz1-=0h@R diff --git a/calendars/urls.py b/calendars/urls.py index 61df0de..873c0cb 100644 --- a/calendars/urls.py +++ b/calendars/urls.py @@ -8,4 +8,5 @@ urlpatterns = [ path('game/add/', views.GameCreateView.as_view(), name='game-add'), path('event//', views.EventUpdateView.as_view(), name='event-update'), path('event//delete/', views.EventDeleteView.as_view(), name='event-delete'), + path('participation////', views.manage_participation, name='manage-participation'), ] diff --git a/calendars/views.py b/calendars/views.py index b8f61ee..c6e113f 100644 --- a/calendars/views.py +++ b/calendars/views.py @@ -1,9 +1,11 @@ -from django.shortcuts import render +from django.shortcuts import render, get_object_or_404, redirect from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.auth.decorators import login_required from django.urls import reverse_lazy -from .models import Event, Training, Game +from .models import Event, Training, Game, EventParticipation from .forms import EventForm, TrainingForm, GameForm +from accounts.models import CustomUser # Import CustomUser for manage_participation view def select_event_type(request): return render(request, 'calendars/select_event_type.html') @@ -73,4 +75,20 @@ class EventUpdateView(LoginRequiredMixin, CoachCheckMixin, UpdateView): class EventDeleteView(LoginRequiredMixin, CoachCheckMixin, DeleteView): model = Event template_name = 'calendars/event_confirm_delete.html' - success_url = reverse_lazy('dashboard') \ No newline at end of file + success_url = reverse_lazy('dashboard') + +@login_required +def manage_participation(request, child_id, event_id, status): + child = get_object_or_404(CustomUser, id=child_id) + event = get_object_or_404(Event, id=event_id) + + # Check if the logged-in user is a parent of the child + if request.user not in child.parents.all(): + # Handle unauthorized access + return redirect('dashboard') + + participation, created = EventParticipation.objects.get_or_create(user=child, event=event) + participation.status = status + participation.save() + + return redirect('dashboard') \ No newline at end of file diff --git a/dashboard/__pycache__/views.cpython-313.pyc b/dashboard/__pycache__/views.cpython-313.pyc index dc2c99ac836e21d0e6ffa05b6cd9a4bdc862976b..3470ac5e145de7d11996d21b37134796780459e3 100644 GIT binary patch delta 1197 zcmZuvO>7%Q6rTO@?%G~won)QFX_GZ>{%qnPVL1pXs*9A6k~D4cb|tH6YL;YaEV&zZ zcFj*k8YA^kxWv{VL90q|q!mIva41}Q>7fS@yRsBpOA>nI*pS{TBxdax7l}E%_s#dd z_vX#K`O*KPyX!Cz@BzGT_U^6!?WuMR5T~o-cZSI?sOrxn^lLz;tNSYijb?}>;Xy?r z>1Sk8rWTn6R%g)QJj2h%dhxxJ$zrCUyigZ zWcu2u<1;5ZxQ()RW#5}*2{&8ZSA3b#HsA5tUuFLknIc+D1T4J)fFDGFLbcRqI#L&9 z@5uarge4@Kukat@?@4Ch!Z zgN{dYXBZ=4H)fqc@#QIEk*AsGFin+#Wuhw++SPLCH}aKk5e8kBT~`g&G$HgNl1dUj zG)<+q1RQ}(v-TCu%x%EjD%4a{a~QQ))buszb{Y#hEYz-*G{bC`YMuf^ZWdoGsGn#s zXKLzI1NOVs!me@ut>aY-g`-HXyYFuHm1{MdE94Dx+Tma3nzw{Ku9j`}v4+8hZfYN! zhI@%fYoW)~h3Knz?{;q7#Dgk>r~aPpna^j+vyFgIe!I~(P(FuJ^eEL32T+b49o(a( z-JtlTd^_~@rw`B8!i%-gnObnE{LVi5mQHRxX8ym6svUTC2b?Jke zbfqp8ZK-Ho+pI}9D*W$5vC7!5J^h62m%3dISI)@aF|0WE|;)(<{?pB zi-Z)PmI7KjItmJY0VRs!2CZT#6(uq_jHexsTBW@i89J|)tlRB8&iz2Dzm z+mhq-QPhgd<&!2@U@1%Zx<)h;R%J^)26a)#jp*^_d<8Le@u};FRm7AP*IDnNarOWW zjxzVr4vKe*@%}wkw$U9-d*~ce=xbD4R4vJpg}#qXXy+!q?L!l0<2kr{!B*=+hg z{^a#FTce89L>g^Lt)ivd(s|_T?Nj4&02?gB)+g;ns7}!b$^ydlk20IjGNl{1glTI| z;DjL|I<2TRWYAT$c}q;J8cZYZldcp z+|3?-W4$Z9effF0KfTm1+~{X-M%TX6Gg_^}OO0G_eke;B99{i|A(`)$w~yC9KIfO;nH5}o7}Fa(-SylBQs$xf>Y&77 hC?kXhaC!h22QW8)nLU*GDIGzV(MSd -

Your Team's Events

+

Your Events

{% if events %}
{% for event in events %} @@ -39,6 +39,44 @@ {% endfor %}
{% else %} -

No events found for your team.

+

No events found for you.

{% endif %} -{% endblock %} \ No newline at end of file + + {% if children_events %} +
+

Your Children's Events

+ {% for child_data in children_events %} +

{{ child_data.child.first_name }}'s Events

+ {% if child_data.events %} +
+ {% for item in child_data.events %} +
+
+
{{ item.event.title }}
+ {{ item.event.start_time|localize }} +
+

{{ item.event.description }}

+ Location: {{ item.event.location_address }} + View on Map +
+ Participation: {{ item.participation.get_status_display }} + Accept + Reject +
+
+ {% endfor %} +
+ {% else %} +

No events found for {{ child_data.child.first_name }}.

+ {% endif %} + {% endfor %} + {% endif %} +{% endblock %} diff --git a/dashboard/views.py b/dashboard/views.py index cb74037..b32cb94 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -1,30 +1,38 @@ from django.shortcuts import render from django.contrib.auth.decorators import login_required -from calendars.models import Event +from calendars.models import Event, EventParticipation from clubs.models import Team @login_required def dashboard(request): user = request.user events = [] - - # Get teams for players + children_events = [] + + # Get user's own events player_teams = [] if hasattr(user, 'team') and user.team: player_teams = [user.team] - - # Get teams for coaches coached_teams = user.coached_teams.all() assisted_teams = user.assisted_teams.all() - - # Combine all teams and remove duplicates from itertools import chain all_teams = list(set(chain(player_teams, coached_teams, assisted_teams))) - if all_teams: events = Event.objects.filter(team__in=all_teams).select_related('game', 'training').order_by('start_time') - + + # Get children's events + if hasattr(user, 'children'): + for child in user.children.all(): + child_events_list = [] + if child.team: + child_events = Event.objects.filter(team=child.team).select_related('game', 'training').order_by('start_time') + for event in child_events: + participation, created = EventParticipation.objects.get_or_create(user=child, event=event) + child_events_list.append({'event': event, 'participation': participation}) + children_events.append({'child': child, 'events': child_events_list}) + context = { 'events': events, + 'children_events': children_events, } - return render(request, 'dashboard/dashboard.html', context) \ No newline at end of file + return render(request, 'dashboard/dashboard.html', context) diff --git a/db.sqlite3 b/db.sqlite3 index dcd41b2ee22cf29fdb90ab1903c26c99d98b4cab..6630a754a924f3eb087ad616107c80a9bc1716a1 100644 GIT binary patch delta 305 zcmY++F-yZx6b0aS-+gIbguK&$TdU3D8tFd}ii3iS_yZIhM8OOaIu{*W6^A$|L=dMg zQqX{F|A0#uad2?R6dfF-i;s3thr{J?KTban`gw5Hpya&Sq2zx1wiO!FlX${AjxjK$ zDX@VtmT?6ihvw4shV5|EIHBQH%APN{S>r{YJ6_h_qWLVpX7{9sPK$_a+KrE~ zV2lJtsPH-r@&~Nf$q_B0oivS;?tZezS_t9V)cOBIX-G#b5FNz_@opM-rJl2lQ3`zG z8>QWQ!IG?6`mU~4 FegIJ;Nn8K` delta 99 zcmV-p0G$7Tpb>ze5s(`JXptO40cf#cq#qs)4wwQDyAS0Lf)A_?=?=ILO%K)&FAtm# z4G(P&n6oi3b`Av|4Ff|7moZcU6qlf#0|$e+E{C`-0f)FQ0=Kv>14*H?0iXjww*(Lb F{67l8A3Xp7 diff --git a/docs/traceback/trace5.log b/docs/traceback/trace5.log new file mode 100644 index 0000000..5838bcd --- /dev/null +++ b/docs/traceback/trace5.log @@ -0,0 +1,74 @@ +/home/mnagel/Projekte/baseball_organisator/calendars/views.py changed, reloading. +Watching for file changes with StatReloader +Performing system checks... + +Exception in thread django-main-thread: +Traceback (most recent call last): + File "/usr/lib64/python3.13/threading.py", line 1043, in _bootstrap_inner + self.run() + ~~~~~~~~^^ + File "/usr/lib64/python3.13/threading.py", line 994, in run + self._target(*self._args, **self._kwargs) + ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/autoreload.py", line 64, in wrapper + fn(*args, **kwargs) + ~~^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/management/commands/runserver.py", line 134, in inner_run + self.check(**check_kwargs) + ~~~~~~~~~~^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/management/base.py", line 492, in check + all_issues = checks.run_checks( + app_configs=app_configs, + ...<2 lines>... + databases=databases, + ) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/registry.py", line 89, in run_checks + new_errors = check(app_configs=app_configs, databases=databases) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/urls.py", line 16, in check_url_config + return check_resolver(resolver) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/checks/urls.py", line 26, in check_resolver + return check_method() + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 531, in check + for pattern in self.url_patterns: + ^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/functional.py", line 47, in __get__ + res = instance.__dict__[self.name] = self.func(instance) + ~~~~~~~~~^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 718, in url_patterns + patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) + ^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/utils/functional.py", line 47, in __get__ + res = instance.__dict__[self.name] = self.func(instance) + ~~~~~~~~~^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/resolvers.py", line 711, in urlconf_module + return import_module(self.urlconf_name) + File "/usr/lib64/python3.13/importlib/__init__.py", line 88, in import_module + return _bootstrap._gcd_import(name[level:], package, level) + ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 1387, in _gcd_import + File "", line 1360, in _find_and_load + File "", line 1331, in _find_and_load_unlocked + File "", line 935, in _load_unlocked + File "", line 1026, in exec_module + File "", line 488, in _call_with_frames_removed + File "/home/mnagel/Projekte/baseball_organisator/baseball_organisator/urls.py", line 25, in + path('calendars/', include('calendars.urls')), + ~~~~~~~^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/urls/conf.py", line 39, in include + urlconf_module = import_module(urlconf_module) + File "/usr/lib64/python3.13/importlib/__init__.py", line 88, in import_module + return _bootstrap._gcd_import(name[level:], package, level) + ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 1387, in _gcd_import + File "", line 1360, in _find_and_load + File "", line 1331, in _find_and_load_unlocked + File "", line 935, in _load_unlocked + File "", line 1026, in exec_module + File "", line 488, in _call_with_frames_removed + File "/home/mnagel/Projekte/baseball_organisator/calendars/urls.py", line 2, in + from . import views + File "/home/mnagel/Projekte/baseball_organisator/calendars/views.py", line 2, in + @login_required + ^^^^^^^^^^^^^^ +NameError: name 'login_required' is not defined +