From 0c13f798de693df4a27456849d36926fb2aa7e97 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 19 Apr 2021 08:41:48 +0200 Subject: [PATCH 1/9] adding async option to NK import --- rowers/c2stuff.py | 2 +- rowers/nkstuff.py | 24 ++++++++++++++++++++++-- rowers/runkeeperstuff.py | 2 +- rowers/sporttracksstuff.py | 2 +- rowers/stravastuff.py | 4 ++-- rowers/tasks.py | 5 ++++- rowers/underarmourstuff.py | 2 +- rowers/urls.py | 1 + rowers/views/importviews.py | 12 +++++++++--- 9 files changed, 42 insertions(+), 12 deletions(-) diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index 2540fc07..bb166676 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -902,7 +902,7 @@ def make_authorization_url(request): return HttpResponseRedirect(url) # Get workout from C2 ID -def get_workout(user,c2id): +def get_workout(user,c2id,do_async=False): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): s = "Token doesn't exist. Need to authorize" diff --git a/rowers/nkstuff.py b/rowers/nkstuff.py index 82a5f48d..5d82f692 100644 --- a/rowers/nkstuff.py +++ b/rowers/nkstuff.py @@ -247,7 +247,7 @@ def get_nk_workout_list(user,fake=False,after=0,before=0): # -def get_workout(user,nkid): +def get_workout(user,nkid,do_async=False): r = Rower.objects.get(user=user) if (r.nktoken == '') or (r.nktoken is None): s = "Token doesn't exist. Need to authorize" @@ -260,6 +260,27 @@ def get_workout(user,nkid): 'sessionIds': nkid, } + if do_async: + res = get_nk_workout_list(r.user) + if res.status_code != 200: + return 0 + alldata = {} + for item in res.json(): + alldata[item['id']] = item + + res = myqueue( + queuehigh, + handle_nk_async_workout, + alldata, + r.user.id, + r.nktoken, + nkid, + 0, + r.defaulttimezone, + ) + + return {},pd.DataFrame() + authorizationstring = str('Bearer ' + r.nktoken) headers = {'Authorization': authorizationstring, @@ -292,7 +313,6 @@ def get_workout(user,nkid): before = before+timedelta(days=1) before = str(int(before.timestamp())*1000) after = str(int(after.timestamp())*1000) - print(after) url = NK_API_LOCATION+"api/v1/sessions/" diff --git a/rowers/runkeeperstuff.py b/rowers/runkeeperstuff.py index a087f7bf..4329cdb9 100644 --- a/rowers/runkeeperstuff.py +++ b/rowers/runkeeperstuff.py @@ -92,7 +92,7 @@ def get_runkeeper_workout_list(user): return s # Get workout summary data by Runkeeper ID -def get_workout(user,runkeeperid): +def get_workout(user,runkeeperid,do_async=False): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): return custom_exception_handler(401,s) diff --git a/rowers/sporttracksstuff.py b/rowers/sporttracksstuff.py index 55cf279f..8cb5d1e4 100644 --- a/rowers/sporttracksstuff.py +++ b/rowers/sporttracksstuff.py @@ -97,7 +97,7 @@ def get_sporttracks_workout_list(user): return s # Get workout summary data by SportTracks ID -def get_workout(user,sporttracksid): +def get_workout(user,sporttracksid,do_async=False): r = Rower.objects.get(user=user) if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): return custom_exception_handler(401,s) diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index c1b319ae..966dc278 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -382,7 +382,7 @@ def async_get_workout(user,stravaid): return job # Get a Strava workout summary data and stroke data by ID -def get_workout(user,stravaid): +def get_workout(user,stravaid,do_async=False): try: thetoken = strava_open(user) except NoTokenError: @@ -773,7 +773,7 @@ def workout_strava_upload(user,w, quick=False,asynchron=True): activity_type = mytypes.stravamapping[w.workouttype] except KeyError: activity_type = 'Rowing' - + with open(tcxfile,'rb') as f: res,mes = handle_stravaexport( f,w.name, diff --git a/rowers/tasks.py b/rowers/tasks.py index 36008a98..c9355451 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2894,7 +2894,10 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone,debug=False,**kwargs): time.sleep(delaysec) - data = alldata[nkid] + try: + data = alldata[nkid] + except KeyError: + data = alldata[int(nkid)] params = { 'sessionIds': nkid, diff --git a/rowers/underarmourstuff.py b/rowers/underarmourstuff.py index be44ea7f..f230e8de 100644 --- a/rowers/underarmourstuff.py +++ b/rowers/underarmourstuff.py @@ -70,7 +70,7 @@ def get_underarmour_workout_list(user): return s # Get workout summary data by Underarmour ID -def get_workout(user,underarmourid): +def get_workout(user,underarmourid,do_async=False): r = Rower.objects.get(user=user) if (r.underarmourtoken == '') or (r.underarmourtoken is None): return custom_exception_handler(401,s) diff --git a/rowers/urls.py b/rowers/urls.py index 3df7665a..c7b0d31c 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -496,6 +496,7 @@ urlpatterns = [ name='workout_getrp3importview'), re_path(r'^workout/rp3import/all/$',views.workout_getrp3workout_all,name='workout_getrp3workout_all'), re_path(r'^workout/(?P\w+.*)import/(?P\d+)/$',views.workout_getimportview,name='workout_getimportview'), + re_path(r'^workout/(?P\w+.*)import/(?P\d+)/async/$',views.workout_getimportview,{'do_async':True},name='workout_getimportview'), re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'), re_path(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next,name='workout_getstravaworkout_next'), re_path(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'), diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index fc19b013..fe8d9d00 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -2001,9 +2001,15 @@ def workout_getrp3importview(request,externalid): return HttpResponseRedirect(url) @login_required() -def workout_getimportview(request,externalid,source = 'c2'): - data,strokedata = importsources[source].get_workout(request.user,externalid) - +def workout_getimportview(request,externalid,source = 'c2',do_async=False): + data,strokedata = importsources[source].get_workout(request.user,externalid, + do_async=do_async) + + if do_async: + messages.info(request,"Your workout will be imported in the background") + url = reverse('workouts_view') + return HttpResponseRedirect(url) + if not data: messages.error(request,"No strokedata received") url = reverse('workouts_view') From ed5af7d8b7363330cc1b75cbda77221c5e2ee207 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 19 Apr 2021 10:22:02 +0200 Subject: [PATCH 2/9] adding rp3 sync to tests --- rowers/imports.py | 1 + rowers/rp3stuff.py | 2 + rowers/tasks.py | 6 ++ rowers/tests/mocks.py | 58 ++++++++++++++++++- rowers/tests/test_imports.py | 87 ++++++++++++++++++++++++++++ rowers/tests/testdata/rp3content.csv | 7 +++ 6 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 rowers/tests/testdata/rp3content.csv diff --git a/rowers/imports.py b/rowers/imports.py index cb1cb83f..a5b5f171 100644 --- a/rowers/imports.py +++ b/rowers/imports.py @@ -93,6 +93,7 @@ def imports_open(user,oauth_data): except (TypeError,AttributeError,KeyError): tokenexpirydate = None + if (token == '') or (token is None): s = "Token doesn't exist. Need to authorize" raise NoTokenError("User has no token") diff --git a/rowers/rp3stuff.py b/rowers/rp3stuff.py index a4f9e99e..2377b2e3 100644 --- a/rowers/rp3stuff.py +++ b/rowers/rp3stuff.py @@ -114,12 +114,14 @@ def get_rp3_workout_list(user): executed_at } }""" + response = requests.post( url=graphql_url, headers=headers, json={'query': get_workouts_list} ) + return response def get_rp3_workouts(rower,do_async=True): diff --git a/rowers/tasks.py b/rowers/tasks.py index c9355451..6b19f50d 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2857,9 +2857,15 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de res = requests.get(download_url,headers=headers) + if not startdatetime: startdatetime = str(timezone.now()) + try: + startdatetime = str(startdatetime) + except: + pass + if res.status_code != 200: return 0 diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 845690a9..70969d21 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -98,7 +98,6 @@ def mocked_myqueue(*args, **kwargs): return Job() def mock_c2open(*args, **kwargs): - print('mock') return('aap') def mocked_session(*args, **kwargs): @@ -123,6 +122,16 @@ def mocked_session(*args, **kwargs): def json(self): return self.json_data + class MockContentResponse: + def __init__(self,filename,status_code): + with open(filename,'rb') as f: + s = f.read() + self.content = s + self.status_code = status_code + self.ok = True + + + return MockEngine() def mocked_sqlalchemy(*args, **kwargs): @@ -697,6 +706,11 @@ def mocked_requests(*args, **kwargs): with open('rowers/tests/testdata/nk_list.json','r') as infile: nkworkoutlist = json.load(infile) + with open('rowers/tests/testdata/rp3_list.json','r') as infile: + rp3workoutlist = json.load(infile) + + rp3linkready = {'data': {'download': {'id': 591621, 'status': 'ready', 'link': 'https://rp3rowing-app.com/api/workouts/591621/download?type=csv'}}} + with open('rowers/tests/testdata/example-session-strokes-with-impeller-data.json','r') as infile: nkimpellerstrokedata = json.load(infile) @@ -781,6 +795,15 @@ def mocked_requests(*args, **kwargs): def json(self): return self.json_data + class MockContentResponse: + def __init__(self,filename,status_code): + with open(filename,'rb') as f: + s = f.read() + self.content = s + self.status_code = status_code + self.ok = True + + class MockHeaderResponse: def __init__(self, header_data, status_code): @@ -832,6 +855,9 @@ def mocked_requests(*args, **kwargs): if 'garmin' in args: return MockOAuth1Session() + if 'url' in kwargs: + if 'rp3' in kwargs['url']: + args = [kwargs['url']] if not args: return MockSession() @@ -845,6 +871,7 @@ def mocked_requests(*args, **kwargs): uatester = re.compile('.*?mapmyfitness\.com') tptester = re.compile('.*?trainingpeaks\.com') nktester = re.compile('.*?nkrowlink\.com') + rp3tester = re.compile('.*?rp3rowing-app\.com') garmintester = re.compile('.*?garmin\.com') c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' @@ -865,6 +892,8 @@ def mocked_requests(*args, **kwargs): nkstrokesregex = '.*?nkrowlink\.com\/api\/v1\/sessions\/strokes' nkstrokestester = re.compile(nkstrokesregex) + rp3graphregex = '.*?rp3rowing-app\.com\/graphql' + rp3graphtester = re.compile(rp3graphregex) stravaathleteregex = '.*?strava\.com\/api\/v3\/athlete$' stravaathletetester = re.compile(stravaathleteregex) @@ -1052,6 +1081,33 @@ def mocked_requests(*args, **kwargs): return MockResponse(nkimpellerworkoutlist,200) return MockResponse(nkworkoutlist,200) + if rp3tester.match(args[0]): + if 'token' in args[0]: + json_data = { + 'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq', + 'expires_in': 604800, + 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' + } + return MockResponse(json_data,200) + + if 'api' in args[0]: + if '591621' in args[0]: + return MockContentResponse('rowers/tests/testdata/rp3content.csv',200) + + + if rp3graphtester.match(args[0]): + if 'json' in kwargs: + try: + query = kwargs['json']['query'] + if 'download' in query: + return MockResponse(rp3linkready,200) + except KeyError: + pass + json_data = rp3workoutlist + return MockResponse(json_data,200) + + + if stravatester.match(args[0]): diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 6a42f1a4..affe1025 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -509,6 +509,93 @@ class NKObjects(DjangoTestCase): w = Workout.objects.get(id=1) #self.assertTrue(w.impeller) +#@pytest.mark.django_db +@override_settings(TESTING=True) +class RP3Objects(DjangoTestCase): + def setUp(self): + self.c = Client() + self.u = User.objects.create_user('john', + 'sander@ds.ds', + 'koeinsloot') + + self.u.first_name = 'John' + self.u.last_name = 'Sander' + self.u.save() + self.r = Rower.objects.create(user=self.u,gdproptin=True,surveydone=True, + gdproptindate=timezone.now() + ) + + self.r.rp3token = '12' + self.r.rp3refreshtoken = '123' + self.r.rp3tokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime + + self.r.save() + self.c.login(username='john',password='koeinsloot') + self.nu = datetime.datetime.now() + + filename = 'rowers/tests/testdata/testdata.csv' + + rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, + hrut1=self.r.ut1,hrat=self.r.at, + hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) + row = rdata(csvfile=filename,rower=rr) + totaldist = row.df['cum_dist'].max() + totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() + totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] + + + hours = int(totaltime/3600.) + minutes = int((totaltime - 3600.*hours)/60.) + seconds = int(totaltime - 3600.*hours - 60.*minutes) + tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) + + duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) + + + workoutdate = row.rowdatetime.strftime('%Y-%m-%d') + workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') + + self.w = Workout.objects.create( + name='testworkout',workouttype='water', + user=self.r,date=self.nu.strftime('%Y-%m-%d'), + starttime=workoutstarttime, + startdatetime=row.rowdatetime, + duration=duration,distance=totaldist, + csvfilename=filename + ) + + @patch('rowers.rp3stuff.requests.get', side_effect=mocked_requests) + @patch('rowers.rp3stuff.requests.post', side_effect=mocked_requests) + @patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db) + def test_rp3_import(self, mock_get, mockpost, + mocked_getsmallrowdata_db): + + response = self.c.get('/rowers/workout/rp3import/591621',follow=True) + + expected_url = reverse('workout_rp3import_view') + + self.assertRedirects(response, + expected_url=expected_url, + status_code=301,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + w = Workout.objects.get(id=1) + + @patch('rowers.tasks.requests.get',side_effect=mocked_requests) + @patch('rowers.tasks.requests.post',side_effect=mocked_requests) + @patch('rowers.tasks.requests.session', side_effect=mocked_requests) + def test_handle_rp3_get_workouts(self, mock_get, mockpost,MockSession): + userid = self.u.id + rp3token = 'ap' + rp3id = '591621' + startdatetime = timezone.now()-datetime.timedelta(days=30) + max_attempts = 2 + + res = tasks.handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts) + self.assertEqual(res,1) + + #@pytest.mark.django_db @override_settings(TESTING=True) diff --git a/rowers/tests/testdata/rp3content.csv b/rowers/tests/testdata/rp3content.csv new file mode 100644 index 00000000..a761e8d5 --- /dev/null +++ b/rowers/tests/testdata/rp3content.csv @@ -0,0 +1,7 @@ +id,workout_interval_id,ref,stroke_number,power,avg_power,stroke_rate,time,stroke_length,distance,distance_per_stroke,estimated_500m_time,energy_per_stroke,energy_sum,pulse,work_per_pulse,peak_force,peak_force_pos,rel_peak_force_pos,drive_time,recover_time,k,curve_data,stroke_number_in_interval,avg_calculated_power +,963271,55,1,31.73,28.78,65.05,0.95,83.6,2.07,207.2,222.6,537.75,0.54,0,0,509,26.4,31.58,0.92,0,1,"1,181,327,391,410,432,449,464,479,492,503,509,509,507,502,493,482,469,461,452,441,429,416,400,381,364,345,327,312,298,283,260,228,183,135,86,40,2,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",1,31.73 +,963271,56,2,94.06,53.18,71.18,1.8,70.4,4.79,271.98,154.96,356.01,0.89,0,0,435,26.4,37.5,0.47,0.37,0.82,"29,25,83,167,283,366,401,419,413,420,431,435,425,422,405,391,385,372,366,361,342,326,312,290,275,258,232,203,162,111,68,39,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",2,62.895 +,963271,57,3,156.86,90.58,77.96,2.43,61.6,7.74,294.47,130.67,262.23,1.16,0,0,364,17.6,28.57,0.36,0.41,0.8,"44,36,113,190,293,338,342,364,328,343,352,338,343,339,336,317,309,288,268,260,249,217,203,164,136,107,76,36,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",3,94.216666666667 +,963271,58,4,182.59,122.14,79.38,3.06,57.2,10.78,304.24,124.22,208.42,1.36,0,0,318,17.6,30.77,0.32,0.44,0.81,"52,41,116,174,277,312,299,318,302,296,313,292,291,281,271,258,238,233,203,199,167,129,108,76,45,5,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",4,116.31 +,963271,59,5,185.23,101.92,88.26,4.08,41.8,13.53,274.94,123.63,92.53,1.46,0,0,203,13.2,31.58,0.23,0.45,0.8,"55,21,72,125,170,203,181,174,170,158,151,150,139,109,110,91,69,59,41,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",5,130.094 +,963271,60,6,180.11,111.58,98.39,4.68,15.4,15.97,244.35,124.79,14.35,1.47,0,0,59,6.6,42.86,0.09,0.52,0.8,"52,30,59,46,48,44,16,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768",6,138.43 From c494fdca2c174447044cbe1b8d1b742e82e54cc1 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 19 Apr 2021 14:10:19 +0200 Subject: [PATCH 3/9] adding tests related to planviews --- rowers/tasks.py | 50 +++++------ rowers/tests/test_imports.py | 14 +++ rowers/tests/test_plans.py | 163 ++++++++++++++++++++++++++++++++++- rowers/urls.py | 12 ++- rowers/views/planviews.py | 142 +++++++++++++++--------------- 5 files changed, 278 insertions(+), 103 deletions(-) diff --git a/rowers/tasks.py b/rowers/tasks.py index 6b19f50d..fdaf22fe 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2834,7 +2834,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de ) - if response.status_code != 200: + if response.status_code != 200: # pragma: no cover have_link = True workout_download_details = pd.json_normalize(response.json()['data']['download']) @@ -2845,12 +2845,12 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de counter += 1 - if counter>max_attempts: + if counter>max_attempts: # pragma: no cover have_link = True time.sleep(waittime) - if download_url == '': + if download_url == '': # pragma: no cover return 0 filename = 'media/RP3Import_'+str(rp3id)+'.csv' @@ -2858,15 +2858,15 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de res = requests.get(download_url,headers=headers) - if not startdatetime: + if not startdatetime: # pragma: no cover startdatetime = str(timezone.now()) try: startdatetime = str(startdatetime) - except: + except: # pragma: no cover pass - if res.status_code != 200: + if res.status_code != 200: # pragma: no cover return 0 @@ -2889,7 +2889,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de response = session.post(UPLOAD_SERVICE_URL,json=uploadoptions) - if response.status_code != 200: + if response.status_code != 200: # pragma: no cover return 0 workoutid = response.json()['id'] @@ -2902,7 +2902,7 @@ def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone try: data = alldata[nkid] - except KeyError: + except KeyError: # pragma: no cover data = alldata[int(nkid)] params = { @@ -3001,7 +3001,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone try: t = data['comments'].split('\n', 1)[0] title += t[:40] - except: + except: # pragma: no cover title = '' weightcategory = 'hwt' @@ -3033,7 +3033,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone try: notes = data['comments'] name = notes[:40] - except (KeyError,TypeError): + except (KeyError,TypeError): # pragma: no cover notes = 'C2 Import Workout from {startdatetime}'.format(startdatetime=startdatetime) name = notes @@ -3044,10 +3044,10 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes" try: s = requests.get(url,headers=headers) - except ConnectionError: + except ConnectionError: # pragma: no cover return 0 - if s.status_code != 200: + if s.status_code != 200: # pragma: no cover return 0 strokedata = pd.DataFrame.from_dict(s.json()['data']) @@ -3065,7 +3065,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone nr_rows = len(unixtime) - try: + try: # pragma: no cover latcoord = strokedata.loc[:,'lat'] loncoord = strokedata.loc[:,'lon'] except: @@ -3075,19 +3075,19 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone try: strokelength = strokedata.loc[:,'strokelength'] - except: + except: # pragma: no cover strokelength = np.zeros(nr_rows) dist2 = 0.1*strokedata.loc[:,'d'] try: spm = strokedata.loc[:,'spm'] - except KeyError: + except KeyError: # pragma: no cover spm = 0*dist2 try: hr = strokedata.loc[:,'hr'] - except KeyError: + except KeyError: # pragma: no cover hr = 0*spm pace = strokedata.loc[:,'p']/10. @@ -3096,7 +3096,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone velo = 500./pace power = 2.8*velo**3 - if workouttype == 'bike': + if workouttype == 'bike': # pragma: no cover velo = 1000./pace df = pd.DataFrame({'TimeStamp (sec)':unixtime, @@ -3142,12 +3142,12 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone response = session.post(UPLOAD_SERVICE_URL,json=uploadoptions) - if response.status_code != 200: + if response.status_code != 200: # pragma: no cover return 0 workoutid = response.json()['id'] - if debug: + if debug: # pragma: no cover engine = create_engine(database_url_debug, echo=False) else: engine = create_engine(database_url, echo=False) @@ -3158,7 +3158,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone with engine.connect() as conn, conn.begin(): result = conn.execute(query) tdata = result.fetchall() - if tdata: + if tdata: # pragma: no cover newc2id = tdata[0][0] conn.close() @@ -3185,16 +3185,16 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone # summary if 'workout' in data: - if 'splits' in data['workout']: + if 'splits' in data['workout']: # pragma: no cover splitdata = data['workout']['splits'] - elif 'intervals' in data['workout']: + elif 'intervals' in data['workout']: # pragma: no cover splitdata = data['workout']['intervals'] - else: + else: # pragma: no cover splitdata = False else: splitdata = False - if splitdata: + if splitdata: # pragma: no cover summary,sa,results = summaryfromsplitdata(splitdata,data,csvfilename,workouttype=workouttype) query = "UPDATE `rowers_workout` SET `summary` = '%s' WHERE `id` = %s" % (summary, workoutid) @@ -3440,7 +3440,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu try: power = strokedata.loc[:,'power'] - except KeyError: + except KeyError: # pragma: no cover power = 2.8*velo**3 #if power.std() == 0 and power.mean() == 0: diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index affe1025..ce2463a4 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -292,6 +292,20 @@ class C2Objects(DjangoTestCase): res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2') + @patch('rowers.tasks.requests.get',side_effect=mocked_requests) + @patch('rowers.tasks.requests.post',side_effect=mocked_requests) + @patch('rowers.tasks.requests.session', side_effect=mocked_requests) + def test_handle_c2_get_workouts(self, mock_get, mockpost,MockSession): + with open('rowers/tests/testdata/c2workoutlist.txt','r') as infile: + c2workoutdata = json.load(infile) + + alldata = {} + for item in c2workoutdata['data']: + alldata[item['id']] = item + + res = tasks.handle_c2_async_workout(alldata,self.u.id,self.r.c2token,33991243,0,self.r.defaulttimezone) + self.assertEqual(res,1) + @override_settings(TESTING=True) class C2ObjectsTokenExpired(DjangoTestCase): def setUp(self): diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index a961e0bb..18651eea 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -182,6 +182,99 @@ class TrainingPlanTest(TestCase): # status_code=302,target_status_code=200) +@override_settings(TESTING=True) +class SessionTemplateTest(TestCase): + def setUp(self): + self.u = UserFactory() + + self.r = Rower.objects.create(user=self.u, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='coach') + + self.c = Client() + self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + self.factory = RequestFactory() + self.password = faker.word() + self.u.set_password(self.password) + self.u.save() + self.pss = [] + + for w in self.user_workouts: + startdatetime = w.startdatetime + + startdate = (startdatetime-datetime.timedelta(days=1)).date() + enddate = (startdatetime+datetime.timedelta(days=1)).date() + preferreddate = startdatetime.date() + + ps = SessionFactory(startdate=startdate,enddate=enddate, + sessiontype='session', + sessionmode = 'time', + criterium = 'none', + sessionvalue = 60, + sessionunit='min', + preferreddate=preferreddate, + manager=self.u, + ) + + + ps.save() + + self.pss.append(ps) + + result = plannedsessions.add_rower_session(self.r,ps) + + + def tearDown(self): + for workout in self.user_workouts: + try: + os.remove(workout.csvfilename) + except (IOError, FileNotFoundError,OSError): + pass + + def test_createtemplate_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('plannedsession_createtemplate_view') + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + post_data = { + 'comment': faker.text(), + 'criterium': 'none', + 'sessionsport': 'water', + 'sessionmode':'time', + 'sessiontype':'session', + 'sessionunit':'min', + 'sessionvalue': '60', + 'name': faker.word(), + } + + form = PlannedSessionTemplateForm(post_data) + self.assertTrue(form.is_valid()) + + expected_url = reverse('template_library_view') + + + response = self.c.post(url,post_data,follow=True) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + + templates = PlannedSession.objects.filter(is_template=True) + self.assertEqual(templates.count(),1) + + t = templates[0] + t.tags.add('test') + url = reverse('template_share_view',kwargs={'id':t.id}) + + response = self.c.get(url,follow=True) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + + url = reverse('template_makeprivate_view',kwargs={'id':t.id}) + + response = self.c.get(url,follow=True) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) @override_settings(TESTING=True) class SessionLinkTest(TestCase): @@ -1335,6 +1428,7 @@ class PlannedSessionsView(TestCase): self.ps_trimp.save() added = plannedsessions.add_rower_session(self.u.rower,self.ps_trimp) added = plannedsessions.add_team_session(self.team,self.ps_trimp) + self.ps_trimp.save() def tearDown(self): try: @@ -1359,6 +1453,53 @@ class PlannedSessionsView(TestCase): # expected_url=expected_url, # status_code=302,target_status_code=200) + def test_teamclone_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('plannedsession_teamclone_view',kwargs={'id':self.ps_trimp.id}) + + today = datetime.date.today() + b = datetime.date.today()-timezone.timedelta(today.weekday()) + e = b+timezone.timedelta(days=6) + + expected_url = '/rowers/sessions/teamedit/5/' + + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + + def test_totemplate_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('plannedsession_totemplate_view',kwargs={'id':self.ps_trimp.id}) + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + + + def test_message_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('plannedsession_message_view',kwargs={'id':self.ps_trimp.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form_data = { + 'rower':[self.r.id], + 'subject':'test', + 'message':'apestaart en knokroos' + } + + form = VirtualRaceAthleteForm(form_data,instance=self.ps_trimp) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data,follow=True) + expected_url = reverse('plannedsession_view',kwargs={'id':self.ps_trimp.id}) + + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + + def test_multiclone_view(self): login = self.c.login(username=self.u.username, password=self.password) self.assertTrue(login) @@ -1441,6 +1582,7 @@ class PlannedSessionsView(TestCase): form_data = { 'team':[self.team.id], + 'members': [self.r.id], 'startdate': self.w1.startdatetime.date(), 'enddate': (self.w1.startdatetime+datetime.timedelta(days=5)).date(), 'preferreddate': self.w1.startdatetime.date(), @@ -1466,6 +1608,21 @@ class PlannedSessionsView(TestCase): response = self.c.post(url,form_data,follow=True) self.assertEqual(response.status_code,200) + pss = PlannedSession.objects.filter(name=form_data['name'],comment=form_data['comment']) + self.assertEqual(pss.count(),1) + ps = pss[0] + url = reverse('plannedsession_teamedit_view',kwargs={'id':ps.id}) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form_data['name'] = faker.word() + plannedsessionform = PlannedSessionForm(form_data,instance=ps) + self.assertTrue(plannedsessionform.is_valid()) + + response = self.c.post(url,form_data,follow=True) + self.assertEqual(response.status_code,200) + def test_teamedit_view(self): login = self.c.login(username=self.u.username, password=self.password) @@ -1630,9 +1787,7 @@ class PlannedSessionsView(TestCase): login = self.c.login(username=self.u.username, password=self.password) self.assertTrue(login) - url = '/rowers/sessions/{id}/edit/'.format( - id=self.ps_time.id, - ) + url = reverse('plannedsession_edit_view',kwargs={'id':self.ps_time.id}) response = self.c.get(url) self.assertEqual(response.status_code,200) @@ -1658,7 +1813,7 @@ class PlannedSessionsView(TestCase): self.assertTrue(form.is_valid()) - response = self.c.post(url,follow=True) + response = self.c.post(url,form_data,follow=True) self.assertEqual(response.status_code,200) diff --git a/rowers/urls.py b/rowers/urls.py index c7b0d31c..26674436 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -761,16 +761,20 @@ urlpatterns = [ name='plannedsession_edit_view'), re_path(r'^sessions/(?P\d+)/templateedit/',views.plannedsession_templateedit_view, name='plannedsession_templateedit_view'), - re_path(r'^sessions/(?P\d+)/maketemplate/$',views.plannedsession_totemplate_view), + re_path(r'^sessions/(?P\d+)/maketemplate/$',views.plannedsession_totemplate_view, + name='plannedsession_totemplate_view'), re_path(r'^sessions/(?P\d+)/compare/$', views.plannedsession_compare_view, name='plannedsession_compare_view'), re_path(r'^sessions/(?P\d+)/compare/user/(?P\d+)/$', views.plannedsession_compare_view, name='plannedsession_compare_view'), - re_path(r'^sessions/(?P\d+)/edit/user/(?P\d+)/$',views.plannedsession_edit_view), - re_path(r'^sessions/(?P\d+)/clone/user/(?P\d+)/$',views.plannedsession_clone_view), - re_path(r'^sessions/(?P\d+)/clone/team/$',views.plannedsession_teamclone_view), + re_path(r'^sessions/(?P\d+)/edit/user/(?P\d+)/$',views.plannedsession_edit_view, + name='plannedsession_edit_view'), + re_path(r'^sessions/(?P\d+)/clone/user/(?P\d+)/$',views.plannedsession_clone_view, + name='plannedsession_clone_view'), + re_path(r'^sessions/(?P\d+)/clone/team/$',views.plannedsession_teamclone_view, + name='plannedsession_teamclone_view'), re_path(r'^sessions/(?P\d+)/clone/$',views.plannedsession_clone_view), re_path(r'^sessions/(?P\d+)/detach/(?P\b[0-9A-Fa-f]+\b)/user/(?P\d+)/$',views.plannedsession_detach_view), re_path(r'^sessions/(?P\d+)/detach/(?P\b[0-9A-Fa-f]+\b)/$',views.plannedsession_detach_view), diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 62f5bd92..918c40c1 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -25,9 +25,9 @@ def plannedsession_comment_view(request,id=0,userid=0): comment = cd['comment'] comment = bleach.clean(comment) try: - if isinstance(comment,unicode): + if isinstance(comment,unicode): # pragma: no cover comment = comment.encode('utf8') - elif isinstance(comment, str): + elif isinstance(comment, str): # pragma: no cover comment = comment.decode('utf8') except: pass @@ -45,13 +45,13 @@ def plannedsession_comment_view(request,id=0,userid=0): comment = comment, url = url, ) - if request.user != manager: + if request.user != manager: # pragma: no cover a_messages.info(r.user,message.encode('ascii','ignore')) sessiontype = 'training session' - if ps.sessiontype == 'race': + if ps.sessiontype == 'race': # pragma: no cover sessiontype = 'online virtual race' - elif ps.sessiontype == 'indoorrace': + elif ps.sessiontype == 'indoorrace': # pragma: no cover sessiontype = 'indoor online virtual race' res = myqueue(queuehigh, @@ -67,14 +67,14 @@ def plannedsession_comment_view(request,id=0,userid=0): ) commenters = {oc.user for oc in comments if oc.notification} - if ps.sessiontype=='race': + if ps.sessiontype=='race': # pragma: no cover registrations = VirtualRaceResult.objects.filter( race__id=ps.id, emailnotifications=True) ids = [rg.userid for rg in registrations] rwrs = Rower.objects.filter(id__in= ids) rowers = {u.user for u in rwrs} - elif ps.sessiontype=='indoorrace': + elif ps.sessiontype=='indoorrace': # pragma: no cover registrations = IndoorVirtualRaceResult.objects.filter( race__id=ps.id, emailnotifications=True) @@ -87,9 +87,9 @@ def plannedsession_comment_view(request,id=0,userid=0): for u in commenters: try: a_messages.info(u,message) - except ValueError: + except ValueError: # pragma: no cover pass - if u != request.user and u != r.user: + if u != request.user and u != r.user: # pragma: no cover ocr = Rower.objects.get(user=u) res = myqueue(queue, handle_sendemailnewresponse, @@ -106,7 +106,7 @@ def plannedsession_comment_view(request,id=0,userid=0): sessiontype = sessiontype, commentlink = url ) - if ps.sessiontype in ['race','indoorrace']: + if ps.sessiontype in ['race','indoorrace']: # pragma: no cover followers = VirtualRaceFollower.objects.filter(race__id=ps.id) for follower in followers: othername = '' @@ -133,7 +133,7 @@ def plannedsession_comment_view(request,id=0,userid=0): rower = getrower(request.user) - if ps.sessiontype in ['race','indoorrace']: + if ps.sessiontype in ['race','indoorrace']: # pragma: no cover breadcrumbs = [ { 'url':reverse('virtualevents_view'), @@ -209,12 +209,14 @@ def plannedsession_message_view(request,id=0,userid=0): message, ) + url = reverse('plannedsession_view',kwargs={'id':ps.id}) + if ps.sessiontype in ['race','indoorrace']: # pragma: no cover + url = reverse('virtualevent_view',kwargs={'id':ps.id}) - url = reverse('virtualevent_view',kwargs={'id':ps.id}) return HttpResponseRedirect(url) - if ps.sessiontype in ['race','indoorrace']: + if ps.sessiontype in ['race','indoorrace']: # pragma: no cover breadcrumbs = [ { 'url':reverse('virtualevents_view'), @@ -274,7 +276,7 @@ def plannedsession_multiclone_view( startdate,enddate = get_dates_timeperiod(request) teamid = get_team(request) - if request.method == 'POST' and 'daterange' in request.POST: + if request.method == 'POST' and 'daterange' in request.POST: # pragma: no cover dateform = DateRangeForm(request.POST) if dateform.is_valid(): startdate = dateform.cleaned_data['startdate'] @@ -337,7 +339,7 @@ def plannedsession_multiclone_view( "startdate","preferreddate","enddate").exclude( sessiontype='race') - if teamid: + if teamid: # pragma: no cover sps = sps.filter(team__in=[teamid]) try: team = Team.objects.get(id=teamid) @@ -349,7 +351,7 @@ def plannedsession_multiclone_view( team = None query = request.GET.get('q') - if query: + if query: # pragma: no cover query_list = query.split() sps = sps.filter( reduce(operator.and_, @@ -390,7 +392,7 @@ def plannedsession_multiclone_view( if Team.objects.filter(manager=request.user).count()>=1: teamform = RowerTeamForm(request.user) - if teamid: + if teamid: # pragma: no cover teamform = RowerTeamForm(request.user,initial={'team':teamid}) else: teamform = None @@ -422,7 +424,7 @@ def template_share_view(request,id=0,userid=0): if ps.can_be_shared: ps.is_public = True ps.save() - else: + else: # pragma: no cover messages.error(request,'This planned session comes from a third party and cannot be shared') return HttpResponseRedirect(reverse(template_library_view)) @@ -471,7 +473,7 @@ def template_library_view(request,userid=0): alltags = uniqify(alltags) tag = request.GET.get('tag') - if tag: + if tag: # pragma: no cover tags = [tag] templates = templates.filter(tags__name__in=tags).distinct() @@ -539,11 +541,11 @@ def plannedsession_create_view(request, }) - if '_continue' in request.POST: + if '_continue' in request.POST: # pragma: no cover url = reverse('plannedsession_edit_view',kwargs={ 'id':ps.id, }) - elif '_addanother' in request.POST: + elif '_addanother' in request.POST: # pragma: no cover url = reverse('plannedsession_create_view',kwargs={'userid':userid}) url = url+'?when='+timeperiod @@ -551,7 +553,7 @@ def plannedsession_create_view(request, return HttpResponseRedirect(url) else: - if 'fstartdate' in request.session: + if 'fstartdate' in request.session: # pragma: no cover try: fstartdate = arrow.get(request.session['fstartdate']).date() except KeyError: @@ -586,7 +588,7 @@ def plannedsession_create_view(request, preferreddate = startdate.date() except AttributeError: preferreddate = startdate - if preferreddate < timezone.now().date(): + if preferreddate < timezone.now().date(): # pragma: no cover preferreddate = timezone.now().date() try: @@ -594,7 +596,7 @@ def plannedsession_create_view(request, except AttributeError: pass - if preferreddate > enddate: + if preferreddate > enddate: # pragma: no cover preferreddate = enddate forminitial = { @@ -626,7 +628,7 @@ def plannedsession_create_view(request, sessiontemplates = sessiontemplates.order_by("name") alltags = [] - for t in sessiontemplates: + for t in sessiontemplates: # pragma: no cover tags = t.tags.all() for tag in tags: alltags.append(tag) @@ -634,7 +636,7 @@ def plannedsession_create_view(request, alltags = uniqify(alltags) tag = request.GET.get('tag') - if tag: + if tag: # pragma: no cover tags = [tag] sessiontemplates = sessiontemplates.filter(tags__name__in=tags).distinct() @@ -709,11 +711,11 @@ def plannedsession_createtemplate_view(request, url = reverse('template_library_view') - if '_continue' in request.POST: + if '_continue' in request.POST: # pragma: no cover url = reverse('plannedsession_templateedit_view',kwargs={ 'id':ps.id, }) - elif '_addanother' in request.POST: + elif '_addanother' in request.POST: # pragma: no cover url = reverse('plannedsession_createtemplate_view') return HttpResponseRedirect(url) @@ -733,7 +735,7 @@ def plannedsession_createtemplate_view(request, sessiontemplates = sessiontemplates.order_by("name") alltags = [] - for t in sessiontemplates: + for t in sessiontemplates: # pragma: no cover tags = t.tags.all() for tag in tags: alltags.append(tag) @@ -806,7 +808,7 @@ def plannedsession_multicreate_view(request, ).order_by("startdate","preferreddate","enddate").exclude( sessiontype='race') - if teamid: + if teamid: # pragma: no cover qset = qset.filter(team__in=[teamid]) try: team = Team.objects.get(id=teamid) @@ -844,10 +846,10 @@ def plannedsession_multicreate_view(request, for ps in instances: ps.save() add_rower_session(r,ps) - if team: + if team: # pragma: no cover add_team_session(team,ps) messages.info(request,"Saved changes for Planned Session "+str(ps)) - for obj in ps_formset.deleted_objects: + for obj in ps_formset.deleted_objects: # pragma: no cover messages.info(request,"Deleted Planned Session "+str(obj)) obj.delete() @@ -862,7 +864,7 @@ def plannedsession_multicreate_view(request, enddatestring = enddate.strftime('%Y-%m-%d') url += '?when='+startdatestring+'/'+enddatestring - if team: + if team: # pragma: no cover url += '&team={teamid}'.format(teamid=team.id) return HttpResponseRedirect(url) @@ -888,7 +890,7 @@ def plannedsession_multicreate_view(request, if Team.objects.filter(manager=request.user).count()>=1: teamform = RowerTeamForm(request.user) - if teamid: + if teamid: # pragma: no cover teamform = RowerTeamForm(request.user,initial={'team':teamid}) else: teamform = None @@ -975,11 +977,11 @@ def plannedsession_teamcreate_view(request, 'userid':userid, }) - if '_continue' in request.POST: + if '_continue' in request.POST: # pragma: no cover url = reverse('plannedsession_edit_view',kwargs={ 'id':ps.id, }) - elif '_addanother' in request.POST: + elif '_addanother' in request.POST: # pragma: no cover url = reverse('plannedsession_teamcreate_view',kwargs={'userid':userid}) url = url+'?when='+timeperiod @@ -995,7 +997,7 @@ def plannedsession_teamcreate_view(request, #next = request.GET.get('next', url) #return HttpResponseRedirect(next) - else: + else: # pragma: no cover timeperiod = startdate.strftime('%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d') breadcrumbs = [ { @@ -1035,7 +1037,7 @@ def plannedsession_teamcreate_view(request, 'preferreddate':startdate, } - if 'teams' in request.session: + if 'teams' in request.session: # pragma: no cover teams = request.session['teams'] theteams = Team.objects.filter(id__in=teams) initialteam = { @@ -1113,7 +1115,7 @@ def plannedsession_teamedit_view(request, startdate__lte = startdate, rowers = r, enddate__gte = enddate)[0] - except IndexError: + except IndexError: # pragma: no cover trainingplan = None sps = [] @@ -1138,11 +1140,10 @@ def plannedsession_teamedit_view(request, ) sessionrowerform = PlannedSessionTeamMemberForm(ps,request.POST) - if sessioncreateform.is_valid(): cd = sessioncreateform.cleaned_data - if cd['sessionunit'] == 'min': + if cd['sessionunit'] == 'min': # pragma: no cover cd['sessionmode'] = 'time' elif cd['sessionunit'] in ['km','m']: cd['sessionmode'] = 'distance' @@ -1152,7 +1153,7 @@ def plannedsession_teamedit_view(request, if res: messages.info(request,message) - else: + else: # pragma: no cover messages.error(request,message) @@ -1166,14 +1167,15 @@ def plannedsession_teamedit_view(request, rs = Rower.objects.filter(team__in=[team]) for r in rs: add_rower_session(r,ps) - else: + else: # pragma: no cover remove_team_session(team,ps) - else: + else: # pragma: no cover selectedteams = [] for team in teams: remove_team_session(team,ps) + if sessionrowerform.is_valid(): cd = sessionrowerform.cleaned_data selectedrowers = cd['members'] @@ -1279,7 +1281,7 @@ def plannedsessions_coach_view(request, trainingplan = None - if teamid != 0: + if teamid != 0:# pragma: no cover try: theteam = Team.objects.get(id=teamid) except Team.DoesNotExist: @@ -1297,7 +1299,7 @@ def plannedsessions_coach_view(request, if therower.rowerplan != 'freecoach': rowers = [therower] - else: + else:# pragma: no cover rowers = [] for ps in sps: @@ -1356,7 +1358,7 @@ def plannedsessions_coach_view(request, }) ttemplate = 'plannedsessionscoach.html' - if len(rowers) > 5 and len(rowers) > len(sps): + if len(rowers) > 5 and len(rowers) > len(sps): # pragma: no cover ttemplate = 'plannedsessionscoach2.html' @@ -1386,16 +1388,16 @@ def plannedsessions_view(request, try: r = getrequestplanrower(request,userid=userid) - except PermissionDenied: + except PermissionDenied: # pragma: no cover r = request.user.rower - if startdatestring: + if startdatestring: # pragma: no cover try: startdate = iso8601.parse_date(startdatestring) except ParseError: pass - if enddatestring: + if enddatestring: # pragma: no cover try: enddate = iso8601.parse_date(enddatestring) except ParseError: @@ -1454,7 +1456,7 @@ def plannedsessions_view(request, tss = hrtss totals['distance'] += w.distance totals['time'] += timefield_to_seconds_duration(w.duration) - if w.plannedsession: + if w.plannedsession: # pragma: no cover if w.plannedsession.sessionmode == 'distance': totals['actualdistance'] += w.distance elif w.plannedsession.sessionmode == 'time': @@ -1464,7 +1466,7 @@ def plannedsessions_view(request, elif w.plannedsession.sessionmode == 'TRIMP': totals['actualtrimp'] += thetrimp - if not sps and request.user.rower.rowerplan == 'basic': + if not sps and request.user.rower.rowerplan == 'basic': # pragma: no cover messages.error(request, "You must purchase Coach or Self-coach plans or be part of a team to get planned sessions") @@ -1479,9 +1481,9 @@ def plannedsessions_view(request, totals['planneddistance'] += ps.sessionvalue elif ps.sessionmode == 'time': totals['plannedtime'] += ps.sessionvalue - elif ps.sessionmode == 'rScore': + elif ps.sessionmode == 'rScore': # pragma: no cover totals['plannedrscore'] += ps.sessionvalue - elif ps.sessionmode == 'TRIMP': + elif ps.sessionmode == 'TRIMP': # pragma: no cover totals['plannedtrimp'] += ps.sessionvalue totals['time'] = int(totals['time']/60.) @@ -1572,7 +1574,7 @@ def plannedsessions_manage_view(request,userid=0, initialsession=0): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True r = getrequestrower(request,userid=userid) @@ -1614,7 +1616,7 @@ def plannedsessions_manage_view(request,userid=0, linkedworkouts = [] for w in ws: - if w.plannedsession is not None: + if w.plannedsession is not None: # pragma: no cover linkedworkouts.append(w.id) plannedsessionstuple = [] @@ -1672,7 +1674,7 @@ def plannedsessions_manage_view(request,userid=0, w_form = WorkoutSessionSelectForm(workoutdata=workoutdata) - if is_ajax: + if is_ajax: # pragma: no cover ajax_workouts = [] for id,name in workoutdata['choices']: ininitial = id in initialworkouts @@ -1746,7 +1748,7 @@ def plannedsession_clone_view(request,id=0,userid=0): startdate__lte = startdate, rowers = r, enddate__gte = enddate)[0] - except IndexError: + except IndexError: # pragma: no cover trainingplan = None ps = get_object_or_404(PlannedSession,pk=id) @@ -1773,7 +1775,7 @@ def plannedsession_clone_view(request,id=0,userid=0): if rowers: for rower in rowers: add_rower_session(rower,ps) - else: + else: # pragma: no cover add_rower_session(r,ps) for team in teams: add_team_session(team,ps) @@ -2010,7 +2012,7 @@ def plannedsession_edit_view(request,id=0,userid=0): startdate__lte = startdate, rowers = r, enddate__gte = enddate)[0] - except IndexError: + except IndexError: # pragma: no cover trainingplan = None ps = get_object_or_404(PlannedSession,pk=id) @@ -2147,13 +2149,13 @@ def plannedsession_view(request,id=0,userid=0): r = getrequestplanrower(request,userid=userid) ps = get_object_or_404(PlannedSession,pk=id) - if ps.steps is not None: + if ps.steps is not None: # pragma: no cover jsons = ps.steps else: jsons = {} - try: + try: # pragma: no cover r = VirtualRace.objects.get(id=ps.id) url = reverse('virtualevent_view', kwargs={'id':ps.id} @@ -2162,7 +2164,7 @@ def plannedsession_view(request,id=0,userid=0): except VirtualRace.DoesNotExist: pass - if ps.course: + if ps.course: # pragma: no cover coursescript,coursediv = course_map(ps.course) else: coursescript = '' @@ -2208,7 +2210,7 @@ def plannedsession_view(request,id=0,userid=0): 'sessionresult':0, 'workoutid':w.id, } - if ps.sessiontype == 'coursetest': + if ps.sessiontype == 'coursetest': # pragma: no cover vs = CourseTestResult.objects.filter(plannedsession=ps, workoutid=w.id) @@ -2257,7 +2259,7 @@ def plannedsession_view(request,id=0,userid=0): if ps.sessiontype == 'coursetest': ranking = sorted(ranking, key=lambda k: k['time']) - if ps.sessiontype == 'fastest_distance': + if ps.sessiontype == 'fastest_distance': # pragma: no cover vs = CourseTestResult.objects.filter(plannedsession=ps) if vs: @@ -2293,7 +2295,7 @@ def plannedsession_view(request,id=0,userid=0): pass ranking = sorted(ranking, key=lambda k: k['time']) - if ps.sessiontype == 'fastest_time': + if ps.sessiontype == 'fastest_time': # pragma: no cover vs = CourseTestResult.objects.filter(plannedsession=ps) if vs: @@ -2363,7 +2365,7 @@ def plannedsession_view(request,id=0,userid=0): comments = PlannedSessionComment.objects.filter(plannedsession=ps).order_by("created") steps = '' - if ps.steps: + if ps.steps: # pragma: no cover d = ps.steps steps = ps_dict_get_description_html(d,short=False) @@ -2407,7 +2409,7 @@ class PlannedSessionDelete(DeleteView): def get_context_data(self, **kwargs): context = super(PlannedSessionDelete,self).get_context_data(**kwargs) - if 'userid' in kwargs: + if 'userid' in kwargs: # pragma: no cover userid = kwargs['userid'] else: userid = 0 @@ -2455,7 +2457,7 @@ class PlannedSessionDelete(DeleteView): def get_success_url(self): ws = Workout.objects.filter(plannedsession=self.object) - for w in ws: + for w in ws: # pragma: no cover w.plannedsession = None w.save() @@ -2468,7 +2470,7 @@ class PlannedSessionDelete(DeleteView): def get_object(self, *args, **kwargs): obj = super(PlannedSessionDelete, self).get_object(*args, **kwargs) - if not can_delete_session(self.request.user,obj): + if not can_delete_session(self.request.user,obj): # pragma: no cover raise PermissionDenied('You are not allowed to delete this planned session') return obj From 33fcc321c12731d7892b6a8852aac4b8c2efb148 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 19 Apr 2021 18:51:41 +0200 Subject: [PATCH 4/9] adding tests --- rowers/tests/test_plans.py | 30 ++++++++-- rowers/tests/testdata/britishrowing.yml | 75 +++++++++++++++++++++++++ rowers/views/planviews.py | 28 ++++----- 3 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 rowers/tests/testdata/britishrowing.yml diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index 18651eea..a246430a 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -195,6 +195,9 @@ class SessionTemplateTest(TestCase): self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + for w in self.user_workouts: + w.startdatetime = arrow.get(w.date).datetime + self.factory = RequestFactory() self.password = faker.word() self.u.set_password(self.password) @@ -276,6 +279,15 @@ class SessionTemplateTest(TestCase): response = self.c.get(url,follow=True) self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + url = reverse('plannedsession_templateedit_view',kwargs={'id':t.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + post_data['name'] = faker.word() + + response = self.c.post(url,post_data,follow=True) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + @override_settings(TESTING=True) class SessionLinkTest(TestCase): def setUp(self): @@ -296,7 +308,7 @@ class SessionLinkTest(TestCase): self.pss = [] for w in self.user_workouts: - startdatetime = w.startdatetime + startdatetime = arrow.get(w.date).datetime startdate = (startdatetime-datetime.timedelta(days=1)).date() enddate = (startdatetime+datetime.timedelta(days=1)).date() @@ -334,11 +346,12 @@ class SessionLinkTest(TestCase): w = self.user_workouts[0] - startdatetime = w.startdatetime + startdatetime = arrow.get(w.date).datetime startdate = (startdatetime-datetime.timedelta(days=1)).date() enddate = (startdatetime+datetime.timedelta(days=1)).date() + url = '/rowers/sessions/' response = self.c.get(url) self.assertEqual(response.status_code,200) @@ -379,8 +392,6 @@ class SessionLinkTest(TestCase): enddate = enddate.strftime("%Y-%m-%d"), ) - - workoutdata = {} workoutdata['initial'] = [] @@ -391,6 +402,7 @@ class SessionLinkTest(TestCase): workoutdata['choices'] = tuple(choices) + form = PlannedSessionSelectForm(plannedsessionstuple,post_data) self.assertTrue(form.is_valid()) @@ -1430,6 +1442,8 @@ class PlannedSessionsView(TestCase): added = plannedsessions.add_team_session(self.team,self.ps_trimp) self.ps_trimp.save() + + def tearDown(self): try: os.remove(self.w1.csvfilename) @@ -1861,3 +1875,11 @@ class PlannedSessionsView(TestCase): response = self.c.post(url,follow=True) self.assertEqual(response.status_code,200) + + def test_instantplan_vie(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('rower_select_instantplan') + response = self.c.get(url) + self.assertEqual(response.status_code,200) diff --git a/rowers/tests/testdata/britishrowing.yml b/rowers/tests/testdata/britishrowing.yml new file mode 100644 index 00000000..14e6d0a8 --- /dev/null +++ b/rowers/tests/testdata/britishrowing.yml @@ -0,0 +1,75 @@ +filename: britishrowing.json +name: British Rowing Training Plan Beginner Week 1 +trainingDays: + - order: 1 + workouts: + - workoutName: Week 1 Session 1 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Intervals + durationType: Time + durationValue: 60000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 60000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" + - order: 4 + workouts: + - workoutName: Week 1 Session 2 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Interval + durationType: Time + durationValue: 300000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 180000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" +duration: 7 +description: "" diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 918c40c1..d791b587 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -1305,7 +1305,7 @@ def plannedsessions_coach_view(request, for ps in sps: if 'coach' in request.user.rower.rowerplan: rowers += ps.rower.all().exclude(rowerplan='freecoach') - else: + else: # pragma: no cover rowers += ps.rower.filter(team__in=rteams).exclude(rowerplan='freecoach') rowers = list(set(rowers)) @@ -1805,10 +1805,10 @@ def plannedsession_teamclone_view(request,id=0): r = getrequestplanrower(request) teams = Team.objects.filter(manager=request.user) - if teams.count()>0: + if teams.count()>0: # pragma: no cover teamchoices = [(team.id, team.name) for team in teams] teaminitial = [str(teams[0].id)] - else: + else: # pragma: no cover messages.info(request,"You have no teams established yet. We are redirecting you to the Team Management page.") url = reverse('rower_teams_view') return HttpResponseRedirect(url) @@ -1873,16 +1873,16 @@ def plannedsession_templateedit_view(request,id=0): try: ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: + except PlannedSession.DoesNotExist: # pragma: no cover raise Http404("Planned Session does not exist") - if ps.manager != request.user: + if ps.manager != request.user: # pragma: no cover raise PermissionDenied("You are not allowed to edit this planned session") - if ps.sessiontype in ['race','indoorrace']: + if ps.sessiontype in ['race','indoorrace']: # pragma: no cover raise PermissionDenied("You are not allowed to edit this planned session because it is a race") - if not ps.is_template: + if not ps.is_template: # pragma: no cover ps.pk = None ps.id = None ps.is_template = True @@ -1900,7 +1900,7 @@ def plannedsession_templateedit_view(request,id=0): cd = sessioncreateform.cleaned_data if cd['sessionunit'] == 'min': cd['sessionmode'] = 'time' - elif cd['sessionunit'] in ['km','m']: + elif cd['sessionunit'] in ['km','m']: # pragma: no cover cd['sessionmode'] = 'distance' obj = sessioncreateform.save(commit=False) @@ -1912,12 +1912,12 @@ def plannedsession_templateedit_view(request,id=0): if res: messages.info(request,message) - else: + else: # pragma: no cover messages.error(request,message) url = reverse('template_library_view') - if '_continue' in request.POST: + if '_continue' in request.POST: # pragma: no cover url = reverse('plannedsession_templateedit_view',kwargs={ 'id':ps.id, }) @@ -2030,7 +2030,7 @@ def plannedsession_edit_view(request,id=0,userid=0): if sessioncreateform.is_valid(): cd = sessioncreateform.cleaned_data - if cd['sessionunit'] == 'min': + if cd['sessionunit'] == 'min': # pragma: no cover cd['sessionmode'] = 'time' elif cd['sessionunit'] in ['km','m']: cd['sessionmode'] = 'distance' @@ -2041,12 +2041,12 @@ def plannedsession_edit_view(request,id=0,userid=0): if res: messages.info(request,message) - else: + else: # pragma: no cover messages.error(request,message) url = reverse('plannedsessions_view') - if "_continue" in request.POST: + if "_continue" in request.POST: # pragma: no cover url = reverse(plannedsession_edit_view, kwargs={ 'id':int(ps.id), @@ -2256,7 +2256,7 @@ def plannedsession_view(request,id=0,userid=0): wdict['distance'] = ps.course.distance wdict['coursecompleted'] = False ranking.append(wdict) - if ps.sessiontype == 'coursetest': + if ps.sessiontype == 'coursetest': # pragma: no cover ranking = sorted(ranking, key=lambda k: k['time']) if ps.sessiontype == 'fastest_distance': # pragma: no cover From f413af91e6e95cf33ff5eaa6bde0bb8759a44af1 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 19 Apr 2021 21:41:00 +0200 Subject: [PATCH 5/9] at least passing part --- rowers/tests/test_plans.py | 110 ++++++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index a246430a..4f7a60b9 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -1876,10 +1876,118 @@ class PlannedSessionsView(TestCase): response = self.c.post(url,follow=True) self.assertEqual(response.status_code,200) - def test_instantplan_vie(self): + # next test should mock training plan server + + def test_instantplan_view(self): + self.u.is_staff = True + self.u.save() login = self.c.login(username=self.u.username, password=self.password) self.assertTrue(login) url = reverse('rower_select_instantplan') response = self.c.get(url) self.assertEqual(response.status_code,200) + + # add a plan + url = reverse('add_instantplan_view') + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + + + form_data = { + 'name': 'Test Plan', + 'price': 0, + 'url':'https://nos.nl', + 'goal':'hard roeien', + 'description':'win everything with this plan', + 'duration':28, + 'target':'race faster', + 'hoursperweek':4, + 'sessionsperweek':4, + #'yaml': {'yaml': SimpleUploadedFile('britishrowing.yml', f.read())} + } + + s = b"""filename: britishrowing.json +name: British Rowing Training Plan Beginner Week 1 +trainingDays: + - order: 1 + workouts: + - workoutName: Week 1 Session 1 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Intervals + durationType: Time + durationValue: 60000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 60000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" + - order: 4 + workouts: + - workoutName: Week 1 Session 2 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Interval + durationType: Time + durationValue: 300000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 180000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" +duration: 7 +description: "" +""" + + file_data = {'yaml': SimpleUploadedFile('britishrowing.yml', s)} + + form = InstantPlanForm(form_data,file_data) + if not form.is_valid(): + print(form.errors) + self.assertTrue(form.is_valid()) From 9677d5166e25a8498aa5d63b8618a609b594d6fa Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 20 Apr 2021 10:41:32 +0200 Subject: [PATCH 6/9] going through importviews ... coverage --- rowers/tests/test_imports.py | 86 ++++++++++ rowers/tests/test_misc.py | 8 + rowers/tests/test_plans.py | 226 +++++++++++++++++--------- rowers/tests/testdata/temp.yml | 75 +++++++++ rowers/tests/testdata/testdata.tcx.gz | Bin 4045 -> 0 bytes rowers/views/importviews.py | 224 ++++++++++++------------- rowers/views/planviews.py | 84 ++++------ 7 files changed, 464 insertions(+), 239 deletions(-) create mode 100644 rowers/tests/testdata/temp.yml delete mode 100644 rowers/tests/testdata/testdata.tcx.gz diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index ce2463a4..db61bd37 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -14,6 +14,9 @@ import rowers from rowers import dataprep from rowers import tasks from rowers import c2stuff +from rowers import stravastuff +import urllib +import json @pytest.mark.django_db @override_settings(TESTING=True) @@ -461,6 +464,11 @@ class NKObjects(DjangoTestCase): ) self.assertTrue(res>0) + @patch('rowers.nkstuff.requests.post', side_effect=mocked_requests) + def notest_nk_callback(self, mock_post): + response = self.c.get('/nk_callback?code=absdef23&scope=read',follow=True) + self.assertEqual(response.status_code, 200) + @patch('rowers.nkstuff.requests.get', side_effect=mocked_requests) @patch('rowers.nkstuff.requests.post', side_effect=mocked_requests) @@ -609,6 +617,10 @@ class RP3Objects(DjangoTestCase): res = tasks.handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts) self.assertEqual(res,1) + @patch('rowers.rp3stuff.requests.post', side_effect=mocked_requests) + def notest_rp3_callback(self, mock_post): + response = self.c.get('/rp3_callback?code=absdef23&scope=read',follow=True) + self.assertEqual(response.status_code, 200) #@pytest.mark.django_db @@ -630,6 +642,7 @@ class StravaObjects(DjangoTestCase): self.r.stravatoken = '12' self.r.stravarefreshtoken = '123' self.r.stravatokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime + self.r.strava_owner_id = 4 self.r.save() self.c.login(username='john',password='koeinsloot') @@ -666,6 +679,79 @@ class StravaObjects(DjangoTestCase): csvfilename=filename ) + @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) + @patch('rowers.stravastuff.requests.get', side_effect=mocked_requests) + def test_strava_webhook(self, mock_get, mock_post): + url = reverse('strava_webhook_view') + + params = { + 'hub.challenge':'aap', + 'hub.verify_token':stravastuff.webhookverification, + } + + url2 = url+'?'+urllib.parse.urlencode(params) + + response = self.c.get(url2) + self.assertEqual(response.status_code,200) + + data = { + 'aspect_type':'create', + 'object_id': 123, + 'object_type':'activity', + 'strava_owner': self.r.strava_owner_id, + 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + } + + raw_data = json.dumps(data) + + response = self.c.generic('POST', url, raw_data) + self.assertEqual(response.status_code,200) + + data = { + 'aspect_type':'update', + 'updates':{ + 'title':faker.word(), + 'type': 'Ride', + }, + 'object_id': 123, + 'object_type':'activity', + 'strava_owner': self.r.strava_owner_id, + 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + } + + raw_data = json.dumps(data) + + response = self.c.generic('POST', url, raw_data) + self.assertEqual(response.status_code,200) + + data = { + 'aspect_type':'delete', + 'object_id': 123, + 'object_type':'activity', + 'strava_owner': self.r.strava_owner_id, + 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + } + + raw_data = json.dumps(data) + + response = self.c.generic('POST', url, raw_data) + self.assertEqual(response.status_code,200) + + + + @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) + @patch('rowers.stravastuff.requests.get', side_effect=mocked_requests) + @patch('rowers.stravastuff.stravalib.Client',side_effect=MockStravalibClient) + def test_strava_upload(self, mock_get, mock_post,MockStravalibClient): + response = self.c.get('/rowers/workout/'+encoded1+'/stravauploadw/') + + self.assertRedirects(response, + expected_url = '/rowers/workout/'+encoded1+'/edit/', + status_code=302,target_status_code=200) + + self.assertEqual(response.url, '/rowers/workout/'+encoded1+'/edit/') + self.assertEqual(response.status_code, 302) + @patch('rowers.stravastuff.requests.get', side_effect=mocked_requests) @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) diff --git a/rowers/tests/test_misc.py b/rowers/tests/test_misc.py index e2174bdf..253f7abf 100644 --- a/rowers/tests/test_misc.py +++ b/rowers/tests/test_misc.py @@ -9,6 +9,14 @@ from .statements import * nu = datetime.datetime.now() from rowers.rower_rules import is_workout_user +from rowers.models import update_records + +class MiscTests(TestCase): + def setUp(self): + pass + + def test_c2records(self): + update_records(verbose=False) #@pytest.mark.django_db class WorkoutTests(TestCase): diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index 4f7a60b9..b5d75e5e 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -1442,6 +1442,104 @@ class PlannedSessionsView(TestCase): added = plannedsessions.add_team_session(self.team,self.ps_trimp) self.ps_trimp.save() + s = b"""filename: britishrowing.json +name: British Rowing Training Plan Beginner Week 1 +trainingDays: + - order: 1 + workouts: + - workoutName: Week 1 Session 1 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Intervals + durationType: Time + durationValue: 60000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 60000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" + - order: 4 + workouts: + - workoutName: Week 1 Session 2 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Interval + durationType: Time + durationValue: 300000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 180000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" +duration: 7 +description: "" +""" + + self.file_data = {'yaml': SimpleUploadedFile('britishrowing.yml', s)} + + with open('media/temp.yml','wb') as f: + f.write(s) + + self.instantplan = InstantPlan( + uuid = "79b0dacf-9b49-4f33-9acf-e2e6734e22dc", + url = "https://thepeteplan.wordpress.com/beginner-training/", + name = faker.word(), + goal = faker.word(), + duration = 42, + description = faker.word(), + target = faker.word(), + hoursperweek = 3, + sessionsperweek = 3, + price = 0, + yaml = 'temp.yml', + ) + + self.instantplan.save() + def tearDown(self): @@ -1555,6 +1653,29 @@ class PlannedSessionsView(TestCase): response = self.c.post(url,formdata,follow=True) self.assertEqual(response.status_code,200) + def test_deletetarget_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('rower_delete_trainingtarget',kwargs={'id':self.target.id}) + + response = self.c.get(url) + self.assertEqual(response.status_code,302) + + def test_deletetrainingplan_view(self): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('trainingplan_delete_view',kwargs={'pk':self.plan.id}) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form = {} + response = self.c.post(url,form) + self.assertEqual(response.status_code,302) + + def test_multicreate_view(self): login = self.c.login(username=self.u.username, password=self.password) @@ -1637,6 +1758,10 @@ class PlannedSessionsView(TestCase): response = self.c.post(url,form_data,follow=True) self.assertEqual(response.status_code,200) + url = reverse('remove_groupsession_view',kwargs={'id':self.ps_trimp.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,302) + def test_teamedit_view(self): login = self.c.login(username=self.u.username, password=self.password) @@ -1908,86 +2033,29 @@ class PlannedSessionsView(TestCase): #'yaml': {'yaml': SimpleUploadedFile('britishrowing.yml', f.read())} } - s = b"""filename: britishrowing.json -name: British Rowing Training Plan Beginner Week 1 -trainingDays: - - order: 1 - workouts: - - workoutName: Week 1 Session 1 - steps: - - stepId: 0 - wkt_step_name: Warmup - durationType: Time - durationValue: 300000 - intensity: Warmup - description: "" - - stepId: 1 - wkt_step_name: Intervals - durationType: Time - durationValue: 60000 - intensity: Active - description: "" - - stepId: 2 - wkt_step_name: Interval Rest - durationType: Time - durationValue: 60000 - intensity: Rest - description: "" - - stepId: 3 - wkt_step_name: Rep - durationType: RepeatUntilStepsCmplt - durationValue: 1 - targetValue: 5 - - stepId: 4 - wkt_step_name: Cooldown - durationType: Time - durationValue: 300000 - intensity: Cooldown - description: "" - sport: "" - description: "" - - order: 4 - workouts: - - workoutName: Week 1 Session 2 - steps: - - stepId: 0 - wkt_step_name: Warmup - durationType: Time - durationValue: 300000 - intensity: Warmup - description: "" - - stepId: 1 - wkt_step_name: Interval - durationType: Time - durationValue: 300000 - intensity: Active - description: "" - - stepId: 2 - wkt_step_name: Interval Rest - durationType: Time - durationValue: 180000 - intensity: Rest - description: "" - - stepId: 3 - wkt_step_name: Rep - durationType: RepeatUntilStepsCmplt - durationValue: 1 - targetValue: 5 - - stepId: 4 - wkt_step_name: Cooldown - durationType: Time - durationValue: 300000 - intensity: Cooldown - description: "" - sport: "" - description: "" -duration: 7 -description: "" -""" - file_data = {'yaml': SimpleUploadedFile('britishrowing.yml', s)} - - form = InstantPlanForm(form_data,file_data) + form = InstantPlanForm(form_data,self.file_data) if not form.is_valid(): print(form.errors) self.assertTrue(form.is_valid()) + + # look at a instant plan + url = reverse('rower_view_instantplan',kwargs={'id':self.instantplan.uuid}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form_data = { + 'name':faker.word(), + 'target': '', + 'startdate':datetime.datetime.now().strftime('%Y-%m-%d'), + 'enddate':(datetime.datetime.now()+datetime.timedelta(days=self.instantplan.duration)).strftime('%Y-%m-%d'), + 'notes': faker.word(), + 'datechoice':'startdate', + } + + form = InstantPlanSelectForm(form_data) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data,follow=True) + + self.assertEqual(response.status_code,200) diff --git a/rowers/tests/testdata/temp.yml b/rowers/tests/testdata/temp.yml new file mode 100644 index 00000000..b88da031 --- /dev/null +++ b/rowers/tests/testdata/temp.yml @@ -0,0 +1,75 @@ +filename: britishrowing.json +name: British Rowing Training Plan Beginner Week 1 +trainingDays: + - order: 1 + workouts: + - workoutName: Week 1 Session 1 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Intervals + durationType: Time + durationValue: 60000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 60000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" + - order: 4 + workouts: + - workoutName: Week 1 Session 2 + steps: + - stepId: 0 + wkt_step_name: Warmup + durationType: Time + durationValue: 300000 + intensity: Warmup + description: "" + - stepId: 1 + wkt_step_name: Interval + durationType: Time + durationValue: 300000 + intensity: Active + description: "" + - stepId: 2 + wkt_step_name: Interval Rest + durationType: Time + durationValue: 180000 + intensity: Rest + description: "" + - stepId: 3 + wkt_step_name: Rep + durationType: RepeatUntilStepsCmplt + durationValue: 1 + targetValue: 5 + - stepId: 4 + wkt_step_name: Cooldown + durationType: Time + durationValue: 300000 + intensity: Cooldown + description: "" + sport: "" + description: "" +duration: 7 +description: "" diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz deleted file mode 100644 index 2d9b5194e7b187fdb84a4ea71098218cae3f2819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4045 zcmV;;4>Ir{iwFpt#V=d}|8!+@bYx+4VJ>uIcmVC4-ESPX5y0OI^nVcikUkXQkuw}} zMo|>xt7rf_4H6^GTd|R^^0m@Q(5*l6-6H+-TEl)z1@BM==nHa zAFo!gUcEBs!_DPpYtF7NSLw^$+4J?~uv#N0IBd_>>8Rc2`1ZVyug->X|8xJ) z4IJr@dI{$B?%DK#e;dZnhl{J5&3d8AJp_b{H_?!Ugfl>2>``qdZoM-RRIjgJyL zM@J`bouKCw$FB_gz;qc z-qw3Ze6hLZ=*c?$648@B2^F|G43N{r7dc|8IwJ{n_>9 z9?-1ahHh;DKY(0#-Z`LmDdPbPo?)B4*l)VN+HA*nw&!mW4-b*~Gm`u7e{sw& zxFF+ygO&XehrWdSF9PEGFXHxP{K{K+=Mme7p74H;J88Ci|I$yt`Qdk~h6jcEd#6k% z{pT=_>3@)%tZx5$@2abG+4p|ruiR$l;lX#TfA?Yl*^yNs;Ly0`FpwX4T@XO13<3m` zq%MdC0!Y?XQ3&`D2%tJi;HfqU$Uu-}3Me2zYp^H;(iQ~4*9HL_N8nfmfs~a5XxoAy z)&_xhdvy>s5O_9F6ase;1gCYwLWRA9#w3BW zwONM52BXyl3Y;yC0Um?_REGi7Wfs7(OLu*RG)rJ8Z_Kc(}J?t1Xh5w$u_vW05haFd$pD+Q1){Q^4*pPGXSM zyoj#)3`ojG5!=I{wkV5J6V1~Ykcli_m1stAh2sXz zVNhG#fY^lSbhZJaGqNBIT(=E=8w1Rh$%xFV@DV02vuJ_34?U+aGX~z+z+NW}2nwf` zItFuN5DW(hpu!+vmj;JnfVE*DCO9VDc$0{Qr9teT!n_zbFc`(@Yy-x^CSvT;U}g-+ z00`)$f%w9~ANWwL<6H!JO!TzW_4-M5(el@2u!+Rh*TPb z=2}@pZ5Viy>_gGn2BC0Ab9)$2Z5Tv@L0OXOOSiI;?b2Xg47@dt1yDC3xA2@~YOS%I zd~FzjiK0w2dy%r$N6leSS=SQg%H(J{s+0mbyC`YU;|9|hutCQpIt-+H3T>s9$mO9o zxRHl}QN@LKYh;w5g1{~-L)G2ff4#c1? zhtcQCWO2&oHHvOg^#)xUOk?1UC($*p5tr^^>{C+b#vqzx8R*7bkd*FPirrI~83Qrm zMO4A$kTglJOm0dVI55Eps}jw@Eeiwe;iE|m$Y4~C#|+>KdkW2AP@7V4Y^)crsy7IE z9p|nT+Nn42xiUFA@v520ArDOI7_^gU_PH_{ghgi?5G<-P8T)*LNeqH<$u`g_g#d-) z2CZQbpf(KHgdn0?Pa#AsY#TI(L2aG_Cf^T4w*X&Y?1|>aF!0G!0No({AlMVlZ7GG^ zfW*r2n9+6&4#c1~Pa)4tcAyI%Md!3oohA|?Q%`lQ{EpAX-y@8L$lZ~qCqv)w@YUw}>DvTm>WfupswiR%p=?f}J=>tRxB*cPAL+W5Vhp{N^)L)-OEeQ38zkzK0*6I;3O$%S zfdQpAZ=yDe7$p|=6q=I;R2v3pe8NB_4cHc5vAsQM5Ng997>5#64kJ5Wlr-oVOk=<% zu;`lC7`SlUpgE<$m0^&JjH8gMK%G&#G&l?csSN{foYN`=UwApr_QFTCDFqiy6wnR5 zNqZL_ded4kIYMn1h{0qWsKQ5FdR5juVz^^4Ck6n#$DpOuQo;ZYkmx)Gfx>Go z~24i_m`Iy&Q3aUN@iLtO!2z|x&c`>-HOjge2Hj00OA2UHseKF_@gO1};ei4-Vr1YU3c}j#dO62OJh959;FpLv0+0At!-! z97rr|CpM=STxA>pvu96{mggXZkS+Wbb02CaCVzu-cTCm!fG za%CKNYpk&7;s-7ko}qkTiK^{><0J=YEQ%=Q0sBR9;JV*9$w9~*c%_{vRG0(o9L&rC z8;ROD64+4KZ-gFCoR9maP9E6WIEZ=472Q~M z2gr+>df<8->9;wEd3GvUbUMEgycEtexz;$4+BiVtt#TxigN2R8>hXhV4uU~Iuha|C z79M=yx}7*P2Vy|m+~|PaqNXXkUZ*<6fdk`2IU~)16kfNtJ-q<6aX@(xin3lAvsKYK zXh|=)XtFra$pdu0a2%=I2Qza3$>Jjky1F!kWi8Lw^9$1)py8nHXF?2%nwQt>k)}Ba zCNhZ5UqD}aEhgywjWcr~CNL}KA0U;UiUZwFoRPhJN1{6b59V;-X^%t{VCE^4K|9#@{`fJ`zD zP-iE4@;#2!R$TdZj;2@I2Z0tC*uStjQrb-%Ht_yOlRnqDC4;>w-j+N7 z%JWc2$w7d^eq*19GB*b?&%r>YUWm9TdC>L3BnQdjW3kHm17cs;U+8(~xj8@+JV)I; z6cXR#iEYJ|F_;*w)#aUo4U4Kn>2~5Y2V%U4vK}eqs6*Ea?bIjoab9_i#OdtB0L$uQ z>2tECIUwUvtj=!?$XzeA6<7A0IbdC1Tkx`|e&=3~G|54Z465@BA=qvoG{%89Kx#WN z+Fq~RQePYAIhqayl^n2J)LfiyCr)r6d5)&_Ldy7oK(AA6i~}%?+IV8LrPukkeLm96 z98lswNEbhd4h#1;+U_^b%mJI|wfzebO82qYo_C&?1LsU&wLHMmeJr-;ooD928$uSP zJn&RF-)Os?I5P*)Bn-S#9#AM;htloDnK^*uH4*9&Yt}NWo z1bu$uyc{?%01|Y5qmcCVTpNlfW)8?WWGx3l3d@5&S9fj>IQO+F;|IdF&&_Kno|rhe zUGH6)ZxnHT-g;vkpaBoMb$P(rK41Aj4&s~~yxDxW#K3SJN@8d{OHSz z_2qgy9{pv%=`Tmacw}EY%7fD!e{ep2bh5hL`S#e8yWhFraQAWZW{;E4Z_+Ehy7_tc zuZP6a&DE>juzfaMT6c&U_q6}>%@^M!w!eOH`Qtj> zpS2%ad;9On>fRS`Uc~;1r4Rd8zuBfo@_Bl(>zgmqgZVLCKYjH-I_<2zl8ONUY;elK diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index fe8d9d00..b46000bd 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -7,7 +7,7 @@ from rowers.views.statements import * import numpy -def default(o): +def default(o): # pragma: no cover if isinstance(o, numpy.int64): return int(o) raise TypeError @@ -21,7 +21,7 @@ def workout_tp_upload_view(request,id=0): res = -1 try: thetoken = tp_open(r.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/tpauthorize/") # ready to upload. Hurray @@ -35,7 +35,7 @@ def workout_tp_upload_view(request,id=0): r.tptoken,tcxfile, name=w.name ) - if res == 0: + if res == 0: # pragma: no cover message = "Upload to TrainingPeaks failed with status code "+str(status_code)+": "+reason try: os.remove(tcxfile) @@ -50,7 +50,7 @@ def workout_tp_upload_view(request,id=0): os.remove(tcxfile) messages.info(request,'Uploaded to TrainingPeaks') - else: # no tcxfile + else: # pragma: no cover # no tcxfile message = "Upload to TrainingPeaks failed" w.uploadedtotp = -1 w.save() @@ -74,10 +74,10 @@ def workout_strava_upload_view(request,id=0): try: thetoken = strava_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/stravaauthorize/") - if (r.stravatoken == '') or (r.stravatoken is None): + if (r.stravatoken == '') or (r.stravatoken is None): # pragma: no cover s = "Token doesn't exist. Need to authorize" return HttpResponseRedirect("/rowers/me/stravaauthorize/") else: @@ -99,9 +99,9 @@ def workout_strava_upload_view(request,id=0): if activity_type == 'match': try: activity_type = mytypes.stravamapping[w.workouttype] - except KeyError: + except KeyError: # pragma: no cover activity_type = 'Ride' - else: + else: # pragma: no cover try: activity_type = mytypes.stravamapping[w.workouttype] except KeyError: @@ -112,7 +112,7 @@ def workout_strava_upload_view(request,id=0): r.stravatoken, description=newnotes, activity_type=activity_type,quick=False) - if res==0: + if res==0: # pragma: no cover messages.error(request,mes) w.uploadedtostrava = -1 w.save() @@ -132,13 +132,13 @@ def workout_strava_upload_view(request,id=0): w.save() try: os.remove(tcxfile) - except WindowsError: + except WindowsError: # pragma: no cover pass url = reverse('workout_edit_view',kwargs={'id':w.id}) messages.info(request,mes) - except: + except: # pragma: no cover with open("media/stravaerrors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") @@ -146,7 +146,7 @@ def workout_strava_upload_view(request,id=0): errorlog.write("views.py line 826\r\n") message = 'Error: '+errorstring messages.error(request,message) - else: # No tcxfile + else: # pragma: no cover # No tcxfile message = "Strava Data error "+tcxmessg messages.error(request,message) w.uploadedtostrava = -1 @@ -164,7 +164,7 @@ def workout_strava_upload_view(request,id=0): } ) response = HttpResponseRedirect(url) - except ActivityUploadFailed as e: + except ActivityUploadFailed as e: # pragma: no cover message = "Strava Upload error: %s" % e messages.error(request,message) w.uploadedtostrava = -1 @@ -188,10 +188,10 @@ def workout_c2_upload_view(request,id=0): try: message,c2id = c2stuff.workout_c2_upload(request.user,w) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/c2authorize/") - if message and c2id <=0: + if message and c2id <=0: # pragma: no cover messages.error(request,message) elif message: messages.info(request,message) @@ -216,14 +216,14 @@ def workout_runkeeper_upload_view(request,id=0): try: thetoken = runkeeper_open(r.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") # ready to upload. Hurray data = runkeeperstuff.createrunkeeperworkoutdata(w) - if not data: + if not data: # pragma: no cover message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, @@ -242,7 +242,7 @@ def workout_runkeeper_upload_view(request,id=0): response = requests.post(url,headers=headers,data=json.dumps(data,default=default)) # check for duplicate error first - if (response.status_code == 409 ): + if (response.status_code == 409 ): # pragma: no cover # pragma: no cover message = "Duplicate error" messages.error(request,message) w.uploadedtorunkeeper = -1 @@ -255,7 +255,7 @@ def workout_runkeeper_upload_view(request,id=0): kwargs={'id':encoder.encode_hex(w.id)}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover s = response message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) messages.error(request,message) @@ -264,9 +264,9 @@ def workout_runkeeper_upload_view(request,id=0): url = reverse(r.defaultlandingpage, kwargs = { 'id':encoder.encode_hex(w.id), - }) + }) # pragma: no cover - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) # pragma: no cover # Upload workout to Underarmour @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) @@ -277,14 +277,14 @@ def workout_underarmour_upload_view(request,id=0): try: thetoken = underarmour_open(r.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/underarmourauthorize/") # ready to upload. Hurray data = underarmourstuff.createunderarmourworkoutdata(w) - if not data: + if not data: # pragma: no cover message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, @@ -305,7 +305,7 @@ def workout_underarmour_upload_view(request,id=0): # check for duplicate error first - if (response.status_code == 409 ): + if (response.status_code == 409 ): # pragma: no cover # pragma: no cover message = "Duplicate error" messages.error(request,message) w.uploadedtounderarmour = -1 @@ -317,7 +317,7 @@ def workout_underarmour_upload_view(request,id=0): url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover s = response message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason messages.error(request,message) @@ -325,9 +325,9 @@ def workout_underarmour_upload_view(request,id=0): url = reverse(r.defaultlandingpage, kwargs = { 'id':encoder.encode_hex(w.id), - }) + }) # pragma: no cover - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) # pragma: no cover # Upload workout to SportTracks @permission_required('workout.change_workout',fn=get_workout_by_opaqueid) @@ -339,14 +339,14 @@ def workout_sporttracks_upload_view(request,id=0): try: thetoken = sporttracks_open(r.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") data = sporttracksstuff.createsporttracksworkoutdata(w) - if not data: + if not data: # pragma: no cover message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, @@ -365,7 +365,7 @@ def workout_sporttracks_upload_view(request,id=0): # check for duplicate error first - if (response.status_code == 409 ): + if (response.status_code == 409 ): # pragma: no cover message = "Duplicate error" messages.error(request,message) w.uploadedtosporttracks = -1 @@ -380,7 +380,7 @@ def workout_sporttracks_upload_view(request,id=0): url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover s = response message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason messages.error(request,message) @@ -388,14 +388,14 @@ def workout_sporttracks_upload_view(request,id=0): url = reverse(r.defaultlandingpage, kwargs = { 'id':encoder.encode_hex(w.id), - }) + }) # pragma: no cover - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) # pragma: no cover # NK LiNK authorization @login_required() -def rower_nk_authorize(request): +def rower_nk_authorize(request): # pragma: no cover state = str(uuid4()) scope = "read" params = { @@ -415,7 +415,7 @@ def rower_nk_authorize(request): # Concept2 authorization @login_required() -def rower_c2_authorize(request): +def rower_c2_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -430,7 +430,7 @@ def rower_c2_authorize(request): # Garmin authorization @login_required() -def rower_garmin_authorize(request): +def rower_garmin_authorize(request): # pragma: no cover authorization_url,token,secret = garmin_stuff.garmin_authorize() request.session['garmin_owner_key'] = token request.session['garmin_owner_secret'] = secret @@ -438,7 +438,7 @@ def rower_garmin_authorize(request): # Strava Authorization @login_required() -def rower_strava_authorize(request): +def rower_strava_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -455,7 +455,7 @@ def rower_strava_authorize(request): # Polar Authorization @login_required() -def rower_polar_authorize(request): +def rower_polar_authorize(request): # pragma: no cover state = str(uuid4()) @@ -473,7 +473,7 @@ def rower_polar_authorize(request): # Runkeeper authorization @login_required() -def rower_runkeeper_authorize(request): +def rower_runkeeper_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -491,7 +491,7 @@ def rower_runkeeper_authorize(request): # SportTracks Authorization @login_required() -def rower_sporttracks_authorize(request): +def rower_sporttracks_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -509,7 +509,7 @@ def rower_sporttracks_authorize(request): # Underarmour Authorization @login_required() -def rower_underarmour_authorize(request): +def rower_underarmour_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -526,7 +526,7 @@ def rower_underarmour_authorize(request): # Underarmour Authorization @login_required() -def rower_rp3_authorize(request): +def rower_rp3_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -541,7 +541,7 @@ def rower_rp3_authorize(request): # Underarmour Authorization @login_required() -def rower_tp_authorize(request): +def rower_tp_authorize(request): # pragma: no cover # Generate a random string for the state parameter # Save it for use later to prevent xsrf attacks @@ -576,7 +576,7 @@ def rower_c2_token_refresh(request): successmessage = "Tokens refreshed. Good to go" messages.info(request,successmessage) - else: + else: # pragma: no cover message = "Something went wrong (refreshing tokens). Please reauthorize:" messages.error(request,message) @@ -677,7 +677,7 @@ def rower_process_callback(request): try: code = request.GET['code'] res = c2stuff.get_token(code) - except MultiValueDictKeyError: + except MultiValueDictKeyError: # pragma: no cover message = "The resource owner or authorization server denied the request" messages.error(request,message) @@ -686,7 +686,7 @@ def rower_process_callback(request): return HttpResponseRedirect(url) access_token = res[0] - if access_token == 0: + if access_token == 0: # pragma: no cover message = res[1] message += ' Contact info@rowsandall.com if this behavior persists.' messages.error(request,message) @@ -716,12 +716,12 @@ def rower_process_callback(request): # dummy @login_required() -def rower_process_twittercallback(request): +def rower_process_twittercallback(request): # pragma: no cover return "dummy" # Process Polar Callback @login_required() -def rower_process_polarcallback(request): +def rower_process_polarcallback(request): # pragma: no cover try: code = request.GET['code'] except MultiValueDictKeyError: @@ -754,7 +754,7 @@ def rower_process_polarcallback(request): # process Garmin callback @login_required() -def rower_process_garmincallback(request): +def rower_process_garmincallback(request): # pragma: no cover r = getrower(request.user) absoluteurl = request.build_absolute_uri() @@ -775,7 +775,7 @@ def rower_process_garmincallback(request): # Process NK Callback @login_required() -def rower_process_nkcallback(request): +def rower_process_nkcallback(request): # pragma: no cover # do stuff try: code = request.GET.get('code',None) @@ -819,7 +819,7 @@ def rower_process_nkcallback(request): def workout_getnkworkout_all(request): try: thetoken = nk_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("rower_nk_authorize") r = getrequestrower(request) @@ -828,7 +828,7 @@ def workout_getnkworkout_all(request): if result: messages.info(request,"Your NK workouts will be imported in the coming few minutes") - else: + else: # pragma: no cover messages.error(request,"Your NK workouts import failed") url = reverse('workouts_view') @@ -840,12 +840,12 @@ def workout_nkimport_view(request,userid=0,after=0,before=0): r = getrequestrower(request,userid=userid) try: thetoken = nk_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/nkauthorize/") res = nkstuff.get_nk_workout_list(request.user,before=before,after=after) - if (res.status_code != 200): + if (res.status_code != 200): # pragma: no cover if (res.status_code == 401): r = getrower(request.user) if (r.stravatoken == '') or (r.stravatoken is None): @@ -869,7 +869,7 @@ def workout_nkimport_view(request,userid=0,after=0,before=0): with open('nkblocked.json','r') as nkblocked: jsondata = json.load(nkblocked) parkedids = jsondata['ids'] - except FileNotFoundError: + except FileNotFoundError: # pragma: no cover pass knownnkids = uniqify(knownnkids+tombstones+parkedids) @@ -893,7 +893,7 @@ def workout_nkimport_view(request,userid=0,after=0,before=0): n = item['name'] if i in knownnkids: nnn = '' - else: + else: # pragma: no cover nnn = 'NEW' ttot = str(datetime.timedelta(seconds=int(float(item['elapsedTime'])/1000.))) s = arrow.get(item['startTime'],tzinfo=r.defaulttimezone).format(arrow.FORMAT_RFC850) @@ -931,10 +931,10 @@ def rower_process_stravacallback(request): try: code = request.GET['code'] scope = request.GET['scope'] - except MultiValueDictKeyError: + except MultiValueDictKeyError:# pragma: no cover try: message = request.GET['error'] - except MultiValueDictKeyError: + except MultiValueDictKeyError:# pragma: no cover message = "access error" messages.error(request,message) @@ -964,7 +964,7 @@ def rower_process_stravacallback(request): messages.info(request,successmessage) url = reverse('rower_exportsettings_view') return HttpResponseRedirect(url) - else: + else:# pragma: no cover message = "Something went wrong with the Strava authorization" messages.error(request,message) url = reverse('rower_exportsettings_view') @@ -979,7 +979,7 @@ def rower_process_runkeepercallback(request): res = runkeeperstuff.get_token(code) access_token = res[0] - if access_token == 0: + if access_token == 0:# pragma: no cover messages.error(request,"Something went wrong importing the token") url = reverse('workouts_view') @@ -1004,7 +1004,7 @@ def rower_process_runkeepercallback(request): def rower_process_sporttrackscallback(request): try: code = request.GET['code'] - except: + except:# pragma: no cover messages.error(request,"Sorry, something went wrong.") url = reverse('rower_exportsettings_view') return HttpResponseRedirect(url) @@ -1058,7 +1058,7 @@ def rower_process_underarmourcallback(request): # Process RP3 callback @login_required() -def rower_process_rp3callback(request): +def rower_process_rp3callback(request): # pragma: no cover try: code = request.GET['code'] except MultiValueDictKeyError: @@ -1095,7 +1095,7 @@ def rower_process_rp3callback(request): def rower_process_tpcallback(request): try: code = request.GET['code'] - except MultiValueDictKeyError: + except MultiValueDictKeyError: # pragma: no cover messages.error(request,"There was an error with the callback") try: errormessage = request.GET['error'] @@ -1128,7 +1128,7 @@ def rower_process_tpcallback(request): # Process Own API callback - for API testing purposes @login_required() -def rower_process_testcallback(request): +def rower_process_testcallback(request): # pragma: no cover code = request.GET['code'] res = ownapistuff.get_token(code) @@ -1153,13 +1153,13 @@ def workout_rp3import_view(request,userid=0): try: thetoken = rp3stuff.rp3_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover url = reverse('rower_rp3_authorize') return HttpResponseRedirect(url) res = rp3stuff.get_rp3_workout_list(request.user) - if (res.status_code != 200): + if (res.status_code != 200): # pragma: no cover if (res.status_code == 401): r = getrower(request.user) if (r.stravatoken == '') or (r.stravatoken is None): @@ -1185,7 +1185,7 @@ def workout_rp3import_view(request,userid=0): for key,data in workouts_list.iterrows(): i = data['id'] - if i in knownrp3ids: + if i in knownrp3ids: # pragma: no cover nnn = '' else: nnn = 'NEW' @@ -1229,14 +1229,14 @@ def workout_stravaimport_view(request,message="",userid=0): # messages.info(request,"You cannot import other people's workouts from Strava") try: thetoken = strava_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/stravaauthorize/") res = stravastuff.get_strava_workout_list(request.user) - if (res.status_code != 200): + if (res.status_code != 200): # pragma: no cover if (res.status_code == 401): r = getrower(request.user) if (r.stravatoken == '') or (r.stravatoken is None): @@ -1258,7 +1258,7 @@ def workout_stravaimport_view(request,message="",userid=0): wfailed = Workout.objects.filter(user=r,uploadedtostrava=-1) - for w in wfailed: + for w in wfailed: # pragma: no cover for item in stravadata: elapsed_time = item['elapsed_time'] start_date = item['start_date'] @@ -1282,7 +1282,7 @@ def workout_stravaimport_view(request,message="",userid=0): for item in res.json(): d = int(float(item['distance'])) i = item['id'] - if i in knownstravaids: + if i in knownstravaids: # pragma: no cover nnn = '' else: nnn = 'NEW' @@ -1317,7 +1317,7 @@ def workout_stravaimport_view(request,message="",userid=0): 'teams':get_my_teams(request.user), }) - return HttpResponse(res) + return HttpResponse(res) # pragma: no cover # for Strava webhook request validation @csrf_exempt @@ -1481,7 +1481,7 @@ def strava_webhook_view(request): # For push notifications from Garmin @csrf_exempt -def garmin_summaries_view(request): +def garmin_summaries_view(request): # pragma: no cover if request.method != 'POST': return HttpResponse(status=200) @@ -1504,7 +1504,7 @@ def garmin_summaries_view(request): return HttpResponse(status=200) @csrf_exempt -def garmin_newfiles_ping(request): +def garmin_newfiles_ping(request): # pragma: no cover t = time.localtime() timestamp = time.strftime('%b-%d-%Y_%H%M', t) @@ -1528,7 +1528,7 @@ def garmin_newfiles_ping(request): except KeyError: pass - return HttpResponse(status=200) + return HttpResponse(status=200) # pragma: no cover @csrf_exempt def garmin_deregistration_view(request): @@ -1544,16 +1544,16 @@ def garmin_deregistration_view(request): r = Rower.objects.get(garmintoken=garmintoken) r.garmintoken = '' r.save() - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass - except KeyError: + except KeyError: # pragma: no cover pass return HttpResponse(status=200) @csrf_exempt def garmin_details_view(request): - if request.method != 'POST': + if request.method != 'POST': # pragma: no cover return HttpResponse(status=200) t = time.localtime() @@ -1577,12 +1577,12 @@ def workout_runkeeperimport_view(request,message="",userid=0): if (r.runkeepertoken == '') or (r.runkeepertoken is None): s = "Token doesn't exist. Need to authorize" return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") - message = "Something went wrong in workout_runkeeperimport_view" - messages.error(request,message) + message = "Something went wrong in workout_runkeeperimport_view" # pragma: no cover + messages.error(request,message) # pragma: no cover - if settings.DEBUG: + if settings.DEBUG: # pragma: no cover return HttpResponse(res) - else: + else: # pragma: no cover url = reverse('workouts_view') return HttpResponseRedirect(url) @@ -1620,7 +1620,7 @@ def workout_runkeeperimport_view(request,message="",userid=0): 'teams':get_my_teams(request.user), }) - return HttpResponse(res) + return HttpResponse(res) # pragma: no cover # The page where you select which RunKeeper workout to import @login_required() @@ -1638,7 +1638,7 @@ def workout_underarmourimport_view(request,message="",userid=0): n = item['name'] try: d = item['aggregates']['distance_total'] - except KeyError: + except KeyError: # pragma: no cover d = 0 try: ttot = item['aggregates']['active_time_total'] @@ -1671,12 +1671,12 @@ def workout_underarmourimport_view(request,message="",userid=0): 'teams':get_my_teams(request.user), }) - return HttpResponse(res) + return HttpResponse(res) # pragma: no cover # the page where you select which Polar workout to Import @login_required() @permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def workout_polarimport_view(request,userid=0): +def workout_polarimport_view(request,userid=0): # pragma: no cover exercises = polarstuff.get_polar_workouts(request.user) workouts = [] @@ -1686,7 +1686,7 @@ def workout_polarimport_view(request,userid=0): messages.error(request,'Not authorized. You need to connect to Polar first') url = reverse('workouts_view') return HttpResponseRedirect(url) - except: + except: # pragma: no cover pass for exercise in exercises: @@ -1744,11 +1744,11 @@ def workout_sporttracksimport_view(request,message="",userid=0): if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): s = "Token doesn't exist. Need to authorize" return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") - else: + else: # pragma: no cover return HttpResponseRedirect("/rowers/me/sporttracksrefresh/") - message = "Something went wrong in workout_sporttracksimport_view" - messages.error(request,message) - if settings.DEBUG: + message = "Something went wrong in workout_sporttracksimport_view" # pragma: no cover + messages.error(request,message) # pragma: no cover + if settings.DEBUG: # pragma: no cover return HttpResponse(res) else: url = reverse('workouts_view') @@ -1764,7 +1764,7 @@ def workout_sporttracksimport_view(request,message="",userid=0): for item in res.json()['items']: d = int(float(item['total_distance'])) i = int(getidfromuri(item['uri'])) - if i in knownstids: + if i in knownstids: # pragma: no cover nnn = '' else: nnn = 'NEW' @@ -1802,10 +1802,10 @@ def workout_sporttracksimport_view(request,message="",userid=0): # List of workouts on Concept2 logbook. This view only used for debugging @login_required() -def c2listdebug_view(request,page=1,message=""): +def c2listdebug_view(request,page=1,message=""): # pragma: no cover try: thetoken = c2_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/c2authorize/") r = getrower(request.user) @@ -1845,10 +1845,10 @@ def c2listdebug_view(request,page=1,message=""): # Import all unknown workouts available on Concept2 logbook @login_required() -def workout_getc2workout_all(request,page=1,message=""): +def workout_getc2workout_all(request,page=1,message=""): # pragma: no cover try: thetoken = c2_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/c2authorize/") r = getrequestrower(request) @@ -1864,10 +1864,10 @@ def workout_getc2workout_all(request,page=1,message=""): return HttpResponseRedirect(url) @login_required() -def workout_getrp3workout_all(request): +def workout_getrp3workout_all(request): # pragma: no cover try: thetoken = rp3_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/rp3authorize/") r = getrequestrower(request) @@ -1891,12 +1891,12 @@ def workout_c2import_view(request,page=1,userid=0,message=""): try: thetoken = c2_open(request.user) - except NoTokenError: + except NoTokenError: # pragma: no cover return HttpResponseRedirect("/rowers/me/c2authorize/") res = c2stuff.get_c2_workout_list(request.user,page=page) - if (res.status_code != 200): + if (res.status_code != 200): # pragma: no cover message = "Something went wrong in workout_c2import_view (C2 token refresh)" messages.error(request,message) url = reverse('workouts_view') @@ -1915,7 +1915,7 @@ def workout_c2import_view(request,page=1,userid=0,message=""): with open('c2blocked.json','r') as c2blocked: jsondata = json.load(c2blocked) parkedids = jsondata['ids'] - except FileNotFoundError: + except FileNotFoundError: # pragma: no cover pass knownc2ids = uniqify(knownc2ids+tombstones+parkedids) @@ -1931,7 +1931,7 @@ def workout_c2import_view(request,page=1,userid=0,message=""): c = item['comments'] if i in knownc2ids: nnn = '' - else: + else: # pragma: no cover nnn = 'NEW' keys = ['id','distance','duration','starttime','rowtype','source','comment','new'] values = [i,d,ttot,s,r,s2,c,nnn] @@ -2005,12 +2005,12 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False): data,strokedata = importsources[source].get_workout(request.user,externalid, do_async=do_async) - if do_async: + if do_async: # pragma: no cover messages.info(request,"Your workout will be imported in the background") url = reverse('workouts_view') return HttpResponseRedirect(url) - if not data: + if not data: # pragma: no cover messages.error(request,"No strokedata received") url = reverse('workouts_view') @@ -2033,7 +2033,7 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False): pass - if strokedata.empty: + if strokedata.empty: # pragma: no cover distance = data['distance'] c2id = data['id'] workouttype = mytypes.c2mappinginv[data['type']] @@ -2106,7 +2106,7 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False): w = get_workout(encoder.encode_hex(id)) - if 'workout' in data: + if 'workout' in data: # pragma: no cover if 'splits' in data['workout']: splitdata = data['workout']['splits'] elif 'intervals' in data['workout']: @@ -2117,7 +2117,7 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False): splitdata = False # splitdata (only for C2) - if splitdata: + if splitdata: # pragma: no cover w.summary,sa,results = c2stuff.summaryfromsplitdata(splitdata,data,w.csvfilename,workouttype=workouttype) w.save() @@ -2142,20 +2142,20 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False): w.uploadedtostrava = externalid elif source == 'c2': w.uploadedtoc2 = externalid - elif source == 'polar': + elif source == 'polar': # pragma: no cover w.uploadedtopolar = externalid elif source == 'runkeeper': w.uploadedtorunkeeper = externalid elif source == 'sporttracks': w.uploadedtosporttracks = externalid - elif source == 'trainingpeaks': + elif source == 'trainingpeaks': # pragma: no cover w.uploadedtotp = externalid elif source == 'underarmour': w.uploadedtounderarmour = externalid w.save() - if message: + if message: # pragma: no cover messages.error(request,message) r = getrower(request.user) @@ -2206,7 +2206,7 @@ def workout_getsporttracksworkout_all(request): def workout_getstravaworkout_all(request): r = getrower(request.user) res = stravastuff.get_strava_workouts(r) - if res == 1: + if res == 1: # pragma: no cover messages.info(request,"Your workouts are being imported and should appear on the site in the next 15 minutes") else: messages.error(request,"Couldn't import Strava workouts ") @@ -2217,7 +2217,7 @@ def workout_getstravaworkout_all(request): # Imports all new workouts from SportTracks @login_required() -def workout_getstravaworkout_next(request): +def workout_getstravaworkout_next(request): # pragma: no cover r = Rower.objects.get(user=request.user) diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index d791b587..957b6d35 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -1192,7 +1192,7 @@ def plannedsession_teamedit_view(request, url = reverse('plannedsessions_view') - if "_continue" in request.POST: + if "_continue" in request.POST: # pragma: no cover url = reverse(plannedsession_edit_view, kwargs={ 'id':int(ps.id), @@ -1648,10 +1648,10 @@ def plannedsessions_manage_view(request,userid=0, ps = PlannedSession.objects.get(id=ps_form.cleaned_data['plannedsession']) if w_form.is_valid(): selectedworkouts = w_form.cleaned_data['workouts'] - else: + else: # pragma: no cover selectedworkouts = [] - if len(selectedworkouts)==0: + if len(selectedworkouts)==0: # pragma: no cover for w in ws: remove_workout_plannedsession(w,ps) @@ -1664,7 +1664,7 @@ def plannedsessions_manage_view(request,userid=0, result,comments,errors = add_workouts_plannedsession(workouts,ps,r) for c in comments: messages.info(request,c) - for er in errors: + for er in errors: # pragma: no cover messages.error(request,er) @@ -2477,7 +2477,7 @@ class PlannedSessionDelete(DeleteView): def rower_view_instantplan(request,id='',userid=0): r = getrequestrower(request,userid=userid) - if not id: + if not id: # pragma: no cover raise Http404("Plan does not exist") plan = InstantPlan.objects.get(uuid=id) @@ -2488,7 +2488,7 @@ def rower_view_instantplan(request,id='',userid=0): headers = {'Authorization':authorizationstring} response = requests.get(url=url,headers=headers) - if response.status_code != 200: + if response.status_code != 200: # pragma: no cover messages.error(request,"Could not connect to the training plan server") return HttpResponseRedirect(reverse('rower_select_instantplan')) @@ -2520,7 +2520,7 @@ def rower_view_instantplan(request,id='',userid=0): ).order_by("-date") if request.method == 'POST' and not request.user.is_anonymous: - if not can_plan(request.user): + if not can_plan(request.user): # pragma: no cover messages.error(request,'You must be on a paid plan to use this functionality') url = reverse('rower_view_instantplan',kwargs={ 'id':id, @@ -2534,11 +2534,11 @@ def rower_view_instantplan(request,id='',userid=0): name = form.cleaned_data['name'] try: targetid = form.cleaned_data['target'] - if targetid != '': + if targetid != '': # pragma: no cover target = TrainingTarget.objects.get(id=int(targetid)) else: target = None - except KeyError: + except KeyError: # pragma: no cover try: targetid = request.POST['target'] if targetid != '': @@ -2553,12 +2553,12 @@ def rower_view_instantplan(request,id='',userid=0): datechoice = form.cleaned_data['datechoice'] status = True - if target and datechoice == 'target': + if target and datechoice == 'target': # pragma: no cover enddate = target.date startdate = enddate-datetime.timedelta(days=plan.duration) elif datechoice == 'startdate': enddate = startdate+datetime.timedelta(days=plan.duration) - else: + else: # pragma: no cover startdate = enddate-datetime.timedelta(days=plan.duration) @@ -2585,7 +2585,7 @@ def rower_view_instantplan(request,id='',userid=0): elif not request.user.is_anonymous: form = InstantPlanSelectForm(targets=targets,instantplan=plan,initial={'datechoice':'startdate'}) - else: + else: # pragma: no cover form = None breadcrumbs = [ @@ -2632,7 +2632,7 @@ def remove_groupsession_view(request,id=0): if res: messages.info(request,"We have removed you from this group session") - else: + else: # pragma: no cover messages.error(request,"For some reason we could not remove you from this group session") url = reverse('plannedsessions_view') @@ -2641,12 +2641,12 @@ def remove_groupsession_view(request,id=0): @login_required() def add_instantplan_view(request): - if not request.user.is_staff: + if not request.user.is_staff: # pragma: no cover raise PermissionDenied("Not Allowed") r = getrequestrower(request) - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover form = InstantPlanForm(request.POST,request.FILES) if form.is_valid(): ip = form.save(commit=False) @@ -2764,9 +2764,9 @@ def rower_create_trainingplan(request,id=0): targetid = request.POST['target'] if targetid != '': target = TrainingTarget.objects.get(id=int(targetid)) - else: + else: # pragma: no cover target = None - except KeyError: + except KeyError: # pragma: no cover target = None startdate = form.cleaned_data['startdate'] status = form.cleaned_data['status'] @@ -2814,7 +2814,7 @@ def rower_create_trainingplan(request,id=0): status=True, ).order_by("-startdate") - for p in plans_to_deactivate: + for p in plans_to_deactivate: # pragma: no cover p.status = False p.save() @@ -2863,18 +2863,6 @@ def rower_delete_trainingtarget(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(can_plan,login_url="/rowers/paidplans", - message="This functionality requires a Coach or Self-Coach plan", - redirect_field_name=None) -@permission_required('target.delete_plan',fn=get_plan_by_pk,raise_exception=True) -def rower_delete_trainingplan(request,id=0): - plan = get_object_or_404(TrainingPlan,pk=id) - plan.delete() - - url = reverse(rower_create_trainingplan) - - return HttpResponseRedirect(url) - class TrainingPlanDelete(DeleteView): model = TrainingPlan template_name = 'trainingplan_delete.html' @@ -2882,12 +2870,12 @@ class TrainingPlanDelete(DeleteView): def get_object(self, *args, **kwargs): obj = super(TrainingPlanDelete, self).get_object(*args, **kwargs) - if not can_delete_plan(self.request.user,obj): + if not can_delete_plan(self.request.user,obj): # pragma: no cover raise PermissionDenied('You are not allowed to delete this training plan') return obj -class MicroCycleDelete(DeleteView): +class MicroCycleDelete(DeleteView): # pragma: no cover model = TrainingMicroCycle template_name = 'trainingplan_delete.html' @@ -2953,7 +2941,7 @@ class MicroCycleDelete(DeleteView): return obj -class MesoCycleDelete(DeleteView): +class MesoCycleDelete(DeleteView): # pragma: no cover model = TrainingMesoCycle template_name = 'trainingplan_delete.html' @@ -3016,7 +3004,7 @@ class MesoCycleDelete(DeleteView): return obj -class MacroCycleDelete(DeleteView): +class MacroCycleDelete(DeleteView): # pragma: no cover model = TrainingMacroCycle template_name = 'trainingplan_delete.html' @@ -3085,13 +3073,13 @@ def rower_trainingplan_execution_view(request, if int(id)>0: try: plan = TrainingPlan.objects.get(id=id) - except TrainingPlan.DoesNotExist: + except TrainingPlan.DoesNotExist: # pragma: no cover raise Http404("Training Plan Does Not Exist") - if not is_coach_user(request.user,plan.manager.user): + if not is_coach_user(request.user,plan.manager.user): # pragma: no cover if request.user.rower not in plan.rowers.all(): raise PermissionDenied("Access denied") - if not startdate or not enddate: + if not startdate or not enddate: # pragma: no cover if int(id)>0: startdate = plan.startdate enddate = plan.enddate @@ -3103,12 +3091,12 @@ def rower_trainingplan_execution_view(request, if int(id)>0: data,message = get_execution_report(r,startdate,enddate,plan=plan) - else: + else: # pragma: no cover data,message = get_execution_report(r,startdate,enddate) if not data.empty: script, div = interactive_planchart(data,startdate,enddate) - else: + else: # pragma: no cover script = '' div = '' messages.error(request,'The plan does not cover this time range') @@ -3133,7 +3121,7 @@ def rower_trainingplan_execution_view(request, 'name': 'Execution' } ] - else: + else: # pragma: no cover breadcrumbs = [ { 'url':reverse(plannedsessions_view, @@ -3224,7 +3212,7 @@ def rower_trainingplan_view(request, try: thismicro = get_todays_micro(plan,thedate=startdate) thismicroid = thismicro.pk - except AttributeError: + except AttributeError: # pragma: no cover thismicroid = None @@ -3242,7 +3230,7 @@ def rower_trainingplan_view(request, } ) -class TrainingMacroCycleUpdate(UpdateView): +class TrainingMacroCycleUpdate(UpdateView): # pragma: no cover model = TrainingMacroCycle template_name = 'trainingplan_edit.html' form_class = TrainingMacroCycleForm @@ -3307,7 +3295,7 @@ class TrainingMacroCycleUpdate(UpdateView): obj.save() return obj -class TrainingMesoCycleUpdate(UpdateView): +class TrainingMesoCycleUpdate(UpdateView): # pragma: no cover model = TrainingMesoCycle template_name = 'trainingplan_edit.html' form_class = TrainingMesoCycleForm @@ -3381,7 +3369,7 @@ class TrainingMesoCycleUpdate(UpdateView): obj.plan.save() return obj -class TrainingMicroCycleUpdate(UpdateView): +class TrainingMicroCycleUpdate(UpdateView): # pragma: no cover model = TrainingMicroCycle template_name = 'trainingplan_edit.html' form_class = TrainingMicroCycleForm @@ -3460,7 +3448,7 @@ class TrainingMicroCycleUpdate(UpdateView): obj.plan.save() return obj -class TrainingPlanUpdate(UpdateView): +class TrainingPlanUpdate(UpdateView): # pragma: no cover model = TrainingPlan template_name = 'trainingplan_edit.html' form_class = TrainingPlanForm @@ -3519,7 +3507,7 @@ class TrainingPlanUpdate(UpdateView): return obj -class TrainingTargetUpdate(UpdateView): +class TrainingTargetUpdate(UpdateView): # pragma: no cover model = TrainingTarget template_name = 'trainingplan_edit.html' form_class = TrainingTargetForm @@ -3575,7 +3563,7 @@ from rowers.utils import allsundays message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) @permission_required('cycle.change_cycle',fn=get_meso_by_pk,raise_exception=True) -def planmesocyclebyweek(request,id=0,userid=0): +def planmesocyclebyweek(request,id=0,userid=0): # pragma: no cover cycle = get_object_or_404(TrainingMesoCycle,pk=id) micros = TrainingMicroCycle.objects.filter(plan=cycle) @@ -3625,7 +3613,7 @@ from rowers.utils import allmonths message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) @permission_required('cycle.change_cycle',fn=get_macro_by_pk,raise_exception=True) -def planmacrocyclebymonth(request,id=0,userid=0): +def planmacrocyclebymonth(request,id=0,userid=0): # pragma: no cover cycle = get_object_or_404(TrainingMacroCycle,pk=id) mesos = TrainingMesoCycle.objects.filter(plan=cycle) From c97d975c096cf96e207883b4339271dad914e365 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 20 Apr 2021 13:20:36 +0200 Subject: [PATCH 7/9] importviews done --- rowers/tests/test_imports.py | 22 ++++++++++-------- rowers/views/importviews.py | 44 ++++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index db61bd37..204075e2 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -636,7 +636,9 @@ class StravaObjects(DjangoTestCase): self.u.last_name = 'Sander' self.u.save() self.r = Rower.objects.create(user=self.u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() + gdproptindate=timezone.now(), + strava_auto_import=True, + strava_auto_delete=True, ) self.r.stravatoken = '12' @@ -676,7 +678,7 @@ class StravaObjects(DjangoTestCase): starttime=workoutstarttime, startdatetime=row.rowdatetime, duration=duration,distance=totaldist, - csvfilename=filename + csvfilename=filename,uploadedtostrava=123, ) @patch('rowers.stravastuff.requests.post', side_effect=mocked_requests) @@ -696,10 +698,10 @@ class StravaObjects(DjangoTestCase): data = { 'aspect_type':'create', - 'object_id': 123, + 'object_id': 245, 'object_type':'activity', - 'strava_owner': self.r.strava_owner_id, - 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + 'owner_id': self.r.strava_owner_id, + 'event_time': arrow.get(datetime.datetime.now()).timestamp(), } raw_data = json.dumps(data) @@ -715,8 +717,8 @@ class StravaObjects(DjangoTestCase): }, 'object_id': 123, 'object_type':'activity', - 'strava_owner': self.r.strava_owner_id, - 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + 'owner_id': self.r.strava_owner_id, + 'event_time': arrow.get(datetime.datetime.now()).timestamp(), } raw_data = json.dumps(data) @@ -726,10 +728,10 @@ class StravaObjects(DjangoTestCase): data = { 'aspect_type':'delete', - 'object_id': 123, + 'object_id': 245, 'object_type':'activity', - 'strava_owner': self.r.strava_owner_id, - 'starttimeunix': arrow.get(datetime.datetime.now()).timestamp(), + 'owner_id': self.r.strava_owner_id, + 'event_time': arrow.get(datetime.datetime.now()).timestamp(), } raw_data = json.dumps(data) diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index b46000bd..e4735ffe 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -1325,7 +1325,7 @@ def strava_webhook_view(request): if request.method == 'GET': challenge = request.GET.get('hub.challenge') verificationtoken = request.GET.get('hub.verify_token') - if verificationtoken != stravastuff.webhookverification: + if verificationtoken != stravastuff.webhookverification: # pragma: no cover return HttpResponse(status=403) data = {"hub.challenge":challenge} return JSONResponse(data) @@ -1341,12 +1341,16 @@ def strava_webhook_view(request): # POST - does nothing so far data = json.loads(request.body) + aspect_type = data['aspect_type'] + object_type = data['object_type'] + strava_owner = data['owner_id'] + starttimeunix = data['event_time'] try: aspect_type = data['aspect_type'] object_type = data['object_type'] strava_owner = data['owner_id'] starttimeunix = data['event_time'] - except KeyError: + except KeyError: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1359,7 +1363,7 @@ def strava_webhook_view(request): if aspect_type == 'create': try: stravaid = data['object_id'] - except KeyError: + except KeyError: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1370,7 +1374,7 @@ def strava_webhook_view(request): try: r = Rower.objects.get(strava_owner_id=strava_owner) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1381,14 +1385,14 @@ def strava_webhook_view(request): ws = Workout.objects.filter(uploadedtostrava=stravaid) if ws.count()==0 and r.strava_auto_import: job = stravastuff.async_get_workout(r.user,stravaid) - if job == 0: + if job == 0: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M',t) with open('strava_webhooks.log','a') as f: f.write('\n') f.write(timestamp) f.write(' ') f.write('Strava strava_open yielded NoTokenError') - else: + else: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1400,7 +1404,7 @@ def strava_webhook_view(request): elif aspect_type == 'delete': try: stravaid = data['object_id'] - except KeyError: + except KeyError: # pragma: no cover with open('strava_webhooks.log','a') as f: f.write('\n') f.write(timestamp) @@ -1410,11 +1414,11 @@ def strava_webhook_view(request): ws = Workout.objects.filter(uploadedtostrava=stravaid) if ws.count() == 0: return HttpResponse(status=200) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover return HttpResponse(status=200) - try: + try: # pragma: no cover r = Rower.objects.get(strava_owner_id=strava_owner) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1422,7 +1426,7 @@ def strava_webhook_view(request): f.write(' ') f.write('Rower not found') return HttpResponse(status=200) - if r.strava_auto_delete: + if r.strava_auto_delete: # pragma: no cover for w in ws: if w.user == r: w.delete() @@ -1430,7 +1434,7 @@ def strava_webhook_view(request): try: updates = data['updates'] stravaid = data['object_id'] - except KeyError: + except KeyError: # pragma: no cover with open('strava_webhooks.log','a') as f: f.write('\n') f.write(timestamp) @@ -1439,9 +1443,9 @@ def strava_webhook_view(request): return HttpResponse(status=200) try: ws = Workout.objects.filter(uploadedtostrava=stravaid) - if ws.count() == 0: + if ws.count() == 0: # pragma: no cover return HttpResponse(status=200) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1451,7 +1455,7 @@ def strava_webhook_view(request): return HttpResponse(status=200) try: r = Rower.objects.get(strava_owner_id=strava_owner) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover timestamp = time.strftime('%b-%d-%Y_%H%M', t) with open('strava_webhooks.log','a') as f: f.write('\n') @@ -1469,7 +1473,7 @@ def strava_webhook_view(request): try: w.workouttype = mytypes.stravamappinginv[value] w.save() - except KeyError: + except KeyError: # pragma: no cover with open('strava_webhooks.log','a') as f: f.write('\n') f.write(timestamp) @@ -1532,7 +1536,7 @@ def garmin_newfiles_ping(request): # pragma: no cover @csrf_exempt def garmin_deregistration_view(request): - if request.method != 'POST': + if request.method != 'POST': # pragma: no cover return HttpResponse(status=200) data = json.loads(request.body) @@ -1750,7 +1754,7 @@ def workout_sporttracksimport_view(request,message="",userid=0): messages.error(request,message) # pragma: no cover if settings.DEBUG: # pragma: no cover return HttpResponse(res) - else: + else: # pragma: no cover url = reverse('workouts_view') return HttpResponseRedirect(url) @@ -1798,7 +1802,7 @@ def workout_sporttracksimport_view(request,message="",userid=0): 'teams':get_my_teams(request.user), }) - return HttpResponse(res) + return HttpResponse(res) # pragma: no cover # List of workouts on Concept2 logbook. This view only used for debugging @login_required() @@ -2189,7 +2193,7 @@ def workout_getsporttracksworkout_all(request): id,message = sporttracksstuff.add_workout_from_data( request.user,sporttracksid,data,strokedata ) - if id==0: + if id==0: # pragma: no cover messages.error(request,message) else: From 0cbce4df9ff6f488712184ce8cbc50d7d53c3ef1 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 20 Apr 2021 15:18:18 +0200 Subject: [PATCH 8/9] racesviews ... coverage --- rowers/views/racesviews.py | 394 ++++++++++++++++++------------------- 1 file changed, 197 insertions(+), 197 deletions(-) diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index bf6dcf3a..6c417ae7 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -25,7 +25,7 @@ def getnearestraces(lat_lon,races): newlist = [] counter = 0 for race in races: - if race.course is None: + if race.course is None: # pragma: no cover newlist.append(race) else: c = race.course @@ -42,7 +42,7 @@ def getnearestraces(lat_lon,races): orders = [(c.id,howfaris(lat_lon,c.course)) for c in courseraces] orders = sorted(orders,key = lambda tup:tup[1]) ids = [id for id,distance in orders[0:4]] - for id, distance in orders[5:]: + for id, distance in orders[5:]: # pragma: no cover if distance 1: + if cs and len(cs) > 1: # pragma: no cover messages.info(request,'File contained multiple courses. We use the first one.') if cs: course = cs[0] @@ -538,7 +538,7 @@ def course_upload_replace_view(request,id=0): polygons = course['polygons'] course = courses.createcourse(r,cname,polygons,notes=cnotes) - if course.country == 'unknown': + if course.country == 'unknown': # pragma: no cover course.country = country course.save() @@ -548,15 +548,15 @@ def course_upload_replace_view(request,id=0): 'id':id, } ) - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse({'result':1,'url':url}) else: return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,"File does not contain a course") - else: + else: # pragma: no cover messages.error(request,"No file attached") - else: + else: # pragma: no cover messages.error(request,"Form is not valid") else: form = CourseForm() @@ -569,7 +569,7 @@ def course_upload_replace_view(request,id=0): 'course':course, 'active':'nav-racing', }) - else: + else: # pragma: no cover return {'result':0} @@ -591,7 +591,7 @@ def course_update_confirm(request,id=0,newid=0): 'id':course2.id, }) return HttpResponseRedirect(url) - else: + else: # pragma: no cover course2.delete() url = reverse(course_view, kwargs = { @@ -639,7 +639,7 @@ def course_update_confirm(request,id=0,newid=0): @login_required() def course_upload_view(request): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True r = getrower(request.user) @@ -666,18 +666,18 @@ def course_upload_view(request): course = courses.createcourse(r,cname,polygons,notes=cnotes) - if course.country == 'unknown': + if course.country == 'unknown': # pragma: no cover course.country = country course.save() os.remove(path_and_filename) url = reverse(courses_view) - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse({'result':1,'url':url}) else: return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,'Something went wrong - no file attached') url = reverse(course_upload_view) @@ -685,7 +685,7 @@ def course_upload_view(request): return JSONResponse({'result':0,'url':0}) else: return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,'Form is not valid') return render(request,'course_form.html', {'form':form, @@ -698,24 +698,24 @@ def course_upload_view(request): {'form':form, 'active':'nav-racing', }) - else: + else: # pragma: no cover return {'result':0} # Standards deactivate @login_required() def standard_deactivate_view(request,id=0): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True r = getrower(request.user) try: collection = StandardCollection.objects.get(id=id) - except StandardCollection.DoesNotExist: + except StandardCollection.DoesNotExist: # pragma: no cover raise Http404("Does not exist") - if request.user != collection.manager: + if request.user != collection.manager: # pragma: no cover raise PermissionDenied("You cannot change this set of time standards") collection.active = False @@ -728,7 +728,7 @@ def standard_deactivate_view(request,id=0): def standards_download_view(request,id=0): try: collection = StandardCollection.objects.get(id=id) - except StandardCollection.DoesNotExist: + except StandardCollection.DoesNotExist: # pragma: no cover raise Http404("Does not exist") filename = 'Standard Times {name} {id} {date}.csv'.format( @@ -752,11 +752,11 @@ def standards_download_view(request,id=0): @login_required() def standards_upload_view(request,id=0): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True r = getrower(request.user) - if id != 0: + if id != 0: # pragma: no cover collection = StandardCollection.objects.get(id=id) if request.user != collection.manager: raise PermissionDenied("You cannot change this set of time standards") @@ -779,24 +779,24 @@ def standards_upload_view(request,id=0): - if id==0: + if id==0: # pragma: no cover url = reverse(standards_view) else: url = reverse(standard_view,kwargs={'id':id}) - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse({'result':1,'url':url}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,'Something went wrong - no file attached') url = reverse(standards_upload_view) if is_ajax: return JSONResponse({'result':0,'url':0}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,'Form is not valid') return render(request,'standard_form.html', {'form':form, @@ -807,7 +807,7 @@ def standards_upload_view(request,id=0): else: if not is_ajax: form = StandardsForm() - if id != 0: + if id != 0: # pragma: no cover collection = StandardCollection.objects.get(id=id) form = StandardsForm(initial={ 'name':collection.name, @@ -818,12 +818,12 @@ def standards_upload_view(request,id=0): 'active':'nav-racing', 'id':id, }) - return {'result':0} + return {'result':0} # pragma: no cover def virtualevents_view(request): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True g = GeoIP2() @@ -831,7 +831,7 @@ def virtualevents_view(request): try: lat_lon = g.lat_lon(ip) city = g.city(ip) - except: + except: # pragma: no cover lat_lon = None city = { 'city': '', @@ -870,7 +870,7 @@ def virtualevents_view(request): regattatype = cd['regattatype'] if country == 'All': countries = VirtualRace.objects.order_by('country').values_list('country').distinct() - else: + else: # pragma: no cover countries = [country, 'Indoor'] @@ -900,13 +900,13 @@ def virtualevents_view(request): evaluation_closure__gte=timezone.now(), country__in=countries ).order_by("startdate","start_time") - elif regattatype == 'my': + elif regattatype == 'my': # pragma: no cover mysessions = get_my_session_ids(r) races = VirtualRace.objects.filter( id__in=mysessions, country__in=countries ).order_by("startdate","start_time") - elif regattatype == 'all': + elif regattatype == 'all': # pragma: no cover races = VirtualRace.objects.filter( country__in=countries ).order_by("startdate","start_time") @@ -915,11 +915,11 @@ def virtualevents_view(request): nearby = request.GET.get('nearby') - if nearby and lat_lon is not None: + if nearby and lat_lon is not None: # pragma: no cover races = getnearestraces(lat_lon,races) - if is_ajax: + if is_ajax: # pragma: no cover return render(request,'racelist.html', { 'races':races, 'rower':r, @@ -960,17 +960,17 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): if race.sessiontype == 'race': recordobj = VirtualRaceResult - else: + else: # pragma: no cover recordobj = IndoorVirtualRaceResult # datum moet voor race evaluation date zijn (ook in template controleren) try: record = recordobj.objects.get(id=recordid) - except recordobj.DoesNotExist: + except recordobj.DoesNotExist: # pragma: no cover messages.error(request,"We couldn't find the record") - if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): + if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): # pragma: no cover messages.error(request,"The evaluation is already closed and the results are official") url = reverse('virtualevent_view',kwargs={'id':raceid}) @@ -1006,11 +1006,11 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): try: workout = Workout.objects.get(id=record.workoutid) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover raise Http404("Workout not found") g = GraphImage.objects.filter(workout=workout).order_by("-creationdatetime") - for i in g: + for i in g: # pragma: no cover try: width,height = Image.open(i.filename).size i.width = width @@ -1027,18 +1027,18 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): if rowdata != 0: try: latitude = rowdata.df[' latitude'] - if not latitude.std(): + if not latitude.std(): # pragma: no cover hascoordinates = 0 - except (KeyError, AttributeError): + except (KeyError, AttributeError): # pragma: no cover hascoordinates = 0 - else: + else: # pragma: no cover hascoordinates = 0 if hascoordinates: mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'], rowdata.df[' longitude'], workout.name) - else: + else: # pragma: no cover mapscript = "" mapdiv = "" @@ -1063,7 +1063,7 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): buttons = [] if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -1072,10 +1072,10 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -1111,13 +1111,13 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): try: record = recordobj.objects.get(id=recordid) - except recordobj.DoesNotExist: + except recordobj.DoesNotExist: # pragma: no cover messages.error(request,"We couldn't find the record") - if r.id != record.userid: + if r.id != record.userid: # pragma: no cover raise PermissionDenied("You are not the owner of this result") - if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): + if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1): # pragma: no cover messages.error(request,"The evaluation is already closed and the results are official") url = reverse('virtualevent_view',kwargs={'id':raceid}) @@ -1151,7 +1151,7 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): else: form = DisqualificationForm(request.POST) - try: + try: # pragma: no cover workout = Workout.objects.get(id=record.workoutid) g = GraphImage.objects.filter(workout=workout).order_by("-creationdatetime") for i in g: @@ -1185,7 +1185,7 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): else: mapscript = "" mapdiv = "" - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover mapscript = "" mapdiv = "" workout = None @@ -1216,7 +1216,7 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): buttons = [] if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -1225,10 +1225,10 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -1255,13 +1255,13 @@ def virtualevent_view(request,id=0): if not request.user.is_anonymous: r = getrower(request.user) - else: + else: # pragma: no cover r = None try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': @@ -1278,7 +1278,7 @@ def virtualevent_view(request,id=0): # to-do - add DNS dns = [] - if timezone.now() > race.evaluation_closure: + if timezone.now() > race.evaluation_closure: # pragma: no cover dns = resultobj.objects.filter( race=race, workoutid__isnull=True, @@ -1301,7 +1301,7 @@ def virtualevent_view(request,id=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r,race): @@ -1310,7 +1310,7 @@ def virtualevent_view(request,id=0): if race_can_edit(r,race): buttons += ['editbutton'] - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm(request.POST,records=records) if form.is_valid(): cd = form.cleaned_data @@ -1424,7 +1424,7 @@ def virtualevent_view(request,id=0): if orderby not in allowed: orderby = None - if orderby is not None: + if orderby is not None: # pragma: no cover try: results = results.order_by(orderby) except AttributeError: @@ -1432,7 +1432,7 @@ def virtualevent_view(request,id=0): racelogos = race.logos.all() - if racelogos: + if racelogos: # pragma: no cover racelogo = racelogos[0] else: racelogo = None @@ -1470,12 +1470,12 @@ def virtualevent_results_download_view(request,id=0): try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': resultobj = VirtualRaceResult - else: + else: # pragma: no cover resultobj = IndoorVirtualRaceResult records = resultobj.objects.filter(race=race) @@ -1503,13 +1503,13 @@ def virtualevent_ranking_view(request,id=0): if not request.user.is_anonymous: r = getrower(request.user) - else: + else: # pragma: no cover r = None try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': @@ -1527,7 +1527,7 @@ def virtualevent_ranking_view(request,id=0): # to-do - add DNS dns = [] - if timezone.now() > race.evaluation_closure: + if timezone.now() > race.evaluation_closure: # pragma: no cover dns = resultobj.objects.filter( race=race, workoutid__isnull=True, @@ -1541,7 +1541,7 @@ def virtualevent_ranking_view(request,id=0): if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -1550,16 +1550,16 @@ def virtualevent_ranking_view(request,id=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): buttons += ['editbutton'] - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm(request.POST,records=records) if form.is_valid(): cd = form.cleaned_data @@ -1641,7 +1641,7 @@ def virtualevent_ranking_view(request,id=0): if results: form = RaceResultFilterForm(records=records) - else: + else: # pragma: no cover form = None @@ -1661,7 +1661,7 @@ def virtualevent_ranking_view(request,id=0): racelogos = race.logos.all() - if racelogos: + if racelogos: # pragma: no cover racelogo = racelogos[0] else: racelogo = None @@ -1689,14 +1689,14 @@ def virtualevent_withdraw_view(request,id=0,recordid=None): try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race_can_withdraw(r,race): remove_rower_race(r,race,recordid=recordid) messages.info(request, "You have successfully withdrawn from this race.") - else: + else: # pragma: no cover messages.error(request,"You cannot withdraw from this race") url = reverse('virtualevent_view', @@ -1711,12 +1711,12 @@ def virtualevent_addboat_view(request,id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype in ['race']: resultobj = VirtualRaceResult - else: + else: # pragma: no cover resultobj = IndoorVirtualRaceResult categories = None @@ -1726,7 +1726,7 @@ def virtualevent_addboat_view(request,id=0): standardcollection=race.coursestandards).order_by("name") - if not race_can_adddiscipline(r,race): + if not race_can_adddiscipline(r,race): # pragma: no cover messages.error(request,"You cannot register for this race") url = reverse('virtualevent_view', @@ -1771,11 +1771,11 @@ def virtualevent_addboat_view(request,id=0): if sex == 'not specified': sex = 'male' - if mix: + if mix: # pragma: no cover sex = 'mixed' - if boattype in boattypes and boatclass in boatclasses and race.coursestandards is None: + if boattype in boattypes and boatclass in boatclasses and race.coursestandards is None: # pragma: no cover # check if different sexes therecords = records.filter( boattype=boattype, @@ -1805,7 +1805,7 @@ def virtualevent_addboat_view(request,id=0): thegroups = [record.entrycategory for record in records] - if coursestandard in thegroups: + if coursestandard in thegroups: # pragma: no cover messages.error(request,"You have already registered in that group") url = reverse('virtualevent_view', kwargs = { @@ -1825,19 +1825,19 @@ def virtualevent_addboat_view(request,id=0): returnurl = reverse(virtualevent_register_view, kwargs={'id':race.id}) - if age < coursestandard.agemin: + if age < coursestandard.agemin: # pragma: no cover messages.error(request,'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) - if age > coursestandard.agemax: + if age > coursestandard.agemax: # pragma: no cover messages.error(request,'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) - if sex == 'male' and coursestandard.sex != 'male': + if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error(request,'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) - if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: # pragma: no cover messages.error(request,'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) @@ -1900,13 +1900,13 @@ def virtualevent_addboat_view(request,id=0): race.name, race.id ) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race = race) - for follower in followers: + for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name @@ -1938,7 +1938,7 @@ def virtualevent_addboat_view(request,id=0): 'sex':sex, 'entrycategory':initialcategory, } - else: + else: # pragma: no cover initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, @@ -1976,7 +1976,7 @@ def virtualevent_addboat_view(request,id=0): buttons = [] if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -1985,7 +1985,7 @@ def virtualevent_addboat_view(request,id=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] if race_can_withdraw(r,race): @@ -2009,7 +2009,7 @@ def virtualevent_register_view(request,id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") @@ -2032,7 +2032,7 @@ def virtualevent_register_view(request,id=0): if race.sessiontype == 'race': resultobj = VirtualRaceResult - else: + else: # pragma: no cover resultobj = IndoorVirtualRaceResult # we're still here @@ -2061,7 +2061,7 @@ def virtualevent_register_view(request,id=0): if sex == 'not specified': sex = 'male' - if mix: + if mix: # pragma: no cover sex = 'mixed' @@ -2080,19 +2080,19 @@ def virtualevent_register_view(request,id=0): returnurl = reverse(virtualevent_register_view, kwargs={'id':race.id}) - if age < coursestandard.agemin: + if age < coursestandard.agemin: # pragma: no cover messages.error(request,'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) - if age > coursestandard.agemax: + if age > coursestandard.agemax: # pragma: no cover messages.error(request,'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) - if sex == 'male' and coursestandard.sex != 'male': + if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error(request,'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) - if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: # pragma: no cover messages.error(request,'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) @@ -2135,7 +2135,7 @@ def virtualevent_register_view(request,id=0): # remove followers myfollows = VirtualRaceFollower.objects.filter(user=r.user,race=race) - for f in myfollows: + for f in myfollows: # pragma: no cover f.delete() otherrecords = resultobj.objects.filter( @@ -2155,12 +2155,12 @@ def virtualevent_register_view(request,id=0): race.name, race.id ) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race = race) - for follower in followers: + for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name @@ -2200,7 +2200,7 @@ def virtualevent_register_view(request,id=0): 'sex':sex, 'entrycategory':initialcategory, } - else: + else: # pragma: no cover initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, @@ -2239,16 +2239,16 @@ def virtualevent_register_view(request,id=0): if race_can_register(r,race): buttons += ['registerbutton'] - if race_can_adddiscipline(r,race): + if race_can_adddiscipline(r,race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -2272,7 +2272,7 @@ def virtualevent_toggle_email_view(request,id=0): if True in [record.emailnotifications for record in records]: newsetting = False - else: + else: # pragma: no cover newsetting = True for record in records: @@ -2294,7 +2294,7 @@ def indoorvirtualevent_toggle_email_view(request,id=0): if True in [record.emailnotifications for record in records]: newsetting = False - else: + else: # pragma: no cover newsetting = True for record in records: @@ -2311,11 +2311,11 @@ def indoorvirtualevent_register_view(request,id=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") categories = None - if race.coursestandards is not None: + if race.coursestandards is not None: # pragma: no cover categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") @@ -2354,7 +2354,7 @@ def indoorvirtualevent_register_view(request,id=0): coursestandard = None referencespeed = 5.0 - if race.coursestandards is not None: + if race.coursestandards is not None: # pragma: no cover coursestandard = cd['entrycategory'] referencespeed = coursestandard.referencespeed boatclass = coursestandard.boatclass @@ -2419,7 +2419,7 @@ def indoorvirtualevent_register_view(request,id=0): # remove followers myfollows = VirtualRaceFollower.objects.filter(user=r.user,race=race) - for f in myfollows: + for f in myfollows: # pragma: no cover f.delete() otherrecords = IndoorVirtualRaceResult.objects.filter( @@ -2439,12 +2439,12 @@ def indoorvirtualevent_register_view(request,id=0): race.name, race.id ) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race = race) - for follower in followers: + for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name @@ -2479,7 +2479,7 @@ def indoorvirtualevent_register_view(request,id=0): } categories = None - if race.coursestandards is not None: + if race.coursestandards is not None: # pragma: no cover categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") @@ -2510,16 +2510,16 @@ def indoorvirtualevent_register_view(request,id=0): if race_can_register(r,race): buttons += ['registerbutton'] - if race_can_adddiscipline(r,race): + if race_can_adddiscipline(r,race): # pragma: no cover buttons += ['adddisciplinebutton'] if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -2576,7 +2576,7 @@ def indoorvirtualevent_create_view(request): evaluation_closure.replace(tzinfo=None) ) - if registration_form == 'manual': + if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str @@ -2585,14 +2585,14 @@ def indoorvirtualevent_create_view(request): ) except AttributeError: registration_closure = startdatetime - elif registration_form == 'windowstart': + elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime - elif registration_form == 'windowend': + elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure - if sessionunit == 'min': + if sessionunit == 'min': # pragma: no cover sessionmode = 'time' else: sessionmode = 'distance' @@ -2625,9 +2625,9 @@ def indoorvirtualevent_create_view(request): # create Site Announcement & Tweet if settings.DEBUG or settings.TESTING: dotweet = False - elif 'dev' in settings.SITE_URL: + elif 'dev' in settings.SITE_URL: # pragma: no cover dotweet = False - else: + else: # pragma: no cover dotweet = True announcementshort = "New Virtual Indoor Challenge on rowsandall.com: {name}".format( @@ -2640,7 +2640,7 @@ def indoorvirtualevent_create_view(request): ) - if len(announcement)>250: + if len(announcement)>250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( @@ -2719,7 +2719,7 @@ def fastestvirtualevent_create_view(request): evaluation_closure.replace(tzinfo=None) ) - if registration_form == 'manual': + if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str @@ -2728,14 +2728,14 @@ def fastestvirtualevent_create_view(request): ) except AttributeError: registration_closure = startdatetime - elif registration_form == 'windowstart': + elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime - elif registration_form == 'windowend': + elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure - if sessionunit == 'min': + if sessionunit == 'min': # pragma: no cover sessionmode = 'time' sessiontype = 'fastest_time' else: @@ -2771,9 +2771,9 @@ def fastestvirtualevent_create_view(request): # create Site Announcement & Tweet if settings.DEBUG or settings.TESTING: dotweet = False - elif 'dev' in settings.SITE_URL: + elif 'dev' in settings.SITE_URL: # pragma: no cover dotweet = False - else: + else: # pragma: no cover dotweet = True announcementshort = "New Virtual Challenge on rowsandall.com: {name}".format( @@ -2786,7 +2786,7 @@ def fastestvirtualevent_create_view(request): ) - if len(announcement)>250: + if len(announcement)>250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( @@ -2866,7 +2866,7 @@ def virtualevent_create_view(request): evaluation_closure.replace(tzinfo=None) ) - if registration_form == 'manual': + if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str @@ -2875,9 +2875,9 @@ def virtualevent_create_view(request): ) except AttributeError: registration_closure = startdatetime - elif registration_form == 'windowstart': + elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime - elif registration_form == 'windowend': + elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure @@ -2908,9 +2908,9 @@ def virtualevent_create_view(request): # create Site Announcement & Tweet if settings.DEBUG or settings.TESTING: dotweet = False - elif 'dev' in settings.SITE_URL: + elif 'dev' in settings.SITE_URL: # pragma: no cover dotweet = False - else: + else: # pragma: no cover dotweet = True announcementshort = "New Virtual Challenge on rowsandall.com: {name} on course {course}".format( @@ -2924,7 +2924,7 @@ def virtualevent_create_view(request): ) - if len(announcement)>250: + if len(announcement)>250: # pragma: no cover announcement = announcementshort sa = SiteAnnouncement( @@ -2982,7 +2982,7 @@ def virtualevent_edit_view(request,id=0): enddatetime ) - if timezone.now() > enddatetime: + if timezone.now() > enddatetime: # pragma: no cover messages.error(request,"You cannot edit a race after the end of the race window") url = reverse('virtualevent_view', kwargs={ @@ -2998,7 +2998,7 @@ def virtualevent_edit_view(request,id=0): if res: messages.info(request,message) - else: + else: # pragma: no cover messages.error(request,message) url = reverse('virtualevent_view', @@ -3037,16 +3037,16 @@ def virtualevent_edit_view(request,id=0): if race_can_register(r,race): buttons += ['registerbutton'] - if race_can_adddiscipline(r,race): + if race_can_adddiscipline(r,race): # pragma: no cover buttons += ['adddisciplinebutton'] - if race_can_submit(r,race): + if race_can_submit(r,race): # pragma: no cover buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -3082,7 +3082,7 @@ def indoorvirtualevent_edit_view(request,id=0): enddatetime ) - if timezone.now() > enddatetime: + if timezone.now() > enddatetime: # pragma: no cover messages.error(request,"You cannot edit a race after the end of the race window") url = reverse('virtualevent_view', kwargs={ @@ -3098,7 +3098,7 @@ def indoorvirtualevent_edit_view(request,id=0): if res: messages.info(request,message) - else: + else: # pragma: no cover messages.error(request,message) url = reverse('virtualevent_view', @@ -3138,16 +3138,16 @@ def indoorvirtualevent_edit_view(request,id=0): if race_can_register(r,race): buttons += ['registerbutton'] - if race_can_adddiscipline(r,race): + if race_can_adddiscipline(r,race): # pragma: no cover buttons += ['adddisciplinebutton'] - if race_can_submit(r,race): + if race_can_submit(r,race): # pragma: no cover buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -3172,7 +3172,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") start_time = race.start_time @@ -3197,7 +3197,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): race=race ) - if records.count() == 0: + if records.count() == 0: # pragma: no cover hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,referencespeed,initialcategory = default_class(r,None,race) if not hasinitial: messages.error(request,"Sorry, you have to register first") @@ -3232,7 +3232,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): entries['choices'] = entrychoices entries['initial'] = [records[0].id] - if not can_submit: + if not can_submit: # pragma: no cover messages.error(request,'You cannot submit a result to this race') url = reverse('virtualevent_view', kwargs = { @@ -3248,7 +3248,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): startdatetime__lte=enddatetime, ).order_by("-date","-startdatetime","id") - if not ws: + if not ws: # pragma: no cover messages.info( request, 'You have no workouts executed during the race window. Please upload a result or enter it manually.' @@ -3274,7 +3274,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): for w in ws: wtpl = (w.id, w.__str__()) choices.append(wtpl) - if w.id in initialworkouts: + if w.id in initialworkouts: # pragma: no cover workoutdata['initial'].append(w.id) workoutdata['choices'] = tuple(choices) @@ -3297,7 +3297,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): result,comments,errors,jobid = add_workout_race( workouts,race,r, splitsecond=splitsecond,recordid=recordid) - elif race.sessiontype in ['fastest_time','fastest_distance']: + elif race.sessiontype in ['fastest_time','fastest_distance']: # pragma: no cover result, comments, errors, jobid = add_workout_fastestrace( workouts,race,r,recordid=recordid ) @@ -3339,12 +3339,12 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): race.name, race.id ) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass followers = VirtualRaceFollower.objects.filter(race = race) - for follower in followers: + for follower in followers: # pragma: no cover othername = '' if follower.user: othername = follower.user.first_name+' '+follower.user.last_name @@ -3396,7 +3396,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): buttons = [] if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -3405,10 +3405,10 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): @@ -3429,7 +3429,7 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): def addfollower_view(request,id=0): try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if not request.user.is_anonymous: @@ -3446,7 +3446,7 @@ def addfollower_view(request,id=0): return HttpResponseRedirect(url) # Anonymous - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover form = FollowerForm(request.POST) if form.is_valid(): email = form.cleaned_data['emailaddress'] @@ -3464,7 +3464,7 @@ def addfollower_view(request,id=0): return HttpResponseRedirect(url) - else: + else: # pragma: no cover form = FollowerForm() breadcrumbs = [ @@ -3484,7 +3484,7 @@ def addfollower_view(request,id=0): ), 'name': 'Follow' } - ] + ] # pragma: no cover return render(request,'followerform.html', { @@ -3492,17 +3492,17 @@ def addfollower_view(request,id=0): 'active':'nav-racing', 'breadcrumbs':breadcrumbs, } - ) + ) # pragma: no cover @login_required() def virtualevent_entry_edit_view(request,id=0,entryid=0): r = getrower(request.user) try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") - if not race_can_editentry(r,race): + if not race_can_editentry(r,race): # pragma: no cover messages.error(request,'You cannot change your entries for this challenge') url = reverse('virtualevent_view', kwargs={'id':race.id} @@ -3517,10 +3517,10 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): if race.sessiontype == 'race': resultobj = VirtualRaceResult formobj = VirtualRaceResultForm - elif race.sessiontype in ['fastest_distance','fastest_time']: + elif race.sessiontype in ['fastest_distance','fastest_time']: # pragma: no cover resultobj = IndoorVirtualRaceResult formobj = VirtualRaceResultForm - else: + else: # pragma: no cover resultobj = IndoorVirtualRaceResult formobj = IndoorVirtualRaceResultForm @@ -3531,7 +3531,7 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): try: record = resultobj.objects.get(id=entryid) - except resultobj.DoesNotExist: + except resultobj.DoesNotExist: # pragma: no cover raise Http404("Could not find your entry") if request.method == 'POST': @@ -3543,7 +3543,7 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): teamname = cd['teamname'] try: boattype = cd['boattype'] - except KeyError: + except KeyError: # pragma: no cover boattype = None boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] @@ -3551,13 +3551,13 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): age = cd['age'] try: mix = cd['mix'] - except KeyError: + except KeyError: # pragma: no cover mix = None acceptsocialmedia = cd['acceptsocialmedia'] sex = r.sex - if mix: + if mix: # pragma: no cover sex = 'mixed' if boattype == '1x' and r.birthdate: @@ -3583,26 +3583,26 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): adaptiveclass = coursestandard.adaptiveclass skillclass = coursestandard.skillclass - if age < coursestandard.agemin: + if age < coursestandard.agemin: # pragma: no cover messages.error(request,'You are younger than the minimum age for this group') return HttpResponseRedirect(returnurl) - if age > coursestandard.agemax: + if age > coursestandard.agemax: # pragma: no cover messages.error(request,'You are older than the maximum age for this group') return HttpResponseRedirect(returnurl) - if sex == 'male' and coursestandard.sex != 'male': + if sex == 'male' and coursestandard.sex != 'male': # pragma: no cover messages.error(request,'Men are not allowed to enter this category') return HttpResponseRedirect(returnurl) - if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: # pragma: no cover messages.error(request,'Mixed crews are not allowed to enter this category') return HttpResponseRedirect(returnurl) - if record.workoutid: + if record.workoutid: # pragma: no cover try: w = Workout.objects.get(id=record.workoutid) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover w = None if w is not None: @@ -3632,7 +3632,7 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): messages.error(request,'You cannot change adaptive class to a different one ') return HttpResponseRedirect(returnurl) - if record.points != 0: + if record.points != 0: # pragma: no cover if race.sessiontype == 'race': coursedistance = race.course.distance else: @@ -3657,10 +3657,10 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): duplicates = False for otherrecord in records: - if record.isduplicate(otherrecord): + if record.isduplicate(otherrecord): # pragma: no cover duplicates = True - if duplicates: + if duplicates: # pragma: no cover messages.error(request,"You have already entered this group") return HttpResponseRedirect(returnurl) else: @@ -3703,7 +3703,7 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): buttons = [] if not request.user.is_anonymous: - if race_can_register(r,race): + if race_can_register(r,race): # pragma: no cover buttons += ['registerbutton'] if race_can_adddiscipline(r,race): @@ -3712,10 +3712,10 @@ def virtualevent_entry_edit_view(request,id=0,entryid=0): if race_can_submit(r,race): buttons += ['submitbutton'] - if race_can_resubmit(r,race): + if race_can_resubmit(r,race): # pragma: no cover buttons += ['resubmitbutton'] - if race_can_withdraw(r,race): + if race_can_withdraw(r,race): # pragma: no cover buttons += ['withdrawbutton'] if race_can_edit(r,race): From c278f7b900be059b6773df613da83ba84ce49326 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 21 Apr 2021 08:28:09 +0200 Subject: [PATCH 9/9] changing nk import to async --- rowers/models.py | 350 +++++++++++++-------------- rowers/plannedsessions.py | 44 +--- rowers/templates/nk_list_import.html | 2 +- rowers/tests/test_unit_tests.py | 247 +++++++++++++++++++ 4 files changed, 426 insertions(+), 217 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 1ce31758..f1b367aa 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -109,7 +109,7 @@ def a_week_from_now(): def current_day(): return (datetime.datetime.now(tz=timezone.utc)).date() -def current_time(): +def current_time(): # pragma: no cover return datetime.datetime.now(tz=timezone.utc) @@ -132,7 +132,7 @@ class TemplateListField(models.TextField): self.token = kwargs.pop('token',',') super(TemplateListField, self).__init__(*args, **kwargs) - def to_python(self, value): + def to_python(self, value): # pragma: no cover if not value: return if isinstance(value, list): return value @@ -152,9 +152,9 @@ class TemplateListField(models.TextField): return value.split(self.token) def from_db_value(self,value, expression, connection): - if value is None: + if value is None: # pragma: no cover return value - if isinstance(value, list): + if isinstance(value, list): # pragma: no cover return value return value.split(self.token) @@ -163,7 +163,7 @@ class TemplateListField(models.TextField): assert(isinstance(value, list) or isinstance(value, tuple)) return self.token.join([str(s) for s in value]) - def value_to_string(self, obj): + def value_to_string(self, obj): # pragma: no cover value = self._get_val_from_obj(obj) return self.get_deb_prep_value(value) @@ -173,7 +173,7 @@ class AlternativeEmails(models.TextField): self.token = kwargs.pop('token',',') super(AlternativeEmails, self).__init__(*args,**kwargs) - def to_python(self, value): + def to_python(self, value): # pragma: no cover if not value: return if isinstance(value, list): return value @@ -195,7 +195,7 @@ class AlternativeEmails(models.TextField): def from_db_value(self,value, expression, connection): if value is None: return value - if isinstance(value, list): + if isinstance(value, list): # pragma: no cover return value return value.split(self.token) @@ -208,12 +208,12 @@ class AlternativeEmails(models.TextField): try: validate_email(s) newlist.append(s) - except ValidationError: + except ValidationError: # pragma: no cover pass return self.token.join([str(s) for s in newlist]) - def value_to_string(self, obj): + def value_to_string(self, obj): # pragma: no cover value = self._get_val_from_obj(obj) return self.get_deb_prep_value(value) @@ -222,7 +222,7 @@ class PlannedSessionStepField(models.TextField): def __init__(self, *args, **kwargs): super(PlannedSessionStepField, self).__init__(*args, **kwargs) - def to_python(self, value): + def to_python(self, value): # pragma: no cover if not value: return return json.loads(value) @@ -234,7 +234,7 @@ class PlannedSessionStepField(models.TextField): if not value: return return json.dumps(value) - def value_to_string(self, obj): + def value_to_string(self, obj): # pragma: no cover value = self._get_val_from_obj(obj) return self.get_deb_prep_value(value) @@ -246,7 +246,7 @@ class PowerZonesField(models.TextField): self.token = kwargs.pop('token',',') super(PowerZonesField, self).__init__(*args, **kwargs) - def to_python(self, value): + def to_python(self, value): # pragma: no cover if not value: return if isinstance(value, list): return value @@ -266,9 +266,9 @@ class PowerZonesField(models.TextField): return value.split(self.token) def from_db_value(self,value, expression, connection): - if value is None: + if value is None: # pragma: no cover return value - if isinstance(value, list): + if isinstance(value, list): # pragma: no cover return value return value.split(self.token) @@ -277,7 +277,7 @@ class PowerZonesField(models.TextField): assert(isinstance(value, list) or isinstance(value, tuple)) return self.token.join([str(s) for s in value]) - def value_to_string(self, obj): + def value_to_string(self, obj): # pragma: no cover value = self._get_val_from_obj(obj) return self.get_deb_prep_value(value) @@ -290,7 +290,7 @@ def update_records(url=c2url,verbose=True): df = dfs[0] df.columns = df.columns.str.strip() success = 1 - except: + except: # pragma: no cover df = pd.DataFrame() if not df.empty: @@ -339,11 +339,11 @@ def update_records(url=c2url,verbose=True): name = name, ) try: - if verbose: + if verbose: # pragma: no cover print(record) record.save() except: - if verbose: + if verbose: # pragma: no cover print(record,'*') else: pass @@ -371,7 +371,7 @@ class CalcAgePerformance(models.Model): class Meta: db_table = 'calcagegrouprecords' - def __str_(self): + def __str_(self): # pragma: no cover stri = 'Calculated World Class Performance for {s}, {a}, {d} secs, {p} Watts'.format( s = self.sex, a = self.age, @@ -425,7 +425,7 @@ class C2WorldClassAgePerformance(models.Model): class Meta: unique_together = ('age','sex','weightcategory','distance') - def __str__(self): + def __str__(self): # pragma: no cover thestring = '{s} {w} {n} age {a} ({season}) {distance}m {duration} seconds'.format( s = self.sex, w = self.weightcategory, @@ -560,7 +560,7 @@ def course_spline(coordinates): #lonnew = CubicSpline(t,longitudes,bc_type='not-a-knot')(tnew) latnew = interp1d(t,latitudes)(tnew) lonnew = interp1d(t,longitudes)(tnew) - except ValueError: + except ValueError: # pragma: no cover latnew = latitudes lonnew = longitudes @@ -660,18 +660,18 @@ def get_delta(vector,polygon): if len(df[b==2]): return 1.0e3*df[b==2]['dist'].min() - else: + else: # pragma: no cover return 0 -def get_delta_start(course): +def get_delta_start(course): # pragma: no cover polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course") vector = get_dir_vector(polygons[0],polygons[1]) delta = get_delta(vector,polygons[0]) return delta -def get_delta_finish(course): +def get_delta_finish(course): # pragma: no cover polygons = GeoPolygon.objects.filter(course=course).order_by("-order_in_course") vector = get_dir_vector(polygons[0],polygons[1]) delta = get_delta(vector,polygons[0]) @@ -683,7 +683,7 @@ def course_length(course): totaldist = 0 - if not polygons: + if not polygons: # pragma: no cover return 0 for i in range(polygons.count()-1): @@ -702,7 +702,7 @@ def course_length(course): polygons = polygons.reverse() vector = get_dir_vector(polygons[0],polygons[1]) deltafinish = get_delta(vector,polygons[0]) - except IndexError: + except IndexError: # pragma: no cover deltastart = 0 deltafinish = 0 @@ -767,7 +767,7 @@ class PaidPlan(models.Model): class CoachingGroup(models.Model): name = models.CharField(default='group',max_length=30,null=True,blank=True) - def __str__(self): + def __str__(self): # pragma: no cover return 'Coaching Group {id}: {name}'.format( id = self.pk, name = self.name @@ -1095,7 +1095,7 @@ class Rower(models.Model): def __str__(self): return self.user.first_name+' '+self.user.last_name - def clean_email(self): + def clean_email(self): # pragma: no cover return self.user.email.lower() def save(self, *args, **kwargs): @@ -1103,9 +1103,9 @@ class Rower(models.Model): for group in self.coachinggroups.all(): try: coach = Rower.objects.get(mycoachgroup=group) - if coach.rowerplan == 'freecoach': + if coach.rowerplan == 'freecoach': # pragma: no cover self.coachinggroups.remove(group) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass except ValueError: pass @@ -1121,7 +1121,7 @@ class Rower(models.Model): try: coach = Rower.objects.get(mycoachgroup=group) coaches.append(coach) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass return coaches @@ -1132,13 +1132,13 @@ class Rower(models.Model): rs = Rower.objects.filter(coachinggroups__in=[self.mycoachgroup]) rekwests = CoachOffer.objects.filter(coach=self) - if len(rs)+len(rekwests) < self.clubsize and self.offercoaching: + if len(rs)+len(rekwests) < self.clubsize and self.offercoaching: # pragma: no cover return True return False @property - def ispaid(self): + def ispaid(self): # pragma: no cover return self.rowerplan in ['pro','plan','coach'] class DeactivateUserForm(forms.ModelForm): @@ -1247,7 +1247,7 @@ class FavoriteForm(ModelForm): # To generate favorite chart forms on the fly class BaseFavoriteFormSet(BaseFormSet): - def clean(self): + def clean(self): # pragma: no cover if any(self.errors): return @@ -1296,14 +1296,14 @@ class ConditionEditForm(ModelForm): def clean(self): cd = self.cleaned_data try: - if cd['condition'] == 'between' and cd['value2'] is None: + if cd['condition'] == 'between' and cd['value2'] is None: # pragma: no cover raise forms.ValidationError('When using between, you must fill value 1 and value 2') - except KeyError: + except KeyError: # pragma: no cover pass class BaseConditionFormSet(BaseFormSet): def clean(self): - if any(self.errors): + if any(self.errors): # pragma: no cover return for form in self.forms: @@ -1352,12 +1352,12 @@ class Alert(models.Model): return stri - def metricname(self): + def metricname(self): # pragma: no cover metricdict = {key:value for (key,value) in parchoicesy1} return metricdict[self.measured.metric] - def description(self): + def description(self): # pragma: no cover metricdict = {key:value for (key,value) in parchoicesy1} if self.measured.condition == 'between': @@ -1379,7 +1379,7 @@ class Alert(models.Model): return description - def shortdescription(self): + def shortdescription(self): # pragma: no cover metricdict = {key:value for (key,value) in parchoicesy1} if self.measured.condition == 'between': @@ -1407,7 +1407,7 @@ class AlertEditForm(ModelForm): } class BasePlannedSessionFormSet(BaseFormSet): - def clean(self): + def clean(self): # pragma: no cover if any(self.serrors): return @@ -1432,7 +1432,7 @@ class GeoCourse(models.Model): name = self.name country = self.country d = self.distance - if d == 0: + if d == 0: # pragma: no cover self.distance = course_length(self) self.save() d = self.distance @@ -1462,7 +1462,7 @@ class GeoPolygon(models.Model): course = models.ForeignKey(GeoCourse, blank=True,on_delete=models.CASCADE,related_name='polygons') order_in_course = models.IntegerField(default=0) - def __str__(self): + def __str__(self): # pragma: no cover name = self.name coursename = self.course.name @@ -1504,7 +1504,7 @@ class TrainingTarget(models.Model): try: ownerfirst = self.manager.user.first_name ownerlast = self.manager.user.last_name - except AttributeError: + except AttributeError: # pragma: no cover ownerfirst = '' ownerlast = '' @@ -1525,7 +1525,7 @@ def check_trainingtarget_on_change(sender,**kwargs): if action == 'pre_add': for id in pk_set: rower = Rower.objects.get(id=id) - if not can_plan_user(instance.manager.user,rower): + if not can_plan_user(instance.manager.user,rower): # pragma: no cover raise ValidationError("You cannot add this rower. Not your coachee") m2m_changed.connect(check_trainingtarget_on_change, sender=TrainingTarget.rowers.through) @@ -1548,7 +1548,7 @@ class TrainingTargetForm(ModelForm): except AttributeError: if user: teams = Team.objects.filter(manager=user) - else: + else: # pragma: no cover teams = [] if not teams: @@ -1573,7 +1573,7 @@ class InstantPlan(models.Model): price = models.IntegerField(default=0,verbose_name="Price in EURO") url = models.CharField(max_length=250,blank=True,verbose_name="Link to page with more information") - def __str__(self): + def __str__(self): # pragma: no cover return self.name def save(self, *args, **kwargs): @@ -1647,14 +1647,14 @@ class TrainingPlan(models.Model): def save(self, *args, **kwargs): manager = self.manager - if not can_add_plan(manager.user): + if not can_add_plan(manager.user): # pragma: no cover raise ValidationError( "Basic user cannot have a training plan" ) - if self.enddate < self.startdate: + if self.enddate < self.startdate: # pragma: no cover startdate = self.startdate enddate = self.enddate self.startdate = enddate @@ -1667,7 +1667,7 @@ class TrainingPlan(models.Model): for rower in self.rowers.all(): if can_plan_user(manager.user,rower): self.rowers.add(rower) - else: + else: # pragma: no cover self.rowers.remove(rower) if self.status: @@ -1677,9 +1677,9 @@ class TrainingPlan(models.Model): "-startdate") - for otherplan in otherplans: + for otherplan in otherplans: # pragma: no cover if otherplan.startdate <= self.enddate and otherplan.startdate >= self.startdate: - for rower in self.rowers.all(): + for rower in self.rowers.all(): # pragma: no cover if rower in otherplan.rowers.all(): self.status = False self.save() @@ -1713,7 +1713,7 @@ def check_trainingplan_on_change(sender, **kwargs): if action == 'pre_add': for id in pk_set: rower = Rower.objects.get(id=id) - if not can_plan_user(instance.manager.user,rower): + if not can_plan_user(instance.manager.user,rower): # pragma: no cover raise ValidationError("You cannot add this rower. Not your coachee") m2m_changed.connect(check_trainingplan_on_change, sender=TrainingPlan.rowers.through) @@ -1739,7 +1739,7 @@ class TrainingPlanForm(ModelForm): targetchoices = [(x.id,x) for x in targets] targetchoices.append((None,'---')) self.fields['target'].choices = targetchoices - elif self.instance.pk is not None: + elif self.instance.pk is not None: # pragma: no cover self.fields['target'].queryset = TrainingTarget.objects.filter( manager=self.instance.manager, date__gte=current_day()).order_by("date") @@ -1751,7 +1751,7 @@ class TrainingPlanForm(ModelForm): except AttributeError: if user: teams = Team.objects.filter(manager=user) - else: + else: # pragma: no cover teams = [] if not teams: @@ -1789,7 +1789,7 @@ def createmacrofillers(plan): macr.save() thedate = plan.enddate - while cycles: + while cycles: # pragma: no cover if cycles[0].enddate < thedate: macr = TrainingMacroCycle( plan=plan, @@ -1806,7 +1806,7 @@ def createmacrofillers(plan): plan = plan ).order_by("startdate") - if cycles[0].startdate > plan.startdate: + if cycles[0].startdate > plan.startdate: # pragma: no cover macr = TrainingMacroCycle( plan=plan, startdate = plan.startdate, @@ -1839,7 +1839,7 @@ def createmesofillers(plan): macr.save() thedate = plan.enddate - while cycles: + while cycles: # pragma: no cover if cycles[0].enddate < thedate: macr = TrainingMesoCycle( plan=plan, @@ -1856,7 +1856,7 @@ def createmesofillers(plan): plan = plan ).order_by("startdate") - if cycles[0].startdate > plan.startdate: + if cycles[0].startdate > plan.startdate: # pragma: no cover macr = TrainingMesoCycle( plan=plan, startdate = plan.startdate, @@ -1890,7 +1890,7 @@ def createmicrofillers(plan): macr.save() thedate = plan.enddate - while cycles: + while cycles: # pragma: no cover if cycles[0].enddate < thedate: macr = TrainingMicroCycle( plan=plan, @@ -1908,7 +1908,7 @@ def createmicrofillers(plan): ).order_by("startdate") - if cycles and cycles[0].startdate > plan.startdate: + if cycles and cycles[0].startdate > plan.startdate: # pragma: no cover macr = TrainingMicroCycle( plan=plan, startdate = plan.startdate, @@ -1918,7 +1918,7 @@ def createmicrofillers(plan): ) macr.save() -def microcyclecheckdates(plan): +def microcyclecheckdates(plan): # pragma: no cover cycles = TrainingMicroCycle.objects.filter( plan=plan ).order_by("-startdate") @@ -1950,7 +1950,7 @@ def microcyclecheckdates(plan): pass cycles = cycles[1:] -def mesocyclecheckdates(plan): +def mesocyclecheckdates(plan): # pragma: no cover cycles = TrainingMesoCycle.objects.filter( plan=plan ).order_by("-startdate") @@ -1982,7 +1982,7 @@ def mesocyclecheckdates(plan): pass cycles = cycles[1:] -def macrocyclecheckdates(plan): +def macrocyclecheckdates(plan): # pragma: no cover cycles = TrainingMacroCycle.objects.filter( plan=plan ).order_by("-startdate") @@ -2037,7 +2037,7 @@ class TrainingMacroCycle(models.Model): actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore') actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP') - def __str__(self): + def __str__(self): # pragma: no cover stri = 'Macro Cycle - {n} ({sd} - {ed})'.format( n = self.name, sd = self.startdate, @@ -2047,7 +2047,7 @@ class TrainingMacroCycle(models.Model): return stri def save(self, *args, **kwargs): - if self.enddate < self.startdate: + if self.enddate < self.startdate: # pragma: no cover startdate = self.startdate enddate = self.enddate self.startdate = enddate @@ -2058,16 +2058,16 @@ class TrainingMacroCycle(models.Model): for f in fillers: f.delete() - if self.enddate > self.plan.enddate: + if self.enddate > self.plan.enddate: # pragma: no cover self.enddate = self.plan.enddate - if self.startdate < self.plan.startdate: + if self.startdate < self.plan.startdate: # pragma: no cover self.startdate = self.plan.startdate othercycles = TrainingMacroCycle.objects.filter( plan=self.plan).exclude(pk=self.pk).order_by("-startdate") - for othercycle in othercycles: + for othercycle in othercycles: # pragma: no cover if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate: self.enddate = othercycle.startdate-datetime.timedelta(days=1) @@ -2088,7 +2088,7 @@ class TrainingMacroCycle(models.Model): ) meso.save() - else: + else: # pragma: no cover createmesofillers(self) @@ -2126,7 +2126,7 @@ class TrainingMesoCycle(models.Model): actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP') - def __str__(self): + def __str__(self): # pragma: no cover stri = 'Meso Cycle - {n} ({sd} - {ed})'.format( n = self.name, sd = self.startdate, @@ -2136,7 +2136,7 @@ class TrainingMesoCycle(models.Model): return stri def save(self, *args, **kwargs): - if self.enddate < self.startdate: + if self.enddate < self.startdate: # pragma: no cover startdate = self.startdate enddate = self.enddate self.startdate = enddate @@ -2144,19 +2144,19 @@ class TrainingMesoCycle(models.Model): fillers = TrainingMesoCycle.objects.filter( plan=self.plan,type='filler') - for f in fillers: + for f in fillers: # pragma: no cover f.delete() - if self.enddate > self.plan.enddate: + if self.enddate > self.plan.enddate: # pragma: no cover self.enddate = self.plan.enddate - if self.startdate < self.plan.startdate: + if self.startdate < self.plan.startdate: # pragma: no cover self.startdate = self.plan.startdate othercycles = TrainingMesoCycle.objects.filter( plan=self.plan).exclude(pk=self.pk).order_by("-startdate") - for othercycle in othercycles: + for othercycle in othercycles: # pragma: no cover if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate: self.enddate = othercycle.startdate-datetime.timedelta(days=1) @@ -2176,7 +2176,7 @@ class TrainingMesoCycle(models.Model): ) micro.save() - else: + else: # pragma: no cover createmicrofillers(self) @@ -2205,7 +2205,7 @@ class TrainingMicroCycle(models.Model): - def __str__(self): + def __str__(self): # pragma: no cover stri = 'Micro Cycle - {n} ({sd} - {ed})'.format( n = self.name, sd = self.startdate, @@ -2215,7 +2215,7 @@ class TrainingMicroCycle(models.Model): return stri def save(self, *args, **kwargs): - if self.enddate < self.startdate: + if self.enddate < self.startdate: # pragma: no cover startdate = self.startdate enddate = self.enddate self.startdate = enddate @@ -2223,19 +2223,19 @@ class TrainingMicroCycle(models.Model): fillers = TrainingMicroCycle.objects.filter( plan=self.plan,type='filler') - for f in fillers: + for f in fillers: # pragma: no cover f.delete() - if self.enddate > self.plan.enddate: + if self.enddate > self.plan.enddate: # pragma: no cover self.enddate = self.plan.enddate - if self.startdate < self.plan.startdate: + if self.startdate < self.plan.startdate: # pragma: no cover self.startdate = self.plan.startdate othercycles = TrainingMicroCycle.objects.filter( plan=self.plan).exclude(pk=self.pk).order_by("-startdate") - for othercycle in othercycles: + for othercycle in othercycles: # pragma: no cover if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate: self.enddate = othercycle.startdate-datetime.timedelta(days=1) @@ -2417,7 +2417,7 @@ class PlannedSession(models.Model): return stri - def update_steps(self): + def update_steps(self): # pragma: no cover # read file if self.fitfile: steps = steps_read_fit(settings.MEDIA_ROOT+'/'+self.fitfile.name) @@ -2427,7 +2427,7 @@ class PlannedSession(models.Model): def save(self, *args, **kwargs): - if self.sessionvalue <= 0: + if self.sessionvalue <= 0: # pragma: no cover self.sessionvalue = 1 @@ -2439,7 +2439,7 @@ class PlannedSession(models.Model): ) # interval string - if self.interval_string: + if self.interval_string: # pragma: no cover try: dct = trainingparser.parsetodict(self.interval_string) dct = [item for item in dct if item['value'] != 0] @@ -2458,7 +2458,7 @@ class PlannedSession(models.Model): # sort units if self.sessionmode == 'distance': - if self.sessionunit not in ['m','km']: + if self.sessionunit not in ['m','km']: # pragma: no cover self.sessionunit = 'm' elif self.sessionmode == 'time': self.sessionunit = 'min' @@ -2470,7 +2470,7 @@ class PlannedSession(models.Model): if self.sessionvalue < 100: self.sessionmode = 'time' self.sessionunit = 'min' - else: + else: # pragma: no cover self.sessionmode = 'distance' self.sessionunit = 'm' self.criterium = 'exact' @@ -2478,7 +2478,7 @@ class PlannedSession(models.Model): self.sessionmode = 'distance' self.sessionunit = 'm' self.criterium = 'none' - if self.course == None: + if self.course == None: # pragma: no cover self.course = GeoCourse.objects.all()[0] self.sessionvalue = self.course.distance elif self.sessiontype != 'coursetest' and self.sessiontype != 'race': @@ -2516,7 +2516,7 @@ class PlannedSession(models.Model): self.criterium = 'none' if self.sessionmode == 'time': self.sessionvalue = self.approximate_duration - elif self.sessionmode == 'distance': + elif self.sessionmode == 'distance': # pragma: no cover self.sessionvalue = self.approximate_distance @@ -2525,7 +2525,7 @@ class PlannedSession(models.Model): @receiver(models.signals.post_delete,sender=PlannedSession) def auto_delete_fitfile_on_delete(sender, instance, **kwargs): # delete CSV file - if instance.fitfile: + if instance.fitfile: # pragma: no cover filename = os.path.join(settings.MEDIA_ROOT,instance.fitfile.name) if os.path.isfile(filename): os.remove(filename) @@ -2635,7 +2635,7 @@ class VirtualRace(PlannedSession): enddatetime ) - if startdatetime > enddatetime: + if startdatetime > enddatetime: # pragma: no cover self.start_time = end_time self.startdate = end_date self.end_time = start_time @@ -2643,7 +2643,7 @@ class VirtualRace(PlannedSession): enddatetime = startdatetime - if self.evaluation_closure < enddatetime: + if self.evaluation_closure < enddatetime: # pragma: no cover self.evaluation_closure = enddatetime + timezone.timedelta(days=1) super(VirtualRace,self).save(*args, **kwargs) @@ -2656,12 +2656,12 @@ class RaceLogo(models.Model): height = models.IntegerField(default=600) race = models.ManyToManyField(VirtualRace,related_name='logos') - def __str__(self): + def __str__(self): # pragma: no cover return self.filename - def delete(self, *args, **kwargs): + def delete(self, *args, **kwargs): # pragma: no cover os.remove(self.filename) - print('file deleted') + super(RaceLogo,self).delete(*args, **kwargs) # Date input utility @@ -2768,10 +2768,10 @@ def get_course_timezone(course): tf = TimezoneFinder() try: timezone_str = tf.timezone_at(lng=lon,lat=lat) - except ValueError: + except ValueError: # pragma: no cover timezone_str = 'UTC' - if timezone_str is None: + if timezone_str is None: # pragma: no cover timezone_str = tf.closest_timezone_at(lng=lon,lat=lat) if timezone_str is None: timezone_str = 'UTC' @@ -2841,15 +2841,15 @@ class IndoorVirtualRaceForm(ModelForm): timezone_str = cd['timezone'] value = cd['sessionvalue'] - if value <= 0: + if value <= 0: # pragma: no cover raise forms.ValidationError('The Value must be a positive, non-zero value') unit = cd['sessionunit'] - if unit == 'm' and value < 100: + if unit == 'm' and value < 100: # pragma: no cover raise forms.ValidationError('Minimum distance is 100m') start_time = cd['start_time'] - if start_time is None: + if start_time is None: # pragma: no cover raise forms.ValidationError( 'Must have start time', code='missing_yparam1' @@ -2862,7 +2862,7 @@ class IndoorVirtualRaceForm(ModelForm): ) end_time = cd['end_time'] - if end_time is None: + if end_time is None: # pragma: no cover raise forms.ValidationError( 'Must have end time', code='missing endtime' @@ -2880,11 +2880,11 @@ class IndoorVirtualRaceForm(ModelForm): try: evaluation_closure = cd['evaluation_closure'] - except KeyError: + except KeyError: # pragma: no cover evaluation_closure = enddatetime+datetime.timedelta(days=1) cd['evaluation_closure'] = evaluation_closure - if registration_form == 'manual': + if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str @@ -2893,26 +2893,26 @@ class IndoorVirtualRaceForm(ModelForm): ) except AttributeError: registration_closure = startdatetime - elif registration_form == 'windowstart': + elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime - elif registration_form == 'windowend': + elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure - if registration_closure <= timezone.now(): + if registration_closure <= timezone.now(): # pragma: no cover raise forms.ValidationError("Registration Closure cannot be in the past") - if startdatetime > enddatetime: + if startdatetime > enddatetime: # pragma: no cover raise forms.ValidationError("The Start of the challenge Window should be before the End of the challenge Window") - if cd['evaluation_closure'] <= enddatetime: + if cd['evaluation_closure'] <= enddatetime: # pragma: no cover raise forms.ValidationError("Evaluation closure deadline should be after the challenge Window closes") - if cd['evaluation_closure'] <= timezone.now(): + if cd['evaluation_closure'] <= timezone.now(): # pragma: no cover raise forms.ValidationError("Evaluation closure cannot be in the past") @@ -2974,7 +2974,7 @@ class VirtualRaceForm(ModelForm): timezone_str = get_course_timezone(geocourse) start_time = cd['start_time'] - if start_time is None: + if start_time is None: # pragma: no cover raise forms.ValidationError( 'Must have start time', code='missing_yparam1' @@ -2988,14 +2988,14 @@ class VirtualRaceForm(ModelForm): try: end_time = cd['end_time'] - except KeyError: + except KeyError: # pragma: no cover raise forms.ValidationError( 'Must have end time', code='missing endtime' ) - if end_time is None: + if end_time is None: # pragma: no cover raise forms.ValidationError( 'Must have end time', code='missing endtime' @@ -3003,7 +3003,7 @@ class VirtualRaceForm(ModelForm): try: end_date = cd['enddate'] - except KeyError: + except KeyError: # pragma: no cover raise forms.ValidationError( 'Missing or invalid end date', code='missing end date' @@ -3018,7 +3018,7 @@ class VirtualRaceForm(ModelForm): try: registration_closure = cd['registration_closure'] - except KeyError: + except KeyError: # pragma: no cover registration_closure = enddatetime+datetime.timedelta(days=1) cd['registration_closure'] = registration_closure @@ -3026,11 +3026,11 @@ class VirtualRaceForm(ModelForm): try: evaluation_closure = cd['evaluation_closure'] - except KeyError: + except KeyError: # pragma: no cover evaluation_closure = enddatetime+datetime.timedelta(days=1) cd['evaluation_closure'] = evaluation_closure - if registration_form == 'manual': + if registration_form == 'manual': # pragma: no cover try: registration_closure = pytz.timezone( timezone_str @@ -3039,26 +3039,26 @@ class VirtualRaceForm(ModelForm): ) except AttributeError: registration_closure = startdatetime - elif registration_form == 'windowstart': + elif registration_form == 'windowstart': # pragma: no cover registration_closure = startdatetime - elif registration_form == 'windowend': + elif registration_form == 'windowend': # pragma: no cover registration_closure = enddatetime else: registration_closure = evaluation_closure - if registration_closure <= timezone.now(): + if registration_closure <= timezone.now(): # pragma: no cover raise forms.ValidationError("Registration Closure cannot be in the past") - if startdatetime > enddatetime: + if startdatetime > enddatetime: # pragma: no cover raise forms.ValidationError("The Start of the challenge Window should be before the End of the challenge Window") - if cd['evaluation_closure'] <= enddatetime: + if cd['evaluation_closure'] <= enddatetime: # pragma: no cover raise forms.ValidationError("Evaluation closure deadline should be after the challenge Window closes") - if cd['evaluation_closure'] <= timezone.now(): + if cd['evaluation_closure'] <= timezone.now(): # pragma: no cover raise forms.ValidationError("Evaluation closure cannot be in the past") @@ -3218,7 +3218,7 @@ class Workout(models.Model): def save(self, *args, **kwargs): user = self.user - if self.notes is not None and len(self.notes)>1000: + if self.notes is not None and len(self.notes)>1000: # pragma: no cover self.notes = self.notes[0:950] if not can_add_workout(user.user): raise forms.ValidationError("Free Coach User cannot have any workouts") @@ -3319,7 +3319,7 @@ def update_duplicates_on_delete(sender, instance, **kwargs): user=instance.user,date=instance.date, duplicate=True) - for d in duplicates: + for d in duplicates: # pragma: no cover t = d.duration delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second) workoutenddatetime = d.startdatetime+delta @@ -3421,7 +3421,7 @@ class VirtualRaceResult(models.Model): acceptsocialmedia = models.BooleanField(default=True, verbose_name = 'I agree with sharing my name in challenge related social media posts (unchecking this does not prevent you from participation)') - def isduplicate(self,other): + def isduplicate(self,other): # pragma: no cover if self.userid != other.userid: return False if self.weightcategory != other.weightcategory: @@ -3472,7 +3472,7 @@ class VirtualRaceResult(models.Model): t = self.teamname, s = self.sex, ) - else: + else: # pragma: no cover if self.entrycategory: return u'Entry for {n} for "{r}" in {g}'.format( n = name, @@ -3535,7 +3535,7 @@ class IndoorVirtualRaceResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) - def isduplicate(self,other): + def isduplicate(self,other): # pragma: no cover if self.userid != other.userid: return False if self.weightcategory != other.weightcategory: @@ -3567,7 +3567,7 @@ class IndoorVirtualRaceResult(models.Model): u2 = rr.user.last_name, ) if self.teamname: - if self.entrycategory: + if self.entrycategory: # pragma: no cover return u'Entry for {n} for "{r}" in {g} with {t}'.format( n = name, r = self.race, @@ -3581,7 +3581,7 @@ class IndoorVirtualRaceResult(models.Model): c = self.boatclass, s = self.sex, ) - else: + else: # pragma: no cover if self.entrycategory: return u'Entry for {n} for "{r}" in {g}'.format( n = name, @@ -3618,7 +3618,7 @@ class IndoorVirtualRaceResultForm(ModelForm): def __init__(self, *args, **kwargs): categories = kwargs.pop('categories',None) super(IndoorVirtualRaceResultForm, self).__init__(*args, **kwargs) - if categories is not None: + if categories is not None: # pragma: no cover self.fields['entrycategory'].queryset = categories self.fields['entrycategory'].empty_label = None else: @@ -3638,7 +3638,7 @@ class VirtualRaceResultForm(ModelForm): categories = kwargs.pop('categories',None) super(VirtualRaceResultForm, self).__init__(*args, **kwargs) - if boattypes: + if boattypes: # pragma: no cover self.fields['boattype'].choices = boattypes self.fields['mix'] = forms.BooleanField(initial=False, @@ -3757,7 +3757,7 @@ class GraphImage(models.Model): width = models.IntegerField(default=1200) height = models.IntegerField(default=600) - def __str__(self): + def __str__(self): # pragma: no cover return self.filename @@ -3765,7 +3765,7 @@ class GraphImage(models.Model): @receiver(models.signals.post_delete,sender=GraphImage) def auto_delete_image_on_delete(sender,instance, **kwargs): if instance.filename: - if os.path.isfile(instance.filename): + if os.path.isfile(instance.filename): # pragma: no cover others = GraphImage.objects.filter(filename=instance.filename) if others.count() == 0: os.remove(instance.filename) @@ -3817,7 +3817,7 @@ class WorkoutForm(ModelForm): if 'instance' in kwargs: if kwargs['instance'].privacy == 'visible': self.fields['private'].initial = False - else: + else: # pragma: no cover self.fields['private'].initial = True workout = self.instance @@ -3830,7 +3830,7 @@ class WorkoutForm(ModelForm): if not sps: del self.fields['plannedsession'] - else: + else: # pragma: no cover self.fields['plannedsession'].queryset = sps else: del self.fields['plannedsession'] @@ -3907,7 +3907,7 @@ class RowerHRZonesForm(ModelForm): model = Rower fields = ['rest','ut2','ut1','at','tr','an','max'] - def clean(self): + def clean(self): # pragma: no cover cleaned_data = super(RowerHRZonesForm, self).clean() try: @@ -4064,7 +4064,7 @@ class RowerPowerZonesForm(ModelForm): model = Rower fields = ['pw_ut2','pw_ut1','pw_at','pw_tr','pw_an'] - def clean(self): + def clean(self): # pragma: no cover cleaned_data = super(RowerPowerZonesForm, self).clean() try: @@ -4257,7 +4257,7 @@ class AccountRowerForm(ModelForm): z = "".join(cd['emailalternatives'].split()).split(',') emailalternatives = [] for addr in z: - try: + try: # pragma: no cover validate_email(addr) match = User.objects.filter(email__iexact=addr) if match.count() == 0: @@ -4293,14 +4293,14 @@ class UserForm(ModelForm): if len(first_name): return first_name - raise forms.ValidationError('Please fill in your first name') + raise forms.ValidationError('Please fill in your first name') # pragma: no cover def clean_email(self): email = self.cleaned_data.get('email') try: validate_email(email) - except ValidationError: + except ValidationError: # pragma: no cover raise forms.ValidationError( 'Please enter a valid email address') @@ -4308,10 +4308,10 @@ class UserForm(ModelForm): match = User.objects.filter(email__iexact=email).exclude(id=self.instance.id) if match.count() == 0: return email - except User.DoesNotExist: + except User.DoesNotExist: # pragma: no cover return email - raise forms.ValidationError('This email address is not allowed') + raise forms.ValidationError('This email address is not allowed') # pragma: no cover # Form to set rower's Heart Rate zones, including test routines @@ -4330,7 +4330,7 @@ class RowerForm(ModelForm): raise forms.ValidationError("Resting heart rate should be higher than 10 bpm") - if rest>250: + if rest>250: # pragma: no cover self.data['rest'] = 250 raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") @@ -4340,10 +4340,10 @@ class RowerForm(ModelForm): def clean_ut2(self): ut2 = self.cleaned_data['ut2'] - if ut2<10: + if ut2<10: # pragma: no cover raise forms.ValidationError("UT2 heart rate should be higher than 10 bpm") - if ut2>250: + if ut2>250: # pragma: no cover raise forms.ValidationError("UT2 heart rate should be lower than 250 bpm") return ut2 @@ -4351,10 +4351,10 @@ class RowerForm(ModelForm): def clean_ut1(self): ut1 = self.cleaned_data['ut1'] - if ut1<10: + if ut1<10: # pragma: no cover raise forms.ValidationError("UT1 heart rate should be higher than 10 bpm") - if ut1>250: + if ut1>250: # pragma: no cover raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") return ut1 @@ -4362,10 +4362,10 @@ class RowerForm(ModelForm): def clean_at(self): at = self.cleaned_data['at'] - if at<10: + if at<10: # pragma: no cover raise forms.ValidationError("AT heart rate should be higher than 10 bpm") - if at>250: + if at>250: # pragma: no cover raise forms.ValidationError("AT heart rate should be lower than 250 bpm") return at @@ -4373,10 +4373,10 @@ class RowerForm(ModelForm): def clean_tr(self): tr = self.cleaned_data['tr'] - if tr<10: + if tr<10: # pragma: no cover raise forms.ValidationError("TR heart rate should be higher than 10 bpm") - if tr>250: + if tr>250: # pragma: no cover raise forms.ValidationError("TR heart rate should be lower than 250 bpm") return tr @@ -4384,10 +4384,10 @@ class RowerForm(ModelForm): def clean_an(self): an = self.cleaned_data['an'] - if an<10: + if an<10: # pragma: no cover raise forms.ValidationError("AN heart rate should be higher than 10 bpm") - if an>250: + if an>250: # pragma: no cover raise forms.ValidationError("AN heart rate should be lower than 250 bpm") return an @@ -4395,10 +4395,10 @@ class RowerForm(ModelForm): def clean_max(self): max = int(self.cleaned_data['max']) - if max<10: + if max<10: # pragma: no cover raise forms.ValidationError("Max heart rate should be higher than 10 bpm") - if max>250: + if max>250: # pragma: no cover raise forms.ValidationError("Max heart rate should be lower than 250 bpm") return max @@ -4412,12 +4412,12 @@ class RowerForm(ModelForm): except: try: rest = int(self.data['rest']) - except ValueError: + except ValueError: # pragma: no cover rest = 0 try: ut2 = self.cleaned_data['ut2'] - except: + except: # pragma: no cover try: ut2 = int(self.data['ut2']) except ValueError: @@ -4425,7 +4425,7 @@ class RowerForm(ModelForm): try: ut1 = self.cleaned_data['ut1'] - except: + except: # pragma: no cover try: ut1 = int(self.data['ut1']) except ValueError: @@ -4433,15 +4433,15 @@ class RowerForm(ModelForm): try: at = self.cleaned_data['at'] - except: + except: # pragma: no cover try: at = int(self.data['at']) except ValueError: at = 0 - try: + try: # pragma: no cover an = self.cleaned_data['an'] - except: + except: # pragma: no cover try: an = int(self.data['an']) except ValueError: @@ -4449,7 +4449,7 @@ class RowerForm(ModelForm): try: tr = self.cleaned_data['tr'] - except: + except: # pragma: no cover try: tr = int(self.data['tr']) except ValueError: @@ -4457,7 +4457,7 @@ class RowerForm(ModelForm): try: max = self.cleaned_data['max'] - except: + except: # pragma: no cover try: max = int(self.data['max']) except ValueError: @@ -4467,15 +4467,15 @@ class RowerForm(ModelForm): raise forms.ValidationError("Resting heart rate should be lower than UT2") if ut2>=ut1: raise forms.ValidationError("UT2 should be lower than UT1") - if ut2>=ut1: + if ut2>=ut1: # pragma: no cover raise forms.ValidationError("UT2 should be lower than UT1") - if ut1>=at: + if ut1>=at: # pragma: no cover raise forms.ValidationError("UT1 should be lower than AT") - if at>=tr: + if at>=tr: # pragma: no cover raise forms.ValidationError("AT should be lower than TR") - if tr>=an: + if tr>=an: # pragma: no cover raise forms.ValidationError("TR should be lower than AN") - if an>=max: + if an>=max: # pragma: no cover raise forms.ValidationError("AN should be lower than Max") @@ -4493,7 +4493,7 @@ class SiteAnnouncement(models.Model): self.created = timezone.now() self.expires = timezone.now()+datetime.timedelta(days=10) self.modified = timezone.now() - if self.dotweet: + if self.dotweet: # pragma: no cover try: status = tweetapi.PostUpdate(self.announcement) except: @@ -4513,7 +4513,7 @@ class WorkoutComment(models.Model): user = models.ForeignKey(User,on_delete=models.PROTECT) workout = models.ForeignKey(Workout,on_delete=models.CASCADE) - def __str__(self): + def __str__(self): # pragma: no cover return u'Comment to: {w} by {u1} {u2}'.format( w=self.workout, u1 = self.user.first_name, @@ -4540,7 +4540,7 @@ class PlannedSessionComment(models.Model): plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE) - def __str__(self): + def __str__(self): # pragma: no cover return u'Comment to: {w} by {u1} {u2}'.format( w=self.workout, u1 = self.user.first_name, @@ -4574,7 +4574,7 @@ class VideoAnalysis(models.Model): class Meta: unique_together = ('video_id','workout') - def __str__(self): + def __str__(self): # pragma: no cover return self.name @@ -4587,9 +4587,9 @@ class ShareKey(models.Model): @property - def expired(self): + def expired(self): # pragma: no cover return self.creation_date + datetime.timedelta(self.expiration_seconds) < timezone.now() @property - def expiration_date(self): + def expiration_date(self): # pragma: no cover return self.creation_date + datetime.timedelta(self.expiration_seconds) diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 176d8cc9..434f0418 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -50,7 +50,7 @@ def to_time(milliseconds): def rdata(file,rower=rrower()): try: res = rrdata(csvfile=file,rower=rower) - except (IOError, IndexError, EOFError,FileNotFoundError): + except (IOError, IndexError, EOFError,FileNotFoundError): # pragma: no cover try: res = rrdata(csvfile=file+'.gz',rower=rower) except (IOError, IndexError, EOFError,FileNotFoundError): @@ -85,16 +85,7 @@ from rowers.tasks import ( ) from rowers.utils import totaltime_sec_to_string -# nog niet af -def ps_dict_get_durationdistance(d): - sdict = ps_dict_order(d) - return sdict - - - - - -def ps_dict_get_description(d,short=False): +def ps_dict_get_description(d,short=False): # pragma: no cover sdict,totalmeters,totalseconds = ps_dict_order(d,short=short) s = '' for item in sdict: @@ -115,35 +106,6 @@ def ps_dict_get_description_html(d,short=False): return s - -class FitWorkoutSteps(object): - def __init__(self,json_string,name='',sport='Custom'): - self.json = json_string - self.steps = json.loads(json_string) - - self.name = name - self.sport = sport - # message 0 is file id - # message 1 must be workout description - - def to_json(self): - d = self.get_dict() - - return json.dumps(d) - - def get_dict(self): - return self.steps - - - def get_description(self): - s = '' - for step in self.steps: - s += step_to_string(step) - s += '\n' - - return s - - def checkscores(r,macrocycles): for m in macrocycles: createmesofillers(m) @@ -246,7 +208,7 @@ def get_execution_report(rower,startdate,enddate,plan=None): mesos = TrainingMesoCycle.objects.filter(plan__in=macros).order_by("startdate") micros = TrainingMicroCycle.objects.filter(plan__in=mesos).order_by("startdate") micros = micros.exclude(enddate__lte=startdate).exclude(startdate__gte=enddate) - else: + else: # pragma: no cover plans = TrainingPlan.objects.filter(startdate__lte=startdate,enddate__gte=startdate) plans2 = TrainingPlan.objects.filter(enddate__lte=enddate,startdate__lte=enddate) plans = plans | plans2 diff --git a/rowers/templates/nk_list_import.html b/rowers/templates/nk_list_import.html index e97d711b..0c5f4505 100644 --- a/rowers/templates/nk_list_import.html +++ b/rowers/templates/nk_list_import.html @@ -33,7 +33,7 @@ {% for workout in workouts %} - Import + Import {{ workout|lookuplong:'name' }} {{ workout|lookuplong:'starttime' }} {{ workout|lookup:'duration' }} diff --git a/rowers/tests/test_unit_tests.py b/rowers/tests/test_unit_tests.py index b481530e..11cf5a61 100644 --- a/rowers/tests/test_unit_tests.py +++ b/rowers/tests/test_unit_tests.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from .statements import * from rowers.mytypes import rowtypes +from rowers.utils import allmonths,allsundays nu = datetime.datetime.now() @@ -12,8 +13,11 @@ nu = datetime.datetime.now() # interactive plots from rowers import interactiveplots from rowers import dataprep +from rowers import plannedsessions from rowers.views.workoutviews import get_video_id + + class OtherUnitTests(TestCase): def test_get_video_id(self): url1 = 'http://youtu.be/_lOT2p_FCvA' @@ -49,6 +53,249 @@ class OtherUnitTests(TestCase): self.assertEqual(result,expected) +class PlannedSessionTests(TestCase): + def setUp(self): + self.u = UserFactory() + + self.r = Rower.objects.create(user=self.u, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='coach') + + self.c = Client() + self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + self.factory = RequestFactory() + self.password = faker.word() + self.u.set_password(self.password) + self.u.save() + + self.u2 = UserFactory(username='testbasicuser') + self.r2 = Rower.objects.create(user=self.u2, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='basic') + + self.password2 = faker.word() + self.u2.set_password(self.password2) + self.u2.save() + + self.team = Team.objects.create( + name = faker.word(), + notes = faker.text(), + manager = self.u, + ) + + self.team.save() + + self.r.team.add(self.team) + self.r2.team.add(self.team) + self.r.save() + self.r2.save() + + + result = get_random_file(filename='rowers/tests/testdata/2019-01-13_session.csv',name='sprintervals') + + + self.factory = RequestFactory() + self.password = faker.word() + self.u.set_password(self.password) + self.u.save() + + self.w1 = Workout.objects.create( + name='sprintervals', + notes=faker.text(), + startdatetime = result['startdatetime'], + starttime = result['starttime'], + workouttype='rower', + date=result['date'], + duration=result['duration'], + distance=result['totaldist'], + csvfilename=result['filename'], + trimp = 77, + rscore = 69, + hrtss = 43, + normp = 236, + user=self.r, + ) + + # plan + self.target = TrainingTarget.objects.create( + name = faker.word(), + manager = self.u.rower, + notes = faker.text() + ) + self.target.rowers.add(self.u.rower) + self.target.save() + + self.plan = TrainingPlan.objects.create( + manager = self.u.rower, + name = faker.word(), + status=True, + target = self.target, + startdate=timezone.now().date(), + enddate = self.target.date, + ) + + self.plan.rowers.add(self.u.rower) + self.plan.save() + + # cycles + self.macro = TrainingMacroCycle.objects.create( + plan=self.plan, + name=faker.word(), + type='userdefined', + notes = faker.text(), + startdate = self.plan.startdate, + enddate = self.plan.enddate, + ) + + mesos = TrainingMesoCycle.objects.filter(plan=self.macro) + for m in mesos: + m.delete() + + monthstarts = [d for d in allmonths(self.macro.startdate,self.macro.enddate)] + monthstarts.append(self.macro.enddate) + + for i in range(len(monthstarts)-1): + firstday = monthstarts[i] + lastday = monthstarts[i+1]-datetime.timedelta(days=1) + if lastday < self.macro.enddate and i == len(monthstarts)-2: + lastday = self.macro.enddate + + meso = TrainingMesoCycle(startdate=firstday, + enddate=lastday, + plan=self.macro, + name = '%s' % firstday.strftime("%B"), + type = 'userdefined') + meso.save() + + mesos = TrainingMesoCycle.objects.filter(plan=self.macro) + + for cycle in mesos: + micros = TrainingMicroCycle.objects.filter(plan=cycle) + for m in micros: + m.delete() + + sundays = [s for s in allsundays(cycle.startdate,cycle.enddate)] + + if sundays and sundays[-1] < cycle.enddate: + sundays = sundays+[cycle.enddate] + elif not sundays: + sundays = [cycle.enddate] + + for i in range(len(sundays)): + if i==0: + monday = cycle.startdate + else: + monday = sundays[i]-datetime.timedelta(days=6) + if monday < cycle.startdate: + monday = cycle.startdate + + nextsunday = sundays[i] + + micro = TrainingMicroCycle(startdate=monday, + enddate=nextsunday, + plan=cycle, + name = 'Week %s' % monday.isocalendar()[1], + type='userdefined') + micro.save() + + + # sessions + startdatetime = self.w1.startdatetime + + startdate = (startdatetime-datetime.timedelta(days=1)).date() + enddate = (startdatetime+datetime.timedelta(days=1)).date() + preferreddate = startdatetime.date() + + self.startdate = startdate + self.enddate = enddate + + self.ps_rscore = SessionFactory( + startdate=startdate,enddate=enddate, + sessiontype='test', + sessionmode = 'rScore', + criterium = 'none', + sessionvalue = 69, + sessionunit='None', + preferreddate=preferreddate, + manager=self.u, + ) + + + self.ps_rscore.save() + added = plannedsessions.add_rower_session(self.u.rower,self.ps_rscore) + + self.ps_dist = SessionFactory( + startdate=startdate,enddate=enddate, + sessiontype='test', + sessionmode = 'distance', + criterium = 'none', + sessionvalue = result['totaldist'], + sessionunit='m', + preferreddate=preferreddate, + manager=self.u, + ) + + + self.ps_dist.save() + added = plannedsessions.add_rower_session(self.u.rower,self.ps_dist) + + self.ps_time = SessionFactory( + startdate=startdate,enddate=enddate, + sessiontype='test', + sessionmode = 'time', + criterium = 'none', + sessionvalue = 38, + sessionunit='min', + preferreddate=preferreddate, + manager=self.u, + ) + + + self.ps_time.save() + added = plannedsessions.add_rower_session(self.u.rower,self.ps_time) + + self.ps_trimp = SessionFactory( + startdate=startdate,enddate=enddate, + sessiontype='test', + sessionmode = 'TRIMP', + criterium = 'none', + sessionvalue = 77, + sessionunit='none', + preferreddate=preferreddate, + manager=self.u, + ) + + + self.ps_trimp.save() + added = plannedsessions.add_rower_session(self.u.rower,self.ps_trimp) + added = plannedsessions.add_team_session(self.team,self.ps_trimp) + self.ps_trimp.save() + + + def tearDown(self): + pass + + def test_to_time(self): + calculatedTime = plannedsessions.to_time(8100000) + expectedTime = datetime.time(2,15,0,0) + + def test_checkscores(self): + macrocycles = TrainingMacroCycle.objects.filter(plan=self.plan) + plannedsessions.checkscores(self.r,macrocycles) + + def test_executionreport(self): + data, ok = plannedsessions.get_execution_report(self.r,self.plan.startdate,self.plan.enddate) + self.assertEqual(ok,'ok') + + def test_todays_micro(self): + micro1 = plannedsessions.get_todays_micro(self.plan) + micro2 = plannedsessions.get_todays_micro(self.plan,thedate=datetime.date.today()) + self.assertEqual(micro1.id,micro2.id) + class DataPrepTests(TestCase): def setUp(self): self.u = UserFactory()