Index: /WAeUP_SRP/base/Upload.py
===================================================================
--- /WAeUP_SRP/base/Upload.py	(revision 3277)
+++ /WAeUP_SRP/base/Upload.py	(revision 3277)
@@ -0,0 +1,116 @@
+#-*- mode: python; mode: fold -*-
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+
+from Products.CMFCore.utils import UniqueObject, getToolByName
+from Products.CMFCore.permissions import View
+from Products.CMFCore.permissions import ModifyPortalContent
+from Products.CPSCore.CPSBase import CPSBase_adder, CPSBaseFolder
+#from Products.CPSCore.CPSBase import CPSBaseDocument as BaseDocument
+from Products.CPSDocument.CPSDocument import CPSDocument
+from Products.CPSCore.CPSBase import CPSBaseBTreeFolder as BaseBTreeFolder
+from Products.WAeUP_SRP.WAeUPTables import AccommodationTable,NOT_OCCUPIED
+from WAeUPImport import ApplicationImport,CertificateImport,CertificateCourseImport
+from WAeUPImport import CourseImport,CourseResultImport
+from WAeUPImport import DepartmentImport,FacultyImport,StudentImport,VerdictImport
+import logging
+import csv,re,os
+import Globals
+import DateTime
+import re
+p_home = Globals.package_home(globals())
+i_home = Globals.INSTANCE_HOME
+
+storage_path = "%s/%s" % (i_home,'import')
+
+class UploadsFolder(CPSDocument): ###(
+    """
+    WAeUP UploadsFolder containing Uploads
+    """
+    meta_type = 'UploadsFolder'
+    portal_type = meta_type
+    security = ClassSecurityInfo()
+
+    security.declareProtected(View,"Title")
+    def Title(self):
+        """compose title"""
+        return "Upload Section"
+
+
+InitializeClass(UploadsFolder)
+
+def addUploadsFolder(container, id, REQUEST=None, **kw):
+    """Add a UploadFolder."""
+    ob = UploadsFolder(id, **kw)
+    return CPSBase_adder(container, ob, REQUEST=REQUEST)
+###)
+
+class Upload(CPSDocument): ###(
+    """
+    WAeUP Upload
+    """
+    meta_type = 'Upload'
+    portal_type = meta_type
+    security = ClassSecurityInfo()
+
+    security.declareProtected(View,"Title") ###(
+    def Title(self):
+        """compose title"""
+        return self.title
+    ###)
+
+    security.declareProtected(View,"checkKeys") ###(
+    def checkKeys(self):
+        """check fields in csv-headline"""
+        csv_path = os.path.join(storage_path,self.filename)
+        importer_name = ''.join([part.capitalize() for part in self.getContent().import_layout.split('_')])
+        importer = eval("%sImport" % importer_name)(self)
+        msg = ''
+        invalid_keys = []
+        if not os.path.exists(csv_path):
+            msg = 'No such file %(csv_path)s' % vars()
+        else:
+            headline = csv.reader(open(csv_path,"rb")).next()
+            if "import_mode" not in headline:
+                msg += 'import_mode must be in heading'
+            invalid_keys = importer.checkHeadline(headline)
+            if invalid_keys:
+                msg += "invalid keys in heading"
+        return msg,invalid_keys
+
+    security.declareProtected(View,"checkFields") ###(
+    def getKeys(self):
+        """return the valid keys for headline"""
+        importer_name = ''.join([part.capitalize() for part in self.getContent().import_layout.split('_')])
+        importer = eval("%sImport" % importer_name)(self)
+        keys = importer.schema.keys()
+        keys.sort()
+        return keys
+    
+    security.declareProtected(ModifyPortalContent,"editHeadline") ###(
+    def editHeadline(self,key_pairs):
+        """edit headline"""
+        importer_name = ''.join([part.capitalize() for part in self.getContent().import_layout.split('_')])
+        importer = eval("%sImport" % importer_name)(self)
+        csv_path = os.path.join(storage_path,self.filename)
+        reader = csv.reader(open(csv_path,"rb"))
+        headline = reader.next()
+        records = [record for record in reader]
+        #import pdb;pdb.set_trace()
+        for old,new in key_pairs:
+            pos = headline.index(old)
+            del headline[pos]
+            headline.insert(pos,new)
+        writer = csv.writer(open(csv_path,"w"))
+        writer.writerow(headline)
+        writer.writerows(records)
+        
+        
+InitializeClass(Upload)
+
+
+def addUpload(container, id, REQUEST=None, **kw):
+    """Add a Upload."""
+    ob = Upload(id, **kw)
+    return CPSBase_adder(container, ob, REQUEST=REQUEST)
+###)
Index: /WAeUP_SRP/base/WAeUPImport.py
===================================================================
--- /WAeUP_SRP/base/WAeUPImport.py	(revision 3276)
+++ /WAeUP_SRP/base/WAeUPImport.py	(revision 3277)
@@ -26,5 +26,5 @@
 #from Globals import DTMLFile
 #from Globals import InitializeClass
-#from OFS.SimpleItem import SimpleItem
+from OFS.SimpleItem import SimpleItem
 from zExceptions import BadRequest
 
@@ -33,10 +33,10 @@
 #from Products.CPSSchemas.DataModel import DataModel
 #from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
-#from Products.CMFCore.ActionProviderBase import ActionProviderBase
+from Products.CMFCore.ActionProviderBase import ActionProviderBase
 #from Products.CMFCore.permissions import View
 #from Products.ZCatalog.ZCatalog import ZCatalog
 #from Products.CMFCore.permissions import ModifyPortalContent
 #from Products.CMFCore.permissions import ManagePortal
-#from Products.CMFCore.utils import UniqueObject
+from Products.CMFCore.utils import UniqueObject
 #from Products.CMFCore.URLTool import URLTool
 from Products.CMFCore.utils import getToolByName
@@ -51,14 +51,14 @@
 from utils import makeDigest
 
-class WAeUPImport: ###(
+class WAeUPImport(UniqueObject, SimpleItem, ActionProviderBase): ###(
     """ WAeUPImport """
     required_modes = ('create',)
 
-    def __init__(self,waeup_tool):
+    def __init__(self,waeup_tool): ###(
+        self.students_folder = waeup_tool.portal_url.getPortalObject().campus.students
         self.member = member = waeup_tool.portal_membership.getAuthenticatedMember()
         self.import_date = DateTime.DateTime().strftime("%d/%m/%y %H:%M:%S")
         self.current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
         self.waeup_tool = waeup_tool
-        self.students_folder = waeup_tool.portal_url.getPortalObject().campus.students
         self.academics_folder = waeup_tool.portal_url.getPortalObject().campus.academics
         self.schema_tool = getToolByName(waeup_tool, 'portal_schemas')
@@ -115,6 +115,7 @@
             break
         self.init_errors = ','.join(errors)
-
-    def makeIdLists(self):
+    ###)
+
+    def makeIdLists(self): ###(
         pending_digests = []
         pending = []
@@ -134,5 +135,18 @@
             #copy2(self.pending_path,self.pending_backup)
         return pending, pending_digests
+    ###)
+
+    def checkHeadline(self,headline):
+        """ check the headline of an csv.file """
+        import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
+                                                        or k.strip() in self.info.keys())]
+        diff2schema = set(import_keys).difference(set(self.schema.keys()))
+        diff2layout = set(import_keys).difference(set(self.layout.keys()))
+        #if diff2schema and diff2schema != set(['id',]):
+        if diff2schema:
+            return list(diff2schema)
+        return []
 ###)
+
 
 class ApplicationImport(WAeUPImport):###(
Index: /WAeUP_SRP/base/WAeUPTool.py
===================================================================
--- /WAeUP_SRP/base/WAeUPTool.py	(revision 3276)
+++ /WAeUP_SRP/base/WAeUPTool.py	(revision 3277)
@@ -1467,16 +1467,19 @@
         if not pending_only:
             info['imported_from'] = import_source_fn
-        attrs = csv.reader(open(import_source_path,"rb")).next()
-        if "import_mode" not in attrs:
+        headline = csv.reader(open(import_source_path,"rb")).next()
+        if "import_mode" not in headline:
             msg = 'import_mode must be in heading'
             return msg
-
-        import_keys = [k.strip() for k in attrs if not (k.strip().startswith('ignore')
-                                                        or k.strip() in info.keys())]
-        diff2schema = set(import_keys).difference(set(importer.schema.keys()))
-        diff2layout = set(import_keys).difference(set(importer.layout.keys()))
-        if diff2schema and diff2schema != set(['id',]):
-            msg = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
-            return msg
+        invalid_keys = importer.checkHeadline(headline)
+        if invalid_keys:
+            return 'not ignorable key(s): "%s" found in heading' % ", ".join(invalid_keys)
+
+        # import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
+        #                                                 or k.strip() in info.keys())]
+        # diff2schema = set(import_keys).difference(set(importer.schema.keys()))
+        # diff2layout = set(import_keys).difference(set(importer.layout.keys()))
+        # if diff2schema and diff2schema != set(['id',]):
+        #     msg = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
+        #     return msg
         #
         # start importing
@@ -1495,5 +1498,5 @@
         count = 0
         imported = []
-        old_commit_count = 0
+        old_commit_count = -1
         error_count = imported_count = 0
         already_in = 0
@@ -1581,9 +1584,7 @@
                 logger.info(' '.join(log_list))
             finished = count > total_to_import - 1
-            must_commit = False
-            if len(imported) != old_commit_count:
-                if not len(imported) % commit_after:
-                    must_commit = True
-                    old_commit_count = len(imported)
+            must_commit = (imported_count != old_commit_count) and (not imported_count % commit_after)
+            if must_commit:
+                old_commit_count = imported_count
 
             if must_commit or finished:
Index: /WAeUP_SRP/base/Widgets.py
===================================================================
--- /WAeUP_SRP/base/Widgets.py	(revision 3276)
+++ /WAeUP_SRP/base/Widgets.py	(revision 3277)
@@ -372,4 +372,5 @@
             v = ''
         sessions = self._getSessions()
+        #import pdb;pdb.set_trace()
         if not sessions.has_key(v):
             datastructure.setError(widget_id, "'%s' not a valid session key" % v)
@@ -437,6 +438,6 @@
             return 0
 
-        if not value:
-            v = value = '100'
+        # if not value:
+        #     v = value = '100'
         #import pdb;pdb.set_trace()
         levels = self._getLevels()
@@ -1920,4 +1921,5 @@
         """Get the file info from the datastructure."""
         widget_id = self.getWidgetId()
+        info = None
         if  datastructure.has_key(widget_id):
             fileupload = datastructure[widget_id]
@@ -2148,4 +2150,160 @@
 ###)
 
+class DiscFileWidget(CPSFileWidget): ###(
+    """File widget with filesystem storage."""
+    meta_type = 'Disc File Widget'
+    _properties = CPSFileWidget._properties +\
+    (
+     {'id': 'path', 'type': 'string', 'mode': 'w',
+      'label': 'Relative Path'},
+    )
+    path = "import"
+    storage_path = "%s/%s" % (i_home,path)
+
+    def getStoredFileInfo(self,datastructure): ###(
+        datamodel = datastructure.getDataModel()
+        field_id = self.fields[0]
+        widget_id = self.getWidgetId()
+        file_name = datamodel[field_id]
+        info = {}
+        registry = getToolByName(self, 'mimetypes_registry')
+        info['mimetype'] = registry.lookupExtension('file.csv')
+        info['empty_file'] = True
+        info['size'] = 0
+        info['last_modified'] = ''
+        file_path = os.path.join(self.storage_path, file_name)
+        if os.path.exists(file_path):
+            info['empty_file'] = False
+            info['file_name'] = file_name
+            info['content_url'] = os.path.join(self.portal_url(),
+                                            "viewfile",
+                                            file_name,
+                                            )
+            info['current_filename'] =  file_name
+            # get the mimetype
+            mimetype = (registry.lookupExtension(file_name.lower()) or
+                        registry.lookupExtension('file.bin'))
+            info['mimetype'] = mimetype
+            info['file_path'] = file_path
+        else:
+            info['file_name'] = ''
+            info['content_url'] = ''
+            info['current_filename'] = ''
+            info['file_path'] = ''
+        return info
+        ###)
+    
+    def prepare(self, datastructure, **kw): ###(
+        """Prepare datastructure from datamodel."""
+        datamodel = datastructure.getDataModel()
+        #import pdb;pdb.set_trace()
+        widget_id = self.getWidgetId()
+        file_name = datamodel[self.fields[0]]
+        datastructure[widget_id] = file_name
+        datastructure[widget_id + '_filename'] = file_name
+        datastructure[widget_id+'_choice'] = "keep"
+    ###)
+
+    def validate(self, datastructure, **kw): ###(
+        """Update datamodel from user data in datastructure.
+        """
+        logger = logging.getLogger('Widgets.DiscFileWidget.validate')
+        datamodel = datastructure.getDataModel()
+        field_id = self.fields[0]
+        widget_id = self.getWidgetId()
+        store = False
+        fileupload = None
+        mimetype = None
+        old_file = datamodel[field_id]
+        choice = datastructure[widget_id+'_choice']
+        fileupload = datastructure[widget_id]
+        is_upload = isinstance(fileupload, FileUpload)
+        if not is_upload and not datamodel[field_id]:
+            if self.is_required:
+                return self.validateError('File upload required', {},
+                                          datastructure)
+        if choice == 'delete':
+            if self.is_required:
+                return self.validateError('cpsschemas_err_required', {},
+                                          datastructure)
+            info = self.getStoredFileInfo(datastructure)
+            # Remove the file in the filesystem
+            if info:
+                os.remove(info['file_path'])
+            datamodel[field_id] = None
+        elif choice == 'keep':
+            fileupload = datastructure[widget_id]
+            if isinstance(fileupload, PersistableFileUpload):
+                # Keeping something from the session means we
+                # actually want to store it.
+                store = True
+            # else:
+            #     # Nothing to change, don't pollute datastructure
+            #     # with something costly already stored, which therefore
+            #     # doesn't need to be kept in the session.
+            #     self.unprepare(datastructure)
+        elif choice == 'change' and is_upload:
+            if not fileupload:
+                return self.validateError('cpsschemas_err_file_empty', {},
+                                          datastructure)
+            if not isinstance(fileupload, FileUpload):
+                return self.validateError('cpsschemas_err_file', {},
+                                          datastructure)
+            fileupload.seek(0, 2) # end of file
+            size = fileupload.tell()
+            if not size:
+                return self.validateError('cpsschemas_err_file_empty', {},
+                                          datastructure)
+            if self.size_max and size > self.size_max:
+                max_size_str = self.getHumanReadableSize(self.size_max)
+                err = 'This file is too big, the allowed max size is ${max_size}'
+                member_id = str(self.portal_membership.getAuthenticatedMember())
+                logger.info('%s tried to upload picture with size %dk' %(member_id,int(size)/1000) )
+                err_mapping = {'max_size': max_size_str}
+                return self.validateError(err, err_mapping, datastructure)
+            store = True
+
+
+        # Find filename
+        if is_upload and store:
+            filename = cookId('', '', fileupload)[0].strip()
+            base,ext = os.path.splitext(filename)
+            if ext not in ("csv",".csv"):
+                return self.validateError('only csv files allowed', {},
+                                          datastructure)
+            datamodel[field_id] = filename
+            registry = getToolByName(self, 'mimetypes_registry')
+            mimetype = registry.lookupExtension(filename.lower())
+            if mimetype is not None:
+                mimetype = str(mimetype) # normalize
+            file = self.makeFile(filename, fileupload, datastructure)
+            # Fixup mimetype
+            if mimetype and file.content_type != mimetype:
+                file.content_type = mimetype
+            file_path = os.path.join(self.storage_path,filename)
+            #import pdb; pdb.set_trace()
+            data = open(file_path,"w")
+            data.write(str(file.data))
+            data.close()
+        return True
+    ###)
+
+    def render(self, mode, datastructure, **kw): ###(
+        render_method = 'widget_uploadfile_render'
+        meth = getattr(self, render_method, None)
+        #import pdb;pdb.set_trace()
+        if meth is None:
+            raise RuntimeError("Unknown Render Method %s for widget type %s"
+                               % (render_method, self.getId()))
+        file_info = self.getStoredFileInfo(datastructure)
+
+        return meth(mode=mode, datastructure=datastructure, **file_info)
+    ###)
+
+InitializeClass(DiscFileWidget)
+
+widgetRegistry.register(DiscFileWidget)
+###)
+
 ###########
 
Index: /WAeUP_SRP/base/__init__.py
===================================================================
--- /WAeUP_SRP/base/__init__.py	(revision 3276)
+++ /WAeUP_SRP/base/__init__.py	(revision 3277)
@@ -88,4 +88,9 @@
         )
      ),
+     ("Upload",
+        ("UploadsFolder",
+         "Upload",
+         )
+     ),
     )
 
Index: /WAeUP_SRP/base/exportimport.py
===================================================================
--- /WAeUP_SRP/base/exportimport.py	(revision 3276)
+++ /WAeUP_SRP/base/exportimport.py	(revision 3277)
@@ -79,4 +79,5 @@
         students = getattr(campus,'students',None)
         accommodation = getattr(campus,'accommodation',None)
+        upload = getattr(campus,'upload',None)
         campus.manage_setLocalGroupRoles(groupid='CampusOfficers',
                                          roles=('SectionOfficer',))
@@ -103,4 +104,7 @@
                                          roles=('SectionReader',))
             accommodation.manage_setLocalGroupRoles(groupid='AccommodationOfficers',
+                                         roles=('SectionOfficer',))
+        if upload is not None:
+            upload.manage_setLocalGroupRoles(groupid='CampusOfficers',
                                          roles=('SectionOfficer',))
     members = getattr(site.portal_directories,'members')
Index: /WAeUP_SRP/base/skins/waeup_upload/uploads_form.pt
===================================================================
--- /WAeUP_SRP/base/skins/waeup_upload/uploads_form.pt	(revision 3277)
+++ /WAeUP_SRP/base/skins/waeup_upload/uploads_form.pt	(revision 3277)
@@ -0,0 +1,109 @@
+<metal:html tal:define="info options/info;
+            portal_status_message options/psm;
+            ds options/ds;
+            mode options/mode;
+            rendered options/rendered;"
+            >
+  <metal:body use-macro="here/main_template/macros/master">
+    <metal:block fill-slot="header">
+      <a href=""
+         tal:attributes="href string:${here/academicsParent}">
+        <img tal:attributes="src string:${here/portal_url}/arrow_up.gif"/>
+        Up one level
+      </a>
+      <h3 tal:content="here/title_or_id" />
+      <div tal:condition="python:0" tal:content="info/container_path"/>
+      <br />
+    </metal:block>
+    <metal:main fill-slot="main">
+      <form action="" method="post" enctype="multipart/form-data" class="group">
+        <span tal:replace="structure rendered" />
+        <input type="submit" name="upload" value="upload"
+               class="destructive" />
+      </form>
+      <form action="" method="post" class="group"
+            tal:attributes="action info/action"
+            tal:define="rows python: info['items'];"
+            >
+        <table tal:condition="python: 1" class="contentListing" width="100%" summary="content layout" id="folder_content">      
+          <tr>
+            <th></th>
+            <th>Filename</th>
+            <th>Schema</th>
+            <th>Uploaded by</th>
+            <th>Upload Date</th>
+            <th>Message</th>
+            <th>Invalid Keys</th>
+          </tr>            
+          <tr tal:repeat="row rows"
+            tal:attributes="class python:test(repeat['row'].even(), 'even ajaxtd', 'odd ajaxtd')">
+            <td align="left" valign="middle" style="width: 5px;">
+              <input type="checkbox" name="ids:list" value="" id="" class="noborder"
+                     tal:define="id row/id"
+                     tal:attributes="value id;
+                     id python:'cb_' + id;
+                     checked python:id in info['choosen_ids'];" 
+                     />
+            </td>
+            <td tal:condition="nothing"> <a href="view" tal:attributes="href string:${row/url}"> <span tal:content="row/id" /></a>  </td>
+            <td tal:content="row/id" ></td>
+            <td>
+              <select name="import_layout:record" tal:attributes="name string:${row/id}.import_layout:record">
+                <option tal:repeat="option python: context.portal_vocabularies.import_names.items()"
+                        tal:attributes="value python: option[0];
+                        selected python: option[0] == row['import_layout']" 
+                        tal:content="python:option[1]" />
+              </select>
+            </td>
+            <td tal:content="row/uploaded_by" ></td>
+            <td tal:content="row/upload_date" ></td>
+            <td tal:content="row/msg" ></td>
+            <td>
+              <span tal:repeat="key row/invalid_keys">
+                <span tal:replace="key" />
+                <select tal:attributes="name string:${row/id}|${key}.valid_key:record">
+                  <option tal:repeat="new row/valid_keys"
+                          tal:attributes="value new"
+                          tal:content="new" />
+                </select>
+              </span>
+            </td>
+            <td tal:condition="nothing"> 
+            <a href="edit" tal:attributes="href string:${row/url}/external_edit_form"
+                target="edit"
+                onclick="javascript:window.open('','edit','width=600, height=700, directories=no, toolbar=no, location=no, menubar=no, scrollbars=yes, status=no, resizable=no, dependent=no')">
+                [edit]
+                </a> 
+            </td>
+
+          </tr>
+        </table>
+        <table width="100%" cellspacing="0" cellpadding="2"
+               summary="contents of the folder"
+               class="folderButtons">
+          <tr>
+            <td align="left" valign="top" rowspan="3"></td>
+            <td align="left" valign="top">
+                <input tal:condition="nothing" type="button" value="button_select_all" class="context"
+                       onclick="someJavaScriptFunctionThatWillBeReplaced"
+                       i18n:attributes="value"
+                       tal:attributes="onclick python:'toggleSelect(this, \'%s\', \'%s\')'
+                       % (cpsmcat('button_select_all'), cpsmcat('button_deselect_all'))"
+                       />
+                <input type="submit" name="edit" value="edit"
+                       class="destructive" i18n:attributes="value"
+                       />
+                <input type="submit" name="folder_delete:method" value="button_delete"
+                       class="destructive" i18n:attributes="value"
+                       tal:attributes="onclick python:'return window.confirm(\'%s\')' %
+                       (cpsmcat('description_confirm_delete'), )" 
+                       />
+            </td>
+          </tr>
+        </table>
+      </form>
+    </metal:main>
+    
+    <metal:sub fill-slot="sub"/>
+  </metal:body>
+</metal:html>
Index: /WAeUP_SRP/base/skins/waeup_upload/uploads_index.py
===================================================================
--- /WAeUP_SRP/base/skins/waeup_upload/uploads_index.py	(revision 3277)
+++ /WAeUP_SRP/base/skins/waeup_upload/uploads_index.py	(revision 3277)
@@ -0,0 +1,107 @@
+## Script (Python) "getUploadsInfo"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=student=None
+##title=
+##
+# $Id:getUploadsInfo.py 486 2006-09-06 10:09:39Z joachim $
+"""
+return Info about the Uploads
+"""
+import DateTime
+try:
+    from Products.zdb import set_trace
+except:
+    def set_trace():
+        pass
+request = context.REQUEST
+
+wf = context.portal_workflow
+mtool = context.portal_membership
+member = mtool.getAuthenticatedMember()
+
+path_info = request.get('PATH_INFO').split('/')
+
+info = {}
+info['action'] = "%s" % context.absolute_url()
+info['choosen_ids'] = request.get('ids',[])
+info['doc'] = context.getContent()
+
+items = []
+edit = request.form.has_key('edit')
+ids = request.get('ids',[])
+#set_trace()
+if edit and ids:
+    for id in ids:
+        doc = getattr(context, "%s.csv" % id).getContent()
+        doc.edit(mapping = request.form[id])
+        msg, invalid_keys = doc['checkKeys']()
+        new_keys = []
+        for key in invalid_keys:
+            id_key = "%s|%s" % (id,key)
+            if request.form.has_key(id_key):
+                new_keys += (key,request.form.get(id_key)['valid_key']),
+        if new_keys:
+            doc.editHeadline(new_keys)
+        request.RESPONSE.redirect(context.absolute_url())    
+        
+for id,upload in context.objectItems():
+    row = {}
+    doc = upload.getContent()
+    row['valid_keys'] = doc['getKeys']()
+    row['id'] = id.replace('.csv','')
+    row['title'] = doc.filename
+    row['url'] = upload.absolute_url()
+    row['msg'], row['invalid_keys'] = doc['checkKeys']()
+    row['filename'] = doc.filename 
+    row['import_layout'] = doc.import_layout
+    row['upload_date'] =  doc.upload_date.strftime("%d/%m/%y %H:%M:%S")
+    row['uploaded_by'] = doc.uploaded_by
+    items.append(row)
+items.sort()
+info['items'] = items
+
+validate = "upload" in request.keys()
+mode = "edit"
+res,psm,ds = context.portal_layouts.renderLayout(layout_id = 'upload',
+                             schema_id = 'upload',
+                             layout_mode = mode,
+                             context=context,
+                             mapping=validate and request,
+                             ob= {},
+                             commit = True,
+                            )
+if psm == 'invalid':
+    return context.uploads_form(rendered = res,
+                                 psm = "Please correct your input!",
+                                 mode = mode,
+                                 ds = ds,
+                                 info = info,
+                                )
+elif psm == '':
+    return context.uploads_form(rendered = res,
+                                        psm = psm,
+                                        ds = ds,
+                                        mode = mode,
+                                        info = info,
+                                       )
+elif psm == 'valid':
+    pass
+filename = ds['upload_file'].filename
+
+if filename not in context.objectIds():
+    context.invokeFactory('Upload',filename)
+    upload = getattr(context,filename)
+    d = {}
+    d['filename'] = d['id'] = filename 
+    d['upload_date'] =  DateTime.DateTime()
+    d['import_layout'] = ds.get('import_layout','')
+    d['uploaded_by'] = str(member)
+    d['url'] = upload.absolute_url()
+    upload.getContent().edit(mapping=d)
+    #info['items'].append(d)
+request.RESPONSE.redirect(context.absolute_url())    
+
Index: /WAeUP_SRP/base/skins/waeup_upload/widget_uploadfile_render.pt
===================================================================
--- /WAeUP_SRP/base/skins/waeup_upload/widget_uploadfile_render.pt	(revision 3277)
+++ /WAeUP_SRP/base/skins/waeup_upload/widget_uploadfile_render.pt	(revision 3277)
@@ -0,0 +1,99 @@
+<tal:block define="mode options/mode;
+  id here/getWidgetId;
+  current_filename options/current_filename;
+  empty_file options/empty_file;
+  session_file options/session_file|nothing;
+  mimetype options/mimetype;
+  size options/size;
+  content_url options/content_url;
+  last_modified options/last_modified;
+  content_url_nocache string:${content_url}?nocache=${last_modified};
+  ">
+
+  <tal:block condition="python: mode == 'view' and not empty_file">
+    <metal:block define-macro="file_view">
+      <a tal:condition="mimetype"
+        tal:attributes="
+        href content_url_nocache;
+        onClick string:return openLinkInPopup('${content_url_nocache}');
+        ">
+        <img tal:replace="structure python:here.getImgTag(mimetype.icon_path,
+          title=mimetype.name())" /></a>
+      <a class="strong"
+        tal:attributes="href content_url_nocache">
+        <tal:block replace="current_filename" /></a>
+      <span tal:condition="size" class="note"
+        tal:define="str_size python:here.getHumanReadableSize(size);">
+        <tal:block content="str_size"/>
+      </span>
+    </metal:block>
+  </tal:block>
+
+  <tal:block condition="python: mode == 'edit'">
+
+    <metal:block define-macro="file_size_max_view">
+      <tal:block define="size_max python:here.size_max;
+                         str_sizeMax python:here.getHumanReadableSize(size_max)"
+        condition="python:size_max > 0">
+
+        <p i18n:translate="">
+          cpsschemas_size_max
+          <tal:block i18n:name="size_max" content="str_sizeMax"/>
+        </p>
+      </tal:block>
+    </metal:block>
+
+    <metal:block define-macro="file_edit">
+
+      <ul class="fileChoice"
+          tal:define="name here/getHtmlWidgetId;
+                      radio_name string:${name}_choice;"
+                      >
+      <li>
+        <metal:block define-slot="keep_file" tal:condition="nothing">
+          <input type="radio" class="noborder" name="." value="keep"
+                 checked="checked"
+                 tal:attributes="name radio_name;
+                 id string:${radio_name}_keep;"
+                 />
+          <label i18n:translate="cpsschemas_label_file_none"
+                 tal:condition="empty_file"
+                 tal:attributes="for string:${radio_name}_keep">None</label>
+          <label i18n:translate="cpsschemas_label_file_keep"
+                 tal:condition="not:empty_file"
+                 tal:attributes="for string:${radio_name}_keep">Keep</label>
+        </metal:block>
+      </li>
+      <metal:block define-slot="edit_file_action" />
+      <li>
+        <metal:block define-slot="change_file">
+          <input type="hidden" class="noborder"  name="." value="change"
+                 tal:attributes="name radio_name;
+                 id string:${radio_name}_change" 
+                 />
+          <label i18n:translate="cpsschemas_label_file_change"
+                 tal:attributes="for string:${radio_name}_change">Change</label>
+          <input type="file" name="." size="24"
+                 tal:attributes="name name;
+                 onclick string:document.getElementById('${radio_name}_change').checked='checked'" 
+                 />
+        </metal:block>
+      </li>
+      </ul>
+    </metal:block>
+
+    <metal:block define-macro="file_title_edit" tal:condition="nothing">
+      <p tal:define="name here/getHtmlWidgetId;
+                     title_name string:${name}_filename;">
+        <span i18n:translate="cpsschemas_label_filename">
+          Filename
+        </span>
+        <input style="margin-left: 5px" type="text" size="30" maxlength="80"
+               tal:attributes="name title_name;
+                               value current_filename" />
+      </p>
+    </metal:block>
+
+  </tal:block>
+
+</tal:block>
Index: /WAeUP_SRP/uniben/profiles/default/layouts.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/layouts.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/layouts.xml	(revision 3277)
@@ -59,4 +59,5 @@
   <object name="study_level" meta_type="CPS Layout"/>
   <object name="university" meta_type="CPS Layout"/>
+  <object name="upload" meta_type="CPS Layout"/>
   <object name="waeup_common" meta_type="CPS Layout"/>
 </object>
Index: /WAeUP_SRP/uniben/profiles/default/layouts/upload.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/layouts/upload.xml	(revision 3277)
+++ /WAeUP_SRP/uniben/profiles/default/layouts/upload.xml	(revision 3277)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<object name="import_data" meta_type="CPS Layout">
+ <property name="layout_create_method"></property>
+ <property name="layout_edit_method"></property>
+ <property name="layout_view_method"></property>
+ <property name="style_prefix">layout_waeup_</property>
+ <property name="flexible_widgets"/>
+ <property name="validate_values_expr"></property>
+  <widget name="upload_file" meta_type="Disc File Widget">
+    <property name="title">Upload File</property>
+    <property name="fields">
+      <element value="filename"/>
+    </property>
+    <property name="is_required">True</property>
+    <property name="label">Upload File</property>
+    <property name="label_edit">Upload File</property>
+    <property name="readonly_layout_modes"/>
+    <property name="hidden_layout_modes">
+      <element value="create"/>
+    </property>
+    <property name="hidden_readonly_layout_modes"/>
+    <property name="size_max">0</property>
+    <property name="display_external_editor">False</property>
+  </widget>
+ <widget name="import_layout" meta_type="Select Widget">
+  <property name="title">Import Layout</property>
+  <property name="fields">
+   <element value="import_layout"/>
+  </property>
+  <property name="is_required">False</property>
+  <property name="label">Import Layout</property>
+  <property name="label_edit">Import Layout</property>
+  <property name="readonly_layout_modes"/>
+  <property name="hidden_layout_modes"/>
+  <property name="hidden_readonly_layout_modes"/>
+  <property name="vocabulary">import_names</property>
+ </widget>
+ <table>
+  <row>
+   <cell name="upload_file" />
+  </row>
+  <row>
+   <cell name="import_layout" />
+  </row>
+ </table>
+</object>
Index: /WAeUP_SRP/uniben/profiles/default/roots/campus.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/roots/campus.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/roots/campus.xml	(revision 3277)
@@ -6,4 +6,5 @@
   <object name="students" portal_type="StudentsFolder" />
   <object name="pins" portal_type="ScratchCardBatchesFolder" />
+  <object name="uploads" portal_type="UploadsFolder" />
   <object name="documents" portal_type="DocumentsFolder" />
 </object>
Index: /WAeUP_SRP/uniben/profiles/default/roots/campus/upload.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/roots/campus/upload.xml	(revision 3277)
+++ /WAeUP_SRP/uniben/profiles/default/roots/campus/upload.xml	(revision 3277)
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<object name="upload">
+  <property name="Title">Uploads</property>
+</object>
Index: /WAeUP_SRP/uniben/profiles/default/schemas.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/schemas.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/schemas.xml	(revision 3277)
@@ -44,4 +44,5 @@
  <object name="study_level" meta_type="CPS Schema"/>
  <object name="university" meta_type="CPS Schema"/>
+ <object name="upload" meta_type="CPS Schema"/>
  <object name="waeup_common" meta_type="CPS Schema"/>
 </object>
Index: /WAeUP_SRP/uniben/profiles/default/skins.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/skins.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/skins.xml	(revision 3277)
@@ -33,4 +33,6 @@
  <object name="waeup_documents" meta_type="Filesystem Directory View"
     directory="WAeUP_SRP/skins/waeup_documents"/>
+ <object name="waeup_upload" meta_type="Filesystem Directory View"
+    directory="WAeUP_SRP/skins/waeup_upload"/>
 
  <skin-path name="CPSSkins">
@@ -45,4 +47,5 @@
   <layer name="waeup_academics" insert-after="waeup_custom"/>
   <layer name="waeup_documents" insert-after="waeup_custom"/>
+  <layer name="waeup_upload" insert-after="waeup_custom"/>
   <layer name="waeup_accommodation" insert-after="waeup_custom"/>
   <layer name="waeup_utilities" insert-after="waeup_custom"/>
Index: /WAeUP_SRP/uniben/profiles/default/types.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/types.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/types.xml	(revision 3277)
@@ -33,3 +33,5 @@
  <object name="DocumentsFolder" meta_type="CPS Flexible Type Information"/>
  <object name="WAeUPDocument" meta_type="CPS Flexible Type Information"/>
+ <object name="UploadsFolder" meta_type="CPS Flexible Type Information"/>
+ <object name="Upload" meta_type="CPS Flexible Type Information"/>
 </object>
Index: /WAeUP_SRP/uniben/profiles/default/types/Upload.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/types/Upload.xml	(revision 3277)
+++ /WAeUP_SRP/uniben/profiles/default/types/Upload.xml	(revision 3277)
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="types.xsl"?>
+<object name="Upload" meta_type="CPS Flexible Type Information"
+   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title">Upload Data</property>
+ <property name="description"></property>
+ <property name="content_icon"></property>
+ <property name="content_meta_type">Upload</property>
+ <property name="product">WAeUP_SRP</property>
+ <property name="factory">addUpload</property>
+ <property name="immediate_view">student_index</property>
+ <property name="global_allow">True</property>
+ <property name="filter_content_types">True</property>
+ <property name="allowed_content_types"/>
+ <property name="allow_discussion">False</property>
+ <property name="cps_is_searchable">False</property>
+ <property name="cps_proxy_type">folder</property>
+ <property name="cps_display_as_document_in_listing">True</property>
+ <property name="schemas">
+  <element value="upload"/>
+ </property>
+ <property name="layouts">
+  <element value="upload"/>
+ </property>
+ <property name="layout_clusters"/>
+ <property name="flexible_layouts"/>
+ <property name="storage_methods"/>
+ <property name="cps_is_portlet">False</property>
+ <alias from="(Default)" to="student_index"/>
+ <alias from="view" to="upload_view"/>
+ <action title="View" action_id="view" category="object" condition_expr=""
+    url_expr="string:${object_url}/upload_view" visible="True">
+  <permission value="View"/>
+ </action>
+ <action title="action_edit" action_id="edit" category="object"
+    condition_expr="" url_expr="string:${object_url}/waeup_edit_form"
+    visible="False">
+  <permission value="Modify portal content"/>
+ </action>
+</object>
Index: /WAeUP_SRP/uniben/profiles/default/types/UploadsFolder.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/types/UploadsFolder.xml	(revision 3277)
+++ /WAeUP_SRP/uniben/profiles/default/types/UploadsFolder.xml	(revision 3277)
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="types.xsl"?>
+<object name="UploadsFolder" meta_type="CPS Flexible Type Information"
+   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title">WAeUP Uploads Folder</property>
+ <property name="description"></property>
+ <property name="content_icon"></property>
+ <property name="content_meta_type">UploadsFolder</property>
+ <property name="product">WAeUP_SRP</property>
+ <property name="factory">addUploadsFolder</property>
+ <property name="immediate_view">student_index</property>
+ <property name="global_allow">True</property>
+ <property name="filter_content_types">True</property>
+ <property name="allowed_content_types">
+  <element value="Upload"/>
+ </property>
+ <property name="allow_discussion">False</property>
+ <property name="cps_is_searchable">False</property>
+ <property name="cps_proxy_type">btreefolder</property>
+ <property name="cps_display_as_document_in_listing">True</property>
+ <property name="schemas">
+  <element value="metadata"/>
+  <element value="common"/>
+ </property>
+ <property name="layouts"/>
+ <property name="layout_clusters"/>
+ <property name="flexible_layouts"/>
+ <property name="storage_methods"/>
+ <property name="cps_is_portlet">False</property>
+ <alias from="(Default)" to="uploads_index"/>
+ <alias from="view" to="uploads_index"/>
+ <action title="View" action_id="view" category="object" condition_expr=""
+    url_expr="string:${object_url}/uploads_index" visible="True">
+  <permission value="View"/>
+ </action>
+</object>
Index: /WAeUP_SRP/uniben/profiles/default/workflows.xml
===================================================================
--- /WAeUP_SRP/uniben/profiles/default/workflows.xml	(revision 3276)
+++ /WAeUP_SRP/uniben/profiles/default/workflows.xml	(revision 3277)
@@ -121,4 +121,10 @@
    <bound-workflow workflow_id="waeup_section_wf"/>
   </type>
+  <type type_id="UploadsFolder">
+   <bound-workflow workflow_id="waeup_section_wf"/>
+  </type>
+  <type type_id="Upload">
+   <bound-workflow workflow_id="waeup_base_wf"/>
+  </type>
   <type type_id="Workspace">
    <bound-workflow workflow_id="workspace_folder_wf"/>
