Merge branch 'feature/stravawebhooks' into develop
This commit is contained in:
@@ -849,6 +849,7 @@ class Rower(models.Model):
|
|||||||
max_length=30,
|
max_length=30,
|
||||||
choices=stravatypes,
|
choices=stravatypes,
|
||||||
verbose_name="Export Workouts to Strava as")
|
verbose_name="Export Workouts to Strava as")
|
||||||
|
strava_owner_id = models.BigIntegerField(default=0)
|
||||||
|
|
||||||
strava_auto_export = models.BooleanField(default=False)
|
strava_auto_export = models.BooleanField(default=False)
|
||||||
strava_auto_import = models.BooleanField(default=False)
|
strava_auto_import = models.BooleanField(default=False)
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ from rowers.tasks import handle_strava_sync
|
|||||||
|
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
|
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
||||||
|
SITE_URL
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -43,6 +44,9 @@ except ImportError:
|
|||||||
|
|
||||||
from rowers.imports import *
|
from rowers.imports import *
|
||||||
|
|
||||||
|
webhookverification = "kudos_to_rowing"
|
||||||
|
webhooklink = SITE_URL+'/rowers/strava/webhooks/'
|
||||||
|
|
||||||
headers = {'Accept': 'application/json',
|
headers = {'Accept': 'application/json',
|
||||||
'Api-Key': STRAVA_CLIENT_ID,
|
'Api-Key': STRAVA_CLIENT_ID,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -71,6 +75,8 @@ def get_token(code):
|
|||||||
return imports_get_token(code, oauth_data)
|
return imports_get_token(code, oauth_data)
|
||||||
|
|
||||||
def strava_open(user):
|
def strava_open(user):
|
||||||
|
if user.rower.strava_owner_id == 0:
|
||||||
|
strava_owner_id = set_strava_athlete_id(user)
|
||||||
return imports_open(user, oauth_data)
|
return imports_open(user, oauth_data)
|
||||||
|
|
||||||
def do_refresh_token(refreshtoken):
|
def do_refresh_token(refreshtoken):
|
||||||
@@ -95,6 +101,48 @@ def rower_strava_token_refresh(user):
|
|||||||
def make_authorization_url(request):
|
def make_authorization_url(request):
|
||||||
return imports_make_authorization_url(oauth_data)
|
return imports_make_authorization_url(oauth_data)
|
||||||
|
|
||||||
|
def strava_establish_push():
|
||||||
|
url = "https://www.strava.com/api/v3/push_subscriptions"
|
||||||
|
post_data = {
|
||||||
|
'client_id': STRAVA_CLIENT_ID,
|
||||||
|
'client_secret': STRAVA_CLIENT_SECRET,
|
||||||
|
'callback_url': webhooklink,
|
||||||
|
'verify_token': webhookverification,
|
||||||
|
}
|
||||||
|
headers = {'user-agent': 'sanderroosendaal',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': oauth_data['content_type']}
|
||||||
|
|
||||||
|
response = requests.post(url,data=post_data)
|
||||||
|
|
||||||
|
print(response.json())
|
||||||
|
|
||||||
|
return response.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def set_strava_athlete_id(user):
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||||
|
s = "Token doesn't exist. Need to authorize"
|
||||||
|
return custom_exception_handler(401,s)
|
||||||
|
elif (r.stravatokenexpirydate is None or timezone.now()+timedelta(seconds=3599)>r.stravatokenexpirydate):
|
||||||
|
s = "Token expired. Needs to refresh."
|
||||||
|
return custom_exception_handler(401,s)
|
||||||
|
else:
|
||||||
|
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||||
|
headers = {'Authorization': authorizationstring,
|
||||||
|
'user-agent': 'sanderroosendaal',
|
||||||
|
'Content-Type': 'application/json'}
|
||||||
|
url = "https://www.strava.com/api/v3/athlete"
|
||||||
|
|
||||||
|
response = requests.get(url,headers=headers,params={})
|
||||||
|
|
||||||
|
r.strava_owner_id = response.json()['id']
|
||||||
|
r.save()
|
||||||
|
|
||||||
|
return response.json()['id']
|
||||||
|
|
||||||
|
|
||||||
# Get list of workouts available on Strava
|
# Get list of workouts available on Strava
|
||||||
def get_strava_workout_list(user,limit_n=0):
|
def get_strava_workout_list(user,limit_n=0):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
|
|||||||
@@ -606,6 +606,8 @@ def mocked_requests(*args, **kwargs):
|
|||||||
uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r'))
|
uastrokesjson = json.load(open('rowers/tests/testdata/uastrokes.txt','r'))
|
||||||
uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r'))
|
uauserjson = json.load(open('rowers/tests/testdata/uauser.txt','r'))
|
||||||
|
|
||||||
|
stravaathletejson = json.load(open('rowers/tests/testdata/strava_athlete.txt'))
|
||||||
|
|
||||||
class MockResponse:
|
class MockResponse:
|
||||||
def __init__(self, json_data, status_code):
|
def __init__(self, json_data, status_code):
|
||||||
self.json_data = json_data
|
self.json_data = json_data
|
||||||
@@ -660,6 +662,10 @@ def mocked_requests(*args, **kwargs):
|
|||||||
c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d'
|
c2workoutlistregex = '.*?concept2\.com\/api\/users\/me\/results\?page=\d'
|
||||||
c2workoutlisttester = re.compile(c2workoutlistregex)
|
c2workoutlisttester = re.compile(c2workoutlistregex)
|
||||||
|
|
||||||
|
stravaathleteregex = '.*?strava\.com\/api\/v3\/athlete$'
|
||||||
|
stravaathletetester = re.compile(stravaathleteregex)
|
||||||
|
|
||||||
|
|
||||||
stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities'
|
stravaworkoutlistregex = '.*?strava\.com\/api\/v3\/athlete\/activities'
|
||||||
stravaworkoutlisttester = re.compile(stravaworkoutlistregex)
|
stravaworkoutlisttester = re.compile(stravaworkoutlistregex)
|
||||||
|
|
||||||
@@ -703,6 +709,10 @@ def mocked_requests(*args, **kwargs):
|
|||||||
tpuploadregex = '.*?trainingpeaks\.com\/v1\/file'
|
tpuploadregex = '.*?trainingpeaks\.com\/v1\/file'
|
||||||
tpuploadtester = re.compile(tpuploadregex)
|
tpuploadtester = re.compile(tpuploadregex)
|
||||||
|
|
||||||
|
if stravaathletetester.match(args[0]):
|
||||||
|
json_data = stravaathletejson
|
||||||
|
return MockResponse(json_data,200)
|
||||||
|
|
||||||
if polartester.match(args[0]):
|
if polartester.match(args[0]):
|
||||||
json_data = polar_json
|
json_data = polar_json
|
||||||
return MockResponse(json_data,200)
|
return MockResponse(json_data,200)
|
||||||
|
|||||||
1
rowers/tests/testdata/strava_athlete.txt
vendored
Normal file
1
rowers/tests/testdata/strava_athlete.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id": 47155909, "username": null, "resource_state": 2, "firstname": "Rowsandall", "lastname": "Testing", "city": "Zliv", "state": "Jiho\u010desk\u00fd kraj", "country": "Czechia", "sex": "M", "premium": false, "summit": false, "created_at": "2019-10-06T06:59:54Z", "updated_at": "2020-05-15T11:52:33Z", "badge_type_id": 0, "profile_medium": "avatar/athlete/medium.png", "profile": "avatar/athlete/large.png", "friend": null, "follower": null}
|
||||||
@@ -417,6 +417,7 @@ urlpatterns = [
|
|||||||
re_path(r'^workout/(?P<pk>\b[0-9A-Fa-f]+\b)/delete/$',login_required(
|
re_path(r'^workout/(?P<pk>\b[0-9A-Fa-f]+\b)/delete/$',login_required(
|
||||||
views.WorkoutDelete.as_view()),
|
views.WorkoutDelete.as_view()),
|
||||||
name='workout_delete'),
|
name='workout_delete'),
|
||||||
|
re_path(r'^strava/webhooks/',views.strava_webhook_view,name='strava_webhook_view'),
|
||||||
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/files/',views.garmin_newfiles_ping,name='garmin_newfiles_ping'),
|
re_path(r'^garmin/files/',views.garmin_newfiles_ping,name='garmin_newfiles_ping'),
|
||||||
re_path(r'^garmin/activities/',views.garmin_details_view,name='garmin_details_view'),
|
re_path(r'^garmin/activities/',views.garmin_details_view,name='garmin_details_view'),
|
||||||
|
|||||||
@@ -1008,6 +1008,19 @@ def workout_stravaimport_view(request,message="",userid=0):
|
|||||||
|
|
||||||
return HttpResponse(res)
|
return HttpResponse(res)
|
||||||
|
|
||||||
|
# for Strava webhook request validation
|
||||||
|
def strava_webhook_view(request):
|
||||||
|
if request.method == 'GET':
|
||||||
|
challenge = request.GET.get('hub.challenge')
|
||||||
|
verificationtoken = request.GET.get('hub.verify_token')
|
||||||
|
if verificationtoken != stravastuff.webhookverification:
|
||||||
|
return HttpResponse(status=403)
|
||||||
|
data = {"hub.challenge":challenge}
|
||||||
|
return JSONResponse(data)
|
||||||
|
|
||||||
|
# POST - does nothing so far
|
||||||
|
return HttpResponse(status=200)
|
||||||
|
|
||||||
# For push notifications from Garmin
|
# For push notifications from Garmin
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def garmin_summaries_view(request):
|
def garmin_summaries_view(request):
|
||||||
|
|||||||
Reference in New Issue
Block a user