diff --git a/amanuensis/backend/post.py b/amanuensis/backend/post.py index 8a4d59d..6c0913b 100644 --- a/amanuensis/backend/post.py +++ b/amanuensis/backend/post.py @@ -2,19 +2,19 @@ Post query interface """ -import re +from typing import Optional, Sequence, Tuple -from sqlalchemy import select +from sqlalchemy import select, update, func, or_, DateTime from amanuensis.db import DbContext, Post -from amanuensis.db.models import Lexicon +from amanuensis.db.models import Lexicon, Membership from amanuensis.errors import ArgumentError, BackendArgumentTypeError def create( db: DbContext, lexicon_id: int, - user_id: int, + user_id: Optional[int], body: str, ) -> Post: """ @@ -47,3 +47,57 @@ 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() diff --git a/amanuensis/cli/__init__.py b/amanuensis/cli/__init__.py index e457db4..56af06e 100644 --- a/amanuensis/cli/__init__.py +++ b/amanuensis/cli/__init__.py @@ -8,6 +8,7 @@ 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 @@ -113,6 +114,7 @@ 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 diff --git a/amanuensis/cli/post.py b/amanuensis/cli/post.py new file mode 100644 index 0000000..1dfd7f7 --- /dev/null +++ b/amanuensis/cli/post.py @@ -0,0 +1,31 @@ +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 diff --git a/amanuensis/db/models.py b/amanuensis/db/models.py index e951309..0f7aead 100644 --- a/amanuensis/db/models.py +++ b/amanuensis/db/models.py @@ -251,7 +251,9 @@ 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") + posts = relationship( + "Post", back_populates="lexicon", order_by="Post.created.desc()" + ) ####################### # Derived information # diff --git a/amanuensis/resources/editor.css b/amanuensis/resources/editor.css index fb0e52b..2ccbbaa 100644 --- a/amanuensis/resources/editor.css +++ b/amanuensis/resources/editor.css @@ -17,7 +17,7 @@ div#editor-left { display: flex; align-items: stretch; } -div#editor-left div.contentblock { +div#editor-left section { 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 div.contentblock { +div#editor-right section { margin: 10px 5px 10px 10px; } span.message-warning { diff --git a/amanuensis/resources/page.css b/amanuensis/resources/page.css index bffd77b..0a9149d 100644 --- a/amanuensis/resources/page.css +++ b/amanuensis/resources/page.css @@ -8,14 +8,14 @@ body { line-height: 1.4; font-size: 16px; } -div#wrapper { +main { max-width: 800px; position: absolute; left: 0; right: 0; margin: 0 auto; } -div#header { +header { padding: 5px; margin: 5px; background-color: #ffffff; @@ -24,7 +24,7 @@ div#header { overflow: auto; position: relative; } -div#header p, div#header h2 { +header p, header h2 { margin: 5px; } div#login-status { @@ -33,7 +33,7 @@ div#login-status { top: 10px; right: 10px; } -div#sidebar { +nav { width: 200px; float:left; margin:5px; @@ -46,7 +46,7 @@ div#sidebar { img#logo { max-width: 200px; } -div#sidebar table { +nav table { width: 100%; border-collapse: collapse; } @@ -63,32 +63,32 @@ table a { border-radius: 5px; text-decoration: none; } -div#sidebar table a { +nav table a { justify-content: center; } table a:hover { background-color: var(--button-hover); } -div#sidebar table a.current-page { +nav table a.current-page { background-color: var(--button-current); } -div#sidebar table a.current-page:hover { +nav table a.current-page:hover { background-color: var(--button-current); } -div#sidebar table td { +nav table td { padding: 0px; margin: 3px 0; border-bottom: 8px solid transparent; } -div#content { +article { margin: 5px; } -div.content-2col { +article.content-2col { position: absolute; right: 0px; left: 226px; max-width: 564px; } -div.contentblock { +section { background-color: #ffffff; box-shadow: 2px 2px 10px #888888; margin-bottom: 5px; @@ -215,27 +215,35 @@ 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) { - div#wrapper { + main { padding: 5px; } - div#header { + header { max-width: 554px; margin: 0 auto; } - div#sidebar { + nav { max-width: 548px; width: inherit; float: inherit; margin: 10px auto; } - div#content{ + article{ margin: 10px auto; } - div.content-1col { + article.content-1col { max-width: 564px; } - div.content-2col { + article.content-2col { max-width: 564px; position: static; right: inherit; diff --git a/amanuensis/server/__init__.py b/amanuensis/server/__init__.py index c8a9827..4f70c90 100644 --- a/amanuensis/server/__init__.py +++ b/amanuensis/server/__init__.py @@ -76,6 +76,7 @@ def get_app( "memq": memq, "charq": charq, "indq": indq, + "postq": postq, "current_lexicon": current_lexicon, "current_membership": current_membership } diff --git a/amanuensis/server/auth/auth.login.jinja b/amanuensis/server/auth/auth.login.jinja index f6b6ae2..a06dce7 100644 --- a/amanuensis/server/auth/auth.login.jinja +++ b/amanuensis/server/auth/auth.login.jinja @@ -3,21 +3,22 @@ {% block header %}

Amanuensis - Login

{% endblock %} {% block login_status_attr %}style="display:none"{% endblock %} {% block main %} +
- {{ form.hidden_tag() }} -

{{ form.username.label }}
{{ form.username(size=32) }} - {% for error in form.username.errors %} -
{{ error }} - {% endfor %}

-

{{ form.password.label }}
{{ form.password(size=32) }} - {% for error in form.password.errors %} -
{{ error }} - {% endfor %}

-

{{ form.remember }} {{ form.remember.label }}

-

{{ form.submit() }}

+ {{ form.hidden_tag() }} +

{{ form.username.label }}
{{ form.username(size=32) }} + {% for error in form.username.errors %} +
{{ error }} + {% endfor %}

+

{{ form.password.label }}
{{ form.password(size=32) }} + {% for error in form.password.errors %} +
{{ error }} + {% endfor %}

+

{{ form.remember }} {{ form.remember.label }}

+

{{ form.submit() }}

{% for message in get_flashed_messages() %} {{ message }}
{% endfor %} +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/helpers.py b/amanuensis/server/helpers.py index b622a00..c665f71 100644 --- a/amanuensis/server/helpers.py +++ b/amanuensis/server/helpers.py @@ -99,7 +99,7 @@ def admin_required(route): @wraps(route) def admin_route(*args, **kwargs): user: User = current_user - if not user.is_site_admin: + if not user.is_authenticated or 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,7 +114,13 @@ def player_required(route): def player_route(*args, **kwargs): db: DbContext = g.db user: User = current_user - lexicon: Lexicon = g.lexicon + 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')) 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") @@ -134,8 +140,8 @@ def player_required_if_not_public(route): def player_route(*args, **kwargs): db: DbContext = g.db user: User = current_user - lexicon: Lexicon = g.lexicon - if not lexicon.public: + lexicon: Lexicon = current_lexicon + if not user.is_authenticated and 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") @@ -152,7 +158,13 @@ def editor_required(route): def editor_route(*args, **kwargs): db: DbContext = g.db user: User = current_user - lexicon: Lexicon = g.lexicon + 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')) 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") diff --git a/amanuensis/server/home/home.admin.jinja b/amanuensis/server/home/home.admin.jinja index 20ff0f2..ad85b95 100644 --- a/amanuensis/server/home/home.admin.jinja +++ b/amanuensis/server/home/home.admin.jinja @@ -9,6 +9,7 @@ {% set template_sidebar_rows = [self.sb_home(), self.sb_create()] %} {% block main %} +

Users:

{% for user in userq.get_all(db) %} {{ macros.dashboard_user_item(user) }} @@ -17,5 +18,5 @@ {% for lexicon in lexiq.get_all(db) %} {{ macros.dashboard_lexicon_item(lexicon) }} {% endfor %} +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/home/home.root.jinja b/amanuensis/server/home/home.root.jinja index 83d7f29..5aad068 100644 --- a/amanuensis/server/home/home.root.jinja +++ b/amanuensis/server/home/home.root.jinja @@ -4,6 +4,13 @@ {% block header %}

Amanuensis - Home

{% endblock %} {% block main %} +{% if current_user.is_site_admin %} +
+Admin dashboard +
+{% endif %} + +

Welcome to Amanuensis!

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.

@@ -37,13 +44,5 @@ {% else %}

No public games available.

{% endif %} - +
{% endblock %} -{% set template_content_blocks = [self.main()] %} - -{% if current_user.is_site_admin %} -{% block admin_dash %} -Admin dashboard -{% endblock %} -{% set template_content_blocks = [self.admin_dash()] + template_content_blocks %} -{% endif %} \ No newline at end of file diff --git a/amanuensis/server/lexicon.jinja b/amanuensis/server/lexicon.jinja index 46f18c4..1c332bc 100644 --- a/amanuensis/server/lexicon.jinja +++ b/amanuensis/server/lexicon.jinja @@ -15,6 +15,10 @@ {% if current_page == "contents" %}class="current-page" {% else %}href="{{ url_for('lexicon.contents', lexicon_name=g.lexicon.name) }}" {% endif %}>Contents{% endblock %} +{% block sb_posts %}Posts{% set unread_count = postq.get_unread_count(g.db, current_membership.id) if current_membership else None %}{% if unread_count %} ({{ unread_count }}){% endif %}{% endblock %} {% block sb_rules %}
{{ form.hidden_tag() }}

@@ -19,6 +20,5 @@ {% for message in get_flashed_messages() %} {{ message }}
{% endfor %} - + {% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/characters/characters.jinja b/amanuensis/server/lexicon/characters/characters.jinja index 278324e..bb50ad5 100644 --- a/amanuensis/server/lexicon/characters/characters.jinja +++ b/amanuensis/server/lexicon/characters/characters.jinja @@ -3,6 +3,7 @@ {% block title %}Character | {{ lexicon_title }}{% endblock %} {% block main %} +

Characters

{% set players = memq.get_players_in_lexicon(db, g.lexicon.id)|list %} {% set characters = charq.get_in_lexicon(db, g.lexicon.id)|list %} @@ -30,5 +31,5 @@ {% endfor %} +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/lexicon.article.jinja b/amanuensis/server/lexicon/lexicon.article.jinja index 9fc42d7..5e38840 100644 --- a/amanuensis/server/lexicon/lexicon.article.jinja +++ b/amanuensis/server/lexicon/lexicon.article.jinja @@ -2,17 +2,15 @@ {% block title %}{{ article.title }} | {{ lexicon_title }}{% endblock %} {% block main %} - +
{% for message in get_flashed_messages() %} {{ message }}
{% endfor %}

{{ article.title }}

{{ article.html }} - -{% endblock %} - -{% block citations %} +
+

{% for citation in article.cites %} {{ citation }}{% if not loop.last %} / {% endif %} @@ -23,6 +21,5 @@ {{ citation }}{% if not loop.last %} / {% endif %} {% endfor %}

+
{% endblock %} - -{% set template_content_blocks = [self.main(), self.citations()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/lexicon.contents.jinja b/amanuensis/server/lexicon/lexicon.contents.jinja index a61e87c..1415449 100644 --- a/amanuensis/server/lexicon/lexicon.contents.jinja +++ b/amanuensis/server/lexicon/lexicon.contents.jinja @@ -3,7 +3,7 @@ {% block title %}Index | {{ lexicon_title }}{% endblock %} {% block main %} - +
{% for message in get_flashed_messages() %} {{ message }}
{% endfor %} @@ -20,6 +20,5 @@ {% endif %} {% endfor %} - +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/lexicon.join.jinja b/amanuensis/server/lexicon/lexicon.join.jinja index cdd9b24..cf009fd 100644 --- a/amanuensis/server/lexicon/lexicon.join.jinja +++ b/amanuensis/server/lexicon/lexicon.join.jinja @@ -2,7 +2,7 @@ {% block title %}Join | {{ g.lexicon.full_title }}{% endblock %} {% block main %} - +
{{ form.hidden_tag() }} {% if g.lexicon.join_password %} @@ -16,6 +16,5 @@ {% for message in get_flashed_messages() %} {{ message }}
{% endfor %} - +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/lexicon.rules.jinja b/amanuensis/server/lexicon/lexicon.rules.jinja index 20fc070..932ad98 100644 --- a/amanuensis/server/lexicon/lexicon.rules.jinja +++ b/amanuensis/server/lexicon/lexicon.rules.jinja @@ -3,8 +3,7 @@ {% block title %}Rules | {{ lexicon_title }}{% endblock %} {% block main %} - +
Placeholder text - +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/lexicon.statistics.jinja b/amanuensis/server/lexicon/lexicon.statistics.jinja index e816653..3d3f6f5 100644 --- a/amanuensis/server/lexicon/lexicon.statistics.jinja +++ b/amanuensis/server/lexicon/lexicon.statistics.jinja @@ -3,8 +3,7 @@ {% block title %}Session | {{ lexicon_title }}{% endblock %} {% block main %} - +
Placeholder text - +
{% endblock %} -{% set template_content_blocks = [self.main()] %} \ No newline at end of file diff --git a/amanuensis/server/lexicon/posts/__init__.py b/amanuensis/server/lexicon/posts/__init__.py new file mode 100644 index 0000000..3d0a7ec --- /dev/null +++ b/amanuensis/server/lexicon/posts/__init__.py @@ -0,0 +1,95 @@ +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 "
" + + def ParsedArticle(self, span: ParsedArticle): + return "\n".join(span.recurse(self)) + + def BodyParagraph(self, span: BodyParagraph): + return f'

{"".join(span.recurse(self))}

' + + def SignatureParagraph(self, span: SignatureParagraph): + return ( + '

' + f'{"".join(span.recurse(self))}' + "

" + ) + + def BoldSpan(self, span: BoldSpan): + return f'{"".join(span.recurse(self))}' + + def ItalicSpan(self, span: ItalicSpan): + return f'{"".join(span.recurse(self))}' + + 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, + ) diff --git a/amanuensis/server/lexicon/posts/forms.py b/amanuensis/server/lexicon/posts/forms.py new file mode 100644 index 0000000..76ebd83 --- /dev/null +++ b/amanuensis/server/lexicon/posts/forms.py @@ -0,0 +1,10 @@ +from flask_wtf import FlaskForm +from wtforms import SubmitField, TextAreaField +from wtforms.validators import DataRequired + + +class CreatePostForm(FlaskForm): + """/lexicon//posts/""" + + body = TextAreaField(validators=[DataRequired()]) + submit = SubmitField("Post") diff --git a/amanuensis/server/lexicon/posts/posts.jinja b/amanuensis/server/lexicon/posts/posts.jinja new file mode 100644 index 0000000..efc3059 --- /dev/null +++ b/amanuensis/server/lexicon/posts/posts.jinja @@ -0,0 +1,28 @@ +{% extends "lexicon.jinja" %} +{% set current_page = "posts" %} +{% block title %}Character | {{ lexicon_title }}{% endblock %} + +{% macro make_post(post, is_new) %} + +

{{ render_post_body(post) }}

+ + +{% endmacro %} + +{% block main %} +{% if current_lexicon.allow_post %} +
+ + {{ form.hidden_tag() }} +

{{ form.body(class_='fullwidth') }}

+

{{ form.submit() }}

+ +
+{% endif %} +{% for post in new_posts %} +{{ make_post(post, True) }} +{% endfor %} +{% for post in old_posts %} +{{ make_post(post, False) }} +{% endfor %} +{% endblock %} diff --git a/amanuensis/server/lexicon/settings/__init__.py b/amanuensis/server/lexicon/settings/__init__.py index 12295be..975178f 100644 --- a/amanuensis/server/lexicon/settings/__init__.py +++ b/amanuensis/server/lexicon/settings/__init__.py @@ -89,6 +89,7 @@ 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, @@ -109,6 +110,7 @@ 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( diff --git a/amanuensis/server/lexicon/settings/forms.py b/amanuensis/server/lexicon/settings/forms.py index f7dfab1..e830527 100644 --- a/amanuensis/server/lexicon/settings/forms.py +++ b/amanuensis/server/lexicon/settings/forms.py @@ -49,6 +49,7 @@ class SetupSettingsForm(FlaskForm): widget=NumberInput(), validators=[Optional()], ) + allow_post = BooleanField("Allow players to make posts") submit = SubmitField("Submit") diff --git a/amanuensis/server/lexicon/settings/settings.jinja b/amanuensis/server/lexicon/settings/settings.jinja index d143b98..cfc71d2 100644 --- a/amanuensis/server/lexicon/settings/settings.jinja +++ b/amanuensis/server/lexicon/settings/settings.jinja @@ -1,4 +1,5 @@ {% extends "lexicon.jinja" %} +{% set current_page = "settings" %} {% block title %}Edit | {{ lexicon_title }}{% endblock %} {% macro settings_page_link(page, text) -%} @@ -19,6 +20,7 @@ {% endmacro %} {% block main %} +
{% if current_membership.is_editor %}
  • {{ settings_page_link("player", "Player Settings") }}
  • @@ -78,6 +80,7 @@

    {{ number_setting(form.character_limit) }}

    +

    {{ flag_setting(form.allow_post) }}

    {{ form.submit() }}

    {% for message in get_flashed_messages() %} @@ -172,6 +175,5 @@ {% if page_name == "article" %}

    Article Requirements

    {% endif %} +
{% endblock %} - -{% set template_content_blocks = [self.main()] %} diff --git a/amanuensis/server/page.jinja b/amanuensis/server/page.jinja index 5b45466..02f7740 100644 --- a/amanuensis/server/page.jinja +++ b/amanuensis/server/page.jinja @@ -8,8 +8,8 @@ -
- + {% block sidebar %}{% 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 %}
- {{ content_block|safe }}
- {% endfor %} -
-
+
+ {% block main %}{% endblock %} +
+ diff --git a/amanuensis/server/page_2col.jinja b/amanuensis/server/page_2col.jinja index dac4d32..6bce71e 100644 --- a/amanuensis/server/page_2col.jinja +++ b/amanuensis/server/page_2col.jinja @@ -1,12 +1,12 @@ {% extends "page.jinja" %} {% block sidebar %} - + {% endblock %} {% block content_class %}content-2col{% endblock %} \ No newline at end of file diff --git a/amanuensis/server/session/session.editor.jinja b/amanuensis/server/session/session.editor.jinja index 0e10d5a..031deb9 100644 --- a/amanuensis/server/session/session.editor.jinja +++ b/amanuensis/server/session/session.editor.jinja @@ -34,7 +34,7 @@
-
+
{# Thin header bar #}
{# Header always includes backlink to lexicon #} @@ -103,16 +103,16 @@ {# #}{{ article.contents }}{# #} {% endif %} -
+
-
+

This editor requires Javascript to function.

-
+

 

-
+