implement lineup send to gamechanger

This commit is contained in:
2022-06-08 14:08:33 -05:00
parent 50c9b70546
commit f788fb9932
21 changed files with 409 additions and 82 deletions

View File

@@ -32,3 +32,9 @@
vertical-align: middle; vertical-align: middle;
white-space: nowrap; white-space: nowrap;
} }
.btn-gamechanger {
color: #fff;
border-color: #1b73bc;
background-color: #1b73bc;
}

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 741.9 69.6" style="enable-background:new 0 0 741.9 69.6;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st1{filter:url(#Adobe_OpacityMaskFilter);}
.st2{mask:url(#mask-2_00000067194953457310049560000009970419005216943005_);fill-rule:evenodd;clip-rule:evenodd;fill:#00F092;}
</style>
<g id="Logo-Presentation">
<g id="Slide-1-Copy-23" transform="translate(-194.000000, -546.000000)">
<g id="Group-10" transform="translate(194.000000, 546.500000)">
<path id="Fill-1" class="st0" d="M497.6,38.9h-9.4l7.9-15l8,15H497.6z M492.2,15.6l-19.8,37.5h8.3l3.6-6.7h23.8l3.6,6.7h8.3
l-19.9-37.5H492.2L492.2,15.6z"/>
<polyline id="Fill-2" class="st0" points="557.8,42.2 557.7,42.1 533.8,15.6 525.3,15.6 525.3,53.1 532.7,53.1 532.7,25.1
532.8,25.2 557.9,53.1 565.2,53.1 565.2,15.6 557.8,15.6 557.8,42.2 "/>
<path id="Fill-3" class="st0" d="M702.5,33.6h-18.7V23h18.7c1.4,0,2.7,0.6,3.7,1.6l0,0c1,1,1.5,2.3,1.5,3.7s-0.5,2.7-1.5,3.7
C705.2,33.1,703.9,33.6,702.5,33.6z M706.9,40.3l0.5-0.2c2.3-1,4.2-2.6,5.5-4.6c1.4-2.1,2.2-4.6,2.2-7.1c0-3.4-1.3-6.6-3.7-9
c-2.4-2.5-5.5-3.8-8.9-3.8h-26v37.5h7.3V41h13.9l0,0l10.5,12.1h9.8L706.9,40.3L706.9,40.3z"/>
<polyline id="Fill-4" class="st0" points="459.8,30.6 434.9,30.6 434.9,15.6 427.5,15.6 427.5,53.1 434.9,53.1 434.9,38.1
459.8,38.1 459.8,53.1 467.1,53.1 467.1,15.6 459.8,15.6 459.8,30.6 "/>
<polyline id="Fill-5" class="st0" points="318.6,15.6 315.1,15.6 303.2,42.8 291.2,15.6 287.7,15.6 287.7,15.6 280.7,15.6
280.7,53.1 288.2,53.1 288.2,25.7 300.2,53.1 306.1,53.1 318.2,25.6 318.2,53.1 325.6,53.1 325.6,15.6 318.6,15.6 318.6,15.6
"/>
<g id="Group-9" transform="translate(0.000000, 0.008595)">
<g id="Clip-7">
</g>
<path id="Fill-6" class="st0" d="M252.6,38.9L252.6,38.9h-9.4l7.9-15l8,15H252.6z M247.2,15.6l-19.8,37.5h8.3l3.6-6.7h23.8
l3.6,6.7h8.3l-19.9-37.5H247.2L247.2,15.6z"/>
<path id="Fill-8" class="st0" d="M199.2,36.9v0.4H218v0.1c-1.4,4.8-5.8,8.2-10.8,8.2h-10c-6.1,0-11.1-5-11.2-11.1
c-0.1-3,1.1-5.9,3.2-8c2.2-2.2,5.2-3.5,8.2-3.5h9.1c4,0,7.3-3,7.8-7v-0.4h-17.2c-5,0-9.7,2-13.3,5.6c-3.5,3.6-5.4,8.4-5.3,13.4
c0.2,10.2,8.6,18.5,18.9,18.5h9.5h0.1c10.1-0.1,18.5-8.4,18.7-18.5c0-0.1,0-0.2,0-0.2c0-0.1,0-0.1,0-0.2v-0.1l0,0v-4.2H207
C203,29.9,199.6,32.9,199.2,36.9"/>
</g>
<path id="Fill-10" class="st0" d="M594.4,36.9v0.4h18.8v0.1c-1.4,4.8-5.8,8.2-10.8,8.2h-10c-6.1,0-11.1-5-11.2-11.1
c-0.1-3,1.1-5.9,3.2-8c2.2-2.2,5.2-3.5,8.2-3.5h9.1c4,0,7.3-3,7.8-7v-0.4h-17.1c-5,0-9.7,2-13.3,5.6c-3.5,3.6-5.4,8.4-5.4,13.4
c0.2,10.2,8.6,18.5,18.9,18.5h9.5h0.1c10.2-0.1,18.6-8.4,18.7-18.4c0-0.1,0-0.2,0-0.2c0-0.1,0-0.1,0-0.2v-0.1l0,0V30h-18.7
C598.1,30,594.8,33,594.4,36.9"/>
<path id="Fill-11" class="st0" d="M398,23h13.7c4,0,7.3-3,7.8-7v-0.4H398c-5,0-9.7,2-13.3,5.6c-3.5,3.6-5.4,8.4-5.4,13.4
c0.2,10.2,8.6,18.5,18.9,18.5h13.4c4,0,7.3-3,7.8-7v-0.4h-21.3c-3.1,0-6.1-1.3-8.2-3.5s-3.3-5-3.2-8C386.9,28,391.9,23,398,23"/>
<path id="Fill-12" class="st0" d="M367.1,23c4,0,7.3-3,7.7-7v-0.4h-38.6v37.5h30.9c4,0,7.3-3,7.7-7v-0.4h-31.3v-7.6h14
c3.8,0,7-3.1,7-7v-0.5h-20.9V23H367.1"/>
<path id="Fill-13" class="st0" d="M660.4,23c4,0,7.3-3,7.7-7v-0.4h-38.6v37.5h30.9c4,0,7.3-3,7.7-7v-0.4h-31.3v-7.6h13.9
c3.8,0,7-3.1,7-7v-0.5h-20.9V23H660.4"/>
<polyline id="Fill-14" class="st0" points="728.9,53.1 727.5,53.1 727.5,45.6 724.9,45.6 724.9,44.3 731.4,44.3 731.4,45.6
728.9,45.6 728.9,53.1 "/>
<path id="Fill-15" class="st0" d="M736.8,53.1l-2.5-7.2l0,0c0,1.1,0.1,2.1,0.1,3.1v4.2h-1.2v-8.7h1.9l2.4,6.9l0,0l2.5-6.9h1.9
v8.7h-1.4v-4.3c0-0.4,0-1,0-1.7s0-1.1,0-1.2l0,0l-2.6,7.2H736.8"/>
</g>
</g>
</g>
<g id="Logo-Presentation_00000113341718855537428600000001450668188223146168_">
<g id="Slide-1-Copy-23_00000093891632931889047450000011681990669367062677_" transform="translate(-551.000000, -849.000000)">
<g id="DSG_GameChanger_Logomark-Copy-7" transform="translate(551.000000, 849.000000)">
<g id="Clip-2">
</g>
<defs>
<filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="142.9" height="69.6">
<feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/>
</filter>
</defs>
<mask maskUnits="userSpaceOnUse" x="0" y="0" width="142.9" height="69.6" id="mask-2_00000067194953457310049560000009970419005216943005_">
<g class="st1">
<polygon id="path-1_00000010310054758688279420000011862642130963442847_" class="st0" points="0,0 142.9,0 142.9,69.6 0,69.6
"/>
</g>
</mask>
<path id="Fill-1_00000052789438335131278620000014152493238395228080_" class="st2" d="M104.9,55.5c-2.9,0-5.8-0.7-8.4-1.9
c-2.5-1.2-4.8-3-6.7-5.2c-1.8-2.2-3.2-4.8-4-7.5c-0.8-2.9-1-6-0.6-9c1.2-8.3,7.4-15.2,15.5-17.2c0.5-0.1,3.2-0.6,6.7-0.6l22.4,0
c0.1,0,3.1,0,5.8-1.3c4.4-2.5,7.2-7.3,7.2-12.4V0h-38C89,0,75.3,10.9,71.5,26.5c0,0.1,0,0.1,0,0.2l0,0.1H50.7
c-7.5,0-13.7,6-14,13.6l0,0.5h33l0,0c0,0.2-0.1,0.5-0.2,0.8c-2.3,6.8-8.1,12.1-15.1,13.9c0,0-2.9,0.7-6.8,0.6H37
c-3.6,0-6.2-0.5-6.7-0.6c-9.1-2.3-15.6-10.4-15.7-19.8c0-1.1,0-2.4,0.2-3.7c1.2-8.3,7.4-15.3,15.5-17.3c0.5-0.1,3.2-0.6,6.7-0.6
l11.4,0c0.2,0,4,0,7-1.9c3.9-2.7,6.2-7.1,6.2-11.8V0H34.4C15.7,0,0.3,15.3,0,34.2c-0.2,9.2,3.3,18,9.9,24.7
c6.6,6.8,15.8,10.7,25.1,10.7h15.7c10.6,0,20.7-5.1,27.2-13.6c6.7,8.5,16.9,13.6,27.6,13.6h23.4c7.5,0,13.7-6,14-13.6l0-0.5
H104.9"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -85,6 +85,9 @@
<li class="dropdown-item"> <li class="dropdown-item">
<a class="nav-link" href="{% url 'gamechanger_preferences' %}">{% translate "GameChanger Preferences" %}</a> <a class="nav-link" href="{% url 'gamechanger_preferences' %}">{% translate "GameChanger Preferences" %}</a>
</li> </li>
<li class="dropdown-item">
<a class="nav-link" href="{% url 'gamechanger_import_roster' %}">{% translate "GameChanger Import Roster" %}</a>
</li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li class="dropdown-item"> <li class="dropdown-item">
<a class="nav-link" href="{% url 'account_logout' %}">{% translate "Sign Out" %}</a> <a class="nav-link" href="{% url 'account_logout' %}">{% translate "Sign Out" %}</a>

View File

@@ -272,5 +272,5 @@ SOCIALACCOUNT_FORMS = {"signup": "benchcoach.users.forms.UserSocialSignupForm"}
# Your stuff... # Your stuff...
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
INSTALLED_APPS += ["teamsnap", "instagen"] INSTALLED_APPS += ["teamsnap", "instagen", "gamechanger"]
SOCIALACCOUNT_PROVIDERS = {"teamsnap": {"SCOPE": ["read", "write"]}} SOCIALACCOUNT_PROVIDERS = {"teamsnap": {"SCOPE": ["read", "write"]}}

View File

@@ -1,6 +1,8 @@
from django.contrib import admin from django.contrib import admin
from .models import Account, Preferences
from .models import Account, Player, Preferences
# Register your models here. # Register your models here.
admin.site.register(Account) admin.site.register(Account)
admin.site.register(Preferences) admin.site.register(Preferences)
admin.site.register(Player)

View File

@@ -1,7 +1,8 @@
from django import forms from django import forms
from django.forms import ModelForm, formset_factory from django.forms import ModelForm, formset_factory
from .models import Preferences, Account, Player from .models import Account, Player, Preferences
class PreferencesForm(ModelForm): class PreferencesForm(ModelForm):
class Meta: class Meta:
@@ -13,6 +14,7 @@ class PreferencesForm(ModelForm):
} }
labels = {"managed_team_id": "Selected Team"} labels = {"managed_team_id": "Selected Team"}
class AccountForm(ModelForm): class AccountForm(ModelForm):
class Meta: class Meta:
model = Account model = Account
@@ -20,16 +22,24 @@ class AccountForm(ModelForm):
widgets = { widgets = {
"user": forms.HiddenInput(), "user": forms.HiddenInput(),
"email": forms.EmailInput(), "email": forms.EmailInput(),
"password": forms.PasswordInput() "password": forms.PasswordInput(),
} }
class PlayerForm(ModelForm): class PlayerForm(ModelForm):
gamechanger_name = forms.Field() gamechanger_name = forms.Field()
teamsnap_name = forms.Field() teamsnap_name = forms.Field()
gamechanger_id = forms.Field() fname = forms.Field()
lname = forms.Field()
class Meta: class Meta:
model = Player model = Player
fields = ['id', 'teamsnap_member_id'] fields = ["id", "teamsnap_member_id"]
widgets = {
"teamsnap_member_id": forms.Select(
choices=(), attrs={"class": "form-control"}
),
}
PlayerFormSet = formset_factory(PlayerForm, can_delete=True, extra=0) PlayerFormSet = formset_factory(PlayerForm, can_delete=True, extra=0)

View File

@@ -0,0 +1,22 @@
# Generated by Django 3.2.13 on 2022-06-08 12:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gamechanger', '0002_auto_20220607_1259'),
]
operations = [
migrations.CreateModel(
name='Player',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('teamsnap_member_id', models.IntegerField()),
('fname', models.CharField(max_length=30)),
('lname', models.CharField(max_length=30)),
],
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.13 on 2022-06-08 12:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gamechanger', '0003_player'),
]
operations = [
migrations.AlterField(
model_name='player',
name='id',
field=models.CharField(max_length=30, primary_key=True, serialize=False),
),
]

View File

@@ -1,20 +1,36 @@
from django import forms
from django.db import models from django.db import models
from django.db.models import CharField, EmailField from django.db.models import CharField, EmailField
from benchcoach.users.models import User from benchcoach.users.models import User
# Create your models here. # Create your models here.
class Account(models.Model): class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="gamechanger_account") user = models.OneToOneField(
User, on_delete=models.CASCADE, related_name="gamechanger_account"
)
email = EmailField() email = EmailField()
password = CharField(max_length=255) password = CharField(max_length=255)
class Preferences(models.Model): class Preferences(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="gamechanger_preferences") user = models.OneToOneField(
User, on_delete=models.CASCADE, related_name="gamechanger_preferences"
)
season_id = CharField(max_length=255) season_id = CharField(max_length=255)
team_id = CharField(max_length=255) team_id = CharField(max_length=255)
class Meta:
verbose_name_plural = "preferences"
class Player(models.Model): class Player(models.Model):
id = models.AutoField(primary_key=True) id = models.CharField(primary_key=True, max_length=30)
teamsnap_member_id = models.IntegerField() teamsnap_member_id = models.IntegerField()
fname = CharField(max_length=30) fname = CharField(max_length=30)
lname = CharField(max_length=30) lname = CharField(max_length=30)
widgets = {
"teamsnap_member_id": forms.Select(choices=(), attrs={"class": "form-control"}),
}

View File

@@ -5,7 +5,7 @@
{# {{ player.fname }} {{ player.lname }}#} {# {{ player.fname }} {{ player.lname }}#}
{# </li>#} {# </li>#}
{# {% endfor %}#} {# {% endfor %}#}
<form method="post" action='{% url 'gamechanger_save' %}' > <form method="post" action='{% url 'gamechanger_import_roster' %}' >
{{ formset.management_form }} {{ formset.management_form }}
{% csrf_token %} {% csrf_token %}
<table> <table>
@@ -23,16 +23,20 @@
{% for form in formset %} {% for form in formset %}
<tr> <tr>
<td> <td>
{{ form.gamechanger_name }} {{ form.gamechanger_name.value }}
</td> </td>
<td> <td>
{{ form.teamsnap_name }} {{ form.teamsnap_member_id }}
</td> </td>
<td> <td>
{{ form.DELETE }} {{ form.DELETE }}
</td> </td>
{{ form.gamechanger_id.as_hidden }} {{ form.gamechanger_name.as_hidden }}
{{ form.teamsnap_name.as_hidden }}
{{ form.id.as_hidden }}
{{ form.teamsnap_member_id.as_hidden }} {{ form.teamsnap_member_id.as_hidden }}
{{ form.fname.as_hidden }}
{{ form.lname.as_hidden }}
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@@ -1,16 +1,10 @@
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
from django.urls import path from django.urls import path
from .views import ( from .views import AccountFormView, PreferencesFormView, lineup_submit, roster_import
PreferencesFormView,
AccountFormView,
roster_view,
roster_save
)
urlpatterns = [ urlpatterns = [
path("account/", AccountFormView.as_view(), name="gamechanger_account"), path("account/", AccountFormView.as_view(), name="gamechanger_account"),
path("preferences/", PreferencesFormView.as_view(), name="gamechanger_preferences"), path("preferences/", PreferencesFormView.as_view(), name="gamechanger_preferences"),
path("roster/", roster_view, name="gamechanger_roster"), path("roster/import", roster_import, name="gamechanger_import_roster"),
path("roster/save", roster_save, name="gamechanger_save"), path("lineup/submit", lineup_submit, name="gamechanger_lineup_submit"),
] ]

View File

@@ -1,15 +1,70 @@
import requests
import re
import json import json
import re
import requests
url = "https://gc.com/t/{season_id}/{team_id}/{page}" url = "https://gc.com/t/{season_id}/{team_id}/{page}"
def get_authenticated_session(request):
gc_username = request.user.gamechanger_account.user
gc_password = request.user.gamechanger_account.password
s = requests.Session()
s.headers.update({"referer": "https://gc.com/do-login"})
s.get("https://gc.com/login")
r2 = s.post(
"https://gc.com/do-login",
cookies=s.cookies,
data={
"csrfmiddlewaretoken": s.cookies.get("csrftoken"),
"email": gc_username,
"password": gc_password,
},
)
if r2.status_code == 200:
return s
else:
raise requests.exceptions.RequestException(
f"Returned {r2.status_code} for {r2.reason}"
)
def submit_lineup(request, lineup):
authenticated_session = get_authenticated_session(request)
season_id = request.user.gamechanger_preferences.season_id
team_id = request.user.gamechanger_preferences.team_id
authenticated_session.headers.update(
{
"referer": url.format(
season_id=season_id, team_id=team_id, page="lineup_edit"
),
"x-csrftoken": authenticated_session.cookies.get("csrftoken"),
"Content-Type": "application/x-www-form-urlencoded;",
}
)
r = authenticated_session.post(
cookies=authenticated_session.cookies,
url="https://gc.com/do-save-lineup/{team_id}".format(
team_id=team_id.split("-").pop()
),
json={"lineup": lineup},
)
if r.status_code == 200:
return r
else:
raise requests.exceptions.RequestException(
f"Returned {r.status_code} for {r.reason}"
)
def scrape_page(season_id, team_id, page): def scrape_page(season_id, team_id, page):
r = requests.get(url.format(season_id=season_id, team_id=team_id, page=page)) r = requests.get(url.format(season_id=season_id, team_id=team_id, page=page))
j=initialize_page_json = re.search(r'page.initialize\(\$.parseJSON\("(.*?)"\)', r.content.decode('unicode_escape')) initialize_page_json = re.search(
m=j.group(1) r'page.initialize\(\$.parseJSON\("(.*?)"\)', r.content.decode("unicode_escape")
)
m = initialize_page_json.group(1)
return json.loads(m) return json.loads(m)
# d = scrape_page(season_id, team_id, page) # d = scrape_page(season_id, team_id, page)
pass pass

View File

@@ -1,11 +1,14 @@
from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseServerError
from django.shortcuts import render from django.shortcuts import render
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.views.generic.list import ListView
from .forms import PreferencesForm, AccountForm, PlayerFormSet
from .utils.gamechanger import scrape_page
from teamsnap.views import get_teamsnap_client from teamsnap.views import get_teamsnap_client
# Create your views here. from .forms import AccountForm, PlayerFormSet, PreferencesForm
from .models import Player
from .utils import gamechanger
class PreferencesFormView(FormView): class PreferencesFormView(FormView):
template_name = "gamechanger/form.html" template_name = "gamechanger/form.html"
form_class = PreferencesForm form_class = PreferencesForm
@@ -29,6 +32,7 @@ class PreferencesFormView(FormView):
return initial return initial
class AccountFormView(FormView): class AccountFormView(FormView):
template_name = "gamechanger/form.html" template_name = "gamechanger/form.html"
form_class = AccountForm form_class = AccountForm
@@ -52,12 +56,15 @@ class AccountFormView(FormView):
return initial return initial
def roster_view(request):
def roster_import(request):
if request.method == "GET":
from pyteamsnap.api import Member from pyteamsnap.api import Member
client = get_teamsnap_client(request) client = get_teamsnap_client(request)
season_id = request.user.gamechanger_preferences.season_id season_id = request.user.gamechanger_preferences.season_id
team_id = request.user.gamechanger_preferences.team_id team_id = request.user.gamechanger_preferences.team_id
teamsnap_team_id = request.user.preferences.managed_team_id teamsnap_team_id = request.user.teamsnap_preferences.managed_team_id
teamsnap_members = { teamsnap_members = {
f"{member.data['first_name']} {member.data['last_name']}": member f"{member.data['first_name']} {member.data['last_name']}": member
for member in Member.search(client, team_id=teamsnap_team_id) for member in Member.search(client, team_id=teamsnap_team_id)
@@ -65,17 +72,103 @@ def roster_view(request):
page = "roster" page = "roster"
d = scrape_page(season_id, team_id, page) d = gamechanger.scrape_page(season_id, team_id, page)
roster = d['roster'] roster = d["roster"]
initial = [{ initial = [
'gamechanger_name':f"{player['fname']} {player['lname']}", {
'teamsnap_name':"{first_name} {last_name}".format(**teamsnap_members[f"{player['fname']} {player['lname']}"].data), "gamechanger_name": f"{player['fname']} {player['lname']}",
'gamechanger_id':player.get('player_id'), "fname": player["fname"],
'teamsnap_member_id':teamsnap_members[f"{player['fname']} {player['lname']}"].data['id'], "lname": player["lname"],
} for player in roster] "teamsnap_name": "{first_name} {last_name}".format(
**teamsnap_members[f"{player['fname']} {player['lname']}"].data
),
"id": player.get("player_id"),
"teamsnap_member_id": teamsnap_members[
f"{player['fname']} {player['lname']}"
].data["id"],
}
for player in roster
]
formset = PlayerFormSet(initial=initial) formset = PlayerFormSet(initial=initial)
return render(request, "gamechanger/roster.html", context={'roster':roster, 'formset':formset}) choices = [
(
teamsnap_member.data["id"],
f"{teamsnap_member.data['first_name']} {teamsnap_member.data['last_name']}",
)
for teamsnap_member in teamsnap_members.values()
]
for form in formset:
form.fields["teamsnap_member_id"].widget.choices = choices
pass pass
return render(
request,
"gamechanger/roster.html",
context={"roster": roster, "formset": formset},
)
elif request.POST:
formset = PlayerFormSet(request.POST)
if formset.is_valid():
r = []
for form in formset:
data = form.cleaned_data
data.pop("DELETE")
data.pop("gamechanger_name")
data.pop("teamsnap_name")
obj, did_create = Player.objects.update_or_create(**data)
obj.save()
r.append(obj)
return HttpResponse(status=200)
else:
return HttpResponseServerError()
def roster_save(request): return HttpResponseServerError()
pass else:
return HttpResponseServerError()
def lineup_submit(request):
from teamsnap.forms import LineupEntryFormset
if request.GET:
return HttpResponseNotAllowed()
if request.POST:
formset = LineupEntryFormset(request.POST)
if formset.is_valid():
lineup_data = [
form.cleaned_data
for form in formset
if form.cleaned_data.get("label")
and form.cleaned_data.get("sequence") is not None
]
lineup_data.sort(key=lambda x: x.get("sequence"))
lineup = []
for lineup_entry in lineup_data:
d = {
"player_id": lineup_entry["gamechanger_player_id"],
"position": lineup_entry["label"],
}
if lineup_entry["label"] == "DH":
for_whom = [
e
for e in lineup_data
if e["position_only"] and e["label"] != "DR"
][0]
d["forwhom"] = for_whom["gamechanger_player_id"]
lineup.append(d)
if for_whom in lineup:
lineup_data.remove(for_whom)
if for_whom in lineup_data:
lineup_data.remove(for_whom)
lineup.append(
{
"player_id": for_whom["gamechanger_player_id"],
"position": for_whom["label"],
}
)
elif lineup_entry["label"] != "DR":
lineup.append(d)
gamechanger.submit_lineup(request, lineup)
return HttpResponse(status=200)
return HttpResponseServerError()

View File

@@ -21,6 +21,7 @@ class LineupEntryForm(forms.Form):
member = None member = None
availability = None availability = None
lineup_entry = None lineup_entry = None
gamechanger_player_id = forms.Field(required=False)
event_lineup_entry_id = forms.Field(required=False) event_lineup_entry_id = forms.Field(required=False)
event_lineup_id = forms.Field(required=False) event_lineup_id = forms.Field(required=False)

View File

@@ -31,6 +31,7 @@ class Migration(migrations.Migration):
"user", "user",
models.OneToOneField( models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name='teamsnap_preferences',
to=settings.AUTH_USER_MODEL, to=settings.AUTH_USER_MODEL,
), ),
), ),

View File

View File

@@ -5,5 +5,10 @@ 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, related_name="teamsnap_preferences"
)
managed_team_id = models.IntegerField() managed_team_id = models.IntegerField()
class Meta:
verbose_name_plural = "preferences"

View File

@@ -25,7 +25,6 @@
<tbody> <tbody>
<tr class="align-top mx-1"> <tr class="align-top mx-1">
{% for event_data in contexts %} {% for event_data in contexts %}
<td class="px-1"> <td class="px-1">
{% include "lineup/widgets/lineup.html" with event=event_data.event event_id=event_data.event.data.id formset=event_data.formset formset_startinglineup=event_data.formset_startinglineup formset_bench=event_data.formset_bench formset_out=event_data.formset_out formset_startingpositionalonly=event_data.formset_startingpositionalonly %} {% include "lineup/widgets/lineup.html" with event=event_data.event event_id=event_data.event.data.id formset=event_data.formset formset_startinglineup=event_data.formset_startinglineup formset_bench=event_data.formset_bench formset_out=event_data.formset_out formset_startingpositionalonly=event_data.formset_startingpositionalonly %}
</td> </td>
@@ -41,25 +40,24 @@
{% block inline_javascript %} {% block inline_javascript %}
{{ block.super }} {{ block.super }}
<script src="{% static 'js/Sortable.js' %}"></script> <script src="{% static 'js/Sortable.js' %}"></script>
<script src="{% static 'js/lineup-table.js' %}"></script>
<script> <script>
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', () => {
/* Run whatever you want */ /* Run whatever you want */
const postForms = document.querySelectorAll("[id^=form-lineup]"); const postForms = document.querySelectorAll("[id^=form-lineup]");
for (postForm of postForms) { const postSubmits = document.querySelectorAll("[id^=submit-lineup]");
function handleSubmit(postForm) { for (postSubmit of postSubmits) {
postForm.addEventListener("submit", e => { function handleSubmit(postSubmit) {
postSubmit.addEventListener("click", e => {
e.preventDefault(); e.preventDefault();
formData = new FormData(postForm); formData = new FormData(postSubmit.form);
fetch(postForm.action, { fetch(postSubmit.formAction, {
method: 'POST', method: 'POST',
body: formData, body: formData,
}) })
.then(response => response.json()) .then(response => response)
.then(data => { .then(data => {
{#postForm.reset();#}
document.querySelector("#popup-messages-content").innerHTML = `<div class="alert alert-dismissible alert-success" role="alert"> document.querySelector("#popup-messages-content").innerHTML = `<div class="alert alert-dismissible alert-success" role="alert">
<strong>Success!</strong> ${data.formatted_title} <strong>saved</strong>. <strong>Success!</strong>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div> ` </div> `
}) })
@@ -69,7 +67,7 @@
}) })
} }
handleSubmit(postForm) handleSubmit(postSubmit)
} }
}); });
</script> </script>

View File

@@ -1,6 +1,6 @@
{% load static %} {% load static %}
<div class="card mx-auto benchcoach-lineup" style="max-width: 455px" id="benchcoach-lineup-{{ event_id }}"> <div class="card mx-auto benchcoach-lineup" style="max-width: 455px" id="benchcoach-lineup-{{ event_id }}">
<form method="post" action='{% url 'teamsnap_submit_lineup' team_id=event.data.team_id event_id=event.data.id %}' id="form-lineup-{{ event.data.id }}"> <form method="post" id="form-lineup-{{ event.data.id }}">
{{ formset.management_form }} {{ formset.management_form }}
{% csrf_token %} {% csrf_token %}
<div class="border-bottom p-2"> <div class="border-bottom p-2">
@@ -34,11 +34,17 @@
</ul> </ul>
</div> </div>
<div> <div>
<button class="btn btn-teamsnap btn-sm py-0 m-1" type="submit"> <button type="Submit" class="btn btn-teamsnap btn-sm py-0 m-1" formaction="{% url 'teamsnap_submit_lineup' team_id=event.data.team_id event_id=event.data.id %}" form="form-lineup-{{ event.data.id }}" id="submit-lineup-gamechanger-{{ event.data.id }}">
<i class="bi bi-arrow-right"></i> <i class="bi bi-arrow-right"></i>
TeamSnap TeamSnap
</button> </button>
</div> </div>
<div>
<button type="Submit" class="btn btn-gamechanger btn-sm py-0 m-1 text-nowrap" formaction="{% url 'gamechanger_lineup_submit' %}" form="form-lineup-{{ event.data.id }}" id="submit-lineup-gamechanger-{{ event.data.id }}">
<i class="bi bi-arrow-right"></i>
GameChanger
</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -8,6 +8,7 @@
data-player-name="{{ form.member.data.last_name }}, {{ form.member.data.first_name }}" data-player-name="{{ form.member.data.last_name }}, {{ form.member.data.first_name }}"
data-availability-statuscode="{{ form.availability.data.status_code }}" data-availability-statuscode="{{ form.availability.data.status_code }}"
> >
{{ form.gamechanger_player_id.as_hidden }}
{{ form.event_lineup_entry_id.as_hidden }} {{ form.event_lineup_entry_id.as_hidden }}
{{ form.event_lineup_id.as_hidden }} {{ form.event_lineup_id.as_hidden }}
{{ form.event_id.as_hidden }} {{ form.event_id.as_hidden }}

View File

@@ -7,10 +7,12 @@ from allauth.socialaccount.providers.oauth2.views import (
OAuth2CallbackView, OAuth2CallbackView,
OAuth2LoginView, OAuth2LoginView,
) )
from django.http import HttpResponseNotAllowed, HttpResponseServerError, JsonResponse from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseServerError
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from gamechanger.models import Player as GamechangerPlayer
from .forms import PreferencesForm from .forms import PreferencesForm
from .models import Preferences from .models import Preferences
from .provider import TeamsnapProvider from .provider import TeamsnapProvider
@@ -120,7 +122,8 @@ class PreferencesFormView(FormView):
def schedule_view(request, team_id=None): def schedule_view(request, team_id=None):
if not team_id: if not team_id:
return redirect( return redirect(
"teamsnap_schedule", team_id=request.user.preferences.managed_team_id "teamsnap_schedule",
team_id=request.user.teamsnap_preferences.managed_team_id,
) )
client = get_teamsnap_client(request) client = get_teamsnap_client(request)
no_past = bool(request.GET.get("no_past", 0)) no_past = bool(request.GET.get("no_past", 0))
@@ -149,7 +152,7 @@ def schedule_view(request, team_id=None):
def view_event(request, event_id, team_id=None): def view_event(request, event_id, team_id=None):
if not team_id: if not team_id:
return redirect( return redirect(
"teamsnap_event", team_id=request.user.preferences.managed_team_id "teamsnap_event", team_id=request.user.teamsnap_preferences.managed_team_id
) )
from pyteamsnap.api import ( from pyteamsnap.api import (
@@ -225,6 +228,16 @@ def edit_lineup(request, event_ids, team_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}
gc_player_lookup = {
m.data["id"]: getattr(
GamechangerPlayer.objects.filter(
teamsnap_member_id=m.data["id"]
).first(),
"id",
None,
)
for m in ts_members
}
ts_availability_lookup = {m.data["member_id"]: m for m in ts_availabilities} 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} ts_lineup_entries_lookup = {m.data["member_id"]: m for m in ts_lineup_entries}
@@ -300,6 +313,9 @@ def edit_lineup(request, event_ids, team_id):
"member_id": member["member"]["id"], "member_id": member["member"]["id"],
"sequence": member["lineup_entry"].get("sequence"), "sequence": member["lineup_entry"].get("sequence"),
"label": position, "label": position,
"gamechanger_player_id": gc_player_lookup.get(
member["member"]["id"]
),
} }
) )
@@ -360,7 +376,8 @@ def edit_lineup(request, event_ids, team_id):
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
@@ -395,12 +412,11 @@ def dashboard(request, team_id=None):
def submit_lineup(request, team_id, event_id): def submit_lineup(request, team_id, event_id):
from pyteamsnap.api import Event, EventLineup, EventLineupEntry from pyteamsnap.api import EventLineup, EventLineupEntry
from teamsnap.forms import LineupEntryFormset from teamsnap.forms import LineupEntryFormset
client = get_teamsnap_client(request) client = get_teamsnap_client(request)
ts_event = Event.get(client, event_id)
ts_lineup = EventLineup.search(client, event_id=event_id) ts_lineup = EventLineup.search(client, event_id=event_id)
event_lineup_id = ts_lineup[0].data["id"] event_lineup_id = ts_lineup[0].data["id"]
if request.GET: if request.GET:
@@ -443,10 +459,6 @@ def submit_lineup(request, team_id, event_id):
else: else:
pass pass
else: else:
# breakpoint()
pass pass
# breakpoint() return HttpResponse(status=200)
pass return HttpResponseServerError()
return JsonResponse(ts_event.data)
pass
return HttpResponseServerError