[Checkins] SVN: Products.CMFDefault/trunk/Products/CMFDefault/ - added file add view

Yvo Schubbe y.2008 at wcm-solutions.de
Tue Apr 22 08:19:48 EDT 2008


Log message for revision 85591:
  - added file add view

Changed:
  U   Products.CMFDefault/trunk/Products/CMFDefault/CHANGES.txt
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py
  A   Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/tests.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
  U   Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py
  A   Products.CMFDefault/trunk/Products/CMFDefault/profiles/views_support/actions.xml

-=-
Modified: Products.CMFDefault/trunk/Products/CMFDefault/CHANGES.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/CHANGES.txt	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/CHANGES.txt	2008-04-22 12:19:47 UTC (rev 85591)
@@ -2,6 +2,10 @@
 
   Products.CMFDefault 2.2.0 (unreleased)
 
+    - views: Added ContentEditFormBase and FileAddView.
+      This shows how form-driven content creation works. The content is created
+      without using the constructor methods provided by the types tool.
+
     - DublinCore: Modified the 'addCreator' implementation.
       It no longer depends on the membership tool.
 

Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2008-04-22 12:19:47 UTC (rev 85591)
@@ -106,6 +106,14 @@
   <adapter factory=".file.FileSchemaAdapter"/>
 
   <browser:page
+      for="Products.CMFCore.interfaces.IFolderish"
+      layer="..interfaces.ICMFDefaultSkin"
+      name="addFile.html"
+      class=".file.FileAddView"
+      permission="cmf.AddPortalContent"
+      />
+
+  <browser:page
       for="..interfaces.IMutableFile"
       layer="..interfaces.ICMFDefaultSkin"
       name="edit.html"

Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/file.py	2008-04-22 12:19:47 UTC (rev 85591)
@@ -24,6 +24,7 @@
 from zope.schema import Text
 from zope.schema import TextLine
 
+from Products.CMFDefault.formlib.form import ContentAddFormBase
 from Products.CMFDefault.formlib.form import ContentEditFormBase
 from Products.CMFDefault.formlib.schema import ProxyFieldProperty
 from Products.CMFDefault.formlib.schema import SchemaAdapterBase
@@ -38,11 +39,19 @@
 
     title = TextLine(
         title=_(u'Title'),
-        readonly=True)
+        required=False,
+        missing_value=u'')
 
+    language = TextLine(
+        title=_(u'Language'),
+        required=False,
+        missing_value=u'',
+        max_length=2)
+
     description = Text(
         title=_(u'Description'),
-        readonly=True)
+        required=False,
+        missing_value=u'')
 
     format = ASCIILine(
         title=_(u'Content type'),
@@ -61,20 +70,55 @@
     adapts(IMutableFile)
     implements(IFileSchema)
 
-    title = ProxyFieldProperty(IFileSchema['title'], 'Title')
+    _upload = ProxyFieldProperty(IFileSchema['upload'], 'data')
+
+    def _setUpload(self, value):
+        self.context.manage_upload(value)
+
+    title = ProxyFieldProperty(IFileSchema['title'], 'Title', 'setTitle')
+    language = ProxyFieldProperty(IFileSchema['language'],
+                                  'Language', 'setLanguage')
     description = ProxyFieldProperty(IFileSchema['description'],
-                                     'Description')
+                                     'Description', 'setDescription')
     format = ProxyFieldProperty(IFileSchema['format'], 'Format')
-    upload = ProxyFieldProperty(IFileSchema['upload'],
-                                'data', 'manage_upload')
+    upload = property(_upload.__get__, _setUpload)
 
 
+class FileAddView(ContentAddFormBase):
+
+    """Add view for IMutableFile.
+    """
+
+    form_fields = (
+        form.FormFields(IFileSchema).select('title', 'description') +
+        form.FormFields(Bytes(__name__='upload', title=_(u'Upload')),
+                        TextLine(__name__='portal_type', default=u'File'))
+        )
+
+    def setUpWidgets(self, ignore_request=False):
+        super(FileAddView,
+              self).setUpWidgets(ignore_request=ignore_request)
+        self.widgets['description'].height = 3
+        self.widgets['portal_type'].hide = True
+        self.widgets['upload'].displayWidth = 60
+
+    def finishCreate(self, obj, data):
+        adapted = FileSchemaAdapter(obj)
+        adapted.language = u''
+        adapted.upload = self.request.form['%s.upload' % self.prefix]
+        if data['title']:
+            adapted.title = data['title']
+        if data['description']:
+            adapted.description = data['description']
+        return obj
+
+
 class FileEditView(ContentEditFormBase):
 
     """Edit view for IMutableFile.
     """
 
-    form_fields = form.FormFields(IFileSchema)
+    form_fields = form.FormFields(IFileSchema).omit('language')
 
     def setUpWidgets(self, ignore_request=False):
         super(FileEditView,
@@ -83,6 +127,8 @@
         self.widgets['upload'].displayWidth = 60
 
     def _handle_success(self, action, data):
-        if not data.get('upload'):
+        if data.get('upload'):
+            data['upload'] = self.request.form['%s.upload' % self.prefix]
+        else:
             del data['upload']
         return super(FileEditView, self)._handle_success(action, data)

Added: Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt	2008-04-22 12:19:47 UTC (rev 85591)
@@ -0,0 +1,59 @@
+File Views
+----------
+
+Set up user.
+
+    >>> uf = app.site.acl_users
+    >>> uf._doAddUser('mgr', 'mgrpw', ['Manager'], [])
+
+Create the browser object we'll be using.
+
+    >>> from Products.Five.testbrowser import Browser
+    >>> browser = Browser()
+    >>> browser.handleErrors = False
+    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+
+Use the add form without input.
+
+    >>> browser.open('http://localhost/site/@@addFile.html')
+    >>> '[[cmf_default][Add [[cmf_default][File]]]]' in browser.contents
+    True
+    >>> browser.getControl('[[zope][Add]]').click()
+    >>> '[[zope][There were errors]]' in browser.contents
+    True
+    >>> '[[zope][Required input is missing.]]' in browser.contents
+    True
+
+Use the add form with valid input.
+
+    >>> from StringIO import StringIO
+    >>> browser.open('http://localhost/site/@@addFile.html')
+    >>> '[[cmf_default][Add [[cmf_default][File]]]]' in browser.contents
+    True
+    >>> browser.getControl(name='form.title').value = 'FILE TITLE'
+    >>> browser.getControl(name='form.description').value = 'FILE DESCRIPTION.'
+    >>> ctrl = browser.getControl(name='form.upload')
+    >>> ctrl.add_file(StringIO('FILE DATA'), 'text/plain', 'myFile')
+    >>> browser.getControl('[[zope][Add]]').click()
+    >>> '[[cmf_default][[[cmf_default][File]] added.]]' in browser.contents
+    True
+
+Use the edit form without input.
+
+    >>> browser.open('http://localhost/site/myFile/@@edit.html')
+    >>> '[[cmf_default][Edit [[cmf_default][File]]]]' in browser.contents
+    True
+    >>> browser.getControl('[[cmf_default][Change]]').click()
+    >>> '[[cmf_default][Nothing to change.]]' in browser.contents
+    True
+
+Use the edit form with valid input.
+
+    >>> browser.open('http://localhost/site/myFile/@@edit.html')
+    >>> '[[cmf_default][Edit [[cmf_default][File]]]]' in browser.contents
+    True
+    >>> ctrl = browser.getControl(name='form.upload')
+    >>> ctrl.add_file(StringIO('FILE DATA'), 'text/plain', 'test.txt')
+    >>> browser.getControl('[[cmf_default][Change]]').click()
+    >>> '[[cmf_default][[[cmf_default][File]] changed.]]' in browser.contents
+    True


Property changes on: Products.CMFDefault/trunk/Products/CMFDefault/browser/file.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/tests.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/tests.py	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/tests.py	2008-04-22 12:19:47 UTC (rev 85591)
@@ -32,6 +32,9 @@
     s = ZopeTestCase.FunctionalDocFileSuite('document.txt')
     s.layer = FunctionalLayer
     suite.addTest(s)
+    s = ZopeTestCase.FunctionalDocFileSuite('file.txt')
+    s.layer = FunctionalLayer
+    suite.addTest(s)
     return suite
 
 if __name__ == '__main__':

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/form.py	2008-04-22 12:19:47 UTC (rev 85591)
@@ -19,8 +19,12 @@
 from sets import Set
 
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from Products.Five.formlib.formbase import PageAddForm
 from Products.Five.formlib.formbase import PageDisplayForm
 from Products.Five.formlib.formbase import PageForm
+from zope.app.container.interfaces import INameChooser
+from zope.component import getUtility
+from zope.component.interfaces import IFactory
 from zope.datetime import parseDatetimetz
 from zope.formlib import form
 from zope.i18n.interfaces import IUserPreferredLanguages
@@ -53,7 +57,7 @@
         return locales.getLocale(None, None, None)
 
 
-class EditFormBase(PageForm, ViewBase):
+class _EditFormMixin(ViewBase):
 
     template = ViewPageTemplateFile('editform.pt')
 
@@ -92,10 +96,106 @@
             self.request.other['portal_status_message'] = message
 
 
-class ContentEditFormBase(EditFormBase):
+class EditFormBase(_EditFormMixin, PageForm):
 
+    pass
+
+
+class ContentAddFormBase(_EditFormMixin, PageAddForm):
+
     actions = form.Actions(
         form.Action(
+            name='add',
+            label=form._('Add'),
+            condition=form.haveInputWidgets,
+            success='handle_add',
+            failure='handle_failure'),
+        form.Action(
+            name='cancel',
+            label=_(u'Cancel'),
+            success='handle_cancel_success',
+            failure='handle_cancel_failure'))
+
+    description = u''
+
+    @property
+    def label(self):
+        obj_type = self.widgets['portal_type']._getFormValue()
+        obj_type = translate(obj_type, self.context)
+        return _(u'Add ${obj_type}', mapping={'obj_type': obj_type})
+
+    def handle_add(self, action, data):
+        obj = self.createAndAdd(data)
+        if obj is None:
+            if self.status:
+                message = translate(self.status, self.context)
+                self.request.other['portal_status_message'] = message
+            return
+        obj_type = translate(obj.Type(), self.context)
+        message = translate(_(u'${obj_type} added.',
+                              mapping={'obj_type': obj_type}), self.context)
+        if isinstance(message, unicode):
+            message = message.encode(self._getBrowserCharset())
+        fti = obj.getTypeInfo()
+        self._nextURL = '%s/%s?%s' % (obj.absolute_url(), fti.immediate_view,
+                                    make_query(portal_status_message=message))
+
+    def handle_cancel_success(self, action, data):
+        return self._setRedirect('portal_types', 'object/folderContents')
+
+    def handle_cancel_failure(self, action, data, errors):
+        self.status = None
+        return self._setRedirect('portal_types', 'object/folderContents')
+
+    def create(self, data):
+        portal_type = self.request.form['%s.portal_type' % self.prefix]
+
+        #check type exists
+        ttool = self._getTool('portal_types')
+        fti = ttool.getTypeInfo(portal_type)
+        if fti is None:
+            raise ValueError(u'No such content type: %s' % portal_type)
+
+        factory = getUtility(IFactory, fti.factory)
+        obj = factory('temp_id')
+        if hasattr(obj, '_setPortalTypeName'):
+            obj._setPortalTypeName(portal_type)
+
+        return self.finishCreate(obj, data)
+
+    def add(self, obj):
+        container = self.context
+        upload = self.request.form.get('%s.upload' % self.prefix)
+        if upload:
+            filename = upload.filename.split('\\')[-1] # for IE
+            filename = filename.strip().replace(' ','_')
+        else:
+            filename = u''
+        name = INameChooser(container).chooseName(filename, obj)
+
+        #check container constraints
+        ttool = self._getTool('portal_types')
+        container_ti = ttool.getTypeInfo(container)
+        portal_type = obj.getPortalTypeName()
+        if container_ti is not None and \
+                not container_ti.allowType(portal_type):
+            self.status = u'Disallowed subobject type: %s' % portal_type
+            return None
+
+        obj.id = name
+        container._setObject(name, obj)
+
+        self._finished_add = True
+        return container._getOb(name)
+
+    def nextURL(self):
+        return self._nextURL
+
+
+class ContentEditFormBase(_EditFormMixin, PageForm):
+
+    actions = form.Actions(
+        form.Action(
             name='change',
             label=_(u'Change'),
             validator='handle_validate',

Modified: Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py	2008-04-22 12:11:58 UTC (rev 85590)
+++ Products.CMFDefault/trunk/Products/CMFDefault/formlib/schema.py	2008-04-22 12:19:47 UTC (rev 85591)
@@ -55,7 +55,7 @@
         self._get_name = get_name
         self._set_name = set_name
 
-    def __get__(self, inst, klass):
+    def __get__(self, inst, cls=None):
         if inst is None:
             return self
 

Added: Products.CMFDefault/trunk/Products/CMFDefault/profiles/views_support/actions.xml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/profiles/views_support/actions.xml	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/profiles/views_support/actions.xml	2008-04-22 12:19:47 UTC (rev 85591)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<object name="portal_actions" meta_type="CMF Actions Tool"
+   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <object name="folder">
+  <object name="add_file" meta_type="CMF Action" i18n:domain="cmf_default">
+   <property name="title" i18n:translate="">Add File</property>
+   <property name="description"
+      i18n:translate="">Add new File object</property>
+   <property name="url_expr">string:${object_url}/addFile.html</property>
+   <property name="icon_expr"></property>
+   <property
+      name="available_expr">python: folder is object and object.getTypeInfo().allowType('File')</property>
+   <property name="permissions">
+    <element value="Add portal content"/>
+   </property>
+   <property name="visible">True</property>
+  </object>
+ </object>
+</object>


Property changes on: Products.CMFDefault/trunk/Products/CMFDefault/profiles/views_support/actions.xml
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list