Implement player-specific and game setup settings

This commit is contained in:
Tim Van Baak 2021-09-04 13:48:24 -07:00
parent bc6f29713e
commit bff25fb97f
6 changed files with 211 additions and 24 deletions

View File

@ -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: def password_set(db: DbContext, lexicon_id: int, new_password: Optional[str]) -> None:
"""Set or clear a lexicon's password.""" """Set or clear a lexicon's password."""
password_hash = generate_password_hash(new_password) if new_password else None 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() db.session.commit()

View File

@ -114,6 +114,10 @@ textarea.fullwidth {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
input.fullwidth {
width: 100%;
box-sizing: border-box;
}
input.smallnumber { input.smallnumber {
width: 4em; width: 4em;
} }

View File

@ -50,7 +50,7 @@ def edit(lexicon_name, character_id: uuid.UUID):
# Data is valid # Data is valid
character.name = form.name.data character.name = form.name.data
character.signature = form.signature.data character.signature = form.signature.data
g.db.session.commit() g.db.session.commit() # TODO refactor into backend
return redirect( return redirect(
url_for("lexicon.characters.list", lexicon_name=lexicon_name) url_for("lexicon.characters.list", lexicon_name=lexicon_name)
) )

View File

@ -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.backend import *
from amanuensis.db 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=".") 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)) return redirect(url_for("lexicon.settings.player", lexicon_name=lexicon_name))
@bp.get("/player/") @bp.route("/player/", methods=["GET", "POST"])
@lexicon_param @lexicon_param
@player_required @player_required
def player(lexicon_name): 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 @lexicon_param
@editor_required @editor_required
def general(lexicon_name): def setup(lexicon_name):
return render_template( form = SetupSettingsForm()
"settings.jinja", lexicon_name=lexicon_name, page_name=general.__name__ 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/") else:
@lexicon_param # POST
@editor_required if form.validate():
def join(lexicon_name): # Data is valid
return render_template("settings.jinja", lexicon_name=lexicon_name, page_name=join.__name__) 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/") @bp.get("/progress/")

View File

@ -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/<name>/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/<name>/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")

View File

@ -5,12 +5,24 @@
<a{% if page_name != page %} href="{{ url_for('lexicon.settings.' + page, lexicon_name=lexicon_name) }}"{% endif %}>{{ text }}</a> <a{% if page_name != page %} href="{{ url_for('lexicon.settings.' + page, lexicon_name=lexicon_name) }}"{% endif %}>{{ text }}</a>
{%- endmacro %} {%- endmacro %}
{% macro flag_setting(field) %}
{{ field() }}
{{ field.label }}<br>
{% endmacro %}
{% macro number_setting(field) %}
{{ field(autocomplete="off", class_="smallnumber") }}
{{ field.label }}<br>
{% for error in field.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
{% endmacro %}
{% block main %} {% block main %}
{% if current_membership.is_editor %} {% if current_membership.is_editor %}
<ul class="unordered-tabs"> <ul class="unordered-tabs">
<li>{{ settings_page_link("player", "Player") }}</li> <li>{{ settings_page_link("player", "Player") }}</li>
<li>{{ settings_page_link("general", "General") }}</li> <li>{{ settings_page_link("setup", "Game Setup") }}</li>
<li>{{ settings_page_link("join", "Visibility and Joining") }}</li>
<li>{{ settings_page_link("progress", "Game Progress") }}</li> <li>{{ settings_page_link("progress", "Game Progress") }}</li>
<li>{{ settings_page_link("publish", "Turn Publishing") }}</li> <li>{{ settings_page_link("publish", "Turn Publishing") }}</li>
<li>{{ settings_page_link("article", "Article Requirements") }}</li> <li>{{ settings_page_link("article", "Article Requirements") }}</li>
@ -19,14 +31,56 @@
{% if page_name == "player" %} {% if page_name == "player" %}
<h3>Player Settings</h3> <h3>Player Settings</h3>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{% if current_membership.is_editor %}{{ flag_setting(form.notify_ready) }}{% endif %}
{{ flag_setting(form.notify_reject) }}
{{ flag_setting(form.notify_approve) }}
</p>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
{% endif %} {% endif %}
{% if page_name == "general" %} {% if page_name == "setup" %}
<h3>General Settings</h3> <h3>Game Setup</h3>
{% endif %} <form action="" method="post" novalidate>
{{ form.hidden_tag() }}
{% if page_name == "join" %} <p>
<h3>Visibility and Joining</h3> {{ form.title.label }}:<br>
{{ form.title(autocomplete="off", placeholder="Lexicon " + lexicon_name, class_="fullwidth") }}<br>
</p>
<p>
{{ form.prompt.label }}: {{ form.prompt(class_="fullwidth") }}
{% for error in form.prompt.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
</p>
<p>
{{ flag_setting(form.public) }}
{{ flag_setting(form.joinable) }}
{{ form.has_password() }}
{{ form.has_password.label }}:<br>
{{ form.password(autocomplete="off") }}
</p>
<p>
{{ number_setting(form.turn_count) }}
</p>
<p>
{{ number_setting(form.player_limit) }}
</p>
<p>
{{ number_setting(form.character_limit) }}
</p>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
{% endif %} {% endif %}
{% if page_name == "progress" %} {% if page_name == "progress" %}