diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 7233b84e..e9a077cc 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -309,6 +309,8 @@ def clean_df_stats(datadf, workstrokesonly=True, ignorehr=True, # clean data remove zeros and negative values # bring metrics which have negative values to positive domain + if datadf.empty: + return datadf try: datadf['catch'] = -datadf['catch'] except KeyError: @@ -1670,7 +1672,7 @@ def getsmallrowdata_db(columns, ids=[], doclean=True, workstrokesonly=True): try: f = row.df['TimeStamp (sec)'].diff().mean() - except AttributeError: + except (AttributeError,KeyError) as e: f = 0 if f != 0 and not np.isnan(f): diff --git a/rowers/templates/about_us.html b/rowers/templates/about_us.html index 0cf52bcf..b2b2d03c 100644 --- a/rowers/templates/about_us.html +++ b/rowers/templates/about_us.html @@ -75,7 +75,7 @@

Rowsandall.com tries to be compatible with the most important tools that rowers use to capture the data (both indoor and OTW). For a full list of currently supported devides/apps, click - here. + here. diff --git a/rowers/templates/compatibility.html b/rowers/templates/compatibility.html index 6dc792cb..c23ce1f2 100644 --- a/rowers/templates/compatibility.html +++ b/rowers/templates/compatibility.html @@ -7,14 +7,15 @@

Import Compatibility

Rowsandall.com tries to be compatible with the most important tools - that rowers use to capture the data (both indoor and OTW). For a full - list of currently supported devides/apps, click - here. + that rowers use to capture the data (both indoor and OTW).

On The Water

diff --git a/rowers/templates/workout_form.html b/rowers/templates/workout_form.html index 03a04eff..a2692ca7 100644 --- a/rowers/templates/workout_form.html +++ b/rowers/templates/workout_form.html @@ -235,7 +235,7 @@

- Update Summary + Update Summary

diff --git a/rowers/tests.py b/rowers/tests.py index 5fd5288b..c465447d 100644 --- a/rowers/tests.py +++ b/rowers/tests.py @@ -1,3 +1,6 @@ +from __future__ import print_function +from bs4 import BeautifulSoup +import re from django.test import TestCase, Client,override_settings from django.core.management import call_command from django.utils.six import StringIO @@ -34,8 +37,7 @@ from dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() - - + class DjangoTestCase(TestCase, MockTestCase): def _pre_setup(self): MockTestCase.setUp(self) diff --git a/rowers/traverselinktest.py b/rowers/traverselinktest.py new file mode 100644 index 00000000..bb9826a2 --- /dev/null +++ b/rowers/traverselinktest.py @@ -0,0 +1,186 @@ +from __future__ import print_function +from bs4 import BeautifulSoup +import re +from django.test import TestCase, Client,override_settings +from django.core.management import call_command +from django.utils.six import StringIO +from django.test.client import RequestFactory +from .views import checkworkoutuser,c2_open +from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage +from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail +import rowers.plots as plots +import rowers.interactiveplots as iplots +import datetime +from rowingdata import rowingdata as rdata +from rowingdata import rower as rrower +from django.utils import timezone +from rowers.rows import handle_uploaded_file +from django.core.files.uploadedfile import SimpleUploadedFile +from time import strftime,strptime,mktime,time,daylight +import os +from rowers.tasks import handle_makeplot +from rowers.utils import serialize_list,deserialize_list +from rowers.c2stuff import C2NoTokenError +from shutil import copyfile + +from minimocktest import MockTestCase +import pandas as pd + +import json +import numpy as np + +from rowers import urls +from rowers.views import error500_view,error404_view,error400_view,error403_view + +from dataprep import delete_strokedata + +from redis import StrictRedis +redis_connection = StrictRedis() + +VERBOSE = True + +class TraverseLinksTest(TestCase): + def setUp(self): + self.u = User.objects.create_superuser( + 'superuser1', + 'superuser1@example.com','pwd') + self.r = Rower.objects.create(user=self.u,gdproptin=True,gdproptindate=timezone.now()) + nu = datetime.datetime.now() + + self.w = Workout.objects.create( + name='testworkout',workouttype='On-water', + user=self.r,date=nu.strftime('%Y-%m-%d'), + starttime=nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000) + self.w2 = Workout.objects.create( + name='testworkout 2',workouttype='On-water', + user=self.r,date=nu.strftime('%Y-%m-%d'), + starttime=nu.strftime('%H:%M:%S'), + duration="0:55:00",distance=8000) + if self.client.login( + username="superuser1", password="pwd"): + if VERBOSE: + print('\nLogin as superuser OK') + else: + raise BaseException('Login failed') + + @classmethod + def setUpTestData(cls): + # Initialise your database here as needed + pass + + + def test_traverse_urls(self): + # Fill these lists as needed with your site specific URLs to check and to avoid + to_traverse_list = ['/rowers/list-workouts'] + to_avoid_list = ['^/$', '^$', 'javascript:history\.back()', + 'javascript:history\.go\(-1\)', '^mailto:.*', + '.*github\.io.*', 'javascript:.*', + '.*biorow\.com.*','.*facebook.*', + '.*wordpress.*','.*analytics.*','.*freenet.*', + '.*twitter.*','^blog.*', + '.*\d+-\d+-\d+.*', + '.*flexchart/.*', + '.*heroku.*', + '.*oauth.*', + '.*rowingdata.*', + '.*thisisant.*', + '.*garmin.*', + '.*sub7.*', + '.*bitbucket.*', + '.*rathburn.*', + '.*team.*', + '.*concept2.*', + '.*static.*', + '.*authorize.*', + '.*youtu.*', + '.*earth.*', + '.*underarmour.*', + '.*runkeeper.*', + '.*c2list.*', + '.*stravaimport.*', + '.*performancephones.*', + '.*sporttracks.*', + '.*join-select.*', + ] + + done_list = [] + error_list = [] + source_of_link = dict() + for link in to_traverse_list: + source_of_link[link] = 'initial' + + (to_traverse_list, to_avoid_list, done_list, error_list, source_of_link) = \ + self.recurse_into_path(to_traverse_list, to_avoid_list, done_list, error_list, source_of_link) + + print('END REACHED\nStats:') + if VERBOSE: print('\nto_traverse_list = ' + str(to_traverse_list)) + if VERBOSE: print('\nto_avoid_list = ' + str(to_avoid_list)) + if VERBOSE: print('\nsource_of_link = ' + str(source_of_link)) + if VERBOSE: print('\ndone_list = ' + str(done_list)) + print('Followed ' + str(len(done_list)) + ' links successfully') + print('Avoided ' + str(len(to_avoid_list)) + ' links') + + if error_list: + print('!! ' + str(len(error_list)) + ' error(s) : ') + for error in error_list: + print(str(error) + ' found in page ' + source_of_link[error[0]]) + + print('Errors found traversing links') + assert False + else: + print('No errors') + + def recurse_into_path(self, to_traverse_list, to_avoid_list, done_list, error_list, source_of_link): + """ Dives into first item of to_traverse_list + Returns: (to_traverse_list, to_avoid_list, done_list, source_of_link) + """ + + if to_traverse_list: + url = to_traverse_list.pop() + + if not match_any(url, to_avoid_list): + print('Surfing to ' + str(url) + ', discovered in ' + str(source_of_link[url])) + response = self.client.get(url, follow=True) + + if response.status_code == 200: + soup = BeautifulSoup(response.content, 'html.parser') + + text = soup.get_text() + + for link in soup.find_all('a'): + new_link = link.get('href') + if VERBOSE: print(' Found link: ' + str(new_link)) + if match_any(new_link, to_avoid_list): + if VERBOSE: print(' Avoiding it') + elif new_link in done_list: + if VERBOSE: print(' Already done, ignoring') + elif new_link in to_traverse_list: + if VERBOSE: print(' Already in to traverse list, ignoring') + else: + if VERBOSE: print(' New, unknown link: Storing it to traverse later') + source_of_link[new_link] = url + to_traverse_list.append(new_link) + + done_list.append(url) + if VERBOSE: print('Done') + else: + error_list.append((url, response.status_code)) + to_avoid_list.append(url) + + if VERBOSE: print('Diving into next level') + return self.recurse_into_path(to_traverse_list, to_avoid_list, done_list, error_list, source_of_link) + + else: + # Nothing to traverse + if VERBOSE: print('Returning to upper level') + return to_traverse_list, to_avoid_list, done_list, error_list, source_of_link + + +def match_any(my_string, regexp_list): + if my_string: + combined = "(" + ")|(".join(regexp_list) + ")" + return re.match(combined, my_string) + else: + # 'None' as string always matches + return True diff --git a/rowers/views.py b/rowers/views.py index 489ade0a..a4d51b0d 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -2712,7 +2712,7 @@ def rower_process_testcallback(request): @login_required() def histo_all(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=10), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), deltadays=-1, startdatestring="", enddatestring="", @@ -2894,7 +2894,7 @@ def cum_flex(request,theuser=0, yparam1='power', yparam2='None', startdate=timezone.now()-datetime.timedelta(days=10), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), deltadays=-1, startdatestring="", enddatestring="", @@ -3623,7 +3623,7 @@ def rankings_view(request,theuser=0, # test to fix bug startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) thedistances = [] theworkouts = [] @@ -4029,7 +4029,7 @@ def rankings_view2(request,theuser=0, # test to fix bug startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) thedistances = [] @@ -4407,7 +4407,7 @@ def otwrankings_view(request,theuser=0, # test to fix bug startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) @@ -4683,7 +4683,7 @@ def oterankings_view(request,theuser=0, # test to fix bug startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) @@ -5080,7 +5080,7 @@ def workouts_join_select(request, message='', successmessage='', startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), teamid=0): try: @@ -5152,7 +5152,7 @@ def workouts_join_select(request, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) @@ -5239,7 +5239,7 @@ def team_comparison_select(request, message='', successmessage='', startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), teamid=0): try: @@ -5311,7 +5311,7 @@ def team_comparison_select(request, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) @@ -5478,13 +5478,13 @@ def multi_compare_view(request): # Multi Flex Chart with Grouping @user_passes_test(ispromember,login_url="/",redirect_field_name=None) def user_multiflex_select(request, - startdatestring="", - enddatestring="", - message='', - successmessage='', - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now()+datetime.timedelta(days=1), - userid=0): + startdatestring="", + enddatestring="", + message='', + successmessage='', + startdate=timezone.now()-datetime.timedelta(days=30), + enddate=timezone.now(), + userid=0): if userid == 0: user = request.user @@ -5575,7 +5575,7 @@ def user_multiflex_select(request, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) @@ -6017,7 +6017,7 @@ def user_boxplot_select(request, message='', successmessage='', startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), options={ 'includereststrokes':False, 'workouttypes':['rower','dynamic','slides'], @@ -6113,7 +6113,7 @@ def user_boxplot_select(request, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) @@ -6413,7 +6413,7 @@ def courses_view(request): def workouts_view(request,message='',successmessage='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now()+datetime.timedelta(days=1), + enddate=timezone.now(), teamid=0,rankingonly=False,rowerid=0,userid=0): request.session['referer'] = absolute(request)['PATH'] @@ -6448,7 +6448,7 @@ def workouts_view(request,message='',successmessage='', startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) @@ -6590,7 +6590,7 @@ def workout_comparison_list(request,id=0,message='',successmessage='', startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if enddate < startdate: s = enddate @@ -6668,7 +6668,7 @@ def workout_fusion_list(request,id=0,message='',successmessage='', startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - enddate = enddate+datetime.timedelta(days=1) + #enddate = enddate+datetime.timedelta(days=1) if enddate < startdate: s = enddate @@ -10988,7 +10988,10 @@ def workout_summary_edit_view(request,id,message="",successmessage="" if rowdata == 0: return HttpResponse("Error: CSV Data File Not Found") intervalstats = rowdata.allstats() - itime,idist,itype = rowdata.intervalstats_values() + try: + itime,idist,itype = rowdata.intervalstats_values() + except TypeError: + return HttpResponse("Error: CSV Data File Not Found") nrintervals = len(idist) # create interactive plot @@ -12209,7 +12212,7 @@ def plannedsession_multiclone_view( request,timeperiod='none', rowerid=0, startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now()+datetime.timedelta(days=1)): + enddate=timezone.now()): if rowerid==0: r = getrower(request.user)