From 424178ac0ee13b3a2c5005ffebed82c11fe7bacb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 9 Feb 2020 13:55:43 +0100 Subject: [PATCH] working --- rowers/dataprep.py | 1 + rowers/forms.py | 20 +++++++++++ rowers/tests/test_emails.py | 47 +++++++++++++++++++++++++ rowers/tests/test_uploads.py | 1 - rowers/urls.py | 2 +- rowers/views/workoutviews.py | 67 +++++++++++++++++++----------------- 6 files changed, 104 insertions(+), 34 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 3912e8c1..b2ae436f 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1568,6 +1568,7 @@ def new_workout_from_file(r, f2, if workoutsource is None: workoutsource = fileformat + print(f2,'final name') id, message = save_workout_database( f2, r, notes=notes, diff --git a/rowers/forms.py b/rowers/forms.py index 530c842d..829bbd3a 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -395,6 +395,26 @@ class TeamUploadOptionsForm(forms.Form): initial='timeplot', label='Plot Type') + upload_to_C2 = forms.BooleanField(initial=False,required=False, + label='Export to Concept2 logbook') + upload_to_Strava = forms.BooleanField(initial=False,required=False, + label='Export to Strava') + upload_to_SportTracks = forms.BooleanField(initial=False,required=False, + label='Export to SportTracks') + upload_to_RunKeeper = forms.BooleanField(initial=False,required=False, + label='Export to RunKeeper') + upload_to_MapMyFitness = forms.BooleanField(initial=False, + required=False, + label='Export to MapMyFitness') + upload_to_TrainingPeaks = forms.BooleanField(initial=False, + required=False, + label='Export to TrainingPeaks') + # do_physics = forms.BooleanField(initial=False,required=False,label='Power Estimate (OTW)') + makeprivate = forms.BooleanField(initial=False,required=False, + label='Make Workout Private') + + + class Meta: fields = ['make_plot','plottype'] diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py index b65bcd9c..06ede1d6 100644 --- a/rowers/tests/test_emails.py +++ b/rowers/tests/test_emails.py @@ -9,6 +9,7 @@ from .statements import * class EmailUpload(TestCase): def setUp(self): redis_connection.publish('tasks','KILL') + self.c = Client() u = User.objects.create_user('john', 'sander@ds.ds', 'koeinsloot') @@ -50,6 +51,52 @@ workout run except (IOError,FileNotFoundError,OSError): pass + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) + def test_uploadapi(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): + form_data = { + 'title': 'test', + 'workouttype':'rower', + 'boattype': '1x', + 'notes': 'aap noot mies', + 'make_plot': False, + 'upload_to_C2': False, + 'plottype': 'timeplot', + 'file': 'media/mailbox_attachments/colin3.csv', + 'secret': 'potjandorie', + 'user': 1, + } + + url = reverse('workout_upload_api') + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,200) + + # should also test if workout is created + w = Workout.objects.get(id=1) + self.assertEqual(w.name,'test') + self.assertEqual(w.notes,'aap noot mies') + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) + def test_uploadapi_credentials(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): + form_data = { + 'title': 'test', + 'workouttype':'rower', + 'boattype': '1x', + 'notes': 'aap noot mies', + 'make_plot': False, + 'upload_to_C2': False, + 'plottype': 'timeplot', + 'file': 'media/mailbox_attachments/colin3.csv', + 'secret': 'potjandorie2', + 'user': 1, + } + + url = reverse('workout_upload_api') + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,403) + + @patch('rowers.dataprep.create_engine') @patch('rowers.polarstuff.get_polar_notifications') @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index 22f9a4e5..21e03df9 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -245,7 +245,6 @@ class ViewTest(TestCase): - @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.TCXParser') def test_upload_view_TCX_CN(self, mocked_sqlalchemy, mocked_tcx_parser): diff --git a/rowers/urls.py b/rowers/urls.py index 00b83ac9..625ee831 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -745,7 +745,7 @@ urlpatterns = [ re_path(r'^courses/(?P\d+)/map/$',views.course_map_view,name='course_map_view'), # URLS to be created re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), - + re_path(r'^workout/api/upload/',views.workout_upload_api,name='workout_upload_api'), ] if settings.DEBUG: diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 6fbcfaf2..fd2cc78c 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -3,6 +3,9 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +import hashlib +from shutil import copyfile + from rowers.views.statements import * import rowers.teams as teams import rowers.mytypes as mytypes @@ -4384,24 +4387,35 @@ def workout_toggle_ranking(request,id=0): return response -def workout_add(request): +# simple POST API for files on local (e.g. in mailbox) +@csrf_exempt +def workout_upload_api(request): if request.method != 'POST': raise PermissionDenied("This view cannot be accessed") - # check credentials here + # only allow local host + print(request.get_host(),'get_host') - form = DocumentsForm(request.POST,request.FILES) + # check credentials here + secret = request.POST['secret'] + if secret != 'potjandorie': + raise PermissionDenied("Invalid credentials") + + form = DocumentsForm(request.POST) optionsform = TeamUploadOptionsForm(request.POST) rowerform = TeamInviteForm(request.POST) rowerform.fields.pop('email') - if form.is_valid(): - f = request.FILES.get('file',False) - if f: - res = handle_uploaded_file(f) - else: - message = {'message':'no file attached','status':'false'} - return JsonResponse(status=400,data=message) + try: + fstr = request.POST['file'] + f1 = uuid.uuid4().hex[:10]+'-'+time.strftime("%Y%m%d-%H%M%S")+os.path.splitext(fstr)[1] + print(f1) + f2 = 'media/'+f1 + copyfile(fstr,f2) + except KeyError: + message = {'status':'false','message':'no filename given'} + return JSONResponse(status=400,data=message) + if form.is_valid(): t = form.cleaned_data['title'] offline = True offline = form.cleaned_data['offline'] @@ -4425,37 +4439,22 @@ def workout_add(request): upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness'] upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks'] makeprivate = optionsform.cleaned_data['makeprivate'] - landingpage = optionsform.cleaned_data['landingpage'] + else: + message = optionsform.errors + return JSonResponse(status=400,data=message) - uploadoptions = { - 'makeprivate':makeprivate, - 'make_plot':make_plot, - 'plottype':plottype, - 'upload_to_C2':upload_to_c2, - 'upload_to_Strava':upload_to_strava, - 'upload_to_SportTracks':upload_to_st, - 'upload_to_RunKeeper':upload_to_rk, - 'upload_to_MapMyFitness':upload_to_ua, - 'upload_to_TrainingPeaks':upload_to_tp, - 'landingpage':landingpage, - 'boattype': boattype, - 'workouttype': workouttype, - } - - f1 = res[0] - f2 = res[1] id, message, f2 = dataprep.new_workout_from_file( r,f2, workouttype=workouttype, - workoutsource=workoutsource, + workoutsource=None, boattype=boattype, makeprivate=makeprivate, title = t, notes=notes, ) - if <= 0: + if id <= 0: message = {'status':'false','message':'unable to process file'} return JSonResponse(status=400,data=message) @@ -4472,8 +4471,12 @@ def workout_add(request): # add other export options - message = {'status': 'true','id':w.id} - return JSONResponse(status=200,data=message) + else: # form invalid + message = form.errors + return JsonResponse(status=400,data=message) + + message = {'status': 'true','id':w.id} + return JSONResponse(status=200,data=message)