Merge branch 'v2' into v2-gamechanger

# Conflicts:
#	config/settings/base.py
#	setup.cfg
#	teamsnap/migrations/0001_initial.py
This commit is contained in:
2022-06-10 11:45:32 -05:00
7 changed files with 277 additions and 226 deletions

View File

@@ -275,6 +275,7 @@ SOCIALACCOUNT_FORMS = {"signup": "benchcoach.users.forms.UserSocialSignupForm"}
INSTALLED_APPS += [ INSTALLED_APPS += [
"teamsnap", "teamsnap",
"instagen", "instagen",
"gamecard",
"gamechanger", "gamechanger",
"teamsnap.lineup", "teamsnap.lineup",
"teamsnap.dashboard", "teamsnap.dashboard",

View File

@@ -1,191 +1,240 @@
{% load static %} {% load static %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.2/font/bootstrap-icons.css">
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="{% static 'css/gamecard.css' %}"> <link rel="stylesheet" href="{% static 'css/gamecard.css' %}">
<title>Title</title> <title>Title</title>
</head> </head>
<body class="b5"> <body class="b5">
<section class="sheet"> <section class="sheet">
<div class="whole-card"> <div class="whole-card">
<div class="half-card"> <div class="half-card">
<div class="content card-left"> <div class="content card-left">
<table> <table>
<thead> <thead>
<tr> <tr>
<th colspan="8" class="gametitle"> <th colspan="8" class="gametitle">
{{ event.data.formatted_title }} {{ event.data.start_date|date:'m/d/Y g:i A' }} {{ event.data.formatted_title }} {{ event.data.start_date|date:'m/d/Y g:i A' }}
{# G#01 at Browns 05/01/2021 12:30 PM#} {# G#01 at Browns 05/01/2021 12:30 PM#}
</th> </th>
<th class="homeaway" colspan="4">{{ event.data.game_type }}</th> <th class="homeaway" colspan="4">{{ event.data.game_type }}</th>
</tr> </tr>
</thead> </thead>
</table> </table>
<table> <table>
<thead> <thead>
<tr> <tr>
<th class="numbercell"> <th class="numbercell">
</th> </th>
<th class="customcol"> <th class="customcol">
</th> </th>
<th class="numbercell"> <th class="numbercell">
</th> </th>
<th class="numbercell"> <th class="numbercell">
</th> </th>
<th class="numbercell">1 <th class="numbercell">1
</th> </th>
<th class="numbercell">2 <th class="numbercell">2
</th> </th>
<th class="numbercell">3 <th class="numbercell">3
</th> </th>
<th class="numbercell">4 <th class="numbercell">4
</th> </th>
<th class="numbercell">5 <th class="numbercell">5
</th> </th>
<th class="numbercell">6 <th class="numbercell">6
</th> </th>
<th class="numbercell">7 <th class="numbercell">7
</th> </th>
<th class="numbercell">X <th class="numbercell">X
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for member in members_startinglineup %} {% for member in members_startinglineup %}
<tr> <tr>
<td class="numbercell">{{ member.lineup_entry.sequence | add:"1" }}</td> <td class="numbercell">{{ member.lineup_entry.sequence | add:"1" }}</td>
<td class="customcol">{{ member.member.last_name }}</td> <td class="customcol">{{ member.member.last_name }}</td>
<td class="numbercell">{{ member.member.jersey_number }}</td> <td class="numbercell">{{ member.member.jersey_number }}</td>
<td class="numbercell">{{ member.lineup_entry.label }}</td> <td class="numbercell">{{ member.lineup_entry.label }}</td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<table> <table>
<tbody> <tbody>
{% for member in members_startingpositiononly %} {% for member in members_startingpositiononly %}
<tr> <tr>
<td class="numbercell"></td> <td class="numbercell"></td>
<td class="customcol">{{ member.member.last_name }}</td> <td class="customcol">{{ member.member.last_name }}</td>
<td class="numbercell">{{ member.member.jersey_number }}</td> <td class="numbercell">{{ member.member.jersey_number }}</td>
<td class="numbercell">{{ member.lineup_entry.label }}</td> <td class="numbercell">{{ member.lineup_entry.label }}</td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<div class="half-card">
<div class="content card-right">
<table class="tg">
<thead>
<tr>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="condensedNameCell">Available</th>
<th class="statscell">AVG/OBP/SLG:PA</th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
<th class="numbercell"></th>
</tr>
</thead>
<tbody>
{% for member in members %}
<tr>
<td class="numbercell"></td>
<td class="numbercell available-status-code-{{ member.availability.status_code }}">{{ member.member.jersey_number }}</td>
<td class="condensedNameCell available-status-code-{{ member.availability.status_code }}">{{ member.member.last_name }}</td>
<td class="statscell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
<td class="numbercell"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div> </div>
<div class="whole-card"> <div class="half-card">
<div class="half-card"> <div class="content card-right">
<div class="content card-left"></div> <table class="tg">
</div> <thead>
<div class="half-card"> <tr>
<div class="content card-right"> <th class="numbercell"></th>
<div> <th class="numbercell"></th>
<table> <th class="condensedNameCell">Available</th>
<thead> <th class="statscell">AVG/OBP/SLG:PA</th>
<tr> <th class="numbercell">P</th>
<th class="numbercell" style="background-color: #323669"> <th class="numbercell">C</th>
{{ event.data.start_date|date:"D, F j, Y g:i A" }} <th class="numbercell">IF</th>
</th> <th class="numbercell">OF</th>
</tr> {% for event in events_future %}
<tr> <th class="numbercell">
<th class="numbercell" style="background-color: #323669"> <span style="transform: rotate(-90deg);display: inline-block">
{{ event.data.location_name }} {{ event.data.start_date|date:'D' }}
</th> </span>
</tr> </th>
<tr> {% endfor %}
<th class="numbercell" style="background-color: lightgray"> {% for event in events_past %}
<th class="numbercell">
<span style="transform: rotate(-90deg);display: inline-block">
{{ event.data.start_date|date:'D' }}
</span>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for member in members %}
</th> <tr>
</tr> <td class="numbercell"></td>
</thead> <td class="numbercell available-status-code-{{ member.availability.status_code }}">{{ member.member.jersey_number }}</td>
</table> <td class="condensedNameCell available-status-code-{{ member.availability.status_code }}">{{ member.member.last_name }}</td>
<div> <td class="statscell"></td>
<div class="" width="100%"> <td class="numbercell">
<img src="{{ ts_team.logo.url }}" {% if "P" in member.member.position %}
height="120px" <i class="bi bi-check-square-fill"></i>
> {% else %}
</div> <i class="bi bi-square"></i>
<div class="" width="100%" style="text-align: center;font-size: xxx-large; font-family: Pacifico"> {% endif %}
VS. <td class="numbercell">
</div> {% if "C" in member.member.position %}
<div class="" width="100%" style="text-align: right"> <i class="bi bi-check-square-fill"></i>
<img src="{{ ts_opponent.logo.url }}" {% else %}
width="120px" <i class="bi bi-square"></i>
> {% endif %}
</div> </td>
</div> <td class="numbercell">
</div> {% if "IF" in member.member.position or "1B" in member.member.position %}
</div> <i class="bi bi-check-square-fill"></i>
</div> {% else %}
<i class="bi bi-square"></i>
{% endif %}
</td>
<td class="numbercell">
{% if "OF" in member.member.position %}
<i class="bi bi-check-square-fill"></i>
{% else %}
<i class="bi bi-square"></i>
{% endif %}
</td>
<td class="numbercell available-status-code-{{ member.availability_future.0.data.status_code }}">
{{ member.availability_future.0.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_future.1.data.status_code }}">
{{ member.availability_future.1.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_future.2.data.status_code }}">
{{ member.availability_future.2.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_future.3.data.status_code }}">
{{ member.availability_future.3.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_past.0.data.status_code }}">
{{ member.availability_past.0.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_past.1.data.status_code }}">
{{ member.availability_past.1.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_past.2.data.status_code }}">
{{ member.availability_past.2.data.status.0 }}
</td>
<td class="numbercell available-status-code-{{ member.availability_past.3.data.status_code }}">
{{ member.availability_past.3.data.status.0 }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
</div>
<div class="whole-card">
<div class="half-card">
<div class="content card-left"></div>
</div>
<div class="half-card">
<div class="content card-right">
<div>
<table>
<thead>
<tr>
<th class="numbercell" style="background-color: #323669">
{{ event.data.start_date|date:"D, F j, Y g:i A" }}
</th>
</tr>
<tr>
<th class="numbercell" style="background-color: #323669">
{{ event.data.location_name }}
</th>
</tr>
<tr>
<th class="numbercell" style="background-color: lightgray">
</th>
</tr>
</thead>
</table>
<div>
<div class="" width="100%">
<img src="{{ ts_team.logo.url }}"
height="120px"
>
</div>
<div class="" width="100%" style="text-align: center;font-size: xxx-large; font-family: Pacifico">
VS.
</div>
<div class="" width="100%" style="text-align: right">
{% if ts_opponent %}
<img src="{{ ts_opponent.logo.url }}"
width="120px"
>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</section> </section>
</body> </body>
</html> </html>

View File

@@ -1,9 +1,12 @@
# TODO Remove VCR
import vcr
from django.shortcuts import render from django.shortcuts import render
from teamsnap.models import Opponent, Team from teamsnap.models import Opponent, Team
from teamsnap.utils import get_teamsnap_client from teamsnap.utils import get_teamsnap_client
@vcr.use_cassette("gamecard/fixtures/gamecard.yaml", record_mode="new_episodes")
def gamecard(request, team_id, event_id): def gamecard(request, team_id, event_id):
import re import re
@@ -20,13 +23,28 @@ def gamecard(request, team_id, event_id):
ts_bulkload = client.bulk_load( ts_bulkload = client.bulk_load(
team_id=team_id, team_id=team_id,
types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member], types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member],
event__id=event_id,
) )
ts_event = [ ts_events = [e for e in ts_bulkload if isinstance(e, Event)]
i for i in ts_bulkload if isinstance(i, Event) and i.data["id"] == event_id ts_events.sort(key=lambda d: d.data.get("start_date"))
][0] ts_event = [e for e in ts_events if e.data["id"] == event_id][0]
ts_availabilities = Availability.search(client, event_id=ts_event.data["id"]) ts_events_future = ts_events[ts_events.index(ts_event) + 1 :]
ts_events_past = ts_events[: ts_events.index(ts_event)]
ts_availabilities = Availability.search(client, team_id=team_id)
ts_availabilities_future = list(
filter(
lambda a: a.data["event_id"] in [e.data["id"] for e in ts_events_future],
ts_availabilities,
)
)
ts_availabilities_past = list(
filter(
lambda a: a.data["event_id"] in [e.data["id"] for e in ts_events_past],
ts_availabilities,
)
)
ts_lineup_entries = EventLineupEntry.search(client, event_id=event_id) ts_lineup_entries = EventLineupEntry.search(client, event_id=event_id)
@@ -41,7 +59,7 @@ def gamecard(request, team_id, event_id):
ts_members = [i for i in ts_bulkload if isinstance(i, Member)] ts_members = [i for i in ts_bulkload if isinstance(i, Member)]
# ts_member_lookup = {m.data["id"]: m for m in ts_members} # ts_member_lookup = {m.data["id"]: m for m in ts_members}
ts_availability_lookup = {m.data["member_id"]: m for m in ts_availabilities} ts_availability_lookup = {m.data["id"]: m for m in ts_availabilities}
ts_lineup_entries_lookup = {m.data["member_id"]: m for m in ts_lineup_entries} ts_lineup_entries_lookup = {m.data["member_id"]: m for m in ts_lineup_entries}
members = [] members = []
@@ -52,11 +70,27 @@ def gamecard(request, team_id, event_id):
{ {
"member": getattr(member, "data"), "member": getattr(member, "data"),
"availability": getattr( "availability": getattr(
ts_availability_lookup.get(member.data["id"], {}), "data", {} ts_availability_lookup.get(
f"{member.data['id']}-{event_id}", {}
),
"data",
{},
), ),
"lineup_entry": getattr( "lineup_entry": getattr(
ts_lineup_entries_lookup.get(member.data["id"], {}), "data", {} ts_lineup_entries_lookup.get(member.data["id"], {}), "data", {}
), ),
"availability_future": list(
filter(
lambda a: a.data.get("member_id") == member.data["id"],
ts_availabilities_future,
)
)[:4],
"availability_past": list(
filter(
lambda a: a.data.get("member_id") == member.data["id"],
ts_availabilities_past,
)
)[:4],
} }
) )
@@ -100,10 +134,12 @@ def gamecard(request, team_id, event_id):
context = { context = {
"event": ts_event, "event": ts_event,
"events_future": ts_events_future[:4],
"events_past": list(reversed(ts_events_past))[:4],
"members": members, "members": members,
"members_startinglineup": members_startinglineup, "members_startinglineup": members_startinglineup,
"members_startingpositiononly": members_startingpositiononly, "members_startingpositiononly": members_startingpositiononly,
"ts_team": Team.objects.get(id=team_id), "ts_team": Team.objects.get(id=team_id),
"ts_opponent": Opponent.objects.get(id=ts_event.data["opponent_id"]), "ts_opponent": Opponent.objects.filter(id=ts_event.data["opponent_id"]).first,
} }
return render(request, "gamecard/gamecard.html", context=context) return render(request, "gamecard/gamecard.html", context=context)

View File

@@ -1,7 +1,7 @@
[flake8] [flake8]
max-line-length = 120 max-line-length = 120
exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv
ignore = W503,E203 ignore = W503, E203
[pycodestyle] [pycodestyle]
max-line-length = 120 max-line-length = 120

View File

@@ -8,7 +8,8 @@ from teamsnap.views import get_teamsnap_client
def dashboard(request, team_id=None): def dashboard(request, team_id=None):
if not team_id: if not team_id:
return redirect( return redirect(
"teamsnap_dashboard", team_id=request.user.preferences.managed_team_id "teamsnap_dashboard",
team_id=request.user.teamsnap_preferences.managed_team_id,
) )
from pyteamsnap.api import AvailabilitySummary, Event from pyteamsnap.api import AvailabilitySummary, Event

View File

@@ -1,4 +1,4 @@
# Generated by Django 3.2.13 on 2022-06-10 14:00 # Generated by Django 3.2.13 on 2022-06-09 23:57
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@@ -35,10 +35,7 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('managed_team_id', models.IntegerField()), ('managed_team_id', models.IntegerField()),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='teamsnap_preferences', to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
options={
'verbose_name_plural': 'preferences',
},
), ),
] ]

View File

@@ -1,33 +0,0 @@
# Generated by Django 3.2.13 on 2022-06-09 12:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0003_auto_20220609_0721'),
]
operations = [
migrations.AlterField(
model_name='opponent',
name='logo',
field=models.ImageField(blank=True, null=True, upload_to='logos'),
),
migrations.AlterField(
model_name='opponent',
name='logo_mono',
field=models.ImageField(blank=True, null=True, upload_to='logos_mono'),
),
migrations.AlterField(
model_name='team',
name='logo',
field=models.ImageField(blank=True, null=True, upload_to='logos'),
),
migrations.AlterField(
model_name='team',
name='logo_mono',
field=models.ImageField(blank=True, null=True, upload_to='logos_mono'),
),
]