diff --git a/baseball_organisator/__pycache__/settings.cpython-313.pyc b/baseball_organisator/__pycache__/settings.cpython-313.pyc index d8a7ea7..1008b13 100644 Binary files a/baseball_organisator/__pycache__/settings.cpython-313.pyc and b/baseball_organisator/__pycache__/settings.cpython-313.pyc differ diff --git a/baseball_organisator/__pycache__/urls.cpython-313.pyc b/baseball_organisator/__pycache__/urls.cpython-313.pyc index e1c7bf8..6603856 100644 Binary files a/baseball_organisator/__pycache__/urls.cpython-313.pyc and b/baseball_organisator/__pycache__/urls.cpython-313.pyc differ diff --git a/baseball_organisator/settings.py b/baseball_organisator/settings.py index 20139e2..e0c5073 100644 --- a/baseball_organisator/settings.py +++ b/baseball_organisator/settings.py @@ -126,3 +126,5 @@ STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' AUTH_USER_MODEL = 'accounts.CustomUser' + +LOGIN_REDIRECT_URL = '/' diff --git a/baseball_organisator/urls.py b/baseball_organisator/urls.py index 40f07c6..0119cc1 100644 --- a/baseball_organisator/urls.py +++ b/baseball_organisator/urls.py @@ -22,5 +22,5 @@ urlpatterns = [ path('accounts/', include('accounts.urls')), path('clubs/', include('clubs.urls')), path('calendars/', include('calendars.urls')), - path('dashboard/', include('dashboard.urls')), + path('', include('dashboard.urls')), ] diff --git a/calendars/__pycache__/admin.cpython-313.pyc b/calendars/__pycache__/admin.cpython-313.pyc index d34c1f4..5169540 100644 Binary files a/calendars/__pycache__/admin.cpython-313.pyc and b/calendars/__pycache__/admin.cpython-313.pyc differ diff --git a/calendars/__pycache__/forms.cpython-313.pyc b/calendars/__pycache__/forms.cpython-313.pyc new file mode 100644 index 0000000..50227b4 Binary files /dev/null and b/calendars/__pycache__/forms.cpython-313.pyc differ diff --git a/calendars/__pycache__/models.cpython-313.pyc b/calendars/__pycache__/models.cpython-313.pyc index 915d57d..895e3a3 100644 Binary files a/calendars/__pycache__/models.cpython-313.pyc and b/calendars/__pycache__/models.cpython-313.pyc differ diff --git a/calendars/__pycache__/urls.cpython-313.pyc b/calendars/__pycache__/urls.cpython-313.pyc index a972459..e553981 100644 Binary files a/calendars/__pycache__/urls.cpython-313.pyc and b/calendars/__pycache__/urls.cpython-313.pyc differ diff --git a/calendars/__pycache__/views.cpython-313.pyc b/calendars/__pycache__/views.cpython-313.pyc index 5efd986..9ced318 100644 Binary files a/calendars/__pycache__/views.cpython-313.pyc and b/calendars/__pycache__/views.cpython-313.pyc differ diff --git a/calendars/admin.py b/calendars/admin.py index 8c38f3f..b997dd9 100644 --- a/calendars/admin.py +++ b/calendars/admin.py @@ -1,3 +1,7 @@ from django.contrib import admin +from .models import Event, Training, Game, GameResult -# Register your models here. +admin.site.register(Event) +admin.site.register(Training) +admin.site.register(Game) +admin.site.register(GameResult) \ No newline at end of file diff --git a/calendars/forms.py b/calendars/forms.py new file mode 100644 index 0000000..b614b0f --- /dev/null +++ b/calendars/forms.py @@ -0,0 +1,7 @@ +from django import forms +from .models import Event + +class EventForm(forms.ModelForm): + class Meta: + model = Event + fields = ['title', 'description', 'start_time', 'end_time', 'location_address', 'team'] diff --git a/calendars/migrations/0001_initial.py b/calendars/migrations/0001_initial.py new file mode 100644 index 0000000..94bf2ec --- /dev/null +++ b/calendars/migrations/0001_initial.py @@ -0,0 +1,55 @@ +# Generated by Django 5.2.6 on 2025-10-01 06:21 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('clubs', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('description', models.TextField(blank=True)), + ('start_time', models.DateTimeField()), + ('end_time', models.DateTimeField(blank=True, null=True)), + ('location_address', models.CharField(max_length=255)), + ('maps_shortlink', models.URLField(blank=True, editable=False)), + ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='clubs.team')), + ], + ), + migrations.CreateModel( + name='Game', + fields=[ + ('event_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='calendars.event')), + ('opponent', models.CharField(max_length=255)), + ('meeting_minutes_before_game', models.PositiveIntegerField(default=60)), + ('season', models.CharField(blank=True, max_length=255)), + ('min_players', models.PositiveIntegerField(default=9)), + ], + bases=('calendars.event',), + ), + migrations.CreateModel( + name='Training', + fields=[ + ('event_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='calendars.event')), + ], + bases=('calendars.event',), + ), + migrations.CreateModel( + name='GameResult', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('inning_results', models.CharField(help_text="Comma-separated scores per inning, e.g., '1-0,0-2,3-1'", max_length=255)), + ('game', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='result', to='calendars.game')), + ], + ), + ] diff --git a/calendars/migrations/__pycache__/0001_initial.cpython-313.pyc b/calendars/migrations/__pycache__/0001_initial.cpython-313.pyc new file mode 100644 index 0000000..b518ebf Binary files /dev/null and b/calendars/migrations/__pycache__/0001_initial.cpython-313.pyc differ diff --git a/calendars/models.py b/calendars/models.py index 71a8362..29228dd 100644 --- a/calendars/models.py +++ b/calendars/models.py @@ -1,3 +1,37 @@ from django.db import models +from django.conf import settings +import urllib.parse -# Create your models here. +class Event(models.Model): + title = models.CharField(max_length=255) + description = models.TextField(blank=True) + start_time = models.DateTimeField() + end_time = models.DateTimeField(null=True, blank=True) + location_address = models.CharField(max_length=255) + maps_shortlink = models.URLField(blank=True, editable=False) + team = models.ForeignKey('clubs.Team', on_delete=models.CASCADE, related_name='events') + + def save(self, *args, **kwargs): + if self.location_address and not self.maps_shortlink: + self.maps_shortlink = f"https://www.google.com/maps/search/?api=1&query={urllib.parse.quote(self.location_address)}" + super().save(*args, **kwargs) + + def __str__(self): + return self.title + +class Training(Event): + pass + +class Game(Event): + opponent = models.CharField(max_length=255) + meeting_minutes_before_game = models.PositiveIntegerField(default=60) + season = models.CharField(max_length=255, blank=True) + min_players = models.PositiveIntegerField(default=9) + +class GameResult(models.Model): + game = models.OneToOneField(Game, on_delete=models.CASCADE, related_name='result') + # A simple way to store inning results as a string. A more complex solution could use a JSONField or separate Inning 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 diff --git a/calendars/templates/calendars/event_confirm_delete.html b/calendars/templates/calendars/event_confirm_delete.html new file mode 100644 index 0000000..5ffc6e5 --- /dev/null +++ b/calendars/templates/calendars/event_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +
Are you sure you want to delete "{{ object.title }}"?
+ +{% endblock %} diff --git a/calendars/templates/calendars/event_form.html b/calendars/templates/calendars/event_form.html new file mode 100644 index 0000000..adec35c --- /dev/null +++ b/calendars/templates/calendars/event_form.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +{{ event.description }}
+Location: {{ event.location_address }}
+ View on Map + {% if user == event.team.head_coach or user in event.team.assistant_coaches.all %} + Edit + Delete + {% endif %} +No events found for your team.
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/dashboard/urls.py b/dashboard/urls.py index bbbd7cc..ca81b57 100644 --- a/dashboard/urls.py +++ b/dashboard/urls.py @@ -2,5 +2,5 @@ from django.urls import path from . import views urlpatterns = [ - # Add your URLs here -] + path('', views.dashboard, name='dashboard'), +] \ No newline at end of file diff --git a/dashboard/views.py b/dashboard/views.py index 91ea44a..0a2015e 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -1,3 +1,30 @@ from django.shortcuts import render +from django.contrib.auth.decorators import login_required +from calendars.models import Event +from clubs.models import Team -# Create your views here. +@login_required +def dashboard(request): + user = request.user + events = [] + + # Get teams for players + 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).order_by('start_time') + + context = { + 'events': events, + } + return render(request, 'dashboard/dashboard.html', context) diff --git a/db.sqlite3 b/db.sqlite3 index 985bf46..57f3111 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/docs/phase4.md b/docs/phase4.md new file mode 100644 index 0000000..4871f47 --- /dev/null +++ b/docs/phase4.md @@ -0,0 +1,29 @@ +## Phase 4: Terminverwaltung und Google Maps API + +Hier wird die Kalenderfunktionalität implementiert, einschließlich der verschiedenen Termintypen und der Integration von Google Maps. + + Schritt 1: Terminkategorien und Basismodell erstellen + + Navigiere in das calendars-Verzeichnis und öffne models.py. + + Erstelle ein Event-Modell als Basis für alle Termine, mit Feldern wie title, description, start_time, end_time (optional), location_address und Maps_shortlink. + + Erstelle Training und Game als Submodelle von Event unter Verwendung von Multi-Table-Inheritance. + + Schritt 2: Besondere Logik für Game implementieren + + Füge dem Game-Modell die Felder opponent, meeting_minutes_before_game und die season hinzu. + + Implementiere Logik für die Mindestanzahl von Spielern (Default 9, kann von Coaches überschrieben werden). + + Erstelle ein Modell GameResult zur Speicherung der Ergebnisse pro Inning. + + Schritt 3: Google Maps Integration + + Implementiere eine Logik im calendars App, die eine gegebene Adresse in einen Google Maps Shortlink umwandelt. Dies erfordert die Nutzung einer API (oder eine einfache URL-Erstellung basierend auf den Adressdaten). + + Schritt 4: Dashboard-Views und Zugriffsrechte + + Entwickle die Views in der dashboard-App, die basierend auf der Rolle des eingeloggten Benutzers (Elternteil, Spieler, Coach) die entsprechenden Termine und "Widgets" anzeigen. + + Implementiere die Zugriffslogik, sodass ein Coach nur Termine für seine Gliederung (Mannschaft oder Team) anlegen, absagen oder bearbeiten kann.