Commit 0c273c09 authored by Yoshinori Okuji's avatar Yoshinori Okuji

Initial import. This is the HEAD of the official repository + my patch

to address the problem that Cc: or Bcc: does not work. Since I don't see
any maintenance activity in them, I put a fork here. Once they fix
the problem officially, we can trash this fork.

FYI, here is my report:

https://secure.simplistix.co.uk/support/issue318


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@20876 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 849af0b1
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
import os
import rfc822
from AccessControl import ClassSecurityInfo
from DateTime import DateTime
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from Globals import InitializeClass, package_home
from MTMultipart import MTMultipart
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate, SUPPORTS_WEBDAV_LOCKS
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from ZPublisher import HTTPResponse
# Configured using zope.conf in Zope 2.7.8, Zope 2.8.2, and above
default_encoding = getattr(HTTPResponse,'default_encoding','iso-8859-15')
class BaseMailTemplate:
security = ClassSecurityInfo()
_properties = ()
ZScriptHTML_tryForm = None
content_type = 'text/plain'
mailhost = None
security.declarePrivate('_process')
def _process(self,kw):
# sort out what encoding we're going to use
encoding = kw.get('encoding',
self.getProperty('encoding',
default_encoding))
text = self.__class__.__bases__[1].__call__(self,**kw)
if not self.html():
text = text.encode(encoding,'replace')
# now turn the result into a MIMEText object
msg = MIMEText(
text.replace('\r',''),
self.content_type.split('/')[1],
encoding
)
# sort out what headers and addresses we're going to use
headers = {}
values = {}
# headers from the headers property
for header in getattr(self,'headers',()):
name,value = header.split(':',1)
headers[name]=value
# headers from the headers parameter
headers_param = kw.get('headers',{})
headers.update(headers_param)
# values and some specific headers
for key,header in (('mfrom','From'),
('mto','To'),
('mcc','Cc'),
('mbcc','Bcc'),
('subject','Subject')):
value = kw.get(key,
headers_param.get(header,
getattr(self,
key,
headers.get(header))))
if value is not None:
values[key]=value
# turn some sequences in coma-seperated strings
if isinstance(value,tuple) or isinstance(value,list):
value = ', '.join(value)
# make sure we have no unicode headers
if isinstance(value,unicode):
value = value.encode(encoding)
headers[header]=value
# check required values have been supplied
errors = []
for param in ('mfrom','mto','subject'):
if not values.get(param):
errors.append(param)
if errors:
raise TypeError(
'The following parameters were required by not specified: '+(
', '.join(errors)
))
# add date header
headers['Date']=DateTime().rfc822()
# turn headers into an ordered list for predictable header order
keys = headers.keys()
keys.sort()
return msg,values,[(key,headers[key]) for key in keys]
security.declarePrivate('_send')
def _send(self,mfrom,mto,msg):
mailhost = self.restrictedTraverse(self.mailhost,None)
if not getattr(mailhost,'meta_type',None) in (
'Mail Host','Maildrop Host'
):
raise RuntimeError(
'Could not traverse to MailHost %r' % self.mailhost
)
mailhost._send(mfrom,mto,msg.as_string())
security.declareProtected('View', 'send')
def send(self,**kw):
msg,values,headers = self._process(kw)
for header,value in headers:
msg[header]=value
to_addrs = ()
for key in ('mto', 'mcc', 'mbcc'):
v = values.get(key)
if v:
if isinstance(v, basestring):
v = [rfc822.dump_address_pair(addr) for addr \
in rfc822.AddressList(v)]
to_addrs += tuple(v)
self._send(values['mfrom'], to_addrs, msg)
security.declareProtected('View', '__call__')
__call__ = send
security.declareProtected('View', 'as_message')
def as_message(self,**kw):
msg,values,headers = self._process(kw)
multipart_kw = {}
subtype = kw.get('subtype')
if subtype:
multipart_kw['_subtype'] = subtype
boundary = kw.get('boundary')
if boundary:
multipart_kw['boundary'] = boundary
multipart = MTMultipart(self,
values['mfrom'],
values['mto'],
**multipart_kw)
# set the encoding for the container
multipart.set_charset(msg.get_charset())
for header,value in headers:
multipart[header]=value
multipart.attach(msg)
return multipart
InitializeClass(BaseMailTemplate)
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
from AccessControl import ClassSecurityInfo
from AccessControl import getSecurityManager
from Globals import InitializeClass
from Products.CMFCore.FSPageTemplate import FSPageTemplate,expandpath
from Products.CMFCore.DirectoryView import registerFileExtension
from Products.CMFCore.DirectoryView import registerMetaType
from BaseMailTemplate import BaseMailTemplate
from MailTemplate import MailTemplate
class FSMailTemplate(BaseMailTemplate,FSPageTemplate):
"Wrapper for Mail Template"
security = ClassSecurityInfo()
meta_type = 'Filesystem Mail Template'
def __init__(self, id, filepath, fullname=None, properties=None):
FSPageTemplate.__init__(self,id,filepath,fullname,properties)
self._properties = properties
security.declarePrivate('_createZODBClone')
def _createZODBClone(self):
"""Create a ZODB (editable) equivalent of this object."""
obj = MailTemplate(self.getId(), self._text, self.content_type)
obj.expand = 0
obj.write(self.read())
obj._setPropValue('mailhost',self.mailhost)
obj.content_type = self.content_type
if self._properties:
keys = self._properties.keys()
keys.sort()
for id in keys:
if id not in ('mailhost','content_type'):
obj.manage_addProperty(id,self._properties[id],'string')
return obj
security.declarePrivate('_readFile')
def _readFile(self, reparse):
fp = expandpath(self._filepath)
file = open(fp, 'r') # not 'rb', as this is a text file!
try:
data = file.read()
finally:
file.close()
if reparse:
self.write(data)
def _exec(self, bound_names, args, kw):
"""Call a FSPageTemplate"""
try:
response = self.REQUEST.RESPONSE
except AttributeError:
response = None
# Read file first to get a correct content_type default value.
self._updateFromFS()
if not kw.has_key('args'):
kw['args'] = args
bound_names['options'] = kw
security=getSecurityManager()
bound_names['user'] = security.getUser()
# Retrieve the value from the cache.
keyset = None
if self.ZCacheable_isCachingEnabled():
# Prepare a cache key.
keyset = {
# Why oh why?
# All this code is cut and paste
# here to make sure that we
# dont call _getContext and hence can't cache
# Annoying huh?
'here': self.aq_parent.getPhysicalPath(),
'bound_names': bound_names}
result = self.ZCacheable_get(keywords=keyset)
if result is not None:
# Got a cached value.
return result
# Execute the template in a new security context.
security.addContext(self)
try:
result = self.pt_render(extra_context=bound_names)
if keyset is not None:
# Store the result in the cache.
self.ZCacheable_set(result, keywords=keyset)
return result
finally:
security.removeContext(self)
return result
InitializeClass(FSMailTemplate)
registerFileExtension('mt', FSMailTemplate)
registerMetaType('Mail Template', FSMailTemplate)
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
from AccessControl import ClassSecurityInfo
from email import Encoders
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from Globals import InitializeClass
from zope.app.content_types import guess_content_type
from OFS.Image import File
from ZPublisher.HTTPRequest import FileUpload
def cookId(filename):
return filename[max(filename.rfind('/'),
filename.rfind('\\'),
filename.rfind(':'),
)+1:]
class MTMultipart(MIMEMultipart):
security = ClassSecurityInfo()
security.setDefaultAccess('allow')
def __init__(self,mt,mfrom,mto,_subtype='mixed',boundary=None):
MIMEMultipart.__init__(self,_subtype,boundary)
self.mfrom = mfrom
self.mto = mto
self.mt = mt
security.declarePublic('send')
def send(self):
"send ourselves using our MailTemplate's send method"
return self.mt._send(self.mfrom,self.mto,self)
security.declarePublic('add_file')
def add_file(self,theFile=None,data=None,filename=None,content_type=None):
"add a Zope file or Image to ourselves as an attachment"
if theFile and data:
raise TypeError(
'A file-like object was passed as well as data to create a file'
)
if (data or filename) and not (data and filename):
raise TypeError(
'Both data and filename must be specified'
)
if data:
if content_type is None:
content_type, enc=guess_content_type(filename, data)
elif isinstance(theFile,File):
filename = theFile.getId()
data = str(theFile.data)
content_type = content_type or theFile.content_type
elif isinstance(theFile,file):
filename = cookId(theFile.name)
data = theFile.read()
if content_type is None:
content_type,enc = guess_content_type(filename, data)
elif isinstance(theFile,FileUpload):
filename = cookId(theFile.filename)
data=theFile.read()
headers=theFile.headers
if content_type is None:
if headers.has_key('content-type'):
content_type=headers['content-type']
else:
content_type, enc=guess_content_type(filename, data)
else:
raise TypeError('Unknown object type found: %r' % theFile)
msg = MIMEBase(*content_type.split('/'))
msg.set_payload(data)
Encoders.encode_base64(msg)
msg.add_header('Content-Disposition', 'attachment',
filename=filename)
self.attach(msg)
InitializeClass(MTMultipart)
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
import os
from AccessControl import ClassSecurityInfo
from AccessControl import getSecurityManager
from Globals import InitializeClass, package_home
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate, SUPPORTS_WEBDAV_LOCKS
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from BaseMailTemplate import BaseMailTemplate
class MailTemplate(BaseMailTemplate,ZopePageTemplate):
"A ZPT-like template for sending mails"
security = ClassSecurityInfo()
meta_type = 'Mail Template'
_properties = ()
manage_options = ZopePageTemplate.manage_options[0:1] + \
ZopePageTemplate.manage_options[2:]
_default_content_fn = os.path.join(package_home(globals()),
'www', 'default.txt')
security.declareProtected('View management screens','pt_editForm')
pt_editForm = PageTemplateFile('www/mtEdit', globals(),
__name__='pt_editForm')
manage = manage_main = pt_editForm
security.declareProtected('Change Page Templates','pt_editAction')
def pt_editAction(self, REQUEST, mailhost, text, content_type, expand):
"""Change the mailhost and document."""
if SUPPORTS_WEBDAV_LOCKS and self.wl_isLocked():
raise ResourceLockedError, "File is locked via WebDAV"
self.expand=expand
self._setPropValue('mailhost',mailhost)
self.pt_edit(text, content_type)
REQUEST.set('text', self.read()) # May not equal 'text'!
message = "Saved changes."
if getattr(self, '_v_warnings', None):
message = ("<strong>Warning:</strong> <i>%s</i>"
% '<br>'.join(self._v_warnings))
return self.pt_editForm(manage_tabs_message=message)
def om_icons(self):
"""Return a list of icon URLs to be displayed by an ObjectManager"""
icons = ({'path': 'misc_/MailTemplates/mt.gif',
'alt': self.meta_type, 'title': self.meta_type},)
if not self._v_cooked:
self._cook()
if self._v_errors:
icons = icons + ({'path': 'misc_/PageTemplates/exclamation.gif',
'alt': 'Error',
'title': 'This template has an error'},)
return icons
def _exec(self, bound_names, args, kw):
"""Call a Page Template"""
if not kw.has_key('args'):
kw['args'] = args
bound_names['options'] = kw
security=getSecurityManager()
bound_names['user'] = security.getUser()
# Retrieve the value from the cache.
keyset = None
if self.ZCacheable_isCachingEnabled():
# Prepare a cache key.
keyset = {'here': self._getContext(),
'bound_names': bound_names}
result = self.ZCacheable_get(keywords=keyset)
if result is not None:
# Got a cached value.
return result
# Execute the template in a new security context.
security.addContext(self)
try:
result = self.pt_render(extra_context=bound_names)
if keyset is not None:
# Store the result in the cache.
self.ZCacheable_set(result, keywords=keyset)
return result
finally:
security.removeContext(self)
InitializeClass(MailTemplate)
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
from AccessControl import allow_module,allow_class
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from MailTemplate import MailTemplate
from types import ClassType
from urllib import quote
try:
import Products.CMFCore
except ImportError:
pass
else:
import FSMailTemplate
import Products.CMFCore.utils
Products.CMFCore.utils.registerIcon(FSMailTemplate.FSMailTemplate,
'www/fsmt.gif', globals())
def initialize( context ):
context.registerClass(
MailTemplate,
# we use the same permission as page templates
# in order to keep things simple.
permission='Add Page Templates',
constructors=(addMailTemplateForm,
addMailTemplate),
icon='www/mt.gif',
)
addMailTemplateForm = PageTemplateFile(
'www/mtAdd',
globals(),
__name__='addMailTemplateForm'
)
def addMailTemplate(self, id, mailhost=None, text=None,
REQUEST=None, submit=None):
"Add a Mail Template with optional file content."
id = str(id)
if REQUEST is None:
self._setObject(id, MailTemplate(id, text))
ob = getattr(self, id)
if mailhost:
ob._setPropValue('mailhost',mailhost)
return ob
else:
file = REQUEST.form.get('file')
headers = getattr(file, 'headers', None)
if headers is None or not file.filename:
mt = MailTemplate(id, text)
else:
mt = MailTemplate(id, file, headers.get('content_type'))
self._setObject(id, mt)
ob = getattr(self, id)
if mailhost:
ob._setPropValue('mailhost',mailhost)
if submit == " Add and Edit ":
u = ob.absolute_url()
else:
u = ob.aq_parent.absolute_url()
REQUEST.RESPONSE.redirect(u+'/manage_main')
# allow all the email module's public bits
import email
for name in email.__all__:
path = 'email.'+name
allow_module(path)
try:
mod = __import__(path)
except ImportError:
pass
else:
mod = getattr(mod,name)
for mod_name in dir(mod):
obj = getattr(mod,mod_name)
if isinstance(obj,ClassType):
allow_class(obj)
Copyright (c) 2005-2006 Simplistix Ltd
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This diff is collapsed.
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>Dear <tal:x replace="options/mto"/>,
<tal:x replace="user/getId"/> would like to thank you for
your interest in:
<tal:x replace="root/absolute_url"/>
<tal:x replace="options/message"/>
cheers,
The Web Team
</tal:body>
container.my_mt(
mfrom='webmaster@example.com',
mto='user@example.com',
subject='This is a test!',
message='This is a test!'
)
return 'Mail Sent!'
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Date:
From: webmaster@example.com
Subject: This is a test!
To: user@example.com
Dear user@example.com,
Test User would like to thank you for
your interest in:
http://foo
This is a test!
cheers,
The Web Team
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Date:
From: webmaster@example.com
Subject: Thankyou for your interest!
To: member@example.com
Dear Test Member,
Thankyou for you interest in our portal!
cheers,
The Web Team
This is the file attachment
\ No newline at end of file
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>Dear <tal:x replace="options/mto"/>,
Please find attached the file you requested.
cheers,
The Web Team
</tal:body>
msg = container.my_mt.as_message(
mfrom='from@example.com',
mto='to1@example.com',
subject='Your requested file',
boundary='111' # for testing only, so we get a consistent boundary
)
msg.add_file(container['myfile.bin'])
msg.send()
return 'Mail Sent!'
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="111"; charset="iso-8859-15"
Content-Transfer-Encoding: quoted-printable
Date:
From: from@example.com
Subject: Your requested file
To: to1@example.com
--111
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Dear to1@example.com,
=
Please find attached the file you requested.
=
cheers,
The Web Team
--111
Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="myfile.bin"
VGhpcyBpcyB0aGUgZmlsZSBhdHRhY2htZW50
--111--
\ No newline at end of file
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>Dear <tal:x replace="options/mto"/>,
Welcome to our site!
cheers,
The Web Team
</tal:body>
container.my_mt(
mto='user@example.com',
subject=container.my_mt.subject % container.absolute_url()
)
return 'Mail Sent!'
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Date:
From: webmaster@example.com
Subject: Welcome to http://foo
To: user@example.com
Dear user@example.com,
Welcome to our site!
cheers,
The Web Team
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>Dear <tal:x replace="options/member/getUserName"/>,
Thankyou for you interest in our portal!
cheers,
The Web Team
</tal:body>
[default]
mailhost=MailHost
mfrom=webmaster@example.com
subject=Thankyou for your interest!
for member in context.portal_membership.listMembers():
context.my_mt(
member=member,
mto=member.getProperty('email')
)
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>Test Body
</tal:body>
[default]
mailhost = MailHost
subject = Hello %s there
mfrom = from@example.com
charset = latin-1
content_type = text/notplain
Content-Type: text/notplain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
Test Body
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="111"; charset="iso-8859-15"
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
--111
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Test Body
--111
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="test.txt"
A Test Attachment
--111--
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="111"; charset="iso-8859-15"
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
--111
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Test Body
--111
Content-Type: text/plain
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.txt"
QSBUZXN0IEF0dGFjaG1lbnQ=
--111--
\ No newline at end of file
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
X-Mailer: MailTemplates
Test Body
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
X-Mailer: MailTemplates
X-Mailer2: MailTemplates
Test Body
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Bcc: bcc@example.com
Cc: cc@example.com
Date:
From: from@example.com
Subject: Hello out there
To: to@example.com, to2@example.com
Test Body
Content-Type: text/plain; charset="iso-8859-15"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Date:
From: from@example.com
Subject: Test Subject
To: to@example.com
Test Body
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Date:
From: from@example.com
Subject: Test Subject
To: to@example.com
VGVzdCDCo8KjwqMK
Content-Type: text/html; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Date:
From: from@example.com
Subject: Test Subject
To: to@example.com
VGVzdCDCo8KjwqMK
A Test Attachment
\ No newline at end of file
# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.
import os
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.User import system as SystemUser,SimpleUser
from cStringIO import StringIO
from OFS.Folder import Folder
from Products.MailHost.MailHost import MailHost
from test_MailTemplate import DummyMailHost,Zope,get_transaction
from Testing.makerequest import makerequest
from unittest import TestCase,TestSuite,makeSuite,main
try:
import Products.CMFCore
except ImportError:
# no CMF, no use ;-)
class TestFSMailTemplate(TestCase):
pass
else:
from Products.CMFCore.DirectoryView import addDirectoryViews
from Products.CMFCore.tests.base.testcase import FSDVTest
from Products.CMFCore.tests.base.dummy import DummyFolder
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
class DummyMember:
security = ClassSecurityInfo()
security.declareObjectPublic()
security.setDefaultAccess('allow')
security.declarePublic('getUserName')
def getUserName(self):
return 'Test Member'
security.declarePublic('getProperty')
def getProperty(self,name):
return 'member@example.com'
InitializeClass(DummyMember)
class DummyMembershipTool:
security = ClassSecurityInfo()
security.declareObjectPublic()
security.setDefaultAccess('allow')
security.declarePublic('listMembers')
def listMembers(self):
return (DummyMember(),)
InitializeClass(DummyMembershipTool)
class TestFSMailTemplate(FSDVTest):
_sourceprefix = os.path.dirname(__file__)
def setUp(self):
FSDVTest.setUp(self)
self.app = makerequest(Zope.app())
self._registerDirectory()
ob = self.ob = self.app
addDirectoryViews(ob, self._skinname, self.tempname)
self.r = self.app.REQUEST
self.r.other['URL1'] = 'http://foo/test_mt'
self._add= self.app.manage_addProduct['MailTemplates'].addMailTemplate
self.folder = Folder('folder')
if getattr(self.app,'test_mt',None):
self.app.manage_delObjects(ids=['test_mt'])
if getattr(self.app,'MailHost',None):
self.app.manage_delObjects(ids=['MailHost'])
self.MailHost = self.app.MailHost = DummyMailHost()
newSecurityManager( None, SystemUser )
def tearDown(self):
noSecurityManager()
get_transaction().abort()
self.app._p_jar.close()
try:
FSDVTest.tearDown(self)
except OSError:
# waggh, on windows, files in .svn get locked for some reason :-(
pass
def test_render(self):
self.MailHost.setExpected(mfrom='from@example.com',
mto=('to@example.com','to2@example.com'),
filename='mail_FSSendSimple.txt')
self.ob.fake_skin.test.send(subject=self.ob.fake_skin.test.subject % 'out',
mcc=('cc@example.com',),
mbcc=('bcc@example.com',),
headers={
'To':('to@example.com','to2@example.com'),
'Subject':'cheese',
})
self.MailHost.checkSent()
# check we're not setting a content type
self.failIf(self.r.RESPONSE.headers.get('content-type'),
self.r.RESPONSE.headers)
def test_properties(self):
self.assertEqual(self.ob.fake_skin.test.mailhost,'MailHost')
self.assertEqual(self.ob.fake_skin.test.subject,'Hello %s there')
self.assertEqual(self.ob.fake_skin.test.mfrom,'from@example.com')
def test_zodbclone(self):
from Products.MailTemplates.MailTemplate import MailTemplate
clone = self.ob.fake_skin.test._createZODBClone()
self.failUnless(isinstance(clone,MailTemplate),'Clone not a MailTemplate!')
self.assertEqual(self.ob.fake_skin.test.read(),clone.read())
self.assertEqual(clone.getProperty('mailhost'),None)
self.assertEqual(clone.mailhost,'MailHost')
self.assertEqual(clone.getProperty('subject'),'Hello %s there')
self.assertEqual(clone.getProperty('mfrom'),'from@example.com')
self.assertEqual(clone.content_type,'text/notplain')
def test_view_manage_workspace(self):
from zExceptions import Redirect
try:
self.assertRaises(self.ob.fake_skin.test.manage_workspace(self.r))
except Redirect,r:
# this may appear to be incorrect, but http://foo/test_mt
# is what we set as REQUEST['URL1']
self.assertEqual(r.args,('http://foo/test_mt/manage_main',))
self.ob.fake_skin.test.manage_main()
# ugh, okay, so we can't really test for security, but lets
# test for the missing docstring that was causing problems!
self.failUnless(self.ob.fake_skin.test.__doc__)
def test_example2(self):
# login
noSecurityManager()
self.app.aq_chain[-1].id = 'testing'
newSecurityManager(
None,
SimpleUser('Test User','',('Manager',),[]).__of__(self.app)
)
try:
# setup
self.app.portal_membership = DummyMembershipTool()
# set expected
self.MailHost.setExpected(mfrom='webmaster@example.com',
mto='member@example.com',
filename='example2.txt')
# test
self.ob.fake_skin.send_mails()
finally:
# logout
noSecurityManager()
newSecurityManager( None, SystemUser )
def test_suite():
return TestSuite((
makeSuite(TestFSMailTemplate),
))
if __name__ == '__main__':
main(defaultTest='test_suite')
This diff is collapsed.
Mail Templates SVN TRUNK
<tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
>
</tal:body>
\ No newline at end of file
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Mail Template"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
Mail Templates allow you to use TALES, METAL and other ZPT functionality
to generate and send emails.
</p>
<form action="addMailTemplate" method="post"
enctype="multipart/form-data">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
MailHost
</div>
</td>
<td align="left" valign="top">
<select name="mailhost">
<option tal:repeat="mh python:here.superValues(('Mail Host','Maildrop Host'))"
tal:content="mh/title_and_id"
tal:attributes="value mh/getId"/>
</select>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
File
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
<input class="form-element" type="submit" name="submit"
value=" Add and Edit " />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
tal:replace="structure here/manage_tabs">Tabs</h2>
<tal:block define="global body request/other/text | request/form/text
| here/read" />
<form action="" method="post" tal:attributes="action request/URL1">
<input type="hidden" name=":default_method" value="pt_changePrefs">
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="middle">
<div class="form-optional">
MailHost
</div>
</td>
<td align="left" valign="middle">
<select name="mailhost"
tal:define="mh_meta_types python:('Mail Host','Maildrop Host')">
<option tal:define="mh python:here.restrictedTraverse(here.mailhost,None)"
tal:condition="python:getattr(mh,'meta_type',None) not in mh_meta_types"
tal:attributes="value here/mailhost"
tal:content="string:'${here/mailhost}' is no longer valid!"
selected="selected"/>
<option tal:repeat="mh python:here.superValues(mh_meta_types)"
tal:content="mh/title_and_id"
tal:attributes="value mh/getId;
selected python:here.mailhost==mh.getId()"/>
</select>
</td>
<td align="left" valign="middle">
<div class="form-optional">
Content-Type
</div>
</td>
<td align="left" valign="middle">
<input type="text" name="content_type" size="14"
tal:attributes="value request/content_type | here/content_type" />
</td>
</tr>
<tr>
<td align="left" valign="middle">
<div class="form-label">
Last Modified
</div>
</td>
<td align="left" valign="middle">
<div class="form-text"
tal:content="python:here.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
</div>
</td>
<td align="left" valign="top" colspan=2>
<a href="source.html" tal:condition="here/html">Browse HTML source</a>
<a href="source.xml" tal:condition="not:here/html">Browse XML source</a>
<br>
<input type="hidden" name="expand:int:default" value="0">
<input type="checkbox" value="1" name="expand:int"
tal:attributes="checked request/expand | here/expand">
Expand macros when editing
</td>
</tr>
<tr tal:define="errors here/pt_errors" tal:condition="errors">
<tal:block define="global body python:here.document_src({'raw':1})"/>
<td align="left" valign="middle" class="form-label">Errors</td>
<td align="left" valign="middle" style="background-color: #FFDDDD"
colspan="3">
<pre tal:content="python:modules['string'].join(errors, '\n')">errors</pre>
</td>
</tr>
<tr tal:define="warnings here/pt_warnings" tal:condition="warnings">
<td align="left" valign="middle" class="form-label">Warnings</td>
<td align="left" valign="middle" style="background-color: #FFEEDD"
colspan="3">
<pre tal:content="python:modules['string'].join(warnings, '\n')">errors</pre>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4"
tal:define="width request/dtpref_cols | string:100%;
relative_width python:str(width).endswith('%')">
<textarea name="text:text" wrap="off" style="width: 100%;" rows="20"
tal:condition="relative_width"
tal:attributes="style string:width: $width;;;
rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
<textarea name="text:text" wrap="off" rows="20" cols="50"
tal:condition="not:relative_width"
tal:attributes="cols width; rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4">
<div class="form-element">
<em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:here/wl_isLocked"
class="form-element" type="submit"
name="pt_editAction:method" value="Save Changes">
&nbsp;&nbsp;
<input class="form-element" type="submit" name="height" value="Taller">
<input class="form-element" type="submit" name="height" value="Shorter">
<input class="form-element" type="submit" name="width" value="Wider">
<input class="form-element" type="submit" name="width" value="Narrower">
</div>
</td>
</tr>
</table>
</form>
<p class="form-help">
You can upload the text for <span tal:replace="here/title_and_id" />
using the following form.
Choose an existing HTML or XML file from your local computer by clicking
<em>browse</em>. You can also <a href="document_src">click here</a>
to view or download the current text.
</p>
<form action="pt_upload" method="post"
enctype="multipart/form-data">
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
File &nbsp;
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="">
</td>
</tr>
<tr>
<td></td>
<td align="left" valign="top">
<div class="form-element">
<em tal:condition="here/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:here/wl_isLocked"
class="form-element" type="submit" value="Upload File">
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment