API: add an activity (w/ gpx file)
This commit is contained in:
		@@ -1,7 +1,15 @@
 | 
				
			|||||||
from flask import Blueprint, jsonify
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from datetime import timedelta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..users.utils import authenticate
 | 
					from flask import Blueprint, current_app, jsonify, request
 | 
				
			||||||
 | 
					from mpwo_api import appLog, db
 | 
				
			||||||
 | 
					from sqlalchemy import exc
 | 
				
			||||||
 | 
					from werkzeug.utils import secure_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ..users.utils import authenticate, verify_extension
 | 
				
			||||||
from .models import Activity
 | 
					from .models import Activity
 | 
				
			||||||
 | 
					from .utils import get_gpx_info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
activities_blueprint = Blueprint('activities', __name__)
 | 
					activities_blueprint = Blueprint('activities', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,3 +37,77 @@ def get_activities(auth_user_id):
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return jsonify(response_object), 200
 | 
					    return jsonify(response_object), 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@activities_blueprint.route('/activities', methods=['POST'])
 | 
				
			||||||
 | 
					@authenticate
 | 
				
			||||||
 | 
					def post_activity(auth_user_id):
 | 
				
			||||||
 | 
					    """Post an activity"""
 | 
				
			||||||
 | 
					    code = 400
 | 
				
			||||||
 | 
					    response_object = verify_extension('activity', request)
 | 
				
			||||||
 | 
					    if response_object['status'] != 'success':
 | 
				
			||||||
 | 
					        return jsonify(response_object), code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    activity_data = json.loads(request.form["data"])
 | 
				
			||||||
 | 
					    if not activity_data or activity_data.get('sport_id') is None:
 | 
				
			||||||
 | 
					        response_object = {
 | 
				
			||||||
 | 
					            'status': 'error',
 | 
				
			||||||
 | 
					            'message': 'Invalid payload.'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return jsonify(response_object), 400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    activity_file = request.files['file']
 | 
				
			||||||
 | 
					    filename = secure_filename(activity_file.filename)
 | 
				
			||||||
 | 
					    dirpath = os.path.join(
 | 
				
			||||||
 | 
					        current_app.config['UPLOAD_FOLDER'],
 | 
				
			||||||
 | 
					        'activities',
 | 
				
			||||||
 | 
					        str(auth_user_id)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    if not os.path.exists(dirpath):
 | 
				
			||||||
 | 
					        os.makedirs(dirpath)
 | 
				
			||||||
 | 
					    filepath = os.path.join(dirpath, filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        activity_file.save(filepath)
 | 
				
			||||||
 | 
					        gpx_data = get_gpx_info(filepath)
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        appLog.error(e)
 | 
				
			||||||
 | 
					        response_object = {
 | 
				
			||||||
 | 
					            'status': 'error',
 | 
				
			||||||
 | 
					            'message': 'Error during activity file save.'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return jsonify(response_object), 500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        new_activity = Activity(
 | 
				
			||||||
 | 
					            user_id=auth_user_id,
 | 
				
			||||||
 | 
					            sport_id=activity_data.get('sport_id'),
 | 
				
			||||||
 | 
					            activity_date=gpx_data['start'],
 | 
				
			||||||
 | 
					            duration=timedelta(seconds=gpx_data['duration'])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        new_activity.gpx = filepath
 | 
				
			||||||
 | 
					        new_activity.pauses = timedelta(seconds=gpx_data['stop_time'])
 | 
				
			||||||
 | 
					        new_activity.moving = timedelta(seconds=gpx_data['moving_time'])
 | 
				
			||||||
 | 
					        new_activity.distance = gpx_data['distance']
 | 
				
			||||||
 | 
					        new_activity.min_alt = gpx_data['elevation_min']
 | 
				
			||||||
 | 
					        new_activity.max_alt = gpx_data['elevation_max']
 | 
				
			||||||
 | 
					        new_activity.descent = gpx_data['downhill']
 | 
				
			||||||
 | 
					        new_activity.ascent = gpx_data['uphill']
 | 
				
			||||||
 | 
					        new_activity.max_speed = gpx_data['max_speed']
 | 
				
			||||||
 | 
					        new_activity.ave_speed = gpx_data['average_speed']
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        response_object = {
 | 
				
			||||||
 | 
					            'status': 'created',
 | 
				
			||||||
 | 
					            'message': 'Activity added.'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return jsonify(response_object), 201
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except (exc.IntegrityError, ValueError) as e:
 | 
				
			||||||
 | 
					        db.session.rollback()
 | 
				
			||||||
 | 
					        appLog.error(e)
 | 
				
			||||||
 | 
					        response_object = {
 | 
				
			||||||
 | 
					            'status': 'fail',
 | 
				
			||||||
 | 
					            'message': 'Error during activity save.'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return jsonify(response_object), 500
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								mpwo_api/mpwo_api/activities/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								mpwo_api/mpwo_api/activities/utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					import gpxpy.gpx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_gpx_info(gpx_file):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpx_data = {'filename': gpx_file}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpx_file = open(gpx_file, 'r')
 | 
				
			||||||
 | 
					    gpx = gpxpy.parse(gpx_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    max_speed = 0
 | 
				
			||||||
 | 
					    start = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for track in gpx.tracks:
 | 
				
			||||||
 | 
					        for segment in track.segments:
 | 
				
			||||||
 | 
					            for point_idx, point in enumerate(segment.points):
 | 
				
			||||||
 | 
					                if point_idx == 0:
 | 
				
			||||||
 | 
					                    start = point.time
 | 
				
			||||||
 | 
					                speed = segment.get_speed(point_idx)
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    if speed > max_speed:
 | 
				
			||||||
 | 
					                        max_speed = speed
 | 
				
			||||||
 | 
					                except Exception:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpx_data['max_speed'] = (max_speed / 1000) * 3600
 | 
				
			||||||
 | 
					    gpx_data['start'] = start
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    duration = gpx.get_duration()
 | 
				
			||||||
 | 
					    gpx_data['duration'] = duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ele = gpx.get_elevation_extremes()
 | 
				
			||||||
 | 
					    gpx_data['elevation_max'] = ele.maximum
 | 
				
			||||||
 | 
					    gpx_data['elevation_min'] = ele.minimum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hill = gpx.get_uphill_downhill()
 | 
				
			||||||
 | 
					    gpx_data['uphill'] = hill.uphill
 | 
				
			||||||
 | 
					    gpx_data['downhill'] = hill.downhill
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mv = gpx.get_moving_data()
 | 
				
			||||||
 | 
					    gpx_data['moving_time'] = mv.moving_time
 | 
				
			||||||
 | 
					    gpx_data['stop_time'] = mv.stopped_time
 | 
				
			||||||
 | 
					    distance = mv.moving_distance + mv.stopped_distance
 | 
				
			||||||
 | 
					    gpx_data['distance'] = distance/1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    average_speed = distance / duration
 | 
				
			||||||
 | 
					    gpx_data['average_speed'] = (average_speed / 1000) * 3600
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return gpx_data
 | 
				
			||||||
@@ -15,6 +15,7 @@ class BaseConfig:
 | 
				
			|||||||
        current_app.root_path, 'uploads'
 | 
					        current_app.root_path, 'uploads'
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    PICTURE_ALLOWED_EXTENSIONS = {'jpg', 'png', 'gif'}
 | 
					    PICTURE_ALLOWED_EXTENSIONS = {'jpg', 'png', 'gif'}
 | 
				
			||||||
 | 
					    ACTIVITY_ALLOWED_EXTENSIONS = {'gpx'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DevelopmentConfig(BaseConfig):
 | 
					class DevelopmentConfig(BaseConfig):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,30 @@
 | 
				
			|||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					from io import BytesIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mpwo_api.tests.utils import add_activity, add_sport, add_user
 | 
					from mpwo_api.tests.utils import add_activity, add_sport, add_user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gpx_file = (
 | 
				
			||||||
 | 
					    '<?xml version=\'1.0\' encoding=\'UTF-8\'?>'
 | 
				
			||||||
 | 
					    '<gpx xmlns:gpxdata="http://www.cluetrust.com/XML/GPXDATA/1/0" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxext="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns="http://www.topografix.com/GPX/1/1">'  # noqa
 | 
				
			||||||
 | 
					    '  <metadata/>'
 | 
				
			||||||
 | 
					    '  <trk>'
 | 
				
			||||||
 | 
					    '    <trkseg>'
 | 
				
			||||||
 | 
					    '      <trkpt lat="77.2261324" lon="-42.1223054">'
 | 
				
			||||||
 | 
					    '        <time>2015-09-20T13:48:44+00:00</time>'
 | 
				
			||||||
 | 
					    '      </trkpt>'
 | 
				
			||||||
 | 
					    '      <trkpt lat="77.2261324" lon="-42.1223054">'
 | 
				
			||||||
 | 
					    '        <time>2015-09-20T13:48:46+00:00</time>'
 | 
				
			||||||
 | 
					    '        <ele>223.28399658203125</ele>'
 | 
				
			||||||
 | 
					    '      </trkpt>'
 | 
				
			||||||
 | 
					    '      <trkpt lat="77.2261324" lon="-42.1223054">'
 | 
				
			||||||
 | 
					    '        <time>2015-09-20T13:48:46+00:00</time>'
 | 
				
			||||||
 | 
					    '      </trkpt>'
 | 
				
			||||||
 | 
					    '    </trkseg>'
 | 
				
			||||||
 | 
					    '  </trk>'
 | 
				
			||||||
 | 
					    '</gpx>'
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_all_activities(app):
 | 
					def test_get_all_activities(app):
 | 
				
			||||||
    add_user('test', 'test@test.com', '12345678')
 | 
					    add_user('test', 'test@test.com', '12345678')
 | 
				
			||||||
@@ -54,3 +76,132 @@ def test_get_all_activities(app):
 | 
				
			|||||||
    assert 3600 == data['data']['activities'][0]['duration']
 | 
					    assert 3600 == data['data']['activities'][0]['duration']
 | 
				
			||||||
    assert 1024 == data['data']['activities'][1]['duration']
 | 
					    assert 1024 == data['data']['activities'][1]['duration']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_add_an_activity(app):
 | 
				
			||||||
 | 
					    add_user('test', 'test@test.com', '12345678')
 | 
				
			||||||
 | 
					    add_sport('cycling')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    client = app.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(
 | 
				
			||||||
 | 
					            email='test@test.com',
 | 
				
			||||||
 | 
					            password='12345678'
 | 
				
			||||||
 | 
					        )),
 | 
				
			||||||
 | 
					        content_type='application/json'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/activities',
 | 
				
			||||||
 | 
					        data=dict(
 | 
				
			||||||
 | 
					            file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
 | 
				
			||||||
 | 
					            data='{"sport_id": 1}'
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            content_type='multipart/form-data',
 | 
				
			||||||
 | 
					            Authorization='Bearer ' + json.loads(
 | 
				
			||||||
 | 
					                resp_login.data.decode()
 | 
				
			||||||
 | 
					            )['auth_token']
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 201
 | 
				
			||||||
 | 
					    assert 'created' in data['status']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_add_an_activity_invalid_file(app):
 | 
				
			||||||
 | 
					    add_user('test', 'test@test.com', '12345678')
 | 
				
			||||||
 | 
					    add_sport('cycling')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    client = app.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(
 | 
				
			||||||
 | 
					            email='test@test.com',
 | 
				
			||||||
 | 
					            password='12345678'
 | 
				
			||||||
 | 
					        )),
 | 
				
			||||||
 | 
					        content_type='application/json'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/activities',
 | 
				
			||||||
 | 
					        data=dict(
 | 
				
			||||||
 | 
					            file=(BytesIO(str.encode(gpx_file)), 'example.png'),
 | 
				
			||||||
 | 
					            data='{"sport_id": 1}'
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            content_type='multipart/form-data',
 | 
				
			||||||
 | 
					            Authorization='Bearer ' + json.loads(
 | 
				
			||||||
 | 
					                resp_login.data.decode()
 | 
				
			||||||
 | 
					            )['auth_token']
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 400
 | 
				
			||||||
 | 
					    assert data['status'] == 'fail'
 | 
				
			||||||
 | 
					    assert data['message'] == 'File extension not allowed.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_add_an_activity_no_sport_id(app):
 | 
				
			||||||
 | 
					    add_user('test', 'test@test.com', '12345678')
 | 
				
			||||||
 | 
					    add_sport('cycling')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    client = app.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(
 | 
				
			||||||
 | 
					            email='test@test.com',
 | 
				
			||||||
 | 
					            password='12345678'
 | 
				
			||||||
 | 
					        )),
 | 
				
			||||||
 | 
					        content_type='application/json'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/activities',
 | 
				
			||||||
 | 
					        data=dict(
 | 
				
			||||||
 | 
					            file=(BytesIO(str.encode(gpx_file)), 'example.gpx'),
 | 
				
			||||||
 | 
					            data='{}'
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            content_type='multipart/form-data',
 | 
				
			||||||
 | 
					            Authorization='Bearer ' + json.loads(
 | 
				
			||||||
 | 
					                resp_login.data.decode()
 | 
				
			||||||
 | 
					            )['auth_token']
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 400
 | 
				
			||||||
 | 
					    assert data['status'] == 'error'
 | 
				
			||||||
 | 
					    assert data['message'] == 'Invalid payload.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_add_an_activity_no_file(app):
 | 
				
			||||||
 | 
					    add_user('test', 'test@test.com', '12345678')
 | 
				
			||||||
 | 
					    add_sport('cycling')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    client = app.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(
 | 
				
			||||||
 | 
					            email='test@test.com',
 | 
				
			||||||
 | 
					            password='12345678'
 | 
				
			||||||
 | 
					        )),
 | 
				
			||||||
 | 
					        content_type='application/json'
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/activities',
 | 
				
			||||||
 | 
					        data=dict(
 | 
				
			||||||
 | 
					            data='{}'
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            content_type='multipart/form-data',
 | 
				
			||||||
 | 
					            Authorization='Bearer ' + json.loads(
 | 
				
			||||||
 | 
					                resp_login.data.decode()
 | 
				
			||||||
 | 
					            )['auth_token']
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 400
 | 
				
			||||||
 | 
					    assert data['status'] == 'fail'
 | 
				
			||||||
 | 
					    assert data['message'] == 'No file part.'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
import datetime
 | 
					 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from mpwo_api.tests.utils import add_admin, add_sport, add_user
 | 
					from mpwo_api.tests.utils import add_admin, add_sport, add_user
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ from sqlalchemy import exc, or_
 | 
				
			|||||||
from werkzeug.utils import secure_filename
 | 
					from werkzeug.utils import secure_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import User
 | 
					from .models import User
 | 
				
			||||||
from .utils import allowed_picture, authenticate, register_controls
 | 
					from .utils import authenticate, register_controls, verify_extension
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auth_blueprint = Blueprint('auth', __name__)
 | 
					auth_blueprint = Blueprint('auth', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -236,20 +236,11 @@ def edit_user(user_id):
 | 
				
			|||||||
@authenticate
 | 
					@authenticate
 | 
				
			||||||
def edit_picture(user_id):
 | 
					def edit_picture(user_id):
 | 
				
			||||||
    code = 400
 | 
					    code = 400
 | 
				
			||||||
    if 'file' not in request.files:
 | 
					    response_object = verify_extension('picture', request)
 | 
				
			||||||
        response_object = {'status': 'fail', 'message': 'No file part.'}
 | 
					    if response_object['status'] != 'success':
 | 
				
			||||||
        return jsonify(response_object), code
 | 
					 | 
				
			||||||
    file = request.files['file']
 | 
					 | 
				
			||||||
    if file.filename == '':
 | 
					 | 
				
			||||||
        response_object = {'status': 'fail', 'message': 'No selected file.'}
 | 
					 | 
				
			||||||
        return jsonify(response_object), code
 | 
					 | 
				
			||||||
    if not allowed_picture(file.filename):
 | 
					 | 
				
			||||||
        response_object = {
 | 
					 | 
				
			||||||
            'status': 'fail',
 | 
					 | 
				
			||||||
            'message': 'File extension not allowed.'
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return jsonify(response_object), code
 | 
					        return jsonify(response_object), code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    file = request.files['file']
 | 
				
			||||||
    filename = secure_filename(file.filename)
 | 
					    filename = secure_filename(file.filename)
 | 
				
			||||||
    dirpath = os.path.join(
 | 
					    dirpath = os.path.join(
 | 
				
			||||||
        current_app.config['UPLOAD_FOLDER'],
 | 
					        current_app.config['UPLOAD_FOLDER'],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,12 +6,40 @@ from flask import current_app, jsonify, request
 | 
				
			|||||||
from .models import User
 | 
					from .models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def allowed_activity(filename):
 | 
				
			||||||
 | 
					    return '.' in filename and \
 | 
				
			||||||
 | 
					           filename.rsplit('.', 1)[1].lower() in \
 | 
				
			||||||
 | 
					           current_app.config.get('ACTIVITY_ALLOWED_EXTENSIONS')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def allowed_picture(filename):
 | 
					def allowed_picture(filename):
 | 
				
			||||||
    return '.' in filename and \
 | 
					    return '.' in filename and \
 | 
				
			||||||
           filename.rsplit('.', 1)[1].lower() in \
 | 
					           filename.rsplit('.', 1)[1].lower() in \
 | 
				
			||||||
           current_app.config.get('PICTURE_ALLOWED_EXTENSIONS')
 | 
					           current_app.config.get('PICTURE_ALLOWED_EXTENSIONS')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def verify_extension(file_type, req):
 | 
				
			||||||
 | 
					    response_object = {'status': 'success'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if 'file' not in req.files:
 | 
				
			||||||
 | 
					        response_object = {'status': 'fail', 'message': 'No file part.'}
 | 
				
			||||||
 | 
					        return response_object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    file = req.files['file']
 | 
				
			||||||
 | 
					    if file.filename == '':
 | 
				
			||||||
 | 
					        response_object = {'status': 'fail', 'message': 'No selected file.'}
 | 
				
			||||||
 | 
					        return response_object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((file_type == 'picture' and not allowed_picture(file.filename)) or
 | 
				
			||||||
 | 
					            (file_type == 'activity' and not allowed_activity(file.filename))):
 | 
				
			||||||
 | 
					        response_object = {
 | 
				
			||||||
 | 
					            'status': 'fail',
 | 
				
			||||||
 | 
					            'message': 'File extension not allowed.'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return response_object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def authenticate(f):
 | 
					def authenticate(f):
 | 
				
			||||||
    @wraps(f)
 | 
					    @wraps(f)
 | 
				
			||||||
    def decorated_function(*args, **kwargs):
 | 
					    def decorated_function(*args, **kwargs):
 | 
				
			||||||
@@ -34,6 +62,7 @@ def authenticate(f):
 | 
				
			|||||||
        if not user:
 | 
					        if not user:
 | 
				
			||||||
            return jsonify(response_object), code
 | 
					            return jsonify(response_object), code
 | 
				
			||||||
        return f(resp, *args, **kwargs)
 | 
					        return f(resp, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return decorated_function
 | 
					    return decorated_function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ Flask-Bcrypt==0.7.1
 | 
				
			|||||||
Flask-Migrate==2.1.1
 | 
					Flask-Migrate==2.1.1
 | 
				
			||||||
Flask-SQLAlchemy==2.3.2
 | 
					Flask-SQLAlchemy==2.3.2
 | 
				
			||||||
Flask-Testing==0.6.2
 | 
					Flask-Testing==0.6.2
 | 
				
			||||||
 | 
					gpxpy==1.2.0
 | 
				
			||||||
isort==4.2.15
 | 
					isort==4.2.15
 | 
				
			||||||
itsdangerous==0.24
 | 
					itsdangerous==0.24
 | 
				
			||||||
Jinja2==2.10
 | 
					Jinja2==2.10
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user