import datetime import pyteamsnap.api import requests from allauth.socialaccount.providers.oauth2.views import ( OAuth2Adapter, OAuth2CallbackView, OAuth2LoginView, ) from django.http import ( HttpResponse, HttpResponseNotAllowed, HttpResponseServerError, JsonResponse, ) from django.shortcuts import redirect, render from django.views.generic.edit import FormView from .forms import PreferencesForm from .models import Preferences from .provider import TeamsnapProvider 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 pyteamsnap.api import ( Availability, AvailabilitySummary, Event, EventLineup, EventLineupEntry, Member, ) from teamsnap.forms import LineupEntryFormset 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 member.data not 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 pyteamsnap.api import Event, EventLineup, EventLineupEntry from teamsnap.forms import LineupEntryFormset 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 Exception as e: e 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 multi_lineup_choose(request, team_id): from django.forms import formset_factory from pyteamsnap.api import Event from .forms import EventChooseForm client = get_teamsnap_client(request) if request.method == "POST": ts_events = Event.search(client, team_id=team_id) EventChooseFormset = formset_factory(EventChooseForm) formset = EventChooseFormset(request.POST) choices = [(e.data["id"], e.data["formatted_title"]) for e in ts_events] for form in formset: form.fields["event_id"].choices = choices if formset.is_valid(): event_ids = [f.cleaned_data["event_id"] for f in formset] else: event_ids = request.GET.get("event_ids").split(",") EventChooseFormset = formset_factory(EventChooseForm) formset = EventChooseFormset(request.POST) return redirect( "teamsnap_edit_multiple_lineups", team_id=team_id, event_ids=",".join(event_ids), ) elif not request.GET.get("num"): return HttpResponse(500) else: num = int(request.GET.get("num")) TEAM_ID = team_id ts_events = Event.search(client, team_id=TEAM_ID) ts_events = {e.data["id"]: e for e in ts_events} EventChooseFormset = formset_factory(EventChooseForm, extra=num) formset = EventChooseFormset() choices = [(id, e.data["formatted_title"]) for id, e in ts_events.items()] for form in formset: form.fields["event_id"].choices = choices pass return render( request, "lineup/multiple_choose.html", context={"formset": formset, "team_id": team_id}, )