sync improvements

allow blank for teamsnap fields
This commit is contained in:
2021-12-22 15:21:36 -06:00
parent e0b9ed6d87
commit 3f39a7aa68
13 changed files with 189 additions and 590 deletions

View File

@@ -1 +0,0 @@
[{"model": "teamsnap.user", "pk": 1, "fields": {"teamsnap_id": "25560745", "access_token": "u2SqDq78FumVvhkt1D-V1CQ2ZIaB-nUVlzGwd1YhGtA"}}, {"model": "teamsnap.team", "pk": 1, "fields": {"teamsnap_id": "7644001", "name": null, "bencoach_team": null}}]

View File

@@ -1,25 +1,29 @@
from django import forms from django import forms
from .models import LineupEntry, Event from .models import Team, Location, Opponent, Event, Member
import benchcoach.models
from django.forms import modelformset_factory from django.forms import modelformset_factory
class LineupEntryForm(forms.ModelForm): select_kwargs = {
availability = None 'attrs':{'class': 'form-control form-control-sm'}
class Meta: }
model = LineupEntry
widgets = {
'label': forms.Select(attrs={'class': 'form-control form-control-sm'})
}
exclude = ()
LineupEntryFormSet = modelformset_factory( text_input_kwargs = {
model=LineupEntry, 'attrs':{"readonly": "readonly", 'class':'form-control form-control-sm'}
form=LineupEntryForm, }
extra=0
) class MemberForm(forms.ModelForm):
class Meta:
model = Member
fields = ('first_name', 'last_name', 'benchcoach_object')
labels = {
'benchcoach_object': 'BenchCoach Link',
}
widgets = {
"benchcoach_object": forms.Select(**select_kwargs),
"first_name": forms.TextInput(**text_input_kwargs),
"last_name": forms.TextInput(**text_input_kwargs),
}
class EventForm(forms.ModelForm): class EventForm(forms.ModelForm):
availability = None
class Meta: class Meta:
model = Event model = Event
fields = ('formatted_title', 'start_date', 'benchcoach_object') fields = ('formatted_title', 'start_date', 'benchcoach_object')
@@ -29,12 +33,45 @@ class EventForm(forms.ModelForm):
'start_date':'Date/Time' 'start_date':'Date/Time'
} }
widgets = { widgets = {
"formatted_title":forms.TextInput(attrs={"disabled":"disabled"}), "benchcoach_object": forms.Select(**select_kwargs),
"start_date": forms.DateTimeInput(attrs={"disabled": "disabled"}) "formatted_title":forms.TextInput(**text_input_kwargs),
"start_date": forms.DateTimeInput(**text_input_kwargs)
} }
EventFormSet = modelformset_factory( class TeamForm(forms.ModelForm):
model=Event, class Meta:
form=EventForm, model = Team
extra=0 fields = ('name', 'benchcoach_object')
) labels ={
'benchcoach_object':'BenchCoach Link',
}
widgets = {
"name":forms.TextInput(**text_input_kwargs),
"benchcoach_object": forms.Select(**select_kwargs)
}
class OpponentForm(forms.ModelForm):
class Meta:
model = Opponent
fields = ('name', 'benchcoach_object')
labels ={
'benchcoach_object':'BenchCoach Link',
}
widgets = {
"name":forms.TextInput(**text_input_kwargs),
"benchcoach_object": forms.Select(**select_kwargs)
}
class LocationForm(forms.ModelForm):
class Meta:
model = Location
fields = ('name', 'benchcoach_object')
labels ={
'benchcoach_object':'BenchCoach Link',
}
widgets = {
"name":forms.TextInput(**text_input_kwargs),
"benchcoach_object": forms.Select(**select_kwargs)
}

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-12-22 15:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('teamsnap', '0003_auto_20211219_2058'),
]
operations = [
migrations.AlterField(
model_name='event',
name='is_game',
field=models.BooleanField(null=True),
),
migrations.AlterField(
model_name='member',
name='is_non_player',
field=models.BooleanField(null=True),
),
]

View File

@@ -26,6 +26,7 @@ class Team(TeamsnapBaseModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Team, benchcoach.models.Team,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_team" related_name="teamsnap_team"
) )
@@ -35,7 +36,8 @@ class Team(TeamsnapBaseModel):
def update_or_create_from_teamsnap_api(cls, teamsnap_data): def update_or_create_from_teamsnap_api(cls, teamsnap_data):
fields = ['id', 'name', 'created_at', 'updated_at'] fields = ['id', 'name', 'created_at', 'updated_at']
data = {k: teamsnap_data[k] for k in fields} data = {k: teamsnap_data[k] for k in fields}
team, created = cls.objects.update_or_create(**data) id = data.pop('id')
team, created = cls.objects.update_or_create(id=id, defaults=data)
return (team, created) return (team, created)
class User(TeamsnapBaseModel): class User(TeamsnapBaseModel):
@@ -55,7 +57,8 @@ class User(TeamsnapBaseModel):
obj, created = Team.objects.get_or_create(id=managed_team_id) obj, created = Team.objects.get_or_create(id=managed_team_id)
managed_teams.append(obj) managed_teams.append(obj)
pass pass
user, created = cls.objects.update_or_create(**user_data) id = user_data.pop('id')
user, created = cls.objects.update_or_create(id=id, defaults=user_data)
user.managed_teams.add(*managed_teams) user.managed_teams.add(*managed_teams)
return (user, created) return (user, created)
@@ -80,6 +83,7 @@ class Opponent(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Team, benchcoach.models.Team,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_opponent" related_name="teamsnap_opponent"
) )
@@ -90,8 +94,10 @@ class Opponent(TeamsnapManagedObjectModel):
fields = ['id', 'name', 'created_at', 'updated_at'] fields = ['id', 'name', 'created_at', 'updated_at']
opponent_data = {k: teamsnap_data[k] for k in fields} opponent_data = {k: teamsnap_data[k] for k in fields}
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
opponent, created = cls.objects.update_or_create(**opponent_data) id = opponent_data.pop('id')
opponent, created = cls.objects.update_or_create(id=id, defaults=opponent_data)
opponent.team = team opponent.team = team
opponent.save()
return (opponent, created) return (opponent, created)
class Location(TeamsnapManagedObjectModel): class Location(TeamsnapManagedObjectModel):
@@ -100,6 +106,7 @@ class Location(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Venue, benchcoach.models.Venue,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_location" related_name="teamsnap_location"
) )
@@ -110,8 +117,10 @@ class Location(TeamsnapManagedObjectModel):
fields = ['id', 'name', 'created_at', 'updated_at'] fields = ['id', 'name', 'created_at', 'updated_at']
opponent_data = {k: teamsnap_data[k] for k in fields} opponent_data = {k: teamsnap_data[k] for k in fields}
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
location, created = cls.objects.update_or_create(**opponent_data) id = opponent_data.pop('id')
location, created = cls.objects.update_or_create(id=id, defaults=opponent_data)
location.team = team location.team = team
location.save()
return (location, created) return (location, created)
class Member(TeamsnapManagedObjectModel): class Member(TeamsnapManagedObjectModel):
@@ -123,13 +132,14 @@ class Member(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Player, benchcoach.models.Player,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_member" related_name="teamsnap_member"
) )
first_name = models.CharField(max_length = 50, null=True) first_name = models.CharField(max_length = 50, null=True)
last_name = models.CharField(max_length = 50, null=True) last_name = models.CharField(max_length = 50, null=True)
jersey_number = models.IntegerField(null=True) jersey_number = models.IntegerField(null=True)
is_non_player = models.BooleanField() is_non_player = models.BooleanField(null=True)
ApiObject = teamsnap.teamsnap.api.Member ApiObject = teamsnap.teamsnap.api.Member
@classmethod @classmethod
@@ -137,8 +147,10 @@ class Member(TeamsnapManagedObjectModel):
fields = ['id', 'created_at', 'updated_at', 'first_name', 'last_name', 'jersey_number','is_non_player'] fields = ['id', 'created_at', 'updated_at', 'first_name', 'last_name', 'jersey_number','is_non_player']
member_data = {k: teamsnap_data[k] for k in fields} member_data = {k: teamsnap_data[k] for k in fields}
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
member, created = cls.objects.update_or_create(**member_data) id = member_data.pop('id')
member, created = cls.objects.update_or_create(id=id, defaults= member_data)
member.team = team member.team = team
member.save()
return (member, created) return (member, created)
def __str__(self): def __str__(self):
@@ -156,6 +168,7 @@ class Event(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Event, benchcoach.models.Event,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_event" related_name="teamsnap_event"
) )
@@ -166,7 +179,7 @@ class Event(TeamsnapManagedObjectModel):
formatted_title = models.CharField(max_length = 50, null=True) formatted_title = models.CharField(max_length = 50, null=True)
points_for_opponent = models.PositiveSmallIntegerField(null=True) points_for_opponent = models.PositiveSmallIntegerField(null=True)
points_for_team = models.PositiveSmallIntegerField(null=True) points_for_team = models.PositiveSmallIntegerField(null=True)
is_game = models.BooleanField() is_game = models.BooleanField(null=True)
game_type = models.CharField(max_length = 50, null=True) game_type = models.CharField(max_length = 50, null=True)
ApiObject = teamsnap.teamsnap.api.Event ApiObject = teamsnap.teamsnap.api.Event
@@ -187,13 +200,15 @@ class Event(TeamsnapManagedObjectModel):
event_data = {k: teamsnap_data[k] for k in fields} event_data = {k: teamsnap_data[k] for k in fields}
location, created = Location.objects.get_or_create(id=teamsnap_data['location_id']) location, created = Location.objects.get_or_create(id=teamsnap_data['location_id'])
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
event, created = cls.objects.update_or_create(**event_data) id = event_data.pop('id')
event, created = cls.objects.update_or_create(id=id, defaults=event_data)
event.location = location event.location = location
if teamsnap_data['opponent_id']: if teamsnap_data['opponent_id']:
opponent, created = Opponent.objects.get_or_create(id=teamsnap_data['opponent_id']) opponent, created = Opponent.objects.get_or_create(id=teamsnap_data['opponent_id'])
event.opponent = opponent event.opponent = opponent
event.team = team event.team = team
return (location, created) event.save()
return (team, created)
def __str__(self): def __str__(self):
return f"{self.formatted_title} ({self.id})" return f"{self.formatted_title} ({self.id})"
@@ -214,6 +229,7 @@ class Availability(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Availability, benchcoach.models.Availability,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_availability" related_name="teamsnap_availability"
) )
@@ -238,10 +254,12 @@ class Availability(TeamsnapManagedObjectModel):
member, created = Member.objects.get_or_create(id=teamsnap_data['member_id']) member, created = Member.objects.get_or_create(id=teamsnap_data['member_id'])
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
event, created = Event.objects.get_or_create(id=teamsnap_data['event_id']) event, created = Event.objects.get_or_create(id=teamsnap_data['event_id'])
availability, created = cls.objects.update_or_create(**availability_data) id = availability_data.pop('id')
availability, created = cls.objects.update_or_create(id=id, defaults=availability_data)
availability.team = team availability.team = team
availability.event = event availability.event = event
availability.member = member availability.member = member
availability.save()
return (availability, created) return (availability, created)
class LineupEntry(TeamsnapManagedObjectModel): class LineupEntry(TeamsnapManagedObjectModel):
@@ -263,6 +281,7 @@ class LineupEntry(TeamsnapManagedObjectModel):
benchcoach_object = models.OneToOneField( benchcoach_object = models.OneToOneField(
benchcoach.models.Positioning, benchcoach.models.Positioning,
null=True, null=True,
blank=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="teamsnap_lineupentry" related_name="teamsnap_lineupentry"
) )
@@ -283,8 +302,10 @@ class LineupEntry(TeamsnapManagedObjectModel):
member, created = Member.objects.get_or_create(id=teamsnap_data['member_id']) member, created = Member.objects.get_or_create(id=teamsnap_data['member_id'])
team, created = Team.objects.get_or_create(id=teamsnap_data['team_id']) team, created = Team.objects.get_or_create(id=teamsnap_data['team_id'])
event, created = Event.objects.get_or_create(id=teamsnap_data['event_id']) event, created = Event.objects.get_or_create(id=teamsnap_data['event_id'])
lineup_entry, created = cls.objects.update_or_create(**lineup_entry_data) id = lineup_entry_data.pop('id')
lineup_entry, created = cls.objects.update_or_create(id=id, defaults=lineup_entry_data)
lineup_entry.team = team lineup_entry.team = team
lineup_entry.event = event lineup_entry.event = event
lineup_entry.member = member lineup_entry.member = member
lineup_entry.save()
return (lineup_entry, created) return (lineup_entry, created)

View File

@@ -1,23 +0,0 @@
{% extends "base.html" %}
{% block title %} {{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
{#<ol class="list-group">#}
{% for item in object_list %}
<ul class="card">
<span class="card-title">{{ item.formatted_title }}</span>
<span class="fs-6">{{ item.subtitle }}</span>
{# {% if item.body %}#}
{# <br><span class="fs-6">{{ item.body }}</span>#}
<br>{{ item.start_date|date:"D, M j, g:i A" }},<br>{{item.location.name}}
{# {% endif %}#}
<br>
{% for button in item.buttons %}
<a class="btn btn-primary btn-sm" href="{{ button.href }}" role="button">{{ button.label }}</a>
{% endfor %}
</ul>
{% endfor %}
</ol>
{% endblock %}

View File

@@ -7,32 +7,30 @@
<p><b>TeamSnap: </b>{{ teamsnap_user.email }}</p> <p><b>TeamSnap: </b>{{ teamsnap_user.email }}</p>
<p><b>TeamSnap Managed Team: </b>{{ teamsnap_team.name }}</p> <p><b>TeamSnap Managed Team: </b>{{ teamsnap_team.name }}</p>
<button type="button" class="btn btn-primary m-1" onclick="sync_teamsnap_db()"> <button type="button" class="btn btn-primary m-1" onclick="sync_teamsnapdb_with_teamsnapapi()">
Sync TeamSnap DB Sync TeamSnapDB with TeamSnap.com
<div id="teamsnap-sync-spinner" class="spinner-border spinner-border-sm d-none" role="status"> <div id="teamsnap-sync-spinner" class="spinner-border spinner-border-sm d-none" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</button> </button>
<button type="button" class="btn btn-primary m-1" onclick="sync_teamsnap_db()"> <button type="button" class="btn btn-primary m-1" onclick="sync_teamsnapdb_to_benchcoachdb()">
Sync TeamSnap DB Sync BenchCoachDB with TeamSnapDB
<div id="teamsnap-sync-spinner" class="spinner-border spinner-border-sm d-none" role="status"> <div id="benchcoach-sync-spinner" class="spinner-border spinner-border-sm d-none" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</button> </button>
{% include 'messages.html' %} {% include 'messages.html' %}
<div id="message-area"> </div> <div id="message-area"> </div>
<script> <script>
const progress_spinner = document.getElementById("teamsnap-sync-spinner")
const message_area = document.getElementById("message-area") function sync_teamsnapdb_with_teamsnapapi(){
function sync_teamsnap_db(){ const progress_spinner = document.getElementById("teamsnap-sync-spinner")
const Http = new XMLHttpRequest(); const Http = new XMLHttpRequest();
const url='{% url 'sync teamsnap db' %}'; const url='{% url 'sync with teamsnapapi' %}';
console.log(progress_spinner)
progress_spinner.classList.remove("d-none"); progress_spinner.classList.remove("d-none");
fetch(url) fetch(url)
.then((response) => { .then((response) => {
progress_spinner.classList.add("d-none") progress_spinner.classList.add("d-none")
message_area.innerText = "test"
return response.json(); return response.json();
}) })
.then((myJson) => { .then((myJson) => {
@@ -41,15 +39,16 @@
}); });
} }
function sync_teamsnap_db_2(){ function sync_teamsnapdb_to_benchcoachdb(){
console.log('hello')
const progress_spinner = document.getElementById("benchcoach-sync-spinner")
const Http = new XMLHttpRequest(); const Http = new XMLHttpRequest();
const url='{% url 'sync teamsnap db' %}'; const url='{% url 'sync benchcoach' %}';
console.log(progress_spinner) console.log(url)
progress_spinner.classList.remove("d-none"); progress_spinner.classList.remove("d-none");
fetch(url) fetch(url)
.then((response) => { .then((response) => {
progress_spinner.classList.add("d-none") progress_spinner.classList.add("d-none")
message_area.innerText = "test"
return response.json(); return response.json();
}) })
.then((myJson) => { .then((myJson) => {

View File

@@ -1,157 +0,0 @@
{% extends 'base.html' %}{% block title %} {{ title }} {% endblock %}{% load static %}
{% block content %}
<div class="w-100 text-center mx-auto text-center">
<h1 class="display-5 fw-bold"><a href="#" class="btn btn-primary btn-secondary p-1 mx-3"><</a>{{ event.formatted_title }}<a href="#" class="btn btn-primary btn-secondary p-1 mx-3">></a></h1>
<div class="lead">
<p class="">{{ event.start_date|date:"l, F j, Y g:i A" }}<br>{{ event.location.name }}</p>
</div>
</div>
<div class="container">
<form action="{% url 'teamsnap edit lineup' event_id=event.id%}" method="post">
{% csrf_token %}
{{ formset.management_form }}
<div class="row">
{# <input type="submit" value="Submit" class="btn btn-sm btn-success mx-3 my-0 my-0">#}
<div class="col-md-6">
<div class="card my-1">
<div class="card-header"><h5>Lineup</h5></div>
<div class="card-body p-0">
{% include 'teamsnap/player-table.html' with table_id="lineup" formset=formset_lineup available_class="d-none"%}
<div class="justify-content-md-end d-md-flex m-2"><input type="submit" value="Submit" class="btn btn-primary"></div>
</div>
</div>
<div class="card my-1">
<div class="card-header"><h5>DH'd</h5></div>
<div class="card-body p-0">
{% include 'teamsnap/player-table.html' with table_id="dhd" formset=formset_dhd available_class="d-none" sequence_class="d-none"%}
<div class="justify-content-md-end d-md-flex m-2"><input type="submit" value="Submit" class="btn btn-primary"></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card my-1">
<div class="card-header"><h5>Bench</h5></div>
<div class="card-body p-0">
{% include 'teamsnap/player-table.html' with table_id="bench" formset=formset_bench sequence_class="d-none"%}
</div>
</div>
</div>
</div>
</form>
</div>
<script src="{% static 'js/Sortable.js' %}"></script>
<script id="sortable">
function refresh_lineup_sequence (){
var member_rows = document.getElementById('lineup').querySelectorAll('tr')
var has_dh = false
for (let i = 0; i < member_rows.length; i++) {
if (member_rows[i].dataset.sequence == 0) {
has_dh = true
continue
}
if (has_dh) {
member_rows[i].dataset.sequence = i
}
else {
member_rows[i].dataset.sequence = i+1
}
var member_sequence = member_rows[i].querySelector('[id^="member-sequence-button"]')
var form_element_sequence = member_rows[i].querySelector('[id$="sequence"]')
member_sequence.innerText = parseInt(member_rows[i].dataset.sequence)
form_element_sequence.value = parseInt(member_rows[i].dataset.sequence)
}
}
var lineup = new Sortable.create(
document.getElementById('dhd'), {
animation: 150,
ghostClass: "ghost",
{#handle: ".bars-move",#}
group: {
put: true,
pull: true
}
})
var lineup = new Sortable.create(
document.getElementById('lineup'), {
animation: 150,
ghostClass:"ghost",
{#handle: ".bars-move",#}
group:{
put:true,
pull:true
},
onAdd: function (/**Event*/evt) {
// Add to Lineup
var itemEl = evt.item; // dragged HTMLElement
var member_id = itemEl.dataset.memberId
console.log(itemEl)
var form_element_sequence =itemEl.querySelector('[id$="sequence"]')
var member_sequence = itemEl.querySelector('[id^="member-sequence"]')
var member_available =itemEl.querySelector('[id^="member-available"]')
var member_sequence_button =itemEl.querySelector('[id^="member-sequence-button"]')
console.log(member_sequence.parentElement.dataset)
toggle_in_lineup(member_sequence_button)
member_sequence.parentElement.dataset.sequence = evt.newIndex
refresh_lineup_sequence()
{#member_available.parentElement.style.display="none"#}
member_available.parentElement.classList.add('d-none')
{#member_sequence.style.display="table-cell"#}
member_sequence.classList.remove('d-none')
},
onUpdate: function (/**Event*/evt) {
console.log('update to lineup')
var itemEl = evt.item; // dragged HTMLElement
refresh_lineup_sequence()
},
});
var bench = new Sortable.create(
document.getElementById('bench'), {
animation: 150,
ghostClass:"ghost",
sort: false,
{#handle: ".bars-move",#}
group:{
put:true,
pull:true
},
onAdd: function (/**Event*/evt) {
console.log('added to bench')
var itemEl = evt.item; // dragged HTMLElement
console.log(itemEl)
var form_element_sequence =itemEl.querySelector('[id$="sequence"]')
var member_sequence = itemEl.querySelector('[id^="member-sequence"]')
var member_available =itemEl.querySelector('[id^="member-available"]')
{#member_available.parentElement.style.display="table-cell"#}
member_available.parentElement.classList.remove('d-none')
form_element_sequence.value = 0
member_sequence.innerHTML = 1
{#member_sequence.style.display="none"#}
member_sequence.classList.add('d-none')
var member_id = itemEl.dataset.memberId
refresh_lineup_sequence()
}
});
function toggle_in_lineup(sequence_button){
var member_row = sequence_button.parentNode.parentNode
if (member_row.dataset.sequence == 0) {
sequence_button.innerText = "1"
sequence_button.classList.add("btn-light")
sequence_button.classList.remove("btn-dark")
member_row.dataset.sequence = 1
}
else {
sequence_button.innerText = "D"
sequence_button.classList.remove("btn-light")
sequence_button.classList.add("btn-dark")
member_row.dataset.sequence = 0
}
refresh_lineup_sequence()
}
</script>
{% endblock %}

View File

@@ -1,86 +0,0 @@
<table class="table">
<thead>
<tr class="border border-light">
{# <th scope="col" style="display: none"></th>#}
{# <th scope="col" class="border border-light"></th>#}
{# <th scope="col">Name</th>#}
{# <th scope="col">Pos</th>#}
</tr>
</thead>
<tbody id={{ table_id }}>
{% for form in formset %}
<tr data-member-id="{{ form.instance.member.id }}"
data-position="{{ form.instance.position }}"
data-sequence="{{ form.instance.sequence }}">
{{ form.id.as_hidden }}
{{ form.event.as_hidden }}
{{ form.sequence.as_hidden }}
{{ form.member.as_hidden }}
{{ form.teamsnap_id.as_hidden }}
<td id="member-availability-{{ form.instance.member.id }}"
class="{{ available_class }}"
>
{% if form.availability.status_code == 2 %}
<button class="btn btn-light bg-info p-1"
id="member-available-{{ form.instance.member.id }}"
>
<span style="visibility: hidden">2</span>
<span class="visually-hidden">Maybe</span>
</button>
{% elif form.availability.status_code == 1%}
<button class="btn btn-light bg-success p-1"
id="member-available-{{ form.instance.member.id }}"
>
<span style="visibility: hidden">1</span>
</button>
<span class="visually-hidden">Maybe</span>
{% elif form.availability.status_code == 0%}
<button class="btn btn-light bg-danger p-1"
id="member-available-{{ form.instance.member.id }}"
>
<span style="visibility: hidden">0</span>
</button>
<span class="visually-hidden">No</span>
{% else %}
<button class="btn btn-light bg-secondary p-1"
id="member-available-{{ form.instance.member.id }}"
>
<span style="visibility: hidden">X</span>
</button>
<span class="visually-hidden">Unknown</span>
{% endif %}
</td>
<th scope="row"
id="member-sequence-{{ form.instance.member.id }}"
class="{{ sequence_class }}">
{% if form.sequence.value %}
<button type="button"
class="btn btn-light p-1"
id="member-sequence-button-{{ form.instance.member.id }}"
onclick="toggle_in_lineup(this)"
>
{{ form.sequence.value }}
</button>
{% elif form.sequence.value == 0 %}
<button type="button"
class="btn btn-dark p-1"s
id="member-sequence-button-{{ form.instance.member.id }}"
onclick="toggle_in_lineup(this)"
>
D
</button>
{% endif %}
</th>
<th>
{{ form.instance.member.first_name }}&nbsp;{{ form.instance.member.last_name }}&nbsp;
<small class="text-muted fw-light">#{{ form.instance.member.jersey_number }}</small>
{# <br><code><small>{{ form.statline }}</small></code>#}
</th>
<td>
{{ form.label }}
</td>
{# <td>{{ form.instance.position }}</td>#}
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -1,13 +1,8 @@
<!DOCTYPE html> {% extends 'base.html' %}
<html lang="en"> {% block content %}
<head> <form method="post">
<meta charset="UTF-8"> {{ formset.management_form }}{% csrf_token %}
<title>Title</title> <table class="table">
</head>
<body>
{{ formset.management_form }}
<table>
<tr> <tr>
{% for _, field in formset.0.base_fields.items %} {% for _, field in formset.0.base_fields.items %}
<th>{{ field.label }}</th> <th>{{ field.label }}</th>
@@ -24,6 +19,6 @@
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
<input type="submit" value="Submit">
</body> </form>
</html> {% endblock %}

View File

@@ -7,9 +7,11 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.home, name='teamsnap home'), path('', views.home, name='teamsnap home'),
path('events', views.EventsListView.as_view(), name="teamsnap list events"), # path('events', views.EventsListView.as_view(), name="teamsnap list events"),
path('events-table', views.EventsTableView.as_view(), name="teamsnap table events"), # path('event-table', views.EventsTableView.as_view(), name="teamsnap table events"),
path('table/<str:object>', views.TeamsnapObjTableView.as_view(), name="teamsnap table obj"),
path('edit/event/<int:id>', views.edit_event, name='teamsnap edit event'), path('edit/event/<int:id>', views.edit_event, name='teamsnap edit event'),
path('sync_teamsnap_db', views.sync_teamsnap_db, name="sync teamsnap db"), path('sync_teamsnap_db', views.sync_teamsnapdb_with_teamsnapapi, name="sync with teamsnapapi"),
path('sync_benchcoach_db', views.sync_teamsnapdb_to_benchcoachdb, name="sync benchcoach"),
# path('import_teamsnap', views.import_teamsnap, name="import teamsnap"), # path('import_teamsnap', views.import_teamsnap, name="import teamsnap"),
] ]

View File

@@ -29,9 +29,10 @@ def update_teamsnap_object(d, teamsnap_object: TeamsnapBaseModel, benchcoach_mod
if teamsnap_object.benchcoach_object: if teamsnap_object.benchcoach_object:
#TODO I'm not sure this does anything. need to make sure. #TODO I'm not sure this does anything. need to make sure.
benchcoach_object = benchcoach_model.objects.filter(id=teamsnap_object.benchcoach_object.id).first() benchcoach_object = benchcoach_model.objects.filter(id=teamsnap_object.benchcoach_object.id)
benchcoach_object.update(**d)
created = False created = False
r.append((benchcoach_object, created)) r.append((benchcoach_object.first(), created))
elif not teamsnap_object.benchcoach_object and create_benchcoach_object: elif not teamsnap_object.benchcoach_object and create_benchcoach_object:
benchcoach_object = benchcoach_model(**d) # create new benchcoach object benchcoach_object = benchcoach_model(**d) # create new benchcoach object
teamsnap_object.benchcoach_object = benchcoach_object teamsnap_object.benchcoach_object = benchcoach_object

View File

@@ -1,198 +0,0 @@
import os
import sys
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "benchcoachproject.settings")
os.environ["DJANGO_SETTINGS_MODULE"] = "benchcoachproject.settings"
import django
django.setup()
from teamsnap.teamsnap.api import TeamSnap
import teamsnap.teamsnap.api
from teamsnap.models import User, Member, Team, Event, Location, Availability, Opponent, TeamsnapBaseModel
from typing import List, Type, Tuple
from benchcoachproject.models import Profile as BenchcoachUser
import benchcoach.models
from django.db import models
import pytz
def update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel: Type[TeamsnapBaseModel],
teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
fields: List[str]= ['created_at', 'updated_at'],
additional_fields: List[str] = [],
related_fields: List[Tuple[str, Type[TeamsnapBaseModel]]] = [],
create = True,
create_related = True,
**teamsnap_search_kwargs
):
api_response_objects = TeamsnapModel.ApiObject.search(
client=teamsnap_client, **teamsnap_search_kwargs
)
r = []
for response_object in api_response_objects:
d = {k:response_object.data[k] for k in fields}
d.update({k:response_object.data[k] for k in additional_fields})
for related_field_name, RelatedTeamSnapModel in related_fields:
related_field_name = f"{related_field_name}_id"
filter_criteria = {related_field_name:response_object.data[related_field_name]}
if related_field_name == "team_id" and RelatedTeamSnapModel.__name__ == "Team":
filter_criteria = {'id':response_object.data[related_field_name]}
related_teamsnap_object = RelatedTeamSnapModel.objects.filter(**filter_criteria).first()
if related_teamsnap_object:
d[related_field_name] = related_teamsnap_object
elif not related_teamsnap_object and create_related:
related_teamsnap_object = RelatedTeamSnapModel(**{related_field_name:response_object.data[related_field_name]})
related_teamsnap_object.save()
elif not related_teamsnap_object and not create_related:
raise RelatedTeamSnapModel.DoesNotExist
teamsnap_object = TeamsnapModel.objects.filter(id=response_object.data['id'])
if teamsnap_object:
teamsnap_object.update(**d)
created = False
r.append((teamsnap_object.first(), created))
elif not teamsnap_object and create:
new_teamsnap_object = TeamsnapModel(**d) # create new benchcoach object
new_teamsnap_object.save()
created = True
r.append((new_teamsnap_object, created))
elif not teamsnap_object and not create:
raise TeamsnapModel.DoesNotExist
return r
def update_events(
teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
create: bool = True,
create_related: bool = False,
**teamsnap_search_kwargs
):
r = update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel= Event,
teamsnap_client= teamsnap_client,
additional_fields=['label', 'start_date', 'formatted_title', 'points_for_opponent', 'points_for_team', 'is_game', 'game_type'],
related_fields=[('location', Location), ('opponent', Opponent), ('team', Team)],
create=create,
create_related=create_related,
**teamsnap_search_kwargs
)
return r
def update_opponents(
teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
create: bool = True,
create_related: bool = False,
**teamsnap_search_kwargs
):
r = update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel= Opponent,
teamsnap_client= teamsnap_client,
additional_fields=['name'],
related_fields=[('team', Team)],
create=create,
create_related=create_related,
**teamsnap_search_kwargs
)
return r
def update_teams(
teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
create: bool = True,
create_related: bool = False,
**teamsnap_search_kwargs
):
r = update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel=Team,
teamsnap_client=teamsnap_client,
additional_fields=['name'],
create=create,
create_related=create_related,
**teamsnap_search_kwargs
)
def update_locations(
teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
create: bool = True,
create_related: bool = False,
**teamsnap_search_kwargs
):
r = update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel=Location,
teamsnap_client=teamsnap_client,
additional_fields=['name'],
related_fields=[('team', Team)],
create=create,
create_related=create_related,
**teamsnap_search_kwargs
)
def update_availabilities(teamsnap_client: teamsnap.teamsnap.api.TeamSnap,
create: bool = True,
create_related: bool = False,
**teamsnap_search_kwargs
):
r = update_teamsnapbasemodel_from_teamsnap(
TeamsnapModel= Availability,
teamsnap_client= teamsnap_client,
related_fields=[('event', Event), ('member', Member), ('team', Team)],
create=create,
create_related=create_related,
**teamsnap_search_kwargs
)
def import_teamsnap():
user = BenchcoachUser.objects.get(id=1)
TOKEN = user.teamsnap_access_token
USER_ID = user.teamsnap_user.id
TEAM_ID = user.teamsnapsettings.managed_team.id
CLIENT = TeamSnap(token=TOKEN)
l = []
for team in Opponent.objects.filter(managed_by_team_id=TEAM_ID):
l += update_opponent(team, create_benchcoach_object=True, create_related=True)
for team in Team.objects.filter(id=TEAM_ID):
l += update_team(team, create_benchcoach_object=True, create_related=True)
for location in Location.objects.filter(managed_by_team_id=TEAM_ID):
l += update_location(location, create_benchcoach_object=True, create_related=True)
for member in Member.objects.filter(managed_by_team_id=TEAM_ID, is_non_player=False):
l += update_member(member, create_benchcoach_object= True, create_related=True)
for event in Event.objects.filter(managed_by_team_id=TEAM_ID):
l += update_event(event, create_benchcoach_object=True, create_related=True)
for availability in Availability.objects.filter(managed_by_team_id=TEAM_ID):
l += update_availability(availability, create_benchcoach_object=True, create_related=True)
pass
# l += update_teams(CLIENT, team_id=TEAM_ID)
# l += update_members(CLIENT, team_id=TEAM_ID)
# l += update_locations(CLIENT, team_id=TEAM_ID)
# l += update_events(CLIENT, team_id=TEAM_ID)
# l += update_availabilities(CLIENT, team_id=TEAM_ID)
if __name__ == "__main__":
TOKEN = BenchcoachUser.objects.get(id=1).teamsnap_access_token
USER_ID = BenchcoachUser.objects.get(id=1).teamsnap_user_id
TEAM_ID = BenchcoachUser.objects.get(id=1).teamsnapsettings.managed_team_id
CLIENT = TeamSnap(token=TOKEN)
for Obj in [User]:
a = Obj.ApiObject.search(CLIENT, id=USER_ID)
for _a in a:
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
for Obj in [Event, Availability, Location, Member, Opponent, Team]:
a = Obj.ApiObject.search(CLIENT, team_id=TEAM_ID)
for _a in a:
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
# update_opponents(CLIENT, team_id=TEAM_ID)
# update_events(CLIENT, team_id=TEAM_ID)

View File

@@ -4,20 +4,20 @@ from .teamsnap.api import Event as TsApiEvent
from .teamsnap.api import TeamSnap from .teamsnap.api import TeamSnap
from .models import User, Member, Team, Event, Location, LineupEntry, Opponent, Availability from .models import User, Member, Team, Event, Location, LineupEntry, Opponent, Availability
from lib.views import BenchcoachListView from lib.views import BenchcoachListView
from .forms import LineupEntryForm, LineupEntryFormSet, EventForm, EventFormSet from .forms import EventForm, MemberForm, OpponentForm, TeamForm, LocationForm
from django.urls import reverse from django.urls import reverse
from django.db.models import Case, When from django.db.models import Case, When
from django.views import View from django.views import View
from django.http import HttpResponse from django.http import HttpResponse
import benchcoachproject.models import benchcoachproject.models
import benchcoach.models import benchcoach.models
import teamsnap.teamsnap.api
import json
from django.http import JsonResponse from django.http import JsonResponse
from .utils.teamsnap_object_utils import update_users, update_teams, update_events, update_members, update_locations, update_availabilities from .utils.teamsnap_object_utils import update_users, update_teams, update_events, update_members, update_locations, update_availabilities
from django.contrib import messages from django.contrib import messages
from django.template.loader import render_to_string from django.template.loader import render_to_string
from .utils.import_teamsnap import update_team, update_event, update_member, update_location, update_opponent, update_availability, update_teamsnap_object from .utils.import_teamsnap import update_team, update_event, update_member, update_location, update_opponent, update_availability, update_teamsnap_object
from django.forms import modelformset_factory
import django.db.models
def queryset_from_ids(Model, id_list): def queryset_from_ids(Model, id_list):
#https://stackoverflow.com/questions/4916851/django-get-a-queryset-from-array-of-ids-in-specific-order #https://stackoverflow.com/questions/4916851/django-get-a-queryset-from-array-of-ids-in-specific-order
@@ -40,61 +40,45 @@ def home(request):
} }
return render(request, 'teamsnap/home.html', context) return render(request, 'teamsnap/home.html', context)
class EventsTableView(View): class TeamsnapObjTableView(View):
def get(self, request): Model = None
qs = Event.objects.all() Form = None
formset = EventFormSet(queryset=qs) template = 'teamsnap/table.html'
return render(request,'teamsnap/event-table.html', context={'formset':formset}) options = {
'event': (Event, EventForm),
'location': (Location, LocationForm),
'member': (Member, MemberForm),
'opponent': (Opponent, OpponentForm),
'team': (Team, TeamForm)
}
class EventsListView(BenchcoachListView): def post(self, request, object):
Model = Event self.Model, self.Form = self.options[object]
edit_url = 'teamsnap edit event' self.Formset = modelformset_factory(
list_url = 'teamsnap list events' model=self.Model,
page_title = "TeamSnap Events" form=self.Form,
title_strf = '{item.formatted_title}' extra=0
body_strf = "{item.start_date:%a, %b %-d, %-I:%M %p},\n{item.location.name}" )
formset = self.Formset(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponse(200)
else:
return HttpResponse(422)
pass
def get_context_data(self): def get(self, request, object):
context = super().get_context_data() self.Model, self.Form = self.options[object]
for item in context['items']: self.Formset = modelformset_factory(
item['buttons'].append( model=self.Model,
{ form=self.Form,
'label': 'Edit Lineup', extra=0
'href': reverse('teamsnap edit lineup', args=[item['id']]) )
} qs = self.Model.objects.all()
) formset = self.Formset(queryset=qs)
return context return render(request, self.template, context={'formset': formset})
class TeamListView(BenchcoachListView): def sync_teamsnapdb_with_teamsnapapi(request):
Model = Team
edit_url = 'teamsnap edit team'
list_url = 'teamsnap list teams'
page_title = "TeamSnap Teams"
class LocationListView(BenchcoachListView):
Model = Location
edit_url = 'teamsnap edit location'
list_url = 'teamsnap list locations'
page_title = "TeamSnap Locations"
def update_from_teamsnap_event(request):
TOKEN = benchcoachproject.models.User.objects.get(id=1).teamsnap_access_token
CLIENT = TeamSnap(token=TOKEN)
teamsnap_event_id=request.POST.get('teamsnap event')
benchcoach_event_id=request.POST.get('teamsnap event')
if teamsnap_event_id:
benchcoach_event = benchcoach.models.Event.objects.get(id=benchcoach_event_id)
teamsnap_object = benchcoach.models.Event.objects.get(id=teamsnap_event_id)
teamsnap_id = teamsnap_object.teamsnap_id
teamsnap_response = TsApiEvent.search(client=CLIENT, id=teamsnap_id)
if teamsnap_response[0]:
data = teamsnap_response[0].data
location = Location.objects.get(teamsnap_id=data['location_id'])
opponent = Team.objects.get(teamsnap_id=data['opponent_id'])
return HttpResponse(f'Success, {data}')
def sync_with_teamsnap_api(request):
''' '''
This sync the internal TeamSnap Database with the TeamSnap API This sync the internal TeamSnap Database with the TeamSnap API
''' '''
@@ -119,6 +103,7 @@ def sync_with_teamsnap_api(request):
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data) obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
r[Obj.__name__].append((obj, created)) r[Obj.__name__].append((obj, created))
for object_name, results in r.items(): for object_name, results in r.items():
if len(r) == 0: if len(r) == 0:
messages.error(request, f"Error! No {object_name} objects created or updated") messages.error(request, f"Error! No {object_name} objects created or updated")
@@ -132,7 +117,7 @@ def sync_with_teamsnap_api(request):
return JsonResponse(data) return JsonResponse(data)
def sync_teamsnap_db(request): def sync_teamsnapdb_to_benchcoachdb(request):
''' '''
This syncs the internal BenchCoach Database and the TeamSnap Database This syncs the internal BenchCoach Database and the TeamSnap Database
''' '''
@@ -148,7 +133,7 @@ def sync_teamsnap_db(request):
r['location'] = [] r['location'] = []
for location in Location.objects.filter(team_id=TEAM_ID): for location in Location.objects.filter(team_id=TEAM_ID):
r['team/location'] += update_location(location, create_benchcoach_object=True, create_related=True) r['location'] += update_location(location, create_benchcoach_object=True, create_related=True)
r['member'] = [] r['member'] = []
for member in Member.objects.filter(team_id=TEAM_ID, is_non_player=False): for member in Member.objects.filter(team_id=TEAM_ID, is_non_player=False):
@@ -159,8 +144,9 @@ def sync_teamsnap_db(request):
r['event'] += update_event(event, create_benchcoach_object=True, create_related=True) r['event'] += update_event(event, create_benchcoach_object=True, create_related=True)
r['availability'] = [] r['availability'] = []
for availability in Availability.objects.filter(team_id=TEAM_ID): for availability in Availability.objects.filter(team_id=TEAM_ID, member__is_non_player=False):
r['availability'] += update_availability(availability, create_benchcoach_object=True, create_related=True) r['availability'] += update_availability(availability, create_benchcoach_object=True, create_related=True)
pass
for object_name, results in r.items(): for object_name, results in r.items():
if len(r) == 0: if len(r) == 0: