6r!As-Y~-Y6c_BV`8Fal7J4!7_o9Ou
zDLI#ENPm7-#{
zSZ2|3TIuiL{i%XsA||fU@dAMEFyh-F@cqE&LE?+#XA07{Fz>g@Iw@&0MRD^Hw47&U
z<148+?sUn54n`UPy$?gQV=)s>6?J-fvyCMi$h2FjQL**6#_BOo#BVEY(cK!tQ!Eq1
zH!-hJAbtX5#HwOLk2y&x@tNWO;FO`K6XJl18|Yy0^d~5-=cH=bJNOW{{Sm1}tCv#=3Ykd-}@G>zYk-Nxdw-w6<(?8G9BClT`Watvh$
zJ$|fe!iuj0z;xpIyo(FcoNo1nSE?z8Tqy!SJy!hGH%k+p|I;a-T0|?~jLYq(82CXn
zSpb3zShCSF&Nb^;OduN5imzCwR-`HNr-18V9Y^{=~Z=-YjXdf$As%cn##;5IpH5FD4TgoK*|@NY~56<)}e-?nOb~G
zNDH#Tu>r%)hHBv<|1beT7Rpb#(E^QWH*&oVpl>MWnNx}mi1kuiRa*7osfU|%Q^Q3{
zu9$U)=vWoHHPpAguS&G8?mP*~LZ+57nvX`-3^^n1m)xLS{FQ2jW}H3rm};dX(I
zs9>YBohv%=Z9&wV`bb143_VUMoAu566dBvPR~zA7o}<&A-&k6>S!NT#qc~7?*SB(z
zqh+?(ZRRPJjl&c%QNl}zvK?n8fNnQx40_&-{RkCc1HOfBmw-mFGk=3`-lTJuW-9GR
zQ^MTIV#$;^lvt=rT5atgMym$qs=rho0mINo*J9DlKubHZ@y5O8HEY*$GV-)UZ*ZxH
zF%eqHshjX+BGRfP^vmN^ij^3c#3EY$a(jVdHAzu1Ru+|&j&9?iJ2>e5o}NMF!GY(^
zw^`|AvPUJxM-U4&*%_?WulYFJHsO;Q&Yhy@Tn0ON)CxP-5;wtxzlPM9#|VXB6)L<>
zd2qijsPOFI;A}q)KwKb0m>3`GyTOMl(90d@_0)Ux;=58}DGx*`>?!5%R()BU;3J6P
z*Uc<=I60dNPiFR5+#B9ct||3LM&c1)U7#n7AUtf~=ZnET6{tBG7W*Fw_1@Wgy-M$C
z&;S-=igl+Sv(^koEQ57gz^XVD_8dHhioDGl9(^%9zK?D-M+R}A<_sv20hOKuwl=)y
z{hii{I~A4xkDVos{wj$aNVb&~wP-kk_djA~VxBgdA
zIM^~fT(7W#4hdtk`985j@kwS#XfA%rMiFHeHrtee%3v(8O8QNm8{<~}cFNr6u)O#2
zT+D_GSPBc?Z*WX>7>#y-S}
z-c+xym=4sOVTEg1@3W5LPbgZaq-1%3l#xyYxD+F2G`8EwQp1ONVv(n|X4}~VA3qLH
zmXcO~!9$2hz2=}&d_iPDe>(?-zydshFApN!9H|2peQG;&??o?%n8?u1TZUr=&h
zIeE}FuS+Qq!|rjweOD;o)WW2(PHr)X
z5t)kTNSF6yy+kDeh&8%{UDtOg$6tA2mm#-?{0oJAirH&fCpBvuDrh;SK
zA4zh65-Etx0bt7UwYy1d1SztMOu^J-D5+CohZGu>vf=sX1FYj;Z4Q*p3OKiz5
z7bd%Kn9)~#(+i+p2RO~-{S$%fF~MZrRS=Q`AhUpp9*_hRWQM=yg!cq~e}Zc73jdpI
zYXqT40e4P)G>WaG!~%l&Ek6}5Gqj{r?A5kQ?DqSw>Shz6nXhK}m;vqpoa?54qyfGTsABltNg)SM&L!Mkx<^xL~P09pE1$klIiJpt0JUy@YtM#h*D2PD-&);$t7
za0PB`uuH?ic(^Q}jE|G1{@GL8#g2nW=s-p6cpDQDbrn5Vr~ncG`Mj)@Fhaj2@V_OX
zd)47G9M~5cRJ#D0&3t8~7&_f{Ok@W{WbXgv$GWqkabjx_M3SVn>Ndw1Du$OeW8$+-
zCMJZG02z}|q)q*W(qKH1Tusl@33`Y9I=#!bzV(mZp@h*|f{Y2xIrf~{8`i_yATTn5
z@m@k%!IB{+AZup9*Pxe?mo4{SBk48}d1WKAyGagn^?yGJ-)x~a9pSy+IH7aHsjesgoORE}#f0*;Y
zx&L^rQcrd(FS`u|gq6!5vn{sF8;!;HE&aTnBr}eL+Ub)}LL{D{GTZ9-cmVz9WV|U-
z;8j++uC)!3MFnqH2I28I4$^Y^k+H~QO?itAIIq;X=^Gw!E4Zfl+1io^%Kl63;f1L5
z7x%As9el(ko#LY;!q<~Dm~we#A1w{c>aYNSrrF|0fP_92-{Tr8O78tN<#9em>(Eid
zN9zNXNV#!_oTw8%+s545dH=%+d=XKW2h9DpYtfyfw9X4xBC=R!Wu8
zOta4|XQ}a0B^dR(QgV)InpEWU8>D;*&eZ(;G|n{l96ozPWqFpI-X#~w9h^_#)t+We
zf&Y9DN|Y}nuq+|6INna3;9x!jL#8gy+VYqI69hkGxpNXG#*~?1IRuj*nDD$mnsxR#
zN?uTl?I@RPB}+L!uUAbrK`Uan)FDTLPc)|B0y^HLDrT^sfWd#Xmb5Y06(AL!VL(M5
z^#<8ZZhu62L0yjOV@j-;=
znI|F`L2#+2Sbo!^u)X&h2wV{-KDB#^gO(e1`*JPsYzxS+B{TGAJOV#>3lwsrF0V$Y
zekm$B7d+-)zr&}uzE%Gc%i?HP6dZ<6dKMYSLsc_ZPpTYMygUS_`VqmkJ+v1c4Z#f~
zs~_+Ojh~JN!Jk>5_f4S&j;+5n<~>pKDk>;>EPCvV8qDI44?M!s)%S!KRVE%rbfgBK
zA)ZPh)L?t4k-5S_lvWRQzl6)ZuF3M`;{Q^BljhL$=SQl{CbTL
zKSermO;_soMtK(Z-%Zkd-1_JRaML$K*p-H0?!QN+zs~+*eVv(#x%3wF(~Eh3a_C~B
zGCEhtASEY`x1HC3{TeLWOXY$HG%yctZ`Hivb0Z^8(Tv19gBU@rslo9q9FO+&Fz>rI
zgdaKa@HwQR;Bi7SD4HZ#?x?xG7nEviPz8}GGTtq3kJ<2l{p$Iz3B-j@=~2~Jgv;v<
z+U=n`Mpx7$myZ$NBLhWCMuirWrB)ak0@@Mn<-B-&JN1(
zspRXRe%j>32%VRC*f)68_+n;`hr8^{zL_(p+OtE?Nx{5vB?cF4^EFsf!s5$=Td=Qj
z4N{}mJ9)YCHb(3);KW&XM6x7)ymkAu9j2*{uQP6zY4{QtHy)mmv;%V_3$&CD7&HY{njhd#)
zCB4a8ODr?JjgXeOz*lDxT&eiFVWy-TYp34r8eIpsYMj5-@bAGp{@2x1yx7|o+xbhv
zGTtn3lTF~=yM78TMT_s^HPV)IxfiwPmG$GeVU6epnhtr#p;T?R)iM9rUO=klkcnUc
zXimj7|C_xfmt6`PDqs9A0yz@lA!W~c1+oJ7PdM{Yd&g@pUDROM4gmwrPj{g
z@zZ7?Vg8?h)>@ZqbgsXQjrL0aqr2M+Keey^PBuToGtds_7tYT+P#F)};z;<|SIKIf
z5ro0jg}vly57+OGRNB;WSH+BmVWow+pYlo9gX+iT0*gqiw5wZK7$T15$Wl0jzm$MW
zlE?P3{y4&gSxHsDUkPZjG4o7hs^Q<-t!Sq48{f+33!B!Oi^uZ@_4-fRiaOW#D6MIM=FY8YJI3>i=OGY)Ky^G>@uWZKsw7G!uio^4;DN0
z#OR)Wh!*|hs#M%NeULUL^?4`gG&w<_j5DsVgQM*xU|&+L
zzDktg)N;dQj=ZSQ(5>ibJe0n7^_|GC6#w$Tg6G2olef5Z=cwuS
zh(Kbrr)(B#MxYYm)qWkkWT$sif!4zomO(rBjUHN!g_VYk3WgLGN^Ub~6<_#fqAWDp
z+mFM}usq(MQzsjk%YfE5E@_eOfp|HliNlQLg%o2{j#H0Dfsvwu`kSy^!!F|Empq?*
z)xqhj+=XJL7DN7Tv!+sau{0F|30>F;63nb-_YR
zqo^|k$l~DZo>SWbx6WLWxvvm7Nc!_-@9E<_cZ}q13S`SeH*VKJb|AjHzXvrve9_;i
zk8Xfw+UGpjN)>lU-KgJ#yQX6IMUE^M1!
NJTQBOK>~pO{{b}x${qj!
literal 0
HcmV?d00001
From 82ad2d90db983c36a96df18dd0f7ca151c47ac2d Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 22 Jun 2018 14:40:49 +0200
Subject: [PATCH 2/3] concept2 auto import
---
rowers/c2stuff.py | 34 ++++++++++++++++++++--
rowers/dataprep.py | 6 +++-
rowers/dataprepnodjango.py | 6 +++-
rowers/management/commands/processemail.py | 7 +++++
rowers/models.py | 1 +
5 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py
index c1df31d8..dca87e85 100644
--- a/rowers/c2stuff.py
+++ b/rowers/c2stuff.py
@@ -34,7 +34,7 @@ import sys
import urllib
from requests import Request, Session
-from utils import myqueue
+from utils import myqueue,uniqify,isprorower
from rowers.types import otwtypes
@@ -114,7 +114,37 @@ def add_stroke_data(user,c2id,workoutid,startdatetime,csvfilename):
csvfilename)
return 1
+
+def get_c2_workouts(rower):
+
+ if not isprorower(rower):
+ return 0
+ try:
+ thetoken = c2_open(rower.user)
+ except C2NoTokenError:
+ return 0
+
+ res = get_c2_workout_list(rower.user,page=1)
+
+ if (res.status_code != 200):
+ return 0
+ else:
+ c2ids = [item['id'] for item in res.json()['data']]
+ alldata = {}
+ for item in res.json()['data']:
+ alldata[item['id']] = item
+
+ knownc2ids = uniqify([
+ w.uploadedtoc2 for w in Workout.objects.filter(user=rower)
+ ])
+ newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
+
+ for c2id in newids:
+ workoutid = create_async_workout(alldata,
+ rower.user,c2id)
+
+ return 1
# get workout metrics, then relay stroke data to an asynchronous task
def create_async_workout(alldata,user,c2id):
@@ -155,7 +185,7 @@ def create_async_workout(alldata,user,c2id):
w = Workout(
user=r,
workouttype = workouttype,
- name = 'Imported workout',
+ name = 'C2 Import Workout from {startdatetime}'.format(startdatetime=startdatetime),
date = workoutdate,
starttime = starttime,
startdatetime = startdatetime,
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index c98edd6c..ddcb0b05 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -1999,7 +1999,11 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
rowdatadf.loc[row_index, ' Stroke500mPace (sec/500m)'] = 3000.
p = rowdatadf.ix[:, ' Stroke500mPace (sec/500m)']
- velo = rowdatadf.ix[:,' AverageBoatSpeed (m/s)']
+ try:
+ velo = rowdatadf.ix[:,' AverageBoatSpeed (m/s)']
+ except KeyError:
+ velo = 500./p
+
hr = rowdatadf.ix[:, ' HRCur (bpm)']
spm = rowdatadf.ix[:, ' Cadence (stokes/min)']
cumdist = rowdatadf.ix[:, 'cum_dist']
diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py
index 2e2b523e..3828afdb 100644
--- a/rowers/dataprepnodjango.py
+++ b/rowers/dataprepnodjango.py
@@ -978,7 +978,11 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
rowdatadf.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000.
p = rowdatadf.ix[:,' Stroke500mPace (sec/500m)']
- velo = rowdatadf.ix[:,' AverageBoatSpeed (m/s)']
+ try:
+ velo = rowdatadf.ix[:,' AverageBoatSpeed (m/s)']
+ except KeyError:
+ velo = 500./p
+
hr = rowdatadf.ix[:,' HRCur (bpm)']
spm = rowdatadf.ix[:,' Cadence (stokes/min)']
cumdist = rowdatadf.ix[:,'cum_dist']
diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py
index c8c3f2f9..e8f7f8d8 100644
--- a/rowers/management/commands/processemail.py
+++ b/rowers/management/commands/processemail.py
@@ -21,6 +21,7 @@ from rowingdata import rowingdata as rrdata
import rowers.uploads as uploads
from rowers.mailprocessing import make_new_workout_from_email, send_confirm
import rowers.polarstuff as polarstuff
+import rowers.c2stuff as c2stuff
workoutmailbox = Mailbox.objects.get(name='workouts')
failedmailbox = Mailbox.objects.get(name='Failed')
@@ -148,8 +149,14 @@ class Command(BaseCommand):
"""Run the Email processing command """
def handle(self, *args, **options):
+ # Polar
polar_available = polarstuff.get_polar_notifications()
res = polarstuff.get_all_new_workouts(polar_available)
+
+ # Concept2
+ rowers = Rower.objects.filter(c2_auto_import=True)
+ for r in rowers:
+ c2stuff.get_c2_workouts(r)
messages = Message.objects.filter(mailbox_id = workoutmailbox.id)
message_ids = [m.id for m in messages]
diff --git a/rowers/models.py b/rowers/models.py
index 9cd7fc0f..b237088a 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -2021,6 +2021,7 @@ class RowerImportExportForm(ModelForm):
fields = [
'polar_auto_import',
'c2_auto_export',
+ 'c2_auto_import',
'mapmyfitness_auto_export',
'runkeeper_auto_export',
'sporttracks_auto_export',
From 6e73ab2d698cd05782361ac51a97be98663636d7 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 22 Jun 2018 17:02:51 +0200
Subject: [PATCH 3/3] bug fix interval coloring
---
rowers/interactiveplots.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index fc1e88c6..057c97d0 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -2214,16 +2214,18 @@ def interactive_chart(id=0,promember=0,intervaldata = {}):
intervaldf = pd.DataFrame(intervaldata)
intervaldf['itime'] = intervaldf['itime']*1.e3
intervaldf['time'] = intervaldf['itime'].cumsum()
- intervaldf['time_r'] = intervaldf['time'] +intervaldf['itime'].shift(-1)
- intervaldf['value'] = 10
+ intervaldf['time'] = intervaldf['time'].shift(1)
+ intervaldf.ix[0,'time'] = 0
+ intervaldf['time_r'] = intervaldf['time'] +intervaldf['itime']
+ intervaldf['value'] = 100
mask = intervaldf['itype'] == 3
- intervaldf.loc[mask,'value'] = 45
+ intervaldf.loc[mask,'value'] = 0
intervaldf['bottom'] = 10
intervalsource = ColumnDataSource(
intervaldf
)
-
+
plot.quad(left='time',top='value',bottom='bottom',
right='time_r',source=intervalsource,color='mediumvioletred',
y_range_name='spmax',fill_alpha=0.2,line_alpha=0.2)