ska-referee-test/ref-test/admin/views.py
viveksantayana c6a6ed963e Finished most of admin console
Basic CRUD operations for managing registered admin users
Encrypted personal information
Still missing sections on managing tests and results
Also missing dashboards/index/category landing pages
2021-11-23 13:00:03 +00:00

266 lines
11 KiB
Python

from flask import Blueprint, render_template, flash, redirect, request, jsonify, abort
from flask.helpers import url_for
from functools import wraps
from werkzeug.security import check_password_hash
from security.database import decrypt_find, decrypt_find_one
from .user.models import User
from flask_mail import Message
from main import db
from uuid import uuid4
import secrets
from main import mail
from datetime import datetime, timedelta
from .forms import CreateUserForm
cookie_consent = Blueprint(
'cookie_consent',
__name__
)
@cookie_consent.route('/')
def _cookies():
resp = redirect('/')
resp.set_cookie(
key = 'cookie_consent',
value = 'True',
max_age = timedelta(days=14) if request.cookies.get('remember') == 'True' else 'Session',
path = '/',
expires = datetime.utcnow() + timedelta(days=14) if request.cookies.get('remember') else 'Session'
)
return resp
views = Blueprint(
'admin_views',
__name__,
template_folder='templates',
static_folder='static'
)
def admin_account_required(function):
@wraps(function)
def decorated_function(*args, **kwargs):
if not db.users.find_one({}):
flash('No administrator accounts have been registered. Please register an administrator account.', 'alert')
return redirect(url_for('admin_auth.register'))
return function(*args, **kwargs)
return decorated_function
def disable_on_registration(function):
@wraps(function)
def decorated_function(*args, **kwargs):
if db.users.find_one({}):
return abort(404)
return function(*args, **kwargs)
return decorated_function
def get_id_from_cookie():
return request.cookies.get('_id')
def get_user_from_db(_id):
return db.users.find_one({'_id': _id})
def check_login():
_id = get_id_from_cookie()
return True if get_user_from_db(_id) else False
def login_required(function):
@wraps(function)
def decorated_function(*args, **kwargs):
if not check_login():
flash('Please log in to view this page.', 'alert')
return redirect(url_for('admin_auth.login'))
return function(*args, **kwargs)
return decorated_function
def disable_if_logged_in(function):
@wraps(function)
def decorated_function(*args, **kwargs):
if check_login():
return abort(404)
return function(*args, **kwargs)
return decorated_function
@views.route('/')
@views.route('/home/')
@views.route('/dashboard/')
@admin_account_required
@login_required
def home():
return render_template('/admin/index.html')
@views.route('/settings/')
@admin_account_required
@login_required
def settings():
return render_template('/admin/settings/index.html')
@views.route('/settings/users/', methods=['GET','POST'])
@admin_account_required
@login_required
def users():
form = CreateUserForm()
if request.method == 'GET':
users_list = decrypt_find(db.users, {})
return render_template('/admin/settings/users.html', users = users_list, form = form)
if request.method == 'POST':
if form.validate_on_submit():
entry = User(
_id = uuid4().hex,
username = request.form.get('username').lower(),
email = request.form.get('email'),
password = request.form.get('password') if not request.form.get('password') == '' else secrets.token_hex(12),
)
email = Message(
subject = 'RefTest | Registration Confirmation',
recipients = [entry.email],
body = f"""
Hello {entry.username}, \n\n
You have been registered as an administrator for the SKA RefTest App!\n\n
You can access your account using the username '{entry.username}'.\n\n
Your password is as follows:\n\n
{entry.password}\n\n
You can change your password by logging in to the admin console by copying the following URL into a web browser:\n\n
{url_for('admin_views.home', _external = True)}\n\n
Have a nice day.
""",
html = f"""
<p>Hello {entry.username},</p>
<p>You have been registered as an administrator for the SKA RefTest App!</p>
<p>You can access your account using the username '{entry.username}'.</p>
<p>Your password is as follows:</p>
<strong>{entry.password}</strong>
<p>You can change your password by logging in to the admin console at the link below:</p>
<p><a href='{url_for('admin_views.home', _external = True)}'>{url_for('admin_views.home', _external = True)}</a></p>
<p>Have a nice day.</p>
"""
)
mail.send(email)
return entry.register()
else:
errors = [*form.username.errors, *form.email.errors, *form.password.errors]
return jsonify({ 'error': errors}), 400
@views.route('/settings/users/delete/<string:_id>', methods = ['GET', 'POST'])
@admin_account_required
@login_required
def delete_user(_id:str):
if _id == get_id_from_cookie():
flash('Cannot delete your own user account.', 'error')
return redirect(url_for('admin_views.users'))
from .forms import DeleteUserForm
form = DeleteUserForm()
user = decrypt_find_one(db.users, {'_id': _id})
if request.method == 'GET':
if not user:
return abort(404)
return render_template('/admin/settings/delete-user.html', form = form, _id = _id, user = user)
if request.method == 'POST':
if not user:
return jsonify({ 'error': 'User does not exist.' }), 404
if form.validate_on_submit():
_user = decrypt_find_one(db.users, {'_id': get_id_from_cookie()})
password = request.form.get('password')
if not check_password_hash(_user['password'], password):
return jsonify({ 'error': 'The password you entered is incorrect.' }), 401
if request.form.get('notify'):
email = Message(
subject = 'RefTest | Account Deletion',
recipients = [user['email']],
bcc = [_user['email']],
body = f"""
Hello {user['username']}, \n\n
Your administrator account for the SKA RefTest App has been deleted by {_user['username']}. All data about your account has been deleted.\n\n
If you believe this was done in error, please contact them immediately.\n\n
If you would like to register to administer the app, please ask an existing administrator to create a new account.\n\n
Have a nice day.
""",
html = f"""
<p>Hello {user['username']},</p>
<p>Your administrator account for the SKA RefTest App has been deleted by {_user['username']}. All data about your account has been deleted.</p>
<p>If you believe this was done in error, please contact them immediately.</p>
<p>If you would like to register to administer the app, please ask an existing administrator to create a new account.</p>
<p>Have a nice day.</p>
"""
)
mail.send(email)
user = User(
_id = user['_id']
)
return user.delete()
else: return abort(400)
@views.route('/settings/users/update/<string:_id>', methods = ['GET', 'POST'])
@admin_account_required
@login_required
def update_user(_id:str):
if _id == get_id_from_cookie():
flash('Cannot delete your own user account.', 'error')
return redirect(url_for('admin_views.users'))
from .forms import UpdateUserForm
form = UpdateUserForm()
user = decrypt_find_one( db.users, {'_id': _id})
if request.method == 'GET':
if not user:
return abort(404)
return render_template('/admin/settings/update-user.html', form = form, _id = _id, user = user)
if request.method == 'POST':
if not user:
return jsonify({ 'error': 'User does not exist.' }), 404
if form.validate_on_submit():
_user = decrypt_find_one(db.users, {'_id': get_id_from_cookie()})
password = request.form.get('password')
if not check_password_hash(_user['password'], password):
return jsonify({ 'error': 'The password you entered is incorrect.' }), 401
if request.form.get('notify'):
recipient = request.form.get('email') if not request.form.get('email') == '' else user['email']
email = Message(
subject = 'RefTest | Account Update',
recipients = [recipient],
bcc = [_user['email']],
body = f"""
Hello {user['username']}, \n\n
Your administrator account for the SKA RefTest App has been updated by {_user['username']}.\n\n
Your new account details are as follows:\n\n
Email: {recipient}\n
Password: {request.form.get('password')}\n\n
You can update your email and password by logging in to the app.\n\n
Have a nice day.
""",
html = f"""
<p>Hello {user['username']},</p>
<p>Your administrator account for the SKA RefTest App has been updated by {_user['username']}.</p>
<p>Your new account details are as follows:</p>
<p>Email: {recipient} <br/>Password: {request.form.get('password')}</p>
<p>You can update your email and password by logging in to the app.</p>
<p>Have a nice day.</p>
"""
)
mail.send(email)
entry = User(
_id = _id,
email = request.form.get('email'),
password = request.form.get('password')
)
return entry.update()
else:
errors = [*form.user_password.errors, *form.email.errors, *form.password.errors, *form.password_reenter.errors]
return jsonify({ 'error': errors}), 400
@views.route('/settings/questions/')
@admin_account_required
@login_required
def questions():
return render_template('/admin/settings/questions.html')
@views.route('/settings/questions/upload/')
@admin_account_required
@login_required
def upload_questions():
return render_template('/admin/settings/upload-questions.html')
@views.route('/tests/')
@admin_account_required
@login_required
def tests():
return render_template('/admin/tests.html')