Finishing light comments and cleanup
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
# All the functionality to connect to SportTracks
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
import cgi
|
import cgi
|
||||||
@@ -31,6 +33,8 @@ from rowers.models import Rower,Workout
|
|||||||
|
|
||||||
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
|
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
|
||||||
|
|
||||||
|
# Custom exception handler, returns a 401 HTTP message
|
||||||
|
# with exception details in the json data
|
||||||
def custom_exception_handler(exc,message):
|
def custom_exception_handler(exc,message):
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
@@ -48,6 +52,7 @@ def custom_exception_handler(exc,message):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
# Refresh ST token using refresh token
|
||||||
def do_refresh_token(refreshtoken):
|
def do_refresh_token(refreshtoken):
|
||||||
client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
|
client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
|
||||||
post_data = {"grant_type": "refresh_token",
|
post_data = {"grant_type": "refresh_token",
|
||||||
@@ -75,7 +80,7 @@ def do_refresh_token(refreshtoken):
|
|||||||
|
|
||||||
return [thetoken,expires_in,refresh_token]
|
return [thetoken,expires_in,refresh_token]
|
||||||
|
|
||||||
|
# Exchange ST access code for long-lived ST access token
|
||||||
def get_token(code):
|
def get_token(code):
|
||||||
client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
|
client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
|
||||||
post_data = {"grant_type": "authorization_code",
|
post_data = {"grant_type": "authorization_code",
|
||||||
@@ -100,6 +105,7 @@ def get_token(code):
|
|||||||
|
|
||||||
return [thetoken,expires_in,refresh_token]
|
return [thetoken,expires_in,refresh_token]
|
||||||
|
|
||||||
|
# Make authorization URL including random string
|
||||||
def make_authorization_url(request):
|
def make_authorization_url(request):
|
||||||
# Generate a random string for the state parameter
|
# Generate a random string for the state parameter
|
||||||
# Save it for use later to prevent xsrf attacks
|
# Save it for use later to prevent xsrf attacks
|
||||||
@@ -118,7 +124,7 @@ def make_authorization_url(request):
|
|||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# This is token refresh. Looks for tokens in our database, then refreshes
|
||||||
def rower_sporttracks_token_refresh(user):
|
def rower_sporttracks_token_refresh(user):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
res = do_refresh_token(r.sporttracksrefreshtoken)
|
res = do_refresh_token(r.sporttracksrefreshtoken)
|
||||||
@@ -135,6 +141,7 @@ def rower_sporttracks_token_refresh(user):
|
|||||||
r.save()
|
r.save()
|
||||||
return r.sporttrackstoken
|
return r.sporttrackstoken
|
||||||
|
|
||||||
|
# Get list of workouts available on SportTracks
|
||||||
def get_sporttracks_workout_list(user):
|
def get_sporttracks_workout_list(user):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
||||||
@@ -154,7 +161,7 @@ def get_sporttracks_workout_list(user):
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
# Get workout summary data by SportTracks ID
|
||||||
def get_sporttracks_workout(user,sporttracksid):
|
def get_sporttracks_workout(user,sporttracksid):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
||||||
@@ -174,6 +181,7 @@ def get_sporttracks_workout(user,sporttracksid):
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
# Create Workout Data for upload to SportTracks
|
||||||
def createsporttracksworkoutdata(w):
|
def createsporttracksworkoutdata(w):
|
||||||
filename = w.csvfilename
|
filename = w.csvfilename
|
||||||
try:
|
try:
|
||||||
@@ -272,6 +280,8 @@ def createsporttracksworkoutdata(w):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
# Obtain SportTracks Workout ID from the response returned on successful
|
||||||
|
# upload
|
||||||
def getidfromresponse(response):
|
def getidfromresponse(response):
|
||||||
t = json.loads(response.text)
|
t = json.loads(response.text)
|
||||||
uri = t['uris'][0]
|
uri = t['uris'][0]
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# All the functionality needed to connect to Strava
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
import oauth2 as oauth
|
import oauth2 as oauth
|
||||||
import cgi
|
import cgi
|
||||||
@@ -30,6 +32,9 @@ import stravalib
|
|||||||
|
|
||||||
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
|
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
|
||||||
|
|
||||||
|
# Exponentially weighted moving average
|
||||||
|
# Used for data smoothing of the jagged data obtained by Strava
|
||||||
|
# See bitbucket issue 72
|
||||||
def ewmovingaverage(interval,window_size):
|
def ewmovingaverage(interval,window_size):
|
||||||
# Experimental code using Exponential Weighted moving average
|
# Experimental code using Exponential Weighted moving average
|
||||||
|
|
||||||
@@ -45,45 +50,11 @@ def ewmovingaverage(interval,window_size):
|
|||||||
|
|
||||||
return interval2
|
return interval2
|
||||||
|
|
||||||
def geo_distance(lat1,lon1,lat2,lon2):
|
from utils import geo_distance
|
||||||
""" Approximate distance and bearing between two points
|
|
||||||
defined by lat1,lon1 and lat2,lon2
|
|
||||||
This is a slight underestimate but is close enough for our purposes,
|
|
||||||
We're never moving more than 10 meters between trackpoints
|
|
||||||
|
|
||||||
Bearing calculation fails if one of the points is a pole.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# radius of earth in km
|
|
||||||
R = 6373.0
|
|
||||||
|
|
||||||
# pi
|
|
||||||
pi = math.pi
|
|
||||||
|
|
||||||
lat1 = math.radians(lat1)
|
|
||||||
lat2 = math.radians(lat2)
|
|
||||||
lon1 = math.radians(lon1)
|
|
||||||
lon2 = math.radians(lon2)
|
|
||||||
|
|
||||||
dlon = lon2 - lon1
|
|
||||||
dlat = lat2 - lat1
|
|
||||||
|
|
||||||
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
|
|
||||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
|
||||||
|
|
||||||
distance = R * c
|
|
||||||
|
|
||||||
tc1 = atan2(sin(lon2-lon1)*cos(lat2),
|
|
||||||
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
|
|
||||||
|
|
||||||
tc1 = tc1 % (2*pi)
|
|
||||||
|
|
||||||
bearing = math.degrees(tc1)
|
|
||||||
|
|
||||||
return [distance,bearing]
|
|
||||||
|
|
||||||
|
|
||||||
|
# Custom exception handler, returns a 401 HTTP message
|
||||||
|
# with exception details in the json data
|
||||||
def custom_exception_handler(exc,message):
|
def custom_exception_handler(exc,message):
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
@@ -101,6 +72,7 @@ def custom_exception_handler(exc,message):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
# Exchange access code for long-lived access token
|
||||||
def get_token(code):
|
def get_token(code):
|
||||||
client_auth = requests.auth.HTTPBasicAuth(STRAVA_CLIENT_ID, STRAVA_CLIENT_SECRET)
|
client_auth = requests.auth.HTTPBasicAuth(STRAVA_CLIENT_ID, STRAVA_CLIENT_SECRET)
|
||||||
post_data = {"grant_type": "authorization_code",
|
post_data = {"grant_type": "authorization_code",
|
||||||
@@ -118,7 +90,7 @@ def get_token(code):
|
|||||||
|
|
||||||
return [thetoken]
|
return [thetoken]
|
||||||
|
|
||||||
|
# Make authorization URL including random string
|
||||||
def make_authorization_url(request):
|
def make_authorization_url(request):
|
||||||
# Generate a random string for the state parameter
|
# Generate a random string for the state parameter
|
||||||
# Save it for use later to prevent xsrf attacks
|
# Save it for use later to prevent xsrf attacks
|
||||||
@@ -134,6 +106,7 @@ def make_authorization_url(request):
|
|||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# Get list of workouts available on Strava
|
||||||
def get_strava_workout_list(user):
|
def get_strava_workout_list(user):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||||
@@ -150,6 +123,7 @@ def get_strava_workout_list(user):
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
# Get a Strava workout summary data and stroke data by ID
|
||||||
def get_strava_workout(user,stravaid):
|
def get_strava_workout(user,stravaid):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||||
@@ -236,6 +210,7 @@ def get_strava_workout(user,stravaid):
|
|||||||
|
|
||||||
return [workoutsummary,df]
|
return [workoutsummary,df]
|
||||||
|
|
||||||
|
# Generate Workout data for Strava (a TCX file)
|
||||||
def createstravaworkoutdata(w):
|
def createstravaworkoutdata(w):
|
||||||
filename = w.csvfilename
|
filename = w.csvfilename
|
||||||
try:
|
try:
|
||||||
@@ -247,6 +222,8 @@ def createstravaworkoutdata(w):
|
|||||||
|
|
||||||
return tcxfilename
|
return tcxfilename
|
||||||
|
|
||||||
|
# Upload the TCX file to Strava and set the workout activity type
|
||||||
|
# to rowing on Strava
|
||||||
def handle_stravaexport(file,workoutname,stravatoken,description=''):
|
def handle_stravaexport(file,workoutname,stravatoken,description=''):
|
||||||
# w = Workout.objects.get(id=workoutid)
|
# w = Workout.objects.get(id=workoutid)
|
||||||
client = stravalib.Client(access_token=stravatoken)
|
client = stravalib.Client(access_token=stravatoken)
|
||||||
@@ -264,12 +241,6 @@ def handle_stravaexport(file,workoutname,stravatoken,description=''):
|
|||||||
errorlog.write(timestr+errorstring+"\r\n")
|
errorlog.write(timestr+errorstring+"\r\n")
|
||||||
errorlog.write("stravastuff.py line 262\r\n")
|
errorlog.write("stravastuff.py line 262\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# w.uploadedtostrava = res.id
|
|
||||||
# w.save()
|
|
||||||
# file.close()
|
|
||||||
|
|
||||||
return res.id
|
return res.id
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
42
rowers/utils.py
Normal file
42
rowers/utils.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
def geo_distance(lat1,lon1,lat2,lon2):
|
||||||
|
""" Approximate distance and bearing between two points
|
||||||
|
defined by lat1,lon1 and lat2,lon2
|
||||||
|
This is a slight underestimate but is close enough for our purposes,
|
||||||
|
We're never moving more than 10 meters between trackpoints
|
||||||
|
|
||||||
|
Bearing calculation fails if one of the points is a pole.
|
||||||
|
(Hey, from the North pole you can walk South, East, North and end up
|
||||||
|
on the same spot!)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# radius of our earth in km --> should be moved to settings if
|
||||||
|
# rowing takes off on other planets
|
||||||
|
R = 6373.0
|
||||||
|
|
||||||
|
# pi
|
||||||
|
pi = math.pi
|
||||||
|
|
||||||
|
lat1 = math.radians(lat1)
|
||||||
|
lat2 = math.radians(lat2)
|
||||||
|
lon1 = math.radians(lon1)
|
||||||
|
lon2 = math.radians(lon2)
|
||||||
|
|
||||||
|
dlon = lon2 - lon1
|
||||||
|
dlat = lat2 - lat1
|
||||||
|
|
||||||
|
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
|
||||||
|
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||||
|
|
||||||
|
distance = R * c
|
||||||
|
|
||||||
|
tc1 = atan2(sin(lon2-lon1)*cos(lat2),
|
||||||
|
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
|
||||||
|
|
||||||
|
tc1 = tc1 % (2*pi)
|
||||||
|
|
||||||
|
bearing = math.degrees(tc1)
|
||||||
|
|
||||||
|
return [distance,bearing]
|
||||||
@@ -189,47 +189,7 @@ def splitstdata(lijst):
|
|||||||
|
|
||||||
return [np.array(t),np.array(latlong)]
|
return [np.array(t),np.array(latlong)]
|
||||||
|
|
||||||
|
from utils import geo_distance
|
||||||
def geo_distance(lat1,lon1,lat2,lon2):
|
|
||||||
""" Approximate distance and bearing between two points
|
|
||||||
defined by lat1,lon1 and lat2,lon2
|
|
||||||
This is a slight underestimate but is close enough for our purposes,
|
|
||||||
We're never moving more than 10 meters between trackpoints
|
|
||||||
|
|
||||||
Bearing calculation fails if one of the points is a pole.
|
|
||||||
(Hey, from the North pole you can walk South, East, North and end up
|
|
||||||
on the same spot!)
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# radius of our earth in km --> should be moved to settings if
|
|
||||||
# rowing takes off on other planets
|
|
||||||
R = 6373.0
|
|
||||||
|
|
||||||
# pi
|
|
||||||
pi = math.pi
|
|
||||||
|
|
||||||
lat1 = math.radians(lat1)
|
|
||||||
lat2 = math.radians(lat2)
|
|
||||||
lon1 = math.radians(lon1)
|
|
||||||
lon2 = math.radians(lon2)
|
|
||||||
|
|
||||||
dlon = lon2 - lon1
|
|
||||||
dlat = lat2 - lat1
|
|
||||||
|
|
||||||
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
|
|
||||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
|
||||||
|
|
||||||
distance = R * c
|
|
||||||
|
|
||||||
tc1 = atan2(sin(lon2-lon1)*cos(lat2),
|
|
||||||
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
|
|
||||||
|
|
||||||
tc1 = tc1 % (2*pi)
|
|
||||||
|
|
||||||
bearing = math.degrees(tc1)
|
|
||||||
|
|
||||||
return [distance,bearing]
|
|
||||||
|
|
||||||
# Check if a user is a Pro member
|
# Check if a user is a Pro member
|
||||||
def promember(user):
|
def promember(user):
|
||||||
|
|||||||
Reference in New Issue
Block a user