0001-workflows-add-mail-template-management-25378.patch
tests/test_mail_templates.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | ||
3 |
import base64 |
|
4 |
import os |
|
5 |
import pytest |
|
6 | ||
7 |
from django.utils import six |
|
8 |
from django.utils.encoding import force_bytes |
|
9 |
from quixote import cleanup |
|
10 |
from wcs.formdef import FormDef |
|
11 |
from wcs.mail_templates import MailTemplate |
|
12 |
from wcs.workflows import Workflow, SendmailWorkflowStatusItem |
|
13 |
from wcs.qommon.http_request import HTTPRequest |
|
14 |
from wcs.qommon.ident.password_accounts import PasswordAccount |
|
15 | ||
16 |
from utilities import (get_app, login, create_temporary_pub, clean_temporary_pub) |
|
17 | ||
18 | ||
19 |
def setup_module(module): |
|
20 |
cleanup() |
|
21 | ||
22 | ||
23 |
def teardown_module(module): |
|
24 |
clean_temporary_pub() |
|
25 | ||
26 | ||
27 |
@pytest.fixture |
|
28 |
def pub(request): |
|
29 |
pub = create_temporary_pub() |
|
30 |
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'}) |
|
31 |
pub.set_app_dir(req) |
|
32 |
pub._set_request(req) |
|
33 |
pub.cfg['identification'] = {'methods': ['password']} |
|
34 |
pub.write_cfg() |
|
35 |
return pub |
|
36 | ||
37 | ||
38 |
@pytest.fixture |
|
39 |
def superuser(pub): |
|
40 |
if pub.user_class.select(lambda x: x.name == 'admin'): |
|
41 |
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0] |
|
42 |
user1.is_admin = True |
|
43 |
user1.store() |
|
44 |
return user1 |
|
45 | ||
46 |
user1 = pub.user_class(name='admin') |
|
47 |
user1.is_admin = True |
|
48 |
user1.store() |
|
49 | ||
50 |
account1 = PasswordAccount(id='admin') |
|
51 |
account1.set_password('admin') |
|
52 |
account1.user_id = user1.id |
|
53 |
account1.store() |
|
54 | ||
55 |
return user1 |
|
56 | ||
57 | ||
58 |
@pytest.fixture |
|
59 |
def mail_templates_option(pub): |
|
60 |
if not pub.site_options.has_section('options'): |
|
61 |
pub.site_options.add_section('options') |
|
62 |
pub.site_options.set('options', 'mail-templates', 'true') |
|
63 |
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: |
|
64 |
pub.site_options.write(fd) |
|
65 |
return pub |
|
66 | ||
67 | ||
68 |
def test_mail_templates_disabled(pub, superuser): |
|
69 |
app = login(get_app(pub)) |
|
70 |
resp = app.get('/backoffice/workflows/') |
|
71 |
assert 'Mail Templates' not in resp |
|
72 | ||
73 | ||
74 |
def test_mail_templates_basics(pub, superuser, mail_templates_option): |
|
75 |
app = login(get_app(pub)) |
|
76 |
resp = app.get('/backoffice/workflows/') |
|
77 |
assert 'Mail Templates' in resp |
|
78 |
resp = resp.click('Mail Templates') |
|
79 |
assert 'There are no mail templates defined.' in resp |
|
80 | ||
81 |
resp = resp.click('New') |
|
82 |
resp.form['name'] = 'first mail template' |
|
83 |
resp = resp.form.submit('cancel').follow() |
|
84 |
assert 'There are no mail templates defined.' in resp |
|
85 | ||
86 |
resp = resp.click('New') |
|
87 |
resp.form['name'] = 'first mail template' |
|
88 |
resp = resp.form.submit('submit').follow() |
|
89 |
resp.form['subject'] = 'mail subject' |
|
90 |
resp.form['body'] = 'mail body' |
|
91 |
resp = resp.form.submit('submit').follow() |
|
92 | ||
93 |
resp = resp.click('Edit') |
|
94 |
resp.form['subject'] = 'edited mail subject' |
|
95 |
resp.form['body'] = 'edited mail body' |
|
96 |
resp = resp.form.submit('submit').follow() |
|
97 | ||
98 |
resp = resp.click('Delete') |
|
99 |
resp = resp.form.submit('cancel').follow() |
|
100 |
assert 'first mail template' in resp |
|
101 | ||
102 |
resp = resp.click('Delete') |
|
103 |
resp = resp.form.submit('submit').follow() |
|
104 |
assert 'first mail template' not in resp |
|
105 |
assert 'There are no mail templates defined.' in resp |
|
106 | ||
107 |
resp = resp.click('New') |
|
108 |
resp.form['name'] = 'first mail template' |
|
109 |
resp = resp.form.submit('submit').follow() |
|
110 |
resp.form['subject'] = 'mail subject' |
|
111 |
resp.form['body'] = 'mail body' |
|
112 |
resp = resp.form.submit('submit').follow() |
|
113 | ||
114 |
resp = app.get('/backoffice/workflows/') |
|
115 |
resp = resp.click('Mail Templates') |
|
116 |
assert 'first mail template' in resp |
|
117 | ||
118 | ||
119 |
def test_mail_template_in_use(pub, mail_templates_option): |
|
120 |
Workflow.wipe() |
|
121 |
MailTemplate.wipe() |
|
122 |
workflow = Workflow(name='test mail template') |
|
123 |
st1 = workflow.add_status('Status1') |
|
124 |
item = SendmailWorkflowStatusItem() |
|
125 |
item.to = ['_receiver'] |
|
126 |
item.subject = 'Foobar' |
|
127 |
item.body = 'Hello' |
|
128 |
st1.items.append(item) |
|
129 |
item.parent = st1 |
|
130 |
workflow.store() |
|
131 | ||
132 |
mail_template = MailTemplate(name='test mail template') |
|
133 |
mail_template.subject = 'test subject' |
|
134 |
mail_template.body = 'test body' |
|
135 |
mail_template.store() |
|
136 |
assert mail_template.is_in_use() is False |
|
137 | ||
138 |
item.mail_template = mail_template.slug |
|
139 |
workflow.store() |
|
140 |
assert mail_template.is_in_use() is True |
|
141 | ||
142 | ||
143 |
def test_admin_workflow_edit(pub, superuser, mail_templates_option): |
|
144 |
Workflow.wipe() |
|
145 |
MailTemplate.wipe() |
|
146 |
mail_template = MailTemplate(name='test mail template') |
|
147 |
mail_template.subject = 'test subject' |
|
148 |
mail_template.body = 'test body' |
|
149 |
mail_template.store() |
|
150 | ||
151 |
workflow = Workflow(name='test mail template') |
|
152 |
st1 = workflow.add_status('Status1') |
|
153 |
item = SendmailWorkflowStatusItem() |
|
154 |
item.to = ['_receiver'] |
|
155 |
item.subject = 'Foobar' |
|
156 |
item.body = 'Hello' |
|
157 |
st1.items.append(item) |
|
158 |
item.parent = st1 |
|
159 |
workflow.store() |
|
160 | ||
161 |
app = login(get_app(pub)) |
|
162 |
resp = app.get('/backoffice/workflows/%s/' % workflow.id) |
|
163 |
resp = resp.click('Status1') |
|
164 |
resp = resp.click('Email') |
|
165 |
resp.form['mail_template'] = 'test-mail-template' |
|
166 |
resp = resp.form.submit('submit') |
|
167 | ||
168 |
workflow = Workflow.get(workflow.id) |
|
169 |
assert workflow.possible_status[0].items[0].mail_template == 'test-mail-template' |
|
170 | ||
171 | ||
172 |
def test_workflow_send_mail_template(pub, superuser, mail_templates_option, emails): |
|
173 |
Workflow.wipe() |
|
174 |
MailTemplate.wipe() |
|
175 | ||
176 |
mail_template = MailTemplate(name='test mail template') |
|
177 |
mail_template.subject = 'test subject' |
|
178 |
mail_template.body = 'test body' |
|
179 |
mail_template.store() |
|
180 | ||
181 |
workflow = Workflow(name='test mail template') |
|
182 |
st1 = workflow.add_status('Status1') |
|
183 |
item = SendmailWorkflowStatusItem() |
|
184 |
item.to = 'xyz@localhost' |
|
185 |
item.subject = 'Foobar' |
|
186 |
item.body = 'Hello' |
|
187 |
item.mail_template = mail_template.slug |
|
188 |
st1.items.append(item) |
|
189 |
item.parent = st1 |
|
190 |
workflow.store() |
|
191 | ||
192 |
formdef = FormDef() |
|
193 |
formdef.name = 'baz' |
|
194 |
formdef.fields = [] |
|
195 |
formdef.store() |
|
196 | ||
197 |
formdata = formdef.data_class()() |
|
198 |
formdata.just_created() |
|
199 |
formdata.store() |
|
200 | ||
201 |
item.perform(formdata) |
|
202 |
pub.get_request().response.process_after_jobs() |
|
203 |
assert emails.count() == 1 |
|
204 |
assert emails.get('test subject')['email_rcpt'] == ['xyz@localhost'] |
|
205 |
if six.PY2: |
|
206 |
assert 'test body' in emails.get('test subject')['msg'].get_payload(0).get_payload() |
|
207 |
else: |
|
208 |
assert b'test body' in base64.decodestring(force_bytes(emails.get('test subject')['msg'].get_payload(0).get_payload())) |
wcs/admin/mail_templates.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2020 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from quixote import get_response, redirect |
|
18 |
from quixote.directory import Directory |
|
19 |
from quixote.html import TemplateIO, htmltext |
|
20 | ||
21 |
from wcs.qommon import _, errors, template |
|
22 |
from wcs.qommon.backoffice.menu import html_top |
|
23 |
from wcs.qommon.form import Form, HtmlWidget, StringWidget, TextWidget, ComputedExpressionWidget |
|
24 |
from wcs.mail_templates import MailTemplate |
|
25 | ||
26 | ||
27 |
class MailTemplatesDirectory(Directory): |
|
28 |
_q_exports = ['', 'new'] |
|
29 |
do_not_call_in_templates = True |
|
30 | ||
31 |
def _q_traverse(self, path): |
|
32 |
get_response().breadcrumb.append(('workflows/', _('Workflows'))) |
|
33 |
get_response().breadcrumb.append(('mail-templates/', _('Mail Templates'))) |
|
34 |
return super(MailTemplatesDirectory, self)._q_traverse(path) |
|
35 | ||
36 |
def _q_lookup(self, component): |
|
37 |
return MailTemplatePage(component) |
|
38 | ||
39 |
def _q_index(self): |
|
40 |
html_top('mail_templates', title=_('Mail Templates')) |
|
41 |
return template.QommonTemplateResponse( |
|
42 |
templates=['wcs/backoffice/mail-templates.html'], |
|
43 |
context={'view': self, 'mail_templates': MailTemplate.select(order_by='name')}) |
|
44 | ||
45 |
def new(self): |
|
46 |
form = Form(enctype='multipart/form-data') |
|
47 |
form.add(StringWidget, 'name', title=_('Name'), required=True, size=50) |
|
48 |
form.add_submit('submit', _('Add')) |
|
49 |
form.add_submit('cancel', _('Cancel')) |
|
50 |
if form.get_widget('cancel').parse(): |
|
51 |
return redirect('.') |
|
52 | ||
53 |
if form.is_submitted() and not form.has_errors(): |
|
54 |
mail_template = MailTemplate(name=form.get_widget('name').parse()) |
|
55 |
mail_template.store() |
|
56 |
return redirect('%s/edit' % mail_template.id) |
|
57 | ||
58 |
get_response().breadcrumb.append(('new', _('New Mail Template'))) |
|
59 |
html_top('mail_templates', title=_('New Mail Template')) |
|
60 |
r = TemplateIO(html=True) |
|
61 |
r += htmltext('<h2>%s</h2>') % _('New Mail Template') |
|
62 |
r += form.render() |
|
63 |
return r.getvalue() |
|
64 | ||
65 | ||
66 |
class MailTemplatePage(Directory): |
|
67 |
_q_exports = ['', 'edit', 'delete'] |
|
68 |
do_not_call_in_templates = True |
|
69 | ||
70 |
def __init__(self, mail_template_id): |
|
71 |
try: |
|
72 |
self.mail_template = MailTemplate.get(mail_template_id) |
|
73 |
except KeyError: |
|
74 |
raise errors.TraversalError() |
|
75 |
get_response().breadcrumb.append((mail_template_id + '/', self.mail_template.name)) |
|
76 | ||
77 |
def _q_index(self): |
|
78 |
html_top('mail_templates', title=self.mail_template.name) |
|
79 |
return template.QommonTemplateResponse( |
|
80 |
templates=['wcs/backoffice/mail-template.html'], |
|
81 |
context={'view': self, 'mail_template': self.mail_template}) |
|
82 | ||
83 |
def get_form(self): |
|
84 |
form = Form(enctype='multipart/form-data', advanced_label=_('Additional options')) |
|
85 |
form.add(StringWidget, 'name', title=_('Name'), required=True, size=30, |
|
86 |
value=self.mail_template.name) |
|
87 |
form.add(TextWidget, 'description', title=_('Description'), |
|
88 |
cols=80, rows=3, |
|
89 |
value=self.mail_template.description) |
|
90 |
form.add(StringWidget, 'subject', title=_('Subject'), required=True, size=40, |
|
91 |
value=self.mail_template.subject, |
|
92 |
validation_function=ComputedExpressionWidget.validate_template) |
|
93 |
form.add(TextWidget, 'body', title=_('Body'), |
|
94 |
value=self.mail_template.body, cols=80, rows=15, require=True, |
|
95 |
validation_function=ComputedExpressionWidget.validate_template) |
|
96 | ||
97 |
if self.mail_template.slug and not self.mail_template.is_in_use(): |
|
98 |
form.add(StringWidget, 'slug', |
|
99 |
value=self.mail_template.slug, |
|
100 |
title=_('Identifier'), |
|
101 |
required=True, advanced=True, |
|
102 |
) |
|
103 |
form.add_submit('submit', _('Submit')) |
|
104 |
form.add_submit('cancel', _('Cancel')) |
|
105 |
return form |
|
106 | ||
107 |
def submit_form(self, form): |
|
108 |
name = form.get_widget('name').parse() |
|
109 |
slug_widget = form.get_widget('slug') |
|
110 |
if slug_widget: |
|
111 |
slug = form.get_widget('slug').parse() |
|
112 | ||
113 |
for mail_template in MailTemplate.select(): |
|
114 |
if mail_template.id == self.mail_template.id: |
|
115 |
continue |
|
116 |
if slug_widget and slug == mail_template.slug: |
|
117 |
slug_widget.set_error(_('This value is already used.')) |
|
118 |
if form.has_errors(): |
|
119 |
raise ValueError() |
|
120 | ||
121 |
self.mail_template.name = name |
|
122 |
self.mail_template.description = form.get_widget('description').parse() |
|
123 |
self.mail_template.subject = form.get_widget('subject').parse() |
|
124 |
self.mail_template.body = form.get_widget('body').parse() |
|
125 |
if slug_widget: |
|
126 |
self.mail_template.slug = slug |
|
127 |
self.mail_template.store() |
|
128 | ||
129 |
def edit(self): |
|
130 |
form = self.get_form() |
|
131 |
if form.get_submit() == 'cancel': |
|
132 |
return redirect('.') |
|
133 | ||
134 |
if form.get_submit() == 'submit' and not form.has_errors(): |
|
135 |
try: |
|
136 |
self.submit_form(form) |
|
137 |
except ValueError: |
|
138 |
pass |
|
139 |
else: |
|
140 |
return redirect('.') |
|
141 | ||
142 |
get_response().breadcrumb.append(('edit', _('Edit'))) |
|
143 |
html_top('mail_templates', title=_('Edit Mail Template')) |
|
144 |
r = TemplateIO(html=True) |
|
145 |
r += htmltext('<h2>%s</h2>') % _('Edit Mail Template') |
|
146 |
r += form.render() |
|
147 |
return r.getvalue() |
|
148 | ||
149 |
def delete(self): |
|
150 |
form = Form(enctype='multipart/form-data') |
|
151 |
if not self.mail_template.is_in_use(): |
|
152 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
153 |
'You are about to irrevocably delete this mail template.'))) |
|
154 |
form.add_submit('delete', _('Submit')) |
|
155 |
else: |
|
156 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
157 |
'This mail template is still used, it cannot be deleted.'))) |
|
158 |
form.add_submit('cancel', _('Cancel')) |
|
159 |
if form.get_widget('cancel').parse(): |
|
160 |
return redirect('.') |
|
161 |
if not form.is_submitted() or form.has_errors(): |
|
162 |
get_response().breadcrumb.append(('delete', _('Delete'))) |
|
163 |
html_top('mail_templates', title=_('Delete Mail Template')) |
|
164 |
r = TemplateIO(html=True) |
|
165 |
r += htmltext('<h2>%s %s</h2>') % (_('Deleting Mail Template:'), self.mail_template.name) |
|
166 |
r += form.render() |
|
167 |
return r.getvalue() |
|
168 |
else: |
|
169 |
self.mail_template.remove_self() |
|
170 |
return redirect('..') |
wcs/admin/settings.py | ||
---|---|---|
861 | 861 |
form.add(CheckboxWidget, 'categories', title = _('Categories'), value = True) |
862 | 862 |
form.add(CheckboxWidget, 'settings', title = _('Settings'), value = False) |
863 | 863 |
form.add(CheckboxWidget, 'datasources', title=_('Data sources'), value=True) |
864 |
form.add(CheckboxWidget, 'mail-templates', title=_('Mail templates'), value=True) |
|
864 | 865 |
form.add(CheckboxWidget, 'wscalls', title=_('Webservice calls'), value=True) |
865 | 866 |
form.add_submit('submit', _('Submit')) |
866 | 867 |
form.add_submit('cancel', _('Cancel')) |
... | ... | |
885 | 886 |
c = BytesIO() |
886 | 887 |
z = zipfile.ZipFile(c, 'w') |
887 | 888 |
for d in self.dirs: |
888 |
if d not in ('roles', 'categories', 'datasources', 'wscalls'): |
|
889 |
if d not in ('roles', 'categories', 'datasources', 'wscalls', 'mail-templates'):
|
|
889 | 890 |
continue |
890 | 891 |
path = os.path.join(self.app_dir, d) |
891 | 892 |
if not os.path.exists(path): |
... | ... | |
928 | 929 | |
929 | 930 |
dirs = [] |
930 | 931 |
for w in ('formdefs', 'carddefs', 'workflows', 'roles', 'categories', |
931 |
'datasources', 'wscalls'): |
|
932 |
'datasources', 'wscalls', 'mail-templates'):
|
|
932 | 933 |
if form.get_widget(w) and form.get_widget(w).parse(): |
933 | 934 |
dirs.append(w) |
934 | 935 |
if not dirs and not form.get_widget('settings').parse(): |
... | ... | |
1017 | 1018 |
r += htmltext('<li>%s</li>') % _('Settings') |
1018 | 1019 |
if results['datasources']: |
1019 | 1020 |
r += htmltext('<li>%d %s</li>') % (results['datasources'], _('data sources')) |
1021 |
if results['mail-templates']: |
|
1022 |
r += htmltext('<li>%d %s</li>') % (results['mail-templates'], _('mail templates')) |
|
1020 | 1023 |
if results['wscalls']: |
1021 | 1024 |
r += htmltext('<li>%d %s</li>') % (results['wscalls'], _('webservice calls')) |
1022 | 1025 |
r += htmltext('</ul>') |
wcs/admin/workflows.py | ||
---|---|---|
46 | 46 |
from .fields import FieldDefPage, FieldsDirectory |
47 | 47 |
from .data_sources import NamedDataSourcesDirectory |
48 | 48 |
from .logged_errors import LoggedErrorsDirectory |
49 |
from .mail_templates import MailTemplatesDirectory |
|
49 | 50 |
from wcs.backoffice.studio import StudioDirectory |
50 | 51 | |
51 | 52 | |
... | ... | |
1814 | 1815 | |
1815 | 1816 |
class WorkflowsDirectory(Directory): |
1816 | 1817 |
_q_exports = ['', 'new', ('import', 'p_import'), |
1817 |
('data-sources', 'data_sources')] |
|
1818 |
('data-sources', 'data_sources'), |
|
1819 |
('mail-templates', 'mail_templates')] |
|
1818 | 1820 | |
1819 | 1821 |
data_sources = NamedDataSourcesDirectoryInWorkflows() |
1822 |
mail_templates = MailTemplatesDirectory() |
|
1820 | 1823 | |
1821 | 1824 |
def html_top(self, title): |
1822 | 1825 |
return html_top('workflows', title) |
... | ... | |
1829 | 1832 |
r += htmltext('<div id="appbar">') |
1830 | 1833 |
r += htmltext('<h2>%s</h2>') % _('Workflows') |
1831 | 1834 |
r += htmltext('<span class="actions">') |
1835 |
if get_publisher().has_site_option('mail-templates'): |
|
1836 |
r += htmltext('<a href="mail-templates/">%s</a>') % _('Mail Templates') |
|
1832 | 1837 |
r += htmltext('<a href="data-sources/">%s</a>') % _('Data sources') |
1833 | 1838 |
r += htmltext('<a href="import" rel="popup">%s</a>') % _('Import') |
1834 | 1839 |
r += htmltext('<a class="new-item" rel="popup" href="new">%s</a>') % _('New Workflow') |
wcs/mail_templates.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2020 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from wcs.qommon import misc, get_logger |
|
18 |
from wcs.qommon.xml_storage import XmlStorableObject |
|
19 | ||
20 | ||
21 |
class MailTemplate(XmlStorableObject): |
|
22 |
_names = 'mail-templates' |
|
23 |
_xml_tagname = 'mail-template' |
|
24 | ||
25 |
name = None |
|
26 |
slug = None |
|
27 |
description = None |
|
28 |
subject = None |
|
29 |
body = None |
|
30 | ||
31 |
# declarations for serialization |
|
32 |
XML_NODES = [ |
|
33 |
('name', 'str'), |
|
34 |
('slug', 'str'), |
|
35 |
('description', 'str'), |
|
36 |
('subject', 'str'), |
|
37 |
('body', 'str'), |
|
38 |
] |
|
39 | ||
40 |
def __init__(self, name=None): |
|
41 |
XmlStorableObject.__init__(self) |
|
42 |
self.name = name |
|
43 | ||
44 |
def store(self): |
|
45 |
if self.slug is None: |
|
46 |
# set slug if it's not yet there |
|
47 |
self.slug = self.get_new_slug() |
|
48 |
super(MailTemplate, self).store() |
|
49 | ||
50 |
def get_new_slug(self): |
|
51 |
new_slug = misc.simplify(self.name, space='-') |
|
52 |
base_new_slug = new_slug |
|
53 |
suffix_no = 0 |
|
54 |
known_slugs = {x.slug: x.id for x in self.select(ignore_migration=True, ignore_errors=True)} |
|
55 |
while True: |
|
56 |
if not new_slug in known_slugs: |
|
57 |
break |
|
58 |
suffix_no += 1 |
|
59 |
new_slug = '%s-%s' % (base_new_slug, suffix_no) |
|
60 |
return new_slug |
|
61 | ||
62 |
def is_in_use(self): |
|
63 |
from wcs.workflows import Workflow |
|
64 |
for workflow in Workflow.select(ignore_errors=True, ignore_migration=True): |
|
65 |
for item in workflow.get_all_items(): |
|
66 |
if item.key != 'sendmail': |
|
67 |
continue |
|
68 |
if item.mail_template == self.slug: |
|
69 |
return True |
|
70 |
return False |
|
71 | ||
72 |
@classmethod |
|
73 |
def get_as_options_list(cls): |
|
74 |
options = [] |
|
75 |
for mail_template in cls.select(order_by='name'): |
|
76 |
options.append((mail_template.slug, mail_template.name, mail_template.slug)) |
|
77 |
return options |
|
78 | ||
79 |
@classmethod |
|
80 |
def get_by_slug(cls, slug): |
|
81 |
objects = [x for x in cls.select() if x.slug == slug] |
|
82 |
if objects: |
|
83 |
return objects[0] |
|
84 |
get_logger().warn("mail template '%s' does not exist" % slug) |
|
85 |
return None |
wcs/publisher.py | ||
---|---|---|
160 | 160 |
def import_zip(self, fd): |
161 | 161 |
z = zipfile.ZipFile(fd) |
162 | 162 |
results = {'formdefs': 0, 'carddefs': 0, 'workflows': 0, 'categories': 0, 'roles': 0, |
163 |
'settings': 0, 'datasources': 0, 'wscalls': 0} |
|
163 |
'settings': 0, 'datasources': 0, 'wscalls': 0, 'mail-templates': 0}
|
|
164 | 164 | |
165 | 165 |
def _decode_list(data): |
166 | 166 |
rv = [] |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
1859 | 1859 |
table#listing tr.checked td { |
1860 | 1860 |
background: #ddf; |
1861 | 1861 |
} |
1862 | ||
1863 |
div.mail-body { |
|
1864 |
margin-top: 1em; |
|
1865 |
white-space: pre-line; |
|
1866 |
} |
wcs/templates/wcs/backoffice/base.html | ||
---|---|---|
1 | 1 |
{% block appbar %} |
2 | 2 |
<div id="appbar"> |
3 | 3 |
<h2>{% block appbar-title %}{% endblock %}</h2> |
4 |
<span class="actions">{% block appbar-actions %}{% endblock %}</span> |
|
4 | 5 |
</div> |
5 | 6 |
{% endblock %} |
6 | 7 |
wcs/templates/wcs/backoffice/mail-template.html | ||
---|---|---|
1 |
{% extends "wcs/backoffice/base.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block appbar-title %}{% trans "Mail Template" %} - {{ mail_template.name }}{% endblock %} |
|
5 | ||
6 |
{% block appbar-actions %} |
|
7 |
<a href="delete">{% trans "Delete" %}</a> |
|
8 |
<a href="edit">{% trans "Edit" %}</a> |
|
9 |
{% endblock %} |
|
10 | ||
11 |
{% block content %} |
|
12 |
{% if mail_template.description %} |
|
13 |
<div class="bo-block">{{ mail_template.description }}</div> |
|
14 |
{% endif %} |
|
15 | ||
16 |
{% if mail_template.subject and mail_template.body %} |
|
17 |
<div class="bo-block"> |
|
18 |
<div class="mail-subject"><strong>{% trans "Subject:" %} </strong>{{ mail_template.subject }}</div> |
|
19 |
<div class="mail-body">{{ mail_template.body }}</div> |
|
20 |
</div> |
|
21 |
{% else %} |
|
22 |
<div class="infonotice">{% trans "This mail template still needs to be configured." %}</div> |
|
23 |
{% endif %} |
|
24 | ||
25 |
{% endblock %} |
wcs/templates/wcs/backoffice/mail-templates.html | ||
---|---|---|
1 |
{% extends "wcs/backoffice/base.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block appbar-title %}{% trans "Mail Templates" %}{% endblock %} |
|
5 | ||
6 |
{% block appbar-actions %} |
|
7 |
<a rel="popup" href="new">{% trans "New mail template" %}</a> |
|
8 |
{% endblock %} |
|
9 | ||
10 |
{% block content %} |
|
11 |
{% if mail_templates %} |
|
12 |
<ul class="objects-list single-links"> |
|
13 |
{% for mail_template in mail_templates %} |
|
14 |
<li><a href="{{ mail_template.id }}/">{{ mail_template.name }}</a></li> |
|
15 |
{% endfor %} |
|
16 |
</ul> |
|
17 |
{% else %} |
|
18 |
<div class="infonotice"> |
|
19 |
{% trans "There are no mail templates defined." %} |
|
20 |
</div> |
|
21 |
{% endif %} |
|
22 |
{% endblock %} |
wcs/workflows.py | ||
---|---|---|
46 | 46 |
from .fields import FileField |
47 | 47 |
from .formdef import FormDef |
48 | 48 |
from .formdata import Evolution |
49 |
from .mail_templates import MailTemplate |
|
49 | 50 | |
50 | 51 |
if not __name__.startswith('wcs.') and not __name__ == "__main__": |
51 | 52 |
raise ImportError('Import of workflows module must be absolute (import wcs.workflows)') |
... | ... | |
422 | 423 |
return self.backoffice_fields_formdef.fields or [] |
423 | 424 |
return [] |
424 | 425 | |
426 |
def get_all_items(self): |
|
427 |
for status in self.possible_status or []: |
|
428 |
for item in status.items or []: |
|
429 |
yield item |
|
430 |
for action in self.global_actions or []: |
|
431 |
for item in action.items or []: |
|
432 |
yield item |
|
433 | ||
425 | 434 |
def add_global_action(self, name, id=None): |
426 | 435 |
if [x for x in self.global_actions if x.name == name]: |
427 | 436 |
raise DuplicateGlobalActionNameError() |
... | ... | |
2445 | 2454 | |
2446 | 2455 |
to = [] |
2447 | 2456 |
subject = None |
2457 |
mail_template = None |
|
2448 | 2458 |
body = None |
2449 | 2459 |
custom_from = None |
2450 | 2460 |
attachments = None |
... | ... | |
2487 | 2497 |
return _('not completed') |
2488 | 2498 | |
2489 | 2499 |
def get_parameters(self): |
2490 |
return ('to', 'subject', 'body', 'attachments', 'custom_from', 'condition') |
|
2500 |
return ('to', 'mail_template', 'subject', 'body', 'attachments', 'custom_from', 'condition')
|
|
2491 | 2501 | |
2492 | 2502 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): |
2493 | 2503 |
super(SendmailWorkflowStatusItem, self).add_parameters_widgets( |
2494 | 2504 |
form, parameters, prefix=prefix, formdef=formdef) |
2505 |
subject_body_attrs = {} |
|
2506 |
if 'subject' in parameters or 'body' in parameters: |
|
2507 |
if get_publisher().has_site_option('mail-templates') and MailTemplate.count(): |
|
2508 |
subject_body_attrs = { |
|
2509 |
'data-dynamic-display-value': '', |
|
2510 |
'data-dynamic-display-child-of': '%smail_template' % prefix, |
|
2511 |
} |
|
2512 | ||
2495 | 2513 |
if 'to' in parameters: |
2496 | 2514 |
form.add(WidgetList, '%sto' % prefix, title=_('To'), |
2497 | 2515 |
element_type=SingleSelectWidgetWithOther, |
... | ... | |
2503 | 2521 |
if 'subject' in parameters: |
2504 | 2522 |
form.add(StringWidget, '%ssubject' % prefix, title=_('Subject'), |
2505 | 2523 |
validation_function=ComputedExpressionWidget.validate_template, |
2506 |
value=self.subject, size=40) |
|
2524 |
value=self.subject, size=40, |
|
2525 |
attrs=subject_body_attrs) |
|
2526 |
if 'mail_template' in parameters and get_publisher().has_site_option('mail-templates') and MailTemplate.count(): |
|
2527 |
form.add(SingleSelectWidget, |
|
2528 |
'%smail_template' % prefix, |
|
2529 |
title=_('Mail Template'), |
|
2530 |
value=self.mail_template, |
|
2531 |
options=[(None, '', '')] + MailTemplate.get_as_options_list(), |
|
2532 |
attrs={'data-dynamic-display-parent': 'true'} |
|
2533 |
) |
|
2507 | 2534 |
if 'body' in parameters: |
2508 | 2535 |
form.add(TextWidget, '%sbody' % prefix, title=_('Body'), |
2509 | 2536 |
value=self.body, cols=80, rows=10, |
2510 |
validation_function=ComputedExpressionWidget.validate_template) |
|
2537 |
validation_function=ComputedExpressionWidget.validate_template, |
|
2538 |
attrs=subject_body_attrs) |
|
2511 | 2539 | |
2512 | 2540 |
if 'custom_from' in parameters: |
2513 | 2541 |
form.add(ComputedExpressionWidget, '%scustom_from' % prefix, |
... | ... | |
2520 | 2548 |
def perform(self, formdata): |
2521 | 2549 |
if not self.to: |
2522 | 2550 |
return |
2523 |
if not self.subject: |
|
2524 |
return |
|
2525 |
if not self.body: |
|
2551 |
if not (self.subject and self.body) and not self.mail_template: |
|
2526 | 2552 |
return |
2527 | 2553 | |
2528 | 2554 |
url = formdata.get_url() |
2555 |
body = self.body |
|
2556 |
subject = self.subject |
|
2557 |
if self.mail_template: |
|
2558 |
mail_template = MailTemplate.get_by_slug(self.mail_template) |
|
2559 |
if mail_template: |
|
2560 |
body = mail_template.body |
|
2561 |
subject = mail_template.subject |
|
2562 | ||
2529 | 2563 |
try: |
2530 | 2564 |
mail_body = template_on_formdata(formdata, |
2531 |
self.compute(self.body, render=False),
|
|
2532 |
autoescape=self.body.startswith('<'))
|
|
2565 |
self.compute(body, render=False), |
|
2566 |
autoescape=body.startswith('<')) |
|
2533 | 2567 |
except TemplateError as e: |
2534 | 2568 |
get_logger().error('error in template for email body [%s], ' |
2535 | 2569 |
'mail could not be generated: %s' % (url, str(e))) |
... | ... | |
2537 | 2571 | |
2538 | 2572 |
try: |
2539 | 2573 |
mail_subject = template_on_formdata(formdata, |
2540 |
self.compute(self.subject, render=False),
|
|
2574 |
self.compute(subject, render=False), |
|
2541 | 2575 |
autoescape=False) |
2542 | 2576 |
except TemplateError as e: |
2543 | 2577 |
get_logger().error('error in template for email subject [%s], ' |
2544 |
- |