[CMF-checkins] SVN: CMF/branches/tseaver-viewification/ Branch for viewifying CMFDefault.

Tres Seaver tseaver at palladion.com
Fri Oct 21 19:27:46 EDT 2005


Log message for revision 39555:
  Branch for viewifying CMFDefault.
  

Changed:
  A   CMF/branches/tseaver-viewification/
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/__init__.py
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/configure.zcml
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.pt
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.py
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/tests/
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/tests/__init__.py
  A   CMF/branches/tseaver-viewification/CMFDefault/browser/tests/test_metadata.py
  U   CMF/branches/tseaver-viewification/CMFDefault/configure.zcml

-=-
Copied: CMF/branches/tseaver-viewification (from rev 39553, CMF/trunk)

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/__init__.py
===================================================================
--- CMF/trunk/CMFDefault/browser/__init__.py	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/__init__.py	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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 package for CMFDefault.
+
+$Id$
+"""


Property changes on: CMF/branches/tseaver-viewification/CMFDefault/browser/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/configure.zcml
===================================================================
--- CMF/trunk/CMFDefault/browser/configure.zcml	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/configure.zcml	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,24 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    >
+
+ <browser:page
+    for="Products.CMFCore.interfaces.IMutableDublinCore"
+    class=".metadata.MetadataView"
+    name="metadata.html"
+    template="metadata.pt"
+    permission="cmf.ModifyPortalContent"
+    layer="cmf"
+    />
+
+ <browser:page
+    for="Products.CMFCore.interfaces.IMutableDublinCore"
+    class=".metadata.MetadataView"
+    name="metadata.py"
+    attribute="controller"
+    permission="cmf.ModifyPortalContent"
+    layer="cmf"
+    />
+
+</configure>

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.pt
===================================================================
--- CMF/trunk/CMFDefault/browser/metadata.pt	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.pt	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,125 @@
+<html metal:use-macro="context/@@standard_macros/page"
+>
+<body>
+
+<metal:slot metal:fill-slot="header"
+            i18n:domain="cmf_default">
+<h1 i18n:translate="">
+ Resource Metadata: <tal:span tal:content="context/Title"
+                              i18n:name="obj_title">Title</tal:span></h1>
+</metal:slot>
+
+<metal:slot metal:fill-slot="body"
+            i18n:domain="cmf_default"
+            tal:define="minfo view/getMetadataInfo;
+                        finfo view/getFormInfo;
+                       ">
+
+<form action="metadata.py" method="post">
+<table class="FormLayout">
+ <tr>
+  <th i18n:translate="">Enable Discussion?</th>
+  <td colspan="3"
+      tal:define="allowed finfo/allow_discussion" >
+   <select name="allow_discussion" >
+    <option value="default"
+            tal:attributes="selected python: allowed is None"
+            i18n:translate="">Default</option>
+    <option value="off"
+            tal:attributes="selected python: allowed is False"
+            i18n:translate="">Off</option>
+    <option value="on"
+            tal:attributes="selected python: allowed is True"
+            i18n:translate="">On</option>
+   </select>
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Identifier</th>
+  <td colspan="3"> <span tal:replace="minfo/Identifier"></span>
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Title</th>
+  <td colspan="3">
+   <input type="text" name="title" value="" size="65"
+          tal:attributes="value minfo/Title" />
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Description</th>
+  <td colspan="3">
+   <textarea name="description:text" rows="5" cols="65" wrap="soft"
+             tal:content="minfo/Description"></textarea>
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Subject</th>
+  <td>
+   <textarea name="subject:lines" rows="3" cols="20"
+             tal:content="finfo/subject_lines"></textarea>
+  </td>
+  <th i18n:translate="">Contributors</th>
+  <td>
+   <textarea name="contributors:lines" rows="5" cols="30"
+             tal:content="finfo/contributor_lines"></textarea>
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Creation Date</th>
+  <td> <span tal:replace="minfo/CreationDate"></span>
+  </td>
+  <th i18n:translate="">Last Modified Date</th>
+  <td> <span tal:replace="minfo/ModificationDate"></span>
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Effective Date</th>
+  <td>
+   <input type="text" name="effective_date" value=""
+          tal:attributes="value minfo/EffectiveDate" />
+  </td>
+  <th i18n:translate="">Expiration Date</th>
+  <td>
+   <input type="text" name="expiration_date" value=""
+          tal:attributes="value minfo/ExpirationDate" />
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Format</th>
+  <td> <input type="text" name="format" value=""
+              tal:attributes="value minfo/Format" />
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Language</th>
+  <td> <input type="text" name="language" value=""
+              tal:attributes="value minfo/Language" />
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Rights</th>
+  <td> <input type="text" name="rights" value=""
+              tal:attributes="value minfo/Rights" />
+  </td>
+ </tr>
+ <tr>
+  <td>&nbsp;</td>
+  <td colspan="3">
+   <div class="FormButtons">
+   <tal:loop tal:repeat="button finfo/buttons"
+   ><input type="submit" name="ButtonName" value="ButtonValue"
+           tal:attributes="name button/name;
+                           value button/value;
+                          "
+           i18n:attributes="value" /></tal:loop>
+  </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+</metal:slot>
+
+</body>
+</html>


Property changes on: CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.py
===================================================================
--- CMF/trunk/CMFDefault/browser/metadata.py	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.py	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,142 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+""" Metadata view class
+
+$Id$
+"""
+from Globals import InitializeClass
+from Products.Five.browser import BrowserView
+from Products.CMFCore.interfaces import IDublinCore
+from Products.CMFCore.interfaces import ICatalogableDublinCore
+from Products.CMFCore.utils import getToolByName
+
+from Products.CMFDefault.utils import MessageID as _
+
+_DC_NAMES = IDublinCore.names()
+_CDC_NAMES = ICatalogableDublinCore.names()
+
+_BUTTONS = {
+    'change':
+        {'value': _('Change'),
+         'redirect' : 'metadata.html',
+        },
+    'change_and_edit':
+        {'value': _('Change and Edit'),
+         'redirect': 'edit.html',
+        },
+    'change_and_view':
+        {'value': _('Change and View'),
+         'redirect': 'view.html',
+        },
+}
+
+_BUTTON_NAMES = ('change', 'change_and_edit', 'change_and_view')
+
+def _tuplify( value ):
+
+    if isinstance(value, basestring):
+        value = (value,)
+    elif not isinstance(value, tuple):
+        value = tuple(value)
+
+    return tuple(filter(None, value))
+
+class MetadataView(BrowserView):
+
+    def getMetadataInfo(self):
+        """ Return a mapping describing all our context's metadata.
+        """
+        result = {}
+        context = self.context
+
+        for name in _DC_NAMES + _CDC_NAMES:
+
+            if name.startswith('list'):
+                key = name[4:]
+            elif name == 'Contributors':
+                key = name
+                name = 'listContributors'
+            else:
+                key = name
+
+            result[key] = getattr(context, name)()
+
+        return result
+
+    def getFormInfo(self):
+        """ Return a mapping describing all our context formstate.
+        """
+        result = {}
+        context = self.context
+        result['allow_discussion'] = getattr(context, 'allow_discussion', None)
+        result['subject_lines'] = '\n'.join(context.Subject())
+        result['contributor_lines'] = '\n'.join(context.listContributors())
+        result['buttons'] = [{'name': name, 'value': _BUTTONS[name]['value']}
+                                for name in _BUTTON_NAMES]
+        return result
+
+    def update(self, form):
+        context = self.context
+        dtool = getToolByName(context, 'portal_discussion', None)
+
+        if 'title' in form:
+            context.setTitle(form['title'])
+
+        if 'description' in form:
+            context.setDescription(form['description'])
+
+        if 'subject' in form:
+            context.setSubject(_tuplify(form['subject']))
+
+        if 'contributors' in form:
+            context.setContributors(_tuplify(form['contributors']))
+
+        if 'effective_date' in form:
+            context.setEffectiveDate(form['effective_date'])
+
+        if 'expiration_date' in form:
+            context.setExpirationDate(form['expiration_date'])
+
+        if 'format' in form:
+            context.setFormat(form['format'])
+
+        if 'language' in form:
+            context.setLanguage(form['language'])
+
+        if 'rights' in form:
+            context.setRights(form['rights'])
+
+        if dtool and 'allow_discussion' in form:
+            allow_discussion = form['allow_discussion']
+            if allow_discussion == 'default':
+                allow_discussion = None
+            elif allow_discussion == 'off':
+                allow_discussion = False
+            elif allow_discussion == 'on':
+                allow_discussion = True
+            dtool.overrideDiscussionFor(context, allow_discussion)
+            
+    def controller(self, RESPONSE):
+        """ Process a form post and redirect, if needed.
+        """
+        context = self.context
+        form = self.request.form
+        for button in _BUTTONS.keys():
+            if button in form:
+                self.update(form)
+                redirect = _BUTTONS[button]['redirect']
+                RESPONSE.redirect('%s/%s' % (context.absolute_url(), redirect))
+                return
+
+        return self.index()
+


Property changes on: CMF/branches/tseaver-viewification/CMFDefault/browser/metadata.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/tests/__init__.py
===================================================================
--- CMF/trunk/CMFDefault/browser/tests/__init__.py	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/tests/__init__.py	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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 package unit tests for CMFDefault.
+
+$Id$
+"""


Property changes on: CMF/branches/tseaver-viewification/CMFDefault/browser/tests/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: CMF/branches/tseaver-viewification/CMFDefault/browser/tests/test_metadata.py
===================================================================
--- CMF/trunk/CMFDefault/browser/tests/test_metadata.py	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/tests/test_metadata.py	2005-10-21 23:27:46 UTC (rev 39555)
@@ -0,0 +1,234 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+""" Unit tests for CMFDefault's metadata views
+
+$Id$
+"""
+import unittest
+from Products.Five.traversable import FakeRequest
+from DateTime.DateTime import DateTime
+
+_DC_VALUES = {
+    'Title': "Title",
+    'Creators': ("Creator",),
+    'Subject': ("Subject",),
+    'Description': "Description",
+    'Publisher': "Publisher",
+    'Contributors': ("Contributors",),
+    'created': DateTime('2005-10-21'),
+    'effective': DateTime('2005-10-23'),
+    'expires': DateTime('2005-10-24'),
+    'modified': DateTime('2005-10-22'),
+    'Type': "Type",
+    'Format': "Format",
+    'Identifier': "Identifier",
+    'Language': "Language",
+    'Rights': "Rights",
+}
+
+_DC_DATE_STRINGS = [
+    ('created', 'CreationDate',),
+    ('modified', 'ModificationDate',),
+    ('effective', 'EffectiveDate',),
+    ('expires', 'ExpirationDate',),
+]
+
+_EXAMPLE_URL = 'http://www.example.com/document'
+
+class MetadataViewTests(unittest.TestCase):
+
+    def _getTargetClass(self):
+        from Products.CMFDefault.browser.metadata import MetadataView
+        return MetadataView
+
+    def _makeOne(self, context, request=None, *args, **kw):
+        if request is None:
+            request = FakeRequest()
+        return self._getTargetClass()(context, request, *args, **kw)
+
+    def _makeContext(self, **kw):
+        from zope.interface import implements
+        from Products.CMFCore.interfaces import IMutableDublinCore
+
+        class _Dummy:
+            implements(IMutableDublinCore)
+            allow_discussion = None
+            def __init__(self, kw):
+                self.__dict__.update(dict([('_%s' % k, v)
+                                           for k, v in _DC_VALUES.items()]))
+                self.__dict__.update(kw)
+
+            def Title(self):
+                return self._Title
+
+            def listCreators(self):
+                return self._Creators
+
+            def Creator(self):
+                return self._Creators[0]
+
+            def Subject(self):
+                return self._Subject
+
+            def Description(self):
+                return self._Description
+
+            def Publisher(self):
+                return self._Publisher
+
+            def listContributors(self):
+                return self._Contributors
+
+            def Date(self):
+                return self._created.Date()
+
+            def CreationDate(self):
+                return self._created.Date()
+
+            def EffectiveDate(self):
+                return self._effective.Date()
+
+            def ExpirationDate(self):
+                return self._expires.Date()
+
+            def ModificationDate(self):
+                return self._modified.Date()
+
+            def Type(self):
+                return self._Type
+
+            def Format(self):
+                return self._Format
+
+            def Identifier(self):
+                return self._Identifier
+
+            def Language(self):
+                return self._Language
+
+            def Rights(self):
+                return self._Rights
+
+            def created(self):
+                return self._created
+
+            def effective(self):
+                return self._effective
+
+            def expires(self):
+                return self._expires
+
+            def modified(self):
+                return self._modified
+
+            def absolute_url(self):
+                return _EXAMPLE_URL
+
+            def setTitle(self, value):
+                self._Title = value
+
+        return _Dummy(kw)
+
+    def test_empty(self):
+        context = self._makeContext()
+        request = FakeRequest()
+        view = self._makeOne(context, request)
+        self.failUnless(view.context is context)
+        self.failUnless(view.request is request)
+
+    def test_getMetadataInfo(self):
+        context = self._makeContext()
+        view = self._makeOne(context)
+
+        minfo = view.getMetadataInfo()
+
+        for k, v in _DC_VALUES.items():
+            self.assertEqual(minfo[k], v)
+
+        for dn, sn in _DC_DATE_STRINGS:
+            mapped = _DC_VALUES[dn].Date()
+            self.assertEquals(minfo[sn], mapped)
+
+    def test_getFormInfo_allow_discussion(self):
+        context = self._makeContext()
+        view = self._makeOne(context)
+
+        finfo = view.getFormInfo()
+        self.assertEqual(finfo['allow_discussion'], None)
+
+        context.allow_discussion = False
+        finfo = view.getFormInfo()
+        self.assertEqual(finfo['allow_discussion'], False)
+
+        context.allow_discussion = True
+        finfo = view.getFormInfo()
+        self.assertEqual(finfo['allow_discussion'], True)
+
+    def test_getFormInfo_subject_lines(self):
+        SUBJECTS = ('abc', 'def')
+        context = self._makeContext()
+        context._Subject = SUBJECTS
+        view = self._makeOne(context)
+        finfo = view.getFormInfo()
+        self.assertEqual(finfo['subject_lines'], '\n'.join(SUBJECTS))
+
+    def test_getFormInfo_contributor_lines(self):
+        CONTRIBUTORS = ('abc', 'def')
+        context = self._makeContext()
+        context._Contributors = CONTRIBUTORS
+        view = self._makeOne(context)
+        finfo = view.getFormInfo()
+        self.assertEqual(finfo['contributor_lines'], '\n'.join(CONTRIBUTORS))
+
+    def test_getFormInfo_buttons(self):
+        BUTTONS =(('change', 'Change'),
+                  ('change_and_edit', 'Change and Edit'),
+                  ('change_and_view', 'Change and View'),
+                 )
+        context = self._makeContext()
+        view = self._makeOne(context)
+        finfo = view.getFormInfo()
+        buttons = finfo['buttons']
+
+        self.assertEqual(len(buttons), len(BUTTONS))
+        for found, expected in zip(buttons, BUTTONS):
+            self.assertEqual(found['name'], expected[0])
+
+    def test_controller_redirect(self):
+        NEW_TITLE = 'New Title'
+
+        class _DummyResponse:
+            _redirected = None
+            def redirect(self, target):
+                self._redirected = target
+
+        context = self._makeContext()
+        request = FakeRequest()
+        request.form = {'title': NEW_TITLE, 'change': 'Change'}
+        response = _DummyResponse()
+
+        view = self._makeOne(context, request)
+        view.controller(response)
+        self.assertEqual(response._redirected,
+                         '%s/%s' % (_EXAMPLE_URL, 'metadata.html'))
+        self.assertEqual(context._Title, NEW_TITLE)
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(MetadataViewTests),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: CMF/branches/tseaver-viewification/CMFDefault/browser/tests/test_metadata.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: CMF/branches/tseaver-viewification/CMFDefault/configure.zcml
===================================================================
--- CMF/trunk/CMFDefault/configure.zcml	2005-10-21 17:53:46 UTC (rev 39553)
+++ CMF/branches/tseaver-viewification/CMFDefault/configure.zcml	2005-10-21 23:27:46 UTC (rev 39555)
@@ -1,5 +1,6 @@
 <configure
     xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five"
     >
 
   <include
@@ -7,7 +8,19 @@
     />
 
   <include
+    file="configure.zcml"
+    package=".browser"
+    />
+
+  <include
     file="exportimport.zcml"
     />
 
+  <!-- XXX: Setting this is required to make the views accessible TTW, but it
+            breaks tests for now.  2005/10/21, TS
+  <five:traversable
+     class="Products.CMFDefault.Document.Document"
+     />
+   -->
+
 </configure>



More information about the CMF-checkins mailing list