[z3-checkins] r9222 - in z3/zblog: . branch tag trunk trunk/browser
trunk/browser/ftests trunk/tests
rspivak at codespeak.net
rspivak at codespeak.net
Mon Feb 14 22:04:33 MET 2005
Author: rspivak
Date: Mon Feb 14 22:04:32 2005
New Revision: 9222
Added:
z3/zblog/
z3/zblog/branch/
z3/zblog/tag/
z3/zblog/trunk/
z3/zblog/trunk/Makefile
z3/zblog/trunk/__init__.py
z3/zblog/trunk/blog.py
z3/zblog/trunk/blogentry.py
z3/zblog/trunk/browser/
z3/zblog/trunk/browser/__init__.py
z3/zblog/trunk/browser/blog.png (contents, props changed)
z3/zblog/trunk/browser/blog.py
z3/zblog/trunk/browser/blogentry.png (contents, props changed)
z3/zblog/trunk/browser/blogentry.py
z3/zblog/trunk/browser/blogentrydetails.pt
z3/zblog/trunk/browser/bloglisting.pt
z3/zblog/trunk/browser/configure.zcml
z3/zblog/trunk/browser/dublincore.py
z3/zblog/trunk/browser/ftests/
z3/zblog/trunk/browser/ftests/__init__.py
z3/zblog/trunk/browser/ftests/test_blogentry.py
z3/zblog/trunk/configure.zcml
z3/zblog/trunk/interfaces.py
z3/zblog/trunk/tests/
z3/zblog/trunk/tests/__init__.py
z3/zblog/trunk/tests/test_blog.py
z3/zblog/trunk/tests/test_blogentry.py
Log:
initial import
Added: z3/zblog/trunk/Makefile
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/Makefile Mon Feb 14 22:04:32 2005
@@ -0,0 +1,5 @@
+.PHONY: clean
+
+clean:
+ find . "(" -name "*~" -or -name ".#*" -or -name "*.pyc" ")" -print | xargs rm -f
+
Added: z3/zblog/trunk/__init__.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/__init__.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1 @@
+#
\ No newline at end of file
Added: z3/zblog/trunk/blog.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/blog.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,62 @@
+# $Id$
+
+from zope.interface import implements
+from zope.component import adapts
+from zope.app.container.btree import BTreeContainer
+from zope.app.container.interfaces import INameChooser
+
+from zblog.interfaces import IBlog
+import re
+from datetime import datetime
+
+class Blog(BTreeContainer):
+ """Blog implementation using BTree container.
+
+ Make sure that Blog implements IBlog interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IBlog, Blog)
+ True
+
+ Example of changing blog title and description:
+
+ >>> blog = Blog()
+
+ >>> blog.title
+ u''
+ >>> blog.title = u'Blog title'
+ >>> blog.title
+ u'Blog title'
+
+ >>> blog.description
+ u''
+ >>> blog.description = u'Blog description'
+ >>> blog.description
+ u'Blog description'
+ """
+
+ implements(IBlog)
+
+ # See zblog.interfaces.IBlog
+ description = u''
+
+ # See zblog.interfaces.IBlog
+ title = u''
+
+
+class BlogNameChooser:
+ """An adapter to choose names for blog entries."""
+ implements(INameChooser)
+ adapts(IBlog)
+
+ def __init__(self, context):
+ self.context = context
+
+ def chooseName(self, name, entry):
+ if name:
+ return name
+ return datetime.now().strftime('%Y_%m_%d_') + \
+ re.sub('\s', '_', entry.title)
+
+ def checkName(self, name, entry):
+ return True
Added: z3/zblog/trunk/blogentry.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/blogentry.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,50 @@
+# $Id$
+
+from zope.interface import implements
+from persistent import Persistent
+from zope.app.container.contained import Contained
+from zblog.interfaces import IBlogEntry, IBlogEntryContained
+
+class BlogEntry(Persistent, Contained):
+ """Blog entry.
+
+ Make sure that BlogEntry implements IBlogEntry interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(IBlogEntry, BlogEntry)
+ True
+
+ Testing title, content:
+
+ >>> blogentry = BlogEntry()
+
+ >>> blogentry.title
+ u''
+ >>> blogentry.title = u'Blog entry title'
+ >>> blogentry.title
+ u'Blog entry title'
+
+ >>> blogentry.content
+ u''
+ >>> blogentry.content = u'Blog entry content'
+ >>> blogentry.content
+ u'Blog entry content'
+
+ Example of changing summary field:
+
+ >>> blogentry.summary
+ u''
+ >>> blogentry.summary = u'Blog entry summary'
+ >>> blogentry.summary
+ u'Blog entry summary'
+ """
+ implements(IBlogEntry, IBlogEntryContained)
+
+ # See zblog.interfaces.IBlogEntry
+ title = u''
+
+ # See zblog.interfaces.IBlogEntry
+ content = u''
+
+ # See zblog.interfaces.IBlogEntry
+ summary = u''
Added: z3/zblog/trunk/browser/__init__.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/__init__.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1 @@
+#
Added: z3/zblog/trunk/browser/blog.png
==============================================================================
Binary file. No diff available.
Added: z3/zblog/trunk/browser/blog.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/blog.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,14 @@
+# $Id$
+
+from zope.app import zapi
+from zope.app.dublincore.interfaces import ICMFDublinCore
+
+class BlogListing:
+
+ def getSortedBlogEntries(self):
+ """Returns blog entries sorted on creation date in reverse order."""
+ items = [(ICMFDublinCore(entry).created, entry) for
+ entry in self.context.values()]
+ items.sort()
+ items.reverse()
+ return [t[1] for t in items]
Added: z3/zblog/trunk/browser/blogentry.png
==============================================================================
Binary file. No diff available.
Added: z3/zblog/trunk/browser/blogentry.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/blogentry.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,4 @@
+from zblog.browser.dublincore import DublinCoreViews
+
+class BlogEntryDetails(DublinCoreViews):
+ pass
Added: z3/zblog/trunk/browser/blogentrydetails.pt
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/blogentrydetails.pt Mon Feb 14 22:04:32 2005
@@ -0,0 +1,12 @@
+<html metal:use-macro="views/standard_macros/view">
+ <body>
+ <div metal:fill-slot="body">
+ <h1 tal:content="context/title">Blog entry title</h1>
+ <div class="row" tal:content="context/content" />
+ <div class="row">
+ <span tal:content="view/author" />
+ <span tal:content="view/created" />
+ </div>
+ </div>
+ </body>
+</html>
Added: z3/zblog/trunk/browser/bloglisting.pt
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/bloglisting.pt Mon Feb 14 22:04:32 2005
@@ -0,0 +1,14 @@
+<html metal:use-macro="views/standard_macros/view">
+ <body>
+ <div metal:fill-slot="body">
+ <h1 tal:content="context/title"></h1>
+ <div tal:content="context/description" />
+
+ <div class="row" tal:repeat="item view/getSortedBlogEntries">
+ <div class="row" tal:content="item/title" />
+ <div class="row" tal:content="item/summary" />
+ <hr/>
+ </div>
+ </div>
+ </body>
+</html>
Added: z3/zblog/trunk/browser/configure.zcml
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/configure.zcml Mon Feb 14 22:04:32 2005
@@ -0,0 +1,117 @@
+<configure
+ xmlns="http://namespaces.zope.org/browser">
+
+ <!-- Blog -->
+
+ <addform
+ label="Add Blog"
+ name="AddBlog.html"
+ schema="zblog.interfaces.IBlog"
+ content_factory="zblog.blog.Blog"
+ fields="title description"
+ permission="zope.ManageContent"
+ />
+
+ <addMenuItem
+ class="zblog.blog.Blog"
+ title="Blog"
+ description="A Blog"
+ permission="zope.ManageContent"
+ view="AddBlog.html"
+ />
+
+ <editform
+ schema="zblog.interfaces.IBlog"
+ for="zblog.interfaces.IBlog"
+ label="Change Blog"
+ name="edit.html"
+ permission="blog.Edit"
+ menu="zmi_views" title="Edit"
+ />
+
+ <containerViews
+ for="zblog.interfaces.IBlog"
+ index="blog.View"
+ contents="blog.Edit"
+ add="blog.Add"
+ />
+
+ <page
+ name="view.html"
+ for="zblog.interfaces.IBlog"
+ class=".blog.BlogListing"
+ template="bloglisting.pt"
+ permission="blog.View"
+ menu="zmi_views" title="Preview" />
+
+ <defaultView
+ for="zblog.interfaces.IBlog"
+ name="view.html" />
+
+ <icon
+ name="zmi_icon"
+ for="zblog.interfaces.IBlog"
+ file="blog.png" />
+
+
+ <!-- Blog Entry -->
+
+ <addform
+ label="Add Blog Entry"
+ name="AddBlogEntry.html"
+ schema="zblog.interfaces.IBlogEntry"
+ content_factory="zblog.blogentry.BlogEntry"
+ fields="title content summary"
+ permission="blog.Add"
+ set_before_add="title"
+ />
+
+ <addMenuItem
+ class="zblog.blogentry.BlogEntry"
+ title="Blog Entry"
+ description="A Blog Entry"
+ permission="blog.Add"
+ view="AddBlogEntry.html"
+ />
+
+ <editform
+ schema="zblog.interfaces.IBlogEntry"
+ for="zblog.interfaces.IBlogEntry"
+ label="Change Blog Entry"
+ name="edit.html"
+ permission="blog.Edit"
+ menu="zmi_views" title="Edit"
+ />
+
+ <page
+ name="details.html"
+ for="zblog.interfaces.IBlogEntry"
+ class=".blogentry.BlogEntryDetails"
+ template="blogentrydetails.pt"
+ permission="blog.View"
+ menu="zmi_views" title="Preview"
+ />
+
+ <defaultView
+ for="zblog.interfaces.IBlogEntry"
+ name="details.html" />
+
+ <icon
+ name="zmi_icon"
+ for="zblog.interfaces.IBlogEntry"
+ file="blogentry.png" />
+
+ <!-- separate menu for Blog|Entry and Blog -->
+ <menu
+ id="blogentry_actions"
+ title="Menu for BlogEntry related actions"
+ />
+
+ <menuItems
+ menu="blogentry_actions"
+ for="zblog.interfaces.IBlogEntry">
+ <menuItem title="View" action="@@details.html" />
+ <menuItem title="Edit" action="@@edit.html" />
+ </menuItems>
+
+</configure>
Added: z3/zblog/trunk/browser/dublincore.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/dublincore.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,16 @@
+from zope.app.dublincore.interfaces import ICMFDublinCore
+
+class DublinCoreViews:
+
+ def author(self):
+ creators = ICMFDublinCore(self.context).creators
+ if creators is None:
+ return u'unknown'
+ return creators[0]
+
+ def created(self):
+ date = ICMFDublinCore(self.context).created
+ if date is None:
+ return ''
+ formatter = self.request.locale.dates.getFormatter('dateTime', 'medium')
+ return formatter.format(date)
Added: z3/zblog/trunk/browser/ftests/__init__.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/ftests/__init__.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1 @@
+#
Added: z3/zblog/trunk/browser/ftests/test_blogentry.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/browser/ftests/test_blogentry.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,50 @@
+# $Id$
+
+import unittest
+from zope.app.tests.functional import BrowserTestCase
+
+class BlogEntryTest(BrowserTestCase):
+
+ def testAddBlogEntry(self):
+ response = self.publish(
+ '/+/AddBlog.html=blog',
+ basic='mgr:mgrpw',
+ form={'field.title' : u'Blog title',
+ 'field.description' : u'Blog description',
+ 'UPDATE_SUBMIT' : 'Add'})
+ self.assertEqual(response.getStatus(), 302)
+ self.assertEqual(response.getHeader('Location'),
+ 'http://localhost/@@contents.html')
+
+ response = self.publish(
+ '/blog/+/AddBlogEntry.html=bentry',
+ basic='mgr:mgrpw',
+ form={'field.title' : u'Blog entry title',
+ 'field.content' : u'Blog entry content',
+ 'field.summary' : u'Blog entry summary',
+ 'UPDATE_SUBMIT' : 'Add'})
+ self.assertEqual(response.getStatus(), 302)
+ # id of blog entry can be changed if there is adapter
+ # for Blog that implements INameChooser
+ self.assertEqual(response.getHeader('Location'),
+ 'http://localhost/blog/@@contents.html')
+
+ def testBlogEntryDetails(self):
+ self.testAddBlogEntry()
+
+ response = self.publish('/blog/bentry/@@details.html',
+ basic='mgr:mgrpw')
+ body = response.getBody()
+ self.checkForBrokenLinks(body, '/blog/bentry/@@details.html',
+ basic='mgr:mgrpw')
+
+ self.assert_('Blog entry title' in body)
+ self.assert_('Blog entry content' in body)
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(BlogEntryTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: z3/zblog/trunk/configure.zcml
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/configure.zcml Mon Feb 14 22:04:32 2005
@@ -0,0 +1,115 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope">
+
+ <permission
+ id="blog.View"
+ title="View Blog and Blog entries"
+ description="View blog and blog entries"
+ />
+ <permission
+ id="blog.Add"
+ title="Add Blog Entry"
+ description="Add Blog Entry"
+ />
+ <permission
+ id="blog.Edit"
+ title="Edit Blog Entry"
+ description="Edit Blog Entry"
+ />
+ <permission
+ id="blog.Delete"
+ title="Delete Blog Entry"
+ description="Delete Blog Entry"
+ />
+
+ <role
+ id="blog.User"
+ title="Blog User"
+ description="Blog visitors, who can view blog/blog entries and comment"
+ />
+ <role
+ id="blog.Poster"
+ title="Blog Poster"
+ description="The Poster can add and view blog entries"
+ />
+ <role
+ id="blog.Manager"
+ title="Blog Manager"
+ description="Manager can do everything"
+ />
+
+ <grant
+ permission="blog.View"
+ role="blog.User"
+ />
+ <grant
+ permission="blog.Add"
+ role="blog.Poster"
+ />
+ <grant
+ permission="blog.Edit"
+ role="blog.Manager"
+ />
+ <grant
+ permission="blog.Delete"
+ role="blog.Manager"
+ />
+
+ <interface
+ interface=".interfaces.IBlog"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <content class=".blog.Blog">
+ <implements
+ interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <implements
+ interface="zope.app.container.interfaces.IContentContainer"
+ />
+ <factory
+ id="blog.Blog"
+ description="Blog"
+ />
+ <require
+ permission="blog.View"
+ interface=".interfaces.IBlog"
+ />
+ <require
+ permission="blog.Edit"
+ set_schema=".interfaces.IBlog"
+ />
+ </content>
+
+ <interface
+ interface=".interfaces.IBlogEntry"
+ type="zope.app.content.interfaces.IContentType"
+ />
+
+ <content class=".blogentry.BlogEntry">
+ <implements
+ interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
+ />
+ <factory
+ id="blogentry.BlogEntry"
+ description="Blog Entry"
+ />
+ <require
+ permission="blog.View"
+ interface=".interfaces.IBlogEntry"
+ />
+ <require
+ permission="blog.Add"
+ set_schema=".interfaces.IBlogEntry"
+ />
+ </content>
+
+ <adapter
+ for="zblog.interfaces.IBlog"
+ factory=".blog.BlogNameChooser"
+ provides="zope.app.container.interfaces.INameChooser"
+ />
+
+ <include package=".browser" />
+
+</configure>
Added: z3/zblog/trunk/interfaces.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/interfaces.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,56 @@
+from zope.interface import Interface
+from zope.schema import Text, TextLine, Field
+
+from zope.app.container.constraints import ContainerTypesConstraint
+from zope.app.container.constraints import ItemTypePrecondition
+from zope.app.container.interfaces import IContained, IContainer
+
+class IBlogEntry(Interface):
+ """Interface for blog entry objects."""
+
+ title = TextLine(
+ title = u"Blog entry title",
+ description = u"Blog entry title.",
+ default = u"",
+ required = True)
+
+ content = Text(
+ title = u"Blog entry content",
+ description = u"Blog entry content.",
+ default = u"",
+ required = True)
+
+ summary = Text(
+ title = u"Summary",
+ description = u"An excerpt from content.""",
+ default = u"",
+ max_length = 250,
+ required = False)
+
+
+class IBlog(IContainer):
+ """The blog container which can contain IBlogEntry objects."""
+
+ def __setitem__(name, object):
+ """Add a IBlogEntry object."""
+
+ __setitem__.precondition = ItemTypePrecondition(IBlogEntry)
+
+ title = TextLine(
+ title = u"Blog title",
+ description = u"Blog description",
+ default = u"",
+ required = True)
+
+ description = Text(
+ title = u"Description",
+ description = u"A detailed description of the blog's contents.",
+ default = u"",
+ required = False)
+
+
+class IBlogEntryContained(IContained):
+ """Interface that specifies which type of objects can contain blog
+ entries."""
+
+ __parent__ = Field(constraint = ContainerTypesConstraint(IBlog))
Added: z3/zblog/trunk/tests/__init__.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/tests/__init__.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1 @@
+#
Added: z3/zblog/trunk/tests/test_blog.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/tests/test_blog.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,22 @@
+# $Id$
+
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+
+from zope.app.container.tests.test_icontainer import TestSampleContainer
+
+from zblog.blog import Blog
+
+class Test(TestSampleContainer):
+
+ def makeTestObject(self):
+ return Blog()
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('zblog.blog'),
+ unittest.makeSuite(Test),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: z3/zblog/trunk/tests/test_blogentry.py
==============================================================================
--- (empty file)
+++ z3/zblog/trunk/tests/test_blogentry.py Mon Feb 14 22:04:32 2005
@@ -0,0 +1,14 @@
+# $Id$
+
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+
+from zblog.blogentry import BlogEntry
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('zblog.blogentry'),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the z3-checkins
mailing list