refactor users views etc.

This commit is contained in:
Lance Edgar 2012-07-14 10:40:08 -05:00
parent 4c2319b759
commit b3b4e40bcf
9 changed files with 192 additions and 252 deletions

View file

@ -13,7 +13,6 @@
div.crud {
font-size: 10pt;
margin: auto;
width: 950px;
}
@ -41,7 +40,7 @@ div.crud div.field-couple {
div.crud div.field-couple label {
display: block;
float: left;
width: 135px;
width: 140px;
font-weight: bold;
margin-top: 2px;
white-space: nowrap;

View file

@ -3,9 +3,9 @@
<%def name="title()">People</%def>
<%def name="menu()">
<%def name="context_menu_items()">
% if request.has_perm('people.create'):
<p>${h.link_to("Create a new Person", url('person.new'))}</p>
<li>${h.link_to("Create a new Person", url('person.new'))}</li>
% endif
</%def>

View file

@ -3,8 +3,8 @@
<%def name="title()">Roles</%def>
<%def name="menu()">
<p>${h.link_to("Create a new Role", url('role.new'))}</p>
<%def name="context_menu_items()">
<li>${h.link_to("Create a new Role", url('role.new'))}</li>
</%def>
${parent.body()}

View file

@ -3,8 +3,8 @@
<%def name="crud_name()">User</%def>
<%def name="menu()">
<p>${h.link_to("Back to Users", url('users.list'))}</p>
<%def name="context_menu_items()">
<li>${h.link_to("Back to Users", url('users.list'))}</li>
</%def>
${parent.body()}

View file

@ -0,0 +1,2 @@
<%inherit file="/users/crud.mako" />
${parent.body()}

View file

@ -3,8 +3,8 @@
<%def name="title()">Users</%def>
<%def name="menu()">
<p>${h.link_to("Create a new User", url('user.new'))}</p>
<%def name="context_menu_items()">
<li>${h.link_to("Create a new User", url('user.new'))}</li>
</%def>
${parent.body()}

View file

@ -0,0 +1,2 @@
<%inherit file="/users/crud.mako" />
${parent.body()}

View file

@ -28,8 +28,8 @@
# from pyramid.renderers import render_to_response
# from pyramid.httpexceptions import HTTPException, HTTPFound, HTTPOk, HTTPUnauthorized
import transaction
from pyramid.httpexceptions import HTTPFound, HTTPException
# import transaction
from pyramid.httpexceptions import HTTPFound
# import sqlahelper
@ -97,6 +97,9 @@ class Crud(object):
def post_sync(self, fs):
pass
def validation_failed(self, fs):
pass
def crud(self, obj=None):
if obj is None:
obj = self.mapped_class
@ -126,15 +129,14 @@ class Crud(object):
result = None
with transaction.manager:
fs.sync()
result = self.post_sync(fs)
if not result:
Session.add(fs.model)
Session.flush()
self.request.session.flash('%s "%s" has been %s.' % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
fs.sync()
result = self.post_sync(fs)
if not result:
Session.add(fs.model)
Session.flush()
self.request.session.flash('%s "%s" has been %s.' % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
if result:
return result
@ -144,6 +146,8 @@ class Crud(object):
return HTTPFound(location=self.home_url)
self.validation_failed(fs)
# TODO: This probably needs attention.
if not fs.edit:
fs.allow_continue = True
@ -163,8 +167,7 @@ class Crud(object):
uuid = self.request.matchdict['uuid']
obj = Session.query(self.mapped_class).get(uuid) if uuid else None
assert obj
with transaction.manager:
Session.delete(obj)
Session.delete(obj)
return HTTPFound(location=self.home_url)
@classmethod
@ -201,109 +204,109 @@ class Crud(object):
permission=kw['permission'], http_cache=0)
def crud(request, cls, fieldset_factory, home=None, delete=None, post_sync=None, pre_render=None):
"""
Adds a common CRUD mechanism for objects.
# def crud(request, cls, fieldset_factory, home=None, delete=None, post_sync=None, pre_render=None):
# """
# Adds a common CRUD mechanism for objects.
``cls`` should be a SQLAlchemy-mapped class, presumably deriving from
:class:`edbob.Object`.
# ``cls`` should be a SQLAlchemy-mapped class, presumably deriving from
# :class:`edbob.Object`.
``fieldset_factory`` must be a callable which accepts the fieldset's
"model" as its only positional argument.
# ``fieldset_factory`` must be a callable which accepts the fieldset's
# "model" as its only positional argument.
``home`` will be used as the redirect location once a form is fully
validated and data saved. If you do not speficy this parameter, the
user will be redirected to be the CRUD page for the new object (e.g. so
an object may be created before certain properties may be edited).
# ``home`` will be used as the redirect location once a form is fully
# validated and data saved. If you do not speficy this parameter, the
# user will be redirected to be the CRUD page for the new object (e.g. so
# an object may be created before certain properties may be edited).
``delete`` may either be a string containing a URL to which the user
should be redirected after the object has been deleted, or else a
callback which will be executed *instead of* the normal algorithm
(which is merely to delete the object via the Session).
# ``delete`` may either be a string containing a URL to which the user
# should be redirected after the object has been deleted, or else a
# callback which will be executed *instead of* the normal algorithm
# (which is merely to delete the object via the Session).
``post_sync`` may be a callback which will be executed immediately
after :meth:`FieldSet.sync()` is called, i.e. after validation as well.
# ``post_sync`` may be a callback which will be executed immediately
# after :meth:`FieldSet.sync()` is called, i.e. after validation as well.
``pre_render`` may be a callback which will be executed after any POST
processing has occured, but just before rendering.
"""
# ``pre_render`` may be a callback which will be executed after any POST
# processing has occured, but just before rendering.
# """
uuid = request.params.get('uuid')
obj = Session.query(cls).get(uuid) if uuid else cls
assert obj
# uuid = request.params.get('uuid')
# obj = Session.query(cls).get(uuid) if uuid else cls
# assert obj
if request.params.get('delete'):
if delete:
if isinstance(delete, basestring):
with transaction.manager:
Session.delete(obj)
return HTTPFound(location=delete)
with transaction.manager:
res = delete(obj)
if res:
return res
else:
with transaction.manager:
Session.delete(obj)
if not home:
raise ValueError("Must specify 'home' or 'delete' url "
"in call to crud()")
return HTTPFound(location=home)
# if request.params.get('delete'):
# if delete:
# if isinstance(delete, basestring):
# with transaction.manager:
# Session.delete(obj)
# return HTTPFound(location=delete)
# with transaction.manager:
# res = delete(obj)
# if res:
# return res
# else:
# with transaction.manager:
# Session.delete(obj)
# if not home:
# raise ValueError("Must specify 'home' or 'delete' url "
# "in call to crud()")
# return HTTPFound(location=home)
fs = fieldset_factory(obj)
# fs = fieldset_factory(obj)
# if not fs.readonly and self.request.params.get('fieldset'):
# fs.rebind(data=self.request.params)
# if fs.validate():
# fs.sync()
# if post_sync:
# res = post_sync(fs)
# if isinstance(res, HTTPFound):
# return res
# if self.request.params.get('partial'):
# self.Session.flush()
# return self.json_success(uuid=fs.model.uuid)
# return HTTPFound(location=self.request.route_url(objects, action='index'))
# # if not fs.readonly and self.request.params.get('fieldset'):
# # fs.rebind(data=self.request.params)
# # if fs.validate():
# # fs.sync()
# # if post_sync:
# # res = post_sync(fs)
# # if isinstance(res, HTTPFound):
# # return res
# # if self.request.params.get('partial'):
# # self.Session.flush()
# # return self.json_success(uuid=fs.model.uuid)
# # return HTTPFound(location=self.request.route_url(objects, action='index'))
if not fs.readonly and request.POST:
fs.rebind(data=request.params)
if fs.validate():
with transaction.manager:
fs.sync()
if post_sync:
res = post_sync(fs)
if res:
return res
# if not fs.readonly and request.POST:
# fs.rebind(data=request.params)
# if fs.validate():
# with transaction.manager:
# fs.sync()
# if post_sync:
# res = post_sync(fs)
# if res:
# return res
if request.params.get('partial'):
# Session.flush()
# return self.json_success(uuid=fs.model.uuid)
assert False, "need to fix this"
# if request.params.get('partial'):
# # Session.flush()
# # return self.json_success(uuid=fs.model.uuid)
# assert False, "need to fix this"
if not home:
fs.model = Session.merge(fs.model)
home = request.current_route_url(uuid=fs.model.uuid)
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
return HTTPFound(location=home)
# if not home:
# fs.model = Session.merge(fs.model)
# home = request.current_route_url(uuid=fs.model.uuid)
# request.session.flash("%s \"%s\" has been %s." % (
# fs.crud_title, fs.get_display_text(),
# 'updated' if fs.edit else 'created'))
# return HTTPFound(location=home)
data = {'fieldset': fs, 'crud': True}
# data = {'fieldset': fs, 'crud': True}
if pre_render:
res = pre_render(fs)
if res:
if isinstance(res, HTTPException):
return res
data.update(res)
# if pre_render:
# res = pre_render(fs)
# if res:
# if isinstance(res, HTTPException):
# return res
# data.update(res)
# data = {'fieldset':fs}
# if self.request.params.get('partial'):
# return render_to_response('/%s/crud_partial.mako' % objects,
# data, request=self.request)
# return data
# # data = {'fieldset':fs}
# # if self.request.params.get('partial'):
# # return render_to_response('/%s/crud_partial.mako' % objects,
# # data, request=self.request)
# # return data
return data
# return data
# class needs_perm(object):

View file

@ -26,78 +26,63 @@
``edbob.pyramid.views.users`` -- User Views
"""
import transaction
from pyramid.httpexceptions import HTTPFound
from webhelpers.html import literal, tags
import formalchemy
from formalchemy.fields import SelectFieldRenderer
from webhelpers.html import literal
from webhelpers.html.tags import hidden, link_to, password
import edbob
from edbob.db.auth import set_user_password
from edbob.pyramid import filters
from edbob.pyramid import forms
from edbob.pyramid import grids
from edbob.pyramid import Session
from edbob.pyramid.filters import filter_ilike
from edbob.pyramid.grids import sorter
from edbob.pyramid.views import GridView
from edbob.pyramid.views.crud import Crud
def filter_map():
return filters.get_filter_map(
edbob.User,
ilike=['username'],
person=filters.filter_ilike(edbob.Person.display_name))
class UserGrid(GridView):
def search_config(request, fmap):
return filters.get_search_config(
'users.list', request, fmap,
include_filter_username=True,
filter_type_username='lk')
mapped_class = edbob.User
route_name = 'users.list'
route_prefix = 'user'
def search_form(config):
return filters.get_search_form(config)
def join_map(self):
return {
'person':
lambda q: q.outerjoin(edbob.Person),
}
def grid_config(request, search, fmap):
return grids.get_grid_config(
'users.list', request, search,
filter_map=fmap, sort='username')
def filter_map(self):
return self.make_filter_map(
ilike=['username'],
person=filter_ilike(edbob.Person.display_name))
def sort_map():
return grids.get_sort_map(
edbob.User, ['username'],
person=grids.sorter(edbob.Person.display_name))
def search_config(self, fmap):
return self.make_search_config(
fmap,
include_filter_username=True,
filter_type_username='lk',
include_filter_person=True,
filter_type_person='lk')
def query(config):
jmap = {'person': lambda q: q.outerjoin(edbob.Person)}
smap = sort_map()
q = Session.query(edbob.User)
q = filters.filter_query(q, config, jmap)
q = grids.sort_query(q, config, smap, jmap)
return q
def grid_config(self, search, fmap):
return self.make_grid_config(search, fmap,
sort='username')
def sort_map(self):
return self.make_sort_map(
'username',
person=sorter(edbob.Person.display_name))
def users(context, request):
fmap = filter_map()
config = search_config(request, fmap)
search = search_form(config)
config = grid_config(request, search, fmap)
users = grids.get_pager(query, config)
g = forms.AlchemyGrid(
edbob.User, users, config,
gridurl=request.route_url('users.list'),
objurl='user.edit')
g.configure(
include=[
g.username,
g.person,
],
readonly=True)
grid = g.render(class_='clickable users')
return grids.render_grid(request, grid, search)
def grid(self, data, config):
g = self.make_grid(data, config)
g.configure(
include=[
g.username,
g.person,
],
readonly=True)
return g
class _RolesFieldRenderer(SelectFieldRenderer):
@ -108,8 +93,8 @@ class _RolesFieldRenderer(SelectFieldRenderer):
for uuid in self.value:
role = roles.get(uuid)
res += literal('<li>%s</li>' % (
link_to(role.name,
self.request.route_url('role.edit', uuid=role.uuid))))
tags.link_to(role.name,
self.request.route_url('role.edit', uuid=role.uuid))))
res += literal('</ul>')
return res
@ -146,8 +131,8 @@ class _ProtectedPersonRenderer(formalchemy.FieldRenderer):
def render_readonly(self, **kwargs):
res = str(self.person)
res += hidden('User--person_uuid',
value=self.field.parent.person_uuid.value)
res += tags.hidden('User--person_uuid',
value=self.field.parent.person_uuid.value)
return res
@ -161,18 +146,19 @@ def ProtectedPersonRenderer(uuid):
class _LinkedPersonRenderer(formalchemy.FieldRenderer):
def render_readonly(self, **kwargs):
return link_to(str(self.raw_value),
self.request.route_url('person.edit', uuid=self.value))
return tags.link_to(str(self.raw_value),
self.request.route_url('person.edit', uuid=self.value))
def LinkedPersonRenderer(request):
return type('LinkedPersonRenderer', (_LinkedPersonRenderer,), {'request': request})
return type('LinkedPersonRenderer', (_LinkedPersonRenderer,),
{'request': request})
class PasswordFieldRenderer(formalchemy.PasswordFieldRenderer):
def render(self, **kwargs):
return password(self.name, value='', maxlength=self.length, **kwargs)
return tags.password(self.name, value='', maxlength=self.length, **kwargs)
def passwords_match(value, field):
@ -196,94 +182,42 @@ class PasswordField(formalchemy.Field):
set_user_password(self.model, password)
def user_fieldset(user, request):
fs = forms.make_fieldset(user, url=request.route_url,
url_action=request.current_route_url(),
route_name='users.list')
class UserCrud(Crud):
fs.append(PasswordField('password'))
fs.append(formalchemy.Field('confirm_password',
renderer=PasswordFieldRenderer))
mapped_class = edbob.User
home_route = 'users.list'
fs.append(RolesField(
'roles', renderer=RolesFieldRenderer(request)))
def fieldset(self, user):
fs = self.make_fieldset(user)
fs.configure(
include=[
fs.person,
fs.username,
fs.password.label("Set Password"),
fs.confirm_password,
fs.roles,
])
fs.append(PasswordField('password'))
fs.append(formalchemy.Field('confirm_password',
renderer=PasswordFieldRenderer))
fs.append(RolesField('roles',
renderer=RolesFieldRenderer(self.request)))
if isinstance(user, edbob.User) and user.person:
fs.person.set(readonly=True,
renderer=LinkedPersonRenderer(request))
fs.configure(
include=[
fs.username,
fs.person,
fs.password.label("Set Password"),
fs.confirm_password,
fs.roles,
])
return fs
# if fs.edit and user.person:
if isinstance(user, edbob.User) and user.person:
fs.person.set(readonly=True,
renderer=LinkedPersonRenderer(self.request))
return fs
def new_user(request):
"""
View for creating a new :class:`edbob.User` instance.
"""
fs = user_fieldset(edbob.User, request)
if request.POST:
fs.rebind(data=request.params)
if fs.validate():
with transaction.manager:
Session.add(fs.model)
fs.sync()
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
home = request.route_url('users.list')
return HTTPFound(location=home)
if fs.person_uuid.value:
def validation_failed(self, fs):
if not fs.edit and fs.person_uuid.value:
fs.person.set(readonly=True,
renderer=ProtectedPersonRenderer(fs.person_uuid.value))
return {'fieldset': fs, 'crud': True}
def edit_user(request):
uuid = request.matchdict['uuid']
user = Session.query(edbob.User).get(uuid) if uuid else None
assert user
fs = user_fieldset(user, request)
if request.POST:
fs.rebind(data=request.params)
if fs.validate():
with transaction.manager:
Session.add(fs.model)
fs.sync()
request.session.flash("%s \"%s\" has been %s." % (
fs.crud_title, fs.get_display_text(),
'updated' if fs.edit else 'created'))
home = request.route_url('users.list')
return HTTPFound(location=home)
return {'fieldset': fs, 'crud': True}
def includeme(config):
config.add_route('users.list', '/users')
config.add_view(users, route_name='users.list', renderer='/users/index.mako',
permission='users.list', http_cache=0)
config.add_route('user.new', '/users/new')
config.add_view(new_user, route_name='user.new', renderer='/users/user.mako',
permission='users.create', http_cache=0)
config.add_route('user.edit', '/users/{uuid}/edit')
config.add_view(edit_user, route_name='user.edit', renderer='/users/user.mako',
permission='users.edit', http_cache=0)
UserGrid.add_route(config, 'users.list', '/users')
UserCrud.add_routes(config)