sort of saves files
This commit is contained in:
@@ -8,6 +8,8 @@ from rowers.mytypes import otwtypes
|
|||||||
from rowers.rower_rules import is_workout_user,ispromember
|
from rowers.rower_rules import is_workout_user,ispromember
|
||||||
from iso8601 import ParseError
|
from iso8601 import ParseError
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import json
|
import json
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
@@ -27,6 +29,7 @@ from rowers.models import C2WorldClassAgePerformance,Rower,Workout,TombStone
|
|||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
from rowers.utils import custom_exception_handler,NoTokenError
|
from rowers.utils import custom_exception_handler,NoTokenError
|
||||||
|
from rowingdata import rowingdata
|
||||||
|
|
||||||
oauth_data = {
|
oauth_data = {
|
||||||
'client_id': GARMIN_CLIENT_KEY,
|
'client_id': GARMIN_CLIENT_KEY,
|
||||||
@@ -43,6 +46,18 @@ oauth_data = {
|
|||||||
'headers': 'Authorization: OAuth oauth_version="1.0"'
|
'headers': 'Authorization: OAuth oauth_version="1.0"'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
columns = {
|
||||||
|
'startTimeInSeconds':'TimeStamp (sec)',
|
||||||
|
'latitudeinDegree':' latitude',
|
||||||
|
'longitudeInDegree':' longitude',
|
||||||
|
'heartRate':' HRCur (bpm)',
|
||||||
|
'speedMetersPerSecond':' AverageBoatSpeed (m/s)',
|
||||||
|
'totalDistanceInMeters':' Horizontal (meters)',
|
||||||
|
'clockDurationInSeconds':' ElapsedTime (sec)',
|
||||||
|
'powerInWatts':' Power (watts)',
|
||||||
|
'bikeCadenceInRPM':' Cadence (stokes/min)',
|
||||||
|
}
|
||||||
|
|
||||||
def garmin_authorize():
|
def garmin_authorize():
|
||||||
redirect_uri = oauth_data['redirect_uri']
|
redirect_uri = oauth_data['redirect_uri']
|
||||||
client_secret = oauth_data['client_secret']
|
client_secret = oauth_data['client_secret']
|
||||||
@@ -110,51 +125,100 @@ def get_garmin_workout_list(user):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def garmin_getworkout(garminid,r,activity):
|
||||||
|
starttime = activity['startTimeInSeconds']
|
||||||
|
startdatetime = arrow.get(starttime)
|
||||||
|
durationseconds = activity['durationInSeconds']
|
||||||
|
duration = dataprep.totaltime_sec_to_string(durationseconds)
|
||||||
|
activitytype = activity['activityType']
|
||||||
|
name = 'Imported from Garmin'
|
||||||
|
date = startdatetime.date()
|
||||||
|
try:
|
||||||
|
distance = activity['distanceInMeters']
|
||||||
|
except KeyError:
|
||||||
|
distance = 0
|
||||||
|
try:
|
||||||
|
averagehr = activity['averageHeartRateInBeatsPerMinute']
|
||||||
|
maxhr = activity['maxHeartRateInBeatsPerMinute']
|
||||||
|
except KeyError:
|
||||||
|
averagehr = 0
|
||||||
|
maxhr = 0
|
||||||
|
try:
|
||||||
|
w = Workout.objects.get(uploadedtogarmin=garminid)
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
newcsvfile='media/garmin{code}_{importid}.csv'
|
||||||
|
w = Workout(user=r,csvfilename=newcsvfile)
|
||||||
|
w.startdatetime = datetime.datetime(
|
||||||
|
year=startdatetime.year,
|
||||||
|
month=startdatetime.month,
|
||||||
|
day=startdatetime.day,
|
||||||
|
hour=startdatetime.hour,
|
||||||
|
minute=startdatetime.minute,
|
||||||
|
second=startdatetime.second,
|
||||||
|
tzinfo=startdatetime.tzinfo)
|
||||||
|
w.starttime = startdatetime.time()
|
||||||
|
try:
|
||||||
|
w.duration = datetime.datetime.strptime(duration,"%H:%M:%S.%f").time()
|
||||||
|
except ValueError:
|
||||||
|
w.duration = datetime.datetime.strptime(duration,"%H:%M:%S")
|
||||||
|
try:
|
||||||
|
w.workouttype = mytypes.garminmappinginv[activitytype]
|
||||||
|
except KeyError:
|
||||||
|
w.workouttype = 'other'
|
||||||
|
w.name = name
|
||||||
|
w.date = date
|
||||||
|
w.distance = distance
|
||||||
|
|
||||||
|
w.save()
|
||||||
|
|
||||||
|
|
||||||
|
return w
|
||||||
|
|
||||||
|
def garmin_workouts_from_details(activities):
|
||||||
|
for activity in activities:
|
||||||
|
garmintoken = activity['userAccessToken']
|
||||||
|
try:
|
||||||
|
r = Rower.objects.get(garmintoken=garmintoken)
|
||||||
|
garminid = activity['summaryId'][:-7]
|
||||||
|
summary = activity['summary']
|
||||||
|
w = garmin_getworkout(garminid,r,summary)
|
||||||
|
samples = activity['samples']
|
||||||
|
df = pd.DataFrame(samples)
|
||||||
|
df.rename(columns=columns,inplace=True)
|
||||||
|
try:
|
||||||
|
pace = 500./df[' AverageBoatSpeed (m/s)']
|
||||||
|
except KeyError:
|
||||||
|
pace = 0
|
||||||
|
df[' AverageBoatSpeed (m/s)'] = 0
|
||||||
|
df[' Stroke500mPace (sec/500m)'] = pace
|
||||||
|
try:
|
||||||
|
spm = df[' Cadence (stokes/min)']
|
||||||
|
except KeyError:
|
||||||
|
df[' Cadence (stokes/min)'] = 0
|
||||||
|
df['cum_dist'] = df[' Horizontal (meters)']
|
||||||
|
try:
|
||||||
|
power = df[' Power (watts)']
|
||||||
|
except KeyError:
|
||||||
|
df[' Power (watts)'] = 0
|
||||||
|
df[' AverageDriveForce (lbs)'] = 0
|
||||||
|
df[' DriveLength (meters)'] = 0
|
||||||
|
df[' PeakDriveForce (lbs)'] = 1
|
||||||
|
df[' DriveTime (ms)'] = 0
|
||||||
|
rowdata = rowingdata(df=df)
|
||||||
|
rowdata.write_csv(w.csvfilename,gzip=True)
|
||||||
|
data = dataprep.dataprep(rowdata.df,id=w.id)
|
||||||
|
except Rower.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
def garmin_workouts_from_summaries(activities):
|
def garmin_workouts_from_summaries(activities):
|
||||||
for activity in activities:
|
for activity in activities:
|
||||||
garmintoken = activity['userAccessToken']
|
garmintoken = activity['userAccessToken']
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(garmintoken=garmintoken)
|
r = Rower.objects.get(garmintoken=garmintoken)
|
||||||
starttime = activity['startTimeInSeconds']
|
id = activity['summaryId']
|
||||||
startdatetime = arrow.get(starttime)
|
w = garmin_getworkout(id,r,activity)
|
||||||
durationseconds = activity['durationInSeconds']
|
|
||||||
duration = dataprep.totaltime_sec_to_string(durationseconds)
|
|
||||||
activitytype = activity['activityType']
|
|
||||||
name = 'Imported from Garmin'
|
|
||||||
date = startdatetime.date()
|
|
||||||
try:
|
|
||||||
distance = activity['durationInMeters']
|
|
||||||
except KeyError:
|
|
||||||
distance = 0
|
|
||||||
try:
|
|
||||||
averagehr = activity['averageHeartRateInBeatsPerMinute']
|
|
||||||
maxhr = activity['maxHeartRateInBeatsPerMinute']
|
|
||||||
except KeyError:
|
|
||||||
averagehr = 0
|
|
||||||
maxhr = 0
|
|
||||||
uploadedtogarmin = activity['summaryId']
|
|
||||||
try:
|
|
||||||
w = Workout.objects.get(uploadedtogarmin=uploadedtogarmin)
|
|
||||||
except Workout.DoesNotExist:
|
|
||||||
newcsvfile='media/garmin{code}_{importid}.csv'
|
|
||||||
w = Workout(user=r,csvfilename=newcsvfile)
|
|
||||||
w.startdatetime = datetime.datetime(
|
|
||||||
year=startdatetime.year,
|
|
||||||
month=startdatetime.month,
|
|
||||||
day=startdatetime.day,
|
|
||||||
hour=startdatetime.hour,
|
|
||||||
minute=startdatetime.minute,
|
|
||||||
second=startdatetime.second,
|
|
||||||
tzinfo=startdatetime.tzinfo)
|
|
||||||
w.starttime = startdatetime.time()
|
|
||||||
w.duration = duration
|
|
||||||
try:
|
|
||||||
w.workouttype = mytypes.garminmappinginv[activitytype]
|
|
||||||
except KeyError:
|
|
||||||
w.workouttype = 'other'
|
|
||||||
w.name = name
|
|
||||||
w.date = date
|
|
||||||
w.save()
|
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -2842,12 +2842,13 @@ class Workout(models.Model):
|
|||||||
boattype = self.boattype
|
boattype = self.boattype
|
||||||
workouttype = self.workouttype
|
workouttype = self.workouttype
|
||||||
|
|
||||||
|
|
||||||
if workouttype != 'water':
|
if workouttype != 'water':
|
||||||
stri = u'{d} {n} {dist}m {duration:%H:%M:%S} {workouttype} {ownerfirst} {ownerlast}'.format(
|
stri = u'{d} {n} {dist}m {duration} {workouttype} {ownerfirst} {ownerlast}'.format(
|
||||||
d = date.strftime('%Y-%m-%d'),
|
d = date.strftime('%Y-%m-%d'),
|
||||||
n = name,
|
n = name,
|
||||||
dist = distance,
|
dist = distance,
|
||||||
duration = duration,
|
duration = duration.strftime("%H:%M:%S"),
|
||||||
workouttype = workouttype,
|
workouttype = workouttype,
|
||||||
ownerfirst = ownerfirst,
|
ownerfirst = ownerfirst,
|
||||||
ownerlast = ownerlast,
|
ownerlast = ownerlast,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ nu = datetime.datetime.now()
|
|||||||
|
|
||||||
|
|
||||||
import rowers
|
import rowers
|
||||||
|
from rowers import dataprep
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@override_settings(TESTING=True)
|
@override_settings(TESTING=True)
|
||||||
@@ -42,12 +43,54 @@ class GarminObjects(TransactionTestCase):
|
|||||||
content_type="application/json")
|
content_type="application/json")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
response = self.c.get('/rowers/workout/'+encoded1+'/', follow=True)
|
#response = self.c.get('/rowers/workout/'+encoded1+'/', follow=True)
|
||||||
|
#self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
ws = Workout.objects.filter(user=self.r)
|
||||||
|
self.assertEqual(ws.count(),3)
|
||||||
|
|
||||||
|
def test_garmin_push_details3(self):
|
||||||
|
data = json.load(open('rowers/tests/testdata/garmindetail3.txt','r'))
|
||||||
|
response = self.c.post('/rowers/garmin/activities/',json.dumps(data),
|
||||||
|
content_type='application/json')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
ws = Workout.objects.filter(user=self.r)
|
||||||
|
self.assertEqual(ws.count(),1)
|
||||||
|
|
||||||
|
data,w = dataprep.getrowdata_db(id=ws[0].id)
|
||||||
|
|
||||||
|
self.assertEqual(len(data),515)
|
||||||
|
|
||||||
|
def test_garmin_push_details2(self):
|
||||||
|
data = json.load(open('rowers/tests/testdata/garmindetail2.txt','r'))
|
||||||
|
response = self.c.post('/rowers/garmin/activities/',json.dumps(data),
|
||||||
|
content_type='application/json')
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
ws = Workout.objects.filter(user=self.r)
|
ws = Workout.objects.filter(user=self.r)
|
||||||
self.assertEqual(ws.count(),3)
|
self.assertEqual(ws.count(),3)
|
||||||
|
|
||||||
|
data,w = dataprep.getrowdata_db(id=ws[0].id)
|
||||||
|
self.assertEqual(len(data),451)
|
||||||
|
|
||||||
|
def test_garmin_push_details1(self):
|
||||||
|
data = json.load(open('rowers/tests/testdata/garmindetail1.txt','r'))
|
||||||
|
response = self.c.post('/rowers/garmin/activities/',json.dumps(data),
|
||||||
|
content_type='application/json')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.c.get('/rowers/workout/'+encoded1+'/', follow=True)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
ws = Workout.objects.filter(user=self.r)
|
||||||
|
self.assertEqual(ws.count(),2)
|
||||||
|
|
||||||
|
data,w = dataprep.getrowdata_db(id=ws[0].id)
|
||||||
|
self.assertEqual(len(data),2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
5
rowers/tests/testdata/garmindetail1.txt
vendored
5
rowers/tests/testdata/garmindetail1.txt
vendored
@@ -1,4 +1,5 @@
|
|||||||
[ {
|
[ { "userId": "25858854-f086-4026-83ac-a3bfc97dcbb1",
|
||||||
|
"userAccessToken": "dfdzf",
|
||||||
"summaryId" : "14098044-detail",
|
"summaryId" : "14098044-detail",
|
||||||
"summary" : {
|
"summary" : {
|
||||||
"durationInSeconds" : 4828,
|
"durationInSeconds" : 4828,
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
"movingDurationInSeconds" : 0
|
"movingDurationInSeconds" : 0
|
||||||
} ]
|
} ]
|
||||||
}, {
|
}, {
|
||||||
|
"userId": "25858854-f086-4026-83ac-a3bfc97dcbb1",
|
||||||
|
"userAccessToken": "dfdzf",
|
||||||
"summaryId" : "14033650-detail",
|
"summaryId" : "14033650-detail",
|
||||||
"summary" : {
|
"summary" : {
|
||||||
"durationInSeconds" : 4778,
|
"durationInSeconds" : 4778,
|
||||||
|
|||||||
5
rowers/tests/testdata/garmindetail2.txt
vendored
5
rowers/tests/testdata/garmindetail2.txt
vendored
File diff suppressed because one or more lines are too long
@@ -416,6 +416,7 @@ urlpatterns = [
|
|||||||
views.WorkoutDelete.as_view()),
|
views.WorkoutDelete.as_view()),
|
||||||
name='workout_delete'),
|
name='workout_delete'),
|
||||||
re_path(r'^garmin/summaries/',views.garmin_summaries_view,name='garmin_summaries_view'),
|
re_path(r'^garmin/summaries/',views.garmin_summaries_view,name='garmin_summaries_view'),
|
||||||
|
re_path(r'^garmin/activities/',views.garmin_details_view,name='garmin_details_view'),
|
||||||
# re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/delete/$',login_required(
|
# re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/delete/$',login_required(
|
||||||
# views.workout_code_delete_view),name='workout_code_delete'),
|
# views.workout_code_delete_view),name='workout_code_delete'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/smoothenpace/$',views.workout_smoothenpace_view,name='workout_smoothenpace_view'),
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/smoothenpace/$',views.workout_smoothenpace_view,name='workout_smoothenpace_view'),
|
||||||
|
|||||||
@@ -1023,6 +1023,20 @@ def garmin_summaries_view(request):
|
|||||||
|
|
||||||
return HttpResponse(status=400)
|
return HttpResponse(status=400)
|
||||||
|
|
||||||
|
def garmin_details_view(request):
|
||||||
|
if request.method != 'POST':
|
||||||
|
raise Http404("not allowed")
|
||||||
|
|
||||||
|
# POST request
|
||||||
|
data = json.loads(request.body)
|
||||||
|
result = garmin_stuff.garmin_workouts_from_details(data)
|
||||||
|
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return HttpResponse(status=200)
|
||||||
|
|
||||||
|
return HttpResponse(status=400)
|
||||||
|
|
||||||
|
|
||||||
# The page where you select which RunKeeper workout to import
|
# The page where you select which RunKeeper workout to import
|
||||||
@login_required()
|
@login_required()
|
||||||
|
|||||||
Reference in New Issue
Block a user