import rowers.teams as teams from rowers.serializers import RowerSerializer, WorkoutSerializer from rowers.integrations import integrations from rq import Queue, cancel_job from redis import StrictRedis, Redis from rowers.models import C2WorldClassAgePerformance from rowers.utils import ProcessorCustomerError import rowers.datautils as datautils from rowers.utils import ( geo_distance, serialize_list, deserialize_list, uniqify, str2bool, range_to_color_hex, absolute, myqueue, get_call, calculate_age, rankingdistances, rankingdurations, my_dict_from_instance, wavg, NoTokenError, request_is_ajax, dologging ) from rowers.fitness import calculate_fitness from rowers.celery import result as celery_result from rowers.interactiveplots import * from scipy.interpolate import griddata from rowers.dataprep import getsmallrowdata_pd, read_data from rowers.dataprep import timedeltaconv from scipy.special import lambertw from io import BytesIO import rowers.plots as plots from rowers.permissions import IsOwnerOrNot, IsCompetitorOrNot from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.decorators import api_view, renderer_classes, permission_classes from rest_framework.response import Response from rq.job import Job from rules.contrib.views import permission_required, objectgetter from django.core.cache import cache from django.db import models from django.utils.crypto import get_random_string from rq.registry import StartedJobRegistry from rq.exceptions import NoSuchJobError import threading import redis import colorsys import re import gzip import zipfile import bleach import arrow import pytz from pytz import UnknownTimeZoneError import operator import warnings import urllib import yaml from PIL import Image from numbers import Number from django.views.generic.base import TemplateView, View from django.contrib.auth import views as auth_views from django.db.models import Q from django import template from django.db import IntegrityError, transaction from django.views.decorators.csrf import csrf_exempt from django.shortcuts import get_object_or_404 from matplotlib.backends.backend_agg import FigureCanvas import gc from pyparsing import ParseException from uuid import uuid4 import codecs import isodate import re import cgi from icalendar import Calendar, Event from functools import reduce from rules.contrib.views import PermissionRequiredMixin import rowers.braintreestuff as braintreestuff import rowers.payments as payments from rowers.opaque import encoder from rowers.rower_rules import ( ispromember, is_coach_user, is_team_member, is_rower_team_member, is_workout_user, isplanmember, can_delete_session, can_view_target, can_change_target, can_delete_target, can_view_plan, can_change_plan, can_delete_plan, can_view_cycle, can_change_cycle, can_delete_cycle, can_add_workout_member, can_plan_user, is_paid_coach, can_start_trial, can_start_plantrial, can_start_coachtrial, can_plan, is_workout_team, is_promember,user_is_basic, is_coachtrial, is_coach, workout_is_strava, is_workout_owner, can_add_session, ) from django.shortcuts import render from django.template.loader import render_to_string from django.views.generic.edit import UpdateView, DeleteView from django.http import ( HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseForbidden, HttpResponseNotAllowed, HttpResponseNotFound, Http404, HttpResponseBadRequest, ) from django.contrib.auth import authenticate, login, logout from rowers.forms import ( WorkoutBulkActions, ExportChoices, ForceCurveOptionsForm, HistoForm, TeamMessageForm, LoginForm, DocumentsForm, UploadOptionsForm, ImageForm, CourseForm, CourseConfirmForm, ResampleForm, TeamUploadOptionsForm, WorkFlowLeftPanelForm, WorkFlowMiddlePanelForm, WorkFlowLeftPanelElement, WorkFlowMiddlePanelElement, WorkoutNameTemplateElement, LandingPageForm, PlannedSessionSelectForm, WorkoutSessionSelectForm, PlannedSessionTeamForm, PlannedSessionTeamMemberForm, VirtualRaceSelectForm, WorkoutRaceSelectForm, CourseSelectForm, RaceResultFilterForm, PowerIntervalUpdateForm, FlexAxesForm, FlexOptionsForm, DataFrameColumnsForm, OteWorkoutTypeForm, MetricsForm, DisqualificationForm, disqualificationreasons, disqualifiers, SearchForm, BillingForm, PlanSelectForm, VideoAnalysisCreateForm, WorkoutSingleSelectForm, VideoAnalysisMetricsForm, SurveyForm, HistorySelectForm, StravaChartForm, FitnessFitForm, PerformanceManagerForm, TrainingPlanBillingForm, InstantPlanSelectForm, TrainingZonesForm, InstrokeForm, InStrokeMultipleCompareForm, ForceCurveMultipleCompareForm, PlanByRscoreForm, AssignChoices, ) from django.urls import reverse, reverse_lazy from django.core.exceptions import PermissionDenied, MultipleObjectsReturned from django.template import RequestContext from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.conf import settings from django.urls import resolve from django.utils.decorators import method_decorator from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.utils.datastructures import MultiValueDictKeyError from django.utils import timezone, translation from django.core.mail import send_mail, BadHeaderError from rowers.forms import ( SummaryStringForm, StrokeDataForm, StatsOptionsForm, PredictedPieceForm, DateRangeForm, DeltaDaysForm, FitnessMetricForm, PredictedPieceFormNoDistance, EmailForm, RegistrationForm, RegistrationFormTermsOfService, RegistrationFormUniqueEmail, RegistrationFormSex, CNsummaryForm, StandardsForm, WorkoutMultipleCompareForm, ChartParamChoiceForm, FusionMetricChoiceForm, BoxPlotChoiceForm, MultiFlexChoiceForm, TrendFlexModalForm, WorkoutSplitForm, WorkoutJoinParamForm, AnalysisOptionsForm, AnalysisChoiceForm, PlannedSessionMultipleCloneForm, SessionDateShiftForm, RowerTeamForm, ) from rowers.models import ( Workout, User, Rower, WorkoutForm, FavoriteChart, PlannedSession, DeactivateUserForm, DeleteUserForm, TrainingPlan, TrainingPlanForm, TrainingTarget, TrainingTargetForm, TrainingMacroCycle, TrainingMesoCycle, TrainingMicroCycle, TrainingMacroCycleForm, createmacrofillers, createmicrofillers, createmesofillers, microcyclecheckdates, mesocyclecheckdates, macrocyclecheckdates, TrainingMesoCycleForm, TrainingMicroCycleForm, RaceLogo, RowerBillingAddressForm, PaidPlan, AlertEditForm, ConditionEditForm, PlannedSessionComment, CoachRequest, CoachOffer, VideoAnalysis, ShareKey, StandardCollection, CourseStandard, VirtualRaceFollower, TombStone, InstantPlan, PlannedSessionStep,InStrokeAnalysis, ForceCurveAnalysis, SyncRecord, UserMessage,APIKey, ) from rowers.models import ( RowerPowerForm, RowerHRZonesForm, SimpleRowerPowerForm, RowerForm, RowerCPForm, GraphImage, AdvancedWorkoutForm, RowerPowerZonesForm, AccountRowerForm, UserForm, Team, TeamForm, TeamInviteForm, TeamInvite, TeamRequest, WorkoutComment, WorkoutCommentForm, RowerExportForm, CalcAgePerformance, PowerTimeFitnessMetric, BlogPost, PlannedSessionForm, PlannedSessionTemplateForm, PlannedSessionFormSmall, GeoCourseEditForm, VirtualRace, VirtualRaceForm, VirtualRaceResultForm, RowerImportExportForm, WorkoutRPEForm, IndoorVirtualRaceResultForm, IndoorVirtualRaceResult, IndoorVirtualRaceForm, PlannedSessionCommentForm, Alert, Condition, StaticChartRowerForm, FollowerForm, VirtualRaceAthleteForm, InstantPlanForm, DataRowerForm, StepEditorForm, iDokladToken, RowerExportFormStrava, RowerExportFormPolar, RowerExportFormSportTracks, RowerExportFormTrainingPeaks, RowerExportFormConcept2, RowerExportFormIntervals, RowerExportFormRP3, RowerExportFormNK, RowerPrivateImportForm, NextWeekPlanForm, ) from rowers.models import ( FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet, get_course_timezone, BaseConditionFormSet, ) from rowers.metrics import rowingmetrics, defaultfavoritecharts, nometrics, metricsgroups from rowers import metrics as metrics from rowers import courses as courses import rowers.uploads as uploads from django.forms.formsets import formset_factory from django.forms import modelformset_factory from django.contrib.auth.decorators import login_required # ,user_passes_test from rowers.decorators import user_passes_test from time import strftime, strptime, mktime, time, daylight import os import sys import datetime import iso8601 import rowers.rojabo_stuff as rojabo_stuff from iso8601 import ParseError import rowers.rojabo_stuff as rojabo_stuff import rowers.garmin_stuff as garmin_stuff from rowers.rojabo_stuff import rojabo_open from rowers.integrations import * from polars.exceptions import ColumnNotFoundError import rowers.ownapistuff as ownapistuff from rowers.ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET, TP_CLIENT_ID, TP_REDIRECT_URI, TP_CLIENT_KEY, TP_CLIENT_SECRET, RP3_CLIENT_ID, RP3_REDIRECT_URI, RP3_CLIENT_KEY, RP3_CLIENT_SECRET, BRAINTREE_MERCHANT_ID, BRAINTREE_PUBLIC_KEY, BRAINTREE_PRIVATE_KEY, PAYMENT_PROCESSING_ON, RECAPTCHA_SITE_KEY, RECAPTCHA_SITE_SECRET, NK_REDIRECT_URI, NK_CLIENT_ID, NK_CLIENT_SECRET, ROJABO_REDIRECT_URI, ROJABO_CLIENT_ID, ROJABO_CLIENT_SECRET, IDOKLAD_REDIRECT_URI, IDOKLAD_CLIENT_ID, IDOKLAD_CLIENT_SECRET, UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET, ) from django.contrib import messages from async_messages import messages as a_messages from django.contrib.admin.widgets import AdminDateWidget, AdminTimeWidget, AdminSplitDateTime import requests import json from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from rowers.rows import handle_uploaded_file, handle_uploaded_image from rowers.plannedsessions import * from rowers.tasks import handle_makeplot, handle_otwsetpower, handle_sendemailtcx, handle_sendemailcsv from rowers.tasks import ( handle_intervals_updateworkout, handle_post_workout_api, handle_sendemail_newftp, instroke_static, fetch_rojabo_session, handle_sendemail_unrecognized, handle_sendemailnewcomment, handle_request_post, handle_sendemailsummary, handle_rp3_async_workout, handle_send_template_email, handle_send_disqualification_email, handle_send_withdraw_email, handle_sendemailfile, handle_sendemailkml, handle_sendemailnewresponse, handle_updatedps, long_test_task, long_test_task2, handle_zip_file, handle_getagegrouprecords, handle_update_empower, handle_sendemailics, handle_sendemail_userdeleted, handle_sendemail_raceregistration, handle_sendemail_racesubmission, handle_sendemail_optout, handle_sendemail_ical, handle_c2_async_workout, handle_send_email_instantplan_notification, handle_nk_async_workout, check_tp_workout_id, handle_assignworkouts, handle_split_workout_by_intervals, ) from scipy.signal import savgol_filter try: from Cookie import SimpleCookie except ModuleNotFoundError: from http.cookies import SimpleCookie from shutil import copyfile, move import rowers.mytypes as mytypes from rowingdata import rower as rrower from rowingdata import main as rmain from rowingdata import rowingdata as rrdata from rowingdata import make_cumvalues from rowingdata import summarydata import pandas as pd import numpy as np import matplotlib.pyplot as plt from rowers.emails import send_template_email, htmlstrip, send_confirm from rowers.alerts import * from pytz import timezone as tz, utc from timezonefinder import TimezoneFinder import dateutil import mpld3 from mpld3 import plugins import stravalib from stravalib.exc import ActivityUploadFailed, TimeoutExceeded from rowers.weather import get_wind_data, get_airport_code, get_metar_data from oauth2_provider.models import Application, Grant, AccessToken import base64 from django.http import HttpResponse from django.contrib.auth import authenticate, login def view_or_apikey(view, request, test_func, realm = "", *args, **kwargs): if test_func(request.user): return view(request, *args, **kwargs) if 'Authorization' in request.META: api_key = request.META.get('Authorization') if api_key: try: api_key = APIKey.objects.get(key=api_key, is_active=True) except APIKey.DoesNotExist: raise AuthenticationFailed('Invalid API key') login(request, api_key.user, backend='django.contrib.auth.backends.ModelBackend') request.user = api_key.user return view(request, *args, **kwargs) response = HttpResponse() response.status_code = 401 response['WWW-Authenticate'] = 'Basic realm="%s"' % realm return response ############################################################################# # def view_or_basicauth(view, request, test_func, realm = "", *args, **kwargs): """ This is a helper function used by both 'logged_in_or_basicauth' and 'has_perm_or_basicauth' that does the nitty of determining if they are already logged in or if they have provided proper http-authorization and returning the view if all goes well, otherwise responding with a 401. """ if test_func(request.user): # Already logged in, just return the view. # return view(request, *args, **kwargs) # They are not logged in. See if they provided login credentials # if 'HTTP_AUTHORIZATION' in request.META: auth = request.META['HTTP_AUTHORIZATION'].split() if len(auth) == 2: # NOTE: We are only support basic authentication for now. # if auth[0].lower() == "basic": uname, passwd = base64.b64decode(auth[1]).decode("utf-8").split(':') user = authenticate(username=uname, password=passwd) if user is not None: if user.is_active: login(request, user) request.user = user return view(request, *args, **kwargs) # Either they did not provide an authorization header or # something in the authorization attempt failed. Send a 401 # back to them to ask them to authenticate. # response = HttpResponse() response.status_code = 401 response['WWW-Authenticate'] = 'Basic realm="%s"' % realm return response ############################################################################# # def logged_in_or_apikey(realm = ""): def view_decorator(func): def wrapper(request, *args, **kwargs): return view_or_apikey(func, request, lambda u: u.is_authenticated, realm, *args, **kwargs) return wrapper return view_decorator def logged_in_or_basicauth(realm = ""): """ A simple decorator that requires a user to be logged in. If they are not logged in the request is examined for a 'authorization' header. If the header is present it is tested for basic authentication and the user is logged in with the provided credentials. If the header is not present a http 401 is sent back to the requestor to provide credentials. The purpose of this is that in several django projects I have needed several specific views that need to support basic authentication, yet the web site as a whole used django's provided authentication. The uses for this are for urls that are access programmatically such as by rss feed readers, yet the view requires a user to be logged in. Many rss readers support supplying the authentication credentials via http basic auth (and they do NOT support a redirect to a form where they post a username/password.) Use is simple: @logged_in_or_basicauth def your_view: ... You can provide the name of the realm to ask for authentication within. """ def view_decorator(func): def wrapper(request, *args, **kwargs): return view_or_basicauth(func, request, lambda u: u.is_authenticated, realm, *args, **kwargs) return wrapper return view_decorator ############################################################################# # def has_perm_or_basicauth(perm, realm = ""): """ This is similar to the above decorator 'logged_in_or_basicauth' except that it requires the logged in user to have a specific permission. Use: @logged_in_or_basicauth('asforums.view_forumcollection') def your_view: ... """ def view_decorator(func): def wrapper(request, *args, **kwargs): return view_or_basicauth(func, request, lambda u: u.has_perm(perm), realm, *args, **kwargs) return wrapper return view_decorator import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('high') g_acc = 9.80665 def get_totals(workouts): totalseconds = 0 totalmeters = 0 for w in workouts: totalmeters += w.distance totalseconds += 60*(w.duration.hour*60 + w.duration.minute)+w.duration.second hours, remainder = divmod(totalseconds, 3600) minutes, seconds = divmod(remainder, 60) return totalmeters, hours, minutes, seconds # creating shareable views def allow_shares(view_func): def sharify(request, *args, **kwargs): shared = kwargs.get('__shared', None) if shared is not None: # pragma: no cover del kwargs["__shared"] request.session['shared'] = True return view_func(request, *args, **kwargs) else: return login_required(view_func)(request, *args, **kwargs) return sharify class SharifyError(Exception): pass def sharedPage(request, key): try: try: shareKey = ShareKey.objects.get(pk=key) except: # pragma: no cover raise SharifyError if shareKey.expired: # pragma: no cover raise SharifyError func, args, kwargs = resolve(shareKey.location) kwargs["__shared"] = True return func(request, *args, **kwargs) except SharifyError: # pragma: no cover # or add a more detailed error page. This either means that the key doesn’t exist or is expired. raise Http404 def createShareURL(request): if request.method == 'POST': url = request.POST['url'] ndays = int(request.POST['ndays']) key = ShareKey.objects.create(pk=get_random_string(40), expiration_seconds=60*60*24*ndays, location=url) key.save() return render(request, 'share.html', {"key": key}) else: # pragma: no cover raise Http404 def createShareModel(request, model_id): # pragma: no cover task = MyModel.objects.get(pk=model_id) key = ShareKey.objects.create(pk=get_random_string(40), expiration_seconds=60*60*24, # 1 day location=task.get_absolute_url(), ) key.save() return render(request, 'share.html', {"key": key}) # Utility to get stroke data in a JSON response class JSONResponse(HttpResponse): def __init__(self, data, **kwargs): try: content = JSONRenderer().render(data) except ValueError: content = '' kwargs['content_type'] = 'application/json' super(JSONResponse, self).__init__(content, **kwargs) def getfavorites(r, row): workouttype = 'ote' if row.workouttype in mytypes.otwtypes: workouttype = 'otw' matchworkouttypes = [workouttype, 'all'] workoutsource = row.workoutsource if 'speedcoach2' in row.workoutsource: # pragma: no cover workoutsource = 'speedcoach2' favorites = FavoriteChart.objects.filter(user=r, workouttype__in=matchworkouttypes).order_by("id") favorites2 = FavoriteChart.objects.filter(user=r, workouttype__in=[workoutsource]).order_by("id") favorites = favorites | favorites2 maxfav = len(favorites)-1 return favorites, maxfav def get_logo_by_pk(request, *args, **kwargs): # pragma: no cover id = kwargs['id'] return get_object_or_404(RaceLogo, pk=id) def get_virtualevent_by_pk(request, *args, **kwargs): id = kwargs['id'] return get_object_or_404(VirtualRace, pk=id) def get_promember(request, *args, **kwargs): # pragma: no cover return request.user def get_course_by_pk(request, *args, **kwargs): id = kwargs['id'] return get_object_or_404(GeoCourse, pk=id) def get_workout_by_opaqueid(request, id, **kwargs): pk = encoder.decode_hex(id) return get_object_or_404(Workout, pk=pk) def get_session_by_pk(request, *args, **kwargs): id = kwargs['id'] return get_object_or_404(PlannedSession, pk=id) def get_target_by_pk(request, *args, **kwargs): id = kwargs['id'] return get_object_or_404(TrainingTarget, pk=id) def get_plan_by_pk(request, *args, **kwargs): id = kwargs['id'] return get_object_or_404(TrainingPlan, pk=id) def get_macro_by_pk(request, *args, **kwargs): # pragma: no cover id = kwargs['id'] return get_object_or_404(TrainingMacroCycle, pk=id) def get_meso_by_pk(request, *args, **kwargs): # pragma: no cover id = kwargs['id'] return get_object_or_404(TrainingMesoCycle, pk=id) def get_micro_by_pk(request, *args, **kwargs): # pragma: no cover id = kwargs['id'] return get_object_or_404(TrainingMicroCycle, pk=id) def get_workout_default_page(request, id): if request.user.is_anonymous: return reverse('workout_view', kwargs={'id': id}) else: r = Rower.objects.get(user=request.user) if r.defaultlandingpage == 'workout_edit_view': return reverse('workout_edit_view', kwargs={'id': id}) else: # pragma: no cover return reverse('workout_workflow_view', kwargs={'id': id}) def get_user_by_userid(*args, **kwargs): request = args[0] try: id = kwargs['userid'] except KeyError: id = request.user.id if id is not None and int(id) == 0: id = request.user.id u = get_object_or_404(User, pk=id) return u def get_user_by_id(*args, **kwargs): # pragma: no cover request = args[0] try: id = args[1] except IndexError: try: id = kwargs['id'] except KeyError: id = request.user.id return get_object_or_404(User, pk=id) def get_rower_by_id(request, id): # pragma: no cover u = User.objects.get(id=id) return u.rower def getrequestrower(request, rowerid=0, userid=0, notpermanent=False): userid = int(userid) rowerid = int(rowerid) # if userid == 0: # userid = request.user.id if notpermanent is False: if rowerid == 0 and 'rowerid' in request.session: rowerid = request.session['rowerid'] if userid != 0: rowerid = 0 try: if rowerid != 0: r = Rower.objects.get(id=rowerid) u = r.user elif userid != 0: u = User.objects.get(id=userid) r = getrower(u) elif request.user.is_anonymous: # pragma: no cover return None else: r = getrower(request.user) u = r.user except Rower.DoesNotExist: # pragma: no cover: # pragma: no cover raise Http404("Rower doesn't exist") if r.user == request.user: request.session['rowerid'] = r.id return r if userid != 0 and not is_rower_team_member(request.user, u.rower): request.session['rowerid'] = request.user.rower.id raise PermissionDenied("You have no access to this user") if notpermanent is False: request.session['rowerid'] = r.id request.session['rowerid'] = r.id return r def getrequestrowercoachee(request, rowerid=0, userid=0, notpermanent=False): userid = int(userid) rowerid = int(rowerid) # if userid == 0: # userid = request.user.id if notpermanent is False: if rowerid == 0 and 'rowerid' in request.session: rowerid = request.session['rowerid'] if userid != 0: rowerid = 0 try: if rowerid != 0: r = Rower.objects.get(id=rowerid) u = r.user elif userid != 0: u = User.objects.get(id=userid) r = getrower(u) elif request.user.is_anonymous: # pragma: no cover return None else: r = getrower(request.user) u = r.user except Rower.DoesNotExist: # pragma: no cover: # pragma: no cover raise Http404("Rower doesn't exist") if r.user == request.user: request.session['rowerid'] = r.id return r if userid != 0 and not is_coach_user(request.user, u): # pragma: no cover request.session['rowerid'] = request.user.rower.id raise PermissionDenied("You have no access to this user") if notpermanent is False: request.session['rowerid'] = r.id request.session['rowerid'] = r.id return r def getrequestplanrower(request, rowerid=0, userid=0, notpermanent=False): userid = int(userid) rowerid = int(rowerid) if notpermanent is False: if rowerid == 0 and 'rowerid' in request.session: rowerid = request.session['rowerid'] if userid != 0: rowerid = 0 try: if rowerid != 0: r = Rower.objects.get(id=rowerid) elif userid != 0: try: u = User.objects.get(id=userid) except User.DoesNotExist: # pragma: no cover: # pragma: no cover raise Http404("User does not exist") r = getrower(u) else: r = getrower(request.user) except Rower.DoesNotExist: # pragma: no cover: # pragma: no cover raise Http404("Rower doesn't exist") if 'shared' in request.session and request.session['shared']: # pragma: no cover return r if r.user != request.user and not can_plan_user(request.user, r): request.session['rowerid'] = r.id raise PermissionDenied("You have no access to this user") if notpermanent is False: request.session['rowerid'] = r.id return r def getrower(user): try: if user is None or user.is_anonymous: return None except AttributeError: # pragma: no cover if User.objects.get(id=user).is_anonymous: return None try: r = Rower.objects.get(user=user) except Rower.DoesNotExist: # pragma: no cover: r = Rower(user=user) r.save() return r def get_workout(id): try: id = encoder.decode_hex(id) w = Workout.objects.get(id=id) except Workout.DoesNotExist: # pragma: no cover: raise Http404("Workout doesn't exist") return w def get_workoutuser(id, request): try: id = encoder.decode_hex(id) w = Workout.objects.get(id=id) except Workout.DoesNotExist: # pragma: no cover: raise Http404("Workout doesn't exist") if not is_workout_user(request.user, w): # pragma: no cover raise PermissionDenied return w def getvalue(data): # pragma: no cover total = 1 done = 0 id = 0 session_key = 'noot' for i in data.iteritems(): if i[0] == 'total': total = float(i[1]) if i[0] == 'done': done = float(i[1]) if i[0] == 'id': id = i[1] if i[0] == 'session_key': session_key = i[1] return total, done, id, session_key class SessionTaskListener(threading.Thread): # pragma: no cover def __init__(self, r, channels): threading.Thread.__init__(self) self.redis = r self.pubsub = self.redis.pubsub() self.pubsub.subscribe(channels) def work(self, item): try: data = json.loads(item['data']) total, done, id, session_key = getvalue(data) perc = int(100.*done/total) cache.set(id, perc, 3600) except TypeError: pass def run(self): for item in self.pubsub.listen(): if item['data'] == "KILL": self.pubsub.unsubscribe() break else: self.work(item) queuefailed = Queue("failed", connection=Redis()) redis_connection = StrictRedis() r = Redis() # this doesn't yet work on production # if settings.DEBUG: # client = SessionTaskListener(r,['tasks']) # client.start() rq_registry = StartedJobRegistry(queue.name, connection=redis_connection) rq_registryhigh = StartedJobRegistry( queuehigh.name, connection=redis_connection) rq_registrylow = StartedJobRegistry(queuelow.name, connection=redis_connection) try: from rest_framework_swagger.views import get_swagger_view except ImportError: # pragma: no cover pass try: from rest_framework import permissions, generics except ImportError: # pragma: no cover pass USER_LANGUAGE = 'en-US' # Define the API documentation try: schema_view = get_swagger_view(title='Rowsandall API') except NameError: # pragma: no cover pass def remove_asynctask(request, id): # pragma: no cover try: oldtasks = request.session['async_tasks'] except KeyError: oldtasks = [] newtasks = [] for task in oldtasks: if id not in task[0]: newtasks += [(task[0], task[1])] request.session['async_tasks'] = newtasks def get_job_result(jobid): # pragma: no cover if settings.TESTING: return None elif settings.CELERY: result = celery_result.AsyncResult(jobid).result else: running_job_ids = rq_registry.get_job_ids() if len(running_job_ids) and jobid in running_job_ids: # job is running return None else: # job is ready try: job = Job.fetch(jobid, connection=redis_connection) result = job.result except NoSuchJobError: return None return result verbose_job_status = { 'updatecp': 'Critical Power Calculation for Ergometer Workouts', 'updatecpwater': 'Critical Power Calculation for OTW Workouts', 'otwsetpower': 'Rowing Physics OTW Power Calculation', 'agegrouprecords': 'Calculate age group records', 'make_plot': 'Create static chart', 'long_test_task': 'Long Test Task', 'long_test_task2': 'Long Test Task 2', 'update_empower': 'Correct Empower Inflated Power Bug', 'submit_race': 'Checking Race Course Result', 'check_race_course': 'Checking Course Result', } def get_job_status(jobid): # pragma: no cover if settings.TESTING: summary = { 'status': 'failed', 'result': 0, 'finished': True, 'failed': True, 'started_at': None, } return summary elif settings.CELERY: job = celery_result.AsyncResult(jobid) jobresult = job.result if 'fail' in job.status.lower(): jobresult = '0' summary = { 'status': job.status, 'result': jobresult, 'started_at': None } else: try: job = Job.fetch(jobid, connection=redis_connection) try: status = job.status except AttributeError: status = job.get_status() summary = { 'status': status, 'result': job.result, 'started_at': job.started_at } except NoSuchJobError: summary = { 'status': 'success', 'result': 1, 'started_at': None, } try: if 'fail' in summary['status'].lower(): summary['failed'] = True else: summary['failed'] = False if 'success' in summary['status'].lower(): summary['finished'] = True elif 'finished' in summary['status'].lower(): summary['finished'] = True else: summary['finished'] = False except AttributeError: summary = { 'status': 'failed', 'result': 0, 'finished': True, 'failed': True, 'started_at': None, } return summary def kill_async_job(request, id='aap'): # pragma: no cover if settings.CELERY: job = celery_result.AsyncResult(id) job.revoke() else: try: cancel_job(id, connection=redis_connection) except NoSuchJobError: pass remove_asynctask(request, id) cache.delete(id) url = reverse(session_jobs_status) return HttpResponseRedirect(url) @login_required() def raise_500(request): # pragma: no cover if request.user.is_superuser: raise ValueError else: return HttpResponse("invalid") # @login_required() # def test_job_view(request,aantal=100): # # session_key = request.session._session_key # # job = myqueue(queuehigh,long_test_task,int(aantal), # session_key=session_key) # # # try: # request.session['async_tasks'] += [(job.id,'long_test_task')] # except KeyError: # request.session['async_tasks'] = [(job.id,'long_test_task')] # # url = reverse(session_jobs_status) # # return HttpResponseRedirect(url) # @login_required() # def test_job_view2(request,aantal=100): # # # job = myqueue(queuehigh,long_test_task2,int(aantal), # secret=settings.PROGRESS_CACHE_SECRET)# # # # try: # request.session['async_tasks'] += [(job.id,'long_test_task2')] # except KeyError: # request.session['async_tasks'] = [(job.id,'long_test_task2')] # # url = reverse(session_jobs_status) # # return HttpResponseRedirect(url) @csrf_exempt def post_progress(request, id=None, value=0): # pragma: no cover if request.method == 'POST': try: secret = request.POST['secret'] except KeyError: return HttpResponse('Access Denied', status=401) if secret == settings.PROGRESS_CACHE_SECRET: if not id: try: id = request.POST['id'] except KeyError: return HttpResponse('Invalid request', 400) try: value = request.POST['value'] except KeyError: pass cache.set(id, value, 3600) # test result = cache.get(id) return HttpResponse('progress cached '+str(result), status=201) else: # secret not given return HttpResponse('access denied', status=401) else: # request method is not POST return HttpResponse('GET method not allowed', status=405) def get_all_queued_jobs(userid=0): # pragma: no cover r = StrictRedis() jobs = [] celerykeys = r.keys('celery*') for key in celerykeys: id = key[17:] job = celery_result.AsyncResult(id) jobresult = job.result if 'fail' in job.status.lower(): jobresult = '0' jobs.append( (id, { 'status': job.status, 'result': jobresult, 'function': '', 'meta': job.info, })) ids = [j.id for j in queue.jobs] ids += [j.id for j in queuehigh.jobs] ids += [j.id for j in queuelow.jobs] ids += [j.id for j in queuefailed.jobs] for id in ids: job = Job.fetch(id, connection=redis_connection) jobs.append( (id, { 'status': job.get_status(), 'result': job.result, 'function': job.func_name, 'meta': job.meta, })) return jobs def get_stored_tasks_status(request): try: taskids = request.session['async_tasks'] except KeyError: taskids = [] taskstatus = [] for id, func_name in reversed(taskids): # pragma: no cover progress = 0 try: cached_progress = cache.get(id) if cached_progress is not None: cached_progress = int(cached_progress) else: cached_progress = 0 except ValueError: cached_progress = 0 finished = get_job_status(id)['finished'] if finished: cache.set(id, 100) progress = 100 elif cached_progress is not None and cached_progress > 0: progress = cached_progress else: progress = 0 this_task_status = { 'id': id, 'status': get_job_status(id)['status'], 'failed': get_job_status(id)['failed'], 'finished': get_job_status(id)['finished'], 'func_name': func_name, 'verbose': verbose_job_status[func_name], 'progress': progress, } taskstatus.append(this_task_status) return taskstatus @permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True) def get_thumbnails(request, id): row = get_workout_by_opaqueid(request, id) r = getrower(request.user) favorites, maxfav = getfavorites(r, row) charts = [] charts = thumbnails_set(r, encoder.decode_hex(id), favorites) try: if charts[0]['script'] == '': charts = [] except IndexError: # pragma: no cover charts = [] return JSONResponse(charts) def get_blog_posts(request): # pragma: no cover blogposts = BlogPost.objects.all().order_by("-date") jsondata = [] if blogposts: for blogpost in blogposts[0:3]: thedict = { 'title': blogpost.title, 'link': blogpost.link, } jsondata.append(thedict) return JSONResponse(jsondata) def get_blog_posts_old(request): # pragma: no cover try: response = requests.get( 'https://analytics.rowsandall.com/wp-json/wp/v2/posts?per_page=3') if response.status_code == 200: blogs_json = response.json() # with open('blogs.txt','w') as o: # o.write(json.dumps(blogs_json,indent=2,sort_keys=True)) else: blogs_json = [] except ConnectionError: pass blogposts = [] for postdata in blogs_json[0:3]: try: title = postdata['title']['rendered'].encode( 'ascii', 'xmlcharrefreplace') except TypeError: title = postdata['title']['rendered'].encode( 'ascii', 'xmlcharrefreplace').decode('utf-8') thedict = { 'title': title, # 'author': '', # 'image': image_url, # 'excerpt': excerpt_first, 'link': postdata['link'], } blogposts.append(thedict) return JSONResponse(blogposts) @login_required() def session_jobs_view(request): taskstatus = get_stored_tasks_status(request) return HttpResponse(json.dumps(taskstatus)) @login_required() def session_jobs_status(request): taskstatus = get_stored_tasks_status(request) return render(request, 'async_tasks.html', {'taskstatus': taskstatus}) # Test if row data include candidates def rowhascoordinates(row): # create interactive plot f1 = row.csvfilename rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: latitude = rowdata.df[' latitude'] if not latitude.std(): # pragma: no cover hascoordinates = 0 except (KeyError, AttributeError): hascoordinates = 0 else: # pragma: no cover hascoordinates = 0 return hascoordinates # Wrapper around the rowingdata call to catch some exceptions # Checks for CSV file, then for gzipped CSV file, and if all fails, returns 0 def rdata(csvfile=None, rower=rrower()): if csvfile is None: # pragma: no cover return 0 try: res = rrdata(csvfile=csvfile, rower=rower) except pd.errors.EmptyDataError: # pragma: no cover res = 0 except (IOError, IndexError, EOFError, FileNotFoundError): # pragma: no cover try: res = rrdata(csvfile=csvfile+'.gz', rower=rower) except (IOError, IndexError, EOFError, FileNotFoundError): res = 0 return res # Query to get teams managed and member of def get_my_teams(user): try: therower = Rower.objects.get(user=user) try: teams1 = therower.team.all() except AttributeError: # pragma: no cover teams1 = [] teams2 = Team.objects.filter(manager=user) myteams = list(set(teams1).union(set(teams2))) except TypeError: myteams = [] return myteams # Used for the interval editor - translates seconds to a time object def get_time(second): # pragma: no cover if (second <= 0) or (second > 1e9): hours = 0 minutes = 0 sec = 0 microsecond = 0 elif math.isnan(second): # pragma: no cover hours = 0 minutes = 0 sec = 0 microsecond = 0 else: days = int(second/(24.*3600.)) % (24*3600) hours = int((second-24.*3600.*days)/3600.) % 24 minutes = int((second-3600.*(hours+24.*days))/60.) % 60 sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60 microsecond = int( 1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) return datetime.time(hours, minutes, sec, microsecond) # get the workout ID from the SportTracks URI def getidfromsturi(uri, length=8): # pragma: no cover return uri[len(uri)-length:] def getidfromuri(uri): # pragma: no cover m = re.search('/(\w.*)\/(\d+)', uri) return m.group(2) # Check if a user is a Coach member def iscoachmember(user): if not user.is_anonymous: try: r = Rower.objects.get(user=user) except Rower.DoesNotExist: # pragma: no cover: r = Rower(user=user) r.save() if user.is_authenticated: if 'pro' in r.rowerplan: return True elif r.protrialexpires >= timezone.now().date(): return True return False # More User/Rower utils def add_defaultfavorites(r): for c in defaultfavoritecharts: f = FavoriteChart(user=r, yparam1=c['yparam1'], yparam2=c['yparam2'], xparam=c['xparam'], plottype=c['plottype'], workouttype=c['workouttype'], reststrokes=c['reststrokes'], notes=c['notes']) f.save() return 1 # Shows email form and sends it if submitted def sendmail(request): form = EmailForm() if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): # pragma: no cover firstname = form.cleaned_data['firstname'] lastname = form.cleaned_data['lastname'] email = form.cleaned_data['email'] subject = 'Rowsandall Contact Form:'+form.cleaned_data['subject'] message = form.cleaned_data['message'] fullemail = firstname + " " + lastname + " " + "<" + email + ">" d = { 'firstname': firstname, 'lastname': lastname, 'email': email, 'subject': subject, 'message': message, } res = send_template_email('Rowsandall ', ['Rowsandall '], subject, 'contactformemail.html', d ) if res: messages.info(request,"Your contact form was submitted") else: messages.error( request, "Something went wrong trying to send the form") return HttpResponseRedirect('/rowers/email/thankyou/') else: if "captcha" in form.errors: messages.error(request,"Bots are not welcome") return HttpResponseRedirect(reverse("sendmail")) return render(request,'email.html', { 'form': form }) def keyvalue_get_default(key, options, def_options): # pragma: no cover try: return options[key] except KeyError: return def_options[key] # Creates unix time stamp from a datetime object def totimestamp(dt, epoch=datetime.datetime(1970, 1, 1, tzinfo=tz('UTC'))): # pragma: no cover td = dt - epoch # return td.total_seconds() return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6 # Check if a column of a dataframe has the required (aantal) # number of elements. Also checks if the column is a numerical type # Replaces any faulty columns with zeros def trydf(df, aantal, column): # pragma: no cover try: s = df[column] if len(s) != aantal: return np.zeros(aantal) if not s.dtype in pl.NUMERIC_DTYPES: return np.zeros(aantal) except (KeyError, ColumnNotFoundError): s = np.zeros(aantal) return s