2
0
mirror of https://github.com/offen/website.git synced 2024-11-23 01:20:29 +01:00
website/accounts/accounts/views.py

123 lines
3.7 KiB
Python

from datetime import datetime, timedelta
import requests
from flask_admin.contrib.sqla import ModelView
from wtforms import PasswordField, StringField, Form
from wtforms.validators import InputRequired, EqualTo
from passlib.hash import bcrypt
import jwt
from accounts import db, app
from accounts.models import AccountUserAssociation
class RemoteServerException(Exception):
status = 0
def __str__(self):
return "Status {}: {}".format(
self.status, super(RemoteServerException, self).__str__()
)
def _call_remote_server(account_id, method):
# expires in 30 seconds as this will mean the HTTP request would have
# timed out anyways
expiry = datetime.utcnow() + timedelta(seconds=30)
encoded = jwt.encode(
{"ok": True, "exp": expiry, "priv": {"rpc": "1"}},
app.config["JWT_PRIVATE_KEY"].encode(),
algorithm="RS256",
).decode("utf-8")
do_request = None
if method == "POST":
do_request = requests.post
elif method == "DELETE":
do_request = requests.delete
if not do_request:
raise Exception("Received unsupported method {}, cannot continue.".format(method))
r = do_request(
"{}/accounts".format(app.config["SERVER_HOST"]),
json={"accountId": account_id},
headers={"X-RPC-Authentication": encoded},
)
if r.status_code > 299:
err = r.json()
remote_err = RemoteServerException(err["error"])
remote_err.status = err["status"]
raise remote_err
def create_remote_account(account_id):
return _call_remote_server(account_id, "POST")
def retire_remote_account(account_id):
return _call_remote_server(account_id, "DELETE")
class AccountForm(Form):
name = StringField(
"Account Name",
validators=[InputRequired()],
description="This is the account name visible to users",
)
class AccountView(ModelView):
form = AccountForm
column_display_all_relations = True
column_list = ("name", "account_id")
def after_model_change(self, form, model, is_created):
if is_created:
try:
create_remote_account(model.account_id)
except RemoteServerException as server_error:
db.session.delete(model)
db.session.commit()
raise server_error
def after_model_delete(self, model):
retire_remote_account(model.account_id)
class UserView(ModelView):
inline_models = [(AccountUserAssociation, dict(form_columns=["id", "account"]))]
column_auto_select_related = True
column_display_all_relations = True
column_list = ("email", "user_id")
form_columns = ("email", "accounts")
form_create_rules = ("email", "password", "confirm", "accounts")
form_edit_rules = ("email", "password", "confirm", "accounts")
def on_model_change(self, form, model, is_created):
if form.password.data:
model.hashed_password = bcrypt.hash(form.password.data)
def get_create_form(self):
form = super(UserView, self).get_create_form()
form.password = PasswordField(
"Password",
validators=[
InputRequired(),
EqualTo("confirm", message="Passwords must match"),
],
)
form.confirm = PasswordField("Repeat Password", validators=[InputRequired()])
return form
def get_edit_form(self):
form = super(UserView, self).get_edit_form()
form.password = PasswordField(
"Password",
description="When left blank, the password will remain unchanged on update",
validators=[EqualTo("confirm", message="Passwords must match")],
)
form.confirm = PasswordField("Repeat Password", validators=[])
return form