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 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 # def get_callback_url(self, request, app): # callback_url = reverse(self.provider_id + "_callback") # protocol = self.redirect_uri_protocol # return build_absolute_uri(request, callback_url, protocol) # return "urn:ietf:wg:oauth:2.0:oob" oauth2_login = OAuth2LoginView.adapter_view(TeamsnapAdapter) oauth2_callback = OAuth2CallbackView.adapter_view(TeamsnapAdapter) 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 ) 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 ) no_past = bool(request.GET.get("no_past", 0)) games_only = bool(request.GET.get("games_only", 0)) from pyteamsnap.api import Event, TeamSnap client = TeamSnap(token=ts_token) 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 ) 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 ) from pyteamsnap.api import ( AvailabilitySummary, Event, EventLineup, EventLineupEntry, Member, TeamSnap, ) client = TeamSnap(token=ts_token) 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 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 ) from pyteamsnap.api import ( Availability, AvailabilitySummary, Event, EventLineup, EventLineupEntry, Member, TeamSnap, ) client = TeamSnap(token=ts_token) 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 ) 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 ) from pyteamsnap.api import AvailabilitySummary, Event, TeamSnap client = TeamSnap(token=ts_token) 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 request.user.socialaccount_set.filter(provider="teamsnap").first() from pyteamsnap.api import EventLineup, TeamSnap, EventLineupEntry, Event current_teamsnap_user = request.user.socialaccount_set.filter( provider="teamsnap" ).first() ts_token = ( current_teamsnap_user.socialtoken_set.order_by("-expires_at").first().token ) client = TeamSnap(token=ts_token) 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