diff --git a/benchcoach/utils/teamsnap_sync_engine.py b/benchcoach/utils/teamsnap_sync_engine.py
deleted file mode 100644
index 4d2e7a6..0000000
--- a/benchcoach/utils/teamsnap_sync_engine.py
+++ /dev/null
@@ -1,354 +0,0 @@
-import django.db.models
-from typing import List, Tuple
-from benchcoach.models import Availability, Player, Team, Positioning, Event, Venue
-from teamsnap.teamsnap.api import TeamSnap
-import teamsnap.models
-
-from benchcoach.utils.sync_engine import AbstractSyncEngine
-
-class TeamsnapSyncEngine(AbstractSyncEngine):
- models = [
- Availability,
- Player,
- Team,
- # Positioning, # Not Implemented
- Event,
- Venue
- ]
-
- def __init__(self, managed_team_teamsnap_id, teamsnap_token):
- self.managed_teamsnap_team_id = managed_team_teamsnap_id
- self.client = TeamSnap(token=teamsnap_token)
-
- def _update_teamsnapdb_from_teamsnapapi(self, teamsnap_instance):
- ApiObject = {
- teamsnap.models.Availability:teamsnap.teamsnap.api.Availability,
- teamsnap.models.Member:teamsnap.teamsnap.api.Member,
- teamsnap.models.Team:teamsnap.teamsnap.api.Team,
- teamsnap.models.Opponent:teamsnap.teamsnap.api.Opponent,
- # teamsnap.models.LineupEntry # Not Implemented
- teamsnap.models.Event:teamsnap.teamsnap.api.Event,
- teamsnap.models.Location:teamsnap.teamsnap.api.Location
- }.get(teamsnap_instance._meta.model)
- teamsnap_model = teamsnap_instance._meta.model
- new_data = ApiObject.get(client=self.client, id=teamsnap_instance.id).data
- obj, created = self._update_or_create_from_teamsnapapi(teamsnap_model, new_data)
- return [(obj, created)]
-
- def _update_or_create_from_teamsnapapi(self, teamsnap_model, teamsnap_data, create_benchcoach_object = False):
- related_objects = {}
- fields = ['id', 'created_at', 'updated_at']
- if teamsnap_model == teamsnap.models.Event:
- fields += [
- 'label',
- 'start_date',
- 'formatted_title',
- 'points_for_opponent',
- 'points_for_team',
- 'is_game',
- 'game_type'
- ]
- if teamsnap_data.get('location_id'):
- related_objects['location'] = self._update_or_create_from_teamsnapapi(
- teamsnap.models.Location,
- {'id':teamsnap_data['location_id']}
- )
- if teamsnap_data.get('opponent_id'):
- related_objects['opponent'] = self._update_or_create_from_teamsnapapi(
- teamsnap.models.Opponent,
- {'id':teamsnap_data['opponent_id']}
- )
-
- elif teamsnap_model == teamsnap.models.Opponent:
- fields += ['name']
-
- elif teamsnap_model == teamsnap.models.Team:
- fields += ['name']
-
- elif teamsnap_model == teamsnap.models.Location:
- fields += ['name']
-
- elif teamsnap_model == teamsnap.models.Member:
- fields += [
- 'first_name',
- 'last_name',
- 'jersey_number',
- 'is_non_player'
- ]
- elif teamsnap_model == teamsnap.models.Availability:
- fields += ['status_code']
-
- related_objects['member'] = self._update_or_create_from_teamsnapapi(
- teamsnap.models.Member,
- {'id': teamsnap_data['member_id']}
- )
-
- related_objects['event'] = self._update_or_create_from_teamsnapapi(
- teamsnap.models.Event,
- {'id': teamsnap_data['event_id']}
- )
-
- else:
- raise ValueError
-
- if teamsnap_data.get('team_id'):
- related_objects['team'] = self._update_or_create_from_teamsnapapi(teamsnap.models.Team,
- {"id":teamsnap_data['team_id']})
-
- data = {field: teamsnap_data[field] for field in fields if teamsnap_data.get(field) != None}
- id = data.pop('id')
- instance, created = teamsnap_model.objects.update_or_create(id=id, defaults=data)
- r_related_objects = []
- for related_object_name, related_objectcreated_list in related_objects.items():
- related_object, created = related_objectcreated_list[0] #FIXME This can't be right, do we need a list for related?
- setattr(instance, related_object_name, related_object)
- r_related_objects.append((related_object, created))
- instance.save()
- # if create_benchcoach_object:
- # ben
- return [(instance, created)] + r_related_objects
-
- def _update_teamsnapdb_to_benchcoachdb(self, benchcoach_instance, teamsnap_instance,
- create_if_doesnt_exist: bool = False) -> List[Tuple[django.db.models.Model, bool]]:
- ''' Function to update from a teamsnap object to Benchcoach object.
-
- :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.
- '''
-
- if isinstance(teamsnap_instance, teamsnap.models.Event):
- benchcoach_model = Event
-
- d = {
- 'start': teamsnap_instance.start_date,
- }
-
- if teamsnap_instance.team:
- if teamsnap_instance.team.benchcoach_object:
- if teamsnap_instance.game_type == "Home":
- d['home_team'] = teamsnap_instance.team.benchcoach_object
- elif teamsnap_instance.game_type == "Away":
- d['away_team'] = teamsnap_instance.team.benchcoach_object
- elif not teamsnap_instance.team.benchcoach_object:
- raise Team.DoesNotExist
-
- if teamsnap_instance.opponent:
- if teamsnap_instance.opponent.benchcoach_object:
- if teamsnap_instance.game_type == 'Home':
- d['away_team'] = teamsnap_instance.opponent.benchcoach_object
- elif teamsnap_instance.game_type == 'Away':
- d['home_team'] = teamsnap_instance.opponent.benchcoach_object
- elif not teamsnap_instance.opponent.benchcoach_object:
- raise Team.DoesNotExist
-
- if teamsnap_instance.location:
- if teamsnap_instance.location.benchcoach_object:
- if teamsnap_instance.location:
- d['venue'] = teamsnap_instance.location.benchcoach_object
- elif not teamsnap_instance.location.benchcoach_object:
- raise Venue.DoesNotExist
-
- elif isinstance(teamsnap_instance, teamsnap.models.Opponent):
- benchcoach_model = Team
- d = {
- 'name': teamsnap_instance.name,
- }
-
- elif isinstance(teamsnap_instance, teamsnap.models.Team):
- benchcoach_model = Team
- d = {
- 'name': teamsnap_instance.name,
- }
-
- elif isinstance(teamsnap_instance, teamsnap.models.Location):
- benchcoach_model = Venue
- d = {
- 'name': teamsnap_instance.name,
- }
-
- elif isinstance(teamsnap_instance, teamsnap.models.Member):
- benchcoach_model = Player
- d = {
- 'first_name': teamsnap_instance.first_name,
- 'last_name': teamsnap_instance.last_name,
- 'jersey_number': teamsnap_instance.jersey_number,
- }
-
- elif isinstance(teamsnap_instance, teamsnap.models.Availability):
- benchcoach_model = Availability
-
- translation = {
- teamsnap_instance.YES: Availability.YES,
- teamsnap_instance.NO: Availability.NO,
- teamsnap_instance.MAYBE: Availability.MAYBE
- }
-
- d = {
- 'available': translation.get(teamsnap_instance.status_code, Availability.UNKNOWN),
- 'player': teamsnap_instance.member.benchcoach_object,
- 'event': teamsnap_instance.event.benchcoach_object
- }
-
- r = []
-
- if teamsnap_instance.member.benchcoach_object:
- d['player'] = teamsnap_instance.member.benchcoach_object
- elif not teamsnap_instance.member.benchcoach_object:
- raise Availability.DoesNotExist
-
- if teamsnap_instance.event.benchcoach_object:
- d['event'] = teamsnap_instance.event.benchcoach_object
- elif not teamsnap_instance.event.benchcoach_object:
- raise Event.DoesNotExist
-
- else:
- raise ValueError
-
- r=[]
- if teamsnap_instance.benchcoach_object:
- benchcoach_object = benchcoach_model.objects.filter(id=teamsnap_instance.benchcoach_object.id)
- benchcoach_object.update(**d)
- created = False
- r.append((benchcoach_object.first(), created))
- # elif not teamsnap_instance.benchcoach_object and create_if_doesnt_exist:
- elif not teamsnap_instance.benchcoach_object:
- raise django.db.models.Model.DoesNotExist
-
- return r
-
- def _find_counterpart(self, instance):
- instance_type = type(instance)
- if instance_type == Availability:
- counterpart_instance = instance.teamsnap_availability
-
- elif instance_type == Player:
- counterpart_instance = instance.teamsnap_member
-
- elif instance_type == Event:
- counterpart_instance = instance.teamsnap_event
-
- elif instance_type == Venue:
- counterpart_instance = instance.teamsnap_location
-
- elif instance_type == Team:
- if hasattr(instance, 'teamsnap_opponent'):
- counterpart_instance = instance.teamsnap_opponent
- elif hasattr(instance, 'teamsnap_team'):
- counterpart_instance = instance.teamsnap_team
- else:
- raise ValueError("instance doesn't seem to be an teamsnap opponent or a teamsnap team")
-
- elif instance_type == Positioning:
- counterpart_instance = instance.teamsnap_lineupentry
-
- if not counterpart_instance: raise Exception()
-
- return counterpart_instance
-
- def _fetch_new_data(self, instance):
- api_object = instance.ApiObject.get(client=self.client, id=instance.id)
- return api_object.data
-
- def _fetch_sync(self, instance):
- r=[]
- counterpart_instance = self._find_counterpart(instance)
- r += self._update_teamsnapdb_from_teamsnapapi(counterpart_instance)
- r += self._update_teamsnapdb_to_benchcoachdb(instance, counterpart_instance)
- return r
-
- def _sync_qs (self, qs, direction):
- if qs.model not in self.models:
- raise TypeError(f"Sync engine does not sync {qs.model} models")
-
- r=[]
-
- for instance in qs:
- r += self._sync_instance(instance, direction=direction)
-
- return r
-
- def _sync_instance(self, instance, direction, data=None):
- r=[]
- if direction == 'download':
- r += self._fetch_sync(instance)
-
- 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
-
-
- def sync(self, qs: django.db.models.QuerySet = None, instance: django.db.models.Model = None,
- direction='download') -> List[Tuple[django.db.models.Model, bool]]:
- if not qs and not instance:
- raise TypeError(f"sync requires either a QuerySet or model instance to be provided")
- if qs and instance:
- raise TypeError(f"sync requires either a QuerySet or model instance to be provided, but not both")
- elif qs:
- r = self._sync_qs(qs, direction)
- elif instance:
- r = self._sync_instance(instance, direction)
-
- return r
-
- def import_items(self, object_name):
- object_names = []
- if object_name == 'team':
- object_names += ['opponent', 'team']
- elif object_name == 'player':
- object_names = ['member']
- elif object_name == 'venue':
- object_name == ['location']
- elif object_name in [model.__name__.lower() for model in self.models]:
- object_names += [object_name]
-
- if len(object_names) == 0:
- raise ValueError('no valid keyword provided')
-
- for object_name in object_names:
- Object = {
- obj.__name__.lower(): obj
- for obj in
- [
- teamsnap.models.Availability,
- teamsnap.models.Event,
- # teamsnap.models.LineupEntry,
- teamsnap.models.Location,
- teamsnap.models.Member,
- teamsnap.models.Opponent,
- teamsnap.models.Team,
- # teamsnap.models.User
- ]
- }.get(object_name)
-
- ApiObject = {
- apiobj.__name__.lower(): apiobj
- for apiobj in
- [
- teamsnap.teamsnap.api.Availability,
- teamsnap.teamsnap.api.Event,
- # teamsnap.teamsnap.api.LineupEntry,
- teamsnap.teamsnap.api.Location,
- teamsnap.teamsnap.api.Member,
- teamsnap.teamsnap.api.Opponent,
- teamsnap.teamsnap.api.Team,
- # teamsnap.teamsnap.api.User
- ]
- }.get(object_name)
-
- pass
-
- if not Object: raise KeyError(f"key {object_name} not found.")
- r = []
-
- a = ApiObject.search(self.client, team_id=self.managed_teamsnap_team_id)
- for _a in a:
- response = self._update_or_create_from_teamsnapapi(Object, _a.data)
- r += response
-
- return r
\ No newline at end of file
diff --git a/benchcoach/utils/test_sync.py b/benchcoach/utils/test_sync.py
deleted file mode 100644
index b1ccf50..0000000
--- a/benchcoach/utils/test_sync.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from django.test import TestCase
-import os
-
-from benchcoach.utils.teamsnap_sync_engine import TeamsnapSyncEngine
-
-import benchcoach.models
-
-TEAMSNAP_TOKEN = os.environ['TEAMSNAP_TOKEN']
-TEAM_TEAMSNAP_ID = os.environ['TEAM_TEAMSNAP_ID']
-
-syncengine = TeamsnapSyncEngine(managed_team_teamsnap_id=TEAM_TEAMSNAP_ID, teamsnap_token=TEAMSNAP_TOKEN)
-r=syncengine.import_items('event')
-pass
-
-class TestEventModel(TestCase):
- fixtures = ['minimal']
-
- def setUp(self):
- self.syncengine = TeamsnapSyncEngine(managed_team_teamsnap_id=TEAM_TEAMSNAP_ID, teamsnap_token=TEAMSNAP_TOKEN)
-
- def test_all_models(self):
- for Model in self.syncengine.models:
- with self.subTest():
- self.syncengine.import_items(Model.__name__.lower())
- pass
\ No newline at end of file
diff --git a/teamsnap/models.py b/teamsnap/models.py
index 40a01c9..e00027d 100644
--- a/teamsnap/models.py
+++ b/teamsnap/models.py
@@ -25,8 +25,6 @@ class Team(TeamsnapBaseModel):
name = models.CharField(max_length=50, null=True)
benchcoach_object = models.OneToOneField(
benchcoach.models.Team,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_team"
)
@@ -74,8 +72,6 @@ class Opponent(TeamsnapManagedObjectModel):
name = models.CharField(max_length=50, null=True)
benchcoach_object = models.OneToOneField(
benchcoach.models.Team,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_opponent"
)
@@ -86,8 +82,6 @@ class Location(TeamsnapManagedObjectModel):
name = models.CharField(max_length=50, null=True)
benchcoach_object = models.OneToOneField(
benchcoach.models.Venue,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_location"
)
@@ -101,8 +95,6 @@ class Member(TeamsnapManagedObjectModel):
name = models.CharField(max_length=50, null=True)
benchcoach_object = models.OneToOneField(
benchcoach.models.Player,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_member"
)
@@ -126,8 +118,6 @@ class Event(TeamsnapManagedObjectModel):
type = 'event'
benchcoach_object = models.OneToOneField(
benchcoach.models.Event,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_event"
)
@@ -161,8 +151,6 @@ class Availability(TeamsnapManagedObjectModel):
member = models.ForeignKey(Member, null=True, on_delete=models.CASCADE)
benchcoach_object = models.OneToOneField(
benchcoach.models.Availability,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_availability"
)
@@ -193,8 +181,6 @@ class LineupEntry(TeamsnapManagedObjectModel):
]
benchcoach_object = models.OneToOneField(
benchcoach.models.Positioning,
- null=True,
- blank=True,
on_delete=models.CASCADE,
related_name="teamsnap_lineupentry"
)
diff --git a/teamsnap/templates/teamsnap/home.html b/teamsnap/templates/teamsnap/home.html
index 301a8a3..df837ab 100644
--- a/teamsnap/templates/teamsnap/home.html
+++ b/teamsnap/templates/teamsnap/home.html
@@ -9,6 +9,10 @@
{% include 'messages.html' %}
+
+ Import
+
+
{% for obj_name, obj_data in teamsnap_objects.items %}
@@ -17,11 +21,8 @@
| {{ obj_data.object_count }} |
{{ obj_data.counterpart.name }} |
{{ obj_data.counterpart.object_count }} |
-
-
- |
-
-
+ |
+ Sync
|
{% endfor %}
diff --git a/teamsnap/urls.py b/teamsnap/urls.py
index 94aace3..264e8fc 100644
--- a/teamsnap/urls.py
+++ b/teamsnap/urls.py
@@ -15,6 +15,7 @@ urlpatterns = [
path('sync_benchcoach_db', views.sync_teamsnapdb_to_benchcoachdb, name="sync benchcoach"),
path('update/', views.update_teamsnapdb_from_teamsnapapi, name="update"),
path('send/', views.send_to_benchcoach, name="send"),
- path('sync/', views.sync, name="sync")
+ path('sync/', views.sync, name="sync"),
+ path('import/', views.import_teamsnap, name="import")
# path('import_teamsnap', views.import_teamsnap, name="import teamsnap"),
]
\ No newline at end of file
diff --git a/teamsnap/utils/teamsnap_sync_engine.py b/teamsnap/utils/teamsnap_sync_engine.py
new file mode 100644
index 0000000..ef1e386
--- /dev/null
+++ b/teamsnap/utils/teamsnap_sync_engine.py
@@ -0,0 +1,457 @@
+import django.db.models
+from typing import List, Tuple
+
+import benchcoach.models
+from benchcoach.models import BenchcoachModel, Availability, Player, Team, Positioning, Event, Venue
+from teamsnap.teamsnap.api import TeamSnap
+import teamsnap.models
+from django.db.models import QuerySet
+
+from benchcoach.utils.sync_engine import AbstractSyncEngine
+
+class TeamsnapSyncEngine(AbstractSyncEngine):
+ models = [
+ Availability,
+ Player,
+ Team,
+ # Positioning, # Not Implemented
+ Event,
+ Venue
+ ]
+
+ def __init__(self, managed_team_teamsnap_id, teamsnap_token):
+ self.managed_teamsnap_team_id = managed_team_teamsnap_id
+ self.client = TeamSnap(token=teamsnap_token)
+
+ def _bulk_sync_from_teamsnap(self, qs:QuerySet):
+ # -------------------------------------------------------------------------------------------
+ # 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
+ # 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.
+ # -------------------------------------------------------------------------------------------
+ benchcoachmodel_to_teamsnapfield = {
+ Availability:'teamsnap_availability',
+ Player:'teamsnap_member',
+ Team:'teamsnap_opponent',
+ # Positioning:'teamsnap_lineupentry', # Not Implemented Yet, but will be 'teamsnap_lineupentry'
+ Event:'teamsnap_event',
+ Venue:'teamsnap_location'
+ }
+
+ teamsnapmodel_to_apiobject = {
+ teamsnap.models.Availability: teamsnap.teamsnap.api.Availability,
+ teamsnap.models.Event: teamsnap.teamsnap.api.Event,
+ # teamsnap.models.LineupEntry:teamsnap.teamsnap.api.LineupEntry, # Not implemented Yet
+ teamsnap.models.Location: teamsnap.teamsnap.api.Location,
+ teamsnap.models.Member: teamsnap.teamsnap.api.Member,
+ teamsnap.models.Opponent: teamsnap.teamsnap.api.Opponent,
+ teamsnap.models.Team: teamsnap.teamsnap.api.Team,
+ # teamsnap.models.User:teamsnap.teamsnap.api.User # Not implemented yet
+ }
+
+ apiobject_to_teamsnapmodel = {v:k for k,v in teamsnapmodel_to_apiobject.items()}
+
+ if isinstance(qs.first(), benchcoach.models.Team):
+ # This situation requires special attention because opponents and teams share a table in BenchCoach
+ if getattr(qs.first(), 'teamsnap_team', None):
+ teamsnap_attribute_name = 'teamsnap_team'
+ elif getattr(qs.first(), 'teamsnap_opponent', None):
+ teamsnap_attribute_name = 'teamsnap_opponent'
+ else:
+ teamsnap_attribute_name = benchcoachmodel_to_teamsnapfield.get(type(qs.first()))
+
+ ids = [getattr(i, teamsnap_attribute_name).id for i in qs]
+ ApiObject = teamsnapmodel_to_apiobject.get(type(getattr(qs.first(), teamsnap_attribute_name)))
+ api_responses = ApiObject.search(client=self.client, id=",".join(ids))
+ r = []
+ for api_response in api_responses:
+ teamsnap_instance = apiobject_to_teamsnapmodel.get(type(api_response)).objects.get(id=api_response.data['id'])
+ response = self._update_from_teamsnapdata(teamsnap_instance, api_response)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, teamsnap_instance.benchcoach_object)
+ r.append(response)
+ return r
+
+ def _sync_from_teamsnap(self, benchcoach_instance:BenchcoachModel):
+
+ # -------------------------------------------------------------------------------------------
+ # 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
+ # 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.
+ # -------------------------------------------------------------------------------------------
+ benchcoachmodel_to_teamsnapfield = {
+ Availability:'teamsnap_availability',
+ Player:'teamsnap_member',
+ Team:'teamsnap_opponent',
+ # Positioning:'teamsnap_lineupentry', # Not Implemented Yet, but will be 'teamsnap_lineupentry'
+ Event:'teamsnap_event',
+ Venue:'teamsnap_location'
+ }
+
+ teamsnapmodel_to_apiobject = {
+ teamsnap.models.Availability: teamsnap.teamsnap.api.Availability,
+ teamsnap.models.Event: teamsnap.teamsnap.api.Event,
+ # teamsnap.models.LineupEntry:teamsnap.teamsnap.api.LineupEntry, # Not implemented Yet
+ teamsnap.models.Location: teamsnap.teamsnap.api.Location,
+ teamsnap.models.Member: teamsnap.teamsnap.api.Member,
+ teamsnap.models.Opponent: teamsnap.teamsnap.api.Opponent,
+ teamsnap.models.Team: teamsnap.teamsnap.api.Team,
+ # teamsnap.models.User:teamsnap.teamsnap.api.User # Not implemented yet
+ }
+
+ if isinstance(benchcoach_instance, benchcoach.models.Team):
+ # This situation requires special attention because opponents and teams share a table in BenchCoach
+ teamsnap_instance = getattr(benchcoach_instance, 'teamsnap_team', None)
+ if not teamsnap_instance: teamsnap_instance = getattr(benchcoach_instance, 'teamsnap_opponent')
+ else:
+ teamsnap_instance = getattr(benchcoach_instance, benchcoachmodel_to_teamsnapfield.get(type(benchcoach_instance)))
+
+ ApiObject = teamsnapmodel_to_apiobject.get(type(teamsnap_instance))
+ api_response = ApiObject.get(self.client, teamsnap_instance.id)
+
+ r = self._update_from_teamsnapdata(teamsnap_instance, api_response)
+ r = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ return r
+
+ def _update_from_teamsnapdata(self, teamsnap_instance:teamsnap.models.TeamsnapBaseModel, teamsnap_data: teamsnap.teamsnap.api.ApiObject) -> teamsnap.models.TeamsnapBaseModel:
+ ''''''
+ if isinstance(teamsnap_data, teamsnap.teamsnap.api.ApiObject):
+ teamsnap_data = teamsnap_data.data
+ else:
+ raise TypeError
+ if not teamsnap_data['type'] == teamsnap_instance.type:
+ raise Exception()
+ data_type = teamsnap_data['type']
+ fields = ['id', 'created_at', 'updated_at']
+ related_objects = {}
+ if data_type in ['opponent', 'team', 'location']:
+ fields += ['name']
+ elif data_type == 'event':
+ fields += [
+ 'label',
+ 'start_date',
+ 'formatted_title',
+ 'points_for_opponent',
+ 'points_for_team',
+ 'is_game',
+ 'game_type'
+ ]
+ if teamsnap_data.get('location_id'):
+ related_objects['location'] = teamsnap.models.Location.objects.get(id=teamsnap_data['location_id'])
+ if teamsnap_data.get('opponent_id'):
+ related_objects['opponent'] = teamsnap.models.Opponent.objects.get(id=teamsnap_data['opponent_id'])
+ pass
+
+ elif data_type == 'member':
+ fields += [
+ 'first_name',
+ 'last_name',
+ 'jersey_number',
+ 'is_non_player'
+ ]
+
+ elif data_type == 'availability':
+ fields += ['status_code']
+ related_objects['member'] = teamsnap.models.Member.objects.get(id=teamsnap_data['member_id'])
+ related_objects['event'] = teamsnap.models.Event.objects.get(id=teamsnap_data['event_id'])
+
+ else:
+ raise ValueError
+
+ if teamsnap_data.get('team_id'):
+ related_objects['team'] = teamsnap.models.Team.objects.filter(id=teamsnap_data['team_id']).first()
+
+ for field in fields:
+ value = teamsnap_data.get(field)
+ # if value is None:
+ # continue
+ # else:
+ setattr(teamsnap_instance,field,value)
+
+ for related_object_name, related_object in related_objects.items():
+ setattr(teamsnap_instance, related_object_name, related_object)
+
+ teamsnap_instance.save()
+
+ return teamsnap_instance
+
+ def _update_teamsnapdb_to_benchcoachdb(self, teamsnap_instance, benchcoach_instance) -> List[Tuple[django.db.models.Model, bool]]:
+
+ if isinstance(teamsnap_instance, teamsnap.models.Event):
+ benchcoach_model = Event
+
+ d = {
+ 'start': teamsnap_instance.start_date,
+ }
+
+ if teamsnap_instance.team:
+ if teamsnap_instance.team.benchcoach_object:
+ if teamsnap_instance.game_type == "Home":
+ d['home_team'] = teamsnap_instance.team.benchcoach_object
+ elif teamsnap_instance.game_type == "Away":
+ d['away_team'] = teamsnap_instance.team.benchcoach_object
+ elif not teamsnap_instance.team.benchcoach_object:
+ raise Team.DoesNotExist
+
+ if teamsnap_instance.opponent:
+ if teamsnap_instance.opponent.benchcoach_object:
+ if teamsnap_instance.game_type == 'Home':
+ d['away_team'] = teamsnap_instance.opponent.benchcoach_object
+ elif teamsnap_instance.game_type == 'Away':
+ d['home_team'] = teamsnap_instance.opponent.benchcoach_object
+ elif not teamsnap_instance.opponent.benchcoach_object:
+ raise Team.DoesNotExist
+ pass
+
+ if teamsnap_instance.location:
+ if teamsnap_instance.location.benchcoach_object:
+ if teamsnap_instance.location:
+ d['venue'] = teamsnap_instance.location.benchcoach_object
+ elif not teamsnap_instance.location.benchcoach_object:
+ raise Venue.DoesNotExist
+
+ elif isinstance(teamsnap_instance, teamsnap.models.Opponent):
+ benchcoach_model = Team
+ d = {
+ 'name': teamsnap_instance.name,
+ }
+
+ elif isinstance(teamsnap_instance, teamsnap.models.Team):
+ benchcoach_model = Team
+ d = {
+ 'name': teamsnap_instance.name,
+ }
+
+ elif isinstance(teamsnap_instance, teamsnap.models.Location):
+ benchcoach_model = Venue
+ d = {
+ 'name': teamsnap_instance.name,
+ }
+
+ elif isinstance(teamsnap_instance, teamsnap.models.Member):
+ benchcoach_model = Player
+ d = {
+ 'first_name': teamsnap_instance.first_name,
+ 'last_name': teamsnap_instance.last_name,
+ 'jersey_number': teamsnap_instance.jersey_number,
+ }
+
+ elif isinstance(teamsnap_instance, teamsnap.models.Availability):
+ benchcoach_model = Availability
+
+ translation = {
+ teamsnap_instance.YES: Availability.YES,
+ teamsnap_instance.NO: Availability.NO,
+ teamsnap_instance.MAYBE: Availability.MAYBE
+ }
+
+ d = {
+ 'available': translation.get(teamsnap_instance.status_code, Availability.UNKNOWN),
+ 'player': teamsnap_instance.member.benchcoach_object,
+ 'event': teamsnap_instance.event.benchcoach_object
+ }
+
+ r = []
+
+ if teamsnap_instance.member.benchcoach_object:
+ d['player'] = teamsnap_instance.member.benchcoach_object
+ elif not teamsnap_instance.member.benchcoach_object:
+ raise Player.DoesNotExist
+
+ if teamsnap_instance.event.benchcoach_object:
+ d['event'] = teamsnap_instance.event.benchcoach_object
+ elif not teamsnap_instance.event.benchcoach_object:
+ raise Event.DoesNotExist
+
+ else:
+ raise ValueError
+
+ for field, value in d.items():
+ setattr(benchcoach_instance, field, value)
+
+ benchcoach_instance.save()
+ teamsnap_instance.benchcoach_object = benchcoach_instance
+ teamsnap_instance.save()
+ return benchcoach_instance
+
+ def _find_counterpart(self, instance):
+ instance_type = type(instance)
+ counterpart_instance = None
+ if instance_type == Availability:
+ counterpart_instance = instance.teamsnap_availability
+
+ elif instance_type == Player:
+ counterpart_instance = instance.teamsnap_member
+
+ elif instance_type == Event:
+ counterpart_instance = instance.teamsnap_event
+
+ elif instance_type == Venue:
+ counterpart_instance = instance.teamsnap_location
+
+ elif instance_type == Team:
+ if hasattr(instance, 'teamsnap_opponent'):
+ counterpart_instance = instance.teamsnap_opponent
+ elif hasattr(instance, 'teamsnap_team'):
+ counterpart_instance = instance.teamsnap_team
+ else:
+ raise ValueError("instance doesn't seem to be an teamsnap opponent or a teamsnap team")
+
+ elif instance_type == Positioning:
+ counterpart_instance = instance.teamsnap_lineupentry
+
+ else:
+ raise Exception()
+
+ return counterpart_instance
+
+ def _sync_qs (self, qs, direction):
+ if qs.model not in self.models:
+ raise TypeError(f"Sync engine does not sync {qs.model} models")
+
+ r=[]
+ r = self._bulk_sync_from_teamsnap(qs)
+ # for instance in qs:
+ # r += self._sync_instance(instance, direction=direction)
+
+ return r
+
+ def _sync_instance(self, instance, direction, data=None):
+ r=[]
+ if direction == 'download':
+ r.append(self._sync_from_teamsnap(instance))
+
+ 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
+
+
+ def sync(self, qs: django.db.models.QuerySet = None, instance: django.db.models.Model = None,
+ direction='download') -> List[Tuple[django.db.models.Model, bool]]:
+ if not qs and not instance:
+ raise TypeError(f"sync requires either a QuerySet or model instance to be provided")
+ if qs and instance:
+ raise TypeError(f"sync requires either a QuerySet or model instance to be provided, but not both")
+ elif qs:
+ r = self._sync_qs(qs, direction)
+ elif instance:
+ r = self._sync_instance(instance, direction)
+
+ return r
+
+ def import_items(self, object_name=None, object_names=[]):
+ # order is important
+
+ ['team', 'opponent', 'location', 'member', 'event', 'availability']
+ kwargs = {'client':self.client,'team_id': self.managed_teamsnap_team_id}
+ r = {}
+
+ # ---team---
+ r['team'] = []
+ for teamsnap_data in teamsnap.teamsnap.api.Team.search(client=self.client, id=self.managed_teamsnap_team_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()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Team()
+ benchcoach_instance = benchcoach.models.Team()
+ teamsnap_instance.benchcoach_object=benchcoach_instance
+ benchcoach_instance.save()
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ teamsnap_instance.save()
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['team'].append(response)
+
+ # ---opponent---
+ for teamsnap_data in teamsnap.teamsnap.api.Opponent.search(**kwargs):
+ if teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']):
+ teamsnap_instance = teamsnap.models.Opponent.objects.filter(id=teamsnap_data.data['id']).first()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Opponent()
+ benchcoach_instance = benchcoach.models.Team()
+ teamsnap_instance.benchcoach_object = benchcoach_instance
+ benchcoach_instance.save()
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['team'].append(response)
+
+ # ---location---
+ r['location'] = []
+ for teamsnap_data in teamsnap.teamsnap.api.Location.search(**kwargs):
+ if teamsnap.models.Location.objects.filter(id=teamsnap_data.data['id']):
+ teamsnap_instance = teamsnap.models.Location.objects.filter(id=teamsnap_data.data['id']).first()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Location()
+ benchcoach_instance = benchcoach.models.Venue()
+ teamsnap_instance.benchcoach_object = benchcoach_instance
+ benchcoach_instance.save()
+
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['location'].append(response)
+
+ # ---member---
+ # Note: Non players not included in sync.
+ r['member'] = []
+ for teamsnap_data in teamsnap.teamsnap.api.Member.search(**kwargs,
+ is_non_player = False
+ ):
+ if teamsnap_data.data['is_non_player'] == True:
+ continue
+ if teamsnap.models.Member.objects.filter(id=teamsnap_data.data['id']):
+ teamsnap_instance = teamsnap.models.Member.objects.filter(id=teamsnap_data.data['id']).first()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Member()
+ benchcoach_instance = benchcoach.models.Player()
+ teamsnap_instance.benchcoach_object = benchcoach_instance
+ benchcoach_instance.save()
+
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['member'].append(response)
+
+ # ---event---
+ r['event'] = []
+ for teamsnap_data in teamsnap.teamsnap.api.Event.search(**kwargs):
+ if teamsnap.models.Event.objects.filter(id=teamsnap_data.data['id']):
+ teamsnap_instance = teamsnap.models.Event.objects.filter(id=teamsnap_data.data['id']).first()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Event()
+ benchcoach_instance = benchcoach.models.Event()
+ teamsnap_instance.benchcoach_object = benchcoach_instance
+ benchcoach_instance.save()
+
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['event'].append(response)
+
+ # ---availability---
+ # Note: Non players not included in sync
+ r['availability'] = []
+ 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,
+ member_id=",".join(player_ids)
+ ):
+ if teamsnap.models.Availability.objects.filter(id=teamsnap_data.data['id']):
+ teamsnap_instance = teamsnap.models.Availability.objects.filter(id=teamsnap_data.data['id']).first()
+ benchcoach_instance = teamsnap_instance.benchcoach_object
+ else:
+ teamsnap_instance = teamsnap.models.Availability()
+ event_instance = benchcoach.models.Event.objects.get(teamsnap_event__id=teamsnap_data.data['event_id'])
+ player_instance = benchcoach.models.Player.objects.get(teamsnap_member__id=teamsnap_data.data['member_id'])
+ benchcoach_instance = benchcoach.models.Availability(event=event_instance, player=player_instance)
+ benchcoach_instance.save()
+ teamsnap_instance.benchcoach_object_id = benchcoach_instance.id
+ response = self._update_from_teamsnapdata(teamsnap_instance, teamsnap_data)
+ response = self._update_teamsnapdb_to_benchcoachdb(teamsnap_instance, benchcoach_instance)
+ r['availability'].append(response)
+
+ return r
\ No newline at end of file
diff --git a/teamsnap/utils/test_sync.py b/teamsnap/utils/test_sync.py
new file mode 100644
index 0000000..bf5a3b2
--- /dev/null
+++ b/teamsnap/utils/test_sync.py
@@ -0,0 +1,51 @@
+from django.test import TestCase
+import os
+
+from teamsnap.utils.teamsnap_sync_engine import TeamsnapSyncEngine
+
+import benchcoach.models
+import teamsnap.models
+
+TEAMSNAP_TOKEN = os.environ['TEAMSNAP_TOKEN']
+TEAM_TEAMSNAP_ID = os.environ['TEAM_TEAMSNAP_ID']
+
+pass
+
+# syncengine = TeamsnapSyncEngine(managed_team_teamsnap_id=TEAM_TEAMSNAP_ID, teamsnap_token=TEAMSNAP_TOKEN)
+# r = syncengine.import_items()
+
+class TestSync(TestCase):
+ fixtures = ['minimal']
+
+ def setUp(self):
+ self.syncengine = TeamsnapSyncEngine(managed_team_teamsnap_id=TEAM_TEAMSNAP_ID, teamsnap_token=TEAMSNAP_TOKEN)
+ r = self.syncengine.import_items()
+ pass
+
+ def test_syncengine(self):
+ # test that the import can be run again
+ r = self.syncengine.import_items()
+ benchcoach_objects = {
+ 'availability': list(benchcoach.models.Availability.objects.all()),
+ 'event': list(benchcoach.models.Event.objects.all()),
+ 'player': list(benchcoach.models.Player.objects.all()),
+ 'positioning': list(benchcoach.models.Positioning.objects.all()),
+ 'team': list(benchcoach.models.Team.objects.all()),
+ 'venue': list(benchcoach.models.Venue.objects.all())
+ }
+ teamsnap_objects = {
+ 'availability': list(teamsnap.models.Availability.objects.all()),
+ 'event': list(teamsnap.models.Event.objects.all()),
+ 'member': list(teamsnap.models.Member.objects.all()),
+ 'lineupentry': list(teamsnap.models.LineupEntry.objects.all()),
+ 'team': list(teamsnap.models.Team.objects.all()),
+ 'opponent': list(teamsnap.models.Opponent.objects.all()),
+ 'location': list(teamsnap.models.Location.objects.all())
+ }
+ self.assertIsNotNone(r)
+
+ def test_all_models(self):
+ pass
+ self.syncengine.sync(qs=benchcoach.models.Event.objects.all())
+ breakpoint()
+ pass
\ No newline at end of file
diff --git a/teamsnap/views.py b/teamsnap/views.py
index 615978d..da6e248 100644
--- a/teamsnap/views.py
+++ b/teamsnap/views.py
@@ -45,7 +45,7 @@ def home(request):
(Member, benchcoach.models.Player),
(Opponent, benchcoach.models.Team),
(Team, benchcoach.models.Team),
- (User, None)
+ # (User, {'name':})
]:
teamsnap_objects[teamsnap_obj.__name__.lower()] = {}
teamsnap_objects[teamsnap_obj.__name__.lower()]['object_count'] = teamsnap_obj.objects.count()
@@ -183,41 +183,37 @@ def send_to_benchcoach(request, object_name):
}.get(object_name)
TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
+ TOKEN = request.user.profile.teamsnap_access_token
+
+ sync_engine = TeamsnapSyncEngine(teamsnap_token=TOKEN, managed_team_teamsnap_id=TEAM_ID)
r = {}
r[object_name]=[]
if object_name == 'team':
- for team in Object.objects.filter(id=TEAM_ID):
- r[object_name] += update_opponent(team, create_benchcoach_object=True, create_related=True)
+ r[object_name] = sync_engine.sync(qs=benchcoach.models.Team.objects.all())
- if object_name == 'opponent':
- for team in Object.objects.filter(team_id=TEAM_ID):
- r[object_name] += update_team(team, create_benchcoach_object=True, create_related=True)
+ if object_name == 'venue':
+ r[object_name] = sync_engine.sync(qs=benchcoach.models.Venue.objects.all())
+ pass
- if object_name == 'location':
- for location in Location.objects.filter(team_id=TEAM_ID):
- r[object_name] += update_location(location, create_benchcoach_object=True, create_related=True)
-
- if object_name == 'member':
- for member in Member.objects.filter(team_id=TEAM_ID, is_non_player=False):
- r[object_name] += update_member(member, create_benchcoach_object=True, create_related=True)
+ if object_name == 'player':
+ r[object_name] = sync_engine.sync(qs=benchcoach.models.Player.objects.all())
if object_name == 'event':
- for event in Event.objects.filter(team_id=TEAM_ID):
- r[object_name] += update_event(event, create_benchcoach_object=True, create_related=True)
+ r[object_name] = sync_engine.sync(qs=benchcoach.models.Event.objects.all())
+ pass
if object_name == 'availability':
- for availability in Availability.objects.filter(team_id=TEAM_ID, member__is_non_player=False):
- r[object_name] += update_availability(availability, create_benchcoach_object=True, create_related=True)
+ r[object_name] = []
+ for event in benchcoach.models.Player.objects.all():
+ r[object_name] += sync_engine.sync(qs=event.availability_set.all())
for object_name, results in r.items():
- if len(r) == 0:
- messages.error(request, f"Error! No {object_name} objects created or updated")
+ if len(results) == 0:
+ messages.error(request, f"Error! No {object_name} objects 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.")
+ messages.success(request, f"Success! {len(results)} {object_name} objects updated.")
return redirect('teamsnap home')
@@ -304,8 +300,21 @@ def sync_teamsnapdb_to_benchcoachdb(request):
}
return JsonResponse(data)
-
-
+from .utils.teamsnap_sync_engine import TeamsnapSyncEngine
+def import_teamsnap(request):
+ TEAM_ID = request.user.profile.teamsnapsettings.managed_team.id
+ TOKEN = request.user.profile.teamsnap_access_token
+
+ sync_engine = TeamsnapSyncEngine(teamsnap_token=TOKEN, managed_team_teamsnap_id=TEAM_ID)
+ r = sync_engine.import_items()
+
+ for object_name, results in r.items():
+ if len(results) == 0:
+ messages.error(request, f"Error! No {object_name} objects created or updated")
+ else:
+ messages.success(request, f"Success! {len(results)} {object_name} objects imported")
+
+ return redirect('teamsnap home')