fix: make some tweaks for better tailbone compatibility
this is the result of minimally testing the PersonView from wutta, configured via a tailbone app. had to add the `view_profile()` stub, pretty sure we want that..?
This commit is contained in:
parent
058632ebeb
commit
be8a45e543
|
@ -228,9 +228,9 @@ def add_permission(pyramid_config, groupkey, key, label=None):
|
|||
|
||||
See also :func:`add_permission_group()`.
|
||||
"""
|
||||
config = pyramid_config.get_settings()['wutta_config']
|
||||
app = config.get_app()
|
||||
def action():
|
||||
config = pyramid_config.get_settings()['wutta_config']
|
||||
app = config.get_app()
|
||||
perms = pyramid_config.get_settings().get('wutta_permissions', {})
|
||||
group = perms.setdefault(groupkey, {'key': groupkey})
|
||||
group.setdefault('label', app.make_title(groupkey))
|
||||
|
|
|
@ -939,6 +939,20 @@ class Form:
|
|||
|
||||
return model_data
|
||||
|
||||
# TODO: for tailbone compat, should document?
|
||||
# (ideally should remove this and find a better way)
|
||||
def get_vue_field_value(self, key):
|
||||
""" """
|
||||
if key not in self.fields:
|
||||
return
|
||||
|
||||
dform = self.get_deform()
|
||||
if key not in dform:
|
||||
return
|
||||
|
||||
field = dform[key]
|
||||
return make_json_safe(field.cstruct)
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
Try to validate the form, using data from the :attr:`request`.
|
||||
|
|
|
@ -552,7 +552,7 @@ class GridAction:
|
|||
See also :meth:`render_icon_and_label()`.
|
||||
"""
|
||||
if self.request.use_oruga:
|
||||
raise NotImplementedError
|
||||
return HTML.tag('o-icon', icon=self.icon)
|
||||
|
||||
return HTML.tag('i', class_=f'fas fa-{self.icon}')
|
||||
|
||||
|
|
|
@ -9,15 +9,19 @@
|
|||
|
||||
<%def name="render_this_page_template()">
|
||||
${parent.render_this_page_template()}
|
||||
${form.render_vue_template()}
|
||||
% if form is not Undefined:
|
||||
${form.render_vue_template()}
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="finalize_this_page_vars()">
|
||||
${parent.finalize_this_page_vars()}
|
||||
<script>
|
||||
${form.vue_component}.data = function() { return ${form.vue_component}Data }
|
||||
Vue.component('${form.vue_tagname}', ${form.vue_component})
|
||||
</script>
|
||||
% if form is not Undefined:
|
||||
<script>
|
||||
${form.vue_component}.data = function() { return ${form.vue_component}Data }
|
||||
Vue.component('${form.vue_tagname}', ${form.vue_component})
|
||||
</script>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
|
||||
|
|
12
src/wuttaweb/templates/people/view_profile.mako
Normal file
12
src/wuttaweb/templates/people/view_profile.mako
Normal file
|
@ -0,0 +1,12 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/master/view.mako" />
|
||||
|
||||
<%def name="page_content()">
|
||||
<p class="block is-size-5">
|
||||
TODO: view profile page content
|
||||
</p>
|
||||
</%def>
|
||||
|
||||
<%def name="title()">TODO: title</%def>
|
||||
|
||||
${parent.body()}
|
|
@ -242,6 +242,9 @@ class MasterView(View):
|
|||
deleting = False
|
||||
configuring = False
|
||||
|
||||
# default DB session
|
||||
Session = Session
|
||||
|
||||
##############################
|
||||
# index methods
|
||||
##############################
|
||||
|
@ -305,7 +308,7 @@ class MasterView(View):
|
|||
|
||||
if form.validate():
|
||||
obj = self.create_save_form(form)
|
||||
Session.flush()
|
||||
self.Session.flush()
|
||||
return self.redirect(self.get_action_url('view', obj))
|
||||
|
||||
context = {
|
||||
|
@ -362,7 +365,6 @@ class MasterView(View):
|
|||
|
||||
context = {
|
||||
'instance': instance,
|
||||
'instance_title': self.get_instance_title(instance),
|
||||
'form': form,
|
||||
}
|
||||
return self.render_to_response('view', context)
|
||||
|
@ -396,7 +398,6 @@ class MasterView(View):
|
|||
"""
|
||||
self.editing = True
|
||||
instance = self.get_instance()
|
||||
instance_title = self.get_instance_title(instance)
|
||||
|
||||
form = self.make_model_form(instance,
|
||||
cancel_url_fallback=self.get_action_url('view', instance))
|
||||
|
@ -407,7 +408,6 @@ class MasterView(View):
|
|||
|
||||
context = {
|
||||
'instance': instance,
|
||||
'instance_title': instance_title,
|
||||
'form': form,
|
||||
}
|
||||
return self.render_to_response('edit', context)
|
||||
|
@ -460,7 +460,6 @@ class MasterView(View):
|
|||
"""
|
||||
self.deleting = True
|
||||
instance = self.get_instance()
|
||||
instance_title = self.get_instance_title(instance)
|
||||
|
||||
if not self.is_deletable(instance):
|
||||
return self.redirect(self.get_action_url('view', instance))
|
||||
|
@ -481,7 +480,6 @@ class MasterView(View):
|
|||
|
||||
context = {
|
||||
'instance': instance,
|
||||
'instance_title': instance_title,
|
||||
'form': form,
|
||||
}
|
||||
return self.render_to_response('delete', context)
|
||||
|
@ -516,7 +514,7 @@ class MasterView(View):
|
|||
# configure methods
|
||||
##############################
|
||||
|
||||
def configure(self):
|
||||
def configure(self, session=None):
|
||||
"""
|
||||
View for configuring aspects of the app which are pertinent to
|
||||
this master view and/or model.
|
||||
|
@ -562,7 +560,7 @@ class MasterView(View):
|
|||
|
||||
# maybe just remove settings
|
||||
if self.request.POST.get('remove_settings'):
|
||||
self.configure_remove_settings()
|
||||
self.configure_remove_settings(session=session)
|
||||
self.request.session.flash(f"All settings for {config_title} have been removed.",
|
||||
'warning')
|
||||
|
||||
|
@ -572,8 +570,8 @@ class MasterView(View):
|
|||
# gather/save settings
|
||||
data = get_form_data(self.request)
|
||||
settings = self.configure_gather_settings(data)
|
||||
self.configure_remove_settings()
|
||||
self.configure_save_settings(settings)
|
||||
self.configure_remove_settings(session=session)
|
||||
self.configure_save_settings(settings, session=session)
|
||||
self.request.session.flash("Settings have been saved.")
|
||||
|
||||
# reload configure page
|
||||
|
@ -751,6 +749,7 @@ class MasterView(View):
|
|||
def configure_remove_settings(
|
||||
self,
|
||||
simple_settings=None,
|
||||
session=None,
|
||||
):
|
||||
"""
|
||||
Remove all "known" settings from the DB; this is called by
|
||||
|
@ -778,11 +777,11 @@ class MasterView(View):
|
|||
if names:
|
||||
# nb. must avoid self.Session here in case that does not
|
||||
# point to our primary app DB
|
||||
session = Session()
|
||||
session = session or self.Session()
|
||||
for name in names:
|
||||
self.app.delete_setting(session, name)
|
||||
|
||||
def configure_save_settings(self, settings):
|
||||
def configure_save_settings(self, settings, session=None):
|
||||
"""
|
||||
Save the given settings to the DB; this is called by
|
||||
:meth:`configure()`.
|
||||
|
@ -795,7 +794,7 @@ class MasterView(View):
|
|||
"""
|
||||
# nb. must avoid self.Session here in case that does not point
|
||||
# to our primary app DB
|
||||
session = Session()
|
||||
session = session or self.Session()
|
||||
for setting in settings:
|
||||
self.app.save_setting(session, setting['name'], setting['value'],
|
||||
force_create=True)
|
||||
|
@ -885,7 +884,13 @@ class MasterView(View):
|
|||
|
||||
# add crud flags if we have an instance
|
||||
if 'instance' in context:
|
||||
context['instance_deletable'] = self.is_deletable(context['instance'])
|
||||
instance = context['instance']
|
||||
if 'instance_title' not in context:
|
||||
context['instance_title'] = self.get_instance_title(instance)
|
||||
if 'instance_editable' not in context:
|
||||
context['instance_editable'] = self.is_editable(instance)
|
||||
if 'instance_deletable' not in context:
|
||||
context['instance_deletable'] = self.is_deletable(instance)
|
||||
|
||||
# first try the template path most specific to this view
|
||||
template_prefix = self.get_template_prefix()
|
||||
|
@ -1050,7 +1055,7 @@ class MasterView(View):
|
|||
model = self.app.model
|
||||
model_class = self.get_model_class()
|
||||
if model_class and issubclass(model_class, model.Base):
|
||||
session = session or Session()
|
||||
session = session or self.Session()
|
||||
return session.query(model_class)
|
||||
|
||||
def configure_grid(self, grid):
|
||||
|
@ -1110,7 +1115,7 @@ class MasterView(View):
|
|||
"""
|
||||
model_class = self.get_model_class()
|
||||
if model_class:
|
||||
session = session or Session()
|
||||
session = session or self.Session()
|
||||
|
||||
def filtr(query, model_key):
|
||||
key = self.request.matchdict[model_key]
|
||||
|
@ -1361,7 +1366,7 @@ class MasterView(View):
|
|||
if model_class and issubclass(model_class, model.Base):
|
||||
|
||||
# add sqlalchemy model to session
|
||||
session = session or Session()
|
||||
session = session or self.Session()
|
||||
session.add(obj)
|
||||
|
||||
##############################
|
||||
|
|
|
@ -85,6 +85,33 @@ class PersonView(MasterView):
|
|||
if 'users' in f:
|
||||
f.fields.remove('users')
|
||||
|
||||
def view_profile(self, session=None):
|
||||
""" """
|
||||
instance = self.get_instance(session=session)
|
||||
context = {
|
||||
'instance': instance,
|
||||
}
|
||||
return self.render_to_response('view_profile', context)
|
||||
|
||||
@classmethod
|
||||
def defaults(cls, config):
|
||||
cls._defaults(config)
|
||||
cls._people_defaults(config)
|
||||
|
||||
@classmethod
|
||||
def _people_defaults(cls, config):
|
||||
route_prefix = cls.get_route_prefix()
|
||||
instance_url_prefix = cls.get_instance_url_prefix()
|
||||
permission_prefix = cls.get_permission_prefix()
|
||||
|
||||
# view profile
|
||||
config.add_route(f'{route_prefix}.view_profile',
|
||||
f'{instance_url_prefix}/profile',
|
||||
request_method='GET')
|
||||
config.add_view(cls, attr='view_profile',
|
||||
route_name=f'{route_prefix}.view_profile',
|
||||
permission=f'{permission_prefix}.view_profile')
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
|
|
@ -454,6 +454,28 @@ class TestForm(TestCase):
|
|||
# nb. no error message
|
||||
self.assertNotIn('message', html)
|
||||
|
||||
def test_get_vue_field_value(self):
|
||||
schema = self.make_schema()
|
||||
form = self.make_form(schema=schema)
|
||||
|
||||
# TODO: yikes what a hack (?)
|
||||
dform = form.get_deform()
|
||||
dform.set_appstruct({'foo': 'one', 'bar': 'two'})
|
||||
|
||||
# null for missing field
|
||||
value = form.get_vue_field_value('doesnotexist')
|
||||
self.assertIsNone(value)
|
||||
|
||||
# normal value is returned
|
||||
value = form.get_vue_field_value('foo')
|
||||
self.assertEqual(value, 'one')
|
||||
|
||||
# but not if we remove field from deform
|
||||
# TODO: what is the use case here again?
|
||||
dform.children.remove(dform['foo'])
|
||||
value = form.get_vue_field_value('foo')
|
||||
self.assertIsNone(value)
|
||||
|
||||
def test_get_vue_model_data(self):
|
||||
schema = self.make_schema()
|
||||
form = self.make_form(schema=schema)
|
||||
|
|
|
@ -190,9 +190,10 @@ class TestGridAction(TestCase):
|
|||
html = action.render_icon()
|
||||
self.assertIn('<i class="fas fa-blarg">', html)
|
||||
|
||||
# oruga not yet supported
|
||||
# oruga has different output
|
||||
self.request.use_oruga = True
|
||||
self.assertRaises(NotImplementedError, action.render_icon)
|
||||
html = action.render_icon()
|
||||
self.assertIn('<o-icon icon="blarg">', html)
|
||||
|
||||
def test_render_label(self):
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from unittest.mock import MagicMock, patch
|
|||
|
||||
from pyramid import testing
|
||||
from pyramid.response import Response
|
||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||
from pyramid.httpexceptions import HTTPNotFound
|
||||
|
||||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttaweb.views import master
|
||||
|
@ -942,7 +942,7 @@ class TestMasterView(WebTestCase):
|
|||
configure_get_simple_settings=MagicMock(return_value=settings)):
|
||||
|
||||
# get the form page
|
||||
response = view.configure()
|
||||
response = view.configure(session=self.session)
|
||||
self.assertIsInstance(response, Response)
|
||||
|
||||
# post request to save settings
|
||||
|
@ -952,9 +952,9 @@ class TestMasterView(WebTestCase):
|
|||
'wutta.foo': 'bar',
|
||||
'wutta.flag': 'true',
|
||||
}
|
||||
response = view.configure()
|
||||
response = view.configure(session=self.session)
|
||||
# nb. should get redirect back to configure page
|
||||
self.assertIsInstance(response, HTTPFound)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# should now have 5 settings
|
||||
count = self.session.query(model.Setting).count()
|
||||
|
@ -970,9 +970,9 @@ class TestMasterView(WebTestCase):
|
|||
# post request to remove settings
|
||||
self.request.method = 'POST'
|
||||
self.request.POST = {'remove_settings': '1'}
|
||||
response = view.configure()
|
||||
response = view.configure(session=self.session)
|
||||
# nb. should get redirect back to configure page
|
||||
self.assertIsInstance(response, HTTPFound)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# should now have 0 settings
|
||||
count = self.session.query(model.Setting).count()
|
||||
|
|
|
@ -15,6 +15,9 @@ class TestPersonView(WebTestCase):
|
|||
def make_view(self):
|
||||
return people.PersonView(self.request)
|
||||
|
||||
def test_includeme(self):
|
||||
self.pyramid_config.include('wuttaweb.views.people')
|
||||
|
||||
def test_get_query(self):
|
||||
view = self.make_view()
|
||||
query = view.get_query(session=self.session)
|
||||
|
@ -37,3 +40,19 @@ class TestPersonView(WebTestCase):
|
|||
view.configure_form(form)
|
||||
self.assertTrue(form.required_fields)
|
||||
self.assertFalse(form.required_fields['middle_name'])
|
||||
|
||||
def test_view_profile(self):
|
||||
self.pyramid_config.include('wuttaweb.views.common')
|
||||
self.pyramid_config.include('wuttaweb.views.auth')
|
||||
self.pyramid_config.add_route('people', '/people/')
|
||||
|
||||
model = self.app.model
|
||||
person = model.Person(full_name="Barney Rubble")
|
||||
self.session.add(person)
|
||||
self.session.commit()
|
||||
|
||||
# sanity check
|
||||
view = self.make_view()
|
||||
self.request.matchdict = {'uuid': person.uuid}
|
||||
response = view.view_profile(session=self.session)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
|
Loading…
Reference in a new issue