From 51bf72788562a7515ca8409f85e6c0ec1328cb2d Mon Sep 17 00:00:00 2001 From: Matthias Nagel Date: Wed, 1 Oct 2025 09:24:59 +0200 Subject: [PATCH] feat: Implementierung von Phase 5 (Fortgeschrittene Funktionen und Backend) und Fehlerbehebungen --- accounts/__pycache__/admin.cpython-313.pyc | Bin 204 -> 928 bytes accounts/__pycache__/apps.cpython-313.pyc | Bin 528 -> 683 bytes accounts/__pycache__/forms.cpython-313.pyc | Bin 2827 -> 3505 bytes accounts/__pycache__/models.cpython-313.pyc | Bin 2703 -> 3171 bytes accounts/__pycache__/signals.cpython-313.pyc | Bin 0 -> 1124 bytes accounts/__pycache__/urls.cpython-313.pyc | Bin 876 -> 1010 bytes accounts/__pycache__/views.cpython-313.pyc | Bin 2980 -> 6092 bytes accounts/admin.py | 12 ++- accounts/apps.py | 4 +- accounts/forms.py | 9 +++ accounts/migrations/0003_absenceperiod.py | 24 ++++++ .../0003_absenceperiod.cpython-313.pyc | Bin 0 -> 1405 bytes accounts/models.py | 7 +- accounts/signals.py | 19 +++++ accounts/templates/accounts/logout.html | 10 +++ accounts/templates/accounts/player_form.html | 10 +++ accounts/templates/base.html | 9 ++- accounts/urls.py | 3 +- accounts/views.py | 47 +++++++++++- .../__pycache__/admin.cpython-313.pyc | Bin 0 -> 976 bytes .../__pycache__/urls.cpython-313.pyc | Bin 1336 -> 1397 bytes baseball_organisator/admin.py | 11 +++ baseball_organisator/urls.py | 1 + calendars/__pycache__/admin.cpython-313.pyc | Bin 609 -> 711 bytes calendars/__pycache__/models.cpython-313.pyc | Bin 3219 -> 4082 bytes calendars/admin.py | 5 +- .../migrations/0002_eventparticipation.py | 28 +++++++ .../0002_eventparticipation.cpython-313.pyc | Bin 0 -> 1765 bytes calendars/models.py | 10 ++- db.sqlite3 | Bin 241664 -> 266240 bytes docs/phase5.md | 29 ++++++++ docs/traceback/trace2.log | 70 ++++++++++++++++++ docs/traceback/trace3.log | 47 ++++++++++++ 33 files changed, 344 insertions(+), 11 deletions(-) create mode 100644 accounts/__pycache__/signals.cpython-313.pyc create mode 100644 accounts/migrations/0003_absenceperiod.py create mode 100644 accounts/migrations/__pycache__/0003_absenceperiod.cpython-313.pyc create mode 100644 accounts/signals.py create mode 100644 accounts/templates/accounts/logout.html create mode 100644 accounts/templates/accounts/player_form.html create mode 100644 baseball_organisator/__pycache__/admin.cpython-313.pyc create mode 100644 baseball_organisator/admin.py create mode 100644 calendars/migrations/0002_eventparticipation.py create mode 100644 calendars/migrations/__pycache__/0002_eventparticipation.cpython-313.pyc create mode 100644 docs/phase5.md create mode 100644 docs/traceback/trace2.log create mode 100644 docs/traceback/trace3.log diff --git a/accounts/__pycache__/admin.cpython-313.pyc b/accounts/__pycache__/admin.cpython-313.pyc index 3699747078f39ddae1bbefa5356dc728c5317442..2cf9cb3ce2d8dac223d470611a2862f6c0e8d34e 100644 GIT binary patch literal 928 zcmb7CJ8u&~5T3o4&sH28Ss;?iN_gms_);WYgcJ}GI1q)L=q#<)_Qttzk1)F~(gh(w znKGL;}TH5m8X33vzw{yMBlu(J<2OezQ08&CItuESF25?cUk<-H!y|r*Wp{ zPQdVs2FDOVL^hyFkkk#fHms(Nw#IhkY&cC9-KK|L9d5${MD9F9Udvv!#~fH_k?rb) z@7lIqyXH(_%WV}_t+7*w|H$)J^#sQ1&?^M~g@FN4F6*Xora|$g;J9v_3lkVvs`RKY zWS*LHRbFoko^|*Z$2jkHO!Cy62^c=n;22tfBm%S|f_BS6H`HRhAn3IU{~FQA6S>P| z#abatIv@SW!(z`43aav_{J1Tnc;G0Prz}pC-`9O*Eal3PoTbW-1r?I*>})D;C+104 z1O&@EJQXfxSOXuOf%NwNw|gi9)Bfy z*k*#aS(4Bkdn}6ulR1X0)5-gp6yfM<8v6%W)D)w|NFW+|c?W};TZfNTZSC;cpgMO} zT|BKW4vOU?|3h$6xpU&*y|k_S-Y>9jcyFKL+>~HbYcbp1V_7e6bn?vfislunxxWt^ ztS@&PqXx#qdLtRcNE0kf>69a4$(4`1r{&=|ns{7o-mv;>W33-xUAyL8iHCZ*v;YJRGGh2;Ub*Up}QgN0Fz--Z<6WdHyG delta 174 zcmZ3$eulCBGcPX}0}z-<-pQ~B(vLwL7+``jJ_`UDQyGF8f*HLTycmlZ6&TW)G?`z5 zq%|3Du_mVEX6E^6GTq`!$x6&i&(}-N&nqd)Oe$gqDp<+z8Kmx(jebUcZmNE6USfJ` yj($Kank4b@v5Ho5sJr8%i~MI1ntj6hrrVtim`WMsU@pismHTZlX-=wLkpxf|$j`+hK;i>4BO~Ko2E{Kdtc(g1 LBEK>KDX@J2_vuY& delta 185 zcmZ3@I)R1vGcPX}0}z-<-pQCUkvEr7W@5FpL=js$t0vnmKF8$b{L;LVV(0w4w9NFE zEEBiru&!kA(`28#g3*8SA4UmI4xrx8AOj|wG1@8>u>x6Of(6JZ<^>XM3^yb#F0hE* z;1+FmDH53M$)s!#(o`e>A_RfNEe@O9{FKt1RJ$T!AeRw{i$#FM2WCb_#=8uPU)Y!! N#U@04WdKrOT>$xFDtG_@ diff --git a/accounts/__pycache__/forms.cpython-313.pyc b/accounts/__pycache__/forms.cpython-313.pyc index 90fb9f64f6c4733d5e2872abad5743aac89d569a..28b52920950344cb32342abf25fe40dad7549565 100644 GIT binary patch delta 409 zcmeAc+bGTVnU|M~0SMlozLU|$Hjz()@x(;+`CJkVN({kVQVhY|6KmvIxzc$wc{iS# z&B3^GavG;E?w z_oW;)v+7;cD2 zUKdfhB%-n+^`eMLgD*ONvMz_L1Pc>uCgT?d5Lu)IGsI7mdvYR|1Ec%oxm>bbAwXe9 jkgH=gZHO|H=SjgS7(y|6yzB delta 87 zcmdle-7UuVnU|M~0SJT??qqysnaC%>IB%l*e3o=BP410fW^*uVPM*N&%UC@59_K1% nKTWR5A9x%loAOF>c>wh=0&%hZ$$?D56Z<(> zxzbrQxi`+S;S^5>>45<@DC6^liT5=bVb_7Jni{EWQ9NSggrZ#0L~F;s+6O zK*CRxck*ox$@(HSkO(`7a0C%fAOdUzS8+*VQAvDCVoB;Pj?}yqFsn!lBo8v6NESp$ zfe1Gk0n%4&4kX$bZg2};=a#v|Ei)r(gV}bwjdm9T5-)NmHMram6u&O0cu7$4vY>K< zm(&e@(d+#3m-yu`^D8!cKnw+$r^!9}7H2f0+hjv7SuTH|03*n3`^gbpx>8>l_!%X? VC^0iCO>mp;GtuWO1CR;U3IMZ m2q_?Oi^C>2KczG$)vm}B$YliLV*SZ7Ji1(88Tc6`!3qI!j}>wN diff --git a/accounts/__pycache__/signals.cpython-313.pyc b/accounts/__pycache__/signals.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f8e323e44ef1d4d38039402df6831226bb3d3ef GIT binary patch literal 1124 zcmZuw%}X0W6rat0WD~XZqgJstSS!M6Nh-Dlp$df-N<PdQ#_SkFxmmbW?Feq*5$)0TU5A@AyEQ$~I&HMPhk9lvl)zy_HNcnFk8;2=Eeo3WG z`lZlXM&Xdy#8&1>Q2}K{%BlHOQ3Vxc)z;>NHO}CAi zl${;0wg|Y5q8UQ(Tk-aD_iwYB$lavQJH_=_MCA~!8 zxWEu#8IX|<(+@EUmoAL0_Y^8TsUo_Q>fG@|r$HHU=h}T|EaY`zy`d_;GHkk()|{LL*l=Pm{qX z=R_Mcjr=lDOk8z7&tFfO1V`xo6V4R8k(_+^G< zbICS9Uh*q}hj_pP2{vD1Xgy$a@EBG3JMsx+=c=M8rzC$$#!ktj@8rc#C9`LJUT7#2 Re^Q-FwxyEPWFjTG{sA0!5Y7Mq literal 0 HcmV?d00001 diff --git a/accounts/__pycache__/urls.cpython-313.pyc b/accounts/__pycache__/urls.cpython-313.pyc index c024d90841d468ca5e629bfb5f42c1a982aa7ac2..be27102747e763e4457fe8a8b1d0afcf973610d5 100644 GIT binary patch delta 238 zcmaFE_K98nGcPX}0}$N4awo%-iGkrUhyw%MP{wDkiRvYc%oFEK;fi5YVh9$DVGfd* zI8SX7BPXv=FqM71{R?)% g7l5R2$c5;ni!8~L=P~Q@eBfr|XKLgwk^t%f0H@U?LjV8( diff --git a/accounts/__pycache__/views.cpython-313.pyc b/accounts/__pycache__/views.cpython-313.pyc index fc7da10732f9925fb09f7e078194b27dada6533d..ee2fd6a2a801a9c0ba9c157aca936c007f628df0 100644 GIT binary patch literal 6092 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 diff --git a/accounts/admin.py b/accounts/admin.py index 8c38f3f..9d87a67 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -1,3 +1,13 @@ from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import CustomUser, AbsencePeriod -# Register your models here. +class CustomUserAdmin(UserAdmin): + model = CustomUser + list_display = ['email', 'username', 'team', 'is_staff'] + fieldsets = UserAdmin.fieldsets + ( + (None, {'fields': ('team',)}), + ) + +admin.site.register(CustomUser, CustomUserAdmin) +admin.site.register(AbsencePeriod) \ No newline at end of file diff --git a/accounts/apps.py b/accounts/apps.py index 3e3c765..4f3f51c 100644 --- a/accounts/apps.py +++ b/accounts/apps.py @@ -1,6 +1,8 @@ from django.apps import AppConfig - class AccountsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'accounts' + + def ready(self): + import accounts.signals \ No newline at end of file diff --git a/accounts/forms.py b/accounts/forms.py index d7ab0e9..6fe6bb7 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -26,3 +26,12 @@ class CustomUserChangeForm(forms.ModelForm): class Meta: model = CustomUser fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'team') + +class PlayerCreationForm(forms.ModelForm): + parent1_email = forms.EmailField(required=False) + parent2_email = forms.EmailField(required=False) + birth_date = forms.DateField(input_formats=['%d.%m.%Y'], widget=forms.DateInput(format='%d.%m.%Y')) + + class Meta: + model = CustomUser + fields = ('username', 'first_name', 'last_name', 'email', 'birth_date', 'player_number', 'team') diff --git a/accounts/migrations/0003_absenceperiod.py b/accounts/migrations/0003_absenceperiod.py new file mode 100644 index 0000000..350dabe --- /dev/null +++ b/accounts/migrations/0003_absenceperiod.py @@ -0,0 +1,24 @@ +# Generated by Django 5.2.6 on 2025-10-01 07:05 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0002_customuser_team'), + ] + + operations = [ + migrations.CreateModel( + name='AbsencePeriod', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_date', models.DateField()), + ('end_date', models.DateField()), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absence_periods', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/accounts/migrations/__pycache__/0003_absenceperiod.cpython-313.pyc b/accounts/migrations/__pycache__/0003_absenceperiod.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be680c5302b1834db9b9cc9f987a0f05165ed997 GIT binary patch literal 1405 zcma)6&u`mQ9Dn{1$99q?={mZ0bPZLJNJZ;zEE1IvQfOL1yOt?#BMn7*a^ly_n`4*v zoJvI;kdQdA=MKIq@8xl6cAUwj^p{lffwa{KVN@;|F9>yoQ~l9 zIQ;E#PD1Eq$iyc#1Cu&{?~#d2;Sf;)sCXzINK`6?&!j{7AVpIL3ROzz7Ft85yo}6L zGgY699VN5^F~URB9igne3gK~C;3^|Q;CLNY7P;PaI@Agr-(y_q`ZjS{JJgF$ZU!bF z3Sm~wX+~5u1uB`MAy642XJh4rLSB+7H`Db(@+?LmOTkYu)26y3-xo~{^yXt}Lf24b z#(<9gKXfvnvyj-wXbm+p^;Fn{zv1 zcZz17&UXssBG-=MKEF~y89J|8?Y7_Z0>&4%x3}-%c8>*qx5o&@0kOI~S8XxkwaG(5 z9pC1nW1sAE@v~Z4=2@#3__$4p6%d63>p19LD2$D+-0rr?FUB;+pSaSOx;xSxVe6P~=Apd`MoN`c%#w;@a#7 z*s2>`#Zv{0xsEYxQqLuTvlxHbv)oV}xID&Z4rPJsc*OHVu}#h)8K~1CjLOg%p4pw& zbrkL*4POeL{lw{1q2m288rN!&Oa%3PpAx6z9YW!X{lxM*J{Rp4SErf7PV@9`)!ePt z_GtJf@O<_3njgGGNLd;8~}mMsJ;8(lof9 zUg27>=Wu<8#tPCl$C9|9eDh$eBkjgWy)#trTo+4!7H>Yg7%grL7dL*9e_ii?f%_gE zEV6zfxGt_-U5r+Z;i~as^=`j#@49&VsxeyG9IkA>STXvA?d#&=)mx*bjp5S9PmP}+ zJ%2Q+>PovdWjDIc(Xjt>|;I6%T{H3u-(wlec~EESie;#$vhv)0szY340$o-waLF xkD|5unBD~zzDJ0y!8MiyL6|5=c;|Oi`UAc9mr@XvXZonHJ}9jJjewc@_!nS6XI%gQ literal 0 HcmV?d00001 diff --git a/accounts/models.py b/accounts/models.py index 4d87b3a..fad17c1 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -30,4 +30,9 @@ class InvitationCode(models.Model): return True def __str__(self): - return self.code \ No newline at end of file + return self.code + +class AbsencePeriod(models.Model): + user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='absence_periods') + start_date = models.DateField() + end_date = models.DateField() \ No newline at end of file diff --git a/accounts/signals.py b/accounts/signals.py new file mode 100644 index 0000000..5e9dcc6 --- /dev/null +++ b/accounts/signals.py @@ -0,0 +1,19 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver +from .models import AbsencePeriod +from calendars.models import Event, EventParticipation + +@receiver(post_save, sender=AbsencePeriod) +def handle_absence_period(sender, instance, **kwargs): + user = instance.user + events_in_period = Event.objects.filter( + team=user.team, + start_time__date__gte=instance.start_date, + start_time__date__lte=instance.end_date + ) + for event in events_in_period: + EventParticipation.objects.update_or_create( + user=user, + event=event, + defaults={'status': 'rejected'} + ) diff --git a/accounts/templates/accounts/logout.html b/accounts/templates/accounts/logout.html new file mode 100644 index 0000000..099733f --- /dev/null +++ b/accounts/templates/accounts/logout.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Logout

+

Are you sure you want to log out?

+
+ {% csrf_token %} + +
+{% endblock %} diff --git a/accounts/templates/accounts/player_form.html b/accounts/templates/accounts/player_form.html new file mode 100644 index 0000000..51c8100 --- /dev/null +++ b/accounts/templates/accounts/player_form.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Create Player

+
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/accounts/templates/base.html b/accounts/templates/base.html index 1e9ad1c..8d355b4 100644 --- a/accounts/templates/base.html +++ b/accounts/templates/base.html @@ -4,7 +4,14 @@ Baseball Organisator + {% if user.is_authenticated %} +
+ {% csrf_token %} + +
+ {% endif %} + {% block content %} {% endblock %} - + \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index ab96f4f..2d0f7c6 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -5,7 +5,8 @@ from django.contrib.auth import views as auth_views urlpatterns = [ path('invitation/', views.invitation_code_view, name='invitation_code'), path('register/', views.register_view, name='register'), - path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'), + path('login/', views.MyLoginView.as_view(template_name='accounts/login.html'), name='login'), path('logout/', auth_views.LogoutView.as_view(), name='logout'), path('profile/', views.edit_profile, name='edit_profile'), + path('player/add/', views.PlayerCreateView.as_view(), name='player-add'), ] \ No newline at end of file diff --git a/accounts/views.py b/accounts/views.py index b15b898..d407eaf 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,7 +1,12 @@ from django.shortcuts import render, redirect -from .forms import InvitationCodeForm, CustomUserCreationForm, CustomUserChangeForm -from .models import InvitationCode +from django.urls import reverse_lazy +from django.views.generic.edit import CreateView from django.contrib.auth.decorators import login_required +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.auth import views as auth_views +from .forms import InvitationCodeForm, CustomUserCreationForm, CustomUserChangeForm, PlayerCreationForm +from .models import CustomUser, InvitationCode +import uuid def invitation_code_view(request): if request.method == 'POST': @@ -52,4 +57,40 @@ def edit_profile(request): return redirect('edit_profile') # Or wherever you want to redirect else: form = CustomUserChangeForm(instance=request.user) - return render(request, 'accounts/edit_profile.html', {'form': form}) \ No newline at end of file + return render(request, 'accounts/edit_profile.html', {'form': form}) + +class HeadCoachCheckMixin(UserPassesTestMixin): + def test_func(self): + return self.request.user.is_superuser or self.request.user.coached_teams.exists() + +class PlayerCreateView(LoginRequiredMixin, HeadCoachCheckMixin, CreateView): + model = CustomUser + form_class = PlayerCreationForm + template_name = 'accounts/player_form.html' + success_url = reverse_lazy('dashboard') + + def form_valid(self, form): + # Create player user + player = form.save(commit=False) + player.is_active = False # Player can only login after using invitation code + player.save() + + # Create invitation code for player + InvitationCode.objects.create(code=str(uuid.uuid4()), user=player) + + # Create parent users and invitation codes + for email_field in ['parent1_email', 'parent2_email']: + email = form.cleaned_data.get(email_field) + if email: + parent_user = CustomUser.objects.filter(email=email).first() + if not parent_user: + parent_user = CustomUser.objects.create(email=email, username=email, is_active=False) + InvitationCode.objects.create(code=str(uuid.uuid4()), user=parent_user) + + return redirect(self.success_url) + +class MyLoginView(auth_views.LoginView): + def get(self, request, *args, **kwargs): + if request.user.is_authenticated: + return redirect('dashboard') + return super().get(request, *args, **kwargs) \ No newline at end of file diff --git a/baseball_organisator/__pycache__/admin.cpython-313.pyc b/baseball_organisator/__pycache__/admin.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ec8702f492ce44164a566d730b4ca31df67eef6 GIT binary patch literal 976 zcmZ`%&ubGw6rRbiO|mw|2#S(I6hWhkg(``?w1s7oOg39L**dc;3W27l z;z>Oe4_@>n-t=U9>ObJYAhKboCr{pr`3HQv-NabZVKVc6eD8fP-_CGmCW&Aze?4fu z#R&cKoY9H|#;^y*4yvLmzK`xx|;NElorb=!DKMI20SlV($#@+@bAG9Mzf2q(79SQJ=9j6Q=_JRcGf zPR*u}7=7YUh7 z?7`Xd2Xf|B`HlKo{dTG3$_ssYVYj@m?y0V_(pOeoh4dBTD)qin2k<~n51~C;%Ev^i zu}(U=HD9+nHZy9>Blo8elBVg@)-=$-u&GGg_8x8(%#VnrJyZ$~5m(z*!!hYCb`D&4 z9Ejh9<1mad{)uvbA~AgCFpXw!xY=SqTl`e|viNy%*V*6P+x(t=(2H&-w~{~51;688 D?0~)F literal 0 HcmV?d00001 diff --git a/baseball_organisator/__pycache__/urls.cpython-313.pyc b/baseball_organisator/__pycache__/urls.cpython-313.pyc index 6603856538dd325ae4ab095b22b6b359b622909f..8149b5345a83fc03404e8906c279b89cdebc07e3 100644 GIT binary patch delta 246 zcmdnN^_7eFGcPX}0}#ZWxs&mFBCjOljfv{2YQc=bEZ%HI>@h4#48g21OhE!5HK-s+ zXkwN;J6jAZPzn3Q38L&AU?wMs$pvO|1DUcsU?#6ABSg0;6NJ`hE#gXN+4yTC6Qkec z)yyeOn%t9xSj-Hik`jwklM-`s;`58r6Z0~Q6HD@o^b%8YGxKhVV3V8d&QhWz1T++6 mL2(|C_`uA_$oP?opONLO0t2JseFoLr42qL)u|%tU2~W&W6vZwv z50}Ih91@ec80B*b802p-u(oqG Wa$RQ-zQ`baK}78;gL)A^P&EK5Pb{AR delta 225 zcmX@k`jCb1GcPX}0}%9`xRY^;VIrRdBf~^>btwgg7{(wzkOV3S5}cT$=#5nZRUwEM z!(z$^5yfNN4MkC`#!cp9l$)HyD8a}wxtdX#*-w*m@>WK}$*&m`r3HY7f($MW0}>yY c85tSxGAP_w#M+NovZ)AK*9N6x4!sl#jfhxHvsMMGZA>3&1XG>e6udM& zdGQn$q2j@lP(cv?gL?8J(&Uoz@E_<+O~j+lGz}^`hu_Tn=KH;!YoQRZ5WH)E<%4mq)RyFc}j66N+qJ2X1GK_fbmEX4YO-+ECg zB!ZpjU}Q>$C^~vD85z_T^*?z7oh0%@_0T!yD)W-7y4q9-tb--OxI`o?_gX^CjY7Pv zJBAp@t@Em%FM?kwRUQ`o%35`Q9J3q=5~%hE$qqTPh!%aHS63?4vWU*~P2?lM@AHz+ zS45=Hv+65Is}G8g?{T5dk%F5CU4WiQgiEVyl@j-08oj?BLPCP1lSFvN78yt`1KE`z zm0c*l$ysusGLrNDI~8t8k|B6bQ+u{a1cbiR;@g$ z@g;w)%>7jkaDhTp0mli_2tuLWa2rkP?}ZVbu)WcVr}19WG7^VV5;P?kGluFgNvwh( z;xh}^FD)&&xx&)iwb|SiI8UKF1oZWAm*5P7&^*8B*F0Dz=0B@Io&p4Phes>nCdQGr zk!l&Kty^t7+qAPg!ynT5_vxmQ-<;hu2im6HGVLwCz5aIN^+wa2-puV;N86U&vh3}F zR<{0yvCHzj{FSj-LEgOhLy^=>mm&1dqj8QIG>v&FAEZrNFC#%;<=qH!=Im&fX_C`T RXi{ct_+{#O>O1pnmikS{pVuR^r ZsEiSai`^zq;dkNs%D~2`S)>3I008?55?%lR diff --git a/calendars/admin.py b/calendars/admin.py index b997dd9..8764abb 100644 --- a/calendars/admin.py +++ b/calendars/admin.py @@ -1,7 +1,8 @@ from django.contrib import admin -from .models import Event, Training, Game, GameResult +from .models import Event, Training, Game, GameResult, EventParticipation admin.site.register(Event) admin.site.register(Training) admin.site.register(Game) -admin.site.register(GameResult) \ No newline at end of file +admin.site.register(GameResult) +admin.site.register(EventParticipation) diff --git a/calendars/migrations/0002_eventparticipation.py b/calendars/migrations/0002_eventparticipation.py new file mode 100644 index 0000000..01a53e3 --- /dev/null +++ b/calendars/migrations/0002_eventparticipation.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.6 on 2025-10-01 07:05 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('calendars', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='EventParticipation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(choices=[('attending', 'Attending'), ('rejected', 'Rejected'), ('maybe', 'Maybe')], default='maybe', max_length=20)), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='calendars.event')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'event')}, + }, + ), + ] diff --git a/calendars/migrations/__pycache__/0002_eventparticipation.cpython-313.pyc b/calendars/migrations/__pycache__/0002_eventparticipation.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13be1efc48243bd28a67ab9220440be9787075ab GIT binary patch literal 1765 zcmcgs%}*Og6rbI-*K1?IHUe(< zT5_l=Rq8pHO8g0}dPz>{pHSswyN5-iR;|<%H>b4szTL%u6rVd@@4WZ+&HMb#I~^Ph zAy_|keyiT}A@rBS^p^jOIL!m`JyMY>Y#=7UE^dhH5|gGJnY7_s_cQ;x%;YIFj;4|7 zn?$O=;Li{B3|;JL$)j1IA|&M#huKOBTrsI-X?n#>iab=;DvVf~p_^Q;8)aHEOBV(Z z3ZF5juLUQnf*TPNRe?#WSn%cDd@dhA5K}?!8x2@+R!U?FoQ!$gt0(e7uirs*h~? zZJ9c(MwUhJ8U6o!_OG@VN6M$h)R84&QBdQ{Qc7Skb(D=%#*zsh-0XG!M1e#A3&9ep zQN2u<$-|3_i%VG3HA^Ek9?Kn2-P$3{(n?yxMGF_T^1U@K-dRohc$hRT1D6;j7A^CE z2Gi<<9pWeSkOxi5z=ZaU^6&v=MZ=_6Cw0nY(;`;WOiGSpVp-rAAjyN-9tm=V(S2HS zY%2LP3Z(uzIV@7{-*h&XfY?u*jwK}?C{+!uL`@zj(>>CxSpaYH6^5iLR+amylf|>) z^DGx!f#cuMF(98>l#7xt~X_I2hs8Fj)SyE(E;D){D`SN*L>}j-C28Tw& zy+c331&eb9yE$UaLm0!QYSt*wVT_+PNzFM2+%U#_8Z)h$rc>R(n87?iJZ^qT8Vyo} z17+HPnozxT$ee4;hqL$ZeTwg^xjf$7Ud`R*;d2cQQXW`w%fIPdVdl&d9{xnDWT7!@ zPKZ3XQYFkILu&@3T1DT0{>bHhqE`$qmWy0*YXGBw2UfD`N_I8JLq>!4#=|JaPS3Ow zhITQn*tDn#abE>rr|?JoQL1XxX{xT13azDfn6XcvSTt26CM}X$4I8XNbj>7|!BXc< zNL>t|6oBqS>^7xw8EXrTLlyuB?#scd`8T}2LtPmKuN^BfTe;p*uK%Fev$xx`w|`Z# zUB48Uzq#8Dqu_|GTWcM-ZH?uf8`E@JTwLhpXzFi|2NN5_w@*^~2~$@v$1ue6t%omp#V*6hr7JF{(P z9<(zLT7`OhQg20!<7nb&%$}I*Ow7I5ef99=Lpz;or*n3CtDWAm)4T2TZtHQ$er&ek znXp=sW;f`M4|Ru7bh8^ z*FClbYJA}Ad&$uEJOBmHPqq>$koXSXe c|93R?2b%pyjtlbhkR6$6M`r#-z_>R41M6bJ82|tP literal 0 HcmV?d00001 diff --git a/calendars/models.py b/calendars/models.py index 29228dd..5ec7b39 100644 --- a/calendars/models.py +++ b/calendars/models.py @@ -34,4 +34,12 @@ class GameResult(models.Model): inning_results = models.CharField(max_length=255, help_text="Comma-separated scores per inning, e.g., '1-0,0-2,3-1'") def __str__(self): - return f"Result for {self.game}" \ No newline at end of file + return f"Result for {self.game}" + +class EventParticipation(models.Model): + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + event = models.ForeignKey(Event, on_delete=models.CASCADE) + status = models.CharField(max_length=20, choices=[('attending', 'Attending'), ('rejected', 'Rejected'), ('maybe', 'Maybe')], default='maybe') + + class Meta: + unique_together = ('user', 'event') \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index 57f311177bc52363e015ce491b1adb11999e148d..f70bebe6dff536b9b6a24549ecb9ee0d16197f6c 100644 GIT binary patch delta 3901 zcmb7HeQXow8Nc^F?AXEgI0fn?)QWLg34@F8!}i@dE{SK-((yR~VhwBE^W8Zy1SiB! z0CkmPs{PfWrOF>hqn);{`=i>X%`*#?_=~REv`tgDF_`wnP(P#r9k8t}8U=Ol*|8PF z@i8lY<=pfBo{yiO-}AnnxxmhR+dI3WV>dw%3H)xno_u+ogmzb+dmX4w*Nr)+m!sYN zt{auoTdv|jCqwk~CvO=rSoP^Hz&-=?6_eIjfN#&2tUkJ4|gABy5A(> z6np?j;0NqQ_D$FV=O6^HfQLO>DIH^(6%MK&m2*3g4>5CR`_@nlWadzaL-brI6lG{A z6OX){=v=;(qShj9sxX?uk@siwd7OBBt{jS?&bi-*)~*18aAQt@JwdQ%p#&yefnUR) zp_@HXUBE*!&N&CO-u9ojf4_aU{b2iW zd#t_NeX~;fs=Mf?Q9pv|ta;Fe;dl>?1`rtLm{~Aw?EQ7SKC0zL?Ch~eXrv<048sPj zcG5`D5nGGhlDE=LqX=Rb!nT;?x@jR|iz(`(Q3$bCu$JeM>iJEN(LrFV1pE{J1iykG z!ZDZu19rg^z(E%{*sJUx*lMM8l#TZQP4o!&;Jb^Z3IA$azN=TCU5=K}o>>CcvBRG0 zp4m!i##1zDAUs5y-|tJdwIx;}v|q~^lctv6q7@3GSuMX+8!^W++WzcV)=cHBe+Kg- zoR0h5ob1b)h1PBr#TYO5$)e25yvPetj#oG_9HKO;7N)DK5vDMn#(z6Eji>+b7=jWD zD_BgCsH))TSYuWUm7E*S9a!F!oFK;}xi2DzaW2&hxmCD!I77f0xC|HI<7&sm&!BS& zx3>|pt?rN~W^`5nb$1uEz@pn~=g|8d!@Un{W zYVs~(vaq=G?SLT#1BL#Y&Wf$lXqLMmm_U6xN-{=725bemsL0zu(K^UZn$5}v%s?xO zi(phpy;HS~f?Bs%AN$97nPu2h1RlrVfQ>-1rz)j4*y0f5Aa*5ONS3g6(_w?lXokjx zqeh0)^mK$1Gm;)v!n_gH1zS1c*&hy58|a!F7ax|>rXm@fp!3*G+Tb}gBSbifR}|e8 z1yz?Ki`^9E*n%u2m5<0nR6QFlt@4JJQ8i+jC|Ws)bJuH zVU->t>u$shuPQ=V=As!x<-(?7a+<12TtrgRx+EwW(=XgsRb9XmA5|heRX!I&eJlgp z2{?=om+kNoyjCf#hhi_a>wy?!tc?%C32kkBkg6$b`fRKN>*Z8JzwH1l+`< z1Aljg=lL6(3G`OBt^Mg)}hM4djxz6AH!9+2=8IY?`ja5bTQ?N ze@82@Pn!)uF^D;N@hZB(284{7$!OBZVfo-_Gz)#=+$m}ilrAp~ATby9r1gu0Q7eWakIj-rW6WM}3O73|+SXY}7 zj0K(#X0qm(k;fnR1UH(R5zwuj!F7RP0^d6F1ua*oKQi;dXI^;W85h||q<(=C#8^b^ zQx#r{L>1aaz*5&*98gN0bOU+LdtWZ*1LRfcxTB_doTg4qv$}_RbODY7c zWxu}UO8e$^aBp%u+TL$F-nPW?u0y6zP^ZaHNu^Tql24ZgpK$s{hEPe%<_z;t^BQ7v zeM(K`&B;{ONJ)yS=uuU?*XBfd(=p0lY&p;Fa1ab^+ZqVo%S|xQ8(at*TvJL8Iel52 zt9k!iYsYD-7iX)5bv0~=nR|s9w9B^cVv&ajOSb{T`A%$T^OdL}bmYW4sa*EJy|N!DuQbVr%frVgtlY)FSDJ*|`+Tr^8uVjXH{1l*yhtRSzM&!X zHL9Sc$INDSyiMOUjW)LR<>EJ~&WCD_TT(9%4x`8_JVOdo`CwpLo5XWxvRCBS1h#J5 z8Q8jO^X5iA+ObR`_bxo=F3r^o26_uWdx86pY{G=sS z;Q6RvzwPmI&zF&}xNtG3-&pQ|*2%PY(9*?6RwtZ3RYfmmYt-2zY@X8iS7f|=dIR!# zS~96I^?A(HWFci}1v411))ty_#v)7km&3?k=5yq>lb&PLe|)ba?`uEy)>i(1XCkmB delta 893 zcmah{T}V@582*0d&d%Jv=SZ1lPzyo`n>*W%`3E(P#3;p(u!Me=S{}q@POWv*>beW% zTudmUi=dmjs8icTH{JFJ6=)P;(hsDfv(O}J)VCrK3i{xKm-l_%=Y8IvB}Ud4 zMF=5v^8b1Dqg%r?a_i_d@HOsXOVRxHCSQZw9xfdzC>>|GhYz@b8)6#A(ToWMa2Z}P zZWs0671nsg7VbdGq5(hURv@s=$x5BPPEEzyXi4!Z&dX_ZXt3uJ28IPMMV}_Lq z)Y3K9^FVotmk_s<;S~!6=h2OMJi;rK+H3X8!fMqb_QLknlpBSUmJ%_gs#u{txu?vr z!7H)^b9jk|xQQ_&(S`kJgdgkR6j`b4iLkSWi>Zr=4uY+sL*}*!t0Q)*Sg-MibziW$ zHfYpVhAZ@7Wlbn(PsKJ%FlGs6v1At|-@u+dw@%}Rcw#9d`O=3(Y609~Kf4mH=Z34y zQl?D1UP~)>*~iH$C&dK8gv@-5)I@+*NXH_kNRJTJ!!B3Jzu zFXRLsV2jF~WR_YCmD_WF7S!qJ3iry1ib?sT&28#Q_2|Us+xYvavMQamcKm?d3)dSC8OP^ z;}~uIy$}yyfxp9Z_ycEH&cl}_@hmdS8@acCt=r`xC>Iw!^M!j0;ojqRy574kxjgbb M7L<%... + 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 23, in + path('accounts/', include('accounts.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/accounts/urls.py", line 2, in + from . import views + File "/home/mnagel/Projekte/baseball_organisator/accounts/views.py", line 2, in + class MyLoginView(auth_views.LoginView): + ^^^^^^^^^^ +NameError: name 'auth_views' is not defined + diff --git a/docs/traceback/trace3.log b/docs/traceback/trace3.log new file mode 100644 index 0000000..25b9c6a --- /dev/null +++ b/docs/traceback/trace3.log @@ -0,0 +1,47 @@ +[01/Oct/2025 07:16:54] "GET / HTTP/1.1" 302 0 +[01/Oct/2025 07:17:22] "GET / HTTP/1.1" 200 540 +[01/Oct/2025 07:17:27] "POST /accounts/logout/ HTTP/1.1" 200 3420 +[01/Oct/2025 07:17:31] "GET / HTTP/1.1" 302 0 +[01/Oct/2025 07:17:31] "GET /accounts/login/?next=/ HTTP/1.1" 200 727 +[01/Oct/2025 07:17:37] "POST /accounts/login/?next=/ HTTP/1.1" 302 0 +[01/Oct/2025 07:17:37] "GET / HTTP/1.1" 200 540 +[01/Oct/2025 07:17:49] "GET /accounts/player/add/ HTTP/1.1" 200 2330 +Internal Server Error: /accounts/player/add/ +Traceback (most recent call last): + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/handlers/exception.py", line 55, in inner + response = get_response(request) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/core/handlers/base.py", line 197, in _get_response + response = wrapped_callback(request, *callback_args, **callback_kwargs) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch + return super().dispatch(request, *args, **kwargs) + ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/contrib/auth/mixins.py", line 135, in dispatch + return super().dispatch(request, *args, **kwargs) + ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/views/generic/base.py", line 144, in dispatch + return handler(request, *args, **kwargs) + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/views/generic/edit.py", line 182, in post + return super().post(request, *args, **kwargs) + ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/views/generic/edit.py", line 151, in post + return self.form_valid(form) + ~~~~~~~~~~~~~~~^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/accounts/views.py", line 85, in form_valid + parent_user, created = CustomUser.objects.get_or_create(email=email, defaults={'username': email, 'is_active': False}) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/db/models/manager.py", line 87, in manager_method + return getattr(self.get_queryset(), name)(*args, **kwargs) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/db/models/query.py", line 946, in get_or_create + return self.get(**kwargs), False + ~~~~~~~~^^^^^^^^^^ + File "/home/mnagel/Projekte/baseball_organisator/venv/lib64/python3.13/site-packages/django/db/models/query.py", line 636, in get + raise self.model.MultipleObjectsReturned( + ...<5 lines>... + ) +accounts.models.CustomUser.MultipleObjectsReturned: get() returned more than one CustomUser -- it returned 2! +[01/Oct/2025 07:18:48] "POST /accounts/player/add/ HTTP/1.1" 500 112859 +