diff --git a/pyproject.toml b/pyproject.toml index 8060659..13c0936 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,10 +18,11 @@ typer = "^0.9.0" python-dotenv = "^0.21.0" rich = "^13.7.0" jinja2 = "^3.1.3" +tw2-forms = "^2.2.6" +mako = "^1.3.0" #"tg.devtools" = "^2.4.3" #repoze-who = "^3.0.0" -# tw2-forms = "^2.2.6" [build-system] diff --git a/ttfrog/assets/templates/character_sheet.html b/ttfrog/assets/templates/character_sheet.html new file mode 100644 index 0000000..1dd43d1 --- /dev/null +++ b/ttfrog/assets/templates/character_sheet.html @@ -0,0 +1,5 @@ +

{{ character.name }}

+{{ form.display(value=character) }} +
+{{ character }}
+
diff --git a/ttfrog/db/bootstrap.py b/ttfrog/db/bootstrap.py index c1c17c5..37dec18 100644 --- a/ttfrog/db/bootstrap.py +++ b/ttfrog/db/bootstrap.py @@ -10,7 +10,11 @@ data = { 'ancestry': [ {'name': 'human'}, {'name': 'dragonborn'}, + {'name': 'tiefling'}, ], + 'character': [ + {'name': 'Sabetha', 'ancestry_name': 'tiefling', 'level': 10, 'str': 10, 'dex': 10, 'con': 10, 'int': 10, 'wis': 10, 'cha': 10}, + ] } diff --git a/ttfrog/db/manager.py b/ttfrog/db/manager.py index cad2fb3..12cdf22 100644 --- a/ttfrog/db/manager.py +++ b/ttfrog/db/manager.py @@ -1,4 +1,5 @@ from functools import cached_property +import logging from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker @@ -31,6 +32,13 @@ class SQLDatabaseManager: def query(self, *args, **kwargs): return self.DBSession.query(*args, **kwargs) + def update(self, table, **kwargs): + stmt = table.update().values(**kwargs) + logging.debug(stmt) + result = self.DBSession.execute(stmt) + self.DBSession.commit() + return result + def init_model(self, engine=None): metadata.create_all(bind=engine or self.engine) return self.DBSession diff --git a/ttfrog/db/schema.py b/ttfrog/db/schema.py index df8f28c..995e453 100644 --- a/ttfrog/db/schema.py +++ b/ttfrog/db/schema.py @@ -5,18 +5,17 @@ from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import UnicodeText from sqlalchemy import ForeignKey +from sqlalchemy import CheckConstraint # from sqlalchemy import PrimaryKeyConstraint # from sqlalchemy import DateTime - metadata = MetaData() Ancestry = Table( "ancestry", metadata, - Column("id", Integer, primary_key=True, autoincrement=True), + Column("name", String, primary_key=True), Column("slug", String, index=True, unique=True), - Column("name", String, index=True, unique=True), Column("description", UnicodeText), ) @@ -25,6 +24,13 @@ Character = Table( metadata, Column("id", Integer, primary_key=True, autoincrement=True), Column("slug", String, index=True, unique=True), + Column("ancestry_name", Integer, ForeignKey("ancestry.name")), Column("name", String), - Column("ancestry_id", Integer, ForeignKey("ancestry.id")), + Column("level", Integer, CheckConstraint('level > 0 AND level <= 20')), + Column("str", Integer, CheckConstraint('str >=0')), + Column("dex", Integer, CheckConstraint('dex >=0')), + Column("con", Integer, CheckConstraint('con >=0')), + Column("int", Integer, CheckConstraint('int >=0')), + Column("wis", Integer, CheckConstraint('wis >=0')), + Column("cha", Integer, CheckConstraint('cha >=0')), ) diff --git a/ttfrog/webserver/application.py b/ttfrog/webserver/application.py index 10be26c..c681686 100644 --- a/ttfrog/webserver/application.py +++ b/ttfrog/webserver/application.py @@ -7,8 +7,9 @@ from tg.util.bunch import Bunch from wsgiref.simple_server import make_server import webhelpers2 +import tw2.core -from ttfrog.webserver import controllers +from ttfrog.webserver.controllers import RootController from ttfrog.db import db import ttfrog.path @@ -28,7 +29,7 @@ def application(): config.update_blueprint({ # rendering - 'root_controller': controllers.RootController(), + 'root_controller': RootController(), 'default_renderer': 'jinja', 'renderers': ['jinja'], 'tg.jinja_filters': {}, @@ -37,7 +38,7 @@ def application(): # helpers 'app_globals': app_globals, 'helpers': webhelpers2, - 'tw2.enabled': True, + 'use_toscawidgets2': True, # assets 'serve_static': True, @@ -51,7 +52,9 @@ def application(): 'sqlalchemy.url': db.url, 'model': db, }) - return config.make_wsgi_app() + + # wrap the core wsgi app in a ToscaWidgets2 app + return tw2.core.make_middleware(config.make_wsgi_app(), default_engine='jinja') def start(host: str, port: int, debug: bool = False) -> None: diff --git a/ttfrog/webserver/controllers/__init__.py b/ttfrog/webserver/controllers/__init__.py new file mode 100644 index 0000000..c4f55f7 --- /dev/null +++ b/ttfrog/webserver/controllers/__init__.py @@ -0,0 +1,3 @@ +from .root import RootController + +__ALL__ = [RootController] diff --git a/ttfrog/webserver/controllers/character_sheet.py b/ttfrog/webserver/controllers/character_sheet.py new file mode 100644 index 0000000..08a0e84 --- /dev/null +++ b/ttfrog/webserver/controllers/character_sheet.py @@ -0,0 +1,29 @@ +from tg import expose +from tg import TGController +from ttfrog.db import db +from ttfrog.db.schema import Character +from ttfrog.webserver.widgets import CharacterSheet + + +class CharacterSheetController(TGController): + @expose() + def _lookup(self, *parts): + return FormController(parts[0]), parts[1:] + + +class FormController: + + def __init__(self, slug: str): + self.character = dict() + if slug: + self.load(slug) + + def load(self, slug: str) -> None: + self.character = db.query(Character).filter(Character.columns.slug == slug)[0]._mapping + + @expose('character_sheet.html') + def _default(self, *args, **kwargs): + if kwargs: + db.update(Character, **kwargs) + self.load(self.character['slug']) + return dict(page='sheet', form=CharacterSheet, character=self.character) diff --git a/ttfrog/webserver/controllers.py b/ttfrog/webserver/controllers/root.py similarity index 77% rename from ttfrog/webserver/controllers.py rename to ttfrog/webserver/controllers/root.py index 84eef31..bec9a01 100644 --- a/ttfrog/webserver/controllers.py +++ b/ttfrog/webserver/controllers/root.py @@ -2,11 +2,13 @@ from tg import expose from tg import TGController from tg import tmpl_context from ttfrog.db import db -from ttfrog.db.schema import Character +from ttfrog.webserver.controllers.character_sheet import CharacterSheetController class RootController(TGController): + sheet = CharacterSheetController() + def _before(self, *args, **kwargs): tmpl_context.project_name = 'TableTop Frog' diff --git a/ttfrog/webserver/widgets.py b/ttfrog/webserver/widgets.py new file mode 100644 index 0000000..5cb71ea --- /dev/null +++ b/ttfrog/webserver/widgets.py @@ -0,0 +1,13 @@ +import tw2.core +import tw2.forms +from tg import lurl + + +class CharacterSheet(tw2.forms.Form): + class child(tw2.forms.TableLayout): + name = tw2.forms.TextField() + level = tw2.forms.TextField() + ancestry_name = tw2.forms.TextField(label='Ancestry') + id = tw2.forms.HiddenField() + + action = ''