API v2 (version 1)
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="grid_2">
|
<li class="grid_4">
|
||||||
<p>There are three ways to allow your users to get data to Rowsandall.com.</p>
|
<p>There are three ways to allow your users to get data to Rowsandall.com.</p>
|
||||||
<h2>File based export from your app</h2>
|
<h2>File based export from your app</h2>
|
||||||
|
|
||||||
@@ -26,19 +26,19 @@
|
|||||||
The users
|
The users
|
||||||
upload the file to Rowsandall.com.</p>
|
upload the file to Rowsandall.com.</p>
|
||||||
|
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>Advantages
|
<li>Advantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>User sees immediate results</li>
|
<li>User sees immediate results</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
<li>Disadvantages
|
<li>Disadvantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>It is a multi-step process: Download from your
|
<li>It is a multi-step process: Download from your
|
||||||
app, store, upload.</li>
|
app, store, upload.</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
<h2>Email from your app</h2>
|
<h2>Email from your app</h2>
|
||||||
|
|
||||||
<p>Similar as above, generate TCX, FIT or CSV formatted files and
|
<p>Similar as above, generate TCX, FIT or CSV formatted files and
|
||||||
@@ -46,19 +46,19 @@
|
|||||||
to <em>workouts@rowsandall.com</em> directly from your app. The From: field
|
to <em>workouts@rowsandall.com</em> directly from your app. The From: field
|
||||||
should be the email address of the registered user.</p>
|
should be the email address of the registered user.</p>
|
||||||
|
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>Advantages
|
<li>Advantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>It's a simple process, which can be automated.</li>
|
<li>It's a simple process, which can be automated.</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
<li>Disadvantages
|
<li>Disadvantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>It may take up to five minutes for the workout to show up
|
<li>It may take up to five minutes for the workout to show up
|
||||||
on the site.</li>
|
on the site.</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
<h2>Using the REST API</h2>
|
<h2>Using the REST API</h2>
|
||||||
|
|
||||||
<p>We are building a REST API which will allow you to post and
|
<p>We are building a REST API which will allow you to post and
|
||||||
@@ -71,30 +71,30 @@
|
|||||||
with questions and/or suggestions. We
|
with questions and/or suggestions. We
|
||||||
will get back to you as soon as possible.</p>
|
will get back to you as soon as possible.</p>
|
||||||
|
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>Advantages
|
<li>Advantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>Once it is set up, this is a one-click operation.</li>
|
<li>Once it is set up, this is a one-click operation.</li>
|
||||||
<li>You can read a user's workout data from the site and use
|
<li>You can read a user's workout data from the site and use
|
||||||
them in your app.</li>
|
them in your app.</li>
|
||||||
<li>This is not limited to workout data. You could make a full mobile
|
<li>This is not limited to workout data. You could make a full mobile
|
||||||
version of our site.</li>
|
version of our site.</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>Disadvantages
|
<li>Disadvantages
|
||||||
<ul class="contentli">
|
<p><ul class="contentli">
|
||||||
<li>The API is not stable and not fully tested yet.</li>
|
<li>The API is not stable and not fully tested yet.</li>
|
||||||
<li>You need to register your app with us. We can revoke your
|
<li>You need to register your app with us. We can revoke your
|
||||||
permissions if you misuse them.</li>
|
permissions if you misuse them.</li>
|
||||||
<li>The user user must grant permissions to your app.</li>
|
<li>The user user must grant permissions to your app.</li>
|
||||||
<li>You need to manage authorization tokens.</li>
|
<li>You need to manage authorization tokens.</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul></p>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_4">
|
||||||
<h2>Quick Links</h2>
|
<h2>Quick Links</h2>
|
||||||
|
|
||||||
<h3>Accepted file formats</h3>
|
<h3>Accepted file formats</h3>
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
<p>However, some rowing related parameters are not supported by TCX and FIT. Therefore, we are supporting the CSV format that is documented in the following link.</p>
|
<p>However, some rowing related parameters are not supported by TCX and FIT. Therefore, we are supporting the CSV format that is documented in the following link.</p>
|
||||||
|
|
||||||
<ul class="contentli"><li><a href="http://rowingdata.readthedocs.io/en/latest/#csv-file-standard">Our standard rowing CSV file</a></li></ul>
|
<p><ul class="contentli"><li><a href="http://rowingdata.readthedocs.io/en/latest/#csv-file-standard">Our standard rowing CSV file</a></li></ul></p>
|
||||||
|
|
||||||
<p>Using this standard will guarantee that your user's data are accepted
|
<p>Using this standard will guarantee that your user's data are accepted
|
||||||
without complaints.</p>
|
without complaints.</p>
|
||||||
@@ -129,13 +129,14 @@
|
|||||||
Developers of iOS or Android apps should contact me directly if
|
Developers of iOS or Android apps should contact me directly if
|
||||||
this doesn't work for them. I can add exceptions.</p>
|
this doesn't work for them. I can add exceptions.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
<ul class="contentli">
|
<ul class="contentli">
|
||||||
<li>Authorization URL: <b>https://{{ request.get_host }}/rowers/o/authorize</b></li>
|
<li>Authorization URL: <b>https://{{ request.get_host }}/rowers/o/authorize</b></li>
|
||||||
<li>Access Token request: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
<li>Access Token request: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
||||||
<li>Access Token refresh: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
<li>Access Token refresh: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
||||||
<li>Handy utility for testing: <b><a href="http://django-oauth-toolkit.herokuapp.com/consumer/">http://django-oauth-toolkit.herokuapp.com/consumer/</a></b></li>
|
<li>Handy utility for testing: <b><a href="http://django-oauth-toolkit.herokuapp.com/consumer/">http://django-oauth-toolkit.herokuapp.com/consumer/</a></b></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3>API documentation</h3>
|
<h3>API documentation</h3>
|
||||||
|
|
||||||
@@ -146,12 +147,14 @@
|
|||||||
<p>The workout summary data and the stroke data are obtained and sent
|
<p>The workout summary data and the stroke data are obtained and sent
|
||||||
separately.</p>
|
separately.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
<ul class="contentli">
|
<ul class="contentli">
|
||||||
<li><a href="/rowers/api-docs/">API documentation</a>
|
<li><a href="/rowers/api-docs/">API documentation</a>
|
||||||
(But refer to the below for stroke data.)</li>
|
(But refer to the below for stroke data.)</li>
|
||||||
<li><a href="/rowers/api-docs#/workouts">Try out the workout summary API</a></li>
|
|
||||||
<li><a href="/rowers/api-docs#!/workouts/strokedata_list">GET stroke data</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>POST stroke data - API</h3>
|
||||||
|
|
||||||
<p>You can only post stroke data to an existing workout with
|
<p>You can only post stroke data to an existing workout with
|
||||||
workout number {id}. If the workout already has stroke data, you
|
workout number {id}. If the workout already has stroke data, you
|
||||||
@@ -159,9 +162,13 @@
|
|||||||
future to enable updating stroke data. Stroke data for workout {id} are
|
future to enable updating stroke data. Stroke data for workout {id} are
|
||||||
posted to:</p>
|
posted to:</p>
|
||||||
|
|
||||||
|
<h4>API v1</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
<ul class="contentli">
|
<ul class="contentli">
|
||||||
<li><b>https://{{ request.get_host }}/rowers/api/workouts/{id}/strokedata</b></li>
|
<li><b>https://{{ request.get_host }}/rowers/api/workouts/{id}/strokedata</b></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>The payload is application/json data and looks as follows:</p>
|
<p>The payload is application/json data and looks as follows:</p>
|
||||||
|
|
||||||
@@ -176,14 +183,48 @@
|
|||||||
}
|
}
|
||||||
</pre></p>
|
</pre></p>
|
||||||
|
|
||||||
<p>Mandatory data fields are:</p>
|
<h4>API v2</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<ul class="contentli">
|
||||||
|
<li><b>https://{{ request.get_host }}/rowers/api/v2/workouts/{id}/strokedata</b></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The payload is application/json data and looks as follows:</p>
|
||||||
|
|
||||||
|
<p><pre>
|
||||||
|
{'data':
|
||||||
|
[
|
||||||
|
{"distance":5, "power": 112, "hr": 132, "pace": 145800, "spm": 11, "time": 0},
|
||||||
|
{"distance":12, "power": 221, "hr": 131, "pace": 116400, "spm": 41, "time": 2200},
|
||||||
|
{"distance":19, "power": 511, "hr": 131, "pace": 88100, "spm": 56, "time": 4599},
|
||||||
|
{"distance":27, "power": 673, "hr": 132, "pace": 80400, "spm": 59, "time": 7000},
|
||||||
|
{"distance":35, "power": 744, "hr": 133, "pace": 77700, "spm": 55, "time": 9599},
|
||||||
|
{"distance":43, "power": 754, "hr": 136, "pace": 77400, "spm": 48, "time": 12000},
|
||||||
|
{"distance":51, "power": 754, "hr": 139, "pace": 77400, "spm": 48, "time": 14400},
|
||||||
|
{"distance":59, "power": 749, "hr": 142, "pace": 77600, "spm": 48, "time": 16799},
|
||||||
|
{"distance":67, "power": 729, "hr": 145, "pace": 78300, "spm": 48, "time": 19400},
|
||||||
|
{"distance":75, "power": 729, "hr": 147, "pace": 78300, "spm": 48, "time": 21799},
|
||||||
|
{"distance":82, "power": 726, "hr": 150, "pace": 78400, "spm": 48, "time": 24200},
|
||||||
|
{"distance":90, "power": 709, "hr": 152, "pace": 79000, "spm": 48, "time": 26599},
|
||||||
|
{"distance":100, "power": 707, "hr": 153, "pace": 79100, "spm": 49, "time": 29000},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</pre></p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>For both v1 and v2, mandatory data fields are:</p>
|
||||||
|
<p>
|
||||||
<ul class="contentli">
|
<ul class="contentli">
|
||||||
<li><b>time</b>: Time (milliseconds since workout start)</li>
|
<li><b>time</b>: Time (milliseconds since workout start)</li>
|
||||||
<li><b>distance</b>: Distance (meters)</li>
|
<li><b>distance</b>: Distance (meters)</li>
|
||||||
<li><b>pace</b>: Pace (milliseconds per 500m)</li>
|
<li><b>pace</b>: Pace (milliseconds per 500m)</li>
|
||||||
<li><b>spm</b> Stroke rate (strokes per minute)</li>
|
<li><b>spm</b> Stroke rate (strokes per minute)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</p>
|
||||||
<p>Optional data fiels are:</p>
|
<p>Optional data fiels are:</p>
|
||||||
|
<p>
|
||||||
<ul class="contentli">
|
<ul class="contentli">
|
||||||
<li><b>power</b>: Power (Watt)</li>
|
<li><b>power</b>: Power (Watt)</li>
|
||||||
<li><b>drivelength</b>: Drive length (meters)</li>
|
<li><b>drivelength</b>: Drive length (meters)</li>
|
||||||
@@ -201,8 +242,8 @@
|
|||||||
<li><b>slip</b>: Slip as defined per Empower oarlock (degrees)</li>
|
<li><b>slip</b>: Slip as defined per Empower oarlock (degrees)</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
</p>
|
||||||
<p>Consistency checks will be done and the stroke data will be
|
<p>For both API versions, consistency checks will be done and the stroke data will be
|
||||||
refused if the mandatory data fields don't pass the checks.
|
refused if the mandatory data fields don't pass the checks.
|
||||||
All mandatory data fields
|
All mandatory data fields
|
||||||
must have the same number of records. If an optional data field
|
must have the same number of records. If an optional data field
|
||||||
@@ -216,4 +257,3 @@
|
|||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
{% include 'menu_help.html' %}
|
{% include 'menu_help.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
23
rowers/templates/strokedata_form_v2.html
Normal file
23
rowers/templates/strokedata_form_v2.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<h1>Stroke Data for workout</h1>
|
||||||
|
|
||||||
|
<form enctype="application/json" action="/rowers/api/v2/workouts/{{ id }}/strokedata/" method="post">
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<input class="button green" type="submit" value="POST">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_workout.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -210,6 +210,7 @@ urlpatterns = [
|
|||||||
re_path(r'^api-docs/$', views.schema_view,name='schema_view'),
|
re_path(r'^api-docs/$', views.schema_view,name='schema_view'),
|
||||||
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
re_path(r'^api/workouts/(?P<id>\b[0-9A-Fa-f]+\b)/strokedata/$',views.strokedatajson,name='strokedatajson'),
|
re_path(r'^api/workouts/(?P<id>\b[0-9A-Fa-f]+\b)/strokedata/$',views.strokedatajson,name='strokedatajson'),
|
||||||
|
re_path(r'^api/v2/workouts/(?P<id>\b[0-9A-Fa-f]+\b)/strokedata/$',views.strokedatajson_v2,name='strokedatajson_v2'),
|
||||||
re_path(r'^500v/$',views.error500_view,name='error500_view'),
|
re_path(r'^500v/$',views.error500_view,name='error500_view'),
|
||||||
path('502/', TemplateView.as_view(template_name='502.html'),name='502'),
|
path('502/', TemplateView.as_view(template_name='502.html'),name='502'),
|
||||||
path('500/', TemplateView.as_view(template_name='500.html'),name='500'),
|
path('500/', TemplateView.as_view(template_name='500.html'),name='500'),
|
||||||
@@ -738,6 +739,7 @@ urlpatterns = [
|
|||||||
views.TrainingTargetUpdate.as_view()),
|
views.TrainingTargetUpdate.as_view()),
|
||||||
name='trainingtarget_update_view'),
|
name='trainingtarget_update_view'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/test\_strokedata/$',views.strokedataform),
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/test\_strokedata/$',views.strokedataform),
|
||||||
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/v2/test\_strokedata/$',views.strokedataform_v2),
|
||||||
re_path(r'^sessions/teamcreate/user/(?P<userid>\d+)/$',views.plannedsession_teamcreate_view,
|
re_path(r'^sessions/teamcreate/user/(?P<userid>\d+)/$',views.plannedsession_teamcreate_view,
|
||||||
name='plannedsession_teamcreate_view'),
|
name='plannedsession_teamcreate_view'),
|
||||||
re_path(r'^sessions/teamcreate/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',
|
re_path(r'^sessions/teamcreate/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',
|
||||||
|
|||||||
@@ -40,10 +40,256 @@ def strokedataform(request,id=0):
|
|||||||
'workout':w,
|
'workout':w,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def strokedataform_v2(request,id=0):
|
||||||
|
|
||||||
|
try:
|
||||||
|
id=int(id)
|
||||||
|
except ValueError:
|
||||||
|
id = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
raise Http404("Workout doesn't exist")
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
form = StrokeDataForm()
|
||||||
|
return render(request, 'strokedata_form_v2.html',
|
||||||
|
{
|
||||||
|
'form':form,
|
||||||
|
'teams':get_my_teams(request.user),
|
||||||
|
'id':id,
|
||||||
|
'workout':w,
|
||||||
|
})
|
||||||
|
elif request.method == 'POST':
|
||||||
|
form = StrokeDataForm()
|
||||||
|
|
||||||
|
return render(request, 'strokedata_form_v2.html',
|
||||||
|
{
|
||||||
|
'form':form,
|
||||||
|
'teams':get_my_teams(request.user),
|
||||||
|
'id':id,
|
||||||
|
'workout':w,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# Process the POSTed stroke data according to the API definition
|
# Process the POSTed stroke data according to the API definition
|
||||||
# Return the GET stroke data according to the API definition
|
# Return the GET stroke data according to the API definition
|
||||||
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer
|
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
@login_required()
|
||||||
|
@api_view(["GET","POST"])
|
||||||
|
def strokedatajson_v2(request,id):
|
||||||
|
"""
|
||||||
|
POST: Add Stroke data to workout
|
||||||
|
GET: Get stroke data of workout
|
||||||
|
This v2 API works on stroke based data dict:
|
||||||
|
{"data": [{"hr": 110, "p": 3600, "spm": 53, "d": 6, "t": 12}, {"hr": 111, "p": 3600, "spm": 53, "d": 6, "t": 12}, {"hr": 111, "p": 3600, "spm": 64, "d": 6, "t": 22}, {"hr": 110, "p": 3600, "spm": 16, "d": 14, "t": 55}, {"hr": 110, "p": 3600, "spm": 16, "d": 14, "t": 82}, {"hr": 107, "p": 3600, "spm": 12, "d": 22, "t": 109}, {"hr": 107, "p": 3600, "spm": 12, "d": 22, "t": 133}, {"hr": 108, "p": 3600, "spm": 12, "d": 32, "t": 157}, {"hr": 108, "p": 3577, "spm": 12, "d": 32, "t": 157}, {"hr": 108, "p": 3411, "spm": 12, "d": 32, "t": 157}, {"hr": 108, "p": 2649, "spm": 12, "d": 32, "t": 157}, {"hr": 108, "p": 3099, "spm": 12, "d": 32, "t": 157}, {"hr": 108, "p": 3600, "spm": 12, "d": 32, "t": 157}, {"hr": 100, "p": 3600, "spm": 44, "d": 115, "t": 292}, {"hr": 99, "p": 3600, "spm": 27, "d": 129, "t": 305}, {"hr": 97, "p": 3600, "spm": 34, "d": 161, "t": 330}, {"hr": 96, "p": 3600, "spm": 25, "d": 177, "t": 344}, {"hr": 96, "p": 3494, "spm": 43, "d": 196, "t": 357}, {"hr": 98, "p": 2927, "spm": 26, "d": 235, "t": 377}, {"hr": 102, "p": 2718, "spm": 27, "d": 380, "t": 455}, {"hr": 102, "p": 2753, "spm": 9, "d": 398, "t": 472}, {"hr": 102, "p": 2864, "spm": 61, "d": 406, "t": 477}, {"hr": 101, "p": 2780, "spm": 15, "d": 484, "t": 515}, {"hr": 101, "p": 2365, "spm": 16, "d": 583, "t": 554}, {"hr": 103, "p": 1965, "spm": 16, "d": 681, "t": 592}, {"hr": 104, "
|
||||||
|
"""
|
||||||
|
|
||||||
|
row = get_object_or_404(Workout,pk=id)
|
||||||
|
if row.user != request.user.rower:
|
||||||
|
raise PermissionDenied("You have no access to this workout")
|
||||||
|
|
||||||
|
try:
|
||||||
|
id = int(id)
|
||||||
|
except ValueError:
|
||||||
|
return HttpResponse("Not a valid workout number",stauts=400)
|
||||||
|
|
||||||
|
if request.method == 'GET':
|
||||||
|
columns = ['spm','time','hr','pace','power','distance']
|
||||||
|
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
|
||||||
|
with open('media/apilog.log','a') as logfile:
|
||||||
|
logfile.write(str(timezone.now())+": ")
|
||||||
|
logfile.write(request.user.username+"(GET) \n")
|
||||||
|
|
||||||
|
data = datadf.to_json(orient='records')
|
||||||
|
|
||||||
|
return JSONResponse(data)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
checkdata, r = dataprep.getrowdata_db(id=row.id)
|
||||||
|
if not checkdata.empty:
|
||||||
|
return HttpResponse("Duplicate Error",400)
|
||||||
|
|
||||||
|
df = pd.DataFrame()
|
||||||
|
|
||||||
|
try:
|
||||||
|
df = pd.read_json(request.POST['data'],orient='split')
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
df = pd.read_json(request.POST['strokedata'],orient='split')
|
||||||
|
except:
|
||||||
|
return HttpResponse("No JSON object could be decoded",400)
|
||||||
|
|
||||||
|
df.index = df.index.astype(int)
|
||||||
|
df.sort_index(inplace=True)
|
||||||
|
|
||||||
|
#time, pace, distance,spm
|
||||||
|
try:
|
||||||
|
time = df['time']/1.e3
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
time = df['t']/10.
|
||||||
|
except KeyError:
|
||||||
|
return HttpResponse("Missing time",400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
spm = df['spm']
|
||||||
|
except KeyError:
|
||||||
|
return HttpResponse("Missing spm",400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
distance = df['distance']
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
distance = df['d']/10.
|
||||||
|
except KeyError:
|
||||||
|
return HttpResponse("Missing distance",400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pace = df['pace']/1.e3
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
pace = df['p']/10.
|
||||||
|
except KeyError:
|
||||||
|
return HttpResponse("Missing pace",400)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
power = df['power']
|
||||||
|
except KeyError:
|
||||||
|
power = 0*time
|
||||||
|
try:
|
||||||
|
drivelength = df['drivelength']
|
||||||
|
except KeyError:
|
||||||
|
drivelength = 0*time
|
||||||
|
try:
|
||||||
|
drivespeed = df['drivespeed']
|
||||||
|
except KeyError:
|
||||||
|
drivespeed = 0*time
|
||||||
|
try:
|
||||||
|
dragfactor = df['dragfactor']
|
||||||
|
except KeyError:
|
||||||
|
dragfactor = 0*time
|
||||||
|
try:
|
||||||
|
drivetime = df['drivetime']
|
||||||
|
except KeyError:
|
||||||
|
drivetime = 0*time
|
||||||
|
try:
|
||||||
|
strokerecoverytime = df['strokerecoverytime']
|
||||||
|
except KeyError:
|
||||||
|
strokerecoverytime = 0*time
|
||||||
|
try:
|
||||||
|
averagedriveforce = df['averagedriveforce']
|
||||||
|
except KeyError:
|
||||||
|
averagedriveforce = 0*time
|
||||||
|
try:
|
||||||
|
peakdriveforce = df['peakdriveforce']
|
||||||
|
except KeyError:
|
||||||
|
peakdriveforce = 0*time
|
||||||
|
try:
|
||||||
|
wash = df['wash']
|
||||||
|
except KeyError:
|
||||||
|
wash = 0*time
|
||||||
|
try:
|
||||||
|
catch = df['catch']
|
||||||
|
except KeyError:
|
||||||
|
catch = 0*time
|
||||||
|
try:
|
||||||
|
finish = df['finish']
|
||||||
|
except KeyError:
|
||||||
|
finish = 0*time
|
||||||
|
try:
|
||||||
|
peakforceangle = df['peakforceangle']
|
||||||
|
except KeyError:
|
||||||
|
peakforceangle = 0*time
|
||||||
|
try:
|
||||||
|
driveenergy = df['driveenergy']
|
||||||
|
except KeyError:
|
||||||
|
driveenergy = 60.*power/spm
|
||||||
|
try:
|
||||||
|
slip = df['slip']
|
||||||
|
except KeyError:
|
||||||
|
slip = 0*time
|
||||||
|
try:
|
||||||
|
lapidx = df['lapidx']
|
||||||
|
except KeyError:
|
||||||
|
lapidx = 0*time
|
||||||
|
try:
|
||||||
|
hr = df['hr']
|
||||||
|
except KeyError:
|
||||||
|
hr = 0*df['time']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
starttime = totimestamp(row.startdatetime)+time[0]
|
||||||
|
unixtime = starttime+time
|
||||||
|
|
||||||
|
with open('media/apilog.log','a') as logfile:
|
||||||
|
logfile.write(str(starttime)+": ")
|
||||||
|
logfile.write(request.user.username+"(POST) \r\n")
|
||||||
|
|
||||||
|
|
||||||
|
data = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||||
|
' Horizontal (meters)': distance,
|
||||||
|
' Cadence (stokes/min)':spm,
|
||||||
|
' HRCur (bpm)':hr,
|
||||||
|
' DragFactor':dragfactor,
|
||||||
|
' Stroke500mPace (sec/500m)':pace,
|
||||||
|
' Power (watts)':power,
|
||||||
|
' DriveLength (meters)':drivelength,
|
||||||
|
' DriveTime (ms)':drivetime,
|
||||||
|
' StrokeRecoveryTime (ms)':strokerecoverytime,
|
||||||
|
' AverageDriveForce (lbs)':averagedriveforce,
|
||||||
|
' PeakDriveForce (lbs)':peakdriveforce,
|
||||||
|
' lapIdx':lapidx,
|
||||||
|
' ElapsedTime (sec)':time,
|
||||||
|
'catch':catch,
|
||||||
|
'slip':slip,
|
||||||
|
'finish':finish,
|
||||||
|
'wash':wash,
|
||||||
|
'driveenergy':driveenergy,
|
||||||
|
'peakforceangle':peakforceangle,
|
||||||
|
})
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
|
||||||
|
timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
|
||||||
|
csvfilename ='media/Import_'+timestr+'.csv'
|
||||||
|
|
||||||
|
res = data.to_csv(csvfilename+'.gz',index_label='index',
|
||||||
|
compression='gzip')
|
||||||
|
row.csvfilename = csvfilename
|
||||||
|
row.save()
|
||||||
|
|
||||||
|
powerperc = 100*np.array([r.pw_ut2,
|
||||||
|
r.pw_ut1,
|
||||||
|
r.pw_at,
|
||||||
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if row.workouttype in mytypes.otwtypes:
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
|
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||||
|
hrut1=r.ut1,hrat=r.at,
|
||||||
|
hrtr=r.tr,hran=r.an,ftp=ftp,
|
||||||
|
powerperc=powerperc,powerzones=r.powerzones)
|
||||||
|
rowdata = rdata(row.csvfilename,rower=rr).df
|
||||||
|
|
||||||
|
datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True,empower=True)
|
||||||
|
|
||||||
|
|
||||||
|
return(HttpResponse(encoder.encode_hex(row.id),status=201))
|
||||||
|
|
||||||
|
return HttpResponseNotAllowed("Method not supported")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@login_required()
|
@login_required()
|
||||||
@api_view(['GET','POST'])
|
@api_view(['GET','POST'])
|
||||||
@@ -182,7 +428,7 @@ def strokedatajson(request,id):
|
|||||||
# mangling
|
# mangling
|
||||||
|
|
||||||
#
|
#
|
||||||
return HttpResponse(row.id,status=201)
|
return HttpResponse(encoder.encode_hex(row.id),status=201)
|
||||||
|
|
||||||
#Method not supported
|
#Method not supported
|
||||||
return HttpResponseNotAllowed("Method not supported")
|
return HttpResponseNotAllowed("Method not supported")
|
||||||
|
|||||||
Reference in New Issue
Block a user