Add support for toggling visibility of email profile settings

This commit is contained in:
Lance Edgar 2022-08-06 18:38:17 -05:00
parent 7d3f2e6bdf
commit d52a186e12
5 changed files with 188 additions and 18 deletions

View file

@ -1492,6 +1492,12 @@ class GridAction(object):
return self.url(row, i)
return self.url
def render_icon(self):
"""
Render the HTML snippet for the action link icon.
"""
return HTML.tag('i', class_='fas fa-{}'.format(self.icon))
def render_label(self):
"""
Render the label "text" within the actions column of a grid

View file

@ -135,7 +135,7 @@
</div>
<b-table
:data="data"
:data="visibleData"
## :columns="columns"
:loading="loading"
:row-class="getRowClass"
@ -211,7 +211,7 @@
@click.prevent="${action.click_handler}"
% endif
>
<i class="fas fa-${action.icon}"></i>
${action.render_icon()|n}
${action.render_label()|n}
</a>
&nbsp;
@ -296,15 +296,24 @@
let ${grid.component_studly} = {
template: '#${grid.component}-template',
mixins: [FormPosterMixin],
props: {
csrftoken: String,
},
computed: {
// note, can use this with v-model for hidden 'uuids' fields
selected_uuids: function() {
return this.checkedRowUUIDs().join(',')
},
// nb. this can be overridden if needed, e.g. to dynamically
// show/hide certain records in a static data set
visibleData() {
return this.data
},
},
methods: {

View file

@ -481,7 +481,7 @@
</%def>
<%def name="render_grid_component()">
<${grid.component} :csrftoken="csrftoken"
<${grid.component} ref="grid" :csrftoken="csrftoken"
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
@deleteActionClicked="deleteObject"
% endif

View file

@ -0,0 +1,63 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" />
<%def name="render_grid_component()">
% if master.has_perm('configure'):
<b-field horizontal label="Showing:">
<b-select v-model="showEmails" @input="updateVisibleEmails()">
<option value="available">Available Emails</option>
<option value="all">All Emails</option>
<option value="hidden">Hidden Emails</option>
</b-select>
</b-field>
% endif
${parent.render_grid_component()}
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
% if master.has_perm('configure'):
<script type="text/javascript">
ThisPageData.showEmails = 'available'
ThisPage.methods.updateVisibleEmails = function() {
this.$refs.grid.showEmails = this.showEmails
}
${grid.component_studly}Data.showEmails = 'available'
${grid.component_studly}.computed.visibleData = function() {
if (this.showEmails == 'available') {
return this.data.filter(email => email.hidden == 'No')
} else if (this.showEmails == 'hidden') {
return this.data.filter(email => email.hidden == 'Yes')
}
// showing all
return this.data
}
${grid.component_studly}.methods.renderLabelToggleHidden = function(row) {
return row.hidden == 'Yes' ? "Un-hide" : "Hide"
}
${grid.component_studly}.methods.toggleHidden = function(row) {
let url = '${url('{}.toggle_hidden'.format(route_prefix))}'
let params = {
key: row.key,
hidden: row.hidden == 'No'? true : false,
}
this.submitForm(url, params, response => {
row.hidden = params.hidden ? 'Yes' : 'No'
})
}
</script>
% endif
</%def>
${parent.body()}

View file

@ -27,6 +27,7 @@ Email Views
from __future__ import unicode_literals, absolute_import
import re
import warnings
import six
@ -38,6 +39,7 @@ import colander
from deform import widget as dfwidget
from webhelpers2.html import HTML
from tailbone import grids
from tailbone.db import Session
from tailbone.views import View, MasterView
@ -63,6 +65,7 @@ class EmailSettingView(MasterView):
'subject',
'to',
'enabled',
'hidden',
]
form_fields = [
@ -77,11 +80,19 @@ class EmailSettingView(MasterView):
'cc',
'bcc',
'enabled',
'hidden',
]
def __init__(self, request):
super(EmailSettingView, self).__init__(request)
self.handler = self.get_handler()
self.email_handler = self.get_handler()
@property
def handler(self):
warnings.warn("the `handler` property is deprecated! "
"please use `email_handler` instead",
DeprecationWarning, stacklevel=2)
return self.email_handler
def get_handler(self):
app = self.get_rattail_app()
@ -89,9 +100,12 @@ class EmailSettingView(MasterView):
def get_data(self, session=None):
data = []
for email in self.handler.iter_emails():
key = email.key or email.__name__
email = email(self.rattail_config, key)
if self.has_perm('configure'):
emails = self.email_handler.get_all_emails()
else:
emails = self.email_handler.get_available_emails()
for key, Email in six.iteritems(emails):
email = Email(self.rattail_config, key)
data.append(self.normalize(email))
return data
@ -112,6 +126,20 @@ class EmailSettingView(MasterView):
g.set_renderer('to', self.render_to_short)
g.sorters['to'] = g.make_simple_sorter('to', foldcase=True)
# hidden
if self.has_perm('configure'):
g.sorters['hidden'] = g.make_simple_sorter('hidden')
g.set_type('hidden', 'boolean')
else:
g.remove('hidden')
# toggle hidden
if self.has_perm('configure'):
g.main_actions.append(
self.make_action('toggle_hidden', url='#', icon='ban',
click_handler='toggleHidden(props.row)',
factory=ToggleHidden))
def render_to_short(self, email, column):
profile = email['_email']
if self.rattail_config.production():
@ -133,7 +161,7 @@ class EmailSettingView(MasterView):
if recips:
return ', '.join(recips)
data = email.obtain_sample_data(self.request)
return {
normal = {
'_email': email,
'key': email.key,
'fallback_key': email.fallback_key,
@ -147,10 +175,13 @@ class EmailSettingView(MasterView):
'bcc': get_recips('bcc') or '',
'enabled': email.get_enabled(),
}
if self.has_perm('configure'):
normal['hidden'] = self.email_handler.email_is_hidden(email.key)
return normal
def get_instance(self):
key = self.request.matchdict['key']
return self.normalize(self.handler.get_email(key))
return self.normalize(self.email_handler.get_email(key))
def get_instance_title(self, email):
return email['_email'].get_complete_subject(render=False)
@ -207,8 +238,20 @@ class EmailSettingView(MasterView):
# enabled
f.set_type('enabled', 'boolean')
# hidden
if self.has_perm('configure'):
f.set_type('hidden', 'boolean')
else:
f.remove('hidden')
def make_form_schema(self):
return EmailProfileSchema()
schema = EmailProfileSchema()
if not self.has_perm('configure'):
hidden = schema.get('hidden')
schema.children.remove(hidden)
return schema
def save_edit_form(self, form):
key = self.request.matchdict['key']
@ -223,11 +266,13 @@ class EmailSettingView(MasterView):
app.save_setting(session, 'rattail.mail.{}.cc'.format(key), (data['cc'] or '').replace('\n', ', '))
app.save_setting(session, 'rattail.mail.{}.bcc'.format(key), (data['bcc'] or '').replace('\n', ', '))
app.save_setting(session, 'rattail.mail.{}.enabled'.format(key), six.text_type(data['enabled']).lower())
if self.has_perm('configure'):
app.save_setting(session, 'rattail.mail.{}.hidden'.format(key), six.text_type(data['hidden']).lower())
return data
def template_kwargs_view(self, **kwargs):
key = self.request.matchdict['key']
kwargs['email'] = self.handler.get_email(key)
kwargs['email'] = self.email_handler.get_email(key)
return kwargs
def configure_get_simple_settings(self):
@ -240,10 +285,48 @@ class EmailSettingView(MasterView):
'type': bool},
]
def toggle_hidden(self):
app = self.get_rattail_app()
data = self.request.json_body
name = 'rattail.mail.{}.hidden'.format(data['key'])
app.save_setting(self.Session(), name,
'true' if data['hidden'] else 'false')
return {'ok': True}
@classmethod
def defaults(cls, config):
cls._email_defaults(config)
cls._defaults(config)
@classmethod
def _email_defaults(cls, config):
route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix()
model_title_plural = cls.get_model_title_plural()
# toggle hidden
config.add_route('{}.toggle_hidden'.format(route_prefix),
'{}/toggle-hidden'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='toggle_hidden',
route_name='{}.toggle_hidden'.format(route_prefix),
permission='{}.configure'.format(permission_prefix),
renderer='json')
# TODO: deprecate / remove this
ProfilesView = EmailSettingView
class ToggleHidden(grids.GridAction):
"""
Grid action for toggling the 'hidden' flag for an email profile.
"""
def render_label(self):
return '{{ renderLabelToggleHidden(props.row) }}'
class RecipientsType(colander.String):
"""
Custom schema type for email recipients. This is used to present the
@ -284,6 +367,8 @@ class EmailProfileSchema(colander.MappingSchema):
enabled = colander.SchemaNode(colander.Boolean())
hidden = colander.SchemaNode(colander.Boolean())
class EmailPreview(View):
"""
@ -292,7 +377,14 @@ class EmailPreview(View):
def __init__(self, request):
super(EmailPreview, self).__init__(request)
self.handler = self.get_handler()
self.email_handler = self.get_handler()
@property
def handler(self):
warnings.warn("the `handler` property is deprecated! "
"please use `email_handler` instead",
DeprecationWarning, stacklevel=2)
return self.email_handler
def get_handler(self):
app = self.get_rattail_app()
@ -319,10 +411,10 @@ class EmailPreview(View):
if recipient:
key = self.request.POST.get('email_key')
if key:
email = self.handler.get_email(key)
email = self.email_handler.get_email(key)
data = email.obtain_sample_data(self.request)
self.handler.send_message(email, data,
self.email_handler.send_message(email, data,
subject_prefix="[PREVIEW] ",
to=[recipient],
cc=None, bcc=None)
@ -332,7 +424,7 @@ class EmailPreview(View):
key, recipient))
def preview_template(self, key, type_):
email = self.handler.get_email(key)
email = self.email_handler.get_email(key)
template = email.get_template(type_)
data = email.obtain_sample_data(self.request)
self.request.response.text = template.render(**data)