Compare commits

...

3 Commits

6 changed files with 96 additions and 86 deletions

View File

@ -59,6 +59,11 @@ def parse_index_type(type_str):
class IndexDefinitionForm(FlaskForm):
"""/lexicon/<name>/settings/index/"""
class Meta:
# Disable CSRF on the individual index definitions, since the schema
# form will have one
csrf = False
TYPE_CHOICES = ([("", "")] + [(str(t), str(t).lower()) for t in IndexType])
index_type = SelectField(choices=TYPE_CHOICES, coerce=parse_index_type)

View File

@ -105,7 +105,6 @@
<th>Cap</th>
</tr>
{% for index_form in form.indices %}
{{ index_form.hidden_tag() }}
<tr>
<td>{{ index_form.index_type() }}</td>
<td>{{ index_form.pattern() }}</td>

View File

@ -45,47 +45,21 @@
<h3>General</h3>
<p>
{{ form.title.label }}:<br>
{{ form.title(autocomplete="off", size=32, style="width:100%") }}<br>
{{ form.editor.label }}: {{ form.editor(autocomplete="off") }}<br>
{% for error in form.editor.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
{{ form.prompt.label }}: {{ form.prompt(class_="fullwidth") }}
{% for error in form.prompt.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
</p>
<h3>Game Progress</h3>
<p>
{{ number_setting(form.turnCurrent) }}
{{ number_setting(form.turnMax) }}
{{ form.articleIndexList.label }}:<br>
{{ form.articleIndexList(class_="fullwidth", rows=10) }}
{% for error in form.articleIndexList.errors %}
<span style="color: #ff0000">{{ error }}</span><br>
{% endfor %}
{{ number_setting(form.articleIndexCapacity) }}
{{ form.turnAssignment.label }}:<br>
{{ form.turnAssignment(class_="fullwidth", rows=10) }}
</p>
<h3>Visibility and Joining</h3>
<p>
{{ flag_setting(form.joinPublic) }}
{{ flag_setting(form.joinOpen) }}
{{ form.joinPassword(autocomplete="off") }}
{{ form.joinPassword.label }}<br>
{{ number_setting(form.joinMaxPlayers) }}
{{ number_setting(form.joinCharsPerPlayer) }}
</p>
<h3>Turn Publishing</h3>
<p>
{{ flag_setting(form.publishNotifyEditorOnReady) }}
{{ flag_setting(form.publishNotifyPlayerOnReject) }}
{{ flag_setting(form.publishNotifyPlayerOnAccept) }}
{{ form.publishDeadlines(autocomplete="off") }}
{{ form.publishDeadlines.label }}<br>
{{ flag_setting(form.publishAsap) }}

View File

@ -158,65 +158,20 @@ class Settings():
if name.startswith('s_'):
yield name, setting
s_title = Setting('title',
StringField('Title override', validators=[Optional()]))
s_editor = Setting('editor',
SelectField('Editor', validators=[DataRequired(), User(True)]),
translator=UsernameTranslator())
s_prompt = Setting('prompt',
TextAreaField('Prompt', validators=[DataRequired()]))
s_turnCurrent = Setting('turn.current',
IntegerField(
'Current turn',
widget=NumberInput(),
validators=[Optional()]))
s_turnMax = Setting('turn.max',
IntegerField(
'Number of turns',
widget=NumberInput(),
validators=[DataRequired()]))
s_turnAssignment = Setting('turn.assignment',
TextAreaField('index assignment raw'),
translator=TmpAsgnTranslator())
s_joinPublic = Setting('join.public',
BooleanField('Show game on public pages'))
s_joinOpen = Setting('join.open',
BooleanField('Allow players to join game'))
s_joinPassword = Setting('join.password',
StringField('Password to join game', validators=[Optional()]))
s_joinMaxPlayers = Setting('join.max_players',
IntegerField(
'Maximum number of players',
widget=NumberInput(),
validators=[DataRequired()]))
s_joinCharsPerPlayer = Setting('join.chars_per_player',
IntegerField(
'Characters per player',
widget=NumberInput(),
validators=[DataRequired()]))
s_publishNotifyEditorOnReady = Setting('publish.notify_editor_on_ready',
BooleanField(
'Notify the editor when a player marks an article as ready'))
s_publishNotifyPlayerOnReject = Setting('publish.notify_player_on_reject',
BooleanField(
'Notify a player when their article is rejected by the editor'))
s_publishNotifyPlayerOnAccept = Setting('publish.notify_player_on_accept',
BooleanField(
'Notify a player when their article is accepted by the editor'))
s_publishDeadlines = Setting('publish.deadlines',
StringField(
'Turn deadline, as a crontab specification',
@ -236,18 +191,6 @@ class Settings():
BooleanField(
'Block turn publish if any articles are awaiting editor review'))
s_articleIndexList = Setting('article.index.list',
TextAreaField(
'Index specifications',
validators=[IndexList]),
translator=IndexListTranslator())
s_articleIndexCapacity = Setting('article.index.capacity',
IntegerField(
'Index capacity override',
widget=NumberInput(),
validators=[Optional()]))
s_articleCitationAllowSelf = Setting('article.citation.allow_self',
BooleanField('Allow players to cite themselves'))

View File

@ -15,7 +15,6 @@ def test_character_view(db: DbContext, app: Flask, make: ObjectFactory):
username: str = f"user_{os.urandom(8).hex()}"
charname: str = f"char_{os.urandom(8).hex()}"
char_sig: str = f"signature_{os.urandom(8).hex()}"
# ub: bytes = username.encode("utf8")
with app.test_client() as client:
# Create the user and log in
@ -63,7 +62,6 @@ def test_character_view(db: DbContext, app: Flask, make: ObjectFactory):
created_redirect,
data={"name": charname, "signature": char_sig, "csrf_token": csrf_token},
)
print(response.data.decode("utf8"))
assert 300 <= response.status_code <= 399
# The character is updated

91
tests/test_index.py Normal file
View File

@ -0,0 +1,91 @@
from amanuensis.db.models import IndexType
import os
from urllib.parse import urlsplit
from bs4 import BeautifulSoup
from flask import Flask, url_for
from amanuensis.backend import memq, charq, indq
from amanuensis.db import DbContext
from tests.conftest import ObjectFactory
def test_index_view(db: DbContext, app: Flask, make: ObjectFactory):
"""Test the lexicon index page"""
with app.test_client() as client:
# Create the user and log in
user = make.user()
assert user
user_client = make.client(user.id)
assert client
user_client.login(client)
# Create a lexicon and join as the editor
lexicon = make.lexicon()
assert lexicon
mem = memq.create(db, user.id, lexicon.id, is_editor=True)
assert mem
# The index settings page exists
index_settings = url_for("lexicon.settings.index", lexicon_name=lexicon.name)
response = client.get(index_settings)
assert response.status_code == 200
# Add some indices
i1 = indq.create(db, lexicon.id, IndexType.CHAR, "ABCDE", 0, 0, 0)
assert i1
p1 = i1.pattern
assert p1
i2 = indq.create(db, lexicon.id, IndexType.RANGE, "F-M", 0, 0, 0)
assert i2
p2 = i2.pattern
assert p2
i3 = indq.create(db, lexicon.id, IndexType.CHAR, "NOPQ", 0, 0, 0)
assert i3
p3 = i3.pattern
assert p3
db.session.commit()
# The index settings page shows the indices
response = client.get(index_settings)
assert response.status_code == 200
# for i in indq.get_for_lexicon(db, lexicon.id):
assert p1.encode("utf8") in response.data
assert p2.encode("utf8") in response.data
assert p3.encode("utf8") in response.data
# Indices can be modified
soup = BeautifulSoup(response.data, features="html.parser")
csrf_token = soup.find(id="csrf_token")["value"]
assert csrf_token
response = client.post(
index_settings,
data={
"csrf_token": csrf_token,
"indices-0-index_type": "CHAR",
"indices-0-pattern": "ABCDEF",
"indices-0-logical_order": 0,
"indices-0-display_order": 0,
"indices-0-capacity": "",
"indices-1-index_type": "PREFIX",
"indices-1-pattern": "F-M",
"indices-1-logical_order": 1,
"indices-1-display_order": -1,
"indices-1-capacity": "",
"indices-2-index_type": "",
"indices-2-pattern": "NOPQ",
"indices-2-logical_order": 0,
"indices-2-display_order": 0,
"indices-2-capacity": "",
},
)
assert 300 <= response.status_code <= 399
updated_indices = list(indq.get_for_lexicon(db, lexicon.id))
assert len(updated_indices) == 2
assert updated_indices[0].index_type == IndexType.CHAR
assert updated_indices[0].pattern == "ABCDEF"
assert updated_indices[1].index_type == IndexType.PREFIX
assert updated_indices[1].pattern == "F-M"