From 1bc3638a9622c65eea48fb43d8b32bda0595f428 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 9 Nov 2019 16:38:28 +0100 Subject: [PATCH] added access to video analysis from analytics --- rowers/forms.py | 11 ++ rowers/templates/list_graphs.html | 15 +- rowers/templates/list_videos.html | 90 +++++++++ rowers/templates/menu_analytics.html | 164 ++++++++------- rowers/templates/video_selectworkout.html | 117 +++++++++++ rowers/urls.py | 2 + rowers/views/statements.py | 2 +- rowers/views/workoutviews.py | 230 ++++++++++++++++++++++ 8 files changed, 550 insertions(+), 81 deletions(-) create mode 100644 rowers/templates/list_videos.html create mode 100644 rowers/templates/video_selectworkout.html diff --git a/rowers/forms.py b/rowers/forms.py index 7de907ce..be4adb45 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -822,6 +822,17 @@ class PlanSelectForm(forms.Form): class CourseSelectForm(forms.Form): course = forms.ModelChoiceField(queryset=GeoCourse.objects.all()) +class WorkoutSingleSelectForm(forms.Form): + workout = forms.ModelChoiceField( + queryset=Workout.objects.filter(), + widget=forms.RadioSelect + ) + + def __init__(self, *args, **kwargs): + workouts = kwargs.pop('workouts',Workout.objects.filter().order_by('-date')) + super(WorkoutSingleSelectForm,self).__init__(*args,**kwargs) + self.fields['workout'].queryset = workouts + class WorkoutMultipleCompareForm(forms.Form): workouts = forms.ModelMultipleChoiceField( queryset=Workout.objects.filter(), diff --git a/rowers/templates/list_graphs.html b/rowers/templates/list_graphs.html index 0b9a82df..8daf3046 100644 --- a/rowers/templates/list_graphs.html +++ b/rowers/templates/list_graphs.html @@ -12,14 +12,15 @@

Recent Graphs

+ +
  • + +  Histogram + +
  • +
  • + +  Alerts + +
  • + + +
  • + +  Cumulative Flex Chart + +
  • +
  • + +  Laboratory +
  • + -{% if user.is_authenticated and user|is_manager and rower %} -

     

    + {% if user.is_authenticated and user|is_manager and rower %} +

     

    -{% if user|coach_rowers %} - -{% endif %} -{% endif %} + {% if user|coach_rowers %} + + {% endif %} + {% endif %} -{% if user|user_teams %} -

     

    - -{% endif %} + {% if user|user_teams %} +

     

    + + {% endif %} -{% include 'menuscript.html' %} + {% include 'menuscript.html' %} diff --git a/rowers/templates/video_selectworkout.html b/rowers/templates/video_selectworkout.html new file mode 100644 index 00000000..1902ca5e --- /dev/null +++ b/rowers/templates/video_selectworkout.html @@ -0,0 +1,117 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Workouts{% endblock %} + +{% block main %} + + + + + + + + + +{% endblock %} + +{% block scripts %} +{% if request.method == 'POST' %} + + +{% endif %} + +{% endblock %} + +{% block sidebar %} +{% include 'menu_analytics.html' %} +{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index aecbdd64..2a9c39d6 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -348,6 +348,8 @@ urlpatterns = [ re_path(r'^video/(?P\d+)/delete/$',views.VideoDelete.as_view(),name='video_delete'), re_path(r'^video/(?P\w.+)/$',views.workout_video_view, name='workout_video_view'), + re_path(r'^videos/',views.list_videos,name='list_videos'), + re_path(r'^add-video/',views.video_selectworkout,name='video_selectworkout'), # re_path(r'^workout/(?P\d+)/$',views.workout_view,name='workout_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/$',views.workout_view,name='workout_view'), re_path(r'^workout/fusion/(?P\b[0-9A-Fa-f]+\b)/(?P\b[0-9A-Fa-f]+\b)/$',views.workout_fusion_view,name='workout_fusion_view'), diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 8a57029e..05872c03 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -59,7 +59,7 @@ from rowers.forms import ( FlexOptionsForm,DataFrameColumnsForm,OteWorkoutTypeForm, MetricsForm,DisqualificationForm,disqualificationreasons, disqualifiers,SearchForm,BillingForm,PlanSelectForm, - VideoAnalysisCreateForm + VideoAnalysisCreateForm,WorkoutSingleSelectForm, ) from django.urls import reverse, reverse_lazy diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index e152acf1..1e97d727 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -693,6 +693,197 @@ def workouts_join_view(request): url = reverse('workouts_join_select') return HttpResponseRedirect(url) +@user_passes_test(ispromember, login_url="/rowers/paidplans", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) +def video_selectworkout(request,userid=0,teamid=0): + r = getrequestrower(request, userid=userid) + user = r.user + userid = user.id + workouts = Workout.objects.filter(user=r).order_by('-date') + + try: + theteam = Team.objects.get(id=teamid) + except Team.DoesNotExist: + theteam = None + + + if 'options' in request.session: + options = request.session['options'] + else: + options=defaultoptions + + options['userid'] = userid + try: + workouttypes = options['workouttypes'] + except KeyError: + workouttypes = ['rower','dynamic','slides'] + + try: + modalities = options['modalities'] + modality = modalities[0] + except KeyError: + modalities = [m[0] for m in mytypes.workouttypes_ordered.items()] + modality = 'all' + + + + try: + rankingonly = options['rankingonly'] + except KeyError: + rankingonly = False + + query = request.GET.get('q') + if query: + query_list = query.split() + workouts = workouts.filter( + reduce(operator.and_, + (Q(name__icontains=q) for q in query_list)) | + reduce(operator.and_, + (Q(notes__icontains=q) for q in query_list)) + ) + searchform = SearchForm(initial={'q':query}) + else: + searchform = SearchForm() + + + if 'startdate' in request.session: + startdate = iso8601.parse_date(request.session['startdate']) + else: + startdate=timezone.now()-datetime.timedelta(days=42) + + if 'enddate' in request.session: + enddate = iso8601.parse_date(request.session['enddate']) + else: + enddate = timezone.now() + + + workouts = workouts.filter(date__gte=startdate,date__lte=enddate) + + waterboattype = mytypes.waterboattype + + if request.method == 'POST': + thediv = get_call() + dateform = DateRangeForm(request.POST) + if dateform.is_valid(): + startdate = dateform.cleaned_data['startdate'] + enddate = dateform.cleaned_data['enddate'] + startdatestring = startdate.strftime('%Y-%m-%d') + enddatestring = enddate.strftime('%Y-%m-%d') + request.session['startdate'] = startdatestring + request.session['enddate'] = enddatestring + + form = WorkoutSingleSelectForm(request.POST) + if form.is_valid(): + cd = form.cleaned_data + selectedworkout = cd['workout'] + url = reverse('workout_video_create_view', + kwargs={'id':encoder.encode_hex(selectedworkout.id)}) + return HttpResponseRedirect(url) + else: + id = 0 + else: + form = WorkoutSingleSelectForm(workouts=workouts) + thediv = '' + dateform = DateRangeForm(initial={ + 'startdate':startdate, + 'enddate':enddate, + }) + + + + negtypes = [] + for b in mytypes.boattypes: + if b[0] not in waterboattype: + negtypes.append(b[0]) + + + startdate = datetime.datetime.combine(startdate,datetime.time()) + enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) + + if enddate < startdate: + s = enddate + enddate = startdate + startdate = s + + negtypes = [] + for b in mytypes.boattypes: + if b[0] not in waterboattype: + negtypes.append(b[0]) + + + + if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user): + workouts = Workout.objects.filter(team=theteam, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + workouttype__in=modalities, + ) + elif theteam is not None and theteam.viewing == 'coachonly': + workouts = Workout.objects.filter(team=theteam,user=r, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + workouttype__in=modalities, + ) + else: + workouts = Workout.objects.filter(user=r, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + workouttype__in=modalities, + ) + + workouts = workouts.order_by( + "-date", "-starttime" + ).exclude(boattype__in=negtypes) + + + if rankingonly: + workouts = workouts.exclude(rankingpiece=False) + + + + + optionsform = AnalysisOptionsForm(initial={ + 'modality':modality, + 'waterboattype':waterboattype, + 'rankingonly':rankingonly, + }) + + + + startdatestring = startdate.strftime('%Y-%m-%d') + enddatestring = enddate.strftime('%Y-%m-%d') + request.session['startdate'] = startdatestring + request.session['enddate'] = enddatestring + request.session['options'] = options + + + breadcrumbs = [ + { + 'url':'/rowers/analysis', + 'name':'Analysis' + }, + { + 'url':reverse('analysis_new',kwargs={'userid':userid}), + 'name': 'Analysis Select' + }, + ] + return render(request, 'video_selectworkout.html', + {'workouts': workouts, + 'dateform':dateform, + 'startdate':startdate, + 'enddate':enddate, + 'rower':r, + 'breadcrumbs':breadcrumbs, + 'theuser':user, + 'the_div':thediv, + 'form':form, + 'active':'nav-analysis', + 'searchform':searchform, + 'teams':get_my_teams(request.user), + }) + + @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) @@ -4736,6 +4927,45 @@ def team_workout_upload_view(request,message="", # A page with all the recent graphs (searchable on workout name) +@login_required() +def list_videos(request): + r = getrequestrower(request) + workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") + query = request.GET.get('q') + if query: + query_list = query.split() + if query: + query_list = query.split() + workouts = workouts.filter( + reduce(operator.and_, + (Q(name__icontains=q) for q in query_list)) | + reduce(operator.and_, + (Q(notes__icontains=q) for q in query_list)) + ) + searchform = SearchForm(initial={'q':query}) + else: + searchform = SearchForm() + + g = VideoAnalysis.objects.filter(workout__in=workouts).order_by("-workout__date") + + + paginator = Paginator(g,8) + page = request.GET.get('page') + + try: + g = paginator.page(page) + except PageNotAnInteger: + g = paginator.page(1) + except EmptyPage: + g = paginator.page(paginator.num_pages) + + return render(request, 'list_videos.html', + {'analyses': g, + 'searchform':searchform, + 'active':'nav-analysis', + 'teams':get_my_teams(request.user), + }) + @login_required() def graphs_view(request): request.session['referer'] = reverse('graphs_view')