Add character backend
This commit is contained in:
parent
e47711356c
commit
caa2e1e8a4
64
amanuensis/backend/character.py
Normal file
64
amanuensis/backend/character.py
Normal file
@ -0,0 +1,64 @@
|
||||
"""
|
||||
Character query interface
|
||||
"""
|
||||
|
||||
from sqlalchemy import select, func
|
||||
|
||||
from amanuensis.db import *
|
||||
from amanuensis.errors import ArgumentError
|
||||
|
||||
|
||||
def create(
|
||||
db: DbContext,
|
||||
lexicon_id: int,
|
||||
user_id: int,
|
||||
name: str,
|
||||
signature: str) -> Character:
|
||||
"""
|
||||
Create a new character for a user.
|
||||
"""
|
||||
# Verify argument types are correct
|
||||
if not isinstance(lexicon_id, int):
|
||||
raise ArgumentError('lexicon_id')
|
||||
if not isinstance(user_id, int):
|
||||
raise ArgumentError('user_id')
|
||||
if not isinstance(name, str):
|
||||
raise ArgumentError('name')
|
||||
if signature is not None and not isinstance(signature, str):
|
||||
raise ArgumentError('signature')
|
||||
|
||||
# Verify character name is valid
|
||||
if not name.strip():
|
||||
raise ArgumentError('Character name cannot be blank')
|
||||
|
||||
# If no signature is provided, use a default signature
|
||||
if not signature or not signature.strip():
|
||||
signature = f'~{name}'
|
||||
|
||||
# Check that the user is a member of this lexicon
|
||||
mem: Membership = db(
|
||||
select(Membership)
|
||||
.where(Membership.user_id == user_id)
|
||||
.where(Membership.lexicon_id == lexicon_id)
|
||||
).scalar_one_or_none()
|
||||
if not mem:
|
||||
raise ArgumentError('User is not a member of lexicon')
|
||||
|
||||
# Check that this user is below the limit for creating characters
|
||||
num_user_chars = db(
|
||||
select(func.count(Character.id))
|
||||
.where(Character.lexicon_id == lexicon_id)
|
||||
.where(Character.user_id == user_id)
|
||||
).scalar()
|
||||
if mem.lexicon.character_limit is not None and num_user_chars >= mem.lexicon.character_limit:
|
||||
raise ArgumentError('User is at character limit')
|
||||
|
||||
new_character = Character(
|
||||
lexicon_id=lexicon_id,
|
||||
user_id=user_id,
|
||||
name=name,
|
||||
signature=signature,
|
||||
)
|
||||
db.session.add(new_character)
|
||||
db.session.commit()
|
||||
return new_character
|
73
tests/test_character.py
Normal file
73
tests/test_character.py
Normal file
@ -0,0 +1,73 @@
|
||||
import pytest
|
||||
|
||||
from amanuensis.db import *
|
||||
import amanuensis.backend.character as charq
|
||||
from amanuensis.errors import ArgumentError
|
||||
|
||||
|
||||
def test_create_character(db: DbContext, lexicon_with_editor, make_user):
|
||||
"""Test creating a character."""
|
||||
lexicon, user = lexicon_with_editor
|
||||
kwargs = {
|
||||
'db': db,
|
||||
'user_id': user.id,
|
||||
'lexicon_id': lexicon.id,
|
||||
'name': 'Character Name',
|
||||
'signature': 'Signature',
|
||||
}
|
||||
|
||||
# Bad argument types
|
||||
with pytest.raises(ArgumentError):
|
||||
charq.create(**{**kwargs, 'name': b'bytestring'})
|
||||
with pytest.raises(ArgumentError):
|
||||
charq.create(**{**kwargs, 'name': None})
|
||||
with pytest.raises(ArgumentError):
|
||||
charq.create(**{**kwargs, 'signature': b'bytestring'})
|
||||
|
||||
# Bad character name
|
||||
with pytest.raises(ArgumentError):
|
||||
charq.create(**{**kwargs, 'name': ' '})
|
||||
|
||||
# Signature is auto-populated
|
||||
char = charq.create(**{**kwargs, 'signature': None})
|
||||
assert char.signature is not None
|
||||
|
||||
# User must be in lexicon
|
||||
new_user = make_user()
|
||||
with pytest.raises(ArgumentError):
|
||||
charq.create(**{**kwargs, 'user_id': new_user.id})
|
||||
|
||||
|
||||
def test_character_limits(db: DbContext, lexicon_with_editor):
|
||||
"""Test lexicon settings limiting character creation."""
|
||||
lexicon: Lexicon
|
||||
user: User
|
||||
lexicon, user = lexicon_with_editor
|
||||
|
||||
# Set character limit to one and create a character
|
||||
lexicon.character_limit = 1
|
||||
db.session.commit()
|
||||
char1 = charq.create(db, lexicon.id, user.id, 'Test Character 1', signature=None)
|
||||
assert char1.id, 'Failed to create character 1'
|
||||
|
||||
# Creating a second character should fail
|
||||
with pytest.raises(ArgumentError):
|
||||
char2 = charq.create(db, lexicon.id, user.id, 'Test Character 2', signature=None)
|
||||
assert char2
|
||||
|
||||
# Raising the limit to 2 should allow a second character
|
||||
lexicon.character_limit = 2
|
||||
db.session.commit()
|
||||
char2 = charq.create(db, lexicon.id, user.id, 'Test Character 2', signature=None)
|
||||
assert char2.id, 'Failed to create character 2'
|
||||
|
||||
# Creating a third character should fail
|
||||
with pytest.raises(ArgumentError):
|
||||
char3 = charq.create(db, lexicon.id, user.id, 'Test Character 3', signature=None)
|
||||
assert char3
|
||||
|
||||
# Setting the limit to null should allow a third character
|
||||
lexicon.character_limit = None
|
||||
db.session.commit()
|
||||
char3 = charq.create(db, lexicon.id, user.id, 'Test Character 3', signature=None)
|
||||
assert char3.id, 'Failed to create character 3'
|
Loading…
Reference in New Issue
Block a user