Add edit mode for email "profile" settings.

Plus some related tweaks, needed to make that happen.
This commit is contained in:
Lance Edgar 2016-01-10 17:35:34 -06:00
parent 73d14cb1d9
commit 1956c4c9cf
6 changed files with 94 additions and 43 deletions

View file

@ -26,7 +26,7 @@ Forms
from formencode import Schema from formencode import Schema
from .core import Form, Field, FieldSet from .core import Form, Field, FieldSet, GenericFieldSet
from .simpleform import SimpleForm, FormRenderer from .simpleform import SimpleForm, FormRenderer
from .alchemy import AlchemyForm from .alchemy import AlchemyForm
from .fields import AssociationProxyField from .fields import AssociationProxyField

View file

@ -30,8 +30,9 @@ from edbob.util import prettify
from rattail.util import OrderedDict from rattail.util import OrderedDict
from pyramid.renderers import render import formalchemy
from formalchemy.helpers import content_tag from formalchemy.helpers import content_tag
from pyramid.renderers import render
class Form(object): class Form(object):
@ -108,3 +109,12 @@ class FieldSet(object):
def __init__(self): def __init__(self):
self.fields = OrderedDict() self.fields = OrderedDict()
self.render_fields = self.fields self.render_fields = self.fields
class GenericFieldSet(formalchemy.FieldSet):
"""
FieldSet class based on FormAlchemy, but without the SQLAlchemy magic.
"""
__sa__ = False
_bound_pk = None
data = None

View file

@ -657,7 +657,7 @@ class Grid(object):
return self.cell_attrs return self.cell_attrs
def render_cell(self, row, column): def render_cell(self, row, column):
return unicode(row[column.key]) return column.render(row[column.key])
def get_pagesize_options(self): def get_pagesize_options(self):
# TODO: Make configurable or something... # TODO: Make configurable or something...
@ -681,6 +681,12 @@ class GridColumn(object):
self.key = key self.key = key
self.label = label or prettify(key) self.label = label or prettify(key)
def render(self, value):
"""
Render the given value, to be displayed within a grid cell.
"""
return unicode(value)
class GridAction(object): class GridAction(object):
""" """

View file

@ -1,7 +1,7 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8 -*-
<%inherit file="/base.mako" /> <%inherit file="/base.mako" />
<%def name="title()">${model_title}: ${unicode(instance)}</%def> <%def name="title()">Edit ${model_title}: ${instance_title}</%def>
<%def name="context_menu_items()"> <%def name="context_menu_items()">
<li>${h.link_to("Back to {}".format(model_title_plural), url(route_prefix))}</li> <li>${h.link_to("Back to {}".format(model_title_plural), url(route_prefix))}</li>

View file

@ -26,15 +26,40 @@ Email Views
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
import formalchemy
from formalchemy.helpers import text_area
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from rattail import mail from rattail import mail
from rattail.db import api
from rattail.config import parse_list
from tailbone import forms from tailbone import forms
from tailbone.db import Session
from tailbone.views import MasterView, View from tailbone.views import MasterView, View
from tailbone.newgrids import Grid, GridColumn from tailbone.newgrids import Grid, GridColumn
class EmailListGridColumn(GridColumn):
def render(self, value):
if not value:
return ''
recips = parse_list(value)
if len(recips) < 3:
return value
return "{}, ...".format(', '.join(recips[:2]))
class EmailListFieldRenderer(formalchemy.TextAreaFieldRenderer):
def render(self, **kwargs):
if isinstance(kwargs.get('size'), tuple):
kwargs['size'] = 'x'.join([str(i) for i in kwargs['size']])
value = '\n'.join(parse_list(self.value))
return text_area(self.name, content=value, **kwargs)
class ProfilesView(MasterView): class ProfilesView(MasterView):
""" """
Master view for email admin (settings/preview). Master view for email admin (settings/preview).
@ -49,7 +74,6 @@ class ProfilesView(MasterView):
pageable = False pageable = False
creatable = False creatable = False
editable = False
deletable = False deletable = False
def get_data(self, session=None): def get_data(self, session=None):
@ -84,7 +108,7 @@ class ProfilesView(MasterView):
GridColumn('key'), GridColumn('key'),
GridColumn('prefix'), GridColumn('prefix'),
GridColumn('subject'), GridColumn('subject'),
GridColumn('to'), EmailListGridColumn('to'),
] ]
g.sorters['key'] = g.make_sorter('key', foldcase=True) g.sorters['key'] = g.make_sorter('key', foldcase=True)
@ -93,8 +117,8 @@ class ProfilesView(MasterView):
g.sorters['to'] = g.make_sorter('to', foldcase=True) g.sorters['to'] = g.make_sorter('to', foldcase=True)
g.default_sortkey = 'key' g.default_sortkey = 'key'
# g.main_actions = [] # Make edit link visible by default, no "More" actions.
g.more_actions = [] g.main_actions.append(g.more_actions.pop())
def get_instance(self): def get_instance(self):
key = self.request.matchdict['key'] key = self.request.matchdict['key']
@ -107,35 +131,39 @@ class ProfilesView(MasterView):
""" """
Make a simple form for use with CRUD views. Make a simple form for use with CRUD views.
""" """
# TODO: This needs all kinds of help still... fs = forms.GenericFieldSet(email)
fs.append(formalchemy.Field('key', value=email['key'], readonly=True))
fs.append(formalchemy.Field('fallback_key', value=email['fallback_key'], readonly=True))
fs.append(formalchemy.Field('prefix', value=email['prefix'], label="Subject Prefix"))
fs.append(formalchemy.Field('subject', value=email['subject'], label="Subject Text"))
fs.append(formalchemy.Field('description', value=email['description'], readonly=True))
fs.append(formalchemy.Field('sender', value=email['sender'], label="From"))
fs.append(formalchemy.Field('replyto', value=email['replyto'], label="Reply-To"))
fs.append(formalchemy.Field('to', value=email['to'], renderer=EmailListFieldRenderer, size='60x6'))
fs.append(formalchemy.Field('cc', value=email['cc'], renderer=EmailListFieldRenderer, size='60x2'))
fs.append(formalchemy.Field('bcc', value=email['bcc'], renderer=EmailListFieldRenderer, size='60x2'))
class EmailSchema(forms.Schema): form = forms.AlchemyForm(self.request, fs,
pass creating=self.creating,
editing=self.editing,
form = forms.SimpleForm(self.request, schema=EmailSchema(), obj=email) action_url=self.request.current_route_url(_query=None),
form.creating = self.creating cancel_url=self.get_index_url() if self.creating else self.get_action_url('view', email))
form.editing = self.editing
form.readonly = self.viewing form.readonly = self.viewing
if self.creating:
form.cancel_url = self.get_index_url()
else:
form.cancel_url = self.get_action_url('view', email)
form.fieldset = forms.FieldSet()
form.fieldset.fields['key'] = forms.Field('key', value=email['key'])
form.fieldset.fields['fallback_key'] = forms.Field('fallback_key', value=email['fallback_key'])
form.fieldset.fields['prefix'] = forms.Field('prefix', value=email['prefix'], label="Subject Prefix")
form.fieldset.fields['subject'] = forms.Field('subject', value=email['subject'], label="Subject Text")
form.fieldset.fields['description'] = forms.Field('description', value=email['description'])
form.fieldset.fields['sender'] = forms.Field('sender', value=email['sender'], label="From")
form.fieldset.fields['replyto'] = forms.Field('replyto', value=email['replyto'], label="Reply-To")
form.fieldset.fields['to'] = forms.Field('to', value=email['to'])
form.fieldset.fields['cc'] = forms.Field('cc', value=email['cc'])
form.fieldset.fields['bcc'] = forms.Field('bcc', value=email['bcc'])
return form return form
def save_form(self, form):
fs = form.fieldset
fs.sync()
key = fs.key._value
api.save_setting(Session(), 'rattail.mail.{}.prefix'.format(key), fs.prefix._value)
api.save_setting(Session(), 'rattail.mail.{}.subject'.format(key), fs.subject._value)
api.save_setting(Session(), 'rattail.mail.{}.from'.format(key), fs.sender._value)
api.save_setting(Session(), 'rattail.mail.{}.replyto'.format(key), fs.replyto._value)
api.save_setting(Session(), 'rattail.mail.{}.to'.format(key), (fs.to._value or '').replace('\n', ', '))
api.save_setting(Session(), 'rattail.mail.{}.cc'.format(key), (fs.cc._value or '').replace('\n', ', '))
api.save_setting(Session(), 'rattail.mail.{}.bcc'.format(key), (fs.bcc._value or '').replace('\n', ', '))
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
key = self.request.matchdict['key'] key = self.request.matchdict['key']
kwargs['email'] = mail.get_email(self.rattail_config, key) kwargs['email'] = mail.get_email(self.rattail_config, key)

View file

@ -117,13 +117,9 @@ class MasterView(View):
self.viewing = True self.viewing = True
instance = self.get_instance() instance = self.get_instance()
form = self.make_form(instance) form = self.make_form(instance)
return self.render_to_response('view', { return self.render_to_response('view', {'instance': instance,
'instance': instance, 'instance_title': self.get_instance_title(instance),
'form': form, 'form': form})
'instance_title': self.get_instance_title(instance)})
def get_instance_title(self, instance):
return unicode(instance)
def edit(self): def edit(self):
""" """
@ -134,12 +130,14 @@ class MasterView(View):
form = self.make_form(instance) form = self.make_form(instance)
if self.request.method == 'POST': if self.request.method == 'POST':
if form.validate(): if form.validate():
form.save() self.save_form(form)
self.after_edit(instance) self.after_edit(instance)
self.request.session.flash("{0} {1} has been updated.".format( self.request.session.flash("{0} {1} has been updated.".format(
self.get_model_title(), instance)) self.get_model_title(), self.get_instance_title(instance)))
return HTTPFound(location=self.get_action_url('view', instance)) return HTTPFound(location=self.get_action_url('view', instance))
return self.render_to_response('edit', {'instance': instance, 'form': form}) return self.render_to_response('edit', {'instance': instance,
'instance_title': self.get_instance_title(instance),
'form': form})
def delete(self): def delete(self):
""" """
@ -503,6 +501,12 @@ class MasterView(View):
raise HTTPNotFound() raise HTTPNotFound()
return instance return instance
def get_instance_title(self, instance):
"""
Return a "pretty" title for the instance, to be used in the page title etc.
"""
return unicode(instance)
def make_form(self, instance, **kwargs): def make_form(self, instance, **kwargs):
""" """
Make a FormAlchemy-based form for use with CRUD views. Make a FormAlchemy-based form for use with CRUD views.
@ -525,6 +529,9 @@ class MasterView(View):
form.readonly = self.viewing form.readonly = self.viewing
return form return form
def save_form(self, form):
form.save()
def make_fieldset(self, instance, **kwargs): def make_fieldset(self, instance, **kwargs):
""" """
Make a FormAlchemy fieldset for the given model instance. Make a FormAlchemy fieldset for the given model instance.