Reintegrate basic lexicon pages and joining #16

Merged
Jaculabilis merged 3 commits from tvb/lexicon-pages into develop 2021-08-14 15:22:24 +00:00
3 changed files with 85 additions and 88 deletions
Showing only changes of commit 587a70faf5 - Show all commits

View File

@ -64,3 +64,12 @@ def create(
db.session.add(new_membership) db.session.add(new_membership)
db.session.commit() db.session.commit()
return new_membership return new_membership
def try_from_ids(db: DbContext, user_id: int, lexicon_id: int) -> Membership:
"""Get a membership by the user and lexicon ids, or None if no such membership was found."""
return db(
select(Membership)
.where(Membership.user_id == user_id)
.where(Membership.lexicon_id == lexicon_id)
).scalar_one_or_none()

View File

@ -16,6 +16,7 @@ class BackendArgumentTypeError(ArgumentError):
A call to a backend function was made with a value of an invalid type for the parameter. A call to a backend function was made with a value of an invalid type for the parameter.
Specify the invalid parameter and value as a kwarg. Specify the invalid parameter and value as a kwarg.
""" """
def __init__(self, obj_type, **kwarg): def __init__(self, obj_type, **kwarg):
if not kwarg: if not kwarg:
raise ValueError("Missing kwarg") raise ValueError("Missing kwarg")

View File

@ -1,107 +1,94 @@
# Standard library imports
from datetime import datetime
from functools import wraps from functools import wraps
from typing import Optional
# Third party imports from flask import g, flash, redirect, url_for
from flask import g, flash, redirect, url_for, current_app
from flask_login import current_user from flask_login import current_user
# Module imports from amanuensis.backend import lexiq, memq
from amanuensis.parser import filesafe_title from amanuensis.db import DbContext, Lexicon, User, Membership
from amanuensis.models import ModelFactory, UserModel, LexiconModel
def register_custom_filters(app):
"""Adds custom filters to the Flask app"""
@app.template_filter("user_attr")
def get_user_attr(uid, attr):
factory: ModelFactory = current_app.config['model_factory']
user: UserModel = factory.user(uid)
val = getattr(user.cfg, attr)
return val
@app.template_filter("articlelink")
def article_link(title):
return url_for(
'lexicon.article',
name=g.lexicon.cfg.name,
title=filesafe_title(title))
@app.context_processor
def lexicon_status():
return dict(
PREGAME=LexiconModel.PREGAME,
ONGOING=LexiconModel.ONGOING,
COMPLETE=LexiconModel.COMPLETE)
def lexicon_param(route): def lexicon_param(route):
"""Wrapper for loading a route's lexicon""" """
@wraps(route) Wrapper for loading a route's lexicon to `g`.
def with_lexicon(**kwargs): This decorator should be applied above any other decorators that reference `g.lexicon`.
name = kwargs.get('name') """
model_factory: ModelFactory = current_app.config['model_factory'] @wraps(route)
g.lexicon = model_factory.lexicon(name) def with_lexicon(*args, **kwargs):
if g.lexicon is None: name: str = kwargs.get('name')
flash(f'Couldn\'t find a lexicon with the name "{name}"') lexicon: Optional[Lexicon] = lexiq.try_from_name(name)
return redirect(url_for("home.home")) if lexicon is None:
return route(**kwargs) flash(f"Couldn't find a lexicon with the name \"{name}\"")
return with_lexicon return redirect(url_for("home.home"))
g.lexicon = lexicon
return route(*args, **kwargs)
return with_lexicon
def admin_required(route): def admin_required(route):
""" """
Requires the user to be an admin to load this page Restricts a route to users who are site admins.
""" """
@wraps(route) @wraps(route)
def admin_route(*args, **kwargs): def admin_route(*args, **kwargs):
if not current_user.cfg.is_admin: user: User = current_user
flash("You must be an admin to view this page") if not user.is_site_admin:
return redirect(url_for('home.home')) flash("You must be an admin to view this page")
return route(*args, **kwargs) return redirect(url_for('home.home'))
return admin_route return route(*args, **kwargs)
return admin_route
def player_required(route): def player_required(route):
""" """
Requires the user to be a player in the lexicon to load this page Restricts a route to users who are players in the current lexicon.
""" """
@wraps(route) @wraps(route)
def player_route(*args, **kwargs): def player_route(*args, **kwargs):
if current_user.uid not in g.lexicon.cfg.join.joined: db: DbContext = g.db
flash("You must be a player to view this page") user: User = current_user
return (redirect(url_for('lexicon.contents', name=g.lexicon.cfg.name)) lexicon: Lexicon = g.lexicon
if g.lexicon.cfg.join.public mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
else redirect(url_for('home.home'))) if not mem:
return route(*args, **kwargs) flash("You must be a player to view this page")
return player_route if lexicon.public:
return redirect(url_for('lexicon.contents', name=lexicon.name))
else:
return redirect(url_for('home.home'))
return route(*args, **kwargs)
return player_route
def player_required_if_not_public(route): def player_required_if_not_public(route):
""" """
Requires the user to be a player in the lexicon to load this page if the Restricts a route to users who are players in the current lexicon if the lexicon is nonpublic.
lexicon has join.public = false """
""" @wraps(route)
@wraps(route) def player_route(*args, **kwargs):
def player_route(*args, **kwargs): db: DbContext = g.db
if ((not g.lexicon.cfg.join.public) user: User = current_user
and current_user.uid not in g.lexicon.cfg.join.joined): lexicon: Lexicon = g.lexicon
flash("You must be a player to view this page") if not lexicon.public:
return redirect(url_for('home.home')) mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
return route(*args, **kwargs) if not mem:
return player_route flash("You must be a player to view this page")
return redirect(url_for('home.home'))
return route(*args, **kwargs)
return player_route
def editor_required(route): def editor_required(route):
""" """
Requires the user to be the editor of the current lexicon to load this Restricts a route to users who are editors of the current lexicon.
page """
""" @wraps(route)
@wraps(route) def editor_route(*args, **kwargs):
def editor_route(*args, **kwargs): db: DbContext = g.db
if current_user.uid != g.lexicon.cfg.editor: user: User = current_user
flash("You must be the editor to view this page") lexicon: Lexicon = g.lexicon
return redirect(url_for('lexicon.contents', name=g.lexicon.cfg.name)) mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
return route(*args, **kwargs) if not mem.is_editor:
return editor_route flash("You must be the editor to view this page")
return redirect(url_for('lexicon.contents', name=lexicon.name))
return route(*args, **kwargs)
return editor_route