"""Module contains routes for user authorization,
registering and logout.
"""
import json
import requests
import time
from flask import request, jsonify, Response, render_template
from flask_login import login_user, logout_user, login_required
from urlparse import parse_qsl
import ecomap.user as ecomap_user
from ecomap import validator
from ecomap.app import app, logger, auto
from ecomap.db import util as db
from ecomap.config import Config
_CONFIG = Config().get_config()
@app.route('/api/logout', methods=['POST', 'GET'])
@auto.doc()
@login_required
def logout():
"""Method for user's log out.
:rtype: JSON
:return:
- if logging out was successful:
``{result:True}``
- in case of problems:
``{result:False}``
"""
return jsonify(result=logout_user())
@app.route('/api/register', methods=['POST'])
@auto.doc()
[docs]def register():
"""Method for registration new user in db.
Method checks if user is not exists and handle
registration processes.
:rtype: JSON
:request args: `{'first_name': 'Ivan',
'last_name': 'Sirko',
'email': 'email@test.com',
'password': 'passw'}`
:return:
- if one of the field is incorrect or empty:
``{'error':'Unauthorized'}``
- if user already exists
``{'status': 'user with this email already exists'}``
- if registration was successful:
``{'status': added user <username>}``
:statuscode 401: form is invalid or empty
:statuscode 400: user already exists
:statuscode 200: registration successful
"""
response = jsonify(msg='unauthorized'), 400
if request.method == 'POST' and request.get_json():
data = request.get_json()
valid = validator.user_registration(data)
if valid['status']:
ecomap_user.register(data['first_name'],
data['last_name'],
data['email'],
data['password'])
msg = 'added %s %s' % (data['first_name'],
data['last_name'])
response = jsonify({'status_message': msg}), 201
else:
response = Response(json.dumps(valid),
mimetype='application/json'), 400
return response
@app.route('/api/email_exist', methods=['POST'])
@auto.doc()
def email_exist():
"""Function for AJAX call from frontend.
Validates unique email identifier before registering a new user
:return: json with status 200 or 400
"""
if request.method == 'POST' and request.get_json():
data = request.get_json()
user = ecomap_user.get_user_by_email(data['email'])
return jsonify(isValid=bool(user))
@app.route('/api/login', methods=['POST'])
@auto.doc()
def login():
"""Login processes handler.
Log user in or shows error messages.
:rtype: JSON
:request args: `{'email': 'username@mail.com',
'password': 'userpaswd'}`
:return:
- if credentials are ok and log in successful:
``{"email": "username@mail.com",
"iat": "???",
"id": 6,
"name": "oleg",
"role": "admin",
"surname": "lyashko",
"token": "hashed_auth_token"}``
- if user with entered email isn't exists or password was invalid:
``{'error':'message'}``
:statuscode 401: user doesn't exist or password is invalid
:statuscode 400: login data has invalid format:
:statuscode 200: credentials are ok
"""
response = jsonify(), 401
if request.method == 'POST' and request.get_json():
data = request.get_json()
valid = validator.user_login(data)
if valid['status']:
user = ecomap_user.get_user_by_email(data['email'])
if user and user.verify_password(data['password']):
login_user(user, remember=True)
response = jsonify(id=user.uid,
name=user.first_name,
surname=user.last_name,
role=user.role, iat="???",
token=user.get_auth_token(),
email=user.email)
if not user:
logger.warning('if not user')
response = jsonify(error='There is no user with given email.',
logined=0, ), 401
elif not user.verify_password(data['password']):
logger.warning('if not user verify')
response = jsonify(error='Invalid password, try again.',
logined=0), 401
else:
response = Response(json.dumps(valid),
mimetype='application/json'), 400
return response
@app.route('/api/authorize/<provider>', methods=['POST', 'GET'])
@auto.doc()
def oauth_login(provider):
"""Provides facebook authorization.
Retrieves user info from facebook, check if there is
user with retrieved from facebook user id,
:param provider: Oauth provider (Facebook by default)
- if yes:
skips to next step
- if not:
checks if there is user with retrieved email
- if yes:
adds oauth credentials to this user
- if not:
creates new user
After all function logging in user into app and return it's params
"""
access_token_url = 'https://graph.facebook.com/oauth/access_token'
graph_api_url = 'https://graph.facebook.com/v2.5/me?fields=email,'\
'first_name,last_name,id,picture.type(large)'
params = {
'client_id': request.json['clientId'],
'redirect_uri': request.json['redirectUri'],
'client_secret': app.config['OAUTH_CREDENTIALS']['facebook']['secret'],
'code': request.json['code']
}
resource = requests.get(access_token_url, params=params)
access_token = dict(parse_qsl(resource.text))
resource = requests.get(graph_api_url, params=access_token)
profile = json.loads(resource.text)
logger.info(profile['picture']['data']['url'])
user = ecomap_user.facebook_register(profile['first_name'],
profile['last_name'],
profile['email'],
provider,
profile['id'])
db.insert_user_avatar(user.uid, profile['picture']['data']['url'])
login_user(user, remember=True)
response = jsonify(id=user.uid,
name=user.first_name,
surname=user.last_name,
role=user.role, iat="???",
token=user.get_auth_token(),
email=user.email)
return response
@app.route('/api/restore_password', methods=['POST'])
@auto.doc()
def restore_password_request():
"""Function to restore forgotten password.
:rtype: JSON
:request args: `{'email': 'username@mail.com'}`
:return:
- if credentials are ok and checking successful:
``{message='Email was sended.'}``
- if user's email isn't exists:
``{'error':'There is not such email.'}``
:statuscode 401: no email
:statuscode 200: email sended
"""
json = request.get_json()
email = json['email']
user = ecomap_user.get_user_by_email(email)
if user:
ecomap_user.restore_password(user)
response = jsonify(message='Email was sended.'), 200
else:
response = jsonify(error='There is not such email.'), 401
return response
@app.route('/api/restore_password_page/<string:hashed>', methods=['GET'])
@auto.doc()
def restore_password_page(hashed):
"""Renders page template to restore password.
:param hashed: unique hash to identify user via sending it to email.
:return redirect to main page with rendered template.
"""
valid = validator.hash_check(hashed)
page = render_template('index.html')
if valid:
creation_time = db.check_hash_in_db(hashed)
if creation_time:
elapsed = time.time() - creation_time[0]
if elapsed <= _CONFIG['hash_options.lifetime']:
page = render_template('password_restoring_pass.html')
return page
@app.route('/api/restore_password', methods=['PUT'])
@auto.doc()
def restore_password():
"""Updates user password.
"""
data = request.get_json()
valid = validator.change_password(data)
if valid:
user_id = db.get_user_id_by_hash(data['hash_sum'])
if user_id:
password = ecomap_user.hash_pass(data['password'])
db.restore_password(user_id[0], password)
response = jsonify(message='Password restored.')
else:
response = jsonify(message='got error.'), 400
else:
response = Response(json.dumps(valid),
mimetype='application/json'), 400
return response
@app.route('/api/delete_user_request', methods=['DELETE'])
@auto.doc()
def find_to_delete():
"""Function to send email with delete link"""
data = request.get_json()
search_id = data['user_id']
user = ecomap_user.get_user_by_id(search_id)
if search_id == ecomap_user.User.get_id(user):
ecomap_user.delete_user(user)
response = jsonify(message='Email was sended.'), 200
else:
response = jsonify(error="You can't do that"), 400
return response
@app.route('/api/delete_user_page/<string:hashed>', methods=['GET'])
@auto.doc()
def delete_user_page(hashed):
"""Renders page to confirmation of deleting user"""
valid = validator.hash_check(hashed)
page = render_template('index.html')
if valid:
creation_time = db.check_hash_in_db(hashed)
if creation_time:
elapsed = time.time() - creation_time[0]
if elapsed <= _CONFIG['hash_options.lifetime']:
page = render_template('index.html')
return page
@app.route('/api/user_delete', methods=['DELETE'])
def delete_user():
"""Controller for handling deletion of user profile by
profile owner.
:return: json object with success message or message with error
"""
data = request.get_json()
valid = validator.hash_check(data['hash_sum'])
if valid['status']:
user_id = db.get_user_id_by_hash(data['hash_sum'])
logger.warning(user_id)
tuple_of_problems = db.get_problem_id_for_del(user_id[0])
problem_list = []
for tuple_with_problem_id in tuple_of_problems:
problem_list.append(tuple_with_problem_id[0])
if problem_list:
for problem_id in problem_list:
db.change_problem_to_anon(problem_id)
db.change_activity_to_anon(problem_id)
db.delete_user(user_id[0])
logger.info('User with id %s has been deleted' % user_id[0])
response = jsonify(msg='success', deleted_user=user_id[0])
else:
db.delete_user(user_id[0])
logger.info('User with id %s has been deleted' % user_id[0])
response = jsonify(msg='success', deleted_user=user_id[0])
else:
response = Response(json.dumps(valid),
mimetype='application/json'), 400
return response