import json from flask import request, redirect, render_template, g, abort, make_response, flash, jsonify, session from roc_fnb.util import log, base64_encode, base64_decode from roc_fnb.website.server.decorators import require_user, logger_request_bindings from roc_fnb.website.database import InvitationClaimed, InvitationNotFound from roc_fnb.website.models.user import User def setup_user_routes(app, db): @app.post('/login') @logger_request_bindings(log) def submit_login(log): form = request.json log.info('user attempting login', name=form.get('name')) user = db.get_user_by_name(form['name']) if not user.check_password(form['password']): log.warn('incorrect password submitted', name=form['name']) abort(401) # unauthorized session['user'] = json.dumps(user.public_fields) return jsonify(status='OK') @app.get('/login') def render_login_page(): if getattr(g, 'user', None): log.debug('user is already logged in', user=g.user) return redirect('/me') return render_template('login.html') @app.get('/me') @require_user() def get_profile(): return render_template('profile.html', user=g.user) @app.get('/invite') @require_user(admin=True) def create_invite(): """ Two handlers in one: JSON and HTML. First, a user-agent (browser) makes a request for /invite, and gets the rendered HTML page. Then they click a button which sends a request specifically asking for a JSON reply. The invitation is created and returned in a JSON document. This allows a user to generate more than one invitation code per visit to the page and avoids accidentally creating an invite code on page load. """ if request.headers['Accept'] == 'application/json': invite = base64_encode(db.invite_new_user(g.user)) log.info('new invitation created', inviter=g.user, invitation_code=invite) return jsonify(invite=invite, status='OK') return render_template( 'new_invite.html', user=g.user, app_hostname=g.app_hostname ) @app.post('/new-user') def create_new_user(): decoded_invite_code = base64_decode(request.json['invite_code']) invitee = User.create( request.json['email'], request.json['name'], request.json['password'] ) try: db.store_new_invitee(decoded_invite_code, invitee) log.info('new user created', user=invitee, invite_code=request.json['invite_code']) except InvitationClaimed as err: response = make_response( json.dumps( { 'type': 'InvitationClaimed', 'invite_code': base64_encode(err.invitation['invite_code']), 'message': str(err) } ) ) response.headers['Content-Type'] = 'application/json' response.status_code = 401 abort(response) except InvitationNotFound as err: r = make_response( json.dumps( { 'type': 'InvitationNotFound', 'invite_code': err.invitation_code, 'message': str(err) } ) ) response.headers['Content-Type'] = 'application/json' response.status_code = 404 abort(response) session['user'] = json.dumps(invitee.public_fields) return jsonify(status='OK') @app.get('/new-user') def render_signup_page(): return render_template('sign-up.html')