From 6cedb7b5dbee654c8c556967288ec51fb809dd64 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 26 Jan 2021 20:26:51 +0100
Subject: [PATCH] rp3 auth working
---
rowers/rp3stuff.py | 16 ++++++------
rowers/templates/rower_exportsettings.html | 9 +++++--
rowers/urls.py | 1 +
rowers/views/importviews.py | 28 ++++++++++++++++++---
rowers/views/statements.py | 2 ++
static/img/logo-rp3-full-black.png | Bin 0 -> 14279 bytes
6 files changed, 43 insertions(+), 13 deletions(-)
create mode 100644 static/img/logo-rp3-full-black.png
diff --git a/rowers/rp3stuff.py b/rowers/rp3stuff.py
index 233e059d..02569b48 100644
--- a/rowers/rp3stuff.py
+++ b/rowers/rp3stuff.py
@@ -16,8 +16,8 @@ from io import BytesIO
from rowsandall_app.settings import (
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
- rp3_CLIENT_ID, rp3_CLIENT_SECRET,
- rp3_REDIRECT_URI,rp3_CLIENT_KEY,
+ RP3_CLIENT_ID, RP3_CLIENT_SECRET,
+ RP3_REDIRECT_URI,RP3_CLIENT_KEY,
RP3_CLIENT_ID, RP3_CLIENT_KEY, RP3_REDIRECT_URI, RP3_CLIENT_SECRET
)
@@ -56,23 +56,25 @@ def do_refresh_token(refreshtoken):
# Exchange access code for long-lived access token
def get_token(code):
- client_auth = requests.auth.HTTPBasicAuth(rp3_CLIENT_KEY, rp3_CLIENT_SECRET)
+ client_auth = requests.auth.HTTPBasicAuth(RP3_CLIENT_KEY, RP3_CLIENT_SECRET)
post_data = {
- "client_id":rp3_CLIENT_KEY,
+ "client_id":RP3_CLIENT_KEY,
"grant_type": "authorization_code",
"code": code,
- "redirect_uri":rp3_REDIRECT_URI,
- "client_secret": rp3_CLIENT_SECRET,
+ "redirect_uri":RP3_REDIRECT_URI,
+ "client_secret": RP3_CLIENT_SECRET,
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
response = requests.post(
- "https://oauth.trainingpeaks.com/oauth/token",
+ "https://rp3rowing-app.com/oauth/token",
data=post_data,verify=False,
)
+ print(response.json())
+
try:
token_json = response.json()
diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html
index 25bfe659..81179cb4 100644
--- a/rowers/templates/rower_exportsettings.html
+++ b/rowers/templates/rower_exportsettings.html
@@ -30,7 +30,10 @@
Strava,
{% endif %}
{% if rower.runkeepertoken is not None and rower.runkeepertoken != '' %}
- Runkeeper.
+ Runkeeper,
+ {% endif %}
+ {% if rower.rp3token is not None and rower.rp3token != '' %}
+ RP3
{% endif %}
@@ -77,7 +80,9 @@
alt="connect with Polar" width="130">

+ alt="connect with Garmin" width="130">
+ 
{% endblock %}
diff --git a/rowers/urls.py b/rowers/urls.py
index 3314730a..d33b5393 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -649,6 +649,7 @@ urlpatterns = [
re_path(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize,name='rower_sporttracks_authorize'),
re_path(r'^me/underarmourauthorize/$',views.rower_underarmour_authorize,name='rower_underarmour_authorize'),
re_path(r'^me/tpauthorize/$',views.rower_tp_authorize,name='rower_tp_authorize'),
+ re_path(r'^me/rp3authorize/$',views.rower_rp3_authorize,name='rower_rp3_authorize'),
re_path(r'^me/runkeeperauthorize/$',views.rower_runkeeper_authorize,name='rower_runkeeper_authorize'),
re_path(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh,name='rower_sporttracks_token_refresh'),
re_path(r'^me/underarmourrefresh/$',views.rower_underarmour_token_refresh,name='rower_underarmoud_token_refresh'),
diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py
index e7fce5cd..de8994f8 100644
--- a/rowers/views/importviews.py
+++ b/rowers/views/importviews.py
@@ -497,6 +497,21 @@ def rower_underarmour_authorize(request):
return HttpResponseRedirect(url)
+# Underarmour Authorization
+@login_required()
+def rower_rp3_authorize(request):
+ # Generate a random string for the state parameter
+ # Save it for use later to prevent xsrf attacks
+
+ state = str(uuid4())
+ params = {"client_id": RP3_CLIENT_KEY,
+ "response_type": "code",
+ "redirect_uri": RP3_REDIRECT_URI,
+ }
+ url = "https://rp3rowing-app.com/oauth/authorize/?" +urllib.parse.urlencode(params)
+
+ return HttpResponseRedirect(url)
+
# Underarmour Authorization
@login_required()
def rower_tp_authorize(request):
@@ -874,7 +889,7 @@ def rower_process_rp3callback(request):
url = reverse('rower_exportsettings_view')
return HttpResponseRedirect(url)
- res = tpstuff.get_token(code)
+ res = rp3stuff.get_token(code)
access_token = res[0]
expires_in = res[1]
@@ -882,12 +897,17 @@ def rower_process_rp3callback(request):
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
r = getrower(request.user)
- r.tptoken = access_token
- r.tptokenexpirydate = expirydatetime
- r.tprefreshtoken = refresh_token
+ r.rp3token = access_token
+ r.rp3tokenexpirydate = expirydatetime
+ r.rp3refreshtoken = refresh_token
r.save()
+ successmessage = "Tokens stored. Good to go. Please check your import/export settings"
+ messages.info(request,successmessage)
+ url = reverse('rower_exportsettings_view')
+ return HttpResponseRedirect(url)
+
# Process TrainingPeaks callback
@login_required()
def rower_process_tpcallback(request):
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index 409dab68..f6eb7cdb 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -167,6 +167,7 @@ import rowers.underarmourstuff as underarmourstuff
from rowers.underarmourstuff import underarmour_open
import rowers.tpstuff as tpstuff
import rowers.runkeeperstuff as runkeeperstuff
+import rowers.rp3stuff as rp3stuff
import rowers.ownapistuff as ownapistuff
from rowers.ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
from rowsandall_app.settings import (
@@ -179,6 +180,7 @@ from rowsandall_app.settings import (
UNDERARMOUR_CLIENT_SECRET,UNDERARMOUR_CLIENT_KEY,
RUNKEEPER_CLIENT_ID,RUNKEEPER_REDIRECT_URI,RUNKEEPER_CLIENT_SECRET,
TP_CLIENT_ID,TP_REDIRECT_URI,TP_CLIENT_KEY,TP_CLIENT_SECRET,
+ RP3_CLIENT_ID,RP3_REDIRECT_URI,RP3_CLIENT_KEY,RP3_CLIENT_SECRET,
BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY,
PAYMENT_PROCESSING_ON,
RECAPTCHA_SITE_KEY, RECAPTCHA_SITE_SECRET
diff --git a/static/img/logo-rp3-full-black.png b/static/img/logo-rp3-full-black.png
new file mode 100644
index 0000000000000000000000000000000000000000..389d083c4aa11b9c1eb7ba8de34e779e16811bc8
GIT binary patch
literal 14279
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
literal 0
HcmV?d00001