feat: Implementierung der Eltern-Funktionalität zur Event-Teilnahmeverwaltung und Autocomplete-Verbesserungen
This commit is contained in:
parent
4203a696d9
commit
066a749363
Binary file not shown.
@ -4,10 +4,15 @@ from .models import CustomUser, AbsencePeriod
|
|||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
list_display = ['email', 'username', 'team', 'is_staff']
|
list_display = ['email', 'username', 'team', 'display_parents', 'is_staff']
|
||||||
fieldsets = UserAdmin.fieldsets + (
|
fieldsets = UserAdmin.fieldsets + (
|
||||||
(None, {'fields': ('team',)}),
|
(None, {'fields': ('team', 'parents')}),
|
||||||
)
|
)
|
||||||
|
filter_horizontal = ('parents',)
|
||||||
|
|
||||||
|
def display_parents(self, obj):
|
||||||
|
return ", ".join([parent.username for parent in obj.parents.all()])
|
||||||
|
display_parents.short_description = 'Parents'
|
||||||
|
|
||||||
admin.site.register(CustomUser, CustomUserAdmin)
|
admin.site.register(CustomUser, CustomUserAdmin)
|
||||||
admin.site.register(AbsencePeriod)
|
admin.site.register(AbsencePeriod)
|
||||||
Binary file not shown.
Binary file not shown.
@ -8,4 +8,5 @@ urlpatterns = [
|
|||||||
path('game/add/', views.GameCreateView.as_view(), name='game-add'),
|
path('game/add/', views.GameCreateView.as_view(), name='game-add'),
|
||||||
path('event/<int:pk>/', views.EventUpdateView.as_view(), name='event-update'),
|
path('event/<int:pk>/', views.EventUpdateView.as_view(), name='event-update'),
|
||||||
path('event/<int:pk>/delete/', views.EventDeleteView.as_view(), name='event-delete'),
|
path('event/<int:pk>/delete/', views.EventDeleteView.as_view(), name='event-delete'),
|
||||||
|
path('participation/<int:child_id>/<int:event_id>/<str:status>/', views.manage_participation, name='manage-participation'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.urls import reverse_lazy
|
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 .forms import EventForm, TrainingForm, GameForm
|
||||||
|
from accounts.models import CustomUser # Import CustomUser for manage_participation view
|
||||||
|
|
||||||
def select_event_type(request):
|
def select_event_type(request):
|
||||||
return render(request, 'calendars/select_event_type.html')
|
return render(request, 'calendars/select_event_type.html')
|
||||||
@ -74,3 +76,19 @@ class EventDeleteView(LoginRequiredMixin, CoachCheckMixin, DeleteView):
|
|||||||
model = Event
|
model = Event
|
||||||
template_name = 'calendars/event_confirm_delete.html'
|
template_name = 'calendars/event_confirm_delete.html'
|
||||||
success_url = reverse_lazy('dashboard')
|
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')
|
||||||
Binary file not shown.
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Your Team's Events</h3>
|
<h3>Your Events</h3>
|
||||||
{% if events %}
|
{% if events %}
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for event in events %}
|
{% for event in events %}
|
||||||
@ -39,6 +39,44 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No events found for your team.</p>
|
<p>No events found for you.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if children_events %}
|
||||||
|
<hr>
|
||||||
|
<h3>Your Children's Events</h3>
|
||||||
|
{% for child_data in children_events %}
|
||||||
|
<h4>{{ child_data.child.first_name }}'s Events</h4>
|
||||||
|
{% if child_data.events %}
|
||||||
|
<div class="list-group">
|
||||||
|
{% for item in child_data.events %}
|
||||||
|
<div class="list-group-item list-group-item-action flex-column align-items-start
|
||||||
|
{% if item.event.game %}
|
||||||
|
event-game
|
||||||
|
{% elif item.event.training %}
|
||||||
|
event-training
|
||||||
|
{% else %}
|
||||||
|
event-generic
|
||||||
|
{% endif %}
|
||||||
|
">
|
||||||
|
<div class="d-flex w-100 justify-content-between">
|
||||||
|
<h5 class="mb-1">{{ item.event.title }}</h5>
|
||||||
|
<small>{{ item.event.start_time|localize }}</small>
|
||||||
|
</div>
|
||||||
|
<p class="mb-1">{{ item.event.description }}</p>
|
||||||
|
<small>Location: {{ item.event.location_address }}</small>
|
||||||
|
<a href="{{ item.event.maps_shortlink }}" target="_blank" class="btn btn-secondary btn-sm">View on Map</a>
|
||||||
|
<div>
|
||||||
|
Participation: <strong>{{ item.participation.get_status_display }}</strong>
|
||||||
|
<a href="{% url 'manage-participation' child_data.child.id item.event.id 'attending' %}" class="btn btn-success btn-sm">Accept</a>
|
||||||
|
<a href="{% url 'manage-participation' child_data.child.id item.event.id 'rejected' %}" class="btn btn-danger btn-sm">Reject</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>No events found for {{ child_data.child.first_name }}.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,30 +1,38 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from calendars.models import Event
|
from calendars.models import Event, EventParticipation
|
||||||
from clubs.models import Team
|
from clubs.models import Team
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
user = request.user
|
user = request.user
|
||||||
events = []
|
events = []
|
||||||
|
children_events = []
|
||||||
|
|
||||||
# Get teams for players
|
# Get user's own events
|
||||||
player_teams = []
|
player_teams = []
|
||||||
if hasattr(user, 'team') and user.team:
|
if hasattr(user, 'team') and user.team:
|
||||||
player_teams = [user.team]
|
player_teams = [user.team]
|
||||||
|
|
||||||
# Get teams for coaches
|
|
||||||
coached_teams = user.coached_teams.all()
|
coached_teams = user.coached_teams.all()
|
||||||
assisted_teams = user.assisted_teams.all()
|
assisted_teams = user.assisted_teams.all()
|
||||||
|
|
||||||
# Combine all teams and remove duplicates
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
all_teams = list(set(chain(player_teams, coached_teams, assisted_teams)))
|
all_teams = list(set(chain(player_teams, coached_teams, assisted_teams)))
|
||||||
|
|
||||||
if all_teams:
|
if all_teams:
|
||||||
events = Event.objects.filter(team__in=all_teams).select_related('game', 'training').order_by('start_time')
|
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 = {
|
context = {
|
||||||
'events': events,
|
'events': events,
|
||||||
|
'children_events': children_events,
|
||||||
}
|
}
|
||||||
return render(request, 'dashboard/dashboard.html', context)
|
return render(request, 'dashboard/dashboard.html', context)
|
||||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
74
docs/traceback/trace5.log
Normal file
74
docs/traceback/trace5.log
Normal file
@ -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 "<frozen importlib._bootstrap>", line 1387, in _gcd_import
|
||||||
|
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
|
||||||
|
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/baseball_organisator/urls.py", line 25, in <module>
|
||||||
|
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 "<frozen importlib._bootstrap>", line 1387, in _gcd_import
|
||||||
|
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
|
||||||
|
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/calendars/urls.py", line 2, in <module>
|
||||||
|
from . import views
|
||||||
|
File "/home/mnagel/Projekte/baseball_organisator/calendars/views.py", line 2, in <module>
|
||||||
|
@login_required
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
NameError: name 'login_required' is not defined
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user