From 7e54b14b7f692748d4359a2b656a312f7f4d9c72 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Sat, 4 Sep 2021 13:48:24 -0700 Subject: [PATCH] Implement player-specific and game setup settings --- amanuensis/backend/lexicon.py | 6 +- amanuensis/resources/page.css | 4 + .../server/lexicon/characters/__init__.py | 2 +- .../server/lexicon/settings/__init__.py | 108 +++++++++++++++--- amanuensis/server/lexicon/settings/forms.py | 45 ++++++++ .../server/lexicon/settings/settings.jinja | 70 ++++++++++-- 6 files changed, 211 insertions(+), 24 deletions(-) create mode 100644 amanuensis/server/lexicon/settings/forms.py diff --git a/amanuensis/backend/lexicon.py b/amanuensis/backend/lexicon.py index d2dab71..233c427 100644 --- a/amanuensis/backend/lexicon.py +++ b/amanuensis/backend/lexicon.py @@ -84,7 +84,11 @@ def password_check(db: DbContext, lexicon_id: int, password: str) -> bool: def password_set(db: DbContext, lexicon_id: int, new_password: Optional[str]) -> None: """Set or clear a lexicon's password.""" password_hash = generate_password_hash(new_password) if new_password else None - db(update(Lexicon).where(Lexicon.id == lexicon_id).values(password=password_hash)) + db( + update(Lexicon) + .where(Lexicon.id == lexicon_id) + .values(join_password=password_hash) + ) db.session.commit() diff --git a/amanuensis/resources/page.css b/amanuensis/resources/page.css index db95940..c798e74 100644 --- a/amanuensis/resources/page.css +++ b/amanuensis/resources/page.css @@ -114,6 +114,10 @@ textarea.fullwidth { width: 100%; box-sizing: border-box; } +input.fullwidth { + width: 100%; + box-sizing: border-box; +} input.smallnumber { width: 4em; } diff --git a/amanuensis/server/lexicon/characters/__init__.py b/amanuensis/server/lexicon/characters/__init__.py index 0a3483c..56d5a0d 100644 --- a/amanuensis/server/lexicon/characters/__init__.py +++ b/amanuensis/server/lexicon/characters/__init__.py @@ -50,7 +50,7 @@ def edit(lexicon_name, character_id: uuid.UUID): # Data is valid character.name = form.name.data character.signature = form.signature.data - g.db.session.commit() + g.db.session.commit() # TODO refactor into backend return redirect( url_for("lexicon.characters.list", lexicon_name=lexicon_name) ) diff --git a/amanuensis/server/lexicon/settings/__init__.py b/amanuensis/server/lexicon/settings/__init__.py index 9705e58..3a161a9 100644 --- a/amanuensis/server/lexicon/settings/__init__.py +++ b/amanuensis/server/lexicon/settings/__init__.py @@ -1,8 +1,16 @@ -from flask import Blueprint, render_template, url_for, redirect +from flask import Blueprint, render_template, url_for, g, flash, redirect from amanuensis.backend import * from amanuensis.db import * -from amanuensis.server.helpers import editor_required, lexicon_param, player_required +from amanuensis.server.helpers import ( + editor_required, + lexicon_param, + player_required, + current_membership, + current_lexicon, +) + +from .forms import PlayerSettingsForm, SetupSettingsForm bp = Blueprint("settings", __name__, url_prefix="/settings", template_folder=".") @@ -15,27 +23,99 @@ def page(lexicon_name): return redirect(url_for("lexicon.settings.player", lexicon_name=lexicon_name)) -@bp.get("/player/") +@bp.route("/player/", methods=["GET", "POST"]) @lexicon_param @player_required def player(lexicon_name): - return render_template("settings.jinja", lexicon_name=lexicon_name, page_name=player.__name__) + form = PlayerSettingsForm() + mem: Membership = current_membership + + if not form.is_submitted(): + # GET + form.notify_ready.data = mem.notify_ready + form.notify_reject.data = mem.notify_reject + form.notify_approve.data = mem.notify_approve + return render_template( + "settings.jinja", + lexicon_name=lexicon_name, + page_name=player.__name__, + form=form, + ) + + else: + # POST + if form.validate(): + # Data is valid + mem.notify_ready = form.notify_ready.data + mem.notify_reject = form.notify_reject.data + mem.notify_approve = form.notify_approve.data + g.db.session.commit() # TODO refactor into backend + flash("Settings saved") + return redirect( + url_for("lexicon.settings.player", lexicon_name=lexicon_name) + ) + + else: + # Invalid POST data + return render_template( + "settings.jinja", + lexicon_name=lexicon_name, + page_name=player.__name__, + form=form, + ) -@bp.get("/general/") +@bp.route("/setup/", methods=["GET", "POST"]) @lexicon_param @editor_required -def general(lexicon_name): - return render_template( - "settings.jinja", lexicon_name=lexicon_name, page_name=general.__name__ - ) +def setup(lexicon_name): + form = SetupSettingsForm() + lexicon: Lexicon = current_lexicon + if not form.is_submitted(): + # GET + form.title.data = lexicon.title + form.prompt.data = lexicon.prompt + form.public.data = lexicon.public + form.joinable.data = lexicon.joinable + form.has_password.data = lexicon.join_password is not None + form.turn_count.data = lexicon.turn_count + form.player_limit.data = lexicon.player_limit + form.character_limit.data = lexicon.character_limit + return render_template( + "settings.jinja", + lexicon_name=lexicon_name, + page_name=setup.__name__, + form=form, + ) -@bp.get("/join/") -@lexicon_param -@editor_required -def join(lexicon_name): - return render_template("settings.jinja", lexicon_name=lexicon_name, page_name=join.__name__) + else: + # POST + if form.validate(): + # Data is valid + lexicon.title = form.title.data + lexicon.prompt = form.prompt.data + lexicon.public = form.public.data + lexicon.joinable = form.joinable.data + new_password = form.password.data if form.has_password.data else None + lexiq.password_set(g.db, lexicon.id, new_password) + lexicon.turn_count = form.turn_count.data + lexicon.player_limit = form.player_limit.data + lexicon.character_limit = form.character_limit.data + g.db.session.commit() # TODO refactor into backend + flash("Settings saved") + return redirect( + url_for("lexicon.settings.setup", lexicon_name=lexicon_name) + ) + + else: + # Invalid POST data + return render_template( + "settings.jinja", + lexicon_name=lexicon_name, + page_name=setup.__name__, + form=form, + ) @bp.get("/progress/") diff --git a/amanuensis/server/lexicon/settings/forms.py b/amanuensis/server/lexicon/settings/forms.py new file mode 100644 index 0000000..612a7af --- /dev/null +++ b/amanuensis/server/lexicon/settings/forms.py @@ -0,0 +1,45 @@ +from flask_wtf import FlaskForm +from wtforms import ( + BooleanField, + IntegerField, + PasswordField, + StringField, + SubmitField, + TextAreaField, +) +from wtforms.validators import Optional, DataRequired +from wtforms.widgets.html5 import NumberInput + + +class PlayerSettingsForm(FlaskForm): + """/lexicon//settings/player/""" + + notify_ready = BooleanField("Notify me when an article is submitted for review") + notify_reject = BooleanField("Notify me when an editor rejects one of my articles") + notify_approve = BooleanField( + "Notify me when an editor approves one of my articles" + ) + submit = SubmitField("Submit") + + +class SetupSettingsForm(FlaskForm): + """/lexicon//settings/setup/""" + + title = StringField("Title override") + prompt = TextAreaField("Prompt", validators=[DataRequired()]) + public = BooleanField("Make game publicly visible") + joinable = BooleanField("Allow players to join game") + has_password = BooleanField("Require password to join the game") + password = PasswordField("Game password") + turn_count = IntegerField( + "Number of turns", widget=NumberInput(), validators=[DataRequired()] + ) + player_limit = IntegerField( + "Maximum number of players", widget=NumberInput(), validators=[Optional()] + ) + character_limit = IntegerField( + "Maximum number of characters per player", + widget=NumberInput(), + validators=[Optional()], + ) + submit = SubmitField("Submit") diff --git a/amanuensis/server/lexicon/settings/settings.jinja b/amanuensis/server/lexicon/settings/settings.jinja index 6cfa2ce..3c4de9e 100644 --- a/amanuensis/server/lexicon/settings/settings.jinja +++ b/amanuensis/server/lexicon/settings/settings.jinja @@ -5,12 +5,24 @@ {{ text }} {%- endmacro %} +{% macro flag_setting(field) %} +{{ field() }} +{{ field.label }}
+{% endmacro %} + +{% macro number_setting(field) %} +{{ field(autocomplete="off", class_="smallnumber") }} +{{ field.label }}
+{% for error in field.errors %} +{{ error }}
+{% endfor %} +{% endmacro %} + {% block main %} {% if current_membership.is_editor %}
  • {{ settings_page_link("player", "Player") }}
  • -
  • {{ settings_page_link("general", "General") }}
  • -
  • {{ settings_page_link("join", "Visibility and Joining") }}
  • +
  • {{ settings_page_link("setup", "Game Setup") }}
  • {{ settings_page_link("progress", "Game Progress") }}
  • {{ settings_page_link("publish", "Turn Publishing") }}
  • {{ settings_page_link("article", "Article Requirements") }}
  • @@ -19,14 +31,56 @@ {% if page_name == "player" %}

    Player Settings

    +
    + {{ form.hidden_tag() }} +

    + {% if current_membership.is_editor %}{{ flag_setting(form.notify_ready) }}{% endif %} + {{ flag_setting(form.notify_reject) }} + {{ flag_setting(form.notify_approve) }} +

    +

    {{ form.submit() }}

    +
    + + {% for message in get_flashed_messages() %} + {{ message }}
    + {% endfor %} {% endif %} -{% if page_name == "general" %} -

    General Settings

    -{% endif %} - -{% if page_name == "join" %} -

    Visibility and Joining

    +{% if page_name == "setup" %} +

    Game Setup

    +
    + {{ form.hidden_tag() }} +

    + {{ form.title.label }}:
    + {{ form.title(autocomplete="off", placeholder="Lexicon " + lexicon_name, class_="fullwidth") }}
    +

    +

    + {{ form.prompt.label }}: {{ form.prompt(class_="fullwidth") }} + {% for error in form.prompt.errors %} + {{ error }}
    + {% endfor %} +

    +

    + {{ flag_setting(form.public) }} + {{ flag_setting(form.joinable) }} + {{ form.has_password() }} + {{ form.has_password.label }}:
    + {{ form.password(autocomplete="off") }} +

    +

    + {{ number_setting(form.turn_count) }} +

    +

    + {{ number_setting(form.player_limit) }} +

    +

    + {{ number_setting(form.character_limit) }} +

    +

    {{ form.submit() }}

    +
    + {% for message in get_flashed_messages() %} + {{ message }}
    + {% endfor %} {% endif %} {% if page_name == "progress" %}