consolidated objects into one benchcoach app

created benchcoachproject app to contain all the settings and stuff
some other changes that got grouped with this commit is the adding the ApiObject to the TeamSnap object model
This commit is contained in:
2021-12-21 17:14:52 -06:00
parent e9f91126e5
commit 95697ef4fe
174 changed files with 5351 additions and 16551 deletions

View File

@@ -1,6 +1,11 @@
from django.contrib import admin
from .models import Profile, TeamsnapSettings
from .models import Event, Availability, Positioning, Team, Venue, Player, StatLine
# Register your models here.
admin.site.register(Profile)
admin.site.register(TeamsnapSettings)
admin.site.register(Event)
admin.site.register(Availability)
admin.site.register(Positioning)
admin.site.register(Team)
admin.site.register(Venue)
admin.site.register(Player)
admin.site.register(StatLine)

View File

@@ -1,6 +1,6 @@
from django.apps import AppConfig
class TeamsConfig(AppConfig):
class BenchcoachConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'teams'
name = 'benchcoach'

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
from django import forms
from .models import Positioning
from events.models import Event
from players.models import Player
from django.forms import modelformset_factory, inlineformset_factory, BaseModelFormSet,formset_factory
from crispy_forms.helper import FormHelper, Layout
from .models import Event, Positioning, Team, Venue, Player
from teamsnap.models import Event as TeamsnapEvent
from django.forms import modelformset_factory
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['start', 'home_team', 'away_team', 'venue']
class PositioningForm(forms.ModelForm):
availability = None
class Meta:
@@ -41,4 +42,19 @@ class TeamsnapEventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['start', 'home_team', 'away_team', 'venue']
fields = ['start', 'home_team', 'away_team', 'venue']
class PlayerForm(forms.ModelForm):
class Meta:
model = Player
fields = ['first_name', 'last_name', 'jersey_number', 'team']
class TeamForm(forms.ModelForm):
class Meta:
model = Team
fields = ['name']
class VenueForm(forms.ModelForm):
class Meta:
model = Venue
fields = ['name']

View File

@@ -1,6 +1,8 @@
# Generated by Django 3.2.6 on 2021-12-12 23:36
# Generated by Django 3.2.6 on 2021-12-17 21:33
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
@@ -12,13 +14,89 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='User',
name='Player',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_name', models.CharField(max_length=50, null=True)),
('last_name', models.CharField(max_length=50, null=True)),
('email', models.EmailField(max_length=254)),
('teamsnap_access_token', models.CharField(max_length=50, null=True)),
('first_name', models.CharField(max_length=200)),
('last_name', models.CharField(max_length=200)),
('jersey_number', models.IntegerField()),
],
),
migrations.CreateModel(
name='Season',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name='Team',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('image', models.FileField(null=True, upload_to='images/', validators=[django.core.validators.FileExtensionValidator(['jpg', 'png', 'svg'])])),
],
),
migrations.CreateModel(
name='Venue',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name='StatLine',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('batting_avg', models.DecimalField(decimal_places=3, default=0, max_digits=4)),
('onbase_pct', models.DecimalField(decimal_places=3, default=0, max_digits=4)),
('slugging_pct', models.DecimalField(decimal_places=3, default=0, max_digits=4)),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.player')),
],
),
migrations.AddField(
model_name='player',
name='team',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='benchcoach.team'),
),
migrations.CreateModel(
name='Event',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start', models.DateTimeField(null=True)),
('away_team', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='away_team', to='benchcoach.team')),
('home_team', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='home_team', to='benchcoach.team')),
('venue', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='benchcoach.venue')),
],
),
migrations.CreateModel(
name='Positioning',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('position', models.CharField(blank=True, choices=[('EH', 'EH'), ('P', 'P'), ('C', 'C'), ('1B', '1B'), ('2B', '2B'), ('3B', '3B'), ('SS', 'SS'), ('LF', 'LF'), ('CF', 'CF'), ('RF', 'RF'), ('DH', 'DH')], default=None, max_length=2, null=True)),
('order', models.PositiveSmallIntegerField(blank=True, default=None, null=True)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.player')),
],
options={
'unique_together': {('player', 'event')},
},
),
migrations.AlterUniqueTogether(
name='player',
unique_together={('first_name', 'last_name')},
),
migrations.CreateModel(
name='Availability',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('available', models.IntegerField(choices=[(2, 'Yes'), (0, 'No'), (1, 'Maybe'), (-1, 'Unknown')], default=-1)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.player')),
],
options={
'verbose_name_plural': 'availabilities',
'unique_together': {('event', 'player')},
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-12-19 01:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('benchcoach', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='player',
name='jersey_number',
field=models.IntegerField(null=True),
),
]

View File

@@ -1,20 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-12 23:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0016_auto_20211212_2240'),
('benchcoach', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='teamsnap_user',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='teamsnap.user'),
),
]

View File

@@ -1,29 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-13 00:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('teamsnap', '0018_user_managed_teams'),
('benchcoach', '0002_user_teamsnap_user'),
]
operations = [
migrations.CreateModel(
name='Profile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('teamsnap_access_token', models.CharField(max_length=50, null=True)),
('teamsnap_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='teamsnap.user')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.DeleteModel(
name='User',
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-13 01:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('benchcoach', '0003_auto_20211213_0058'),
]
operations = [
migrations.AddField(
model_name='profile',
name='avatar',
field=models.ImageField(blank=True, null=True, upload_to='benchcoach/static/user_files/'),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-13 01:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('benchcoach', '0004_profile_avatar'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='avatar',
field=models.ImageField(blank=True, null=True, upload_to='avatars'),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-13 01:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('benchcoach', '0005_alter_profile_avatar'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='avatar',
field=models.ImageField(blank=True, null=True, upload_to='avatar'),
),
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-16 18:53
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0019_auto_20211216_1851'),
('benchcoach', '0006_alter_profile_avatar'),
]
operations = [
migrations.CreateModel(
name='TeamsnapSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('managed_team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='teamsnap.team')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='benchcoach.profile')),
],
),
]

View File

@@ -1,20 +0,0 @@
# Generated by Django 3.2.6 on 2021-12-16 18:56
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0019_auto_20211216_1851'),
('benchcoach', '0007_teamsnapsettings'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='teamsnap_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='teamsnap.user'),
),
]

View File

@@ -1,18 +1,128 @@
from django.db import models
from teamsnap.models import User as TeamsnapUser, Team as TeamsnapTeam
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT / user_<id>/<filename>
return 'benchcoach/static/user_files/user_{0}/{1}'.format(instance.user.id, filename)
class Team(models.Model):
name = models.CharField(max_length=50)
image = models.FileField(
upload_to="images/",
validators=[FileExtensionValidator(["jpg", "png", "svg"])],
null=True,
)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
teamsnap_access_token = models.CharField(null=True, max_length=50)
teamsnap_user = models.ForeignKey(TeamsnapUser, on_delete=models.CASCADE, null=True, blank=True)
avatar = models.ImageField(upload_to="avatar", null=True, blank=True)
def __str__(self):
return f"{self.name}"
class TeamsnapSettings(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE)
managed_team = models.ForeignKey(TeamsnapTeam, on_delete=models.CASCADE)
class Venue(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return f"{self.name}"
class Event(models.Model):
start = models.DateTimeField(null=True)
venue = models.ForeignKey(Venue, null=True, on_delete=models.CASCADE)
home_team = models.ForeignKey(
Team, null=True, on_delete=models.CASCADE, related_name="home_team"
)
away_team = models.ForeignKey(
Team, null=True, on_delete=models.CASCADE, related_name="away_team"
)
def __str__(self):
return f"{self.start:%Y-%m-%d %H:%M}"
class Season(models.Model):
name = models.CharField(max_length=50)
class Player(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
jersey_number = models.IntegerField(null=True)
team = models.ForeignKey(Team, null=True, on_delete=models.CASCADE)
def __str__(self):
return f"{self.last_name}, {self.first_name}"
class Meta:
unique_together = (
"first_name",
"last_name",
)
class StatLine(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
batting_avg = models.DecimalField(max_digits=4, decimal_places=3, default=0)
onbase_pct = models.DecimalField(max_digits=4, decimal_places=3, default=0)
slugging_pct = models.DecimalField(max_digits=4, decimal_places=3, default=0)
def __str__(self):
return f"{self.slash_line}"
@property
def slash_line(self):
return "/".join(
[
f"{self.batting_avg:.3f}".lstrip("0"),
f"{self.onbase_pct:.3f}".lstrip("0"),
f"{self.slugging_pct:.3f}".replace("0.", "."),
]
)
class Positioning(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
positions = [
("EH", "EH"),
("P", "P"),
("C", "C"),
("1B", "1B"),
("2B", "2B"),
("3B", "3B"),
("SS", "SS"),
("LF", "LF"),
("CF", "CF"),
("RF", "RF"),
("DH", "DH"),
]
position = models.CharField(
choices=positions, default=None, max_length=2, null=True, blank=True
)
order = models.PositiveSmallIntegerField(default=None, null=True, blank=True)
class Meta:
unique_together = (
"player",
"event",
)
def __str__(self):
return f"{self.player}; {self.event};"
class Availability(models.Model):
YES = 2
MAYBE = 1
NO = 0
UNKNOWN = -1
event = models.ForeignKey(Event, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
choices = [(YES, "Yes"), (NO, "No"), (MAYBE, "Maybe"), (UNKNOWN, "Unknown")]
available = models.IntegerField(choices=choices, default=UNKNOWN)
def __str__(self):
return f"{self.event}; {self.player}; {self.available}"
class Meta:
unique_together = (
"event",
"player",
)
verbose_name_plural = "availabilities"

281
benchcoach/tests.py Normal file
View File

@@ -0,0 +1,281 @@
from django.test import TestCase
from .models import Event, Player, Team, Venue, Positioning
from .forms import PositioningFormSet
from datetime import datetime
from django.urls import reverse
FIXTURES = ["blaseball"]
class TestEventModel(TestCase):
fixtures = FIXTURES
def test_query_event(self):
"""
Return the desired event
"""
event = Event.objects.get(id=1)
self.assertEqual("Chicago Firefighters", event.away_team.name)
self.assertEqual("Dallas Steaks", event.home_team.name)
self.assertEqual("George Fourman Stadium", event.venue.name)
self.assertEqual(
datetime(year=2020, month=8, day=24, hour=16, minute=0, second=1),
event.start,
)
class TestEventViews(TestCase):
fixtures = FIXTURES
def test_event_list(self):
response = self.client.get(reverse("schedule"))
self.assertEqual(200, response.status_code)
def test_event_edit(self):
response = self.client.get(reverse("edit event", args=[2]))
self.assertEqual(200, response.status_code)
# create new event
new_event_data = {
"home_team": 23,
"away_team": 24,
"start": datetime(year=2021, month=1, day=1, hour=9, minute=0, second=0),
"venue": 19,
}
response = self.client.post(
reverse("edit event", args=[0]), data=new_event_data
)
self.assertEqual(201, response.status_code)
new_event = Event.objects.get(id=response.context["id"])
self.assertEqual(new_event_data["home_team"], new_event.home_team.id)
self.assertEqual(new_event_data["away_team"], new_event.away_team_id)
self.assertEqual(new_event_data["start"], new_event.start)
# modify event
modified_event_data = {
"home_team": 23,
"away_team": 24,
"start": datetime(year=2021, month=1, day=1, hour=9, minute=0, second=0),
"venue": 19,
}
response = self.client.post(
reverse("edit event", args=[1]), data=modified_event_data
)
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.context["id"])
modified_event = Event.objects.get(id=response.context["id"])
self.assertEqual(modified_event_data["home_team"], modified_event.home_team.id)
self.assertEqual(modified_event_data["away_team"], modified_event.away_team.id)
self.assertEqual(modified_event_data["start"], modified_event.start)
self.assertEqual(modified_event_data["venue"], modified_event.venue.id)
class TestVenueViews(TestCase):
fixtures = ["blaseball"]
def test_positioning_list(self):
response = self.client.get(reverse("edit lineup", args=[1]))
self.assertEqual(response.status_code, 200)
def test_positioning_formset(self):
event = 1
sample_data = [
# first player positioning
(1, Player.objects.get(id=1).id, "P"),
(2, Player.objects.get(id=2).id, "C"),
(3, Player.objects.get(id=3).id, "1B"),
]
data = {}
for i, (order, player, position) in enumerate(sample_data):
data[f"form-{i}-order"] = order
data[f"form-{i}-player"] = player
data[f"form-{i}-position"] = position
management = {
"form-INITIAL_FORMS": "0",
"form-TOTAL_FORMS": len(sample_data),
"form-MAX_NUM_FORMS": "",
}
formset = PositioningFormSet({**management, **data})
self.assertTrue(formset.is_valid())
for form in formset:
self.assertTrue(form.is_valid())
response = self.client.post(
reverse("edit lineup", args=[event]), {**management, **data}
)
self.assertEqual(response.status_code, 200)
for d in sample_data:
with self.subTest(d):
p = Positioning.objects.get(player_id=d[1], event_id=event)
self.assertEqual(d[0], p.order)
self.assertEqual(d[2], p.position)
pass
class TestPlayerModel(TestCase):
fixtures = FIXTURES
def test_query_player(self):
"""
Return the desired player
"""
player = Player.objects.get(id=1)
self.assertEqual(player.first_name, "Edric")
self.assertEqual(player.last_name, "Tosser")
self.assertEqual(player.jersey_number, 1)
self.assertEqual(player.team.name, "Chicago Firefighters")
class TestPlayerViews(TestCase):
fixtures = FIXTURES
def test_player_list(self):
response = self.client.get(reverse("players list"))
self.assertEqual(response.status_code, 200)
def test_player_edit(self):
response = self.client.get(reverse("edit player", args=[1]))
self.assertEqual(response.status_code, 200)
# create new player
new_player_data = {
"first_name": "A new player first name",
"last_name": "A new player last name",
"jersey_number": 99,
"team": 1,
}
response = self.client.post(
reverse("edit player", args=[0]), data=new_player_data
)
self.assertEqual(201, response.status_code)
new_player = Player.objects.get(id=response.context["id"])
self.assertEqual(new_player_data["first_name"], new_player.first_name)
self.assertEqual(new_player_data["last_name"], new_player.last_name)
# modify player
modified_player_data = {
"first_name": "A changed player first name",
"last_name": "A changed player last name",
"jersey_number": 99,
"team": 1,
}
response = self.client.post(
reverse("edit player", args=[1]), data=modified_player_data
)
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.context["id"])
modified_player = Player.objects.get(id=response.context["id"])
self.assertEqual(modified_player_data["first_name"], modified_player.first_name)
self.assertEqual(modified_player_data["last_name"], modified_player.last_name)
class TestTeamModel(TestCase):
fixtures = ["blaseball"]
def test_query_team(self):
"""
Return the desired team
"""
team = Team.objects.get(id=1)
self.assertEqual(team.name, "Chicago Firefighters")
class TestTeamViews(TestCase):
fixtures = ["blaseball"]
def test_team_list(self):
response = self.client.get(reverse("teams list"))
self.assertEqual(response.status_code, 200)
self.assertIn(
{"id": 1, "title": "Chicago Firefighters"}, response.context["items"]
)
self.assertIn({"id": 2, "title": "Boston Flowers"}, response.context["items"])
self.assertIn({"id": 24, "title": "Baltimore Crabs"}, response.context["items"])
def test_team_edit(self):
response = self.client.get(reverse("edit team", args=[1]))
self.assertEqual(response.status_code, 200)
# create new team
response = self.client.post(
reverse("edit team", args=[0]), data={"name": "A new team"}
)
self.assertEqual(201, response.status_code)
new_team = Team.objects.get(id=response.context["id"])
self.assertEqual(
"A new team",
new_team.name,
)
# modify team
response = self.client.post(
reverse("edit team", args=[1]), data={"name": "A different team name"}
)
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.context["id"])
modified_team = Team.objects.get(id=response.context["id"])
self.assertEqual("A different team name", modified_team.name)
class TestVenueModel(TestCase):
fixtures = ["blaseball"]
def test_query_venue(self):
"""
Return the desired venue
"""
venue = Venue.objects.get(id=1)
self.assertEqual(venue.name, "Chesapeake Racetrack and Ballpark")
class TestVenueViews(TestCase):
fixtures = ["blaseball"]
def test_venue_list(self):
response = self.client.get(reverse("venues list"))
self.assertEqual(response.status_code, 200)
self.assertIn(
{"id": 1, "title": "Chesapeake Racetrack and Ballpark"},
response.context["items"],
)
self.assertIn(
{"id": 2, "title": "Tokyo Fitness Center"}, response.context["items"]
)
self.assertIn(
{"id": 25, "title": "ILB Historical Preservation Site"},
response.context["items"],
)
def test_venue_edit(self):
response = self.client.get(reverse("edit venue", args=[1]))
self.assertEqual(response.status_code, 200)
# create new venue
response = self.client.post(
reverse("edit venue", args=[0]), data={"name": "A new venue"}
)
self.assertEqual(201, response.status_code)
new_venue = Venue.objects.get(id=response.context["id"])
self.assertEqual(
"A new venue",
new_venue.name,
)
# modify venue
response = self.client.post(
reverse("edit venue", args=[1]), data={"name": "A different venue name"}
)
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.context["id"])
modified_venue = Venue.objects.get(id=response.context["id"])
self.assertEqual("A different venue name", modified_venue.name)

View File

@@ -1,33 +1,12 @@
"""events URL Configuration
from django.urls import path
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from .views import welcome, user_login
from . import views
urlpatterns = [
path('', welcome, name="home"),
path('admin/', admin.site.urls),
path('events/', include('events.urls')),
path('teams/', include('teams.urls')),
path('venues/', include('venues.urls')),
path('players/', include('players.urls')),
path('lineups/', include('lineups.urls')),
path('teamsnap/', include('teamsnap.urls')),
path('login', user_login, name="login")
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
path('lineup/edit/<int:event_id>', views.lineup_edit, name="edit lineup"),
path('events/list', views.EventListView.as_view(), name="event list"),
path('events/<int:pk>/detail', views.EventDetailView.as_view(), name="event detail"),
path('players/list', views.PlayerListView.as_view(), name="player list"),
path('teams/list', views.TeamListView.as_view(), name="team list"),
path('venues/list', views.VenueListView.as_view(), name="venue list")
]

View File

@@ -1,31 +1,142 @@
from django.http import HttpResponse
from django.shortcuts import render,redirect, reverse, HttpResponseRedirect
from django.contrib.auth import login,authenticate
from django.shortcuts import render
from .models import Event, Team, Player, Positioning, Venue
from .forms import PositioningFormSet, TeamsnapEventForm
from django.contrib import messages
from django.db.models import F
from django.views.generic import ListView, DetailView
def welcome(request):
pages = ['events list', 'teams list', 'venues list', 'players list', 'teamsnap list events', 'teamsnap home', 'login']
return render(request,'home.html',{'pages':pages})
class BenchCoachListView(ListView):
title = None
class EventDetailView(DetailView):
model = Event
context_object_name = "event"
template_name = 'benchcoach/event-detail.html'
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
class EventListView(ListView):
model = Event
context_object_name = "events"
template_name = 'benchcoach/event-list.html'
try:
user = authenticate(request, username=username, password=password)
if user is not None:
print('Login')
login(request,user)
return redirect(reverse('home'))
else:
print("Someone tried to login and failed.")
print("They used username: {} and password: {}".format(username, password))
class PlayerListView(ListView):
model = Player
template_name = 'benchcoach/list.html'
return redirect('/')
except Exception as identifier:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = "Players"
context['members_tab_active'] ='active'
return context
return redirect('/')
class TeamListView(ListView):
model = Team
template_name = 'benchcoach/list.html'
else:
return render(request, 'login.html')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = "Teams"
context['opponents_tab_active'] ='active'
return context
class VenueListView(ListView):
model = Venue
template_name = 'benchcoach/list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = "Venues"
context['venues_tab_active'] ='active'
return context
def lineup_edit(request, event_id):
if request.method == "POST":
# create a form instance and populate it with data from the request:
formset = PositioningFormSet(request.POST)
is_valid = [f.is_valid() for f in formset]
for form in formset:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
if isinstance(form.cleaned_data["id"], Positioning):
positioning_id = form.cleaned_data.pop(
"id"
).id # FIXME this is a workaround, not sure why it is necessary
positioning = Positioning.objects.filter(id=positioning_id)
positioning.update(**form.cleaned_data)
did_create = False
else:
positioning = Positioning.objects.create(
**form.cleaned_data, event_id=event_id
)
did_create = True
else:
messages.error(
request, f"Error submitting lineup. {form.instance} {form.errors}"
)
pass
if (True in is_valid) and (False in is_valid):
messages.warning(request, "Lineup partially submitted.")
elif True in is_valid:
messages.success(request, "Lineup submitted successfully.")
elif True not in is_valid:
messages.error(request, f"Error submitting lineup.")
else:
messages.error(request, f"Error submitting lineup.")
# return HttpResponse(status=204)
# return render(request, 'success.html', {'call_back':'edit lineup','id':event_id, 'errors':[error for error in formset.errors if error]}, status=200)
previous_event = Event.objects.filter(id=event_id - 1).first()
event = Event.objects.get(id=event_id)
next_event = Event.objects.get(id=event_id + 1)
players = Player.objects.prefetch_related("availability_set", "positioning_set")
for player in players:
Positioning.objects.get_or_create(player_id=player.id, event_id=event_id)
qs = (
event.positioning_set.all()
.filter(player__availability__event=event_id)
.order_by("order", "-player__availability__available", "player__last_name")
.annotate(event_availability=F("player__availability__available"))
)
formset = PositioningFormSet(queryset=qs)
formset_lineup = [f for f in formset if f.instance.order]
formset_dhd = [f for f in formset if not f.instance.order and f.instance.position]
formset_bench = [
f for f in formset if f not in formset_lineup and f not in formset_dhd
]
teamsnap_form = TeamsnapEventForm(instance=event)
details = {
"Away Team": event.away_team,
"Home Team": event.home_team,
"Date": event.start.date(),
"Time": event.start.time(),
"Venue": event.venue,
"TeamSnap": teamsnap_form
# "TeamSnap Link": event.event_set.first()
# "TeamSnap Link": f'<a href="{reverse("teamsnap edit event", kwargs={"id": event.event_set.first().id})}"> {event.event_set.first()} </a>' if event.event_set.first() else None
}
return render(
request,
"benchcoach/lineup.html",
{
"title": "Lineup",
"event": event,
"details": details,
"previous_event": previous_event,
"teamsnap_form": teamsnap_form,
"next_event": next_event,
"formset": formset,
"formset_lineup": formset_lineup,
"formset_bench": formset_bench,
"formset_dhd": formset_dhd,
},
)

View File

@@ -0,0 +1,6 @@
from django.contrib import admin
from .models import Profile, TeamsnapSettings
# Register your models here.
admin.site.register(Profile)
admin.site.register(TeamsnapSettings)

View File

@@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'events.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'benchcoachproject.settings')
application = get_asgi_application()

View File

@@ -1,6 +1,6 @@
[
{
"model": "teams.team",
"model": "benchcoach.team",
"pk": 1,
"fields": {
"name": "a",

View File

@@ -0,0 +1,36 @@
# Generated by Django 3.2.6 on 2021-12-17 22:07
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('teamsnap', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Profile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('teamsnap_access_token', models.CharField(max_length=50, null=True)),
('avatar', models.ImageField(blank=True, null=True, upload_to='avatar')),
('teamsnap_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='teamsnap.user')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='TeamsnapSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('managed_team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='teamsnap.team')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='benchcoachproject.profile')),
],
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 3.2.6 on 2021-12-20 02:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0002_event_game_type'),
('benchcoachproject', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='profile',
name='teamsnap_user',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='benchcoach_object', to='teamsnap.user'),
),
]

View File

@@ -0,0 +1,19 @@
from django.db import models
from teamsnap.models import User as TeamsnapUser, Team as TeamsnapTeam
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
teamsnap_access_token = models.CharField(null=True, max_length=50)
teamsnap_user = models.OneToOneField(
TeamsnapUser,
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="benchcoach_object"
)
avatar = models.ImageField(upload_to="avatar", null=True, blank=True)
class TeamsnapSettings(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE)
managed_team = models.ForeignKey(TeamsnapTeam, on_delete=models.CASCADE)

View File

@@ -31,11 +31,7 @@ ALLOWED_HOSTS = ["smithers-ii.local", "127.0.0.1", "10.0.1.4", "benchcoach.ascor
# Application definition
INSTALLED_APPS = [
'events.apps.EventsConfig',
'teams.apps.TeamsConfig',
'venues.apps.VenuesConfig',
'players.apps.PlayersConfig',
'lineups.apps.LineupsConfig',
'benchcoach.apps.BenchcoachConfig',
'teamsnap.apps.TeamsnapConfig',
'django.contrib.admin',
'django.contrib.auth',
@@ -43,8 +39,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'benchcoach'
'benchcoachproject'
]
MIDDLEWARE = [
@@ -57,7 +52,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'benchcoach.urls'
ROOT_URLCONF = 'benchcoachproject.urls'
TEMPLATES = [
{
@@ -77,7 +72,7 @@ TEMPLATES = [
},
]
WSGI_APPLICATION = 'benchcoach.wsgi.application'
WSGI_APPLICATION = 'benchcoachproject.wsgi.application'
# Database
@@ -115,13 +110,13 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
TIME_ZONE = 'America/Chicago'
USE_I18N = True
USE_L10N = True
USE_TZ = False
USE_TZ = True
# Static files (CSS, JavaScript, Images)
@@ -135,6 +130,4 @@ STATIC_URL = '/static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
CRISPY_TEMPLATE_PACK = 'bootstrap4'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

29
benchcoachproject/urls.py Normal file
View File

@@ -0,0 +1,29 @@
"""events URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
from .views import welcome, user_login
urlpatterns = [
path("", welcome, name="home"),
path("", include("benchcoach.urls")),
path("admin/", admin.site.urls),
path("teamsnap/", include("teamsnap.urls")),
path("login", user_login, name="login"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -0,0 +1,31 @@
from django.http import HttpResponse
from django.shortcuts import render,redirect, reverse, HttpResponseRedirect
from django.contrib.auth import login,authenticate
def welcome(request):
pages = ['event list', 'team list', 'venue list', 'player list', 'teamsnap list events', 'teamsnap home', 'login']
return render(request,'home.html',{'pages':pages})
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
try:
user = authenticate(request, username=username, password=password)
if user is not None:
print('Login')
login(request,user)
return redirect(reverse('home'))
else:
print("Someone tried to login and failed.")
print("They used username: {} and password: {}".format(username, password))
return redirect('/')
except Exception as identifier:
return redirect('/')
else:
return render(request, 'login.html')

View File

@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'events.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'benchcoachproject.settings')
application = get_wsgi_application()

View File

@@ -1,7 +0,0 @@
from django.contrib import admin
from .models import Event
# Register your models here.
admin.site.register(Event)

View File

@@ -1,6 +0,0 @@
from django.apps import AppConfig
class EventsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'events'

View File

@@ -1,412 +0,0 @@
[
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-03-11 17:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-03-21 13:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 18,
"away_team_id": 5,
"home_team_id": null,
"start": "2021-03-28 16:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 5,
"home_team_id": 10,
"start": "2021-04-03 12:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 18,
"away_team_id": 5,
"home_team_id": 10,
"start": "2021-04-11 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 5,
"home_team_id": 4,
"start": "2021-04-17 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 5,
"home_team_id": 8,
"start": "2021-04-24 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-04-27 17:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 1,
"home_team_id": 5,
"start": "2021-05-01 12:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 7,
"away_team_id": 7,
"home_team_id": 5,
"start": "2021-05-02 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 5,
"home_team_id": 9,
"start": "2021-05-06 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 8,
"home_team_id": 5,
"start": "2021-05-08 12:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 2,
"away_team_id": null,
"home_team_id": null,
"start": "2021-05-11 17:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 16,
"away_team_id": 5,
"home_team_id": 6,
"start": "2021-05-16 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 5,
"home_team_id": 3,
"start": "2021-05-21 19:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 7,
"away_team_id": 5,
"home_team_id": 8,
"start": "2021-05-22 12:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 5,
"home_team_id": 7,
"start": "2021-05-23 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 5,
"home_team_id": 1,
"start": "2021-05-30 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 2,
"home_team_id": 5,
"start": "2021-06-01 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 9,
"home_team_id": 5,
"start": "2021-06-03 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 7,
"away_team_id": 5,
"home_team_id": 9,
"start": "2021-06-05 12:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 7,
"home_team_id": 5,
"start": "2021-06-06 10:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 5,
"home_team_id": 4,
"start": "2021-06-10 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 16,
"away_team_id": 1,
"home_team_id": 5,
"start": "2021-06-13 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": 3,
"home_team_id": 5,
"start": "2021-06-15 19:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-06-18 20:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 21,
"away_team_id": 10,
"home_team_id": 5,
"start": "2021-06-19 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 5,
"home_team_id": 10,
"start": "2021-06-19 12:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-06-23 20:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-06-25 19:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 1,
"away_team_id": null,
"home_team_id": null,
"start": "2021-06-27 16:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 4,
"away_team_id": 5,
"home_team_id": 2,
"start": "2021-07-08 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 2,
"away_team_id": 4,
"home_team_id": 5,
"start": "2021-07-10 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 19,
"away_team_id": 4,
"home_team_id": 5,
"start": "2021-07-11 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 16,
"away_team_id": 10,
"home_team_id": 5,
"start": "2021-07-13 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 2,
"away_team_id": 5,
"home_team_id": 2,
"start": "2021-07-15 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 20,
"away_team_id": 5,
"home_team_id": 6,
"start": "2021-07-18 9:30:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 5,
"away_team_id": 8,
"home_team_id": 5,
"start": "2021-07-21 20:00:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 3,
"away_team_id": 5,
"home_team_id": 3,
"start": "2021-07-22 19:15:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 5,
"away_team_id": 6,
"home_team_id": 5,
"start": "2021-07-29 17:50:00"
}
},
{
"model": "events.event",
"pk": null,
"fields": {
"venue_id": 5,
"away_team_id": 1,
"home_team_id": 5,
"start": "2021-07-31 9:30:00"
}
}
]

View File

@@ -1,245 +0,0 @@
- model: events.event
pk: 1
fields:
start: '2020-08-24T16:00:01'
away_team_id: '1'
home_team_id: '7'
venue_id: '15'
- model: events.event
pk: 2
fields:
start: '2020-08-24T19:00:02'
away_team_id: '7'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 3
fields:
start: '2020-08-24T22:00:01'
away_team_id: '12'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 4
fields:
start: '2020-08-25T00:00:01'
away_team_id: '12'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 5
fields:
start: '2020-08-25T01:00:02'
away_team_id: '1'
home_team_id: '2'
venue_id: '10'
- model: events.event
pk: 6
fields:
start: '2020-08-25T04:00:00'
away_team_id: '6'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 7
fields:
start: '2020-08-25T07:00:03'
away_team_id: '1'
home_team_id: '6'
venue_id: '8'
- model: events.event
pk: 8
fields:
start: '2020-08-25T10:00:03'
away_team_id: '11'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 9
fields:
start: '2020-08-25T13:00:01'
away_team_id: '7'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 10
fields:
start: '2020-08-25T16:00:00'
away_team_id: '1'
home_team_id: '7'
venue_id: '15'
- model: events.event
pk: 11
fields:
start: '2020-08-25T19:00:03'
away_team_id: '1'
home_team_id: '16'
venue_id: '24'
- model: events.event
pk: 12
fields:
start: '2020-08-26T00:00:03'
away_team_id: '6'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 13
fields:
start: '2020-08-26T01:00:01'
away_team_id: '1'
home_team_id: '12'
venue_id: '20'
- model: events.event
pk: 14
fields:
start: '2020-08-26T04:00:01'
away_team_id: '1'
home_team_id: '2'
venue_id: '10'
- model: events.event
pk: 15
fields:
start: '2020-08-26T07:00:02'
away_team_id: '1'
home_team_id: '4'
venue_id: '23'
- model: events.event
pk: 16
fields:
start: '2020-08-26T13:00:02'
away_team_id: '11'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 17
fields:
start: '2020-08-26T16:00:00'
away_team_id: '15'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 18
fields:
start: '2020-08-26T19:00:03'
away_team_id: '16'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 19
fields:
start: '2020-08-27T00:00:02'
away_team_id: '11'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 20
fields:
start: '2020-08-27T01:00:00'
away_team_id: '15'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 21
fields:
start: '2020-08-27T14:00:02'
away_team_id: '1'
home_team_id: '2'
venue_id: '10'
- model: events.event
pk: 22
fields:
start: '2020-08-27T17:00:01'
away_team_id: '7'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 23
fields:
start: '2020-08-27T23:00:02'
away_team_id: '1'
home_team_id: '7'
venue_id: '15'
- model: events.event
pk: 24
fields:
start: '2020-08-28T00:00:02'
away_team_id: '1'
home_team_id: '7'
venue_id: '15'
- model: events.event
pk: 25
fields:
start: '2021-10-26T17:12:48'
away_team_id: '1'
home_team_id: '7'
venue_id: '15'
- model: events.event
pk: 26
fields:
start: '2020-08-28T05:00:05'
away_team_id: '1'
home_team_id: '20'
venue_id: '21'
- model: events.event
pk: 27
fields:
start: '2020-08-28T08:00:02'
away_team_id: '1'
home_team_id: '12'
venue_id: '20'
- model: events.event
pk: 28
fields:
start: '2020-08-28T11:00:06'
away_team_id: '1'
home_team_id: '11'
venue_id: '16'
- model: events.event
pk: 29
fields:
start: '2020-08-28T14:00:02'
away_team_id: '1'
home_team_id: '4'
venue_id: '23'
- model: events.event
pk: 30
fields:
start: '2020-08-28T17:00:05'
away_team_id: '1'
home_team_id: '6'
venue_id: '8'
- model: events.event
pk: 31
fields:
start: '2020-08-28T23:00:09'
away_team_id: '19'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 32
fields:
start: '2020-08-29T00:00:05'
away_team_id: '19'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 33
fields:
start: '2020-08-29T02:00:02'
away_team_id: '6'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 34
fields:
start: '2020-08-29T05:00:06'
away_team_id: '15'
home_team_id: '1'
venue_id: '4'
- model: events.event
pk: 35
fields:
start: '2020-08-29T13:00:06'
away_team_id: '8'
home_team_id: '1'
venue_id: '4'

View File

@@ -1,7 +0,0 @@
from django import forms
from .models import Event
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['start', 'home_team', 'away_team', 'venue']

View File

@@ -1,60 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-07 17:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('venues', '0001_initial'),
('teams', '0001_initial'),
('players', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Event',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('start', models.DateTimeField(null=True)),
('away_team', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='away_team', to='teams.team')),
('home_team', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='home_team', to='teams.team')),
('venue', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='venues.venue')),
],
),
migrations.CreateModel(
name='Season',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name='Positioning',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('position', models.CharField(choices=[('P', 'P'), ('C', 'C'), ('1B', '1B'), ('2B', '2B'), ('3B', '3B'), ('SS', 'SS'), ('LF', 'LF'), ('CF', 'CF'), ('RF', 'RF'), ('DH', 'DH'), ('EH', 'EH')], default=None, max_length=2, null=True)),
('order', models.IntegerField(default=None, null=True)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='players.player')),
],
options={
'unique_together': {('player', 'event')},
},
),
migrations.CreateModel(
name='Availability',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('available', models.CharField(choices=[('Yes', 'YES'), ('No', 'NO'), ('Maybe', 'MAY'), ('Unknown', 'UNK')], default='UNK', max_length=7)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='players.player')),
],
options={
'unique_together': {('event', 'player')},
},
),
]

View File

@@ -1,17 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-07 18:39
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='availability',
options={'verbose_name_plural': 'availabilities'},
),
]

View File

@@ -1,16 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-11 03:14
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0002_alter_availability_options'),
]
operations = [
migrations.DeleteModel(
name='Positioning',
),
]

View File

@@ -1,16 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-14 23:59
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('events', '0003_delete_positioning'),
]
operations = [
migrations.DeleteModel(
name='Availability',
),
]

View File

@@ -1,16 +0,0 @@
from django.db import models
from venues.models import Venue
from teams.models import Team
from players.models import Player, StatLine
class Event(models.Model):
start = models.DateTimeField(null=True)
venue = models.ForeignKey(Venue, null=True, on_delete=models.CASCADE)
home_team = models.ForeignKey(Team, null=True,on_delete=models.CASCADE, related_name="home_team")
away_team = models.ForeignKey(Team, null=True,on_delete=models.CASCADE, related_name="away_team")
def __str__(self):
return f"{self.start:%Y-%m-%d %H:%M}"
class Season(models.Model):
name = models.CharField(max_length=50)

View File

@@ -1,80 +0,0 @@
from django.test import TestCase, Client
from django.test.utils import setup_test_environment
from django.urls import reverse
from .models import Event
from datetime import datetime
FIXTURES = ['blaseball']
class TestEventModel(TestCase):
fixtures = FIXTURES
def test_query_event(self):
"""
Return the desired event
"""
event = Event.objects.get(id=1)
self.assertEqual("Chicago Firefighters", event.away_team.name)
self.assertEqual("Dallas Steaks", event.home_team.name)
self.assertEqual('George Fourman Stadium', event.venue.name)
self.assertEqual(datetime(
year=2020,
month=8,
day=24,
hour=16,
minute=0,
second=1), event.start)
class TestEventViews(TestCase):
fixtures = FIXTURES
def test_event_list(self):
response = self.client.get(reverse('schedule'))
self.assertEqual(200, response.status_code)
def test_event_edit(self):
response = self.client.get(reverse('edit event', args=[2]))
self.assertEqual(200, response.status_code)
# create new event
new_event_data = {
'home_team': 23,
'away_team': 24,
'start':datetime(
year=2021,
month=1,
day=1,
hour=9,
minute=0,
second=0),
'venue':19
}
response = self.client.post(reverse('edit event', args=[0]), data=new_event_data)
self.assertEqual(201, response.status_code)
new_event = Event.objects.get(id=response.context['id'])
self.assertEqual(new_event_data['home_team'], new_event.home_team.id)
self.assertEqual(new_event_data['away_team'], new_event.away_team_id)
self.assertEqual(new_event_data['start'], new_event.start)
# modify event
modified_event_data = {
'home_team': 23,
'away_team': 24,
'start':datetime(
year=2021,
month=1,
day=1,
hour=9,
minute=0,
second=0),
'venue':19
}
response = self.client.post(reverse('edit event', args=[1]), data=modified_event_data)
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.context['id'])
modified_event = Event.objects.get(id=response.context['id'])
self.assertEqual(modified_event_data['home_team'], modified_event.home_team.id)
self.assertEqual(modified_event_data['away_team'], modified_event.away_team.id)
self.assertEqual(modified_event_data['start'], modified_event.start)
self.assertEqual(modified_event_data['venue'], modified_event.venue.id)

View File

@@ -1,12 +0,0 @@
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.root, name="root"),
path('list', views.EventsListView.as_view(), name="events list"),
path('edit/<int:id>', views.EventEditView.as_view(), name="edit event"),
path('edit', views.EventEditView.as_view(), name="edit event"),
]

View File

@@ -1,34 +0,0 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from .models import Event
from .forms import EventForm
from lib.views import BenchcoachListView, BenchcoachEditView
def root(request):
return redirect(reverse('events list'))
class EventsListView(BenchcoachListView):
Model = Event
edit_url = 'edit event'
list_url = 'events list'
page_title = "Events"
title_strf = '{item.away_team} vs. {item.home_team}'
body_strf = "{item.start:%a, %b %-d, %-I:%M %p},\n{item.venue}"
active_tabs = ['events_tab']
def get_context_data(self):
context = super().get_context_data()
for item in context['items']:
item['buttons'].append(
{
'label': 'Edit Lineup',
'href': reverse('edit lineup', args=[item['id']])
}
)
return context
class EventEditView(BenchcoachEditView):
Model = Event
edit_url = 'edit event'
list_url = 'events list'
Form = EventForm

View File

View File

@@ -1,6 +0,0 @@
from django.contrib import admin
from .models import Availability, Positioning
# Register your models here.
admin.site.register(Availability)
admin.site.register(Positioning)

View File

@@ -1,6 +0,0 @@
from django.apps import AppConfig
class LineupsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'lineups'

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-11 03:14
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('events', '0003_delete_positioning'),
('players', '0003_player_team'),
]
operations = [
migrations.CreateModel(
name='Positioning',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('position', models.CharField(choices=[('P', 'P'), ('C', 'C'), ('1B', '1B'), ('2B', '2B'), ('3B', '3B'), ('SS', 'SS'), ('LF', 'LF'), ('CF', 'CF'), ('RF', 'RF'), ('DH', 'DH'), ('EH', 'EH')], default=None, max_length=2, null=True)),
('order', models.IntegerField(default=None, null=True)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='players.player')),
],
options={
'unique_together': {('player', 'event')},
},
),
]

View File

@@ -1,29 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-14 23:59
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('players', '0003_player_team'),
('events', '0004_delete_availability'),
('lineups', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Availability',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('available', models.IntegerField(choices=[(2, 'Yes'), (-1, 'No'), (1, 'MAY'), (0, 0)], default=0, max_length=7)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.event')),
('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='players.player')),
],
options={
'verbose_name_plural': 'availabilities',
'unique_together': {('event', 'player')},
},
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-15 00:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lineups', '0002_availability'),
]
operations = [
migrations.AlterField(
model_name='availability',
name='available',
field=models.IntegerField(choices=[(2, 'Yes'), (0, 'No'), (1, 'MAY'), (-1, 0)], default=-1),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-15 00:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lineups', '0003_alter_availability_available'),
]
operations = [
migrations.AlterField(
model_name='availability',
name='available',
field=models.IntegerField(choices=[(2, 'Yes'), (0, 'No'), (1, 'Maybe'), (-1, 'Unknown')], default=-1),
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 3.2.6 on 2021-11-18 23:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lineups', '0004_alter_availability_available'),
]
operations = [
migrations.AlterField(
model_name='positioning',
name='position',
field=models.CharField(choices=[('EH', 'EH'), ('P', 'P'), ('C', 'C'), ('1B', '1B'), ('2B', '2B'), ('3B', '3B'), ('SS', 'SS'), ('LF', 'LF'), ('CF', 'CF'), ('RF', 'RF'), ('DH', 'DH')], default=None, max_length=2, null=True),
),
]

Some files were not shown because too many files have changed in this diff Show More