Add basic support for "mobile edit" of records

specifically need to allow this for Customer records, for one app
This commit is contained in:
Lance Edgar 2019-02-19 17:10:02 -06:00
parent 37a8bfd6f5
commit b0b551af82
8 changed files with 88 additions and 22 deletions

View file

@ -42,3 +42,7 @@ ${form.render()|n}
<br /> <br />
${grid.render_complete()|n} ${grid.render_complete()|n}
% endif % endif
% if master.mobile_editable and instance_editable and request.has_perm('{}.edit'.format(permission_prefix)):
${h.link_to("Edit This", url('mobile.{}.edit'.format(route_prefix), uuid=instance.uuid), class_='ui-btn ui-corner-all')}
% endif

View file

@ -223,7 +223,9 @@ class CustomersView(MasterView):
f.set_renderer('groups', self.render_groups) f.set_renderer('groups', self.render_groups)
f.set_readonly('groups') f.set_readonly('groups')
def objectify(self, form, data): def objectify(self, form, data=None):
if data is None:
data = form.validated
customer = super(CustomersView, self).objectify(form, data) customer = super(CustomersView, self).objectify(form, data)
customer = self.objectify_contact(customer, data) customer = self.objectify_contact(customer, data)
return customer return customer

View file

@ -195,7 +195,9 @@ class EmployeesView(MasterView):
if not self.viewing: if not self.viewing:
f.remove_fields('first_name', 'last_name') f.remove_fields('first_name', 'last_name')
def objectify(self, form, data): def objectify(self, form, data=None):
if data is None:
data = form.validated
employee = super(EmployeesView, self).objectify(form, data) employee = super(EmployeesView, self).objectify(form, data)
self.update_stores(employee, data) self.update_stores(employee, data)
self.update_departments(employee, data) self.update_departments(employee, data)

View file

@ -100,6 +100,7 @@ class MasterView(View):
supports_mobile = False supports_mobile = False
mobile_creatable = False mobile_creatable = False
mobile_editable = False
mobile_pageable = True mobile_pageable = True
mobile_filterable = False mobile_filterable = False
mobile_executable = False mobile_executable = False
@ -1111,7 +1112,7 @@ class MasterView(View):
context = { context = {
'instance': instance, 'instance': instance,
'instance_title': self.get_instance_title(instance), 'instance_title': self.get_instance_title(instance),
# 'instance_editable': self.editable_instance(instance), 'instance_editable': self.editable_instance(instance),
# 'instance_deletable': self.deletable_instance(instance), # 'instance_deletable': self.deletable_instance(instance),
'form': form, 'form': form,
} }
@ -1199,12 +1200,12 @@ class MasterView(View):
self.configure_common_form(form) self.configure_common_form(form)
def validate_mobile_form(self, form): def validate_mobile_form(self, form):
controls = self.request.POST.items() if form.validate(newstyle=True):
try: # TODO: deprecate / remove self.form_deserialized
self.form_deserialized = form.validate(controls) self.form_deserialized = form.validated
except deform.ValidationFailure: return True
else:
return False return False
return True
def make_mobile_row_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs): def make_mobile_row_form(self, instance=None, factory=None, fields=None, schema=None, **kwargs):
""" """
@ -1535,15 +1536,61 @@ class MasterView(View):
context['dform'] = form.make_deform_form() context['dform'] = form.make_deform_form()
return self.render_to_response('edit', context) return self.render_to_response('edit', context)
def mobile_edit(self):
"""
Mobile view for editing an existing model record.
"""
self.mobile = True
self.editing = True
obj = self.get_instance()
if not self.editable_instance(obj):
msg = "Edit is not permitted for {}: {}".format(
self.get_model_title(),
self.get_instance_title(obj))
self.request.session.flash(msg, 'error')
return self.redirect(self.get_action_url('view', obj))
form = self.make_mobile_form(obj)
if self.request.method == 'POST':
if self.validate_mobile_form(form):
# note that save_form() may return alternate object
obj = self.save_mobile_edit_form(form)
msg = "{} has been updated: {}".format(
self.get_model_title(),
self.get_instance_title(obj))
self.request.session.flash(msg)
return self.redirect_after_edit(obj, mobile=True)
context = {
'instance': obj,
'instance_title': self.get_instance_title(obj),
'instance_deletable': self.deletable_instance(obj),
'instance_url': self.get_action_url('view', obj, mobile=True),
'form': form,
}
if hasattr(form, 'make_deform_form'):
context['dform'] = form.make_deform_form()
return self.render_to_response('edit', context, mobile=True)
def save_edit_form(self, form): def save_edit_form(self, form):
uploads = self.normalize_uploads(form) if not self.mobile:
obj = self.objectify(form, self.form_deserialized) uploads = self.normalize_uploads(form)
self.process_uploads(obj, form, uploads) obj = self.objectify(form)
if not self.mobile:
self.process_uploads(obj, form, uploads)
self.after_edit(obj) self.after_edit(obj)
self.Session.flush() self.Session.flush()
return obj
def redirect_after_edit(self, instance): def save_mobile_edit_form(self, form):
return self.redirect(self.get_action_url('view', instance)) return self.save_edit_form(form)
def redirect_after_edit(self, instance, mobile=False):
return self.redirect(self.get_action_url('view', instance, mobile=mobile))
def delete(self): def delete(self):
""" """
@ -3286,12 +3333,17 @@ class MasterView(View):
"Download associated data for {}".format(model_title)) "Download associated data for {}".format(model_title))
# edit # edit
if cls.editable or cls.mobile_editable:
config.add_tailbone_permission(permission_prefix, '{}.edit'.format(permission_prefix),
"Edit {}".format(model_title))
if cls.editable: if cls.editable:
config.add_route('{0}.edit'.format(route_prefix), '{0}/{{{1}}}/edit'.format(url_prefix, model_key)) config.add_route('{}.edit'.format(route_prefix), '{}/{{{}}}/edit'.format(url_prefix, model_key))
config.add_view(cls, attr='edit', route_name='{0}.edit'.format(route_prefix), config.add_view(cls, attr='edit', route_name='{}.edit'.format(route_prefix),
permission='{0}.edit'.format(permission_prefix)) permission='{}.edit'.format(permission_prefix))
config.add_tailbone_permission(permission_prefix, '{0}.edit'.format(permission_prefix), if cls.mobile_editable:
"Edit {0}".format(model_title)) config.add_route('mobile.{}.edit'.format(route_prefix), '/mobile{}/{{{}}}/edit'.format(url_prefix, model_key))
config.add_view(cls, attr='mobile_edit', route_name='mobile.{}.edit'.format(route_prefix),
permission='{}.edit'.format(permission_prefix))
# execute # execute
if cls.executable or cls.mobile_executable: if cls.executable or cls.mobile_executable:

View file

@ -238,7 +238,9 @@ class MessagesView(MasterView):
elif self.viewing: elif self.viewing:
f.remove('body') f.remove('body')
def objectify(self, form, data): def objectify(self, form, data=None):
if data is None:
data = form.validated
message = super(MessagesView, self).objectify(form, data) message = super(MessagesView, self).objectify(form, data)
if self.creating: if self.creating:

View file

@ -106,7 +106,9 @@ class RolesView(PrincipalMasterView):
return "" return ""
return six.text_type(role.session_timeout) return six.text_type(role.session_timeout)
def objectify(self, form, data): def objectify(self, form, data=None):
if data is None:
data = form.validated
role = super(RolesView, self).objectify(form, data) role = super(RolesView, self).objectify(form, data)
role.permissions = data['permissions'] role.permissions = data['permissions']
return role return role

View file

@ -229,7 +229,7 @@ class UsersView(PrincipalMasterView):
.filter(~model.Role.uuid.in_(excluded))\ .filter(~model.Role.uuid.in_(excluded))\
.order_by(model.Role.name) .order_by(model.Role.name)
def objectify(self, form, data): def objectify(self, form, data=None):
# create/update user as per normal # create/update user as per normal
if data is None: if data is None:

View file

@ -114,7 +114,9 @@ class VendorsView(MasterView):
f.set_readonly('contact') f.set_readonly('contact')
f.set_renderer('contact', self.render_contact) f.set_renderer('contact', self.render_contact)
def objectify(self, form, data): def objectify(self, form, data=None):
if data is None:
data = form.validated
vendor = super(VendorsView, self).objectify(form, data) vendor = super(VendorsView, self).objectify(form, data)
vendor = self.objectify_contact(vendor, data) vendor = self.objectify_contact(vendor, data)