rewrite using pyramid and wtforms
This commit is contained in:
@@ -10,9 +10,14 @@ from ttfrog.webserver.routes import routes
|
||||
def configuration():
|
||||
config = Configurator(settings={
|
||||
'sqlalchemy.url': db.url,
|
||||
'jinja2.directories': 'ttfrog.assets:templates/'
|
||||
})
|
||||
config.include('pyramid_tm')
|
||||
config.include('pyramid_sqlalchemy')
|
||||
config.include('pyramid_jinja2')
|
||||
config.add_static_view(name='/static', path='ttfrog.assets:static/')
|
||||
config.add_jinja2_renderer('.html', settings_prefix='jinja2.')
|
||||
|
||||
return config
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from .base import BaseController
|
||||
from .character_sheet import CharacterSheet
|
||||
|
||||
__all__ = [BaseController, CharacterSheet]
|
||||
|
||||
@@ -1,19 +1,74 @@
|
||||
import inspect
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from tg import flash
|
||||
from tg import TGController
|
||||
from tg import tmpl_context
|
||||
from markupsafe import Markup
|
||||
from wtforms_sqlalchemy.orm import model_form
|
||||
|
||||
from ttfrog.db.manager import db
|
||||
|
||||
|
||||
class BaseController(TGController):
|
||||
class BaseController:
|
||||
model = None
|
||||
|
||||
def _before(self, *args, **kwargs):
|
||||
tmpl_context.project_name = 'TableTop Frog'
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
self.record = None
|
||||
self.attrs = defaultdict(str)
|
||||
self.configure()
|
||||
if self.model:
|
||||
self.model_form = model_form(self.model, db_session=db.session)
|
||||
|
||||
# load this from dotenv or something
|
||||
self.config = {
|
||||
'static_url': '/static',
|
||||
'project_name': 'TTFROG'
|
||||
}
|
||||
|
||||
def configure(self):
|
||||
self.load_from_id()
|
||||
|
||||
|
||||
def load_from_id(self):
|
||||
if not self.request.POST['id']:
|
||||
return
|
||||
self.record = db.query(self.model).get(self.request.POST['id'])
|
||||
|
||||
def form(self) -> str:
|
||||
# no model? no form.
|
||||
if not self.model:
|
||||
return ''
|
||||
|
||||
# no user submission to process
|
||||
if self.request.method != 'POST':
|
||||
return self.model_form(obj=self.record)
|
||||
|
||||
# process submission
|
||||
form = self.model_form(self.request.POST, obj=self.record)
|
||||
if self.model.validate(form):
|
||||
form.populate_obj(self.record)
|
||||
error = self.save_changes()
|
||||
if error:
|
||||
form.errors['process'] = error
|
||||
return form
|
||||
|
||||
def save_changes(self):
|
||||
try:
|
||||
with db.transaction():
|
||||
for (key, val) in self.request.POST.items():
|
||||
if hasattr(self.record, key):
|
||||
setattr(self.record, key, val)
|
||||
except Exception as e:
|
||||
return e
|
||||
return None
|
||||
|
||||
def output(self, **kwargs) -> dict:
|
||||
return dict(
|
||||
page=inspect.stack()[1].function,
|
||||
flash=Markup(flash.render('flash', use_js=False)),
|
||||
config=self.config,
|
||||
request=self.request,
|
||||
record=self.record,
|
||||
form=self.form(),
|
||||
**self.attrs,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def response(self):
|
||||
return self.output()
|
||||
|
||||
@@ -1,72 +1,20 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from tg import expose
|
||||
from tg import flash
|
||||
from tg import validate
|
||||
from tg.controllers.util import redirect
|
||||
from ttfrog.db import db
|
||||
from ttfrog.webserver.controllers import BaseController
|
||||
from ttfrog.db.manager import db
|
||||
from ttfrog.db.schema import Character
|
||||
from ttfrog.webserver.controllers.base import BaseController
|
||||
from ttfrog.webserver.widgets import CharacterSheet
|
||||
|
||||
|
||||
class CharacterSheetController(BaseController):
|
||||
@expose()
|
||||
def _lookup(self, *parts):
|
||||
slug = parts[0] if parts else ''
|
||||
return FormController(slug), parts[1:] if len(parts) > 1 else []
|
||||
class CharacterSheet(BaseController):
|
||||
model = Character
|
||||
|
||||
|
||||
class FormController(BaseController):
|
||||
|
||||
def __init__(self, slug: str):
|
||||
super().__init__()
|
||||
self.character = dict()
|
||||
def configure(self):
|
||||
self.attrs['all_characters'] = db.query(Character).all()
|
||||
slug = self.request.matchdict.get('slug', None)
|
||||
if slug:
|
||||
self.load_from_slug(slug)
|
||||
|
||||
@property
|
||||
def uri(self):
|
||||
if self.character:
|
||||
return f"/sheet/{self.character['slug']}/{self.character['name']}"
|
||||
try:
|
||||
self.record = db.query(Character).filter(Character.slug == slug)[0]
|
||||
except IndexError:
|
||||
logging.warning(f"Could not load record with slug {slug}")
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def all_characters(self):
|
||||
return [row._mapping for row in db.query(Character).all()]
|
||||
|
||||
def load_from_slug(self, slug) -> None:
|
||||
self.character = db.query(Character).filter(Character.columns.slug == slug)[0]._mapping
|
||||
|
||||
def save(self, fields) -> str:
|
||||
rec = dict()
|
||||
if not self.character:
|
||||
result, error = db.insert(Character, **fields)
|
||||
if error:
|
||||
return error
|
||||
fields['id'] = result.inserted_primary_key[0]
|
||||
fields['slug'] = db.slugify(fields)
|
||||
else:
|
||||
rec = dict(**self.character)
|
||||
|
||||
rec.update(**fields)
|
||||
result, error = db.update(Character, **rec)
|
||||
self.load_from_slug(rec['slug'])
|
||||
if not error:
|
||||
flash(f"{self.character['name']} updated!")
|
||||
return redirect(self.uri)
|
||||
flash(error)
|
||||
|
||||
@expose('character_sheet.html')
|
||||
@validate(form=CharacterSheet)
|
||||
def _default(self, *args, **fields):
|
||||
if fields:
|
||||
return self.save(fields)
|
||||
return self.output(
|
||||
form=CharacterSheet,
|
||||
character=self.character,
|
||||
all_characters=self.all_characters,
|
||||
)
|
||||
self.load_from_id()
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
from tg import expose
|
||||
|
||||
from ttfrog.db import db
|
||||
from ttfrog.webserver.controllers.base import BaseController
|
||||
from ttfrog.webserver.controllers.character_sheet import CharacterSheetController
|
||||
|
||||
|
||||
class RootController(BaseController):
|
||||
|
||||
# serve character sheet interface on /sheet
|
||||
sheet = CharacterSheetController()
|
||||
|
||||
@expose('index.html')
|
||||
def index(self):
|
||||
ancestries = [row._mapping for row in db.query(db.ancestry).all()]
|
||||
return self.output(content=str(ancestries))
|
||||
@@ -1,2 +1,3 @@
|
||||
def routes(config):
|
||||
config.add_route('index', '/')
|
||||
config.add_route('sheet', '/sheet/{slug}/{name}', factory='ttfrog.webserver.controllers.CharacterSheet')
|
||||
|
||||
@@ -8,3 +8,9 @@ from ttfrog.db.schema import Ancestry
|
||||
def index(request):
|
||||
ancestries = [a.name for a in db.session.query(Ancestry).all()]
|
||||
return Response(','.join(ancestries))
|
||||
|
||||
|
||||
@view_config(route_name='sheet', renderer='character_sheet.html')
|
||||
def sheet(request):
|
||||
sheet = request.context
|
||||
return sheet.response()
|
||||
|
||||
Reference in New Issue
Block a user