split gamecard into its own app, add models to teamsnap for custom fields (images)
This commit is contained in:
@@ -272,5 +272,6 @@ SOCIALACCOUNT_FORMS = {"signup": "benchcoach.users.forms.UserSocialSignupForm"}
|
|||||||
|
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
INSTALLED_APPS += ["teamsnap", "instagen"]
|
INSTALLED_APPS += ["teamsnap", "instagen", "gamecard"]
|
||||||
|
|
||||||
SOCIALACCOUNT_PROVIDERS = {"teamsnap": {"SCOPE": ["read", "write"]}}
|
SOCIALACCOUNT_PROVIDERS = {"teamsnap": {"SCOPE": ["read", "write"]}}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ urlpatterns = [
|
|||||||
path("accounts/", include("allauth.urls")),
|
path("accounts/", include("allauth.urls")),
|
||||||
path("", include("teamsnap.urls")),
|
path("", include("teamsnap.urls")),
|
||||||
path("", include("instagen.urls")),
|
path("", include("instagen.urls")),
|
||||||
|
path("", include("gamecard.urls")),
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
0
gamecard/__init__.py
Normal file
0
gamecard/__init__.py
Normal file
6
gamecard/apps.py
Normal file
6
gamecard/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class GamecardConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "gamecard"
|
||||||
0
gamecard/migrations/__init__.py
Normal file
0
gamecard/migrations/__init__.py
Normal file
@@ -169,7 +169,7 @@
|
|||||||
</table>
|
</table>
|
||||||
<div>
|
<div>
|
||||||
<div class="" width="100%">
|
<div class="" width="100%">
|
||||||
<img src="{% static 'teamsnap/ig/logos/hounds.png' %}"
|
<img src="{{ ts_team.logo.url }}"
|
||||||
height="120px"
|
height="120px"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
VS.
|
VS.
|
||||||
</div>
|
</div>
|
||||||
<div class="" width="100%" style="text-align: right">
|
<div class="" width="100%" style="text-align: right">
|
||||||
<img src="{% static 'teamsnap/ig/logos/hounds.png' %}"
|
<img src="{{ ts_opponent.logo.url }}"
|
||||||
width="120px"
|
width="120px"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
3
gamecard/tests.py
Normal file
3
gamecard/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
7
gamecard/urls.py
Normal file
7
gamecard/urls.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import gamecard
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("<int:team_id>/event/<int:event_id>/gamecard/", gamecard, name="gamecard")
|
||||||
|
]
|
||||||
0
gamecard/utils/__init__.py
Normal file
0
gamecard/utils/__init__.py
Normal file
109
gamecard/views.py
Normal file
109
gamecard/views.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from teamsnap.models import Opponent, Team
|
||||||
|
from teamsnap.utils import get_teamsnap_client
|
||||||
|
|
||||||
|
|
||||||
|
def gamecard(request, team_id, event_id):
|
||||||
|
import re
|
||||||
|
|
||||||
|
from pyteamsnap.api import (
|
||||||
|
Availability,
|
||||||
|
AvailabilitySummary,
|
||||||
|
Event,
|
||||||
|
EventLineup,
|
||||||
|
EventLineupEntry,
|
||||||
|
Member,
|
||||||
|
)
|
||||||
|
|
||||||
|
client = get_teamsnap_client(request)
|
||||||
|
ts_bulkload = client.bulk_load(
|
||||||
|
team_id=team_id,
|
||||||
|
types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member],
|
||||||
|
event__id=event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
ts_event = [
|
||||||
|
i for i in ts_bulkload if isinstance(i, Event) and i.data["id"] == event_id
|
||||||
|
][0]
|
||||||
|
ts_availabilities = Availability.search(client, event_id=ts_event.data["id"])
|
||||||
|
|
||||||
|
ts_lineup_entries = EventLineupEntry.search(client, event_id=event_id)
|
||||||
|
|
||||||
|
if ts_lineup_entries:
|
||||||
|
# ts_lineup = EventLineup.get(
|
||||||
|
# client, id=ts_lineup_entries[0].data["event_lineup_id"]
|
||||||
|
# )
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# ts_lineup = EventLineup.search(client, event_id=event_id)
|
||||||
|
pass
|
||||||
|
|
||||||
|
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_availability_lookup = {m.data["member_id"]: m for m in ts_availabilities}
|
||||||
|
ts_lineup_entries_lookup = {m.data["member_id"]: m for m in ts_lineup_entries}
|
||||||
|
|
||||||
|
members = []
|
||||||
|
|
||||||
|
for member in ts_members:
|
||||||
|
if not member.data["is_non_player"]:
|
||||||
|
members.append(
|
||||||
|
{
|
||||||
|
"member": getattr(member, "data"),
|
||||||
|
"availability": getattr(
|
||||||
|
ts_availability_lookup.get(member.data["id"], {}), "data", {}
|
||||||
|
),
|
||||||
|
"lineup_entry": getattr(
|
||||||
|
ts_lineup_entries_lookup.get(member.data["id"], {}), "data", {}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
members = sorted(
|
||||||
|
members,
|
||||||
|
key=lambda d: (
|
||||||
|
{None: 3, 0: 2, 2: 1, 1: 0}.get( # No Response # No # Maybe # Yes
|
||||||
|
d["availability"].get("status_code")
|
||||||
|
),
|
||||||
|
d["member"].get("last_name"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
members_startinglineup = []
|
||||||
|
members_startingpositiononly = []
|
||||||
|
|
||||||
|
for member in members:
|
||||||
|
if re.search(
|
||||||
|
r"([A-Z0-9]+)(?:\s+\[(.*)\])?", member["lineup_entry"].get("label", "")
|
||||||
|
):
|
||||||
|
position, position_note = re.search(
|
||||||
|
r"([A-Z0-9]+)(?:\s+\[(.*)\])?", member["lineup_entry"].get("label", "")
|
||||||
|
).groups()
|
||||||
|
else:
|
||||||
|
position, position_note = ("", "")
|
||||||
|
|
||||||
|
position_only = position_note == "PO"
|
||||||
|
|
||||||
|
if position_only:
|
||||||
|
member["lineup_entry"]["label"] = position
|
||||||
|
|
||||||
|
if member["lineup_entry"].get("id") and not position_only:
|
||||||
|
members_startinglineup.append(member)
|
||||||
|
elif member["lineup_entry"].get("id") and position_only:
|
||||||
|
members_startingpositiononly.append(member)
|
||||||
|
|
||||||
|
members_startinglineup = sorted(
|
||||||
|
members_startinglineup,
|
||||||
|
key=lambda d: d.get("lineup_entry", {}).get("sequence", 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"event": ts_event,
|
||||||
|
"members": members,
|
||||||
|
"members_startinglineup": members_startinglineup,
|
||||||
|
"members_startingpositiononly": members_startingpositiononly,
|
||||||
|
"ts_team": Team.objects.get(id=team_id),
|
||||||
|
"ts_opponent": Opponent.objects.get(id=ts_event.data["opponent_id"]),
|
||||||
|
}
|
||||||
|
return render(request, "gamecard/gamecard.html", context=context)
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Preferences
|
from .models import Opponent, Preferences, Team
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
admin.site.register(Preferences)
|
admin.site.register(Preferences)
|
||||||
|
admin.site.register(Team)
|
||||||
|
admin.site.register(Opponent)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 3.2.13 on 2022-06-02 13:20
|
# Generated by Django 3.2.13 on 2022-06-09 12:09
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -14,6 +14,14 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Team',
|
||||||
|
fields=[
|
||||||
|
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||||
|
('logo', models.ImageField(upload_to='logos')),
|
||||||
|
('logo_mono', models.ImageField(upload_to='logos_mono')),
|
||||||
|
],
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="Preferences",
|
name="Preferences",
|
||||||
fields=[
|
fields=[
|
||||||
|
|||||||
33
teamsnap/migrations/0004_auto_20220609_0722.py
Normal file
33
teamsnap/migrations/0004_auto_20220609_0722.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
teamsnap/migrations/__init__.py
Normal file
0
teamsnap/migrations/__init__.py
Normal file
@@ -7,3 +7,43 @@ from benchcoach.users.models import User
|
|||||||
class Preferences(models.Model):
|
class Preferences(models.Model):
|
||||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
managed_team_id = models.IntegerField()
|
managed_team_id = models.IntegerField()
|
||||||
|
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
logo = models.ImageField(
|
||||||
|
upload_to="logos",
|
||||||
|
height_field=None,
|
||||||
|
width_field=None,
|
||||||
|
max_length=100,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
logo_mono = models.ImageField(
|
||||||
|
upload_to="logos_mono",
|
||||||
|
height_field=None,
|
||||||
|
width_field=None,
|
||||||
|
max_length=100,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Opponent(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
logo = models.ImageField(
|
||||||
|
upload_to="logos",
|
||||||
|
height_field=None,
|
||||||
|
width_field=None,
|
||||||
|
max_length=100,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
logo_mono = models.ImageField(
|
||||||
|
upload_to="logos_mono",
|
||||||
|
height_field=None,
|
||||||
|
width_field=None,
|
||||||
|
max_length=100,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|||||||
@@ -34,7 +34,12 @@
|
|||||||
<h6 class="text-muted mb-2">{{ event.data.location_name }}</h6>
|
<h6 class="text-muted mb-2">{{ event.data.location_name }}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<a class="btn btn-primary btn-sm mx-1" role="button" href="{% url 'teamsnap_edit_lineup' event_ids=event.data.id team_id=event.data.team_id %}">Go to Lineup</a>
|
<a class="btn btn-primary btn-sm mx-1" role="button" href="{% url 'teamsnap_edit_lineup' event_ids=event.data.id team_id=event.data.team_id %}">
|
||||||
|
Go to Lineup
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-primary btn-sm mx-1" role="button" href="{% url 'gamecard' event_id=event.data.id team_id=event.data.team_id %}">
|
||||||
|
<i class="bi bi-book"></i>
|
||||||
|
</a>
|
||||||
<form method="get"
|
<form method="get"
|
||||||
action="{% url 'instagen_generate' team_id=event.data.team_id event_id=event.data.id %}">
|
action="{% url 'instagen_generate' team_id=event.data.team_id event_id=event.data.id %}">
|
||||||
<select hidden class="form-select" name="game_id" id="game_id">
|
<select hidden class="form-select" name="game_id" id="game_id">
|
||||||
@@ -109,40 +114,40 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block inline_javascript %}
|
{% block inline_javascript %}
|
||||||
<script>
|
<script>
|
||||||
function donut(ctx, yes_count, maybe_count, no_count, unknown_count) {
|
function donut(ctx, yes_count, maybe_count, no_count, unknown_count) {
|
||||||
var style = getComputedStyle(document.body);
|
var style = getComputedStyle(document.body);
|
||||||
const myChart = new Chart(ctx, {
|
const myChart = new Chart(ctx, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
responsive: 'true',
|
responsive: 'true',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Availability',
|
label: 'Availability',
|
||||||
labels: [
|
labels: [
|
||||||
'Yes',
|
'Yes',
|
||||||
'Maybe',
|
'Maybe',
|
||||||
'No',
|
'No',
|
||||||
'Unknown'
|
'Unknown'
|
||||||
],
|
],
|
||||||
data: [yes_count, maybe_count, no_count, unknown_count],
|
data: [yes_count, maybe_count, no_count, unknown_count],
|
||||||
backgroundColor: [
|
backgroundColor: [
|
||||||
style.getPropertyValue('--bs-success'),
|
style.getPropertyValue('--bs-success'),
|
||||||
style.getPropertyValue('--bs-info'),
|
style.getPropertyValue('--bs-info'),
|
||||||
style.getPropertyValue('--bs-danger'),
|
style.getPropertyValue('--bs-danger'),
|
||||||
style.getPropertyValue('--bs-secondary')
|
style.getPropertyValue('--bs-secondary')
|
||||||
],
|
],
|
||||||
hoverOffset: 4
|
hoverOffset: 4
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
for (ctx of document.querySelectorAll('.availability-donut')){
|
for (ctx of document.querySelectorAll('.availability-donut')){
|
||||||
donut(ctx,
|
donut(ctx,
|
||||||
ctx.dataset.availableYes,
|
ctx.dataset.availableYes,
|
||||||
ctx.dataset.availableMaybe,
|
ctx.dataset.availableMaybe,
|
||||||
ctx.dataset.availableNo,
|
ctx.dataset.availableNo,
|
||||||
ctx.dataset.availableUnknown,
|
ctx.dataset.availableUnknown,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
14
teamsnap/utils/__init__.py
Normal file
14
teamsnap/utils/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import pyteamsnap
|
||||||
|
|
||||||
|
|
||||||
|
def get_teamsnap_client(request):
|
||||||
|
request.user.socialaccount_set.filter(provider="teamsnap").first()
|
||||||
|
current_teamsnap_user = request.user.socialaccount_set.filter(
|
||||||
|
provider="teamsnap"
|
||||||
|
).first()
|
||||||
|
|
||||||
|
ts_token = (
|
||||||
|
current_teamsnap_user.socialtoken_set.order_by("-expires_at").first().token
|
||||||
|
)
|
||||||
|
|
||||||
|
return pyteamsnap.api.TeamSnap(token=ts_token)
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pyteamsnap.api
|
|
||||||
import requests
|
import requests
|
||||||
from allauth.socialaccount.providers.oauth2.views import (
|
from allauth.socialaccount.providers.oauth2.views import (
|
||||||
OAuth2Adapter,
|
OAuth2Adapter,
|
||||||
@@ -19,6 +18,7 @@ from django.views.generic.edit import FormView
|
|||||||
from .forms import PreferencesForm
|
from .forms import PreferencesForm
|
||||||
from .models import Preferences
|
from .models import Preferences
|
||||||
from .provider import TeamsnapProvider
|
from .provider import TeamsnapProvider
|
||||||
|
from .utils import get_teamsnap_client
|
||||||
|
|
||||||
|
|
||||||
class TeamsnapAdapter(OAuth2Adapter):
|
class TeamsnapAdapter(OAuth2Adapter):
|
||||||
@@ -53,19 +53,6 @@ oauth2_login = OAuth2LoginView.adapter_view(TeamsnapAdapter)
|
|||||||
oauth2_callback = OAuth2CallbackView.adapter_view(TeamsnapAdapter)
|
oauth2_callback = OAuth2CallbackView.adapter_view(TeamsnapAdapter)
|
||||||
|
|
||||||
|
|
||||||
def get_teamsnap_client(request):
|
|
||||||
request.user.socialaccount_set.filter(provider="teamsnap").first()
|
|
||||||
current_teamsnap_user = request.user.socialaccount_set.filter(
|
|
||||||
provider="teamsnap"
|
|
||||||
).first()
|
|
||||||
|
|
||||||
ts_token = (
|
|
||||||
current_teamsnap_user.socialtoken_set.order_by("-expires_at").first().token
|
|
||||||
)
|
|
||||||
|
|
||||||
return pyteamsnap.api.TeamSnap(token=ts_token)
|
|
||||||
|
|
||||||
|
|
||||||
class PreferencesFormView(FormView):
|
class PreferencesFormView(FormView):
|
||||||
template_name = "preferences.html"
|
template_name = "preferences.html"
|
||||||
form_class = PreferencesForm
|
form_class = PreferencesForm
|
||||||
@@ -432,8 +419,7 @@ def submit_lineup(request, team_id, event_id):
|
|||||||
try:
|
try:
|
||||||
r.append(event_lineup_entry.put())
|
r.append(event_lineup_entry.put())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
e
|
raise e
|
||||||
pass
|
|
||||||
pass
|
pass
|
||||||
elif data.get("sequence") is not None and data.get("label"):
|
elif data.get("sequence") is not None and data.get("label"):
|
||||||
event_lineup_entry = EventLineupEntry.new(client)
|
event_lineup_entry = EventLineupEntry.new(client)
|
||||||
|
|||||||
Reference in New Issue
Block a user