[Zope-CVS] SVN: messageboard/trunk/step07/ Updated Event chapter.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Fri May 21 13:52:11 EDT 2004
Log message for revision 24856:
Updated Event chapter.
-=-
Added: messageboard/trunk/step07/__init__.py
===================================================================
--- messageboard/trunk/step07/__init__.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/__init__.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1 @@
+# Make it a Python package
Added: messageboard/trunk/step07/browser/__init__.py
===================================================================
--- messageboard/trunk/step07/browser/__init__.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/__init__.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1 @@
+# Make it a Python package
Added: messageboard/trunk/step07/browser/configure.zcml
===================================================================
--- messageboard/trunk/step07/browser/configure.zcml 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/configure.zcml 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,139 @@
+<configure
+ xmlns="http://namespaces.zope.org/browser"
+ xmlns:zope="http://namespaces.zope.org/zope">
+
+ <addform
+ label="Add Message Board"
+ name="AddMessageBoard.html"
+ schema="book.messageboard.interfaces.IMessageBoard"
+ content_factory="book.messageboard.messageboard.MessageBoard"
+ fields="description"
+ permission="zope.ManageContent"
+ />
+
+ <addMenuItem
+ class="book.messageboard.messageboard.MessageBoard"
+ title="Message Board"
+ description="A Message Board"
+ permission="zope.ManageContent"
+ view="AddMessageBoard.html"
+ />
+
+ <editform
+ schema="book.messageboard.interfaces.IMessageBoard"
+ for="book.messageboard.interfaces.IMessageBoard"
+ label="Change Message Board"
+ name="edit.html"
+ permission="zope.ManageContent"
+ menu="zmi_views" title="Edit"
+ />
+
+ <containerViews
+ for="book.messageboard.interfaces.IMessageBoard"
+ index="book.messageboard.View"
+ contents="book.messageboard.Edit"
+ add="book.messageboard.Add"
+ />
+
+ <page
+ name="thread.html"
+ for="book.messageboard.interfaces.IMessageBoard"
+ class=".thread.Thread"
+ template="thread.pt"
+ permission="book.messageboard.View"
+ menu="zmi_views" title="Thread"/>
+
+ <defaultView
+ for="book.messageboard.interfaces.IMessageBoard"
+ name="thread.html"/>
+
+ <icon
+ name="zmi_icon"
+ for="book.messageboard.interfaces.IMessageBoard"
+ file="messageboard.png" />
+
+ <addform
+ label="Add Message"
+ name="AddMessage.html"
+ schema="book.messageboard.interfaces.IMessage"
+ content_factory="book.messageboard.message.Message"
+ fields="title body"
+ permission="book.messageboard.Add"
+ />
+
+ <addMenuItem
+ class="book.messageboard.message.Message"
+ title="Message"
+ description="A Message"
+ permission="book.messageboard.Add"
+ view="AddMessage.html"
+ />
+
+ <editform
+ schema="book.messageboard.interfaces.IMessage"
+ for="book.messageboard.interfaces.IMessage"
+ label="Change Message"
+ fields="title body"
+ name="edit.html"
+ permission="book.messageboard.Edit"
+ menu="zmi_views" title="Edit"
+ />
+
+ <containerViews
+ for="book.messageboard.interfaces.IMessage"
+ index="book.messageboard.View"
+ contents="book.messageboard.Edit"
+ add="book.messageboard.Add"
+ />
+
+ <page
+ name="details.html"
+ for="book.messageboard.interfaces.IMessage"
+ class=".message.MessageDetails"
+ template="details.pt"
+ permission="book.messageboard.View"
+ menu="zmi_views" title="Preview"/>
+
+ <defaultView
+ for="book.messageboard.interfaces.IMessage"
+ name="details.html"/>
+
+ <page
+ name="thread.html"
+ for="book.messageboard.interfaces.IMessage"
+ class=".thread.Thread"
+ template="thread.pt"
+ permission="book.messageboard.View"
+ menu="zmi_views" title="Thread"/>
+
+ <icon
+ name="zmi_icon"
+ for="book.messageboard.interfaces.IMessage"
+ file="message.png" />
+
+
+ <zope:view
+ type="zope.publisher.interfaces.browser.IBrowserRequest"
+ for="book.messageboard.interfaces.IHTML"
+ provides="zope.app.form.interfaces.IInputWidget"
+ factory=".widgets.HTMLSourceWidget"
+ permission="zope.Public"
+ />
+
+ <pages
+ for="book.messageboard.interfaces.IMessage"
+ class=".message.MailSubscriptions"
+ permission="book.messageboard.Edit"
+ >
+ <page
+ name="subscriptions.html"
+ template="subscriptions.pt"
+ menu="zmi_views" title="Subscriptions"
+ />
+ <page
+ name="changeSubscriptions.html"
+ attribute="change"
+ />
+ </pages>
+
+</configure>
Added: messageboard/trunk/step07/browser/details.pt
===================================================================
--- messageboard/trunk/step07/browser/details.pt 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/details.pt 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,38 @@
+<html metal:use-macro="views/standard_macros/page">
+ <body>
+ <div metal:fill-slot="body" i18n:domain="messageboard">
+
+ <h1 i18n:translate="">Message Details</h1>
+
+ <div class="row">
+ <div class="label" i18n:translate="">Title</div>
+ <div class="field" tal:content="context/title" />
+ </div>
+
+ <div class="row">
+ <div class="label" i18n:translate="">Author</div>
+ <div class="field" tal:content="view/author"/>
+ </div>
+
+ <div class="row">
+ <div class="label" i18n:translate="">Date/Time</div>
+ <div class="field" tal:content="view/modified"/>
+ </div>
+
+ <div class="row">
+ <div class="label" i18n:translate="">Parent</div>
+ <div class="field" tal:define="info view/parent_info">
+ <a href="../"
+ tal:condition="info"
+ tal:content="info/title" />
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="label" i18n:translate="">Body</div>
+ <div class="field" tal:content="structure context/body"/>
+ </div>
+
+ </div>
+ </body>
+</html>
Added: messageboard/trunk/step07/browser/ftests/__init__.py
===================================================================
--- messageboard/trunk/step07/browser/ftests/__init__.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/ftests/__init__.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1 @@
+# Make it a Python package
Added: messageboard/trunk/step07/browser/ftests/test_message.py
===================================================================
--- messageboard/trunk/step07/browser/ftests/test_message.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/ftests/test_message.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Functional Tests
+
+$Id$
+"""
+import unittest
+from zope.app.tests.functional import BrowserTestCase
+
+class MessageTest(BrowserTestCase):
+
+ def testAddMessage(self):
+ response = self.publish(
+ '/+/AddMessageBoard.html=board',
+ basic='mgr:mgrpw',
+ form={'field.description': u'Message Board',
+ 'UPDATE_SUBMIT': 'Add'})
+ self.assertEqual(response.getStatus(), 302)
+ self.assertEqual(response.getHeader('Location'),
+ 'http://localhost/@@contents.html')
+ response = self.publish(
+ '/board/+/AddMessage.html=msg1',
+ basic='mgr:mgrpw',
+ form={'field.title': u'Message 1',
+ 'field.body': u'Body',
+ 'UPDATE_SUBMIT': 'Add'})
+ self.assertEqual(response.getStatus(), 302)
+ self.assertEqual(response.getHeader('Location'),
+ 'http://localhost/board/@@contents.html')
+
+ def testMessageDetails(self):
+ self.testAddMessage()
+ response = self.publish('/board/msg1/@@details.html',
+ basic='mgr:mgrpw')
+ body = response.getBody()
+ self.checkForBrokenLinks(body, '/board/msg1/@@details.html',
+ basic='mgr:mgrpw')
+
+ self.assert_(body.find('Message Details') > 0)
+ self.assert_(body.find('Message 1') > 0)
+ self.assert_(body.find('Body') > 0)
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(MessageTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: messageboard/trunk/step07/browser/message.png
===================================================================
(Binary files differ)
Property changes on: messageboard/trunk/step07/browser/message.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: messageboard/trunk/step07/browser/message.py
===================================================================
--- messageboard/trunk/step07/browser/message.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/message.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Browser Views for IMessage
+
+$Id: message.py,v 1.3 2003/12/13 17:24:36 srichter Exp $
+"""
+from zope.i18n import MessageIDFactory
+
+from zope.app import zapi
+from zope.app.dublincore.interfaces import ICMFDublinCore
+
+from book.messageboard.interfaces import IMessage
+from book.messageboard.interfaces import IMailSubscriptions
+
+_ = MessageIDFactory('messageboard')
+
+class MessageDetails:
+
+ def author(self):
+ """Get user who last modified the Message."""
+ creators = ICMFDublinCore(self.context).creators
+ if not creators:
+ return _('unknown')
+ return creators[0]
+
+ def modified(self):
+ """Get last modification date."""
+ date = ICMFDublinCore(self.context).modified
+ if date is None:
+ date = ICMFDublinCore(self.context).created
+ if date is None:
+ return ''
+ formatter = self.request.locale.dates.getFormatter('dateTime', 'short')
+ return formatter.format(date)
+
+ def parent_info(self):
+ """Get the parent of the message"""
+ parent = zapi.getParent(self.context)
+ if not IMessage.providedBy(parent):
+ return None
+ return {'name': zapi.name(parent), 'title': parent.title}
+
+
+class MailSubscriptions:
+
+ def subscriptions(self):
+ return IMailSubscriptions(self.context).getSubscriptions()
+
+ def change(self):
+ if 'ADD' in self.request:
+ emails = self.request['emails'].split('\n')
+ IMailSubscriptions(self.context).addSubscriptions(emails)
+ elif 'REMOVE' in self.request:
+ emails = self.request['remails']
+ if isinstance(emails, (str, unicode)):
+ emails = [emails]
+ IMailSubscriptions(self.context).removeSubscriptions(emails)
+
+ self.request.response.redirect('./@@subscriptions.html')
Added: messageboard/trunk/step07/browser/messageboard.png
===================================================================
(Binary files differ)
Property changes on: messageboard/trunk/step07/browser/messageboard.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: messageboard/trunk/step07/browser/subscriptions.pt
===================================================================
--- messageboard/trunk/step07/browser/subscriptions.pt 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/subscriptions.pt 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,43 @@
+<html metal:use-macro="views/standard_macros/view">
+ <body>
+ <div metal:fill-slot="body" i18n:domain="messageboard">
+
+ <form action="changeSubscriptions.html" method="post">
+
+ <div class="row">
+ <div class="label"
+ i18n:translate="">Current Subscriptions</div>
+ <div class="field">
+ <div tal:repeat="email view/subscriptions">
+ <input type="checkbox" name="remails:list"
+ value="" tal:attributes="value email">
+ <div tal:replace="email">zope3 at zope3.org</div>
+ </div>
+ <input type="submit" name="REMOVE" value="Remove"
+ i18n:attributes="value remove-button">
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="label" i18n:translate="">
+ Enter new Users (separate by 'Return')
+ </div>
+ <div class="field">
+ <textarea name="emails" cols="40" rows="10"></textarea>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="controls">
+ <input type="submit" value="Refresh"
+ i18n:attributes="value refresh-button" />
+ <input type="submit" name="ADD" value="Add"
+ i18n:attributes="value add-button" />
+ </div>
+ </div>
+
+ </form>
+
+ </div>
+ </body>
+</html>
Added: messageboard/trunk/step07/browser/subthread.pt
===================================================================
--- messageboard/trunk/step07/browser/subthread.pt 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/subthread.pt 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,8 @@
+<ul>
+ <li tal:repeat="item view/listContentInfo">
+ <a href=""
+ tal:attributes="href item/url"
+ tal:content="item/title">Message 1</a>
+ <div tal:replace="structure item/thread"/>
+ </li>
+</ul>
\ No newline at end of file
Added: messageboard/trunk/step07/browser/tests/__init__.py
===================================================================
--- messageboard/trunk/step07/browser/tests/__init__.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/tests/__init__.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1 @@
+# Make it a Python package
Added: messageboard/trunk/step07/browser/tests/test_widgets.py
===================================================================
--- messageboard/trunk/step07/browser/tests/test_widgets.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/tests/test_widgets.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""HTMLSourceWidget Tests
+
+$Id: test_widgets.py,v 1.1 2003/06/10 14:40:44 srichter Exp $
+"""
+import unittest
+from zope.app.form.browser.tests.test_textareawidget import TextAreaWidgetTest
+from book.messageboard.browser.widgets import HTMLSourceWidget
+from book.messageboard.fields import HTML
+
+class HTMLSourceWidgetTest(TextAreaWidgetTest):
+
+ _FieldFactory = HTML
+ _WidgetFactory = HTMLSourceWidget
+
+
+ def test_AllowedTagsConvert(self):
+ widget = self._widget
+ widget.context.allowed_tags=('h1','pre')
+ self.assertEqual(u'<h1>Blah</h1>',
+ widget._toFieldValue(u'<h1>Blah</h1>'))
+ self.assertEqual(u'<pre>Blah</pre>',
+ widget._toFieldValue(u'<pre>Blah</pre>') )
+ self.assertEqual(u'<h1><pre>Blah</pre></h1>',
+ widget._toFieldValue(u'<h1><pre>Blah</pre></h1>'))
+ self.assertEqual(u'<h1 attr=".">Blah</h1>',
+ widget._toFieldValue(u'<h1 attr=".">Blah</h1>'))
+
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<h2>Blah</h2>'))
+ self.assertEqual(u'<pre>Blah</pre>',
+ widget._toFieldValue(u'<h2><pre>Blah</pre></h2>'))
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<h2 a="b">Blah</h2>'))
+
+
+ def test_ForbiddenTagsConvert(self):
+ widget = self._widget
+ widget.context.forbidden_tags=('h2','pre')
+
+ self.assertEqual(u'<h1>Blah</h1>',
+ widget._toFieldValue(u'<h1>Blah</h1>'))
+ self.assertEqual(u'<h1 a="b">Blah</h1>',
+ widget._toFieldValue(u'<h1 a="b">Blah</h1>'))
+
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<h2>Blah</h2>'))
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<pre>Blah</pre>'))
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<h2><pre>Blah</pre></h2>'))
+ self.assertEqual(u'Blah',
+ widget._toFieldValue(u'<h2><pre>Blah</pre></h2>'))
+ self.assertEqual(u'<h1>Blah</h1>',
+ widget._toFieldValue(u'<h1><pre>Blah</pre></h1>'))
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(HTMLSourceWidgetTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: messageboard/trunk/step07/browser/thread.pt
===================================================================
--- messageboard/trunk/step07/browser/thread.pt 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/thread.pt 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,11 @@
+<html metal:use-macro="views/standard_macros/view">
+ <body>
+ <div metal:fill-slot="body" i18n:domain="messageboard">
+
+ <h1 i18n:translate="">Discussion Thread</h1>
+
+ <div tal:replace="structure view/subthread" />
+
+ </div>
+ </body>
+</html>
Added: messageboard/trunk/step07/browser/thread.py
===================================================================
--- messageboard/trunk/step07/browser/thread.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/thread.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,42 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Browser View for the sub-thread of a Message or MessageBoard
+
+$Id$
+"""
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from book.messageboard.interfaces import IMessage
+
+class Thread:
+
+ def __init__(self, context, request, base_url=''):
+ self.context = context
+ self.request = request
+ self.base_url = base_url
+
+ def listContentInfo(self):
+ children = []
+ for name, child in self.context.items():
+ if IMessage.providedBy(child):
+ info = {}
+ info['title'] = child.title
+ url = self.base_url + name + '/'
+ info['url'] = url + '@@thread.html'
+ thread = Thread(child, self.request, url)
+ info['thread'] = thread.subthread()
+ children.append(info)
+ return children
+
+ subthread = ViewPageTemplateFile('subthread.pt')
+
Added: messageboard/trunk/step07/browser/widgets.py
===================================================================
--- messageboard/trunk/step07/browser/widgets.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/browser/widgets.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Module containing custom widget definitions.
+
+$Id: widgets.py,v 1.1 2003/06/10 14:40:44 srichter Exp $
+"""
+import re
+from zope.app.form.browser import TextAreaWidget
+from book.messageboard.fields import forbidden_regex, allowed_regex
+
+class HTMLSourceWidget(TextAreaWidget):
+
+ def _toFieldValue(self, input):
+ input = super(HTMLSourceWidget, self)._toFieldValue(input)
+
+ if self.context.forbidden_tags:
+ regex = forbidden_regex %'|'.join(
+ self.context.forbidden_tags)
+ input = re.sub(regex, '', input)
+
+ if self.context.allowed_tags:
+ regex = allowed_regex %'|'.join(
+ self.context.allowed_tags)
+ input = re.sub(regex, '', input)
+
+ return input
+
Added: messageboard/trunk/step07/configure.zcml
===================================================================
--- messageboard/trunk/step07/configure.zcml 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/configure.zcml 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,108 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ xmlns:event="http://namespaces.zope.org/event"
+ xmlns:mail="http://namespaces.zope.org/mail"
+ i18n_domain="messageboard">
+
+ <permission
+ id="book.messageboard.View"
+ title="View Message Board and Messages"
+ description="View the Message Board and all its content."
+ />
+ <permission
+ id="book.messageboard.Add"
+ title="Add Message"
+ description="Add Message."
+ />
+ <permission
+ id="book.messageboard.Edit"
+ title="Edit Messages"
+ description="Edit Messages."
+ />
+ <permission
+ id="book.messageboard.Delete"
+ title="Delete Message"
+ description="Delete Message."
+ />
+
+ <interface
+ interface=".interfaces.IMessageBoard"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <content class=".messageboard.MessageBoard">
+ <implements
+ interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <implements
+ interface="zope.app.container.interfaces.IContentContainer"
+ />
+ <factory
+ id="book.messageboard.MessageBoard"
+ description="Message Board"
+ />
+ <require
+ permission="book.messageboard.View"
+ interface=".interfaces.IMessageBoard"
+ />
+ <require
+ permission="book.messageboard.Edit"
+ set_schema=".interfaces.IMessageBoard"
+ />
+ </content>
+
+ <interface
+ interface=".interfaces.IMessage"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <content class=".message.Message">
+ <implements
+ interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <implements
+ interface="zope.app.container.interfaces.IContentContainer"
+ />
+ <require
+ permission="book.messageboard.View"
+ interface=".interfaces.IMessage"
+ />
+ <require
+ permission="book.messageboard.Add"
+ set_schema=".interfaces.IMessage"
+ />
+ </content>
+
+ <adapter
+ factory=".message.MessageSized"
+ provides="zope.app.size.interfaces.ISized"
+ for=".interfaces.IMessage"
+ />
+
+ <adapter
+ factory=".message.MailSubscriptions"
+ provides=".interfaces.IMailSubscriptions"
+ for=".interfaces.IMessage" />
+
+ <mail:smtpMailer name="msgboard-smtp" hostname="localhost" port="25" />
+
+ <mail:queuedDelivery
+ name="msgboard-delivery"
+ permission="zope.SendMail"
+ queuePath="./mail-queue"
+ mailer="msgboard-smtp" />
+
+ <event:subscribe
+ subscriber=".message.mailer"
+ event_types="zope.app.event.interfaces.IObjectModifiedEvent
+ zope.app.container.interfaces.IObjectAddedEvent
+ zope.app.container.interfaces.IObjectRemovedEvent" />
+
+
+ <i18n:registerTranslations directory="locales" />
+
+ <include package=".browser" />
+ <include file="security.zcml" />
+
+</configure>
Added: messageboard/trunk/step07/fields.py
===================================================================
--- messageboard/trunk/step07/fields.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/fields.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,56 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Module containing custom field definitions.
+
+$Id$
+"""
+import re
+
+from zope.i18n import MessageIDFactory
+from zope.schema import Text
+from zope.schema.interfaces import ValidationError
+
+_ = MessageIDFactory('messageboard')
+
+forbidden_regex = r'</?(?:%s).*?/?>'
+allowed_regex = r'</??(?!%s)[a-zA-Z0-9]*? ?(?:[a-z0-9]*?=?".*?")*/??>'
+
+class ForbiddenTags(ValidationError):
+ __doc__ = _("Forbidden HTML Tags used.")
+
+
+class HTML(Text):
+
+ allowed_tags = ()
+ forbidden_tags = ()
+
+ def __init__(self, allowed_tags=(), forbidden_tags=(), **kw):
+ self.allowed_tags = allowed_tags
+ self.forbidden_tags = forbidden_tags
+ super(HTML, self).__init__(**kw)
+
+ def _validate(self, value):
+ super(HTML, self)._validate(value)
+
+ if self.forbidden_tags:
+ regex = forbidden_regex %'|'.join(self.forbidden_tags)
+ if re.findall(regex, value):
+ raise ForbiddenTags(value, self.forbidden_tags)
+
+ if self.allowed_tags:
+ regex = allowed_regex %'|'.join(self.allowed_tags)
+ if re.findall(regex, value):
+ raise ForbiddenTags(value, self.allowed_tags)
+
+
Added: messageboard/trunk/step07/interfaces.py
===================================================================
--- messageboard/trunk/step07/interfaces.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/interfaces.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,112 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Board Interfaces
+
+Interfaces for the Zope 3 based Message Board Package
+
+$Id$
+"""
+from zope.i18n import MessageIDFactory
+from zope.interface import classImplements, Interface
+from zope.schema import Text, TextLine, Field, Tuple
+from zope.schema.interfaces import IText
+
+from zope.app.container.constraints import ContainerTypesConstraint
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.container.interfaces import IContainer
+from zope.app.file.interfaces import IFile
+
+from fields import HTML
+
+_ = MessageIDFactory('messageboard')
+
+
+class IMessage(IContainer):
+ """A message object. It can contain its own responses."""
+
+ def __setitem__(name, object):
+ """Add a IMessage object."""
+
+ title = TextLine(
+ title=_("Title/Subject"),
+ description=_("Title and/or subject of the message."),
+ default=u"",
+ required=True)
+
+ body = HTML(
+ title=_("Message Body"),
+ description=_("This is the actual message. Type whatever!"),
+ default=u"",
+ allowed_tags=('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img', 'a',
+ 'br', 'b', 'i', 'u', 'em', 'sub', 'sup',
+ 'table', 'tr', 'td', 'th', 'code', 'pre',
+ 'center', 'div', 'span', 'p', 'font', 'ol',
+ 'ul', 'li', 'q', 's', 'strong'),
+ required=False)
+
+
+class IMessageBoard(IContainer):
+ """The message board is the base object for our package. It can only
+ contain IMessage objects."""
+
+ def __setitem__(name, object):
+ """Add a IMessage object."""
+
+ __setitem__.precondition = ItemTypePrecondition(IMessage)
+
+ description = Text(
+ title=_("Description"),
+ description=_("A detailed description of the content of the board."),
+ default=u"",
+ required=False)
+
+
+IMessage['__setitem__'].setTaggedValue('precondition',
+ ItemTypePrecondition(IMessage, IFile))
+IMessage.setTaggedValue('__parent__', Field(
+ constraint=ContainerTypesConstraint(IMessageBoard, IMessage)))
+
+
+class IHTML(IText):
+ """A text field that handles HTML input."""
+
+ allowed_tags = Tuple(
+ title=_("Allowed HTML Tags"),
+ description=_("""\
+ Only listed tags can be used in the value of the field.
+ """),
+ required=False)
+
+ forbidden_tags = Tuple(
+ title=_("Forbidden HTML Tags"),
+ description=_("""\
+ Listed tags cannot be used in the value of the field.
+ """),
+ required=False)
+
+classImplements(HTML, IHTML)
+
+
+class IMailSubscriptions(Interface):
+ """This interface allows you to retrieve a list of E-mails for
+ mailings. In our context these are messages."""
+
+ def getSubscriptions():
+ """Return a list of E-mails."""
+
+ def addSubscriptions(emails):
+ """Add a bunch of subscriptions; one would be okay too."""
+
+ def removeSubscriptions(emails):
+ """Remove a set of subscriptions."""
Added: messageboard/trunk/step07/locales/de/LC_MESSAGES/messageboard.mo
===================================================================
(Binary files differ)
Property changes on: messageboard/trunk/step07/locales/de/LC_MESSAGES/messageboard.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: messageboard/trunk/step07/locales/de/LC_MESSAGES/messageboard.po
===================================================================
--- messageboard/trunk/step07/locales/de/LC_MESSAGES/messageboard.po 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/locales/de/LC_MESSAGES/messageboard.po 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,238 @@
+# translation of messageboard.po to German
+# translation of messageboard.po to English US
+# Copyright (C) YEAR ORGANIZATION.
+# Stephan Richter <stephan.richter at tufts.edu>, 2003, 2004.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: messageboard\n"
+"POT-Creation-Date: Fri May 21 13:40:01 2004\n"
+"PO-Revision-Date: 2004-05-21 13:46-0400\n"
+"Last-Translator: Stephan Richter <stephan.richter at tufts.edu>\n"
+"Language-Team: German <zope3-dev at zope.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.4\n"
+"X-Generator: KBabel 1.9\n"
+
+#: src/book/messageboard/browser/configure.zcml:128
+msgid "Subscriptions"
+msgstr "Abonnements"
+
+#: src/book/messageboard/browser/configure.zcml:14
+msgid "A Message Board"
+msgstr "Ein Anzeigebrett"
+
+#: src/book/messageboard/browser/configure.zcml:22
+msgid "Change Message Board"
+msgstr "Anzeigebrett ändern"
+
+#: src/book/messageboard/browser/configure.zcml:22
+#: src/book/messageboard/browser/configure.zcml:72
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: src/book/messageboard/browser/configure.zcml:38
+#: src/book/messageboard/browser/configure.zcml:101
+msgid "Thread"
+msgstr "Unterhaltungsfaden"
+
+#: src/book/messageboard/browser/configure.zcml:5
+msgid "Add Message Board"
+msgstr "Anzeigebrett hinzufügen"
+
+#: src/book/messageboard/browser/configure.zcml:64
+msgid "A Message"
+msgstr "Eine Anzeige"
+
+#: src/book/messageboard/browser/configure.zcml:64
+msgid "Message"
+msgstr "Anzeige"
+
+#: src/book/messageboard/browser/configure.zcml:72
+msgid "Change Message"
+msgstr "Anzeige ändern"
+
+#: src/book/messageboard/browser/configure.zcml:89
+msgid "Preview"
+msgstr "Vorschau"
+
+#: src/book/messageboard/browser/details.pt:13
+msgid "Author"
+msgstr "Autor"
+
+#: src/book/messageboard/browser/details.pt:18
+msgid "Date/Time"
+msgstr "Datum/Zeit"
+
+#: src/book/messageboard/browser/details.pt:23
+msgid "Parent"
+msgstr "Vorfahre"
+
+#: src/book/messageboard/browser/details.pt:32
+msgid "Body"
+msgstr "Inhalt"
+
+#: src/book/messageboard/browser/details.pt:5
+msgid "Message Details"
+msgstr "Anzeigedetails"
+
+#: src/book/messageboard/browser/details.pt:8
+msgid "Title"
+msgstr "Titel"
+
+#: src/book/messageboard/browser/message.py:34
+msgid "unknown"
+msgstr "unbekannt"
+
+#: src/book/messageboard/browser/subscriptions.pt:16
+msgid "remove-button"
+msgstr "Entfernen"
+
+# 7/browser/subscriptions.pt:25
+#: src/book/messageboard/browser/subscriptions.pt:22
+msgid "Enter new Users (separate by 'Return')"
+msgstr "Neue Nutzer eingeben (durch 'Return' getrennt)"
+
+# 7/browser/subscriptions.pt:35
+# Default: "Refresh"
+#: src/book/messageboard/browser/subscriptions.pt:32
+msgid "refresh-button"
+msgstr "Zurücksetzen"
+
+#: src/book/messageboard/browser/subscriptions.pt:34
+msgid "add-button"
+msgstr "Hinzufügen"
+
+#: src/book/messageboard/browser/subscriptions.pt:8
+msgid "Current Subscriptions"
+msgstr "Derzeitige Abonnements"
+
+#: src/book/messageboard/browser/thread.pt:5
+msgid "Discussion Thread"
+msgstr "Diskussions-Faden"
+
+#: src/book/messageboard/configure.zcml:13
+msgid "Add Message."
+msgstr "Nachricht hinzufügen."
+
+#: src/book/messageboard/configure.zcml:13
+#: src/book/messageboard/browser/configure.zcml:55
+msgid "Add Message"
+msgstr "Anzeige hinzufügen"
+
+#: src/book/messageboard/configure.zcml:18
+msgid "Edit Messages."
+msgstr "Anzeigen bearbeiten."
+
+#: src/book/messageboard/configure.zcml:18
+msgid "Edit Messages"
+msgstr "Anzeigen bearbeiten"
+
+#: src/book/messageboard/configure.zcml:23
+msgid "Delete Message"
+msgstr "Anzeigen löschen"
+
+#: src/book/messageboard/configure.zcml:23
+msgid "Delete Message."
+msgstr "Anzeigen löschen."
+
+#: src/book/messageboard/configure.zcml:41
+#: src/book/messageboard/browser/configure.zcml:14
+msgid "Message Board"
+msgstr "Anzeigenbrett"
+
+#: src/book/messageboard/configure.zcml:8
+msgid "View the Message Board and all its content."
+msgstr "Das Anzeigebrett und seine Inhalte anschauen."
+
+#: src/book/messageboard/configure.zcml:8
+msgid "View Message Board and Messages"
+msgstr "Anzeigebrett und Anzeigen ansehen"
+
+#: src/book/messageboard/fields.py:30
+msgid "Forbidden HTML Tags used."
+msgstr "Verbotene HTML Tags wurden verwendet."
+
+#: src/book/messageboard/interfaces.py:42
+msgid "Title/Subject"
+msgstr "Titel/Thema"
+
+#: src/book/messageboard/interfaces.py:43
+msgid "Title and/or subject of the message."
+msgstr "Titel und/oder Thema der Anzeige."
+
+#: src/book/messageboard/interfaces.py:48
+msgid "Message Body"
+msgstr "Text der Anzeige"
+
+#: src/book/messageboard/interfaces.py:49
+msgid "This is the actual message. Type whatever!"
+msgstr "Dies ist die Anzeige selbst. Schreib was immer Du willst!"
+
+#: src/book/messageboard/interfaces.py:69
+msgid "Description"
+msgstr "Beschreibung"
+
+#: src/book/messageboard/interfaces.py:70
+msgid "A detailed description of the content of the board."
+msgstr "Eine detailierte Beschreibung des Brett-Inhaltes."
+
+#: src/book/messageboard/interfaces.py:85
+msgid "Allowed HTML Tags"
+msgstr "Erlaubte HTML Tags"
+
+#: src/book/messageboard/interfaces.py:86
+msgid ""
+" Only listed tags can be used in the value of the field.\n"
+" "
+msgstr ""
+" Aufgelistete Tags können im Inhalt dieses Feldes benutzt werden.\n"
+" "
+
+#: src/book/messageboard/interfaces.py:92
+msgid "Forbidden HTML Tags"
+msgstr "Verbotene HTML Tags"
+
+#: src/book/messageboard/interfaces.py:93
+msgid ""
+" Listed tags cannot be used in the value of the field.\n"
+" "
+msgstr ""
+" Aufgelistete Tags können nicht im Inhalt dieses Feldes benutzt "
+"werden.\n"
+" "
+
+#: src/book/messageboard/message.py:146
+msgid "1 reply, 1 attachment"
+msgstr "1 Antwort, 1 Anhang"
+
+#: src/book/messageboard/message.py:148
+msgid "1 reply, ${attachments} attachments"
+msgstr "1 Antwort; ${attachments} Anhänge"
+
+#: src/book/messageboard/message.py:150
+msgid "${messages} replies, 1 attachment"
+msgstr "${messages} Antworten; 1 Anhang"
+
+#: src/book/messageboard/message.py:152
+msgid "${messages} replies, ${attachments} attachments"
+msgstr "${messages} Antworten, ${attachments} Anhänge"
+
+#: src/book/messageboard/security.zcml:18
+msgid "Message Board Editor"
+msgstr "Anzeigebrett Editor"
+
+#: src/book/messageboard/security.zcml:18
+msgid "The Editor can edit and delete Messages."
+msgstr "Der Editor kann Anzeigen bearbeiten und löschen."
+
+#: src/book/messageboard/security.zcml:4
+msgid "Message Board User"
+msgstr "Anzeigenbrett Nutzer"
+
+#: src/book/messageboard/security.zcml:4
+msgid "Users that actually use the Message Board."
+msgstr "Nutzer die das Anzeigenbrett nutzen."
+
Added: messageboard/trunk/step07/locales/en/LC_MESSAGES/messageboard.mo
===================================================================
(Binary files differ)
Property changes on: messageboard/trunk/step07/locales/en/LC_MESSAGES/messageboard.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: messageboard/trunk/step07/locales/en/LC_MESSAGES/messageboard.po
===================================================================
--- messageboard/trunk/step07/locales/en/LC_MESSAGES/messageboard.po 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/locales/en/LC_MESSAGES/messageboard.po 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,8 @@
+# This file contains no message ids because the messageboard's default
+# language is English
+msgid ""
+msgstr ""
+"Project-Id-Version: messageboard\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
Added: messageboard/trunk/step07/locales/messageboard.pot
===================================================================
--- messageboard/trunk/step07/locales/messageboard.pot 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/locales/messageboard.pot 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,240 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+msgid ""
+msgstr ""
+"Project-Id-Version: Development/Unknown\n"
+"POT-Creation-Date: Fri May 21 13:40:01 2004\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: Zope 3 Developers <zope3-dev at zope.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: zope/app/translation_files/extract.py\n"
+
+#: src/book/messageboard/browser/configure.zcml:128
+msgid "Subscriptions"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:14
+msgid "A Message Board"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:22
+msgid "Change Message Board"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:22
+#: src/book/messageboard/browser/configure.zcml:72
+msgid "Edit"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:38
+#: src/book/messageboard/browser/configure.zcml:101
+msgid "Thread"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:5
+msgid "Add Message Board"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:64
+msgid "A Message"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:64
+msgid "Message"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:72
+msgid "Change Message"
+msgstr ""
+
+#: src/book/messageboard/browser/configure.zcml:89
+msgid "Preview"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:13
+msgid "Author"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:18
+msgid "Date/Time"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:23
+msgid "Parent"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:32
+msgid "Body"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:5
+msgid "Message Details"
+msgstr ""
+
+#: src/book/messageboard/browser/details.pt:8
+msgid "Title"
+msgstr ""
+
+#: src/book/messageboard/browser/message.py:34
+msgid "unknown"
+msgstr ""
+
+#: src/book/messageboard/browser/subscriptions.pt:16
+# Default: "Remove"
+msgid "remove-button"
+msgstr ""
+
+#: src/book/messageboard/browser/subscriptions.pt:22
+msgid "Enter new Users (separate by 'Return')"
+msgstr ""
+
+#: src/book/messageboard/browser/subscriptions.pt:32
+# Default: "Refresh"
+msgid "refresh-button"
+msgstr ""
+
+#: src/book/messageboard/browser/subscriptions.pt:34
+# Default: "Add"
+msgid "add-button"
+msgstr ""
+
+#: src/book/messageboard/browser/subscriptions.pt:8
+msgid "Current Subscriptions"
+msgstr ""
+
+#: src/book/messageboard/browser/thread.pt:5
+msgid "Discussion Thread"
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:13
+msgid "Add Message."
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:13
+#: src/book/messageboard/browser/configure.zcml:55
+msgid "Add Message"
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:18
+msgid "Edit Messages."
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:18
+msgid "Edit Messages"
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:23
+msgid "Delete Message"
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:23
+msgid "Delete Message."
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:41
+#: src/book/messageboard/browser/configure.zcml:14
+msgid "Message Board"
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:8
+msgid "View the Message Board and all its content."
+msgstr ""
+
+#: src/book/messageboard/configure.zcml:8
+msgid "View Message Board and Messages"
+msgstr ""
+
+#: src/book/messageboard/fields.py:30
+msgid "Forbidden HTML Tags used."
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:42
+msgid "Title/Subject"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:43
+msgid "Title and/or subject of the message."
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:48
+msgid "Message Body"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:49
+msgid "This is the actual message. Type whatever!"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:69
+msgid "Description"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:70
+msgid "A detailed description of the content of the board."
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:85
+msgid "Allowed HTML Tags"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:86
+msgid ""
+" Only listed tags can be used in the value of the field.\n"
+" "
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:92
+msgid "Forbidden HTML Tags"
+msgstr ""
+
+#: src/book/messageboard/interfaces.py:93
+msgid ""
+" Listed tags cannot be used in the value of the field.\n"
+" "
+msgstr ""
+
+#: src/book/messageboard/message.py:146
+msgid "1 reply, 1 attachment"
+msgstr ""
+
+#: src/book/messageboard/message.py:148
+msgid "1 reply, ${attachments} attachments"
+msgstr ""
+
+#: src/book/messageboard/message.py:150
+msgid "${messages} replies, 1 attachment"
+msgstr ""
+
+#: src/book/messageboard/message.py:152
+msgid "${messages} replies, ${attachments} attachments"
+msgstr ""
+
+#: src/book/messageboard/security.zcml:18
+msgid "Message Board Editor"
+msgstr ""
+
+#: src/book/messageboard/security.zcml:18
+msgid "The Editor can edit and delete Messages."
+msgstr ""
+
+#: src/book/messageboard/security.zcml:4
+msgid "Message Board User"
+msgstr ""
+
+#: src/book/messageboard/security.zcml:4
+msgid "Users that actually use the Message Board."
+msgstr ""
+
Added: messageboard/trunk/step07/message.py
===================================================================
--- messageboard/trunk/step07/message.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/message.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,371 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Implementation
+
+An implementation of the Message using BTreeContainers as base.
+
+$Id: message.py,v 1.1 2003/06/07 11:24:48 srichter Exp $
+"""
+from zope.i18n import MessageIDFactory
+from zope.interface import implements
+
+from zope.app import zapi
+from zope.app.annotation.interfaces import IAnnotations
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.interfaces import IObjectAddedEvent
+from zope.app.container.interfaces import IObjectRemovedEvent
+from zope.app.event.interfaces import IObjectModifiedEvent
+from zope.app.event.interfaces import ISubscriber
+from zope.app.mail.interfaces import IMailDelivery
+from zope.app.size.interfaces import ISized
+
+from book.messageboard.interfaces import IMessage
+from book.messageboard.interfaces import IMailSubscriptions
+
+_ = MessageIDFactory('messageboard')
+
+
+class Message(BTreeContainer):
+ """A simple implementation of a message.
+
+ Make sure that the ``Message`` implements the ``IMessage`` interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IMessage, Message)
+ True
+
+ Here is an example of changing the title and description of the message:
+
+ >>> message = Message()
+ >>> message.title
+ u''
+ >>> message.body
+ u''
+ >>> message.title = u'Message Title'
+ >>> message.body = u'Message Body'
+ >>> message.title
+ u'Message Title'
+ >>> message.body
+ u'Message Body'
+ """
+ implements(IMessage)
+
+ # See book.messageboard.interfaces.IMessage
+ title = u''
+
+ # See book.messageboard.interfaces.IMessage
+ body = u''
+
+
+class MessageSized(object):
+
+ implements(ISized)
+ __used_for__ = IMessage
+
+ def __init__(self, message):
+ self._message = message
+
+ def sizeForSorting(self):
+ """See ISized
+
+ Create the adapter first.
+
+ >>> size = MessageSized(Message())
+
+ Here are some examples of the expected output.
+
+ >>> size.sizeForSorting()
+ ('item', 0)
+ >>> size._message['msg1'] = Message()
+ >>> size.sizeForSorting()
+ ('item', 1)
+ >>> size._message['att1'] = object()
+ >>> size.sizeForSorting()
+ ('item', 2)
+ """
+ return ('item', len(self._message))
+
+ def sizeForDisplay(self):
+ """See ISized
+
+ Creater the adapter first.
+
+ >>> size = MessageSized(Message())
+
+ Here are some examples of the expected output.
+
+ >>> str = size.sizeForDisplay()
+ >>> str
+ u'${messages} replies, ${attachments} attachments'
+ >>> 'msgs: %(messages)s, atts: %(attachments)s' %str.mapping
+ 'msgs: 0, atts: 0'
+ >>> size._message['msg1'] = Message()
+ >>> str = size.sizeForDisplay()
+ >>> str
+ u'1 reply, ${attachments} attachments'
+ >>> 'msgs: %(messages)s, atts: %(attachments)s' %str.mapping
+ 'msgs: 1, atts: 0'
+ >>> size._message['att1'] = object()
+ >>> str = size.sizeForDisplay()
+ >>> str
+ u'1 reply, 1 attachment'
+ >>> 'msgs: %(messages)s, atts: %(attachments)s' %str.mapping
+ 'msgs: 1, atts: 1'
+ >>> size._message['msg2'] = Message()
+ >>> str = size.sizeForDisplay()
+ >>> str
+ u'${messages} replies, 1 attachment'
+ >>> 'msgs: %(messages)s, atts: %(attachments)s' %str.mapping
+ 'msgs: 2, atts: 1'
+ >>> size._message['att2'] = object()
+ >>> str = size.sizeForDisplay()
+ >>> str
+ u'${messages} replies, ${attachments} attachments'
+ >>> 'msgs: %(messages)s, atts: %(attachments)s' %str.mapping
+ 'msgs: 2, atts: 2'
+ """
+ messages = 0
+ for obj in self._message.values():
+ if IMessage.providedBy(obj):
+ messages += 1
+
+ attachments = len(self._message)-messages
+
+ if messages == 1 and attachments == 1:
+ size = _('1 reply, 1 attachment')
+ elif messages == 1 and attachments != 1:
+ size = _('1 reply, ${attachments} attachments')
+ elif messages != 1 and attachments == 1:
+ size = _('${messages} replies, 1 attachment')
+ else:
+ size = _('${messages} replies, ${attachments} attachments')
+
+ size.mapping = {'messages': `messages`, 'attachments': `attachments`}
+
+ return size
+
+
+SubscriberKey='http://www.zope.org/messageboard#1.0/MailSubscriptions/emails'
+
+
+class MailSubscriptions:
+ """Message Mail Subscriptions.
+
+ Verify the interface implementation
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IMailSubscriptions, MailSubscriptions)
+ True
+
+ Create asubscription instance of a message
+
+ >>> msg = Message()
+ >>> sub = MailSubscriptions(msg)
+
+ Verify that we have initially no subscriptions and then add some.
+
+ >>> sub.getSubscriptions()
+ ()
+ >>> sub.addSubscriptions(('foo at bar.com',))
+ >>> sub.getSubscriptions()
+ ('foo at bar.com',)
+ >>> sub.addSubscriptions(('blah at bar.com',))
+ >>> sub.getSubscriptions()
+ ('foo at bar.com', 'blah at bar.com')
+ >>> sub.addSubscriptions(('doh at bar.com',))
+ >>> sub.getSubscriptions()
+ ('foo at bar.com', 'blah at bar.com', 'doh at bar.com')
+
+ Now let's also check that we can remove entries.
+
+ >>> sub.removeSubscriptions(('foo at bar.com',))
+ >>> sub.getSubscriptions()
+ ('blah at bar.com', 'doh at bar.com')
+
+ When we construct a new mail subscription adapter instance, the values
+ should still be there.
+
+ >>> sub1 = MailSubscriptions(msg)
+ >>> sub1.getSubscriptions()
+ ('blah at bar.com', 'doh at bar.com')
+ """
+ implements(IMailSubscriptions)
+ __used_for__ = IMessage
+
+ def __init__(self, context):
+ self.context = context
+ self._annotations = IAnnotations(context)
+ if not self._annotations.get(SubscriberKey):
+ self._annotations[SubscriberKey] = ()
+
+ def getSubscriptions(self):
+ "See zopeproducts.messageboard.interfaces.IMailSubscriptions"
+ return self._annotations[SubscriberKey]
+
+ def addSubscriptions(self, emails):
+ "See zopeproducts.messageboard.interfaces.IMailSubscriptions"
+ subscribers = list(self._annotations[SubscriberKey])
+ for email in emails:
+ if email not in subscribers:
+ subscribers.append(email.strip())
+ self._annotations[SubscriberKey] = tuple(subscribers)
+
+ def removeSubscriptions(self, emails):
+ "See zopeproducts.messageboard.interfaces.IMailSubscriptions"
+ subscribers = list(self._annotations[SubscriberKey])
+ for email in emails:
+ if email in subscribers:
+ subscribers.remove(email)
+ self._annotations[SubscriberKey] = tuple(subscribers)
+
+
+class MessageMailer:
+ """Class to handle all outgoing mail.
+
+ Verify the interface implementation
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(ISubscriber, MessageMailer)
+ True
+ """
+
+ implements(ISubscriber)
+
+ def notify(self, event):
+ r"""See zope.app.event.interfaces.ISubscriber
+
+ Here is a demonstration on how the notification process and mail
+ sending works.
+
+ Before we can test this method, we have to create a mail delivery
+ object for testing.
+
+ >>> mail_result = []
+
+ >>> from zope.interface import implements
+ >>> from zope.app.mail.interfaces import IMailDelivery
+
+ >>> class MailDeliveryStub(object):
+ ... implements(IMailDelivery)
+ ...
+ ... def send(self, fromaddr, toaddrs, message):
+ ... mail_result.append((fromaddr, toaddrs, message))
+
+ >>> from zope.app.tests import ztapi
+ >>> ztapi.provideUtility(IMailDelivery, MailDeliveryStub(),
+ ... name='msgboard-delivery')
+
+ Create a message.
+
+ >>> from zope.interface import directlyProvides
+ >>> from zope.app.traversing.interfaces import IContainmentRoot
+
+ >>> msg = Message()
+ >>> directlyProvides(msg, IContainmentRoot)
+ >>> msg.__name__ = 'msg'
+ >>> msg.__parent__ = None
+ >>> msg.title = 'Hello'
+ >>> msg.body = 'Hello World!'
+
+ Add a subscription to message.
+
+ >>> msg_sub = MailSubscriptions(msg)
+ >>> msg_sub.context.__annotations__[SubscriberKey] = ('foo at bar.com',)
+
+ Now, create an event and send it to the message mailer object.
+
+ >>> from zope.app.event.objectevent import ObjectModifiedEvent
+ >>> event = ObjectModifiedEvent(msg)
+ >>> mailer.notify(event)
+
+ >>> from pprint import pprint
+ >>> pprint(mail_result)
+ [('mailer at messageboard.org',
+ ('foo at bar.com',),
+ 'Subject: Modified: msg\n\n\nHello World!')]
+ """
+ if IMessage.providedBy(event.object):
+ if IObjectAddedEvent.providedBy(event):
+ self.handleAdded(event.object)
+ elif IObjectModifiedEvent.providedBy(event):
+ self.handleModified(event.object)
+ elif IObjectRemovedEvent.providedBy(event):
+ self.handleRemoved(event.object)
+
+ def handleAdded(self, object):
+ subject = 'Added: '+zapi.getName(object)
+ emails = self.getAllSubscribers(object)
+ body = object.body
+ self.mail(emails, subject, body)
+
+ def handleModified(self, object):
+ subject = 'Modified: '+zapi.getName(object)
+ emails = self.getAllSubscribers(object)
+ body = object.body
+ self.mail(emails, subject, body)
+
+ def handleRemoved(self, object):
+ subject = 'Removed: '+zapi.getName(object)
+ emails = self.getAllSubscribers(object)
+ body = subject
+ self.mail(emails, subject, body)
+
+ def getAllSubscribers(self, object):
+ """Retrieves all email subscribers.
+
+ Here a small demonstration of retrieving all subscribers.
+
+ >>> from zope.interface import directlyProvides
+ >>> from zope.app.traversing.interfaces import IContainmentRoot
+
+ Create a parent message as it would be located in the message
+ board. Also add a subscriber to the message.
+
+ >>> msg1 = Message()
+ >>> directlyProvides(msg1, IContainmentRoot)
+ >>> msg1.__name__ = 'msg1'
+ >>> msg1.__parent__ = None
+ >>> msg1_sub = MailSubscriptions(msg1)
+ >>> msg1_sub.context.__annotations__[SubscriberKey] = ('foo at bar.com',)
+
+ Create a reply to the first message and also give it a subscriber.
+
+ >>> msg2 = Message()
+ >>> msg2_sub = MailSubscriptions(msg2)
+ >>> msg2_sub.context.__annotations__[SubscriberKey] = ('blah at bar.com',)
+ >>> msg1['msg2'] = msg2
+
+ When asking for all subscriptions of message 2, we should get the
+ subscriber from message 1 as well.
+
+ >>> mailer.getAllSubscribers(msg2)
+ ('blah at bar.com', 'foo at bar.com')
+ """
+ emails = ()
+ msg = object
+ while IMessage.providedBy(msg):
+ emails += tuple(IMailSubscriptions(msg).getSubscriptions())
+ msg = zapi.getParent(msg)
+ return emails
+
+ def mail(self, toaddrs, subject, body):
+ """Mail out the Message Board change message."""
+ if not toaddrs:
+ return
+ msg = 'Subject: %s\n\n\n%s' %(subject, body)
+ mail_utility = zapi.getUtility(None, IMailDelivery,
+ 'msgboard-delivery')
+ mail_utility.send('mailer at messageboard.org' , toaddrs, msg)
+
+mailer = MessageMailer()
Added: messageboard/trunk/step07/messageboard.py
===================================================================
--- messageboard/trunk/step07/messageboard.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/messageboard.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Board Implementation
+
+An implementation of the Message Board using BTreeContainers as base.
+
+$Id$
+"""
+from zope.interface import implements
+from zope.app.container.btree import BTreeContainer
+
+from book.messageboard.interfaces import IMessageBoard
+
+class MessageBoard(BTreeContainer):
+ """A very simple implementation of a message board using B-Tree Containers
+
+ Make sure that the ``MessageBoard`` implements the ``IMessageBoard``
+ interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IMessageBoard, MessageBoard)
+ True
+
+ Here is an example of changing the description of the board:
+
+ >>> board = MessageBoard()
+ >>> board.description
+ u''
+ >>> board.description = u'Message Board Description'
+ >>> board.description
+ u'Message Board Description'
+ """
+ implements(IMessageBoard)
+
+ # See book.messageboard.interfaces.IMessageBoard
+ description = u''
Added: messageboard/trunk/step07/security.zcml
===================================================================
--- messageboard/trunk/step07/security.zcml 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/security.zcml 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,50 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope">
+
+ <role
+ id="book.messageboard.User"
+ title="Message Board User"
+ description="Users that actually use the Message Board."
+ />
+ <grant
+ permission="book.messageboard.View"
+ role="book.messageboard.User"
+ />
+ <grant
+ permission="book.messageboard.Add"
+ role="book.messageboard.User"
+ />
+
+ <role
+ id="book.messageboard.Editor"
+ title="Message Board Editor"
+ description="The Editor can edit and delete Messages."
+ />
+ <grant
+ permission="book.messageboard.Edit"
+ role="book.messageboard.Editor"
+ />
+ <grant
+ permission="book.messageboard.Delete"
+ role="book.messageboard.Editor"
+ />
+
+
+ <grant
+ permission="book.messageboard.View"
+ role="zope.Manager"
+ />
+ <grant
+ permission="book.messageboard.Add"
+ role="zope.Manager"
+ />
+ <grant
+ permission="book.messageboard.Edit"
+ role="zope.Manager"
+ />
+ <grant
+ permission="book.messageboard.Delete"
+ role="zope.Manager"
+ />
+
+</configure>
Added: messageboard/trunk/step07/tests/__init__.py
===================================================================
--- messageboard/trunk/step07/tests/__init__.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/tests/__init__.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1 @@
+# Make it a Python package
Added: messageboard/trunk/step07/tests/test_fields.py
===================================================================
--- messageboard/trunk/step07/tests/test_fields.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/tests/test_fields.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,64 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Board Tests
+
+$Id: test_fields.py,v 1.1 2003/06/10 14:40:45 srichter Exp $
+"""
+import unittest
+from zope.schema.tests.test_strfield import TextTest
+
+from book.messageboard.fields import HTML, ForbiddenTags
+
+class HTMLTest(TextTest):
+
+ _Field_Factory = HTML
+
+ def test_AllowedTagsHTMLValidate(self):
+ html = self._Field_Factory(allowed_tags=('h1','pre'))
+ html.validate(u'<h1>Blah</h1>')
+ html.validate(u'<pre>Blah</pre>')
+ html.validate(u'<h1><pre>Blah</pre></h1>')
+ html.validate(u'<h1 style="..."><pre>Blah</pre></h1>')
+ html.validate(u'<h1 style="..."><pre f="">Blah</pre></h1>')
+
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2>Foo</h2>')
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2><pre>Foo</pre></h2>')
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2 attr="blah">Foo</h2>')
+
+
+ def test_ForbiddenTagsHTMLValidate(self):
+ html = self._Field_Factory(forbidden_tags=('h2','pre'))
+ html.validate(u'<h1>Blah</h1>')
+ html.validate(u'<h1 style="...">Blah</h1>')
+ html.validate(u'<h1 style="..."><div>Blah</div></h1>')
+ html.validate(u'<h1 style="..."><div f="">Blah</div></h1>')
+
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2>Foo</h2>')
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2><div>Foo</div></h2>')
+ self.assertRaises(ForbiddenTags, html.validate,
+ u'<h2 attr="blah">Foo</h2>')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(HTMLTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: messageboard/trunk/step07/tests/test_message.py
===================================================================
--- messageboard/trunk/step07/tests/test_message.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/tests/test_message.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Board Tests
+
+$Id: test_message.py,v 1.2 2003/08/20 17:07:46 srichter Exp $
+"""
+import unittest
+from zope.interface import classImplements
+from zope.testing.doctestunit import DocTestSuite
+
+from zope.app.annotation.interfaces import IAnnotations
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.annotation.attribute import AttributeAnnotations
+from zope.app.container.tests.test_icontainer import TestSampleContainer
+from zope.app.location import LocationPhysicallyLocatable
+from zope.app.location.interfaces import ILocation
+from zope.app.tests import placelesssetup
+from zope.app.tests import ztapi
+from zope.app.traversing.interfaces import IPhysicallyLocatable
+
+from book.messageboard.interfaces import IMailSubscriptions
+from book.messageboard.interfaces import IMessage
+from book.messageboard.message import MailSubscriptions
+from book.messageboard.message import Message
+
+
+class Test(TestSampleContainer):
+
+ def makeTestObject(self):
+ return Message()
+
+
+def setUp():
+ placelesssetup.setUp()
+ classImplements(Message, IAttributeAnnotatable)
+ ztapi.provideAdapter(IAttributeAnnotatable, IAnnotations,
+ AttributeAnnotations)
+ ztapi.provideAdapter(ILocation, IPhysicallyLocatable,
+ LocationPhysicallyLocatable)
+ ztapi.provideAdapter(IMessage, IMailSubscriptions, MailSubscriptions)
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('book.messageboard.message',
+ setUp=setUp, tearDown=placelesssetup.tearDown),
+ unittest.makeSuite(Test),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: messageboard/trunk/step07/tests/test_messageboard.py
===================================================================
--- messageboard/trunk/step07/tests/test_messageboard.py 2004-05-21 16:27:42 UTC (rev 24855)
+++ messageboard/trunk/step07/tests/test_messageboard.py 2004-05-21 17:52:09 UTC (rev 24856)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Message Board Tests
+
+$Id: test_messageboard.py,v 1.2 2003/08/20 17:07:46 srichter Exp $
+"""
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+
+from zope.app.container.tests.test_icontainer import TestSampleContainer
+
+from book.messageboard.messageboard import MessageBoard
+
+
+class Test(TestSampleContainer):
+
+ def makeTestObject(self):
+ return MessageBoard()
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('book.messageboard.messageboard'),
+ unittest.makeSuite(Test),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the Zope-CVS
mailing list