2018-01-01 16:59:46 +01:00
|
|
|
import datetime
|
2018-01-01 21:54:03 +01:00
|
|
|
import os
|
2018-01-14 20:49:35 +01:00
|
|
|
|
2018-06-07 14:15:27 +02:00
|
|
|
from fittrackee_api import appLog, bcrypt, db
|
2018-01-01 22:36:44 +01:00
|
|
|
from flask import Blueprint, current_app, jsonify, request
|
2017-12-16 21:00:46 +01:00
|
|
|
from sqlalchemy import exc, or_
|
2018-01-01 21:54:03 +01:00
|
|
|
from werkzeug.utils import secure_filename
|
2017-12-16 21:00:46 +01:00
|
|
|
|
2018-07-04 14:13:19 +02:00
|
|
|
from ..activities.utils_files import get_absolute_file_path
|
2017-12-16 21:00:46 +01:00
|
|
|
from .models import User
|
2018-05-01 17:51:38 +02:00
|
|
|
from .utils import authenticate, register_controls, verify_extension
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
auth_blueprint = Blueprint('auth', __name__)
|
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/register', methods=['POST'])
|
|
|
|
def register_user():
|
2019-07-19 12:02:49 +02:00
|
|
|
""" register a user """
|
2017-12-16 21:00:46 +01:00
|
|
|
# get post data
|
|
|
|
post_data = request.get_json()
|
2017-12-25 17:45:28 +01:00
|
|
|
if not post_data or post_data.get('username') is None \
|
|
|
|
or post_data.get('email') is None \
|
2018-01-01 11:10:39 +01:00
|
|
|
or post_data.get('password') is None \
|
|
|
|
or post_data.get('password_conf') is None:
|
2017-12-16 21:00:46 +01:00
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Invalid payload.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
username = post_data.get('username')
|
|
|
|
email = post_data.get('email')
|
|
|
|
password = post_data.get('password')
|
2018-01-01 11:10:39 +01:00
|
|
|
password_conf = post_data.get('password_conf')
|
|
|
|
|
2018-05-13 18:36:31 +02:00
|
|
|
try:
|
|
|
|
ret = register_controls(username, email, password, password_conf)
|
|
|
|
except TypeError as e:
|
|
|
|
db.session.rollback()
|
|
|
|
appLog.error(e)
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Error. Please try again or contact the administrator.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
2018-01-01 11:10:39 +01:00
|
|
|
if ret != '':
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Errors: ' + ret
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
|
2017-12-16 21:00:46 +01:00
|
|
|
try:
|
|
|
|
# check for existing user
|
|
|
|
user = User.query.filter(
|
|
|
|
or_(User.username == username, User.email == email)).first()
|
|
|
|
if not user:
|
|
|
|
# add new user to db
|
|
|
|
new_user = User(
|
|
|
|
username=username,
|
|
|
|
email=email,
|
|
|
|
password=password
|
|
|
|
)
|
2018-06-11 16:44:49 +02:00
|
|
|
new_user.timezone = 'Europe/Paris'
|
2017-12-16 21:00:46 +01:00
|
|
|
db.session.add(new_user)
|
|
|
|
db.session.commit()
|
|
|
|
# generate auth token
|
|
|
|
auth_token = new_user.encode_auth_token(new_user.id)
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'message': 'Successfully registered.',
|
|
|
|
'auth_token': auth_token.decode()
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 201
|
|
|
|
else:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Sorry. That user already exists.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
# handler errors
|
|
|
|
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
|
|
|
db.session.rollback()
|
2017-12-17 09:16:08 +01:00
|
|
|
appLog.error(e)
|
2017-12-25 17:45:28 +01:00
|
|
|
|
2017-12-16 21:00:46 +01:00
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
2017-12-25 17:45:28 +01:00
|
|
|
'message': 'Error. Please try again or contact the administrator.'
|
2017-12-16 21:00:46 +01:00
|
|
|
}
|
2018-05-13 18:36:31 +02:00
|
|
|
return jsonify(response_object), 500
|
2017-12-16 21:00:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/login', methods=['POST'])
|
|
|
|
def login_user():
|
2019-07-19 12:02:49 +02:00
|
|
|
""" user login """
|
2017-12-16 21:00:46 +01:00
|
|
|
# get post data
|
|
|
|
post_data = request.get_json()
|
|
|
|
if not post_data:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Invalid payload.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
email = post_data.get('email')
|
|
|
|
password = post_data.get('password')
|
|
|
|
try:
|
|
|
|
# check for existing user
|
|
|
|
user = User.query.filter(User.email == email).first()
|
|
|
|
if user and bcrypt.check_password_hash(user.password, password):
|
|
|
|
# generate auth token
|
|
|
|
auth_token = user.encode_auth_token(user.id)
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'message': 'Successfully logged in.',
|
|
|
|
'auth_token': auth_token.decode()
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 200
|
|
|
|
else:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
2018-01-01 11:10:39 +01:00
|
|
|
'message': 'Invalid credentials.'
|
2017-12-16 21:00:46 +01:00
|
|
|
}
|
|
|
|
return jsonify(response_object), 404
|
|
|
|
# handler errors
|
|
|
|
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
|
|
|
db.session.rollback()
|
2017-12-17 09:16:08 +01:00
|
|
|
appLog.error(e)
|
2017-12-16 21:00:46 +01:00
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
2017-12-25 17:45:28 +01:00
|
|
|
'message': 'Error. Please try again or contact the administrator.'
|
2017-12-16 21:00:46 +01:00
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/logout', methods=['GET'])
|
2017-12-25 17:45:28 +01:00
|
|
|
@authenticate
|
|
|
|
def logout_user(user_id):
|
2019-07-19 12:02:49 +02:00
|
|
|
""" user logout """
|
2017-12-16 21:00:46 +01:00
|
|
|
# get auth token
|
|
|
|
auth_header = request.headers.get('Authorization')
|
|
|
|
if auth_header:
|
|
|
|
auth_token = auth_header.split(" ")[1]
|
|
|
|
resp = User.decode_auth_token(auth_token)
|
2017-12-25 17:45:28 +01:00
|
|
|
if not isinstance(user_id, str):
|
2017-12-16 21:00:46 +01:00
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'message': 'Successfully logged out.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 200
|
|
|
|
else:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': resp
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 401
|
|
|
|
else:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Provide a valid auth token.'
|
|
|
|
}
|
2018-05-13 18:36:31 +02:00
|
|
|
return jsonify(response_object), 401
|
2017-12-25 17:45:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/profile', methods=['GET'])
|
|
|
|
@authenticate
|
|
|
|
def get_user_status(user_id):
|
2019-07-19 12:02:49 +02:00
|
|
|
""" get authenticated user info """
|
2017-12-25 17:45:28 +01:00
|
|
|
user = User.query.filter_by(id=user_id).first()
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
2018-05-09 15:52:27 +02:00
|
|
|
'data': user.serialize()
|
2017-12-25 17:45:28 +01:00
|
|
|
}
|
|
|
|
return jsonify(response_object), 200
|
2018-01-01 16:59:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/profile/edit', methods=['POST'])
|
|
|
|
@authenticate
|
|
|
|
def edit_user(user_id):
|
2019-07-19 12:02:49 +02:00
|
|
|
""" edit authenticated user """
|
2018-01-01 16:59:46 +01:00
|
|
|
# get post data
|
|
|
|
post_data = request.get_json()
|
|
|
|
if not post_data:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Invalid payload.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
first_name = post_data.get('first_name')
|
|
|
|
last_name = post_data.get('last_name')
|
|
|
|
bio = post_data.get('bio')
|
|
|
|
birth_date = post_data.get('birth_date')
|
|
|
|
location = post_data.get('location')
|
2018-01-01 17:50:12 +01:00
|
|
|
password = post_data.get('password')
|
|
|
|
password_conf = post_data.get('password_conf')
|
2018-06-11 15:10:18 +02:00
|
|
|
timezone = post_data.get('timezone')
|
2018-01-01 17:50:12 +01:00
|
|
|
|
|
|
|
if password is not None and password != '':
|
|
|
|
if password_conf != password:
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Password and password confirmation don\'t match.\n'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 400
|
|
|
|
else:
|
|
|
|
password = bcrypt.generate_password_hash(
|
|
|
|
password, current_app.config.get('BCRYPT_LOG_ROUNDS')
|
|
|
|
).decode()
|
|
|
|
|
2018-01-01 16:59:46 +01:00
|
|
|
try:
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
|
|
|
user.first_name = first_name
|
|
|
|
user.last_name = last_name
|
|
|
|
user.bio = bio
|
|
|
|
user.location = location
|
|
|
|
user.birth_date = (
|
2018-05-08 18:26:42 +02:00
|
|
|
datetime.datetime.strptime(birth_date, '%Y-%m-%d')
|
2018-01-01 16:59:46 +01:00
|
|
|
if birth_date
|
|
|
|
else None
|
|
|
|
)
|
2018-01-01 17:50:12 +01:00
|
|
|
if password is not None and password != '':
|
|
|
|
user.password = password
|
2018-06-11 15:10:18 +02:00
|
|
|
user.timezone = timezone
|
2018-01-01 16:59:46 +01:00
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'message': 'User profile updated.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 200
|
|
|
|
|
|
|
|
# handler errors
|
|
|
|
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
|
|
|
db.session.rollback()
|
|
|
|
appLog.error(e)
|
|
|
|
response_object = {
|
|
|
|
'status': 'error',
|
|
|
|
'message': 'Error. Please try again or contact the administrator.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
2018-01-01 21:54:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/picture', methods=['POST'])
|
|
|
|
@authenticate
|
|
|
|
def edit_picture(user_id):
|
2019-07-19 12:02:49 +02:00
|
|
|
""" update authenticated user picture """
|
2018-01-01 21:54:03 +01:00
|
|
|
code = 400
|
2018-05-01 17:51:38 +02:00
|
|
|
response_object = verify_extension('picture', request)
|
|
|
|
if response_object['status'] != 'success':
|
2018-01-01 21:54:03 +01:00
|
|
|
return jsonify(response_object), code
|
|
|
|
|
2018-05-01 17:51:38 +02:00
|
|
|
file = request.files['file']
|
2018-01-01 21:54:03 +01:00
|
|
|
filename = secure_filename(file.filename)
|
|
|
|
dirpath = os.path.join(
|
|
|
|
current_app.config['UPLOAD_FOLDER'],
|
|
|
|
'pictures',
|
|
|
|
str(user_id)
|
|
|
|
)
|
|
|
|
if not os.path.exists(dirpath):
|
|
|
|
os.makedirs(dirpath)
|
2018-07-04 14:13:19 +02:00
|
|
|
absolute_picture_path = os.path.join(dirpath, filename)
|
|
|
|
relative_picture_path = os.path.join(
|
|
|
|
'pictures',
|
|
|
|
str(user_id),
|
|
|
|
filename
|
|
|
|
)
|
2018-01-01 21:54:03 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
2018-07-04 14:13:19 +02:00
|
|
|
if user.picture is not None:
|
|
|
|
old_picture_path = get_absolute_file_path(user.picture)
|
|
|
|
if os.path.isfile(get_absolute_file_path(old_picture_path)):
|
|
|
|
os.remove(old_picture_path)
|
|
|
|
file.save(absolute_picture_path)
|
|
|
|
user.picture = relative_picture_path
|
2018-01-01 21:54:03 +01:00
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
response_object = {
|
|
|
|
'status': 'success',
|
|
|
|
'message': 'User picture updated.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 200
|
|
|
|
|
|
|
|
except (exc.IntegrityError, ValueError) as e:
|
|
|
|
db.session.rollback()
|
|
|
|
appLog.error(e)
|
|
|
|
response_object = {
|
|
|
|
'status': 'fail',
|
|
|
|
'message': 'Error during picture update.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|
|
|
|
|
|
|
|
|
|
|
|
@auth_blueprint.route('/auth/picture', methods=['DELETE'])
|
|
|
|
@authenticate
|
|
|
|
def del_picture(user_id):
|
2019-07-19 12:02:49 +02:00
|
|
|
""" delete authenticated user picture """
|
2018-01-01 21:54:03 +01:00
|
|
|
try:
|
|
|
|
user = User.query.filter_by(id=user_id).first()
|
2018-07-04 14:13:19 +02:00
|
|
|
picture_path = get_absolute_file_path(user.picture)
|
|
|
|
if os.path.isfile(picture_path):
|
|
|
|
os.remove(picture_path)
|
2018-01-01 21:54:03 +01:00
|
|
|
user.picture = None
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
response_object = {
|
2018-06-12 12:51:23 +02:00
|
|
|
'status': 'no content'
|
2018-01-01 21:54:03 +01:00
|
|
|
}
|
2018-06-12 12:51:23 +02:00
|
|
|
return jsonify(response_object), 204
|
2018-01-01 21:54:03 +01:00
|
|
|
|
|
|
|
except (exc.IntegrityError, ValueError) as e:
|
|
|
|
db.session.rollback()
|
|
|
|
appLog.error(e)
|
|
|
|
response_object = {
|
|
|
|
'status': 'fail',
|
|
|
|
'message': 'Error during picture deletion.'
|
|
|
|
}
|
|
|
|
return jsonify(response_object), 500
|