Compare commits
1 Commits
0d022af335
...
5e5b29b3e7
Author | SHA1 | Date |
---|---|---|
Tim Van Baak | 5e5b29b3e7 |
|
@ -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"]
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()] %}
|
||||
|
|
Loading…
Reference in New Issue