cleanup and added comments

This commit is contained in:
2022-01-03 12:12:37 -06:00
parent f6ecc934a4
commit b14c66ba0f
12 changed files with 154 additions and 683 deletions

View File

@@ -1,19 +0,0 @@
{% extends 'benchcoach/detail.html' %}
{% block navbar %}
{% with events_tab="active" %}
{{ block.super }}
{% endwith %}
{% endblock %}
{% block page_heading %}
Event
{% endblock %}
{% block rows %}
<tr><th>Date</th><td>{{ event.start.date|date }}</td></tr>
<tr><th>Time</th><td>{{ event.start.time|time }}</td></tr>
<tr><th>Away</th><td>{{ event.away_team.name }}</td></tr>
<tr><th>Home</th><td>{{ event.home_team.name }}</td></tr>
<tr><th>Venue</th><td>{{ event.venue }}</td></tr>
{% endblock %}

View File

@@ -18,7 +18,7 @@ Events
<h6>{{ event.away_team|default_if_none:"" }} vs. {{ event.home_team|default_if_none:"" }}</h6> <h6>{{ event.away_team|default_if_none:"" }} vs. {{ event.home_team|default_if_none:"" }}</h6>
{{ event.start|date:"l, F j, Y g:i A" }} <br> {{ event.start|date:"l, F j, Y g:i A" }} <br>
{{ event.venue.name }} <br> {{ event.venue.name }} <br>
<a href="{% url 'edit lineup' event_id=event.id %}">Edit Lineup...</a> <a href="{% url 'event' event_id=event.id %}">Edit Lineup...</a>
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@@ -28,18 +28,18 @@
<ul class="nav nav-tabs nav-fill bg-white" role="tablist"> <ul class="nav nav-tabs nav-fill bg-white" role="tablist">
{% if previous_event %} {% if previous_event %}
<li class="nav-item m-1"> <li class="nav-item m-1">
<a href="{% url 'edit lineup' event_id=previous_event.id active_tab=active_tab %}"> <a href="{% url 'event' event_id=previous_event.id active_tab=active_tab %}">
<i class="bi bi-chevron-left"></i>{{ previous_event.start|date:"D" }}&nbsp;{{ previous_event.start|date:"n/j" }} <i class="bi bi-chevron-left"></i>{{ previous_event.start|date:"D" }}&nbsp;{{ previous_event.start|date:"n/j" }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
<li class="nav-item m-1" role="presentation"> <li class="nav-item m-1" role="presentation">
<a id="event-details-tab" class="nav-link {% if active_tab == "details" %}active{% endif %} px-2 py-0" href="{% url 'edit lineup' event_id=event.id active_tab='details'%}">Details</a></li> <a id="event-details-tab" class="nav-link {% if active_tab == "details" %}active{% endif %} px-2 py-0" href="{% url 'event' event_id=event.id active_tab='details'%}">Details</a></li>
<li class="nav-item m-1" role="presentation"><a id="event-lineup-tab" class="nav-link {% if active_tab == "lineup" %}active{% endif %} px-2 py-0" href="{% url 'edit lineup' event_id=event.id active_tab='lineup'%}">Lineup</a></li> <li class="nav-item m-1" role="presentation"><a id="event-lineup-tab" class="nav-link {% if active_tab == "lineup" %}active{% endif %} px-2 py-0" href="{% url 'event' event_id=event.id active_tab='lineup'%}">Lineup</a></li>
{% if next_event %} {% if next_event %}
<li class="nav-item m-1"> <li class="nav-item m-1">
<a href="{% url 'edit lineup' event_id=next_event.id active_tab=active_tab%}" role="button"> <a href="{% url 'event' event_id=next_event.id active_tab=active_tab%}" role="button">
{{ next_event.start|date:"D" }}&nbsp;{{ next_event.start|date:"n/j" }}<i class="bi bi-chevron-right"></i> {{ next_event.start|date:"D" }}&nbsp;{{ next_event.start|date:"n/j" }}<i class="bi bi-chevron-right"></i>
</a> </a>
</li> </li>
@@ -68,7 +68,7 @@
</form> </form>
</div> </div>
<div id="event-lineup" class="tab-pane {% if active_tab == "lineup" %}show active{% endif %}" role="tabpanel" aria-labelledby="event-lineup-tab"> <div id="event-lineup" class="tab-pane {% if active_tab == "lineup" %}show active{% endif %}" role="tabpanel" aria-labelledby="event-lineup-tab">
<form action="{% url 'edit lineup' event_id=event.id active_tab=active_tab%}" method="post"> <form action="{% url 'event' event_id=event.id active_tab=active_tab%}" method="post">
{% csrf_token %} {% csrf_token %}
{{ formset.management_form }} {{ formset.management_form }}
<div class="row w-100"> <div class="row w-100">

View File

@@ -4,14 +4,12 @@ from django.contrib.auth.decorators import login_required
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('lineup/edit/<int:event_id>/', login_required(views.lineup_edit), name="edit lineup"),
path('lineup/edit/<int:event_id>/<str:active_tab>', login_required(views.lineup_edit), name="edit lineup"),
path('events/list/', login_required(views.EventListView.as_view()), name="event list"), path('events/list/', login_required(views.EventListView.as_view()), name="event list"),
path('events/<int:pk>/detail', login_required(views.EventDetailView.as_view()), name="event detail"), path('events/<int:event_id>/', login_required(views.event), name="event"),
path('events/<int:pk>/lineup', login_required(views.EventDetailView.as_view()), name="event lineup"),
path('players/list/', login_required(views.PlayerListView.as_view()), name="player list"), path('players/list/', login_required(views.PlayerListView.as_view()), name="player list"),
path('teams/list/', login_required(views.TeamListView.as_view()), name="team list"), path('teams/list/', login_required(views.TeamListView.as_view()), name="team list"),
path('venues/list/', login_required(views.VenueListView.as_view()), name="venue list"), path('venues/list/', login_required(views.VenueListView.as_view()), name="venue list"),
path('events/<int:event_id>/card', login_required(views.lineupcard), name="lineup card"), path('events/<int:event_id>/card', login_required(views.lineupcard), name="lineup card"),
path('events/<int:event_id>/csv', views.csv_export, name="lineup csv") path('events/<int:event_id>/csv', views.csv_export, name="lineup csv"),
path('events/<int:event_id>/<str:active_tab>', login_required(views.event), name="event")
] ]

View File

@@ -3,25 +3,30 @@ from abc import ABC, abstractmethod
import django.db.models import django.db.models
from django.db.models import QuerySet from django.db.models import QuerySet
from typing import List, Tuple from typing import List, Tuple
import benchcoach.models
class AbstractSyncEngine(ABC): class AbstractSyncEngine(ABC):
models: List[django.db.models.Model] '''
Class used for importing and syncing Bench Coach models.
'''
models: List[benchcoach.models.BenchcoachModel]
@abstractmethod @abstractmethod
def sync(self, qs: django.db.models.QuerySet = None, instance: django.db.models.Model = None, direction='download') -> List[Tuple[django.db.models.Model, bool]]: def sync(self, qs: django.db.models.QuerySet = None, instance: benchcoach.models.BenchcoachModel = None, direction='download') -> List[Tuple[django.db.models.Model, bool]]:
''' '''
Syncs the input from/to the service. Either a query set or instance should be provided, but not both. Syncs the input from/to the service. Either a query set or instance should be provided, but not both.
:param qs: the queryset to be updated. If set to 'download', it will be updated from the service, if set to uplad, its contents It does not create Bench Coach objects.
will be sent to the server :param qs: the queryset to be updated.
:param instance: the instance to be updated. If set to 'download', it will be updated from the service, if set to uplad, its contents :param instance: the instance to be updated.
will be sent to the server. :param direction: the sync direction, either 'download' or 'upload'. If set to 'download', it will be updated from the service, if set to upload, its contents
:param direction: the sync direction, either 'download' or 'upload'. will be sent to the service
:return: a list of tuples in the form of (created/updated object, true if created/false if not) :return: a list of BenchCoach objects that have been iterated (but not necessarily changed) during sync.
''' '''
@abstractmethod @abstractmethod
def import_items(self): def import_items(self):
''' '''
Imports the items from the service. Imports the items from the service. It imports all models specified in the class property 'model'.
:return: a list of tuples in the form of (created/updated object, true if created/false if not) It creates BenchCoach objects, but should not create duplicates.
:return: a list of BenchCoach objects that have been iterated (but not necessarily changed) during import.
''' '''

View File

@@ -50,7 +50,15 @@ class VenueListView(ListView):
context['venues_tab_active'] ='active' context['venues_tab_active'] ='active'
return context return context
def lineup_edit(request, event_id, active_tab='details'): def event(request, event_id, active_tab='details'):
'''
Event is the main page for showing an event.
:param request: django request
:param event_id: The Bench Coach event ID to display
:param active_tab: The desired active tab, supports "lineup" and "details"
:return: 'details' renders a page with event information, 'lineup' with lineup information.
Either gives context to the template with the event information and formset for the lineup.
'''
if request.method == "POST": if request.method == "POST":
# create a form instance and populate it with data from the request: # create a form instance and populate it with data from the request:
@@ -123,7 +131,7 @@ def lineup_edit(request, event_id, active_tab='details'):
return render( return render(
request, request,
"benchcoach/lineup.html", "benchcoach/event.html",
{ {
"title": "Lineup", "title": "Lineup",
"active_tab":active_tab, "active_tab":active_tab,
@@ -139,6 +147,13 @@ def lineup_edit(request, event_id, active_tab='details'):
) )
def lineupcard(request, event_id): def lineupcard(request, event_id):
'''
Lineup Card is an first attempt at replicating the "Lineup Card" from Google sheets.
It is incomplete.
:param request:
:param event_id: The Event ID to generate
:return: It generates a page layout. The context has info for event, event details, starting players and all players (both as a queryset)
'''
previous_event = Event.objects.filter(id=event_id - 1).first() previous_event = Event.objects.filter(id=event_id - 1).first()
event = Event.objects.get(id=event_id) event = Event.objects.get(id=event_id)
@@ -181,6 +196,13 @@ def lineupcard(request, event_id):
) )
def csv_export(request, event_id): def csv_export(request, event_id):
'''
Exports a CSV to interface with the Google Sheet. The idea is to bring lineup info into the sheet for backwards compatibility.
The row numbers follow each line as comments.
:param request:
:param event_id:
:return: A CSV file.
'''
response = HttpResponse( response = HttpResponse(
content_type='text/csv', content_type='text/csv',
headers={'Content-Disposition': f'attachment; filename=lineup-event-{event_id}.csv'}, headers={'Content-Disposition': f'attachment; filename=lineup-event-{event_id}.csv'},
@@ -201,17 +223,17 @@ def csv_export(request, event_id):
) )
rows = [] rows = []
# Row number (starts at row 2)
rows.append(event.teamsnap_event.csv_event_title) # 2 rows.append(event.teamsnap_event.csv_event_title) # 2
rows.append(event.venue.name) # 3 rows.append(event.venue.name) # 3
[rows.append('') for i in range(3)] #4-6 [rows.append('') for i in range(3)] # 4-6
p = qs.filter(position='P').first() p = qs.filter(position='P').first()
if p: if p:
rows.append(f"{p.player.last_name}, {p.player.first_name}") #7 rows.append(f"{p.player.last_name}, {p.player.first_name}") # 7
else: else:
rows.append('') rows.append('')
[rows.append('') for i in range(3)] #8-10 [rows.append('') for i in range(3)] # 8-10
for pos in ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH']: #11-19 for pos in ['C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH']: # 11-19
p = qs.filter(position=pos).first() p = qs.filter(position=pos).first()
if p: if p:
rows.append(f"{p.player.last_name}, {p.player.first_name}") rows.append(f"{p.player.last_name}, {p.player.first_name}")
@@ -220,22 +242,22 @@ def csv_export(request, event_id):
ehs = qs.filter(position='EH') ehs = qs.filter(position='EH')
if len(ehs) > 0: if len(ehs) > 0:
p=qs.filter(position='EH')[0] p=qs.filter(position='EH')[0]
rows.append(f"{p.player.last_name}, {p.player.first_name}") # 20 rows.append(f"{p.player.last_name}, {p.player.first_name}") # 20
else: else:
rows.append('') rows.append('')
if len(ehs) > 1: if len(ehs) > 1:
p=qs.filter(position='EH')[1] p=qs.filter(position='EH')[1]
rows.append(f"{p.player.last_name}, {p.player.first_name}") # 21 rows.append(f"{p.player.last_name}, {p.player.first_name}") # 21
else: else:
rows.append('') rows.append('')
rows.append('') #22 rows.append('') #22
p=qs.filter(position__isnull=False, order=0).first() p=qs.filter(position__isnull=False, order=0).first()
if p: if p:
rows.append(f"{p.player.last_name}, {p.player.first_name}") # 23 rows.append(f"{p.player.last_name}, {p.player.first_name}") # 23
else: else:
rows.append('') rows.append('')
rows.append('') rows.append('') # 24
for p in qs.filter(order__gt=0).order_by('order'): for p in qs.filter(order__gt=0).order_by('order'): # 25-34
rows.append(f"{p.player.last_name}, {p.player.first_name}") rows.append(f"{p.player.last_name}, {p.player.first_name}")
writer = csv.writer(response) writer = csv.writer(response)

View File

@@ -1,4 +1,4 @@
<form method="post" id="formSync" action="{% url 'send' %}">{% csrf_token %} <form method="post" id="formSync" action="{% url 'sync from teamsnap' %}">{% csrf_token %}
<input type="hidden" name="object_name" value="{{ object_name }}"> <input type="hidden" name="object_name" value="{{ object_name }}">
<input type="hidden" name="object_id" value={{ object_id }}> <input type="hidden" name="object_id" value={{ object_id }}>
<input type="hidden" name="next" value="{{ next }}"> <input type="hidden" name="next" value="{{ next }}">

View File

@@ -7,15 +7,7 @@ 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('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_teamsnapdb_with_teamsnapapi, name="sync with teamsnapapi"), path('sync/download', views.sync_from_teamsnap, name="sync from teamsnap"),
path('sync_benchcoach_db', views.sync_teamsnapdb_to_benchcoachdb, name="sync benchcoach"),
path('update/<str:object_name>', views.update_teamsnapdb_from_teamsnapapi, name="update"),
path('send', views.send_to_benchcoach, name="send"),
path('sync/', views.sync, name="sync"),
path('import/', views.import_teamsnap, name="import") path('import/', views.import_teamsnap, name="import")
# path('import_teamsnap', views.import_teamsnap, name="import teamsnap"),
] ]

View File

@@ -1,219 +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
from benchcoachproject.models import Profile as BenchcoachUser
import benchcoach.models
from django.db import models
import pytz
def update_teamsnap_object(d, teamsnap_object: TeamsnapBaseModel, benchcoach_model: models.Model ,create_benchcoach_object: bool = True, create_related: bool = False):
''' Function to update from a teamsnap object to Benchcoach object. This method is a simple method when there are no related objects
:param d: The information to update.
:param teamsnap_object: The teamsnap object from which to update.
:param create_benchcoach_object: If true, will create the benchcoach object if it doesn't exist
:param create_related: This is here for decoration only. It doesn't do anything.
:return: a list of tuples in the form (obj, did_create) for created or modified objects.
'''
r = []
if teamsnap_object.benchcoach_object:
#TODO I'm not sure this does anything. need to make sure.
benchcoach_object = benchcoach_model.objects.filter(id=teamsnap_object.benchcoach_object.id)
benchcoach_object.update(**d)
created = False
r.append((benchcoach_object.first(), created))
elif not teamsnap_object.benchcoach_object and create_benchcoach_object:
benchcoach_object = benchcoach_model(**d) # create new benchcoach object
teamsnap_object.benchcoach_object = benchcoach_object
benchcoach_object.save()
teamsnap_object.save()
created = True
r.append((benchcoach_object, created))
elif not teamsnap_object.benchcoach_object:
raise benchcoach.models.Team.DoesNotExist
return r
def update_event(event: Event, create_benchcoach_object: bool = True, create_related=False):
benchcoach_model = benchcoach.models.Event
d = {
'start': event.start_date,
}
r = []
if event.team:
if event.team.benchcoach_object:
if event.game_type == "Home":
d['home_team'] = event.team.benchcoach_object
elif event.game_type == "Away":
d['away_team'] = event.team.benchcoach_object
elif not event.team.benchcoach_object and create_related:
# create team object
# update_opponent
# r.append
pass
elif not event.team.benchcoach_object:
raise benchcoach.models.Team.DoesNotExist
if event.opponent:
if event.opponent.benchcoach_object:
if event.game_type == 'Home':
d['away_team'] = event.opponent.benchcoach_object
elif event.game_type == 'Away':
d['home_team'] = event.opponent.benchcoach_object
elif not event.opponent.benchcoach_object and create_related:
# Create opponent object
# update_opponent()
# r.append
pass
elif not event.opponent.benchcoach_object:
raise benchcoach.models.Team.DoesNotExist
if event.location:
if event.location.benchcoach_object:
if event.location:
d['venue'] = event.location.benchcoach_object
elif not event.location.benchcoach_object and create_related:
# Need to account for if no loacation assigned to teamsnap object.
# create team object
# update_opponent
# r.append
pass
elif not event.location.benchcoach_object:
raise benchcoach.models.Venue.DoesNotExist
r += update_teamsnap_object(d, teamsnap_object=event, benchcoach_model=benchcoach_model, create_benchcoach_object=create_benchcoach_object)
return r
def update_opponent(opponent: Opponent, create_benchcoach_object: bool = True, create_related: bool = False):
benchcoach_model = benchcoach.models.Team
d = {
'name': opponent.name,
}
r = update_teamsnap_object(d, teamsnap_object=opponent, benchcoach_model=benchcoach_model, create_benchcoach_object= create_benchcoach_object, create_related = create_related)
return r
def update_team(teamsnap_object: Team, create_benchcoach_object: bool = True, create_related: bool = False):
benchcoach_model = benchcoach.models.Team
d = {
'name': teamsnap_object.name,
}
r = update_teamsnap_object(d, teamsnap_object=teamsnap_object, benchcoach_model=benchcoach_model, create_benchcoach_object=create_benchcoach_object,
create_related=create_related)
return r
def update_location(teamsnap_object: Location, create_benchcoach_object: bool = True, create_related: bool = False):
benchcoach_model = benchcoach.models.Venue
d = {
'name': teamsnap_object.name,
}
r = update_teamsnap_object(d, teamsnap_object=teamsnap_object, benchcoach_model=benchcoach_model, create_benchcoach_object=create_benchcoach_object,
create_related=create_related)
return r
def update_member(teamsnap_object: Member, create_benchcoach_object: bool = True, create_related: bool = False):
benchcoach_model = benchcoach.models.Player
d = {
'first_name': teamsnap_object.first_name,
'last_name': teamsnap_object.last_name,
'jersey_number': teamsnap_object.jersey_number,
}
r = update_teamsnap_object(d, teamsnap_object=teamsnap_object, benchcoach_model=benchcoach_model, create_benchcoach_object=create_benchcoach_object,
create_related=create_related)
return r
def update_availability(availability: Availability, create_benchcoach_object: bool = True, create_related: bool = False):
benchcoach_model = benchcoach.models.Availability
translation = {
Availability.YES: benchcoach.models.Availability.YES,
Availability.NO: benchcoach.models.Availability.NO,
Availability.MAYBE: benchcoach.models.Availability.MAYBE
}
d = {
'available': translation.get(availability.status_code, benchcoach.models.Availability.UNKNOWN),
'player': availability.member.benchcoach_object,
'event': availability.event.benchcoach_object
}
r = []
if availability.member.benchcoach_object:
d['player'] = availability.member.benchcoach_object
elif not availability.member.benchcoach_object and create_related:
r += update_member(availability.member, create_benchcoach_object = True)
d['player'] = availability.member.benchcoach_object
elif not availability.member.benchcoach_object and not create_related:
raise benchcoach.models.Availability.DoesNotExist
if availability.event.benchcoach_object:
d['event'] = availability.event.benchcoach_object
elif not availability.event.benchcoach_object and create_related:
r += update_event(availability.member, create_benchcoach_object = True)
d['event'] = availability.event.benchcoach_object
elif not availability.event.benchcoach_object and not create_related:
raise benchcoach.models.Event.DoesNotExist
r += update_teamsnap_object(d, teamsnap_object=availability, benchcoach_model=benchcoach_model, create_benchcoach_object=create_benchcoach_object,
create_related=create_related)
return r
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(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(team_id=TEAM_ID):
l += update_location(location, create_benchcoach_object=True, create_related=True)
for member in Member.objects.filter(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(team_id=TEAM_ID):
l += update_event(event, create_benchcoach_object=True, create_related=True)
for availability in Availability.objects.filter(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__":
import_teamsnap()

View File

@@ -1,165 +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
from benchcoachproject.models import Profile as BenchcoachUser
def update_object_from_teamsnap(
TeamsnapApiObject: teamsnap.teamsnap.api.ApiObject,
TeamsnapDbModelClass: teamsnap.models.TeamsnapBaseModel,
TeamsnapClient: teamsnap.teamsnap.api.TeamSnap,
teamsnap_search_kwargs: dict,
fetching_keys: List[tuple] = ['id'],
default_keys: List[tuple] = ['name'],
related_objects: List[tuple] = []
):
"""
Import or Update database objects from TeamSnap API. Currently this depends on being run in a particular order when the database is empty.
additional_fetching_keys (key,) or (api_key, db_field_name) or (api_key, db_field_name, callable)
Additional kwargs used to fetch an object from the database. ('id', 'teamsnap_id') are already included
Callable will be run with the retrieved value as an argument. Example uses for this callable are to sanitize the value
such as for a date, or to retrieve another database object
additional_default_keys
Additional Keys used to update the object (key,) or (api_key, db_field_name) or (api_key, db_field_name, callable)
('name',) is already included
Callable will be run with the retrieved value as an argument. Example uses for this callable are to sanitize the value
such as for a date, or to retrieve another database object
:rtype: object
"""
api_response = TeamsnapApiObject.search(client=TeamsnapClient, **teamsnap_search_kwargs)
# This routine allows, for convenience, simplers tuples in which the additional detail is not needed
# for example [('key', 'key', None)] can be passed as ['key'] if the TeamsnapApi key is the same as the TeamsnapDb field/key
# and doesn't need to be sanitized
for d in [fetching_keys, fetching_keys, default_keys]:
for i, key in enumerate(d):
if isinstance(key, tuple):
if len(key) == 1:
d[i] = (key[0], key[0], None)
if len(key) == 2:
d[i] = (key[0], key[1], None)
elif isinstance(key, str):
d[i] = (key, key, None)
r = []
for related_object in related_objects:
pass
for data in [items.data for items in api_response]:
kwargs, defaults = {}, {}
for api_key, db_field_name, callable_function in fetching_keys:
if api_key in data.keys():
kwargs[db_field_name] = callable_function(data[api_key]) if callable_function else data[api_key]
for api_key, db_field_name, callable_function in default_keys:
if api_key in data.keys():
defaults[db_field_name] = callable_function(data[api_key]) if callable_function else data[api_key]
defaults ={k:v for k,v in defaults.items() if v is not None}
obj, created = TeamsnapDbModelClass.objects.update_or_create(**kwargs, defaults=defaults)
r.append((obj,created))
return r
def update_locations (client, **kwargs):
return update_object_from_teamsnap(
teamsnap.teamsnap.api.Location,
Location,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=[
'name', 'created_at', 'updated_at',
('team_id', 'managed_by_team_id')
]
)
def update_teams (client, **kwargs):
teams = update_object_from_teamsnap(
teamsnap.teamsnap.api.Team,
Team,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=[
'name', 'created_at', 'updated_at'
],
related_objects = [
('team_id', 'managed_by_team_id')
]
)
opponents = update_object_from_teamsnap(
teamsnap.teamsnap.api.Opponent,
Opponent,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys= [
'name', 'created_at', 'updated_at',
('team_id', 'managed_by_team_id')
]
)
return teams + opponents
def update_members (client, **kwargs):
return update_object_from_teamsnap(
TeamsnapApiObject=teamsnap.teamsnap.api.Member,
TeamsnapDbModelClass=Member,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=['first_name','last_name','jersey_number','is_non_player', 'created_at', 'updated_at',
('team_id', 'managed_by_team_id'),
]
)
pass
def update_availabilities(client, **kwargs):
return update_object_from_teamsnap(
TeamsnapApiObject=teamsnap.teamsnap.api.Availability,
TeamsnapDbModelClass=Availability,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=[ 'status_code',
'member_id',
'event_id',
'created_at',
'updated_at',
('team_id', 'managed_by_team_id')
]
)
def update_events(client, **kwargs):
return update_object_from_teamsnap(
TeamsnapApiObject=teamsnap.teamsnap.api.Event,
TeamsnapDbModelClass=Event,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=['formatted_title','label','points_for_opponent','points_for_team','is_game','opponent_id','location_id',
'start_date', 'created_at', 'updated_at', 'game_type',
('team_id', 'managed_by_team_id')
]
)
def update_users(client, **kwargs):
return update_object_from_teamsnap(
TeamsnapApiObject=teamsnap.teamsnap.api.User,
TeamsnapDbModelClass=User,
TeamsnapClient=client,
teamsnap_search_kwargs=kwargs,
default_keys=['first_name', 'last_name', 'email', 'created_at', 'updated_at',]
)
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)
# update_users(CLIENT, id=USER_ID)
update_teams(CLIENT, team_id=TEAM_ID)

View File

@@ -23,13 +23,23 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
self.managed_teamsnap_team_id = managed_team_teamsnap_id self.managed_teamsnap_team_id = managed_team_teamsnap_id
self.client = TeamSnap(token=teamsnap_token) self.client = TeamSnap(token=teamsnap_token)
def _bulk_sync_from_teamsnap(self, qs:QuerySet): def _bulk_sync_from_teamsnap(self, qs:QuerySet)-> List[BenchcoachModel]:
# ------------------------------------------------------------------------------------------- '''
Syncs BenchCoach instances (in the form of a QuerySet) from TeamSnap.
This function fetches the actual information from teamsnap, then hands it off to the self._update* functions.
This funciton cuts down on the number of API calls and should be speedier then doing them one by one.
Upating of models from the data is still done one by one.
:param benchcoach_instance: instance to be synced
:return: List of BenchCoach objects that have been processed (but not necessarily changed) during sync.
'''
# I hate having this translation. What I really want is just a property for "teamsnap_object" # I hate having this translation. What I really want is just a property for "teamsnap_object"
# which would simplify all this, but I couldn't figure out how to implement in the # which would simplify all this, but I couldn't figure out how to implement in the
# teamsnap model foreign key and "related_name" that didn't cause conflicts. I don't # teamsnap model foreign key and "related_name" that didn't cause conflicts. I don't
# think I need to be too much smarter to figure this out, but alas I am not smart enough. # think I need to be too much smarter to figure this out, but alas I am not smart enough.
# ------------------------------------------------------------------------------------------- if qs.model not in self.models:
raise TypeError(f"Sync engine does not sync {qs.model} models")
benchcoachmodel_to_teamsnapfield = { benchcoachmodel_to_teamsnapfield = {
Availability:'teamsnap_availability', Availability:'teamsnap_availability',
Player:'teamsnap_member', Player:'teamsnap_member',
@@ -72,14 +82,18 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
r.append(response) r.append(response)
return r return r
def _sync_from_teamsnap(self, benchcoach_instance:BenchcoachModel): def _sync_from_teamsnap(self, benchcoach_instance:BenchcoachModel)->BenchcoachModel:
'''
Syncs BenchCoach instance from TeamSnap. This function fetches the actual information from teamsnap, then
hands it off to the self._update* functions.
:param benchcoach_instance: instance to be synced
:return: BenchCoach object that has been processed (but not necessarily changed) during sync.
'''
# -------------------------------------------------------------------------------------------
# I hate having this translation. What I really want is just a property for "teamsnap_object" # I hate having this translation. What I really want is just a property for "teamsnap_object"
# which would simplify all this, but I couldn't figure out how to implement in the # which would simplify all this, but I couldn't figure out how to implement in the
# teamsnap model foreign key and "related_name" that didn't cause conflicts. I don't # teamsnap model foreign key and "related_name" that didn't cause conflicts. I don't
# think I need to be too much smarter to figure this out, but alas I am not smart enough. # think I need to be too much smarter to figure this out, but alas I am not smart enough.
# -------------------------------------------------------------------------------------------
benchcoachmodel_to_teamsnapfield = { benchcoachmodel_to_teamsnapfield = {
Availability:'teamsnap_availability', Availability:'teamsnap_availability',
Player:'teamsnap_member', Player:'teamsnap_member',
@@ -276,6 +290,12 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
return benchcoach_instance return benchcoach_instance
def _find_counterpart(self, instance): def _find_counterpart(self, instance):
'''
find the counterpart BenchCoach object from the TeamSnap object.
NOT CURRENTLY USED.
:param instance:
:return:
'''
instance_type = type(instance) instance_type = type(instance)
counterpart_instance = None counterpart_instance = None
if instance_type == Availability: if instance_type == Availability:
@@ -307,13 +327,17 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
return counterpart_instance return counterpart_instance
def _sync_qs (self, qs, direction): def _sync_qs (self, qs, direction):
if qs.model not in self.models: if direction == 'download':
raise TypeError(f"Sync engine does not sync {qs.model} models") if qs.model not in self.models:
raise TypeError(f"Sync engine does not sync {qs.model} models")
r=[] r=[]
r = self._bulk_sync_from_teamsnap(qs) r = self._bulk_sync_from_teamsnap(qs)
# for instance in qs:
# r += self._sync_instance(instance, direction=direction) elif direction == 'upload':
raise NotImplementedError('Uploading not supported by this sync engine yet.')
else:
raise TypeError(f"Direction {direction} not supported. 'upload' or 'download' must be specified")
return r return r
@@ -329,7 +353,6 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
return r return r
def sync(self, qs: django.db.models.QuerySet = None, instance: benchcoach.models.BenchcoachModel = None, def sync(self, qs: django.db.models.QuerySet = None, instance: benchcoach.models.BenchcoachModel = None,
direction='download') -> List[Tuple[django.db.models.Model, bool]]: direction='download') -> List[Tuple[django.db.models.Model, bool]]:
if not isinstance(qs, QuerySet) and not isinstance(instance, benchcoach.models.BenchcoachModel): if not isinstance(qs, QuerySet) and not isinstance(instance, benchcoach.models.BenchcoachModel):
@@ -343,30 +366,57 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
return r return r
def import_items(self, object_name=None, object_names=[]): def import_items(self):
# order is important '''
Implementation of import items from the abstract base class AbstractSyncEngine.
Imports objects from TeamSnap into BenchCoach, creating BenchCoach objects when necessary.
It runs through all supported TeamSnap Objects every execution.
NOTE: The number of availability objects causes this function to choke, so consider not updating
those on import.
:return:
'''
['team', 'opponent', 'location', 'member', 'event', 'availability'] ['team', 'opponent', 'location', 'member', 'event', 'availability']
# the common kwargs for searching the API. Most objects just need the client and currently managed team id.
kwargs = {'client':self.client,'team_id': self.managed_teamsnap_team_id} kwargs = {'client':self.client,'team_id': self.managed_teamsnap_team_id}
# r is the result dictionary, the key is the name of the benchcoach object, and the value is the list of BenchCoach objects that
# have been iterated (but not necessarily changed) during this import.
r = {} r = {}
# Walking through each TeamSnap object. There is a fair amount of repetition that could use clean-up.
# ---team--- # ---team---
r['team'] = [] r['team'] = []
# Search API for objects belonging to currently managed team, and iterate
for teamsnap_data in teamsnap.teamsnap.api.Team.search(client=self.client, id=self.managed_teamsnap_team_id): for teamsnap_data in teamsnap.teamsnap.api.Team.search(client=self.client, id=self.managed_teamsnap_team_id):
# check if TeamSnap ID already exists in the Teamsnap DB.
if teamsnap.models.Team.objects.filter(id=teamsnap_data.data['id']): if teamsnap.models.Team.objects.filter(id=teamsnap_data.data['id']):
teamsnap_instance = teamsnap.models.Team.objects.filter(id=teamsnap_data.data['id']).first() teamsnap_instance = teamsnap.models.Team.objects.filter(id=teamsnap_data.data['id']).first()
# If it does, retrieve the BenchCoach instance attached.
# It is enforced (by this import function) that every teamsnap instance has a related BenchCoach instance attached.
# No other function can create TeamSnap instances (or create related BenchCoach instances from the TeamSnap service)
benchcoach_instance = teamsnap_instance.benchcoach_object benchcoach_instance = teamsnap_instance.benchcoach_object
else: else:
# Otherwise create TeamSnap instance
teamsnap_instance = teamsnap.models.Team() teamsnap_instance = teamsnap.models.Team()
# and create related BenchCoach instance
benchcoach_instance = benchcoach.models.Team() benchcoach_instance = benchcoach.models.Team()
# and attach it to the BenchCoach instance
teamsnap_instance.benchcoach_object=benchcoach_instance teamsnap_instance.benchcoach_object=benchcoach_instance
benchcoach_instance.save() benchcoach_instance.save()
# Now, update the data from the API to the retrieved/created instances
response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data) response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
teamsnap_instance.save() teamsnap_instance.save()
response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance) response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
r['team'].append(response) r['team'].append(response)
# ---opponent--- # ---opponent---
# See first object for additional comments on the steps followed.
# Opponents from teamsnap go to the BenchCoach "Team" database.
# Dependent on Team. These objects need to be available to attach as related objects or the functions
# self._update_from teamsnapdata and self.update_teamsnapdb_to_benchcoachdb may fail.
for teamsnap_data in teamsnap.teamsnap.api.Opponent.search(**kwargs): for teamsnap_data in teamsnap.teamsnap.api.Opponent.search(**kwargs):
if teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']): if teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']):
teamsnap_instance = teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']).first() teamsnap_instance = teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']).first()
@@ -381,6 +431,9 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
r['team'].append(response) r['team'].append(response)
# ---location--- # ---location---
# See first object for additional comments on the steps followed.
# Dependent on Team. These objects need to be available to attach as related objects or the functions
# self._update_from teamsnapdata and self.update_teamsnapdb_to_benchcoachdb may fail.
r['location'] = [] r['location'] = []
for teamsnap_data in teamsnap.teamsnap.api.Location.search(**kwargs): for teamsnap_data in teamsnap.teamsnap.api.Location.search(**kwargs):
if teamsnap.models.Location.objects.filter(id=teamsnap_data.data['id']): if teamsnap.models.Location.objects.filter(id=teamsnap_data.data['id']):
@@ -397,8 +450,11 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
r['location'].append(response) r['location'].append(response)
# ---member--- # ---member---
# Note: Non players not included in sync. # See first object for additional comments on the steps followed.
# Dependent on Team. These objects need to be available to attach as related objects or the functions
# self._update_from teamsnapdata and self.update_teamsnapdb_to_benchcoachdb may fail.
r['member'] = [] r['member'] = []
# Search API for members to import. Note: Non players are not included in sync.
for teamsnap_data in teamsnap.teamsnap.api.Member.search(**kwargs, for teamsnap_data in teamsnap.teamsnap.api.Member.search(**kwargs,
is_non_player = False is_non_player = False
): ):
@@ -418,6 +474,9 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
r['member'].append(response) r['member'].append(response)
# ---event--- # ---event---
# See first object for additional comments on the steps followed.
# Dependent on Team, Opponent, Location. These objects need to be available to attach as related objects or the functions
# self._update_from teamsnapdata and self.update_teamsnapdb_to_benchcoachdb may fail.
r['event'] = [] r['event'] = []
for teamsnap_data in teamsnap.teamsnap.api.Event.search(**kwargs): for teamsnap_data in teamsnap.teamsnap.api.Event.search(**kwargs):
if teamsnap.models.Event.objects.filter(id=teamsnap_data.data['id']): if teamsnap.models.Event.objects.filter(id=teamsnap_data.data['id']):
@@ -434,8 +493,16 @@ class TeamsnapSyncEngine(AbstractSyncEngine):
r['event'].append(response) r['event'].append(response)
# ---availability--- # ---availability---
# Note: Non players not included in sync # See first object for additional comments on the steps followed.
# Availability was a bit tricky to implement, because there are "not null" contstraints for the Availability object in Bench Coach
# Ideally, there probably should be more "not null" constraints on more of the BenchCoach models, so a generalized function should
# look more like this than the ones above.
# Dependent on Team, Member, Event. These objects need to be available to attach as related objects or the functions
# self._update_from teamsnapdata and self.update_teamsnapdb_to_benchcoachdb may fail.
#TODO this import is wonky and causes errors on servers. maybe skip this import, or do it in chunks?
r['availability'] = [] r['availability'] = []
# Search API for members to import. Note: Non players are not included in sync.
player_ids = [member.id for member in teamsnap.models.Member.objects.filter(is_non_player=False)] player_ids = [member.id for member in teamsnap.models.Member.objects.filter(is_non_player=False)]
for teamsnap_data in teamsnap.teamsnap.api.Availability.search(**kwargs, for teamsnap_data in teamsnap.teamsnap.api.Availability.search(**kwargs,
member_id=",".join(player_ids) member_id=",".join(player_ids)

View File

@@ -1,33 +1,19 @@
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from .teamsnap.api import Event as TsApiEvent
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 .forms import EventForm, MemberForm, OpponentForm, TeamForm, LocationForm
from django.urls import reverse
from django.db.models import Case, When
from django.views import View
from django.http import HttpResponse from django.http import HttpResponse
import benchcoachproject.models
import benchcoach.models import benchcoach.models
from django.http import JsonResponse
from django.contrib import messages from django.contrib import messages
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 django.forms import modelformset_factory
import django.db.models
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from .utils.teamsnap_sync_engine import TeamsnapSyncEngine
def queryset_from_ids(Model, id_list):
#https://stackoverflow.com/questions/4916851/django-get-a-queryset-from-array-of-ids-in-specific-order
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(id_list)])
queryset = Model.objects.filter(pk__in=id_list).order_by(preserved)
return queryset
def edit_event(request, id): def edit_event(request, id):
'''
redirect to teamsnap.com page for editing of event.
:param request:
:param id:
:return:
'''
event = Event.objects.get(id = id) event = Event.objects.get(id = id)
return redirect(event.edit_url) return redirect(event.edit_url)
@@ -61,121 +47,8 @@ def home(request):
} }
return render(request, 'teamsnap/home.html', context) return render(request, 'teamsnap/home.html', context)
class TeamsnapObjTableView(View):
Model = None
Form = None
template = 'teamsnap/table.html'
options = {
'event': (Event, EventForm),
'location': (Location, LocationForm),
'member': (Member, MemberForm),
'opponent': (Opponent, OpponentForm),
'team': (Team, TeamForm)
}
def post(self, request, object):
self.Model, self.Form = self.options[object]
self.Formset = modelformset_factory(
model=self.Model,
form=self.Form,
extra=0
)
formset = self.Formset(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponse(200)
else:
return HttpResponse(422)
pass
def get(self, request, object):
self.Model, self.Form = self.options[object]
self.Formset = modelformset_factory(
model=self.Model,
form=self.Form,
extra=0
)
qs = self.Model.objects.all()
formset = self.Formset(queryset=qs)
return render(request, self.template, context={'formset': formset})
@login_required() @login_required()
def sync(request): def sync_from_teamsnap(request, object_name=None, object_id=None):
object_name = request.POST.get('object_name')
object_id = request.POST.get('object_id')
if request.POST and request.POST.get('object_name') and request.POST.get('object_id'):
TOKEN = request.user.profile.teamsnap_access_token
USER_ID = request.user.profile.teamsnap_user.id
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
CLIENT = TeamSnap(token=TOKEN)
object_name = request.POST.get('object_name')
object_id = request.POST.get('object_id')
Object = {
obj.__name__.lower(): obj
for obj in
[Availability, Event, LineupEntry, Location, Member, Opponent, Team]
}.get(object_name)
r={}
r[Object.__name__.lower()] = []
a = Object.ApiObject.search(CLIENT, id=object_id)
if a and len(a) == 1:
obj, created = Object.update_or_create_from_teamsnap_api(a[0].data)
r[Object.__name__.lower()].append((obj, created))
for object_name, results in r.items():
if len(results) == 0:
messages.error(request, f"Error! No {object_name} objects created or updated")
else:
result = [created for obj, created in results]
messages.success(request,
f"Success! {sum(result)} {object_name} objects created, {len(result) - sum(result)} {object_name} objects updated.")
return redirect(request.POST.get('next'))
return HttpResponse('404')
@login_required()
def update_teamsnapdb_from_teamsnapapi(request, object_name, object_id=None):
TOKEN = request.user.profile.teamsnap_access_token
USER_ID = request.user.profile.teamsnap_user.id
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
CLIENT = TeamSnap(token=TOKEN)
Object = {
obj.__name__.lower():obj
for obj in
[Availability, Event, LineupEntry, Location, Member, Opponent, Team, User]
}.get(object_name)
r = {}
for Obj in [Object]:
r[Obj.__name__.lower()] = []
if not object_id:
a = Obj.ApiObject.search(CLIENT, team_id=TEAM_ID)
for _a in a:
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
r[Obj.__name__.lower()].append((obj, created))
else:
a = Obj.ApiObject.search(CLIENT, id=object_id)[0]
obj, created = Obj.update_or_create_from_teamsnap_api(a.data)
r[Obj.__name__.lower()].append((obj, created))
for object_name, results in r.items():
if len(results) == 0:
messages.error(request, f"Error! No {object_name} objects created or updated")
else:
result = [created for obj, created in results]
messages.success(request,
f"Success! {sum(result)} {object_name} objects created, {len(result) - sum(result)} {object_name} objects updated.")
return redirect('teamsnap home')
@login_required()
def send_to_benchcoach(request, object_name=None, object_id=None): #TODO rename
if request.POST: if request.POST:
next = request.POST.get('next') next = request.POST.get('next')
object_name = request.POST.get('object_name') object_name = request.POST.get('object_name')
@@ -238,90 +111,7 @@ def send_to_benchcoach(request, object_name=None, object_id=None): #TODO rename
else: else:
return HttpResponse(404) return HttpResponse(404)
def sync_teamsnapdb_with_teamsnapapi(request):
'''
This sync the internal TeamSnap Database with the TeamSnap API
'''
TOKEN = request.user.profile.teamsnap_access_token
USER_ID = request.user.profile.teamsnap_user.id
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
CLIENT = TeamSnap(token=TOKEN)
r = {}
for Obj in [User]:
r[Obj.__name__] = []
a = Obj.ApiObject.search(CLIENT, id=USER_ID)
for _a in a:
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
r[Obj.__name__].append((obj, created))
for Obj in [Event, Availability]:
r[Obj.__name__] = []
a = Obj.ApiObject.search(CLIENT, team_id=TEAM_ID)
for _a in a:
print(f"importing {_a}")
obj, created = Obj.update_or_create_from_teamsnap_api(_a.data)
r[Obj.__name__].append((obj, created))
for object_name, results in r.items():
if len(r) == 0:
messages.error(request, f"Error! No {object_name} objects created or updated")
else:
result = [created for obj, created in results]
messages.success(request, f"Success! {sum(result)} {object_name} objects created, {len(result)-sum(result)} {object_name} objects updated.")
data = {
'msg': render_to_string('messages.html', {}, request),
}
return JsonResponse(data)
def sync_teamsnapdb_to_benchcoachdb(request):
'''
This syncs the internal BenchCoach Database and the TeamSnap Database
'''
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
r={}
r['team/opponent'] = []
for team in Opponent.objects.filter(team_id=TEAM_ID):
r['team/opponent'] += update_opponent(team, create_benchcoach_object=True, create_related=True)
for team in Team.objects.filter(id=TEAM_ID):
r['team/opponent'] += update_team(team, create_benchcoach_object=True, create_related=True)
r['location'] = []
for location in Location.objects.filter(team_id=TEAM_ID):
r['location'] += update_location(location, create_benchcoach_object=True, create_related=True)
r['member'] = []
for member in Member.objects.filter(team_id=TEAM_ID, is_non_player=False):
r['member'] += update_member(member, create_benchcoach_object=True, create_related=True)
r['event'] = []
for event in Event.objects.filter(team_id=TEAM_ID):
r['event'] += update_event(event, create_benchcoach_object=True, create_related=True)
r['availability'] = []
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)
pass
for object_name, results in r.items():
if len(r) == 0:
messages.error(request, f"Error! No {object_name} objects created or updated")
else:
result = [created for obj, created in results]
messages.success(request, f"Success! {sum(result)} {object_name} objects created, {len(result)-sum(result)} {object_name} objects updated.")
data = {
'msg': render_to_string('messages.html', {}, request),
}
return JsonResponse(data)
from .utils.teamsnap_sync_engine import TeamsnapSyncEngine
def import_teamsnap(request): def import_teamsnap(request):
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
TOKEN = request.user.profile.teamsnap_access_token TOKEN = request.user.profile.teamsnap_access_token