Add support for toggling visibility of email profile settings
This commit is contained in:
parent
7d3f2e6bdf
commit
d52a186e12
|
@ -1492,6 +1492,12 @@ class GridAction(object):
|
||||||
return self.url(row, i)
|
return self.url(row, i)
|
||||||
return self.url
|
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):
|
def render_label(self):
|
||||||
"""
|
"""
|
||||||
Render the label "text" within the actions column of a grid
|
Render the label "text" within the actions column of a grid
|
||||||
|
|
|
@ -135,7 +135,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<b-table
|
<b-table
|
||||||
:data="data"
|
:data="visibleData"
|
||||||
## :columns="columns"
|
## :columns="columns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:row-class="getRowClass"
|
:row-class="getRowClass"
|
||||||
|
@ -211,7 +211,7 @@
|
||||||
@click.prevent="${action.click_handler}"
|
@click.prevent="${action.click_handler}"
|
||||||
% endif
|
% endif
|
||||||
>
|
>
|
||||||
<i class="fas fa-${action.icon}"></i>
|
${action.render_icon()|n}
|
||||||
${action.render_label()|n}
|
${action.render_label()|n}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -296,15 +296,24 @@
|
||||||
let ${grid.component_studly} = {
|
let ${grid.component_studly} = {
|
||||||
template: '#${grid.component}-template',
|
template: '#${grid.component}-template',
|
||||||
|
|
||||||
|
mixins: [FormPosterMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
csrftoken: String,
|
csrftoken: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
// note, can use this with v-model for hidden 'uuids' fields
|
// note, can use this with v-model for hidden 'uuids' fields
|
||||||
selected_uuids: function() {
|
selected_uuids: function() {
|
||||||
return this.checkedRowUUIDs().join(',')
|
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: {
|
methods: {
|
||||||
|
|
|
@ -481,7 +481,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_grid_component()">
|
<%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':
|
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
|
||||||
@deleteActionClicked="deleteObject"
|
@deleteActionClicked="deleteObject"
|
||||||
% endif
|
% endif
|
||||||
|
|
63
tailbone/templates/settings/email/index.mako
Normal file
63
tailbone/templates/settings/email/index.mako
Normal 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()}
|
|
@ -27,6 +27,7 @@ Email Views
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from webhelpers2.html import HTML
|
from webhelpers2.html import HTML
|
||||||
|
|
||||||
|
from tailbone import grids
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import View, MasterView
|
from tailbone.views import View, MasterView
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ class EmailSettingView(MasterView):
|
||||||
'subject',
|
'subject',
|
||||||
'to',
|
'to',
|
||||||
'enabled',
|
'enabled',
|
||||||
|
'hidden',
|
||||||
]
|
]
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
|
@ -77,11 +80,19 @@ class EmailSettingView(MasterView):
|
||||||
'cc',
|
'cc',
|
||||||
'bcc',
|
'bcc',
|
||||||
'enabled',
|
'enabled',
|
||||||
|
'hidden',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(EmailSettingView, self).__init__(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):
|
def get_handler(self):
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
@ -89,9 +100,12 @@ class EmailSettingView(MasterView):
|
||||||
|
|
||||||
def get_data(self, session=None):
|
def get_data(self, session=None):
|
||||||
data = []
|
data = []
|
||||||
for email in self.handler.iter_emails():
|
if self.has_perm('configure'):
|
||||||
key = email.key or email.__name__
|
emails = self.email_handler.get_all_emails()
|
||||||
email = email(self.rattail_config, key)
|
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))
|
data.append(self.normalize(email))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -112,6 +126,20 @@ class EmailSettingView(MasterView):
|
||||||
g.set_renderer('to', self.render_to_short)
|
g.set_renderer('to', self.render_to_short)
|
||||||
g.sorters['to'] = g.make_simple_sorter('to', foldcase=True)
|
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):
|
def render_to_short(self, email, column):
|
||||||
profile = email['_email']
|
profile = email['_email']
|
||||||
if self.rattail_config.production():
|
if self.rattail_config.production():
|
||||||
|
@ -133,7 +161,7 @@ class EmailSettingView(MasterView):
|
||||||
if recips:
|
if recips:
|
||||||
return ', '.join(recips)
|
return ', '.join(recips)
|
||||||
data = email.obtain_sample_data(self.request)
|
data = email.obtain_sample_data(self.request)
|
||||||
return {
|
normal = {
|
||||||
'_email': email,
|
'_email': email,
|
||||||
'key': email.key,
|
'key': email.key,
|
||||||
'fallback_key': email.fallback_key,
|
'fallback_key': email.fallback_key,
|
||||||
|
@ -147,10 +175,13 @@ class EmailSettingView(MasterView):
|
||||||
'bcc': get_recips('bcc') or '',
|
'bcc': get_recips('bcc') or '',
|
||||||
'enabled': email.get_enabled(),
|
'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):
|
def get_instance(self):
|
||||||
key = self.request.matchdict['key']
|
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):
|
def get_instance_title(self, email):
|
||||||
return email['_email'].get_complete_subject(render=False)
|
return email['_email'].get_complete_subject(render=False)
|
||||||
|
@ -207,8 +238,20 @@ class EmailSettingView(MasterView):
|
||||||
# enabled
|
# enabled
|
||||||
f.set_type('enabled', 'boolean')
|
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):
|
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):
|
def save_edit_form(self, form):
|
||||||
key = self.request.matchdict['key']
|
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.{}.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.{}.bcc'.format(key), (data['bcc'] or '').replace('\n', ', '))
|
||||||
app.save_setting(session, 'rattail.mail.{}.enabled'.format(key), six.text_type(data['enabled']).lower())
|
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
|
return data
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
key = self.request.matchdict['key']
|
key = self.request.matchdict['key']
|
||||||
kwargs['email'] = self.handler.get_email(key)
|
kwargs['email'] = self.email_handler.get_email(key)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def configure_get_simple_settings(self):
|
def configure_get_simple_settings(self):
|
||||||
|
@ -240,10 +285,48 @@ class EmailSettingView(MasterView):
|
||||||
'type': bool},
|
'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
|
# TODO: deprecate / remove this
|
||||||
ProfilesView = EmailSettingView
|
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):
|
class RecipientsType(colander.String):
|
||||||
"""
|
"""
|
||||||
Custom schema type for email recipients. This is used to present the
|
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())
|
enabled = colander.SchemaNode(colander.Boolean())
|
||||||
|
|
||||||
|
hidden = colander.SchemaNode(colander.Boolean())
|
||||||
|
|
||||||
|
|
||||||
class EmailPreview(View):
|
class EmailPreview(View):
|
||||||
"""
|
"""
|
||||||
|
@ -292,7 +377,14 @@ class EmailPreview(View):
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(EmailPreview, self).__init__(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):
|
def get_handler(self):
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
@ -319,20 +411,20 @@ class EmailPreview(View):
|
||||||
if recipient:
|
if recipient:
|
||||||
key = self.request.POST.get('email_key')
|
key = self.request.POST.get('email_key')
|
||||||
if key:
|
if key:
|
||||||
email = self.handler.get_email(key)
|
email = self.email_handler.get_email(key)
|
||||||
data = email.obtain_sample_data(self.request)
|
data = email.obtain_sample_data(self.request)
|
||||||
|
|
||||||
self.handler.send_message(email, data,
|
self.email_handler.send_message(email, data,
|
||||||
subject_prefix="[PREVIEW] ",
|
subject_prefix="[PREVIEW] ",
|
||||||
to=[recipient],
|
to=[recipient],
|
||||||
cc=None, bcc=None)
|
cc=None, bcc=None)
|
||||||
|
|
||||||
self.request.session.flash(
|
self.request.session.flash(
|
||||||
"Preview for '{}' was emailed to {}".format(
|
"Preview for '{}' was emailed to {}".format(
|
||||||
key, recipient))
|
key, recipient))
|
||||||
|
|
||||||
def preview_template(self, key, type_):
|
def preview_template(self, key, type_):
|
||||||
email = self.handler.get_email(key)
|
email = self.email_handler.get_email(key)
|
||||||
template = email.get_template(type_)
|
template = email.get_template(type_)
|
||||||
data = email.obtain_sample_data(self.request)
|
data = email.obtain_sample_data(self.request)
|
||||||
self.request.response.text = template.render(**data)
|
self.request.response.text = template.render(**data)
|
||||||
|
|
Loading…
Reference in a new issue