This commit is contained in:
Tim Van Baak 2021-09-15 22:17:13 -07:00
parent b94a2224c0
commit 5e5b29b3e7
8 changed files with 227 additions and 8 deletions

View File

@ -1,9 +1,10 @@
import amanuensis.backend.article as artiq
import amanuensis.backend.character as charq
import amanuensis.backend.index as indq
import amanuensis.backend.indexrule as irq
import amanuensis.backend.lexicon as lexiq
import amanuensis.backend.membership as memq
import amanuensis.backend.post as postq
import amanuensis.backend.user as userq
__all__ = ["artiq", "charq", "indq", "lexiq", "memq", "postq", "userq"]
__all__ = ["artiq", "charq", "indq", "irq", "lexiq", "memq", "postq", "userq"]

View File

@ -0,0 +1,55 @@
"""
Index rule query interface
"""
from typing import Sequence
from sqlalchemy import select
from amanuensis.db import *
from amanuensis.errors import ArgumentError, BackendArgumentTypeError
def create(
db: DbContext,
lexicon_id: int,
character_id: int,
index_id: int,
turn: int,
) -> ArticleIndexRule:
"""Create an index assignment."""
# Verify argument types are correct
if not isinstance(lexicon_id, int):
raise BackendArgumentTypeError(int, lexicon_id=lexicon_id)
if character_id is not None and not isinstance(character_id, int):
raise BackendArgumentTypeError(int, character_id=character_id)
if not isinstance(index_id, int):
raise BackendArgumentTypeError(int, index_id=index_id)
if not isinstance(turn, int):
raise BackendArgumentTypeError(int, turn=turn)
# Verify the character belongs to the lexicon
character: Character = db(
select(Character).where(Character.id == character_id)
).scalar_one_or_none()
if not character:
raise ArgumentError("Character does not exist")
if character.lexicon.id != lexicon_id:
raise ArgumentError("Character belongs to the wrong lexicon")
new_assignment: ArticleIndexRule = ArticleIndexRule(
lexicon_id=lexicon_id,
character_id=character_id,
index_id=index_id,
turn=turn,
)
db.session.add(new_assignment)
db.session.commit()
return new_assignment
def get_for_lexicon(db: DbContext, lexicon_id: int) -> Sequence[ArticleIndex]:
"""Returns all index rules for a lexicon."""
return db(
select(ArticleIndexRule).where(ArticleIndexRule.lexicon_id == lexicon_id)
).scalars()

View File

@ -1,4 +1,3 @@
import enum
import logging
from amanuensis.backend import *
@ -40,3 +39,26 @@ def command_create(args) -> int:
)
LOG.info(f"Created {index.index_type}:{index.pattern} in {lexicon.full_title}")
return 0
@add_argument("--lexicon", required=True, help="The lexicon's name")
@add_argument("--character", help="The character's public id")
@add_argument("--index", required=True, help="The index pattern")
@add_argument("--turn", required=True, type=int)
def command_assign(args) -> int:
"""
Create a turn assignment for a lexicon.
"""
db: DbContext = args.get_db()
lexicon = lexiq.try_from_name(db, args.lexicon)
if not lexicon:
raise ValueError("Lexicon does not exist")
char = charq.try_from_public_id(db, args.character)
assert char
indices = indq.get_for_lexicon(db, lexicon.id)
index = [i for i in indices if i.pattern == args.index]
if not index:
raise ValueError("Index not found")
assignment = irq.create(db, lexicon.id, char.id, index[0].id, args.turn)
LOG.info("Created")
return 0

View File

@ -201,7 +201,7 @@ ul.unordered-tabs li a[href]:hover {
background-color: var(--button-hover);
border-color: var(--button-hover);
}
#index-definition-help {
details.setting-help {
margin-block-start: 1em;
margin-block-end: 1em;
}

View File

@ -12,7 +12,7 @@ from amanuensis.server.helpers import (
current_lexicon,
)
from .forms import PlayerSettingsForm, SetupSettingsForm, IndexSchemaForm
from .forms import PlayerSettingsForm, SetupSettingsForm, IndexSchemaForm, IndexAssignmentsForm
bp = Blueprint("settings", __name__, url_prefix="/settings", template_folder=".")
@ -177,6 +177,32 @@ def index_post(lexicon_name):
)
@bp.get("/assign/")
@lexicon_param
@editor_required
def assign(lexicon_name):
# Get the current assignments
rules: Sequence[ArticleIndexRule] = list(irq.get_for_lexicon(g.db, current_lexicon.id))
rule_data = [
{
"turn": rule.turn,
"index": rule.index.pattern,
"character": rule.character.public_id,
}
for rule in rules
]
# Add a blank rule to allow for adding rules
rule_data.append({
"turn": 0,
"index": "",
"character": "",
})
form = IndexAssignmentsForm(rules=rule_data)
return render_template(
"settings.jinja", lexicon_name=lexicon_name, page_name=assign.__name__, form=form
)
@bp.get("/publish/")
@lexicon_param
@editor_required

View File

@ -13,7 +13,8 @@ from wtforms import (
from wtforms.validators import Optional, DataRequired, ValidationError
from wtforms.widgets.html5 import NumberInput
from amanuensis.db import ArticleIndex, IndexType
from amanuensis.db import ArticleIndex, IndexType, Lexicon
from amanuensis.server.helpers import current_lexicon
class PlayerSettingsForm(FlaskForm):
@ -95,3 +96,29 @@ class IndexSchemaForm(FlaskForm):
indices = FieldList(FormField(IndexDefinitionForm))
submit = SubmitField("Submit")
class AssignmentDefinitionForm(FlaskForm):
"""/lexicon/<name>/settings/assign/"""
class Meta:
# Disable CSRF on the individual assignment definitions, since the
# schema form will have one
csrf = False
turn = IntegerField(widget=NumberInput(min=0, max=99))
index = SelectField()
character = SelectField()
def __init__(self, **kwargs):
lexicon: Lexicon = current_lexicon
self.index.choices = [i.pattern for i in lexicon.indices]
self.character.choices = [(c.public_id, c.name) for c in lexicon.characters]
super().__init__(**kwargs)
class IndexAssignmentsForm(FlaskForm):
"""/lexicon/<name>/settings/assign/"""
rules = FieldList(FormField(AssignmentDefinitionForm))
submit = SubmitField("Submit")

View File

@ -24,6 +24,7 @@
<li>{{ settings_page_link("player", "Player Settings") }}</li>
<li>{{ settings_page_link("setup", "Game Setup") }}</li>
<li>{{ settings_page_link("index", "Article Indices") }}</li>
<li>{{ settings_page_link("assign", "Index Assignments") }}</li>
<li>{{ settings_page_link("publish", "Turn Publishing") }}</li>
<li>{{ settings_page_link("article", "Article Requirements") }}</li>
</ul>
@ -86,7 +87,7 @@
{% if page_name == "index" %}
<h3>Article Indexes</h3>
<details id="index-definition-help">
<details class="setting-help">
<summary>Index definition help</summary>
<p>An index is a rule that matches the title of a lexicon article based on its <em>index type</em> and <em>pattern</em>. A <em>char</em> index matches a title if the first letter of the title (excluding "A", "An", and "The") is one of the letters in the pattern. A <em>range</em> index has a pattern denoting a range of letters, such as "A-F", and matches a title if the first letter of the title is in the range. A <em>prefix</em> index matches any title that begins with the pattern. An <em>etc</em> index always matches a title.</p>
<p>When a title is to be sorted under an index, indices are checked in order, sorted first by descending order of <em>logical priority</em>, and then by alphabetical order of index pattern. The title is sorted under the first index that matches it.</p>
@ -128,13 +129,100 @@
{% endfor %}
{% endif %}
{% if page_name == "assign" %}
<h3>Index Assignments</h3>
<details class="setting-help">
<summary>Index assignment help</summary>
<p>An index assignment is a rule that requires a player to write an article under certain indices for a particular turn. If more than one rule applies to a player, any index satisfying one of those rules is permitted. If no rule applies to a player, any index is permitted.</p>
</details>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<table id="index-definition-table">
<tr>
<th>Turn</th>
<th>Index</th>
<th>Character</th>
</tr>
{% for rule_form in form.rules %}
<tr>
<td>{{ rule_form.turn() }}</td>
<td>{{ rule_form.index() }}</td>
<td>{{ rule_form.character() }}</td>
</tr>
{% for field in index_form %}
{% for error in field.errors %}
<tr>
<td colspan="5"><span style="color: #ff0000">{{ error }}</span></td>
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
</table>
<p>{{ form.submit() }}</p>
</form>
{% for message in get_flashed_messages() %}
<span style="color:#ff0000">{{ message }}</span><br>
{% endfor %}
{% endif %}
{% if page_name == "publish" %}
<h3>Turn Publishing</h3>
<h3>Turn Publishing</h3>
{# <h3>Turn Publishing</h3>
<p>
{{ form.publishDeadlines(autocomplete="off") }}
{{ form.publishDeadlines.label }}<br>
{{ flag_setting(form.publishAsap) }}
{% for error in form.publishDeadlines.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
{{ flag_setting(form.publishBlockOnReady) }}
{{ number_setting(form.publishQuorum) }}
<p>
{{ form.turnAssignment.label }}:<br>
{{ form.turnAssignment(class_="fullwidth", rows=10) }}
Transfer editorial control
</p> #}
{% endif %}
{% if page_name == "article" %}
<h3>Article Requirements</h3>
<h3>Article Requirements</h3>
{# <h3>Article Requirements</h3>
<p>
{{ flag_setting(form.articleCitationAllowSelf) }}
{{ number_setting(form.articleCitationMinExtant)}}
{{ number_setting(form.articleCitationMaxExtant)}}
{{ number_setting(form.articleCitationMinPhantom)}}
{{ number_setting(form.articleCitationMaxPhantom)}}
{{ number_setting(form.articleCitationMinTotal)}}
{{ number_setting(form.articleCitationMaxTotal)}}
{{ number_setting(form.articleCitationMinChars)}}
{{ number_setting(form.articleCitationMaxChars)}}
{{ number_setting(form.articleWordLimitSoft)}}
{{ number_setting(form.articleWordLimitHard)}}
{{ flag_setting(form.articleAddendumAllowed) }}
{{ number_setting(form.articleAddendumMax) }}
</p> #}
{% endif %}
{# <p>
Id: {{ g.lexicon.lid }}<br>
Name: {{ g.lexicon.cfg.name }}<br>
Created: {{ g.lexicon.cfg.time.created|asdate }}<br>
Completed: {{ g.lexicon.cfg.time.completed|asdate }}<br>
Players:
{% for uid in g.lexicon.cfg.join.joined %}
{{ uid|user_attr('username') }}{% if not loop.last %},{% endif %}
{% endfor %}<br>
Characters:
{% for char in g.lexicon.cfg.character.values() %}
{{ char.name }}{% if char.player %}
({{ char.player|user_attr('username') }}){% endif %}
{% if not loop.last %},{% endif %}
{% endfor %}<br>
</p> #}
{% endblock %}
{% set template_content_blocks = [self.main()] %}

View File