gamechanger updates (added events, teams). not used yet.

update requirements
This commit is contained in:
2022-06-20 09:35:59 -05:00
parent c0c857a765
commit e027d3d6ae
12 changed files with 229 additions and 34 deletions

View File

@@ -1,8 +1,9 @@
from django.contrib import admin from django.contrib import admin
from .models import Account, Player, Preferences from .models import Account, Player, Preferences, Team
# 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) admin.site.register(Player)
admin.site.register(Team)

View File

@@ -5,14 +5,14 @@ from .models import Account, Player, Preferences
class PreferencesForm(ModelForm): class PreferencesForm(ModelForm):
season_id = ""
class Meta: class Meta:
model = Preferences model = Preferences
fields = ["user", "season_id", "team_id"] fields = ["user", "managed_team"]
widgets = { widgets = {
"user": forms.HiddenInput(), "user": forms.HiddenInput(),
"managed_team_id": forms.TextInput(),
} }
labels = {"managed_team_id": "Selected Team"}
class AccountForm(ModelForm): class AccountForm(ModelForm):

View File

@@ -0,0 +1,37 @@
# Generated by Django 3.2.13 on 2022-06-15 18:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('gamechanger', '0005_alter_preferences_options'),
]
operations = [
migrations.CreateModel(
name='Team',
fields=[
('id', models.CharField(max_length=30, primary_key=True, serialize=False)),
('season_id', models.CharField(max_length=30)),
('name_slug', models.CharField(max_length=30)),
('season_slug', models.CharField(max_length=30)),
],
),
migrations.RemoveField(
model_name='preferences',
name='season_id',
),
migrations.RemoveField(
model_name='preferences',
name='team_id',
),
migrations.AddField(
model_name='preferences',
name='managed_team',
field=models.OneToOneField(default=1, on_delete=django.db.models.deletion.CASCADE, to='gamechanger.team'),
preserve_default=False,
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 3.2.13 on 2022-06-15 19:41
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('gamechanger', '0006_auto_20220615_1330'),
]
operations = [
migrations.RemoveField(
model_name='team',
name='season_id',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.13 on 2022-06-15 21:18
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('gamechanger', '0007_remove_team_season_id'),
]
operations = [
migrations.RenameField(
model_name='team',
old_name='name_slug',
new_name='slug',
),
]

View File

@@ -14,12 +14,17 @@ class Account(models.Model):
password = CharField(max_length=255) password = CharField(max_length=255)
class Team(models.Model):
id = models.CharField(primary_key=True, max_length=30)
slug = CharField(max_length=30)
season_slug = CharField(max_length=30)
class Preferences(models.Model): class Preferences(models.Model):
user = models.OneToOneField( user = models.OneToOneField(
User, on_delete=models.CASCADE, related_name="gamechanger_preferences" User, on_delete=models.CASCADE, related_name="gamechanger_preferences"
) )
season_id = CharField(max_length=255) managed_team = models.OneToOneField(Team, on_delete=models.CASCADE)
team_id = CharField(max_length=255)
class Meta: class Meta:
verbose_name_plural = "preferences" verbose_name_plural = "preferences"

View File

@@ -7,7 +7,7 @@ import pytz
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
url = "https://gc.com/t/{season_id}/{team_id}/{page}" url = "https://gc.com/t/{season_id}/{team_slug}-{team_id}/{page}"
def get_authenticated_session(request): def get_authenticated_session(request):
@@ -35,12 +35,16 @@ def get_authenticated_session(request):
def submit_lineup(request, lineup): def submit_lineup(request, lineup):
authenticated_session = get_authenticated_session(request) authenticated_session = get_authenticated_session(request)
season_id = request.user.gamechanger_preferences.season_id season_id = request.user.gamechanger_preferences.managed_team.season_slug
team_id = request.user.gamechanger_preferences.team_id team_slug = request.user.gamechanger_preferences.managed_team.slug
team_id = request.user.gamechanger_preferences.managed_team.id
authenticated_session.headers.update( authenticated_session.headers.update(
{ {
"referer": url.format( "referer": url.format(
season_id=season_id, team_id=team_id, page="lineup_edit" season_id=season_id,
team_slug=team_slug,
team_id=team_id,
page="lineup_edit",
), ),
"x-csrftoken": authenticated_session.cookies.get("csrftoken"), "x-csrftoken": authenticated_session.cookies.get("csrftoken"),
"Content-Type": "application/x-www-form-urlencoded;", "Content-Type": "application/x-www-form-urlencoded;",
@@ -48,12 +52,10 @@ def submit_lineup(request, lineup):
) )
r = authenticated_session.post( r = authenticated_session.post(
cookies=authenticated_session.cookies, cookies=authenticated_session.cookies,
url="https://gc.com/do-save-lineup/{team_id}".format( url=f"https://gc.com/do-save-lineup/{team_id}",
team_id=team_id.split("-").pop()
),
json={"lineup": lineup}, json={"lineup": lineup},
) )
if r.status_code == 200: if r.status_code == 20 and r.content == b"OK":
return r return r
else: else:
raise requests.exceptions.RequestException( raise requests.exceptions.RequestException(
@@ -61,8 +63,10 @@ def submit_lineup(request, lineup):
) )
def scrape_page(season_id, team_id, page): def scrape_page(season_id, team_id, team_slug, 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, team_slug=team_slug, page=page)
)
initialize_page_json = re.search( initialize_page_json = re.search(
r'page.initialize\(\$.parseJSON\("(.*?)"\)', r.content.decode("unicode_escape") r'page.initialize\(\$.parseJSON\("(.*?)"\)', r.content.decode("unicode_escape")
) )
@@ -160,14 +164,34 @@ def stream():
def stats(request): def stats(request):
authenticated_session = get_authenticated_session(request) authenticated_session = get_authenticated_session(request)
season_id = request.user.gamechanger_preferences.season_id season_id = request.user.gamechanger_preferences.managed_team.season_slug
team_id = request.user.gamechanger_preferences.team_id team_id = request.user.gamechanger_preferences.managed_team.id
team_slug = request.user.gamechanger_preferences.managed_team.slug
page = "stats/batting/Qualified/standard/csv" page = "stats/batting/Qualified/standard/csv"
authenticated_session.headers.update(
{
"referer": url.format(
season_id=season_id, team_id=team_id, team_slug=team_slug, page="stats"
),
"x-csrftoken": authenticated_session.cookies.get("csrftoken"),
}
)
r = authenticated_session.get( r = authenticated_session.get(
url.format(season_id=season_id, team_id=team_id, page=page) cookies=authenticated_session.cookies,
url=url.format(
season_id=season_id, team_id=team_id, team_slug=team_slug, page=page
),
) )
roster = scrape_page(season_id, team_id, "roster") if (
r.status_code != 200
or "Please sign in or join to continue." in r.content.decode("utf-8")
):
raise Exception("Stats fetch failed.")
roster = scrape_page(
season_id=season_id, team_id=team_id, team_slug=team_slug, page="roster"
)
id_lookup = { id_lookup = {
(p.get("fname"), p.get("lname")): p.get("player_id") for p in roster["roster"] (p.get("fname"), p.get("lname")): p.get("player_id") for p in roster["roster"]
} }

View File

@@ -1,3 +1,4 @@
from django import forms
from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseServerError 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
@@ -5,7 +6,7 @@ from django.views.generic.edit import FormView
from teamsnap.views import get_teamsnap_client from teamsnap.views import get_teamsnap_client
from .forms import AccountForm, PlayerFormSet, PreferencesForm from .forms import AccountForm, PlayerFormSet, PreferencesForm
from .models import Account, Player, Preferences from .models import Account, Player, Preferences, Team
from .utils import gamechanger from .utils import gamechanger
@@ -30,10 +31,15 @@ class PreferencesFormView(FormView):
def form_valid(self, form): def form_valid(self, form):
# This method is called when valid form data has been POSTed. # This method is called when valid form data has been POSTed.
# It should return an HttpResponse. # It should return an HttpResponse.
if form.data["user"] == str(self.request.user.id): if form.cleaned_data["user"].username == str(
self.request.user.gamechanger_account.user
):
form.save() form.save()
return super().form_valid(form) return super().form_valid(form)
def form_invalid(self, form):
pass
def get_initial(self): def get_initial(self):
""" """
Returns the initial data to use for forms on this view. Returns the initial data to use for forms on this view.
@@ -51,11 +57,32 @@ class PreferencesFormView(FormView):
""" """
try: try:
contact = Preferences.objects.get(user=self.request.user) preferences = Preferences.objects.get(user=self.request.user)
form = PreferencesForm(instance=contact, **self.get_form_kwargs()) form = PreferencesForm(instance=preferences, **self.get_form_kwargs())
except Preferences.DoesNotExist: except Preferences.DoesNotExist:
form = super().get_form(self.form_class) form = super().get_form(self.form_class)
gc_session = gamechanger.get_authenticated_session(self.request)
teams = gamechanger.get_teams(gc_session)
team_instances = []
choices = []
for team in teams:
instance, _ = Team.objects.get_or_create(
id=team["id"],
slug="-".join(team["team_slug"].split("-")[:-1]),
season_slug=team["season_slug"],
)
team_instances.append(instance)
choices.append((team["id"], f"{team['name']} ({team['season']})"))
form.fields["managed_team"].widget = forms.Select(
choices=choices, attrs={"class": "form-control"}
)
# form.fields["managed_team"].choices = [choice[0] for choice in choices]
# form.fields["managed_team"].widget.choices = choices
return form return form
@@ -97,8 +124,8 @@ class AccountFormView(FormView):
def roster(request): def roster(request):
season_id = request.user.gamechanger_preferences.season_id season_id = request.user.gamechanger_preferences.managed_team.season_slug
team_id = request.user.gamechanger_preferences.team_id team_id = request.user.gamechanger_preferences.id
page = "roster" page = "roster"
d = gamechanger.scrape_page(season_id, team_id, page) d = gamechanger.scrape_page(season_id, team_id, page)
roster = d["roster"] roster = d["roster"]
@@ -110,8 +137,9 @@ def roster_import(request):
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.managed_team.season_slug
team_id = request.user.gamechanger_preferences.team_id team_slug = request.user.gamechanger_preferences.managed_team.slug
team_id = request.user.gamechanger_preferences.managed_team.id
teamsnap_team_id = request.user.teamsnap_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
@@ -120,7 +148,7 @@ def roster_import(request):
page = "roster" page = "roster"
d = gamechanger.scrape_page(season_id, team_id, page) d = gamechanger.scrape_page(season_id, team_id, team_slug, page)
roster = d["roster"] roster = d["roster"]
initial = [ initial = [
{ {
@@ -128,12 +156,18 @@ def roster_import(request):
"fname": player["fname"], "fname": player["fname"],
"lname": player["lname"], "lname": player["lname"],
"teamsnap_name": "{first_name} {last_name}".format( "teamsnap_name": "{first_name} {last_name}".format(
**teamsnap_members[f"{player['fname']} {player['lname']}"].data **getattr(
teamsnap_members.get(f"{player['fname']} {player['lname']}"),
"data",
{"first_name": "", "last_name": ""},
)
), ),
"id": player.get("player_id"), "id": player.get("player_id"),
"teamsnap_member_id": teamsnap_members[ "teamsnap_member_id": getattr(
f"{player['fname']} {player['lname']}" teamsnap_members.get(f"{player['fname']} {player['lname']}"),
].data["id"], "data",
{"id": None},
)["id"],
} }
for player in roster for player in roster
] ]

View File

@@ -3,6 +3,10 @@ version: '3'
volumes: volumes:
benchcoach_local_postgres_data: {} benchcoach_local_postgres_data: {}
benchcoach_local_postgres_data_backups: {} benchcoach_local_postgres_data_backups: {}
certs: {}
vhost: {}
html: {}
acme: {}
services: services:
django: django:
@@ -60,9 +64,23 @@ services:
- "443:443" - "443:443"
volumes: volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro - /var/run/docker.sock:/tmp/docker.sock:ro
- /root/teamsnap-benchcoach/certs:/etc/nginx/certs - certs:/etc/nginx/certs
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
env_file: env_file:
- ./.envs/.linode/.nginx-proxy - ./.envs/.linode/.nginx-proxy
restart: always restart: always
depends_on: depends_on:
- django - django
nginx-proxy-acme:
image: nginxproxy/acme-companion
container_name: nginx-proxy-acme
volumes_from:
- nginx-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- certs:/etc/nginx/certs:rw
- acme:/etc/acme.sh
env_file:
- ./.envs/.linode/.nginx-proxy-acme

View File

@@ -16,3 +16,5 @@ django-allauth==0.50.0 # https://github.com/pennersr/django-allauth
django-crispy-forms==1.14.0 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==1.14.0 # https://github.com/django-crispy-forms/django-crispy-forms
crispy-bootstrap5==0.6 # https://github.com/django-crispy-forms/crispy-bootstrap5 crispy-bootstrap5==0.6 # https://github.com/django-crispy-forms/crispy-bootstrap5
django-redis==5.2.0 # https://github.com/jazzband/django-redis django-redis==5.2.0 # https://github.com/jazzband/django-redis
beautifulsoup4==4.11.1

37
requirements/linode.txt Normal file
View File

@@ -0,0 +1,37 @@
-r base.txt
Werkzeug[watchdog]==2.0.3 # https://github.com/pallets/werkzeug
ipdb==0.13.9 # https://github.com/gotcha/ipdb
psycopg2==2.9.3 # https://github.com/psycopg/psycopg2
# Testing
# ------------------------------------------------------------------------------
mypy==0.950 # https://github.com/python/mypy
django-stubs==1.9.0 # https://github.com/typeddjango/django-stubs
pytest==7.1.2 # https://github.com/pytest-dev/pytest
pytest-sugar==0.9.4 # https://github.com/Frozenball/pytest-sugar
# Documentation
# ------------------------------------------------------------------------------
sphinx==4.5.0 # https://github.com/sphinx-doc/sphinx
sphinx-autobuild==2021.3.14 # https://github.com/GaretJax/sphinx-autobuild
# Code quality
# ------------------------------------------------------------------------------
flake8==4.0.1 # https://github.com/PyCQA/flake8
flake8-isort==4.1.1 # https://github.com/gforcada/flake8-isort
coverage==6.4 # https://github.com/nedbat/coveragepy
black==22.3.0 # https://github.com/psf/black
pylint-django==2.5.3 # https://github.com/PyCQA/pylint-django
pre-commit==2.19.0 # https://github.com/pre-commit/pre-commit
# Django
# ------------------------------------------------------------------------------
factory-boy==3.2.1 # https://github.com/FactoryBoy/factory_boy
django-debug-toolbar==3.4.0 # https://github.com/jazzband/django-debug-toolbar
django-extensions==3.1.5 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==2.0.3 # https://github.com/nedbat/django_coverage_plugin
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
bs4

View File

@@ -33,3 +33,5 @@ django-debug-toolbar==3.4.0 # https://github.com/jazzband/django-debug-toolbar
django-extensions==3.1.5 # https://github.com/django-extensions/django-extensions django-extensions==3.1.5 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==2.0.3 # https://github.com/nedbat/django_coverage_plugin django-coverage-plugin==2.0.3 # https://github.com/nedbat/django_coverage_plugin
pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django pytest-django==4.5.2 # https://github.com/pytest-dev/pytest-django
bs4