roc-fnb-server/roc_fnb/website/server/user.py
2025-06-01 11:55:03 -04:00

103 lines
3.8 KiB
Python

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')