diff --git a/rowers/courses.py b/rowers/courses.py index 060d15ae..fb2f60c4 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -80,11 +80,14 @@ def getnearestcourses(lat_lon, courses, whatisnear=150, strict=False): newlist = [] counter = 0 for c in courses: - distance = howfaris(lat_lon, c) + try: + distance = howfaris(lat_lon, c) - if distance < whatisnear: - newlist.append(c) - counter += 1 + if distance < whatisnear: + newlist.append(c) + counter += 1 + except TypeError: + pass if counter > 0: courses = newlist diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 562ded65..af49c155 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -17,6 +17,7 @@ import rowers.c2stuff as c2stuff import rowers.metrics as metrics import rowers.dataprep as dataprep from rowers.dataprep import rdata +from rowers.dataroutines import remove_nulls_pl import rowers.utils as utils import polars as pl import pytz @@ -1205,6 +1206,7 @@ def forcecurve_multi_interactive_chart(selected): # pragma: no cover rowdata = dataprep.read_data(columns, ids=workoutids, workstrokesonly=False) + rowdata = remove_nulls_pl(rowdata) rowdata = rowdata.fill_nan(None).drop_nulls() if rowdata.is_empty(): @@ -1225,7 +1227,7 @@ def forcecurve_multi_interactive_chart(selected): # pragma: no cover 'forcecurve_analyses': selected_dict, } - script, div = get_chart("/forcecurve_compare", chart_data) + script, div = get_chart("/forcecurve_compare", chart_data, debug=False) return script, div @@ -2224,11 +2226,11 @@ def get_zones_report_pl(rower, startdate, enddate, trainingzones='hr', date_agg= pw_tr = rower.pw_tr pw_an = rower.pw_an if iswater: - pw_ut2 = pw_ut2*rower.otwslack/100. - pw_ut1 = pw_ut1*rower.otwslack/100. - pw_at = pw_at*rower.otwslack/100. - pw_tr = pw_tr*rower.otwslack/100. - pw_an = pw_an*rower.otwslack/100. + pw_ut2 = pw_ut2*(100.-rower.otwslack)/100. + pw_ut1 = pw_ut1*(100.-rower.otwslack)/100. + pw_at = pw_at*(100.-rower.otwslack)/100. + pw_tr = pw_tr*(100.-rower.otwslack)/100. + pw_an = pw_an*(100.-rower.otwslack)/100. # 1 time_ut2 = df.filter( diff --git a/rowers/nkimportutils.py b/rowers/nkimportutils.py index 2ea5b0eb..2b398e75 100644 --- a/rowers/nkimportutils.py +++ b/rowers/nkimportutils.py @@ -175,6 +175,9 @@ def get_nk_intervalstats(workoutdata, strokedata): spm = interval['avgStrokeRate'] dps = interval['distStrokeGps'] + if pwr is None: + pwr = 0 + stri += "{i:0>2}{sep}{sdist:0>5}{sep}{split}{sep}{space}{sep} {pwr:0>3} {sep}".format( i=i + 1, sdist=int(float(sdist)), diff --git a/rowers/tasks.py b/rowers/tasks.py index bb4f04bd..d8e7716c 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2163,7 +2163,10 @@ def handle_sendemail_hard(workoutid, useremail, debug=False, **kwargs): btvalues = pd.read_json(btvalues) - btvalues.sort_values('delta', axis=0, inplace=True) + try: + btvalues.sort_values('delta', axis=0, inplace=True) + except KeyError: + return 0 tablevalues = [ {'delta': t.delta, @@ -3993,7 +3996,11 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid, df.sort('TimeStamp (sec)') row = rowingdata.rowingdata_pl(df=df) - row.write_csv(csvfilename, compressed=False) + try: + row.write_csv(csvfilename, compressed=False) + except ComputeError: + row = rowingdata.rowingdata(df=df) + row.write_csv(csvfilename, compressed=False) # summary = row.allstats() # maxdist = df['cum_dist'].max() diff --git a/rowers/templates/user_analysis_select.html b/rowers/templates/user_analysis_select.html index 840f799b..853039d7 100644 --- a/rowers/templates/user_analysis_select.html +++ b/rowers/templates/user_analysis_select.html @@ -389,14 +389,14 @@ -
-
  • {{ the_div|safe }}
    +
    +
  • You can use the date and search forms to search through all diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 47f64ae6..d2b1f440 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -109,6 +109,20 @@ from rowers.opaque import encoder import inspect + + +class MyTestCase(TestCase): + def setUp(self): + self.osm_mock = patch('something') + self.osm_mock.return_value = "" + super(MyTestCase, self).setUp() + self.osm_mock.start() + + def tearDown(self): + super(MyTestCase, self).tearDown() + self.osm_mock.stop() + + def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''): frm = inspect.stack()[3] diff --git a/rowers/tests/test_aavirtualevents.py b/rowers/tests/test_aavirtualevents.py index c1cbc2f6..e58e5861 100644 --- a/rowers/tests/test_aavirtualevents.py +++ b/rowers/tests/test_aavirtualevents.py @@ -13,7 +13,7 @@ import rowers.courses as courses import rowers.plannedsessions as plannedsessions @override_settings(TESTING=True) -class VirtualEventViewTest(TestCase): +class VirtualEventViewTest(MyTestCase): def setUp(self): # Main User self.u = UserFactory() diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 78818eb5..b5735396 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -49,13 +49,31 @@ class RojaboObjects(DjangoTestCase): self.r.defaulttimezone = 'Europe/Prague' self.r.rowerplan = 'plan' self.r.save() - self.c.login(username='john',password='koeinsloot') + + self.u2 = User.objects.create_user('john2', + 'sander@ds2.ds', + 'stierinsloot') + + self.u2.first_name = 'Sander' + self.u2.last_name = 'John' + self.u2.save() + self.r2 = Rower.objects.create(user=self.u2,gdproptin=True, ftpset=True,surveydone=True, + gdproptindate=timezone.now() + ) + + self.r2.rojabo_token = '12' + self.r2.rojabo_refreshtoken = 'ab' + self.r2.rojabo_tokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime + self.r2.defaulttimezone = 'Europe/Prague' + self.r2.rowerplan = 'pro' + self.r2.save() self.nu = datetime.datetime.now() @patch('rowers.rojabo_stuff.requests.get', side_effect=mocked_requests) @patch('rowers.rojabo_stuff.requests.post', side_effect=mocked_requests) def test_rojabo_import(self, mock_get, mock_post): + self.c.login(username='john',password='koeinsloot') url = '/rowers/session/rojaboimport/' response = self.c.get(url) self.assertEqual(response.status_code, 200) @@ -79,6 +97,26 @@ class RojaboObjects(DjangoTestCase): self.assertEqual(len(ps.steps['steps']),20) + @patch('rowers.rojabo_stuff.requests.get', side_effect=mocked_requests) + @patch('rowers.rojabo_stuff.requests.post', side_effect=mocked_requests) + def test_rojabo_import_denied(self, mock_get, mock_post): + self.c.login(username='john2',password='stierinsloot') + url = '/rowers/session/rojaboimport/' + response = self.c.get(url) + self.assertEqual(response.status_code, 302) + + form_data = { + 'csrfmiddlewaretoken': ['xalRrf8y7P2Hhobges9QC4aKCWg4l06gexDc8g2DeuVExgadfk4YhV8oSE1Yu43U'], + 'sessions': ['Import selected sessions'], + 'sessionid': ['862172'] + } + + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,302) + + + @pytest.mark.django_db @override_settings(TESTING=True) class GarminObjects(DjangoTestCase): diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 4f5d6948..3c0a65ca 100644 Binary files a/rowers/tests/testdata/testdata.tcx.gz and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 327cce0b..5fa3fa82 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -5,6 +5,7 @@ from jinja2 import Environment, FileSystemLoader from rowers.rower_rules import can_view_session from django.forms.widgets import SelectDateWidget, HiddenInput +from polars.exceptions import ComputeError def floatformat(x, prec=2): # pragma: no cover return '{x}'.format(x=round(x, prec)) @@ -945,8 +946,10 @@ def boxplotdata(workouts, options): except ColumnNotFoundError: pass - - datadf = datadf.with_columns((pl.col("workoutid").apply(lambda x: datemapping[x])).alias("date")) + try: + datadf = datadf.with_columns((pl.col("workoutid").apply(lambda x: datemapping[x])).alias("date")) + except ComputeError: + return ("","No Valid Data") if userid == 0: # pragma: no cover extratitle = '' @@ -1591,7 +1594,6 @@ class SavedAnalysisView(UserPassesTestMixin, View): def post(self, request, *args, **kwargs): # pragma: no cover form = self.form_class(request.POST) - if form.is_valid(): cd = form.cleaned_data self.selected = cd['analyses'] diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 93ba604e..f5270e17 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -649,10 +649,10 @@ def rower_process_testcallback(request): # pragma: no cover # The page where you select which Strava workout to import @login_required() -@user_passes_test(ispromember, login_url="/rowers/paidplans/", - message="This functionality requires a Pro plan or higher", +@user_passes_test(isplanmember, login_url="/rowers/paidplans/", + message="This functionality requires a Self-coach plan or higher", redirect_field_name=None) -@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True) +@permission_required('plannedsession.add_session', fn=get_user_by_userid, raise_exception=True) def workout_rojaboimport_view(request, message="", userid=0): # pragma: no cover r = getrequestrower(request, userid=userid) if r.user != request.user: @@ -753,10 +753,12 @@ def workout_rojaboimport_view(request, message="", userid=0): # pragma: no cover 'steps': steps, } ps.save() - messages.info(request,'Saved planned session {id}'.format(id=ps.id)) + except KeyError: # pragma: no cover pass + except ValidationError: + messages.error(request,"You cannot import sessions") except KeyError: pass