diff --git a/rowers/integrations/strava.py b/rowers/integrations/strava.py
index b78281a0..f6e878c1 100644
--- a/rowers/integrations/strava.py
+++ b/rowers/integrations/strava.py
@@ -214,7 +214,7 @@ class StravaIntegration(SyncIntegration):
def get_workout(self, id, *args, **kwargs) -> int:
try:
_ = self.open()
- except NoTokenError("Strava error"):
+ except NoTokenError:
return 0
record = create_or_update_syncrecord(self.rower, None, stravaid=id)
diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py
index c8a14c14..05a16994 100644
--- a/rowers/rower_rules.py
+++ b/rowers/rower_rules.py
@@ -479,7 +479,9 @@ def is_workout_team(user, workout):
@rules.predicate
def can_view_workout(user, workout):
- if workout.privacy != 'private':
+ if workout.workoutsource == 'strava':
+ return user == workout.user.user
+ if workout.privacy not in ('hidden', 'private'):
return True
if user.is_anonymous: # pragma: no cover
return False
diff --git a/rowers/tests/test_api.py b/rowers/tests/test_api.py
index 1187265e..d120c8b2 100644
--- a/rowers/tests/test_api.py
+++ b/rowers/tests/test_api.py
@@ -24,8 +24,229 @@ from rest_framework.test import APIRequestFactory, force_authenticate
import json
+# import BeautifulSoup
+from bs4 import BeautifulSoup
+
from rowers.ownapistuff import *
from rowers.views.apiviews import *
+from rowers.teams import add_member, add_coach
+
+class TeamFactory(factory.DjangoModelFactory):
+ class Meta:
+ model = Team
+
+ name = factory.LazyAttribute(lambda _: faker.word())
+ notes = faker.text()
+ private = 'open'
+ viewing = 'allmembers'
+
+class StravaPrivacy(TestCase):
+ def setUp(self):
+ self.u = UserFactory()
+ self.u2 = UserFactory()
+ self.u3 = UserFactory()
+
+ self.r = Rower.objects.create(user=self.u,
+ birthdate=faker.profile()['birthdate'],
+ gdproptin=True, ftpset=True,surveydone=True,
+ gdproptindate=timezone.now(),
+ rowerplan='coach',subscription_id=1)
+
+ self.r.stravatoken = '12'
+ self.r.stravarefreshtoken = '123'
+ self.r.stravatokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime
+ self.r.strava_owner_id = 4
+
+ self.r.save()
+
+ self.c = Client()
+ self.user_workouts = WorkoutFactory.create_batch(5, user=self.r)
+ for w in self.user_workouts:
+ w.workoutsource = 'strava'
+ w.privacy = 'hidden'
+ w.save()
+
+ self.factory = RequestFactory()
+ self.password = faker.word()
+ self.u.set_password(self.password)
+ self.u.save()
+ self.factory = APIRequestFactory()
+
+ self.r2 = Rower.objects.create(user=self.u2,
+ birthdate=faker.profile()['birthdate'],
+ gdproptin=True, ftpset=True,surveydone=True,
+ gdproptindate=timezone.now(),
+ rowerplan='coach',clubsize=3)
+
+ self.r3 = Rower.objects.create(user=self.u3,
+ birthdate=faker.profile()['birthdate'],
+ gdproptin=True, ftpset=True,surveydone=True,
+ gdproptindate=timezone.now(),
+ rowerplan='basic')
+
+ self.c = Client()
+
+ self.password2 = faker.word()
+ self.u2.set_password(self.password2)
+ self.u2.save()
+
+ self.password3 = faker.word()
+ self.u3.set_password(self.password3)
+ self.u3.save()
+
+ self.team = TeamFactory(manager=self.u2)
+
+ # all are team members
+ add_member(self.team.id, self.r)
+ add_member(self.team.id, self.r2)
+ add_member(self.team.id, self.r3)
+
+ # r2 coaches r
+ add_coach(self.r2, self.r)
+
+ self.factory = APIRequestFactory()
+
+ # Test if workout with workoutsource strava and privacy hidden can be seen by coach
+ def test_privacy_coach(self):
+ login = self.c.login(username=self.u2.username, password=self.password2)
+ self.assertTrue(login)
+
+ w = self.user_workouts[0]
+ url = reverse('workout_view',kwargs={'id':encoder.encode_hex(w.id)})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,403)
+
+ # Test if workout with workoutsource strava and privacy hidden can be seen by team member
+ def test_privacy_member(self):
+ login = self.c.login(username=self.u3.username, password=self.password3)
+ self.assertTrue(login)
+
+ w = self.user_workouts[0]
+ url = reverse('workout_view',kwargs={'id':encoder.encode_hex(w.id)})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,403)
+
+ # same test as above but with user r and the response code should be 200
+ def test_privacy_owner(self):
+ login = self.c.login(username=self.u.username, password=self.password)
+ self.assertTrue(login)
+
+ w = self.user_workouts[0]
+ url = reverse('workout_view',kwargs={'id':encoder.encode_hex(w.id)})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,200)
+
+
+
+ # test if list_workouts returns all workouts for user r
+ def test_list_workouts(self):
+ login = self.c.login(username=self.u.username, password=self.password)
+ self.assertTrue(login)
+
+ url = reverse('workouts_view')
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,200)
+
+ # the response.content is html, so we need to parse it
+ soup = BeautifulSoup(response.content, 'html.parser')
+ # the workouts look like ... and there should be 5 unique ids
+ # the id is a hex string
+ workouts = set([a['href'].split('/')[3] for a in soup.find_all('a') if a['href'].startswith('/rowers/workout/')])
+
+ # throw out "c2import", "nkimport", "stravaimport", "concept2import", "sporttracksimport" from the set
+ workouts = set([w for w in workouts if w not in [
+ 'upload', 'addmanual', 'c2import', 'polarimport', 'rp3import', 'nkimport', 'stravaimport', 'concept2import', 'sporttracksimport']])
+
+ self.assertEqual(len(workouts),5)
+
+ # same test as above but list_workouts with team id = self.team.id
+ def test_list_workouts_team(self):
+ login = self.c.login(username=self.u.username, password=self.password)
+ self.assertTrue(login)
+
+ url = reverse('workouts_view',kwargs={'teamid':self.team.id})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,200)
+
+ # the response.content is html, so we need to parse it
+ soup = BeautifulSoup(response.content, 'html.parser')
+ # the workouts look like ... and there should be 5 unique ids
+ # the id is a hex string
+ workouts = set([a['href'].split('/')[3] for a in soup.find_all('a') if a['href'].startswith('/rowers/workout/')])
+
+ # throw out "c2import", "nkimport", "stravaimport", "concept2import", "sporttracksimport" from the set
+ workouts = set([w for w in workouts if w not in [
+ 'upload', 'addmanual', 'c2import', 'polarimport', 'rp3import', 'nkimport', 'stravaimport', 'concept2import', 'sporttracksimport']])
+
+ self.assertEqual(len(workouts),0)
+
+ # same test as the previous one but with self.r2 and the number of workouts found should 0
+ def test_list_workouts_team_coach(self):
+ login = self.c.login(username=self.u2.username, password=self.password2)
+ self.assertTrue(login)
+
+ url = reverse('workouts_view',kwargs={'teamid':self.team.id})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,200)
+
+ # the response.content is html, so we need to parse it
+ soup = BeautifulSoup(response.content, 'html.parser')
+ # the workouts look like ... and there should be 5 unique ids
+ # the id is a hex string
+ workouts = set([a['href'].split('/')[3] for a in soup.find_all('a') if a['href'].startswith('/rowers/workout/')])
+
+ # throw out "c2import", "nkimport", "stravaimport", "concept2import", "sporttracksimport" from the set
+ workouts = set([w for w in workouts if w not in [
+ 'upload', 'addmanual', 'c2import', 'polarimport', 'rp3import', 'nkimport', 'stravaimport', 'concept2import', 'sporttracksimport']])
+
+ self.assertEqual(len(workouts),0)
+
+ # same test as the previous one but with self.r3 and the number of workouts found should 0
+ def test_list_workouts_team_member(self):
+ login = self.c.login(username=self.u3.username, password=self.password3)
+ self.assertTrue(login)
+
+ url = reverse('workouts_view',kwargs={'teamid':self.team.id})
+ response = self.c.get(url)
+ self.assertEqual(response.status_code,200)
+
+ # the response.content is html, so we need to parse it
+ soup = BeautifulSoup(response.content, 'html.parser')
+ # the workouts look like ... and there should be 5 unique ids
+ # the id is a hex string
+ workouts = set([a['href'].split('/')[3] for a in soup.find_all('a') if a['href'].startswith('/rowers/workout/')])
+
+ # throw out "c2import", "nkimport", "stravaimport", "concept2import", "sporttracksimport" from the set
+ workouts = set([w for w in workouts if w not in [
+ 'upload', 'addmanual', 'c2import', 'polarimport', 'rp3import', 'nkimport', 'stravaimport', 'concept2import', 'sporttracksimport']])
+
+ self.assertEqual(len(workouts),0)
+
+ # now test strava import and test if the created workout has workoutsource strava and privacy hidden
+ @patch('rowers.utils.requests.get', side_effect=mocked_requests)
+ @patch('rowers.integrations.strava.requests.post', side_effect=mocked_requests)
+ @patch('rowers.dataprep.read_data')
+ def test_stravaimport(self, mock_get, mock_post, mocked_read_data):
+ login = self.c.login(username=self.u.username, password=self.password)
+ self.assertTrue(login)
+
+ # remove all self.workouts
+ Workout.objects.filter(user=self.r).delete()
+
+ # get the strava data like in test_strava_import in test_imports.py
+ response = self.c.get('/rowers/workout/stravaimport/12', follow=True)
+ expected_url = reverse('workout_import_view', kwargs={'source':'strava'})
+ self.assertRedirects(response, expected_url, status_code=301, target_status_code=200)
+
+ # check if the workout was created
+ ws = Workout.objects.filter(user=self.r)
+ self.assertEqual(len(ws),1)
+ w = ws[0]
+ self.assertEqual(w.workoutsource,'strava')
+ self.assertEqual(w.privacy,'hidden')
+
+
+
class OwnApi(TestCase):
def setUp(self):
@@ -35,17 +256,7 @@ class OwnApi(TestCase):
birthdate=faker.profile()['birthdate'],
gdproptin=True, ftpset=True,surveydone=True,
gdproptindate=timezone.now(),
- rowerplan='coach',subscription_id=1)
-
-
- self.c = Client()
- self.user_workouts = WorkoutFactory.create_batch(5, user=self.r)
- self.factory = RequestFactory()
- self.password = faker.word()
- self.u.set_password(self.password)
- self.u.save()
-
- self.factory = APIRequestFactory()
+ rowerplan='pro',subscription_id=1)
def test_strokedataform(self):
diff --git a/rowers/uploads.py b/rowers/uploads.py
index 781271f7..83846898 100644
--- a/rowers/uploads.py
+++ b/rowers/uploads.py
@@ -141,6 +141,8 @@ def do_sync(w, options, quick=False):
w.uploadedtostrava = options['stravaid']
# upload_to_strava = False
do_strava_export = False
+ w.workoutsource = 'strava'
+ w.privacy = 'hidden'
w.save()
record = create_or_update_syncrecord(w.user, w, stravaid=options['stravaid'])
except KeyError: