Compare commits
6 Commits
fd5773b521
...
9f939fe57c
Author | SHA1 | Date |
---|---|---|
Tim Van Baak | 9f939fe57c | |
Tim Van Baak | af5b1c4cfa | |
Tim Van Baak | 3b95d650c1 | |
Tim Van Baak | c6f3ae4779 | |
Tim Van Baak | e480658ebe | |
Tim Van Baak | c26a0a058b |
|
@ -2,7 +2,8 @@
|
|||
Character query interface
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from typing import Optional, Sequence
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select, func
|
||||
|
||||
|
@ -68,3 +69,13 @@ def create(
|
|||
db.session.add(new_character)
|
||||
db.session.commit()
|
||||
return new_character
|
||||
|
||||
|
||||
def get_in_lexicon(db: DbContext, lexicon_id: int) -> Sequence[Character]:
|
||||
"""Get all characters in a lexicon."""
|
||||
return db(select(Character).where(Character.lexicon_id == lexicon_id)).scalars()
|
||||
|
||||
|
||||
def try_from_public_id(db: DbContext, public_id: UUID) -> Optional[Character]:
|
||||
"""Get a character by its public id."""
|
||||
return db(select(Character).where(Character.public_id == public_id)).scalar_one_or_none()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
Membership query interface
|
||||
"""
|
||||
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import select, func
|
||||
|
||||
from amanuensis.db import DbContext, Membership
|
||||
|
@ -66,6 +68,11 @@ def create(
|
|||
return new_membership
|
||||
|
||||
|
||||
def get_players_in_lexicon(db: DbContext, lexicon_id: int) -> Sequence[Membership]:
|
||||
"""Get all users who are members of a lexicon."""
|
||||
return db(select(Membership).where(Membership.lexicon_id == lexicon_id)).scalars()
|
||||
|
||||
|
||||
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(
|
||||
|
|
|
@ -5,6 +5,7 @@ import os
|
|||
from typing import Callable
|
||||
|
||||
import amanuensis.cli.admin
|
||||
import amanuensis.cli.character
|
||||
import amanuensis.cli.lexicon
|
||||
import amanuensis.cli.user
|
||||
from amanuensis.db import DbContext
|
||||
|
@ -108,6 +109,7 @@ def main():
|
|||
# Add commands from cli submodules
|
||||
subparsers = parser.add_subparsers(metavar="COMMAND")
|
||||
add_subcommand(subparsers, amanuensis.cli.admin)
|
||||
add_subcommand(subparsers, amanuensis.cli.character)
|
||||
add_subcommand(subparsers, amanuensis.cli.lexicon)
|
||||
add_subcommand(subparsers, amanuensis.cli.user)
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import logging
|
||||
|
||||
from amanuensis.backend import lexiq, userq, charq
|
||||
from amanuensis.db import DbContext, Character
|
||||
|
||||
from .helpers import add_argument
|
||||
|
||||
|
||||
COMMAND_NAME = "char"
|
||||
COMMAND_HELP = "Interact with characters."
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@add_argument("--lexicon", required=True)
|
||||
@add_argument("--user", required=True)
|
||||
@add_argument("--name", required=True)
|
||||
def command_create(args) -> int:
|
||||
"""
|
||||
Create a character.
|
||||
"""
|
||||
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.user)
|
||||
if not user:
|
||||
raise ValueError("User does not exist")
|
||||
char: Character = charq.create(db, lexicon.id, user.id, args.name, signature=None)
|
||||
LOG.info(f"Created {char.name} in {lexicon.full_title}")
|
||||
return 0
|
|
@ -126,6 +126,23 @@ div.dashboard-lexicon-item {
|
|||
padding: 0 10px;
|
||||
border-left: 3px solid black;
|
||||
}
|
||||
ul.blockitem-list {
|
||||
list-style: none;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0.5em;
|
||||
margin-inline-end: 0.5em;
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
ul.blockitem-list li {
|
||||
border-inline-start: 3px solid black;
|
||||
padding-inline-start: 0.5em;
|
||||
}
|
||||
ul.blockitem-list p {
|
||||
margin-block-start: 0.5em;
|
||||
margin-block-end: 0.5em;
|
||||
}
|
||||
div.dashboard-lexicon-unstarted {
|
||||
border-left-color: blue;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import os
|
|||
|
||||
from flask import Flask, g, url_for, redirect
|
||||
|
||||
from amanuensis.backend import lexiq, userq, memq
|
||||
from amanuensis.backend import *
|
||||
from amanuensis.config import AmanuensisConfig, CommandLineConfig
|
||||
from amanuensis.db import DbContext
|
||||
from amanuensis.parser import filesafe_title
|
||||
|
@ -68,7 +68,7 @@ def get_app(
|
|||
|
||||
# Configure jinja options
|
||||
def include_backend():
|
||||
return {"db": db, "lexiq": lexiq, "userq": userq, "memq": memq}
|
||||
return {"db": db, "lexiq": lexiq, "userq": userq, "memq": memq, "charq": charq}
|
||||
|
||||
app.jinja_options.update(trim_blocks=True, lstrip_blocks=True)
|
||||
app.template_filter("date")(date_format)
|
||||
|
|
|
@ -88,7 +88,7 @@ def editor_required(route):
|
|||
user: User = current_user
|
||||
lexicon: Lexicon = g.lexicon
|
||||
mem: Optional[Membership] = memq.try_from_ids(db, user.id, lexicon.id)
|
||||
if not mem.is_editor:
|
||||
if not mem or not mem.is_editor:
|
||||
flash("You must be the editor to view this page")
|
||||
return redirect(url_for('lexicon.contents', name=lexicon.name))
|
||||
return route(*args, **kwargs)
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sb_logo %}{% endblock %}
|
||||
{% block sb_home %}<a href="{{ url_for('home.home') }}">Home</a>
|
||||
{% endblock %}
|
||||
{% block sb_characters %}<a
|
||||
{% if current_page == "characters" %}class="current-page"
|
||||
{% else %}href="{{ url_for('lexicon.characters.characters', name=g.lexicon.name) }}"
|
||||
|
@ -36,7 +34,6 @@
|
|||
) %}
|
||||
{# self.sb_logo(), #}
|
||||
{% set template_sidebar_rows = [
|
||||
self.sb_home(),
|
||||
self.sb_characters(),
|
||||
self.sb_contents(),
|
||||
self.sb_rules(),
|
||||
|
@ -45,7 +42,6 @@
|
|||
{% else %}
|
||||
{# self.sb_logo(), #}
|
||||
{% set template_sidebar_rows = [
|
||||
self.sb_home(),
|
||||
self.sb_characters(),
|
||||
self.sb_contents(),
|
||||
self.sb_rules(),
|
||||
|
|
|
@ -1,52 +1,60 @@
|
|||
from flask import Blueprint, render_template
|
||||
from typing import Optional
|
||||
import uuid
|
||||
|
||||
from flask import Blueprint, render_template, url_for, g, flash
|
||||
from werkzeug.utils import redirect
|
||||
|
||||
from amanuensis.backend import charq
|
||||
from amanuensis.db import Character
|
||||
from amanuensis.server.helpers import lexicon_param, player_required
|
||||
|
||||
from .forms import CharacterCreateForm
|
||||
|
||||
|
||||
bp = Blueprint("characters", __name__, url_prefix="/characters", template_folder=".")
|
||||
|
||||
|
||||
@bp.route('/', methods=['GET', 'POST'])
|
||||
@bp.get('/')
|
||||
@lexicon_param
|
||||
@player_required
|
||||
def characters(name):
|
||||
return render_template("characters.jinja")
|
||||
# form = LexiconCharacterForm()
|
||||
# cid = request.args.get('cid')
|
||||
# if not cid:
|
||||
# # No character specified, creating a new character
|
||||
# return create_character(name, form)
|
||||
|
||||
# character = g.lexicon.cfg.character.get(cid)
|
||||
# if not character:
|
||||
# # Bad character id, abort
|
||||
# flash('Character not found')
|
||||
# return redirect(url_for('session.session', name=name))
|
||||
# if current_user.uid not in (character.player, g.lexicon.cfg.editor):
|
||||
# # Only its owner and the editor can edit a character
|
||||
# flash('Access denied')
|
||||
# return redirect(url_for('session.session', name=name))
|
||||
# # Edit allowed
|
||||
# return edit_character(name, form, character)
|
||||
return render_template('characters.jinja')
|
||||
|
||||
|
||||
# def edit_character(name, form, character):
|
||||
# if not form.is_submitted():
|
||||
# # GET, populate with values
|
||||
# return render_template(
|
||||
# 'session.character.jinja', form=form.for_character(character))
|
||||
@bp.route('/edit/<character_id>', methods=['GET', 'POST'])
|
||||
@lexicon_param
|
||||
@player_required
|
||||
def edit(name, character_id):
|
||||
try:
|
||||
char_uuid = uuid.UUID(character_id)
|
||||
except:
|
||||
flash("Character not found")
|
||||
return redirect(url_for('lexicon.characters.characters', name=name))
|
||||
character: Optional[Character] = charq.try_from_public_id(g.db, char_uuid)
|
||||
if not character:
|
||||
flash("Character not found")
|
||||
return redirect(url_for('lexicon.characters.characters', name=name))
|
||||
|
||||
# if not form.validate():
|
||||
# # POST with invalid data, return unchanged
|
||||
# return render_template('session.character.jinja', form=form)
|
||||
form = CharacterCreateForm()
|
||||
|
||||
# # POST with valid data, update character
|
||||
# with g.lexicon.ctx.edit_config() as cfg:
|
||||
# char = cfg.character[character.cid]
|
||||
# char.name = form.characterName.data
|
||||
# char.signature = form.defaultSignature.data
|
||||
# flash('Character updated')
|
||||
# return redirect(url_for('session.session', name=name))
|
||||
if not form.is_submitted():
|
||||
# GET
|
||||
form.name.data = character.name
|
||||
form.signature.data = character.signature
|
||||
return render_template('characters.edit.jinja', character=character, form=form)
|
||||
|
||||
else:
|
||||
# POST
|
||||
if form.validate():
|
||||
# Data is valid
|
||||
character.name = form.name.data
|
||||
character.signature = form.signature.data
|
||||
g.db.session.commit()
|
||||
return redirect(url_for('lexicon.characters.characters', name=name))
|
||||
|
||||
else:
|
||||
# POST submitted invalid data
|
||||
return render_template('characters.edit.jinja', character=character, form=form)
|
||||
|
||||
|
||||
# def create_character(name: str, form: LexiconCharacterForm):
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{% extends "lexicon.jinja" %}
|
||||
{% block title %}Edit {{ character.name }} | {{ lexicon_title }}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<form action="" method="post" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
{{ form.name.label }}<br>{{ form.name(size=32) }}
|
||||
</p>
|
||||
{% for error in form.name.errors %}
|
||||
<span style="color: #ff0000">{{ error }}</span><br>
|
||||
{% endfor %}</p>
|
||||
<p>
|
||||
{{ form.signature.label }}<br>{{ form.signature(class_='fullwidth') }}
|
||||
</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form>
|
||||
|
||||
{% for message in get_flashed_messages() %}
|
||||
<span style="color:#ff0000">{{ message }}</span><br>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
{% set template_content_blocks = [self.main()] %}
|
|
@ -2,25 +2,23 @@
|
|||
{% block title %}Character | {{ lexicon_title }}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<h1>Character</h1>
|
||||
{# <form action="" method="post" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
{{ form.characterName.label }}<br>{{ form.characterName(size=32) }}
|
||||
</p>
|
||||
{% for error in form.characterName.errors %}
|
||||
<span style="color: #ff0000">{{ error }}</span><br>
|
||||
{% endfor %}</p>
|
||||
<p>
|
||||
{{ form.defaultSignature.label }}<br>{{ form.defaultSignature(class_='fullwidth') }}
|
||||
</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form> #}
|
||||
|
||||
{# {% for message in get_flashed_messages() %}
|
||||
<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 %}
|
||||
<p>This lexicon has <b>{{ players|count }}</b> player{% if players|count > 1 %}s{% endif %} and <b>{{ characters|count }}</b> character{% if characters|count > 1 %}s{% endif %}.</p>
|
||||
{% for message in get_flashed_messages() %}
|
||||
<span style="color:#ff0000">{{ message }}</span><br>
|
||||
{% endfor %} #}
|
||||
|
||||
{% endfor %}
|
||||
<ul class="blockitem-list">
|
||||
{% for character in characters %}
|
||||
<li>
|
||||
<h3>{{ character.name }}</h3>
|
||||
<p>Player: {{ character.user.username }}</p>
|
||||
{% if character.user == current_user %}
|
||||
<p><a href="{{ url_for('lexicon.characters.edit', name=g.lexicon.name, character_id=character.public_id) }}">Edit this character</a></p>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% set template_content_blocks = [self.main()] %}
|
|
@ -0,0 +1,11 @@
|
|||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, TextAreaField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
class CharacterCreateForm(FlaskForm):
|
||||
"""/lexicon/<name>/characters/edit/<character_id>"""
|
||||
|
||||
name = StringField("Character name", validators=[DataRequired()])
|
||||
signature = TextAreaField("Signature")
|
||||
submit = SubmitField("Submit")
|
|
@ -13,8 +13,13 @@
|
|||
<div id="login-status" {% block login_status_attr %}{% endblock %}>
|
||||
{% if current_user.is_authenticated %}
|
||||
<b>{{ current_user.username -}}</b>
|
||||
(<a href="{{ url_for('auth.logout') }}">Logout</a>)
|
||||
‧
|
||||
<a href="{{ url_for('home.home') }}">Home</a>
|
||||
‧
|
||||
<a href="{{ url_for('auth.logout') }}">Logout</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('home.home') }}">Home</a>
|
||||
‧
|
||||
<a href="{{ url_for('auth.login') }}">Login</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue