[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/file/browser/ Improve UI for file uploads.

Fred L. Drake, Jr. fdrake at gmail.com
Mon Aug 16 20:03:35 EDT 2004


Log message for revision 27160:
  Improve UI for file uploads.
  
  - Use the name of the file being uploaded as the default name of the
    object to create if not specified (only when creating a new file).
    (Something similar could be done for Image if anyone has the time.)
  - Determine the MIME type from the file name if not provided.
  
  These changes require that we not use the default schema-based add and
  edit forms.
  


Changed:
  U   Zope3/trunk/src/zope/app/file/browser/configure.zcml
  U   Zope3/trunk/src/zope/app/file/browser/file.py
  A   Zope3/trunk/src/zope/app/file/browser/file_add.pt
  A   Zope3/trunk/src/zope/app/file/browser/file_upload.pt
  A   Zope3/trunk/src/zope/app/file/browser/tests/test_file.py


-=-
Modified: Zope3/trunk/src/zope/app/file/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/file/browser/configure.zcml	2004-08-17 00:01:22 UTC (rev 27159)
+++ Zope3/trunk/src/zope/app/file/browser/configure.zcml	2004-08-17 00:03:35 UTC (rev 27160)
@@ -33,12 +33,12 @@
       filter="python:context.contentType.startswith('text/')"
       permission="zope.ManageContent" />
 
-
-  <browser:editform
+  <browser:page
       name="upload.html"
       menu="zmi_views" title="Upload"
-      schema="zope.app.file.interfaces.IFile"
-      label="Upload a file"
+      for="zope.app.file.interfaces.IFile"
+      template="file_upload.pt"
+      class=".file.FileUpload"
       permission="zope.ManageContent"
       />
 
@@ -58,11 +58,11 @@
       view="zope.app.file.File"
       />
 
-  <browser:addform
-      schema="zope.app.file.interfaces.IFile"
-      label="Add a File"
-      content_factory="zope.app.file.File"
+  <browser:page
       name="zope.app.file.File"
+      for="zope.app.container.interfaces.IAdding"
+      template="file_add.pt"
+      class=".file.FileAdd"
       permission="zope.ManageContent"
       />
 

Modified: Zope3/trunk/src/zope/app/file/browser/file.py
===================================================================
--- Zope3/trunk/src/zope/app/file/browser/file.py	2004-08-17 00:01:22 UTC (rev 27159)
+++ Zope3/trunk/src/zope/app/file/browser/file.py	2004-08-17 00:03:35 UTC (rev 27160)
@@ -15,8 +15,16 @@
 
 $Id$
 """
+
+from datetime import datetime
+
+from zope.app import content_types
+from zope.app.file.file import File
+from zope.app.i18n import ZopeMessageIDFactory as _
+
 __docformat__ = 'restructuredtext'
 
+
 class FileView(object):
 
     def show(self):
@@ -29,3 +37,129 @@
                                        self.context.getSize())
 
         return self.context.data
+
+
+class FileUpdateView(object):
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def errors(self):
+        form = self.request.form
+        if "UPDATE_SUBMIT" in form:
+            filename = getattr(form["field.data"], "filename", None)
+            contenttype = form.get("field.contentType")
+            if filename:
+                if not contenttype:
+                    contenttype = content_types.guess_content_type(filename)[0]
+                if not form.get("add_input_name"):
+                    form["add_input_name"] = filename
+            return self.update_object(form["field.data"], contenttype)
+        return ''
+
+
+class FileAdd(FileUpdateView):
+    """View that adds a new File object based on a file upload.
+
+    >>> class FauxAdding(object):
+    ...     def add(self, content):
+    ...         self.content = content
+    ...     def nextURL(self):
+    ...         return 'next url'
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> import StringIO
+    >>> sio = StringIO.StringIO("some data")
+    >>> sio.filename = 'abc.txt'
+
+    Let's make sure we can use the uploaded file name if one isn't
+    specified by the user, and can use the content type when
+    specified.
+
+    >>> request = TestRequest(form={'field.data': sio,
+    ...                             'field.contentType': 'text/foobar',
+    ...                             'UPDATE_SUBMIT': 'Add'})
+    >>> adding = FauxAdding()
+    >>> view = FileAdd(adding, request)
+    >>> view.errors()
+    ''
+    >>> adding.content.contentType
+    'text/foobar'
+    >>> adding.content.data
+    'some data'
+    >>> request.form['add_input_name']
+    'abc.txt'
+
+    Now let's guess the content type, but also use a provided file
+    name for adding the new content object:
+
+    >>> request = TestRequest(form={'field.data': sio,
+    ...                             'field.contentType': '',
+    ...                             'add_input_name': 'splat.txt',
+    ...                             'UPDATE_SUBMIT': 'Add'})
+    >>> adding = FauxAdding()
+    >>> view = FileAdd(adding, request)
+    >>> view.errors()
+    ''
+    >>> adding.content.contentType
+    'text/plain'
+    >>> request.form['add_input_name']
+    'splat.txt'
+
+    """
+
+    def update_object(self, data, contenttype):
+        f = File(data, contenttype)
+        self.context.add(f)
+        self.request.response.redirect(self.context.nextURL())
+        return ''
+
+
+class FileUpload(FileUpdateView):
+    """View that updates an existing File object with a new upload.
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> import StringIO
+    >>> sio = StringIO.StringIO("some data")
+    >>> sio.filename = 'abc.txt'
+
+    Let's make sure we can use the uploaded file name if one isn't
+    specified by the user, and can use the content type when
+    specified.
+
+    >>> request = TestRequest(form={'field.data': sio,
+    ...                             'field.contentType': 'text/foobar',
+    ...                             'UPDATE_SUBMIT': 'Update'})
+    >>> file = File()
+    >>> view = FileUpload(file, request)
+    >>> view.errors()
+    u'Updated on ${date_time}'
+    >>> file.contentType
+    'text/foobar'
+    >>> file.data
+    'some data'
+
+    Now let's guess the content type, but also use a provided file
+    name for adding the new content object:
+
+    >>> request = TestRequest(form={'field.data': sio,
+    ...                             'field.contentType': '',
+    ...                             'add_input_name': 'splat.txt',
+    ...                             'UPDATE_SUBMIT': 'Update'})
+    >>> file = File()
+    >>> view = FileUpload(file, request)
+    >>> view.errors()
+    u'Updated on ${date_time}'
+    >>> file.contentType
+    'text/plain'
+    """
+
+    def update_object(self, data, contenttype):
+        self.context.contentType = contenttype
+        self.context.data = data
+        formatter = self.request.locale.dates.getFormatter(
+            'dateTime', 'medium')
+        status = _("Updated on ${date_time}")
+        status.mapping = {'date_time': formatter.format(datetime.utcnow())}
+        return status

Added: Zope3/trunk/src/zope/app/file/browser/file_add.pt
===================================================================
--- Zope3/trunk/src/zope/app/file/browser/file_add.pt	2004-08-17 00:01:22 UTC (rev 27159)
+++ Zope3/trunk/src/zope/app/file/browser/file_add.pt	2004-08-17 00:03:35 UTC (rev 27160)
@@ -0,0 +1,57 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+  <form action="." tal:attributes="action request/URL"
+        method="POST" enctype="multipart/form-data">
+
+    <h3>Add a File</h3>
+
+    <div tal:define="errors view/errors" tal:content="errors" />
+
+    <div class="row">
+      <div class="label">
+        <label for="field.contentType"
+               title="The content type identifies the type of data."
+          >Content Type</label>
+      </div>
+      <div class="field">
+        <input class="textType"
+               id="field.contentType"
+               name="field.contentType"
+               size="20"
+               type="text"
+               value="" /></div>
+    </div>
+
+    <div class="row">
+      <div class="label">
+        <label for="field.data"
+               title="The actual content of the object.">Data</label>
+      </div>
+      <div class="field">
+        <input class="fileType"
+               id="field.data"
+               name="field.data"
+               size="20"
+               type="file" /></div>
+    </div>
+
+    <div class="row">
+      <div class="controls"><hr />
+
+        <input type="submit" value="Refresh" />
+        <input type="submit" value="Add" name="UPDATE_SUBMIT" />
+
+        &nbsp;&nbsp;<b i18n:translate="">Object Name</b>&nbsp;&nbsp;
+        <input type="text" name="add_input_name" value="" />
+          
+      </div>
+    </div>
+
+  </form>
+
+</div>
+</body>
+
+</html>


Property changes on: Zope3/trunk/src/zope/app/file/browser/file_add.pt
___________________________________________________________________
Name: svn:mime-type
   + text/xml
Name: svn:eol-style
   + native

Added: Zope3/trunk/src/zope/app/file/browser/file_upload.pt
===================================================================
--- Zope3/trunk/src/zope/app/file/browser/file_upload.pt	2004-08-17 00:01:22 UTC (rev 27159)
+++ Zope3/trunk/src/zope/app/file/browser/file_upload.pt	2004-08-17 00:03:35 UTC (rev 27160)
@@ -0,0 +1,59 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+  <form action="." tal:attributes="action request/URL"
+        method="POST" enctype="multipart/form-data">
+
+    <h3>Upload a file</h3>
+
+    <div tal:define="errors view/errors" tal:content="errors" />
+
+    <div class="row">
+      <div class="label">
+        <label for="field.contentType"
+               title="The content type identifies the type of data."
+          >Content Type</label>
+      </div>
+      <div class="field">
+        <input class="textType"
+               id="field.contentType"
+               name="field.contentType"
+               size="20"
+               type="text"
+               value="" />
+      <tal:span i18n:translate="" tal:condition="context/contentType"
+        >(currently
+        <span i18n:name="content-type"
+              tal:replace="context/contentType"/>)</tal:span>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="label">
+        <label for="field.data"
+               title="The actual content of the object.">Data</label>
+      </div>
+      <div class="field">
+        <input class="fileType"
+               id="field.data"
+               name="field.data"
+               size="20"
+               type="file" /></div>
+    </div>
+
+    <div class="row">
+      <div class="controls"><hr />
+
+        <input type="submit" value="Refresh" />
+        <input type="submit" value="Update" name="UPDATE_SUBMIT" />
+          
+      </div>
+    </div>
+
+  </form>
+
+</div>
+</body>
+
+</html>


Property changes on: Zope3/trunk/src/zope/app/file/browser/file_upload.pt
___________________________________________________________________
Name: svn:mime-type
   + text/xml
Name: svn:eol-style
   + native

Added: Zope3/trunk/src/zope/app/file/browser/tests/test_file.py
===================================================================
--- Zope3/trunk/src/zope/app/file/browser/tests/test_file.py	2004-08-17 00:01:22 UTC (rev 27159)
+++ Zope3/trunk/src/zope/app/file/browser/tests/test_file.py	2004-08-17 00:03:35 UTC (rev 27160)
@@ -0,0 +1,27 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Tests for zope.app.file.browser.file.
+
+$Id$
+"""
+import unittest
+
+from zope.testing import doctest
+
+
+def test_suite():
+    return doctest.DocTestSuite("zope.app.file.browser.file")
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")


Property changes on: Zope3/trunk/src/zope/app/file/browser/tests/test_file.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native



More information about the Zope3-Checkins mailing list