Private
Public Access
1
0

using imports.py on all external APIs

This commit is contained in:
Sander Roosendaal
2018-07-04 16:29:01 +02:00
parent 45a6300c76
commit 6723194a30
9 changed files with 76 additions and 293 deletions

View File

@@ -19,6 +19,18 @@ queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low') queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low')
oauth_data = {
'client_id': C2_CLIENT_ID,
'client_secret': C2_CLIENT_SECRET,
'redirect_uri': C2_REDIRECT_URI,
'autorization_uri': "https://log.concept2.com/oauth/authorize",
'content_type': 'application/x-www-form-urlencoded',
'tokenname': 'c2token',
'refreshtokenname': 'c2refreshtoken',
'expirydatename': 'tokenexpirydate',
'bearer_auth': True,
'base_url': "https://log.concept2.com/oauth/access_token",
}
# Checks if user has Concept2 tokens, resets tokens if they are # Checks if user has Concept2 tokens, resets tokens if they are

View File

@@ -9,6 +9,7 @@ import requests.auth
import json import json
from django.utils import timezone from django.utils import timezone
from datetime import datetime from datetime import datetime
from datetime import timedelta
import arrow import arrow
import numpy as np import numpy as np
from dateutil import parser from dateutil import parser
@@ -77,12 +78,12 @@ def imports_open(user,oauth_data):
token = getattr(r,oauth_data['tokenname']) token = getattr(r,oauth_data['tokenname'])
try: try:
refreshtoken = getattr(r,oauth_data['refreshtokenname']) refreshtoken = getattr(r,oauth_data['refreshtokenname'])
except AttributeError: except (AttributeError,KeyError):
refreshtoken = None refreshtoken = None
try: try:
tokenexpirydate = getattr(r,oauth_data['expirydatename']) tokenexpirydate = getattr(r,oauth_data['expirydatename'])
except AttributeError: except (AttributeError,KeyError):
tokenexpirydate = None tokenexpirydate = None
if (token == '') or (token is None): if (token == '') or (token is None):

View File

@@ -8,6 +8,17 @@ from rowsandall_app.settings import (
RUNKEEPER_CLIENT_ID, RUNKEEPER_CLIENT_SECRET,RUNKEEPER_REDIRECT_URI, RUNKEEPER_CLIENT_ID, RUNKEEPER_CLIENT_SECRET,RUNKEEPER_REDIRECT_URI,
) )
oauth_data = {
'client_id': RUNKEEPER_CLIENT_ID,
'client_secret': RUNKEEPER_CLIENT_SECRET,
'redirect_uri': RUNKEEPER_REDIRECT_URI,
'autorization_uri': "https://www.runkeeper.com/opps/authorize",
'content_type': 'application/x-www-form-urlencoded',
'tokenname': 'runkeepertoken',
'bearer_auth': True,
'base_url': "https://runkeeper.com/apps/token",
}
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname): def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
t = [] t = []
@@ -32,50 +43,15 @@ def splitrunkeeperdata(lijst,xname,yname):
# Checks if user has SportTracks token, renews them if they are expired # Checks if user has SportTracks token, renews them if they are expired
def runkeeper_open(user): def runkeeper_open(user):
r = Rower.objects.get(user=user) return imports_open(user,oauth_data)
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
s = "Token doesn't exist. Need to authorize"
raise NoTokenError("User has no token")
else:
thetoken = r.runkeepertoken
return thetoken
# Exchange access code for long-lived access token # Exchange access code for long-lived access token
def get_token(code): def get_token(code):
client_auth = requests.auth.HTTPBasicAuth(RUNKEEPER_CLIENT_ID, RUNKEEPER_CLIENT_SECRET) return imports_get_token(code,oauth_data)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": RUNKEEPER_REDIRECT_URI,
"client_secret": RUNKEEPER_CLIENT_SECRET,
"client_id":RUNKEEPER_CLIENT_ID,
}
headers = {'user-agent': 'sanderroosendaal'}
response = requests.post("https://runkeeper.com/apps/token",
data=post_data,
headers=headers)
try:
token_json = response.json()
thetoken = token_json['access_token']
except KeyError:
thetoken = 0
return thetoken
# Make authorization URL including random string # Make authorization URL including random string
def make_authorization_url(request): def make_authorization_url(request):
# Generate a random string for the state parameter return imports_make_authorization_url(oauth_data)
# Save it for use later to prevent xsrf attacks
state = str(uuid4())
params = {"client_id": RUNKEEPER_CLIENT_ID,
"response_type": "code",
"redirect_uri": RUNKEEPER_REDIRECT_URI,
}
import urllib
url = "https://www.runkeeper.com/opps/authorize" +urllib.urlencode(params)
return HttpResponseRedirect(url)
# Get list of workouts available on Runkeeper # Get list of workouts available on Runkeeper
def get_runkeeper_workout_list(user): def get_runkeeper_workout_list(user):

View File

@@ -8,109 +8,35 @@ from rowsandall_app.settings import (
SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
) )
oauth_data = {
'client_id': SPORTTRACKS_CLIENT_ID,
'client_secret': SPORTTRACKS_CLIENT_SECRET,
'redirect_uri': SPORTTRACKS_REDIRECT_URI,
'autorization_uri': "https://api.sporttracks.mobi/oauth2/authorize",
'content_type': 'application/json',
'tokenname': 'sporttrackstoken',
'refreshtokenname': 'sporttracksrefreshtoken',
'expirydatename': 'sporttrackstokenexpirydate',
'bearer_auth': False,
'base_url': "https://api.sporttracks.mobi/oauth2/token",
}
# Checks if user has SportTracks token, renews them if they are expired # Checks if user has SportTracks token, renews them if they are expired
def sporttracks_open(user): def sporttracks_open(user):
r = Rower.objects.get(user=user) return imports_open(user, oauth_data)
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
s = "Token doesn't exist. Need to authorize"
raise NoTokenError("User has no token")
else:
if (timezone.now()>r.sporttrackstokenexpirydate):
thetoken = rower_sporttracks_token_refresh(user)
else:
thetoken = r.sporttrackstoken
return thetoken
# Refresh ST token using refresh token # 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) return imports_do_refresh_token(refreshtoken, oauth_data)
post_data = {"grant_type": "refresh_token",
"client_secret": SPORTTRACKS_CLIENT_SECRET,
"client_id":SPORTTRACKS_CLIENT_ID,
"refresh_token": refreshtoken,
}
headers = {'user-agent': 'sanderroosendaal',
'Accept': 'application/json',
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/oauth2/token"
response = requests.post(url,
data=json.dumps(post_data),
headers=headers)
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
try:
refresh_token = token_json['refresh_token']
except KeyError:
refresh_token = refreshtoken
try:
expires_in = int(expires_in)
except (TypeError,ValueError):
expires_in = 0
return [thetoken,expires_in,refresh_token]
# Exchange ST access code for long-lived ST access 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) return imports_get_token(code,oauth_data)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": SPORTTRACKS_REDIRECT_URI,
"client_secret": SPORTTRACKS_CLIENT_SECRET,
"client_id":SPORTTRACKS_CLIENT_ID,
}
headers = {'Accept': 'application/json',
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/oauth2/token"
response = requests.post(url,
data=json.dumps(post_data),
headers=headers)
if response.status_code == 200 or response.status_code == 201:
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
try:
refresh_token = token_json['refresh_token']
except KeyError:
refresh_token = refreshtoken
try:
expires_in = int(expires_in)
except (ValueError,TypeError):
expires_in = 0
else:
return [0,0,0]
return [thetoken,expires_in,refresh_token]
# Make authorization URL including random string # Make authorization URL including random string
def make_authorization_url(request): def make_authorization_url(request):
# Generate a random string for the state parameter return imports_make_authorization_url(oauth_data)
# Save it for use later to prevent xsrf attacks
state = str(uuid4())
params = {"client_id": SPORTTRACKS_CLIENT_ID,
"response_type": "code",
"redirect_uri": SPORTTRACKS_REDIRECT_URI,
"scope":"write",
"state":state}
import urllib
url = "https://api.sporttracks.mobi/oauth2/authorize" +urllib.urlencode(params)
return HttpResponseRedirect(url)
# This is token refresh. Looks for tokens in our database, then refreshes # This is token refresh. Looks for tokens in our database, then refreshes
def rower_sporttracks_token_refresh(user): def rower_sporttracks_token_refresh(user):
@@ -306,7 +232,8 @@ def workout_sporttracks_upload(user,w):
# ready to upload. Hurray # ready to upload. Hurray
r = w.user r = w.user
thetoken = sporttracks_open(user) res = sporttracks_open(user)
thetoken = res[0]
if (checkworkoutuser(user,w)): if (checkworkoutuser(user,w)):
data = createsporttracksworkoutdata(w) data = createsporttracksworkoutdata(w)

View File

@@ -48,13 +48,7 @@ oauth_data = {
# Exchange access code for long-lived access token # Exchange access code for long-lived access token
def get_token(code): def get_token(code):
( return imports_get_token(code, oauth_data)
thetoken, expires_in, refresh_token
) = imports_get_token(code, oauth_data)
return [thetoken]
# Make authorization URL including random string # Make authorization URL including random string
def make_authorization_url(request): def make_authorization_url(request):

View File

@@ -1,40 +1,12 @@
# All the functionality needed to connect to Runkeeper # All the functionality needed to connect to Runkeeper
from rowers.imports import *
# Python # Python
import oauth2 as oauth
import cgi
import requests
import requests.auth
import json
from django.utils import timezone
from datetime import datetime
from datetime import timedelta
import numpy as np
from dateutil import parser
import time
import pytz
import math
import gzip import gzip
from math import sin,cos,atan2,sqrt
import os,sys
import urllib
import base64 import base64
from io import BytesIO from io import BytesIO
from time import strftime
# Django
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse,JsonResponse
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
#from django.contrib import messages
# Project
# from .models import Profile
from rowingdata import rowingdata
import pandas as pd
from rowers.models import Rower,Workout,checkworkoutuser
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,
@@ -50,116 +22,35 @@ from django_rq import job
import time import time
from async_messages import message_user,messages from async_messages import message_user,messages
oauth_data = {
'client_id': TP_CLIENT_ID,
'client_secret': TP_CLIENT_SECRET,
from utils import geo_distance, NoTokenError,ewmovingaverage, custom_exception_handler 'redirect_uri': TP_REDIRECT_URI,
'autorization_uri': "https://oauth.trainingpeaks.com/oauth/authorize?",
'content_type': 'application/x-www-form-urlencoded',
'tokenname': 'tptoken',
'refreshtokenname': 'tprefreshtoken',
'expirydatename': 'tptokenexpirydate',
'bearer_auth': False,
'base_url': "https://oauth.trainingpeaks.com/oauth/token",
}
# Checks if user has UnderArmour token, renews them if they are expired # Checks if user has UnderArmour token, renews them if they are expired
def tp_open(user): def tp_open(user):
r = Rower.objects.get(user=user) return imports_open(user, oauth_data)
if (r.tptoken == '') or (r.tptoken is None):
s = "Token doesn't exist. Need to authorize"
raise NoTokenError("User has no token")
else:
if (timezone.now()>r.tptokenexpirydate):
res = do_refresh_token(r.tprefreshtoken)
if res[0] != 0:
r.tptoken = res[0]
r.tprefreshtoken = res[2]
expirydatetime = timezone.now()+timedelta(seconds=res[1])
r.tptokenexpirydate = expirydatetime
r.save()
thetoken = r.tptoken
else:
raise NoTokenError("Refresh token invalid")
else:
thetoken = r.tptoken
return thetoken
# Refresh ST token using refresh token # Refresh ST token using refresh token
def do_refresh_token(refreshtoken): def do_refresh_token(refreshtoken):
client_auth = requests.auth.HTTPBasicAuth(TP_CLIENT_KEY, TP_CLIENT_SECRET) return imports_do_refresh_token(refreshtoken, oauth_data)
post_data = {"grant_type": "refresh_token",
"client_secret": TP_CLIENT_SECRET,
"client_id":TP_CLIENT_KEY,
"refresh_token": refreshtoken,
}
headers = {'user-agent': 'sanderroosendaal',
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
}
url = "https://oauth.trainingpeaks.com/oauth/token"
response = requests.post(url,
data=post_data,
headers=headers)
if response.status_code == 200 or response.status_code == 201:
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
try:
refresh_token = token_json['refresh_token']
except KeyError:
refresh_token = refreshtoken
else:
return [0,0,0]
return [thetoken,expires_in,refresh_token]
# Exchange access code for long-lived access token # Exchange access code for long-lived access token
def get_token(code): def get_token(code):
client_auth = requests.auth.HTTPBasicAuth(TP_CLIENT_KEY, TP_CLIENT_SECRET) return imports_get_token(code, oauth_data)
post_data = {
"client_id":TP_CLIENT_KEY,
"grant_type": "authorization_code",
"code": code,
"redirect_uri":TP_REDIRECT_URI,
"client_secret": TP_CLIENT_SECRET,
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
response = requests.post("https://oauth.trainingpeaks.com/oauth/token",
data=post_data)
try:
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
refresh_token = token_json['refresh_token']
except KeyError:
thetoken = 0
expires_in = 0
refresh_token = 0
return thetoken,expires_in,refresh_token
# Make authorization URL including random string # Make authorization URL including random string
def make_authorization_url(request): def make_authorization_url(request):
# Generate a random string for the state parameter return imports_make_authorization_url(oauth_data)
# Save it for use later to prevent xsrf attacks
from uuid import uuid4
state = str(uuid4())
params = {"client_id": TP_CLIENT_KEY,
"response_type": "code",
"redirect_uri": TP_REDIRECT_URI,
"scope": "file:write",
}
url = "https://oauth.trainingpeaks.com/oauth/authorize?" +urllib.urlencode(params)
return HttpResponseRedirect(url)
def getidfromresponse(response): def getidfromresponse(response):

View File

@@ -52,8 +52,6 @@ def get_underarmour_workout_list(user):
'Content-Type': 'application/json'} 'Content-Type': 'application/json'}
url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime" url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime"
print url
s = requests.get(url,headers=headers) s = requests.get(url,headers=headers)
@@ -216,7 +214,6 @@ def get_idfromuri(user,links):
id = links['self'][0]['id'] id = links['self'][0]['id']
typeid = links['activity_type'][0]['id'] typeid = links['activity_type'][0]['id']
typename = get_typefromid(typeid,user) typename = get_typefromid(typeid,user)
return id,typename return id,typename

View File

@@ -105,9 +105,6 @@ handler403 = 'views.error403_view'
from oauth2_provider.views import base from oauth2_provider.views import base
urlpatterns = [ urlpatterns = [
# url(r'^password_change/$',auth_views.password_change),
# url(r'^password_change_done/$',auth_views.password_change_done),
# url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url(r'^o/authorize/$', base.AuthorizationView.as_view(), name="authorize"), url(r'^o/authorize/$', base.AuthorizationView.as_view(), name="authorize"),
url(r'^o/token/$', base.TokenView.as_view(), name="token"), url(r'^o/token/$', base.TokenView.as_view(), name="token"),
url(r'^', include(router.urls)), url(r'^', include(router.urls)),
@@ -120,7 +117,6 @@ urlpatterns = [
url(r'^404/$', TemplateView.as_view(template_name='404.html'),name='404'), url(r'^404/$', TemplateView.as_view(template_name='404.html'),name='404'),
url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'), url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'),
url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'), url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'),
# url(r'^imports/$', TemplateView.as_view(template_name='imports.html'), name='imports'),
url(r'^imports/$', views.imports_view), url(r'^imports/$', views.imports_view),
url(r'^exportallworkouts/?$',views.workouts_summaries_email_view), url(r'^exportallworkouts/?$',views.workouts_summaries_email_view),
url(r'^update_empower$',views.rower_update_empower_view), url(r'^update_empower$',views.rower_update_empower_view),
@@ -321,10 +317,8 @@ urlpatterns = [
url(r'^workout/c2list/$',views.workout_c2import_view), url(r'^workout/c2list/$',views.workout_c2import_view),
url(r'^workout/c2list/(?P<page>\d+)$',views.workout_c2import_view), url(r'^workout/c2list/(?P<page>\d+)$',views.workout_c2import_view),
url(r'^workout/stravaimport/$',views.workout_stravaimport_view), url(r'^workout/stravaimport/$',views.workout_stravaimport_view),
# url(r'^workout/c2import/(?P<c2id>\d+)/$',views.workout_getc2workout_view),
url(r'^workout/c2import/all/$',views.workout_getc2workout_all), url(r'^workout/c2import/all/$',views.workout_getc2workout_all),
url(r'^workout/c2import/all/(?P<page>\d+)$',views.workout_getc2workout_all), url(r'^workout/c2import/all/(?P<page>\d+)$',views.workout_getc2workout_all),
# url(r'^workout/stravaimport/(?P<stravaid>\d+)/$',views.workout_getstravaworkout_view),
url(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview), url(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview),
url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all), url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all),
url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next), url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next),
@@ -332,9 +326,7 @@ urlpatterns = [
url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all), url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all),
url(r'^workout/polarimport/$',views.workout_polarimport_view), url(r'^workout/polarimport/$',views.workout_polarimport_view),
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view), url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
# url(r'^workout/runkeeperimport/(?P<runkeeperid>\d+)/$',views.workout_getrunkeeperworkout_view),
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view), url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
# url(r'^workout/underarmourimport/(?P<underarmourid>\d+)/$',views.workout_getunderarmourworkout_view),
url(r'^workout/(?P<id>\d+)/deleteconfirm$',views.workout_delete_confirm_view), url(r'^workout/(?P<id>\d+)/deleteconfirm$',views.workout_delete_confirm_view),
url(r'^workout/(?P<id>\d+)/c2uploadw/$',views.workout_c2_upload_view), url(r'^workout/(?P<id>\d+)/c2uploadw/$',views.workout_c2_upload_view),
url(r'^workout/(?P<id>\d+)/stravauploadw/$',views.workout_strava_upload_view), url(r'^workout/(?P<id>\d+)/stravauploadw/$',views.workout_strava_upload_view),

View File

@@ -1815,7 +1815,8 @@ def workout_sporttracks_upload_view(request,id=0):
r = w.user r = w.user
try: try:
thetoken = sporttracks_open(r.user) res = sporttracks_open(r.user)
thetoken = res[0]
except NoTokenError: except NoTokenError:
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
@@ -2228,7 +2229,8 @@ def rower_process_stravacallback(request):
@login_required() @login_required()
def rower_process_runkeepercallback(request): def rower_process_runkeepercallback(request):
code = request.GET['code'] code = request.GET['code']
access_token = runkeeperstuff.get_token(code) res = runkeeperstuff.get_token(code)
access_token = res[0]
r = getrower(request.user) r = getrower(request.user)
r.runkeepertoken = access_token r.runkeepertoken = access_token
@@ -9176,11 +9178,8 @@ def workout_stravaimport_view(request,message=""):
return HttpResponseRedirect("/rowers/me/stravaauthorize/") return HttpResponseRedirect("/rowers/me/stravaauthorize/")
message = "Something went wrong in workout_stravaimport_view" message = "Something went wrong in workout_stravaimport_view"
messages.error(request,message) messages.error(request,message)
if settings.DEBUG: url = reverse(workouts_view)
return HttpResponse(res) return HttpResponseRedirect(url)
else:
url = reverse(workouts_view)
return HttpResponseRedirect(url)
else: else:
workouts = [] workouts = []
r = getrower(request.user) r = getrower(request.user)
@@ -9264,11 +9263,8 @@ def workout_underarmourimport_view(request,message=""):
return HttpResponseRedirect("/rowers/me/underarmourauthorize/") return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
message = "Something went wrong in workout_underarmourimport_view" message = "Something went wrong in workout_underarmourimport_view"
messages.error(request,message) messages.error(request,message)
if settings.DEBUG: url = reverse(workouts_view)
return HttpResponse(res) return HttpResponseRedirect(url)
else:
url = reverse(workouts_view)
return HttpResponseRedirect(url)
else: else:
workouts = [] workouts = []
items = res.json()['_embedded']['workouts'] items = res.json()['_embedded']['workouts']
@@ -9478,11 +9474,8 @@ def workout_c2import_view(request,page=1,message=""):
if (res.status_code != 200): if (res.status_code != 200):
message = "Something went wrong in workout_c2import_view (C2 token refresh)" message = "Something went wrong in workout_c2import_view (C2 token refresh)"
messages.error(request,message) messages.error(request,message)
if settings.DEBUG: url = reverse(workouts_view)
return HttpResponse(res) return HttpResponseRedirect(url)
else:
url = reverse(workouts_view)
return HttpResponseRedirect(url)
else: else:
workouts = [] workouts = []
r = getrower(request.user) r = getrower(request.user)