Compare commits

..

1 Commits

Author SHA1 Message Date
Nikolai 5b3e5663b7 added form to lexicon creation page 2021-09-23 19:53:27 -07:00
32 changed files with 154 additions and 370 deletions

View File

@ -2,19 +2,19 @@
Post query interface
"""
from typing import Optional, Sequence, Tuple
import re
from sqlalchemy import select, update, func, or_, DateTime
from sqlalchemy import select
from amanuensis.db import DbContext, Post
from amanuensis.db.models import Lexicon, Membership
from amanuensis.db.models import Lexicon
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
db: DbContext,
lexicon_id: int,
user_id: Optional[int],
user_id: int,
body: str,
) -> Post:
"""
@ -47,57 +47,3 @@ def create(
db.session.add(new_post)
db.session.commit()
return new_post
def get_posts_for_membership(
db: DbContext, membership_id: int
) -> Tuple[Sequence[Post], Sequence[Post]]:
"""
Returns posts for the membership's lexicon, split into posts that
are new since the last view and posts that were previously seen.
"""
# Save the current timestamp, so we don't miss posts created between now
# and when we finish looking stuff up
now: DateTime = db(select(func.now())).scalar_one()
# Save the previous last-seen timestamp for splitting new from old posts,
# then update the membership with the current time
last_seen: DateTime = db(
select(Membership.last_post_seen).where(Membership.id == membership_id)
).scalar_one()
db(
update(Membership)
.where(Membership.id == membership_id)
.values(last_post_seen=now)
)
db.session.commit()
# Fetch posts in two groups, new ones after the last-seen time and old ones
# If last-seen is null, then just return everything as new
new_posts = db(
select(Post)
.where(last_seen is None or Post.created > last_seen)
.order_by(Post.created.desc())
).scalars()
old_posts = db(
select(Post)
.where(last_seen is not None and Post.created <= last_seen)
.order_by(Post.created.desc())
).scalars()
return new_posts, old_posts
def get_unread_count(db: DbContext, membership_id: int) -> int:
"""Get the number of posts that the member has not seen"""
return db(
select(func.count(Post.id))
.join(Membership, Membership.lexicon_id == Post.lexicon_id)
.where(
or_(
Membership.last_post_seen.is_(None),
Post.created > Membership.last_post_seen,
)
)
.where(Membership.id == membership_id)
).scalar()

View File

@ -8,7 +8,6 @@ import amanuensis.cli.admin
import amanuensis.cli.character
import amanuensis.cli.index
import amanuensis.cli.lexicon
import amanuensis.cli.post
import amanuensis.cli.user
from amanuensis.db import DbContext
@ -114,7 +113,6 @@ def main():
add_subcommand(subparsers, amanuensis.cli.character)
add_subcommand(subparsers, amanuensis.cli.index)
add_subcommand(subparsers, amanuensis.cli.lexicon)
add_subcommand(subparsers, amanuensis.cli.post)
add_subcommand(subparsers, amanuensis.cli.user)
# Parse args and perform top-level arg processing

View File

@ -1,31 +0,0 @@
import logging
from amanuensis.backend import *
from amanuensis.db import *
from .helpers import add_argument
COMMAND_NAME = "post"
COMMAND_HELP = "Interact with posts."
LOG = logging.getLogger(__name__)
@add_argument("--lexicon", required=True, help="The lexicon's name")
@add_argument("--by", help="The character's public id")
@add_argument("--text", help="The text of the post")
def command_create(args) -> int:
"""
Create a post in a lexicon.
"""
db: DbContext = args.get_db()
lexicon = lexiq.try_from_name(db, args.lexicon)
if not lexicon:
raise ValueError("Lexicon does not exist")
user = userq.try_from_username(db, args.by)
user_id = user.id if user else None
post: Post = postq.create(db, lexicon.id, user_id, args.text)
preview = post.body[:20] + "..." if len(post.body) > 20 else post.body
LOG.info(f"Posted '{preview}' in {lexicon.full_title}")
return 0

View File

@ -181,7 +181,7 @@ class Lexicon(ModelBase):
################################
# Whether players can join the game
joinable = Column(Boolean, nullable=False, default=False)
joinable = Column(Boolean, nullable=False, default=True)
# Whether the game is listed on public pages
public = Column(Boolean, nullable=False, default=False)
@ -251,9 +251,7 @@ class Lexicon(ModelBase):
indices = relationship("ArticleIndex", back_populates="lexicon")
index_rules = relationship("ArticleIndexRule", back_populates="lexicon")
content_rules = relationship("ArticleContentRule", back_populates="lexicon")
posts = relationship(
"Post", back_populates="lexicon", order_by="Post.created.desc()"
)
posts = relationship("Post", back_populates="lexicon")
#######################
# Derived information #

View File

@ -17,7 +17,7 @@ div#editor-left {
display: flex;
align-items: stretch;
}
div#editor-left section {
div#editor-left div.contentblock {
display: flex;
flex-direction: column;
margin: 10px 5px 10px 10px;
@ -48,7 +48,7 @@ textarea#editor-content {
div#editor-right {
overflow-y: scroll;
}
div#editor-right section {
div#editor-right div.contentblock {
margin: 10px 5px 10px 10px;
}
span.message-warning {

View File

@ -8,14 +8,14 @@ body {
line-height: 1.4;
font-size: 16px;
}
main {
div#wrapper {
max-width: 800px;
position: absolute;
left: 0;
right: 0;
margin: 0 auto;
}
header {
div#header {
padding: 5px;
margin: 5px;
background-color: #ffffff;
@ -24,7 +24,7 @@ header {
overflow: auto;
position: relative;
}
header p, header h2 {
div#header p, div#header h2 {
margin: 5px;
}
div#login-status {
@ -33,7 +33,7 @@ div#login-status {
top: 10px;
right: 10px;
}
nav {
div#sidebar {
width: 200px;
float:left;
margin:5px;
@ -46,7 +46,7 @@ nav {
img#logo {
max-width: 200px;
}
nav table {
div#sidebar table {
width: 100%;
border-collapse: collapse;
}
@ -63,32 +63,32 @@ table a {
border-radius: 5px;
text-decoration: none;
}
nav table a {
div#sidebar table a {
justify-content: center;
}
table a:hover {
background-color: var(--button-hover);
}
nav table a.current-page {
div#sidebar table a.current-page {
background-color: var(--button-current);
}
nav table a.current-page:hover {
div#sidebar table a.current-page:hover {
background-color: var(--button-current);
}
nav table td {
div#sidebar table td {
padding: 0px; margin: 3px 0;
border-bottom: 8px solid transparent;
}
article {
div#content {
margin: 5px;
}
article.content-2col {
div.content-2col {
position: absolute;
right: 0px;
left: 226px;
max-width: 564px;
}
section {
div.contentblock {
background-color: #ffffff;
box-shadow: 2px 2px 10px #888888;
margin-bottom: 5px;
@ -215,35 +215,27 @@ details.setting-help {
#index-definition-table td input[type=number] {
width: 4em;
}
section.new-post {
padding: 9px;
border: 1px dashed red;
}
p.post-byline {
color: #606060;
text-align: right;
}
@media only screen and (max-width: 816px) {
main {
div#wrapper {
padding: 5px;
}
header {
div#header {
max-width: 554px;
margin: 0 auto;
}
nav {
div#sidebar {
max-width: 548px;
width: inherit;
float: inherit;
margin: 10px auto;
}
article{
div#content{
margin: 10px auto;
}
article.content-1col {
div.content-1col {
max-width: 564px;
}
article.content-2col {
div.content-2col {
max-width: 564px;
position: static;
right: inherit;

View File

@ -76,7 +76,6 @@ def get_app(
"memq": memq,
"charq": charq,
"indq": indq,
"postq": postq,
"current_lexicon": current_lexicon,
"current_membership": current_membership
}

View File

@ -3,22 +3,21 @@
{% block header %}<h2>Amanuensis - Login</h2>{% endblock %}
{% block login_status_attr %}style="display:none"{% endblock %}
{% block main %}
<section>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>{{ form.username.label }}<br>{{ form.username(size=32) }}
{% for error in form.username.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.password.label }}<br>{{ form.password(size=32) }}
{% for error in form.password.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.remember }} {{ form.remember.label }}</p>
<p>{{ form.submit() }}</p>
{{ form.hidden_tag() }}
<p>{{ form.username.label }}<br>{{ form.username(size=32) }}
{% for error in form.username.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.password.label }}<br>{{ form.password(size=32) }}
{% for error in form.password.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.remember }} {{ form.remember.label }}</p>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
<span style="color: #ff0000">{{ message }}</span><br>
{% endfor %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -99,7 +99,7 @@ def admin_required(route):
@wraps(route)
def admin_route(*args, **kwargs):
user: User = current_user
if not user.is_authenticated or not user.is_site_admin:
if not user.is_site_admin:
flash("You must be an admin to view this page")
return redirect(url_for('home.home'))
return route(*args, **kwargs)
@ -114,13 +114,7 @@ def player_required(route):
def player_route(*args, **kwargs):
db: DbContext = g.db
user: User = current_user
lexicon: Lexicon = current_lexicon
if not user.is_authenticated:
flash("You must be a player to view this page")
if lexicon.public:
return redirect(url_for('lexicon.contents', lexicon_name=lexicon.name))
else:
return redirect(url_for('home.home'))
lexicon: Lexicon = g.lexicon
mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
if not mem:
flash("You must be a player to view this page")
@ -140,8 +134,8 @@ def player_required_if_not_public(route):
def player_route(*args, **kwargs):
db: DbContext = g.db
user: User = current_user
lexicon: Lexicon = current_lexicon
if not user.is_authenticated and not lexicon.public:
lexicon: Lexicon = g.lexicon
if not lexicon.public:
mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
if not mem:
flash("You must be a player to view this page")
@ -158,13 +152,7 @@ def editor_required(route):
def editor_route(*args, **kwargs):
db: DbContext = g.db
user: User = current_user
lexicon: Lexicon = current_lexicon
if not user.is_authenticated:
flash("You must be a player to view this page")
if lexicon.public:
return redirect(url_for('lexicon.contents', lexicon_name=lexicon.name))
else:
return redirect(url_for('home.home'))
lexicon: Lexicon = g.lexicon
mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
if not mem or not mem.is_editor:
flash("You must be the editor to view this page")

View File

@ -1,8 +1,12 @@
from flask import Blueprint, render_template, g
from operator import le
from amanuensis.backend import userq, lexiq
from sqlalchemy.sql.expression import true
from amanuensis.db.models import Lexicon
from flask import Blueprint, render_template, g, url_for, redirect
# from .forms import LexiconCreateForm
from amanuensis.backend import userq, lexiq, memq
from .forms import LexiconCreateForm
bp = Blueprint("home", __name__, url_prefix="/home", template_folder=".")
@ -18,6 +22,34 @@ def home():
def admin():
return render_template("home.admin.jinja", userq=userq, lexiq=lexiq)
@bp.get("/admin/create/")
def create():
form = LexiconCreateForm()
return render_template("home.create.jinja", form=form)
@bp.post("/admin/create/")
def create_post():
form = LexiconCreateForm()
if form.validate():
name = form.lexicon.data
editor = userq.try_from_username(g.db, form.editor.data)
prompt = form.prompt.data
assert editor is not None
lexicon = lexiq.create(g.db, name, None, prompt)
new_membership = memq.create(g.db, editor.id, lexicon.id, is_editor=True)
lexicon.joinable = False
g.db.session.commit()
return redirect(url_for("home.admin"))
else:
return render_template("home.create.jinja", form=form)
# @bp_home.route("/admin/create/", methods=['GET', 'POST'])
# @login_required

View File

@ -2,16 +2,13 @@ from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField
from wtforms.validators import DataRequired
# from amanuensis.server.forms import User, Lexicon
# class LexiconCreateForm(FlaskForm):
# """/admin/create/"""
# lexiconName = StringField(
# 'Lexicon name',
# validators=[DataRequired(), Lexicon(should_exist=False)])
# editorName = StringField(
# 'Username of editor',
# validators=[DataRequired(), User(should_exist=True)])
# promptText = TextAreaField('Prompt')
# submit = SubmitField('Create')
class LexiconCreateForm(FlaskForm):
"""/admin/create/"""
lexicon = StringField(
'Lexicon name',
validators=[DataRequired()])
editor = StringField(
'Username of editor',
validators=[DataRequired()])
prompt = TextAreaField('Prompt')
submit = SubmitField('Create')

View File

@ -3,13 +3,11 @@
{% block title %}Admin | Amanuensis{% endblock %}
{% block header %}<h2>Amanuensis - Admin Dashboard</h2>{% endblock %}
{# TODO #}
{% block sb_home %}<a href="{{ url_for('home.home') }}">Home</a>{% endblock %}
{% block sb_create %}<a href="#{#{ url_for('home.admin_create') }#}">Create a lexicon</a>{% endblock %}
{% block sb_create %}<a href="{{ url_for('home.create') }}">Create a lexicon</a>{% endblock %}
{% set template_sidebar_rows = [self.sb_home(), self.sb_create()] %}
{% block main %}
<section>
<p>Users:</p>
{% for user in userq.get_all(db) %}
{{ macros.dashboard_user_item(user) }}
@ -18,5 +16,5 @@
{% for lexicon in lexiq.get_all(db) %}
{{ macros.dashboard_lexicon_item(lexicon) }}
{% endfor %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -8,22 +8,24 @@
{% set template_sidebar_rows = [self.sb_home(), self.sb_admin()] %}
{% block main %}
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>{{ form.lexiconName.label }}<br>{{ form.lexiconName(size=32) }}
{% for error in form.lexiconName.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
{{ form.hidden_tag() }}
<p>{{ form.lexicon.label }}<br>{{ form.lexicon(size=32) }}
{% for error in form.lexicon.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.editorName.label }}<br>{{ form.editorName(size=32) }}
{% for error in form.editorName.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.editor.label }}<br>{{ form.editor(size=32) }}
{% for error in form.editor.errors %}
<br><span style="color: #ff0000">{{ error }}</span>
{% endfor %}</p>
<p>{{ form.promptText.label }}<br>{{ form.promptText(class_="fullwidth") }}</p>
<p>{{ form.prompt.label }}<br>{{ form.prompt(class_="fullwidth") }}</p>
<p>{{ form.submit() }}</p>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
<span style="color: #ff0000">{{ message }}</span><br>
{% endfor %}

View File

@ -4,13 +4,6 @@
{% block header %}<h2>Amanuensis - Home</h2>{% endblock %}
{% block main %}
{% if current_user.is_site_admin %}
<section>
<a href="{{ url_for('home.admin') }}" style="display:block; text-align:center;">Admin dashboard</a>
</section>
{% endif %}
<section>
<h1>Welcome to Amanuensis!</h1>
<p>Amanuensis is a hub for playing Lexicon, the encyclopedia RPG. Log in to access your Lexicon games. If you do not have an account, contact the administrator.</p>
@ -44,5 +37,13 @@
{% else %}
<p>No public games available.</p>
{% endif %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}
{% if current_user.is_site_admin %}
{% block admin_dash %}
<a href="{{ url_for('home.admin') }}" style="display:block; text-align:center;">Admin dashboard</a>
{% endblock %}
{% set template_content_blocks = [self.admin_dash()] + template_content_blocks %}
{% endif %}

View File

@ -15,10 +15,6 @@
{% if current_page == "contents" %}class="current-page"
{% else %}href="{{ url_for('lexicon.contents', lexicon_name=g.lexicon.name) }}"
{% endif %}>Contents</a>{% endblock %}
{% block sb_posts %}<a
{% if current_page == "posts" %}class="current-page"
{% else %}href="{{ url_for('lexicon.posts.list', lexicon_name=g.lexicon.name) }}"
{% endif %}>Posts{% set unread_count = postq.get_unread_count(g.db, current_membership.id) if current_membership else None %}{% if unread_count %} ({{ unread_count }}){% endif %}</a>{% endblock %}
{% block sb_rules %}<a
{% if current_page == "rules" %}class="current-page"
{% else %}href="{{ url_for('lexicon.rules', lexicon_name=g.lexicon.name) }}"
@ -35,7 +31,6 @@
{% set template_sidebar_rows = [
self.sb_characters(),
self.sb_contents(),
self.sb_posts(),
self.sb_rules(),
self.sb_settings(),
self.sb_stats()] %}

View File

@ -8,7 +8,6 @@ from amanuensis.server.helpers import lexicon_param, player_required_if_not_publ
from .characters import bp as characters_bp
from .forms import LexiconJoinForm
from .posts import bp as posts_bp
from .settings import bp as settings_bp
@ -16,7 +15,6 @@ bp = Blueprint(
"lexicon", __name__, url_prefix="/lexicon/<lexicon_name>", template_folder="."
)
bp.register_blueprint(characters_bp)
bp.register_blueprint(posts_bp)
bp.register_blueprint(settings_bp)

View File

@ -2,7 +2,6 @@
{% block title %}Edit {{ character.name }} | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
@ -20,5 +19,6 @@
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -3,7 +3,6 @@
{% block title %}Character | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
<h1>Characters</h1>
{% set players = memq.get_players_in_lexicon(db, g.lexicon.id)|list %}
{% set characters = charq.get_in_lexicon(db, g.lexicon.id)|list %}
@ -31,5 +30,5 @@
</li>
{% endfor %}
</ul>
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -2,15 +2,17 @@
{% block title %}{{ article.title }} | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
<h1>{{ article.title }}</h1>
{{ article.html }}
</section>
<section>
{% endblock %}
{% block citations %}
<p>
{% for citation in article.cites %}
<a href="{{ citation|articlelink }}">{{ citation }}</a>{% if not loop.last %} / {% endif %}
@ -21,5 +23,6 @@
<a href="{{ citation|articlelink }}">{{ citation }}</a>{% if not loop.last %} / {% endif %}
{% endfor %}
</p>
</section>
{% endblock %}
{% set template_content_blocks = [self.main(), self.citations()] %}

View File

@ -3,7 +3,7 @@
{% block title %}Index | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
@ -20,5 +20,6 @@
</ul>
{% endif %}
{% endfor %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -2,7 +2,7 @@
{% block title %}Join | {{ g.lexicon.full_title }}{% endblock %}
{% block main %}
<section>
<form id="lexicon-join" action="" method="post" novalidate>
{{ form.hidden_tag() }}
{% if g.lexicon.join_password %}
@ -16,5 +16,6 @@
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -3,7 +3,8 @@
{% block title %}Rules | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
Placeholder text
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -3,7 +3,8 @@
{% block title %}Session | {{ lexicon_title }}{% endblock %}
{% block main %}
<section>
Placeholder text
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -1,95 +0,0 @@
from flask import Blueprint, render_template, g
from flask.helpers import url_for
from flask_login import current_user
from werkzeug.utils import redirect
from amanuensis.backend import postq
from amanuensis.db import Post
from amanuensis.parser import RenderableVisitor, parse_raw_markdown
from amanuensis.parser.core import *
from amanuensis.server.helpers import (
lexicon_param,
player_required,
current_lexicon,
current_membership,
)
from .forms import CreatePostForm
bp = Blueprint("posts", __name__, url_prefix="/posts", template_folder=".")
class PostFormatter(RenderableVisitor):
"""Parses stylistic markdown into HTML without links."""
def TextSpan(self, span: TextSpan):
return span.innertext
def LineBreak(self, span: LineBreak):
return "<br>"
def ParsedArticle(self, span: ParsedArticle):
return "\n".join(span.recurse(self))
def BodyParagraph(self, span: BodyParagraph):
return f'<p>{"".join(span.recurse(self))}</p>'
def SignatureParagraph(self, span: SignatureParagraph):
return (
'<hr><span class="signature"><p>'
f'{"".join(span.recurse(self))}'
"</p></span>"
)
def BoldSpan(self, span: BoldSpan):
return f'<b>{"".join(span.recurse(self))}</b>'
def ItalicSpan(self, span: ItalicSpan):
return f'<i>{"".join(span.recurse(self))}</i>'
def CitationSpan(self, span: CitationSpan):
return "".join(span.recurse(self))
def render_post_body(post: Post) -> str:
"""Parse and render the body of a post into post-safe HTML."""
renderable: ParsedArticle = parse_raw_markdown(post.body)
rendered: str = renderable.render(PostFormatter())
return rendered
@bp.get("/")
@lexicon_param
@player_required
def list(lexicon_name):
form = CreatePostForm()
new_posts, old_posts = postq.get_posts_for_membership(g.db, current_membership.id)
return render_template(
"posts.jinja",
lexicon_name=lexicon_name,
form=form,
render_post_body=render_post_body,
new_posts=new_posts,
old_posts=old_posts,
)
@bp.post("/")
@lexicon_param
@player_required
def create(lexicon_name):
form = CreatePostForm()
if form.validate():
# Data is valid
postq.create(g.db, current_lexicon.id, current_user.id, form.body.data)
return redirect(url_for("lexicon.posts.list", lexicon_name=lexicon_name))
else:
# POST received invalid data
return render_template(
"posts.jinja",
lexicon_name=lexicon_name,
form=form,
render_post_body=render_post_body,
)

View File

@ -1,10 +0,0 @@
from flask_wtf import FlaskForm
from wtforms import SubmitField, TextAreaField
from wtforms.validators import DataRequired
class CreatePostForm(FlaskForm):
"""/lexicon/<name>/posts/"""
body = TextAreaField(validators=[DataRequired()])
submit = SubmitField("Post")

View File

@ -1,28 +0,0 @@
{% extends "lexicon.jinja" %}
{% set current_page = "posts" %}
{% block title %}Character | {{ lexicon_title }}{% endblock %}
{% macro make_post(post, is_new) %}
<section{% if is_new %} class="new-post"{% endif %}>
<p>{{ render_post_body(post) }}</p>
<p class="post-byline">Posted {% if post.user_id %}by {{ post.user.display_name }} {% endif %}at {{ post.created }}</p>
</section>
{% endmacro %}
{% block main %}
{% if current_lexicon.allow_post %}
<section>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>{{ form.body(class_='fullwidth') }}</p>
<p>{{ form.submit() }}</p>
</form>
</section>
{% endif %}
{% for post in new_posts %}
{{ make_post(post, True) }}
{% endfor %}
{% for post in old_posts %}
{{ make_post(post, False) }}
{% endfor %}
{% endblock %}

View File

@ -89,7 +89,6 @@ def setup(lexicon_name):
form.turn_count.data = lexicon.turn_count
form.player_limit.data = lexicon.player_limit
form.character_limit.data = lexicon.character_limit
form.allow_post.data = lexicon.allow_post
return render_template(
"settings.jinja",
lexicon_name=lexicon_name,
@ -110,7 +109,6 @@ def setup(lexicon_name):
lexicon.turn_count = form.turn_count.data
lexicon.player_limit = form.player_limit.data
lexicon.character_limit = form.character_limit.data
lexicon.allow_post = form.allow_post.data
g.db.session.commit() # TODO refactor into backend
flash("Settings saved")
return redirect(

View File

@ -49,7 +49,6 @@ class SetupSettingsForm(FlaskForm):
widget=NumberInput(),
validators=[Optional()],
)
allow_post = BooleanField("Allow players to make posts")
submit = SubmitField("Submit")

View File

@ -1,5 +1,4 @@
{% extends "lexicon.jinja" %}
{% set current_page = "settings" %}
{% block title %}Edit | {{ lexicon_title }}{% endblock %}
{% macro settings_page_link(page, text) -%}
@ -20,7 +19,6 @@
{% endmacro %}
{% block main %}
<section>
{% if current_membership.is_editor %}
<ul class="unordered-tabs">
<li>{{ settings_page_link("player", "Player Settings") }}</li>
@ -80,7 +78,6 @@
<p>
{{ number_setting(form.character_limit) }}
</p>
<p>{{ flag_setting(form.allow_post) }}</p>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
@ -175,5 +172,6 @@
{% if page_name == "article" %}
<h3>Article Requirements</h3>
{% endif %}
</section>
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File

@ -8,8 +8,8 @@
<link rel="stylesheet" href="{{ url_for('static', filename='page.css') }}">
</head>
<body>
<main>
<header>
<div id="wrapper">
<div id="header">
<div id="login-status" {% block login_status_attr %}{% endblock %}>
{% if current_user.is_authenticated %}
<b>{{ current_user.username -}}</b>
@ -24,11 +24,15 @@
{% endif %}
</div>
{% block header %}{% endblock %}
</header>
</div>
{% block sidebar %}{% endblock %}
<article class="{% block content_class %}{% endblock %}">
{% block main %}{% endblock %}
</article>
</main>
<div id="content" class="{% block content_class %}{% endblock %}">
{% if not template_content_blocks %}{% set template_content_blocks = [] %}{% endif %}
{% if not content_blocks %}{% set content_blocks = [] %}{% endif %}
{% for content_block in template_content_blocks + content_blocks %}<div class="contentblock">
{{ content_block|safe }}</div>
{% endfor %}
</div>
</div>
</body>
</html>

View File

@ -1,12 +1,12 @@
{% extends "page.jinja" %}
{% block sidebar %}
<nav>
<div id="sidebar">
{% if not template_sidebar_rows %}{% set template_sidebar_rows = [] %}{% endif %}
{% if not sidebar_rows %}{% set sidebar_rows = [] %}{% endif %}
<table>
{% for row in template_sidebar_rows + sidebar_rows %}
<tr><td>{{ row|safe }}</td></tr>{% endfor %}
</table>
</nav>
</div>
{% endblock %}
{% block content_class %}content-2col{% endblock %}

View File

@ -34,7 +34,7 @@
<body>
<div id="wrapper">
<div id="editor-left" class="column">
<section>
<div class="contentblock">
{# Thin header bar #}
<div id="editor-header">
{# Header always includes backlink to lexicon #}
@ -103,16 +103,16 @@
{# #}{{ article.contents }}{#
#}</textarea>
{% endif %}
</section>
</div>
</div>
<div id="editor-right" class="column">
<section id="preview">
<div id="preview" class="contentblock">
<p>This editor requires Javascript to function.</p>
</div>
<section id="preview-citations">
<div id="preview-citations" class="contentblock">
<p>&nbsp;</p>
</div>
<section id="preview-control">
<div id="preview-control" class="contentblock">
<p>&nbsp;</p>
</div>
</div>