import datetime import requests from allauth.socialaccount.providers.oauth2.views import ( OAuth2Adapter, OAuth2CallbackView, OAuth2LoginView, ) from django.shortcuts import redirect, render from django.views.generic.edit import FormView from django.http import HttpResponseNotAllowed, HttpResponse, JsonResponse, HttpResponseServerError from .forms import PreferencesForm from .models import Preferences from .provider import TeamsnapProvider import pyteamsnap.api class TeamsnapAdapter(OAuth2Adapter): provider_id = TeamsnapProvider.id # Fetched programmatically, must be reachable from container access_token_url = "{}/oauth/token/".format("https://auth.teamsnap.com") profile_url = "{}/me/".format("https://api.teamsnap.com/v3/") # Accessed by the user browser, must be reachable by the host authorize_url = "{}/oauth/authorize/".format("https://auth.teamsnap.com/") # NOTE: trailing slashes in URLs are important, don't miss it def complete_login(self, request, app, token, **kwargs): headers = {"Authorization": f"Bearer {token.token}"} resp = requests.get(self.profile_url, headers=headers) j = resp.json() if j.get("collection", {}).get("items"): extra_data = { i["name"]: i["value"] for i in j["collection"]["items"][0]["data"] } return self.get_provider().sociallogin_from_response(request, extra_data) def populate_user(self, request, sociallogin, data): user = super().populate_user(request, sociallogin, data) user.username = user.email return user oauth2_login = OAuth2LoginView.adapter_view(TeamsnapAdapter) oauth2_callback = OAuth2CallbackView.adapter_view(TeamsnapAdapter) def get_teamsnap_client(request): request.user.socialaccount_set.filter(provider="teamsnap").first() current_teamsnap_user = request.user.socialaccount_set.filter( provider="teamsnap" ).first() ts_token = ( current_teamsnap_user.socialtoken_set.order_by("-expires_at").first().token ) return pyteamsnap.api.TeamSnap(token=ts_token) class PreferencesFormView(FormView): template_name = "preferences.html" form_class = PreferencesForm success_url = "/" def form_valid(self, form): # This method is called when valid form data has been POSTed. # It should return an HttpResponse. if form.data["user"] == str(self.request.user.id): form.save() return super().form_valid(form) def get_initial(self): """ Returns the initial data to use for forms on this view. """ initial = super().get_initial() initial["user"] = self.request.user # initial['managed_team_id'] return initial def get_form(self): """ Returns the initial data to use for forms on this view. """ import pyteamsnap ts_account = self.request.user.socialaccount_set.first() ts_token = ts_account.socialtoken_set.first() # ts_token = ts = pyteamsnap.TeamSnap(token=ts_token) me = pyteamsnap.api.Me(ts) teams = [ (id, pyteamsnap.api.Team.get(ts, id=id)) for id in me.data["managed_team_ids"] ] try: contact = Preferences.objects.get(user=self.request.user) form = PreferencesForm(instance=contact, **self.get_form_kwargs()) except Preferences.DoesNotExist: form = super().get_form(self.form_class) choices = [ (id, f"{team.data['name']} ({team.data['season_name']})") for id, team in teams ] form.fields["managed_team_id"].widget.choices = choices return form def schedule_view(request, team_id=None): if not team_id: return redirect( "teamsnap_schedule", team_id=request.user.preferences.managed_team_id ) client = get_teamsnap_client(request) no_past = bool(request.GET.get("no_past", 0)) games_only = bool(request.GET.get("games_only", 0)) from pyteamsnap.api import Event ts_events = Event.search(client, team_id=team_id) if no_past: ts_events = [ e for e in ts_events if e.data["start_date"] > datetime.datetime.now(datetime.timezone.utc) ] if games_only: ts_events = [e for e in ts_events if e.data["is_game"]] ts_events = {e.data["id"]: e for e in ts_events} pass return render( request, "schedule.html", context={"events": ts_events.values(), "team_id": team_id}, ) def view_event(request, event_id, team_id=None): if not team_id: return redirect( "teamsnap_event", team_id=request.user.preferences.managed_team_id ) from pyteamsnap.api import ( AvailabilitySummary, Event, EventLineup, EventLineupEntry, Member, ) client = get_teamsnap_client(request) ts_bulkload = client.bulk_load( team_id=team_id, types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member], event__id=event_id, ) ts_event = [i for i in ts_bulkload if isinstance(i, Event)][0] ts_availability_summary = [ i for i in ts_bulkload if isinstance(i, AvailabilitySummary) and i.data["event_id"] == event_id ][0] ts_lineup_entries = [ i for i in ts_bulkload if isinstance(i, EventLineupEntry) and i.data["event_id"] == event_id ] return render( request, "event/view_event.html", context={ "availability_summary": ts_availability_summary, "event": ts_event, "availablities": [], "lineup_entries": ts_lineup_entries, }, ) def edit_lineup(request, event_ids, team_id): import re from teamsnap.forms import LineupEntryFormset from pyteamsnap.api import ( Availability, AvailabilitySummary, Event, EventLineup, EventLineupEntry, Member, TeamSnap, ) client = get_teamsnap_client(request) event_ids = str(event_ids).split(",") ts_bulkload = client.bulk_load( team_id=team_id, types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member], event__id=",".join(event_ids), ) event_ids = [int(i) for i in event_ids] contexts = [] for event_id in event_ids: ts_event = [ i for i in ts_bulkload if isinstance(i, Event) and i.data["id"] == event_id ][0] ts_availabilities = Availability.search(client, event_id=ts_event.data["id"]) ts_lineup_entries = EventLineupEntry.search(client, event_id=event_id) ts_members = [i for i in ts_bulkload if isinstance(i, Member)] ts_member_lookup = {m.data["id"]: m for m in ts_members} ts_availability_lookup = {m.data["member_id"]: m for m in ts_availabilities} ts_lineup_entries_lookup = {m.data["member_id"]: m for m in ts_lineup_entries} members = [] for lineup_entry in ts_lineup_entries: members.append( { "member": getattr(ts_member_lookup[lineup_entry.data['member_id']],'data'), "availability": getattr( ts_availability_lookup.get(lineup_entry.data['member_id'], {}), "data", {} ), "lineup_entry": getattr( lineup_entry, "data", {} ), } ) in_lineup_already = [m['member'] for m in members] for member in ts_members: if not member.data in in_lineup_already: members.append( { "member": getattr(member, "data"), "availability": getattr( ts_availability_lookup.get(member.data["id"], {}), "data", {} ), "lineup_entry": getattr( ts_lineup_entries_lookup.get(member.data["id"], {}), "data", {} ), } ) members = sorted( members, key=lambda d: ( {None: 3, 0: 2, 2: 1, 1: 0}.get( # No Response # No # Maybe # Yes d["availability"].get("status_code") ), d["member"].get("last_name"), ), ) initial = [] for member in members: if not member["member"]["is_non_player"]: if re.search( r"([A-Z0-9]+)(?:\s+\[(.*)\])?", member["lineup_entry"].get("label", ""), ): position, position_note = re.search( r"([A-Z0-9]+)(?:\s+\[(.*)\])?", member["lineup_entry"].get("label", ""), ).groups() else: position, position_note = ("", "") position_only = position_note == "PO" initial.append( { "event_lineup_entry_id": member["lineup_entry"].get("id"), "event_lineup_id": member["lineup_entry"].get( "event_lineup_id" ), "event_id": event_id, "position_only": position_only, "member_id": member["member"]["id"], "sequence": member["lineup_entry"].get("sequence"), "label": position, } ) formset = LineupEntryFormset(initial=initial) for form in formset: form.member = ts_member_lookup.get(form["member_id"].initial) form.availability = ts_availability_lookup.get(form["member_id"].initial) formset_startinglineup = [ form for form in formset if form.initial.get("event_lineup_entry_id") and not form.initial.get("position_only") ] formset_startinglineup = sorted( formset_startinglineup, key=lambda d: d.initial.get("sequence", 100) ) formset_startingpositiononly = [ form for form in formset if form.initial.get("event_lineup_entry_id") and form not in formset_startinglineup ] formset_startingpositiononly = sorted( formset_startingpositiononly, key=lambda d: d.initial.get("sequence", 100) ) formset_bench = [ form for form in formset if form not in formset_startinglineup and form not in formset_startingpositiononly and form.availability.data["status_code"] in [2, 1] ] formset_out = [ form for form in formset if form not in formset_startinglineup and form not in formset_bench and form not in formset_startingpositiononly and not form.member.data["is_non_player"] ] contexts.append( { "event": ts_event, "formset": formset, "formset_bench": formset_bench, "formset_startinglineup": formset_startinglineup, "formset_startingpositionalonly": formset_startingpositiononly, "formset_out": formset_out, } ) return render( request, "lineup/multiple_edit.html", context={"contexts": contexts} ) def dashboard(request, team_id=None): if not team_id: return redirect( "teamsnap_dashboard", team_id=request.user.preferences.managed_team_id ) from pyteamsnap.api import AvailabilitySummary, Event client = get_teamsnap_client(request) ts_events = Event.search(client, team_id=team_id) ts_availability_summaries_d = { a.data["id"]: a for a in AvailabilitySummary.search(client, team_id=team_id) } ts_events_future = [ e for e in ts_events if e.data["start_date"] > datetime.datetime.now(datetime.timezone.utc) ] ts_events_past = [ e for e in reversed(ts_events) if e.data["start_date"] < datetime.datetime.now(datetime.timezone.utc) ] return render( request, "dashboard.html", { "ts_events_future": ts_events_future, "ts_events_past": ts_events_past, "events_availabilities": [ (e, ts_availability_summaries_d[e.data["id"]]) for e in ts_events_future ], }, ) def submit_lineup(request, team_id, event_id): from teamsnap.forms import LineupEntryFormset from pyteamsnap.api import EventLineup, TeamSnap, EventLineupEntry, Event client = get_teamsnap_client(request) ts_event = Event.get(client,event_id) ts_lineup = EventLineup.search(client, event_id=event_id) event_lineup_id = ts_lineup[0].data['id'] if request.GET: return HttpResponseNotAllowed() if request.POST: formset = LineupEntryFormset(request.POST) if formset.is_valid(): r = [] for form in formset: data = form.cleaned_data if data.get('event_lineup_entry_id'): event_lineup_entry = EventLineupEntry.get(client, id=data.get('event_lineup_entry_id')) if data.get('position_only'): data['label'] = data['label'] + ' [PO]' event_lineup_entry.data.update(data) if not data.get('sequence') and not data.get('label'): try: r.append(event_lineup_entry.delete()) except Exception as e: raise e else: try: r.append(event_lineup_entry.put()) except: pass pass elif data.get('sequence') is not None and data.get('label'): event_lineup_entry = EventLineupEntry.new(client) if data.get('position_only'): data['label'] = data['label'] + ' [PO]' event_lineup_entry.data.update(data) event_lineup_entry.data.update({"event_lineup_id": event_lineup_id}) try: r.append(event_lineup_entry.post()) except Exception as e: raise e else: pass else: # breakpoint() pass # breakpoint() pass return JsonResponse(ts_event.data) pass return HttpResponseServerError def gamecard(request, team_id, event_id): import re from pyteamsnap.api import Event, Availability, Member, EventLineupEntry, EventLineup, \ AvailabilitySummary client = get_teamsnap_client(request) ts_bulkload = client.bulk_load(team_id=team_id, types=[Event, EventLineup, EventLineupEntry, AvailabilitySummary, Member], event__id=event_id) formsets_lineup = [] formsets_bench = [] formsets = [] events = [] contexts = [] ts_event = [i for i in ts_bulkload if isinstance(i, Event) and i.data['id'] == event_id][0] ts_availabilities = Availability.search(client, event_id=ts_event.data['id']) ts_availability_summary = \ [i for i in ts_bulkload if isinstance(i, AvailabilitySummary) and i.data['event_id'] == event_id][0] ts_lineup_entries = EventLineupEntry.search(client, event_id=event_id) if ts_lineup_entries: ts_lineup = EventLineup.get(client, id=ts_lineup_entries[0].data['event_lineup_id']) else: ts_lineup = EventLineup.search(client, event_id=event_id) ts_members = [i for i in ts_bulkload if isinstance(i, Member)] ts_member_lookup = {m.data['id']: m for m in ts_members} ts_availability_lookup = {m.data['member_id']: m for m in ts_availabilities} ts_lineup_entries_lookup = {m.data['member_id']: m for m in ts_lineup_entries} members = [] for member in ts_members: if not member.data['is_non_player']: members.append({ "member": getattr(member, 'data'), "availability": getattr(ts_availability_lookup.get(member.data['id'], {}), 'data', {}), "lineup_entry": getattr(ts_lineup_entries_lookup.get(member.data['id'], {}), 'data', {}) } ) members = sorted(members, key=lambda d: ( { None: 3, # No Response 0: 2, # No 2: 1, # Maybe 1: 0 # Yes }.get(d['availability'].get('status_code')), d['member'].get('last_name')) ) members_startinglineup = [] members_startingpositiononly = [] for member in members: if re.search(r'([A-Z0-9]+)(?:\s+\[(.*)\])?', member['lineup_entry'].get('label', '')): position, position_note = re.search(r'([A-Z0-9]+)(?:\s+\[(.*)\])?', member['lineup_entry'].get('label', '')).groups() else: position, position_note = ("", "") position_only = position_note == "PO" if position_only: member['lineup_entry']['label'] = position if member['lineup_entry'].get('id') and not position_only: members_startinglineup.append(member) elif member['lineup_entry'].get('id') and position_only: members_startingpositiononly.append(member) members_startinglineup = sorted( members_startinglineup, key=lambda d: d.get('lineup_entry',{}).get('sequence', 100) ) from teamsnap.forms import LineupEntryFormset, LineupEntryForm initial = [] l=[] # l = [(member,ts_availability_lookup.get(member['member_id'])) for member in members if not member['is_non_player']] context={ "event": ts_event, "members": members, "members_startinglineup":members_startinglineup, "members_startingpositiononly":members_startingpositiononly } return render(request, "lineup/gamecard.html", context=context)