From 806e5837f90bd6dae1582d404964cbefb8f5f21f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 9 Nov 2021 21:30:11 +0100 Subject: [PATCH 1/5] fixes and extra logging --- rowers/polarstuff.py | 7 +++++-- rowers/stravastuff.py | 1 + rowers/tasks.py | 19 ++++++++++++------- rowers/tests/testdata/testdata.tcx.gz | Bin 0 -> 4000 bytes rowers/uploads.py | 8 ++++++++ 5 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 rowers/tests/testdata/testdata.tcx.gz diff --git a/rowers/polarstuff.py b/rowers/polarstuff.py index 1b703b84..2e2609bf 100644 --- a/rowers/polarstuff.py +++ b/rowers/polarstuff.py @@ -139,8 +139,11 @@ def get_polar_notifications(): available_data = [] - if response.status_code == 200: - available_data = response.json()['available-user-data'] + try: + if response.status_code == 200: + available_data = response.json()['available-user-data'] + except AttributeError: + pass return available_data diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index 7dde007b..592e6de6 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -501,6 +501,7 @@ def workout_strava_upload(user,w, quick=False,asynchron=True): tcxfile,w.name,activity_type, w.notes ) + dologging('strava_export_log.log','Exporting as {t}'.format(t=activity_type)) return "Asynchronous sync",-1 try: tcxfile,tcxmesg = createstravaworkoutdata(w) diff --git a/rowers/tasks.py b/rowers/tasks.py index c8d53492..90634228 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -341,6 +341,7 @@ def handle_strava_sync(stravatoken,workoutid,filename,name,activity_type,descrip dologging('strava_fail.log','Strava upload failed for Workout {id}'.format(id=workoutid)) failed = True except FileNotFoundError: # pragma: no cover + dologging('strava_fail.log','Strava upload failed for Workout {id}'.format(id=workoutid)) failed = True if not failed: @@ -348,21 +349,21 @@ def handle_strava_sync(stravatoken,workoutid,filename,name,activity_type,descrip try: act = client.update_activity(res.id,activity_type=activity_type, description=description,device_name='Rowsandall.com') - dologging('stravalog.log','Updating activity {id} to {type}'.format( + dologging('strava_export_log.log','Updating activity {id} to {type}'.format( id=workoutid, type=activity_type )) except TypeError: # pragma: no cover act = client.update_activity(res.id,activity_type=activity_type, description=description) - dologging('stravalog.log','Updating activity {id} to {type}'.format( + dologging('strava_export_log.log','Updating activity {id} to {type}'.format( id=workoutid, type=activity_type )) except: # pragma: no cover e = sys.exc_info()[0] - dologging('stravalog.log','Update activity failed with error {e} for {id} to {type}'.format( + dologging('strava_export_log.log','Update activity failed with error {e} for {id} to {type}'.format( id=workoutid, type=activity_type, e=e @@ -3168,7 +3169,7 @@ def df_from_summary(data): distances = [0] try: spms = [splits[0]['stroke_rate']] - except (KeyError, TypeError): # pragma: no cover + except (KeyError, TypeError, IndexError): # pragma: no cover spms = [0] try: hrs = [splits[0]['heart_rate']['average']] @@ -3298,9 +3299,13 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone strokedata = pd.DataFrame.from_dict(s.json()['data']) - res = make_cumvalues(0.1*strokedata['t']) - cum_time = res[0] - lapidx = res[1] + try: + res = make_cumvalues(0.1*strokedata['t']) + cum_time = res[0] + lapidx = res[1] + except KeyError: + dologging('debuglog.log','No time values in stroke data') + return 0 unixtime = cum_time+starttimeunix diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz new file mode 100644 index 0000000000000000000000000000000000000000..6e77967ae0cf1950d1e2bb9083070ba4487858a1 GIT binary patch literal 4000 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 GfB^t$WjiGR literal 0 HcmV?d00001 diff --git a/rowers/uploads.py b/rowers/uploads.py index de373685..a1847e20 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -15,6 +15,7 @@ from rowers.tasks import ( from rowers.models import GraphImage from rowers.rower_rules import ispromember +from rowers.utils import dologging from PIL import Image @@ -600,6 +601,13 @@ def do_sync(w,options, quick=False): message,id = stravastuff.workout_strava_upload( w.user.user,w,quick=quick,asynchron=True, ) + dologging( + 'strava_export_log.log', + 'exporting workout {id} as {type}'.format( + id=w.id, + type = w.workouttype, + ) + ) except NoTokenError: # pragma: no cover id = 0 message = "Please connect to Strava first" From 7bf50b67ad08eca7f1627166a99fb4d1248e9a74 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 9 Nov 2021 21:34:07 +0100 Subject: [PATCH 2/5] c2 fx --- rowers/views/importviews.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 5b1baca3..3021d9b9 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -1537,7 +1537,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,JSONDecodeError): # pragma: no cover + except: # pragma: no cover pass knownc2ids = uniqify(knownc2ids+tombstones+parkedids) From 5118255c739b490d0a24912d8efab75971f67054 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 9 Nov 2021 21:36:18 +0100 Subject: [PATCH 3/5] ok --- rowers/tests/testdata/testdata.tcx.gz | Bin 4000 -> 4001 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 6e77967ae0cf1950d1e2bb9083070ba4487858a1..311e28a0a3fcbbe05bbee79ced7e81ab5f14fc2b 100644 GIT binary patch delta 1102 zcmV-U1hM;|AE6(AABzYGZQF`r0{?Vnb97{3bYU)ZV|W1Vok?#THx_{J{uP1_$zc%o zTllyriUP;ZU<}xvATctz4JuMw?ir~isLR{GAF|t#Wm|>hNmB%?KpzZsb!}Z=J@V~5 z{Qlkf+1{Jw)n;|E{%#))?C*Vl^x*KtRkvEN)~An_>wbBE^|m7w3!g<>vU+^1RzDZa;kShW2--IOyK}g|j?7?pJSC{rex^ z^~-g>!5b%dw^@C1hPP}ku1*&OfQ#RrJ^f{Sif>lyP2a7Lm+7d@>R@-?rx(Xvzx}m$ zx`93YQE$k9yxW}o`GJ4$`bXW_#no!LS-inN-~VOTAMf^GUSA6T+NA~o-SyDjZ`?n6 zu(x;k;Q^$dkw1Ri@P6-?%Zsc2yZwLmua;N)yD!t%Pfm^q(0v2)4Z#cK1B(abOmxH% z{swRWaJWc2{jvYk?sD&!zPsvQtj?F;?f==a*B45EhrYPzyR&@QFU#YL^~vT)*dH#w z*!uB+$E)2N^lX`a>?Yl3zL(E7e%$*Hd`F1kaB=p#sCB2ye=O78|J?P@pEW3X5)AH)sYW=!j{=2{NBhqPp?ap2=kI<%z?Ed_Cg~ctGxbgL~ z?%nEt{Pp?&=?28zas#(q;>Ooc*4tOLe}A-nE0&4u^_H6t@?@DF@DX8tjJv;YP`p~5 zo~Bz{_OC8Zj-GYv*WFp7_{r9rdw0kG{p9YqTP`nF>;C5E{6%^P{=&Ps-R;vOKYJy_ z*x}b?d%!&j+@wJM3ko|DwNDmBlFZ7!YZJ94)z6VdDDdMA@f&}wO!1L(uHlYt9B0&ZKA z!wW3|Ewk|p3IY?`m8=21%8?sUCgak9);Dhu{dSWM4le<>lRgeC0k@ND4jq4C>mM5q z7f-v(>krQ_`sL>6tF!*wAJ3NO%XPo^^>)+OdtJW=@BGV`(NcIBP7uC2?Y})-><)Oa zJJTP(F@L`PwAy`t_~ChVw=fjp~ z-G9<0v$Npl=P!3#tNANSjCxPG*so&WGfy6K~zmuJgvvrHWFrw@yrKR9~6=~nC2`t1AVx?gU8e(3t{_inp9NIS2$j~>40 z`>Vsn;`Qs-=B(RXtk&k_@?w#`+@8ExUUb{V?T0U3(Zl^I4!bv>ah7jS`qisd|L2cy z`sF&`;EfZ!*{(h~!)rE|o3jN0;NrKZPoC{g@zrX*?Ys5KG99&D9q!NjJ^!PH`~*{KJf2d|9y9Uxmhi@i&yy9`~T7PC;R=E*O$W2yVM|{yB@m#jSr6> z92^|IeE{iaT=URdic-&#d7m-|7H66@#!%Ey01XKB6yB`Xz`GoiH!DX_*chXUnm`a`uwu*&huf6ct@e!Tu}+4b9>mz$@n^~-+w@BYS*NT>O=JAb)6Mw>3O|MUG77PnmD#@A1~ zH>-<(mlyx18xVKP4cu~x8(%+O?_SmZ&*R-&u}oyIx7>V?r_1z!j|uZ*-2Z)p;%0Sr zmTqm?zqmX-e%h^HcIS!W2U~CM-JSgRgS+2txw>4f``HifO`_SNrC()6!s);NASS|hFhNRZink7(QEt3WuO22+h@-Nw~pZ-pD~^DUtQlP zv57~E{a+tnbCE9k@sptfRsnXC_yT$XgtK!4#{mJmlRE`M0_<9|e+3u<0T7dz2e1K< zlSv410sFJN2&e)dwM_IXHP4D|E}iK+a(68g(d*`VCzDCgYH67R=)@2RzuH z>D_P4pRYfy_TL|UzeyY~H*fd-sY`Fq=JNHnTc394=ewtsKCaehr(NHr^LG2UD^YoW z+|jo$`xlp+8?VW?S6An&lYg#HKmGc}xIXtMCrjUb_i}Z9di`^MP48nm^v1(^yX9&3 zpLEIWEV%jk)7@6 Date: Tue, 9 Nov 2021 21:51:25 +0100 Subject: [PATCH 4/5] do logging --- rowers/stravastuff.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index 592e6de6..5db8dd31 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -45,6 +45,7 @@ except ImportError: # pragma: no cover JSONDecodeError = ValueError from rowers.imports import * +from rowers.utils import dologging webhookverification = "kudos_to_rowing" webhooklink = SITE_URL+'/rowers/strava/webhooks/' From 37e629e103a313cd8da86bfbec161c6703943b2f Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 9 Nov 2021 22:01:12 +0100 Subject: [PATCH 5/5] removing temp file --- rowers/tests/testdata/testdata.tcx.gz | Bin 4001 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 rowers/tests/testdata/testdata.tcx.gz diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz deleted file mode 100644 index 311e28a0a3fcbbe05bbee79ced7e81ab5f14fc2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4001 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