@@ -404,7 +411,58 @@ class Pod(Field):
# Deduce a nice name from p_mailing
res = gutils.produceNiceMessage(mailing)
return res
-
+
+ def getMailingInfo(self, obj, template, mailing):
+ '''Gets the necessary information for sending an email to
+ p_mailing list.'''
+ res = self.mailingInfo(obj, mailing)
+ subject = res.subject
+ if not subject:
+ # Give a predefined subject
+ mapping = {'site': obj.tool.o.getSiteUrl(),
+ 'title': obj.o.getShownValue('title'),
+ 'template': self.getTemplateName(obj, template)}
+ subject = obj.translate('podmail_subject', mapping=mapping)
+ body = res.body
+ if not body:
+ # Give a predefined body
+ mapping = {'site': obj.tool.o.getSiteUrl()}
+ body = obj.translate('podmail_body', mapping=mapping)
+ return res.logins, subject, body
+
+ def sendMailing(self, obj, template, mailing, attachment):
+ '''Sends the emails for m_mailing.'''
+ logins, subject, body = self.getMailingInfo(obj, template, mailing)
+ if not logins:
+ obj.log('mailing %s contains no recipient.' % mailing)
+ return 'action_ko'
+ tool = obj.tool
+ # Collect logins corresponding to inexistent users and recipients
+ missing = []
+ recipients = []
+ for login in logins:
+ user = tool.search1('User', noSecurity=True, login=login)
+ if not user:
+ missing.append(login)
+ continue
+ else:
+ recipient = user.getMailRecipient()
+ if not recipient:
+ missing.append(login)
+ else:
+ recipients.append(recipient)
+ if missing:
+ obj.log('mailing %s: inexistent user or no email for %s.' % \
+ (mailing, str(missing)))
+ if not recipients:
+ obj.log('mailing %s contains no recipient (after removing wrong ' \
+ 'entries, see above).' % mailing)
+ msg = 'action_ko'
+ else:
+ tool.sendMail(recipients, subject, body, [attachment])
+ msg = 'action_done'
+ return msg
+
def getValue(self, obj, template=None, format=None, result=None,
queryData=None, customContext=None, noSecurity=False):
'''For a pod field, getting its value means computing a pod document or
@@ -669,8 +727,17 @@ class Pod(Field):
obj.say(res)
return tool.goto(rq.get('HTTP_REFERER'))
# res contains a FileInfo instance.
- res.writeResponse(rq.RESPONSE)
- return
+ # Must we return the res to the ui or send a mail with the res as
+ # attachment?
+ mailing = rq.get('mailing')
+ if not mailing:
+ res.writeResponse(rq.RESPONSE)
+ return
+ else:
+ # Send the email(s).
+ msg = self.sendMailing(obj, template, mailing, res)
+ obj.say(obj.translate(msg))
+ return tool.goto(rq.get('HTTP_REFERER'))
# Performing any other action requires write access to p_obj.
obj.o.mayEdit(self.writePermission, raiseError=True)
msg = 'action_done'
diff --git a/gen/mail.py b/gen/mail.py
index ed75b10..d286dae 100644
--- a/gen/mail.py
+++ b/gen/mail.py
@@ -9,8 +9,15 @@ from appy.shared.utils import sequenceTypes
# ------------------------------------------------------------------------------
def sendMail(tool, to, subject, body, attachments=None):
- '''Sends a mail, via p_tool.mailHost, to p_to (a single email address or a
- list of email addresses).'''
+ '''Sends a mail, via p_tool.mailHost, to p_to (a single email recipient or
+ a list of recipients). Every (string) recipient can be an email address
+ or a string of the form "[name] <[email]>".
+
+ p_attachment must be a list or tuple whose elements can have 2 forms:
+ 1. a tuple (fileName, fileContent): "fileName" is the name of the file
+ as a string; "fileContent" is the file content, also as a string;
+ 2. a appy.fields.file.FileInfo instance.
+ '''
# Just log things if mail is disabled
fromAddress = tool.mailFrom
if not tool.mailEnabled or not tool.mailHost:
@@ -18,20 +25,20 @@ def sendMail(tool, to, subject, body, attachments=None):
msg = ' (no mailhost defined)'
else:
msg = ''
- tool.log('Mail disabled%s: should send mail from %s to %s.' % \
+ tool.log('mail disabled%s: should send mail from %s to %s.' % \
(msg, fromAddress, str(to)))
- tool.log('Subject: %s' % subject)
- tool.log('Body: %s' % body)
+ tool.log('subject: %s' % subject)
+ tool.log('body: %s' % body)
if attachments:
tool.log('%d attachment(s).' % len(attachments))
return
- tool.log('Sending mail from %s to %s (subject: %s).' % \
+ tool.log('sending mail from %s to %s (subject: %s).' % \
(fromAddress, str(to), subject))
# Create the base MIME message
body = MIMEText(body, 'plain', 'utf-8')
if attachments:
msg = MIMEMultipart()
- msg.attach( body )
+ msg.attach(body)
else:
msg = body
# Add the header values
@@ -48,23 +55,18 @@ def sendMail(tool, to, subject, body, attachments=None):
to = fromAddress
# Add attachments
if attachments:
- for fileName, fileContent in attachments:
- part = MIMEBase('application', 'octet-stream')
- if fileContent.__class__.__name__ == 'FileWrapper':
- fileContent = fileContent._zopeFile
- if hasattr(fileContent, 'data'):
- # It is a File instance coming from the database
- data = fileContent.data
- if isinstance(data, basestring):
- payLoad = data
- else:
- payLoad = ''
- while data is not None:
- payLoad += data.data
- data = data.next
+ for attachment in attachments:
+ # 2 possible forms for an attachment
+ if isinstance(attachment, tuple) or isinstance(attachment, list):
+ fileName, fileContent = attachment
else:
- payLoad = fileContent
- part.set_payload(payLoad)
+ # a FileInfo instance
+ fileName = attachment.uploadName
+ f = file(attachment.fsPath, 'rb')
+ fileContent = f.read()
+ f.close()
+ part = MIMEBase('application', 'octet-stream')
+ part.set_payload(fileContent)
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % fileName)
@@ -85,12 +87,12 @@ def sendMail(tool, to, subject, body, attachments=None):
res = smtpServer.sendmail(fromAddress, [to], msg.as_string())
smtpServer.quit()
if res:
- tool.log('Could not send mail to some recipients. %s' % str(res),
+ tool.log('could not send mail to some recipients. %s' % str(res),
type='warning')
except smtplib.SMTPException, e:
- tool.log('Mail sending failed: %s' % str(e), type='error')
+ tool.log('mail sending failed: %s' % str(e), type='error')
except socket.error, se:
- tool.log('Mail sending failed: %s' % str(se), type='error')
+ tool.log('mail sending failed: %s' % str(se), type='error')
# ------------------------------------------------------------------------------
def sendNotification(obj, transition, transitionName, workflow):
diff --git a/gen/tr/Appy.pot b/gen/tr/Appy.pot
index 08bc2f3..fb44412 100644
--- a/gen/tr/Appy.pot
+++ b/gen/tr/Appy.pot
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/tr/ar.po b/gen/tr/ar.po
index 9192172..dc24e50 100644
--- a/gen/tr/ar.po
+++ b/gen/tr/ar.po
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/tr/de.po b/gen/tr/de.po
index 07d443b..fac8bff 100644
--- a/gen/tr/de.po
+++ b/gen/tr/de.po
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/tr/en.po b/gen/tr/en.po
index 2d00439..7f0470f 100644
--- a/gen/tr/en.po
+++ b/gen/tr/en.po
@@ -723,3 +723,11 @@ msgstr "Microsoft Internet Explorer ${version} is not supported. Please upgrade
#. Default: "Send by email"
msgid "email_send"
msgstr "Send by email"
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr "${site} - ${title} - ${template}"
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
diff --git a/gen/tr/es.po b/gen/tr/es.po
index 19dfde3..e9f272f 100644
--- a/gen/tr/es.po
+++ b/gen/tr/es.po
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/tr/fr.po b/gen/tr/fr.po
index 304deb2..354226a 100644
--- a/gen/tr/fr.po
+++ b/gen/tr/fr.po
@@ -723,3 +723,11 @@ msgstr "Microsoft Internet Explorer ${version} n'est pas supporté. Veuillez met
#. Default: "Send by email"
msgid "email_send"
msgstr "Envoyer par email"
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr "${site} - ${title} - ${template}"
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr "Bonjour, cet email vous est envoyé depuis ${site}. Veuillez consulter le(s) fichier(s) joint(s)."
diff --git a/gen/tr/it.po b/gen/tr/it.po
index 43b74c9..adc9086 100644
--- a/gen/tr/it.po
+++ b/gen/tr/it.po
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/tr/nl.po b/gen/tr/nl.po
index f5c491f..4c04e9b 100644
--- a/gen/tr/nl.po
+++ b/gen/tr/nl.po
@@ -722,3 +722,11 @@ msgstr ""
#. Default: "Send by email"
msgid "email_send"
msgstr ""
+
+#. Default: "${site} - ${title} - ${template}"
+msgid "podmail_subject"
+msgstr ""
+
+#. Default: "Hello, this email that was sent to you via ${site}. Please consult the attached file(s)."
+msgid "podmail_body"
+msgstr ""
diff --git a/gen/ui/appy.js b/gen/ui/appy.js
index cdedcf8..43a6540 100644
--- a/gen/ui/appy.js
+++ b/gen/ui/appy.js
@@ -686,7 +686,7 @@ function toggleCookie(cookieId) {
// Function that allows to generate a document from a pod template.
function generatePod(uid, fieldName, template, podFormat, queryData,
- customParams, getChecked) {
+ customParams, getChecked, mailing) {
var f = document.getElementById('podForm');
f.objectUid.value = uid;
f.fieldName.value = fieldName;
@@ -695,6 +695,7 @@ function generatePod(uid, fieldName, template, podFormat, queryData,
f.queryData.value = queryData;
if (customParams) { f.customParams.value = customParams; }
else { f.customParams.value = ''; }
+ if (mailing) f.mailing.value = mailing;
f.action.value = 'generate';
f.checkedUids.value = '';
f.checkedSem.value = '';
diff --git a/gen/wrappers/ToolWrapper.py b/gen/wrappers/ToolWrapper.py
index 4df33b9..5ace912 100644
--- a/gen/wrappers/ToolWrapper.py
+++ b/gen/wrappers/ToolWrapper.py
@@ -146,6 +146,7 @@ class ToolWrapper(AbstractWrapper):
+
''')
diff --git a/gen/wrappers/UserWrapper.py b/gen/wrappers/UserWrapper.py
index 94b823e..9dce449 100644
--- a/gen/wrappers/UserWrapper.py
+++ b/gen/wrappers/UserWrapper.py
@@ -1,4 +1,5 @@
# ------------------------------------------------------------------------------
+from appy.fields.string import String
from appy.gen import WorkflowOwner
from appy.gen.layout import summaryPageLayouts
from appy.gen.wrappers import AbstractWrapper
@@ -107,6 +108,14 @@ class UserWrapper(AbstractWrapper):
from AccessControl.AuthEncoding import pw_validate
return pw_validate(encryptedPassword, clearPassword)
+ def getMailRecipient(self):
+ '''Returns, for this user, the "recipient string" (first name, name,
+ email) as can be used for sending an email.'''
+ res = self.email or self.login
+ # Ensure this is really an email
+ if not String.EMAIL.match(res): return
+ return '%s <%s>' % (self.title, res)
+
def setLogin(self, oldLogin, newLogin):
'''Changes the login of this user from p_oldLogin to p_newLogin.'''
self.login = newLogin