| 1 | from Products.CMFCore.interfaces import ISiteRoot |
|---|
| 2 | from collective.imstransport import IMSTransportMessageFactory as _ |
|---|
| 3 | from zope.interface import implements |
|---|
| 4 | from collective.imstransport.utilities.interfaces import IIMSManifestReader, IIMSManifestWriter |
|---|
| 5 | import md5 |
|---|
| 6 | from zope.component import getUtility |
|---|
| 7 | import re |
|---|
| 8 | |
|---|
| 9 | class IMSReader(object): |
|---|
| 10 | """ Base class for IMS reader objects. """ |
|---|
| 11 | |
|---|
| 12 | implements(IIMSManifestReader) |
|---|
| 13 | |
|---|
| 14 | def getPackageName(self): |
|---|
| 15 | """ Return the desciptive name of the package type. """ |
|---|
| 16 | return None |
|---|
| 17 | |
|---|
| 18 | def readPackage(self, file, context): |
|---|
| 19 | """ Read IMS manifest. Override this to read specific package info. """ |
|---|
| 20 | |
|---|
| 21 | # Helper functions for readPackage |
|---|
| 22 | |
|---|
| 23 | def createIdFromFile(self, file): |
|---|
| 24 | """ Get Id from file path """ |
|---|
| 25 | return file.split('/')[-1] |
|---|
| 26 | |
|---|
| 27 | def createPathFromFile(self, file): |
|---|
| 28 | """ Get folder path from file path """ |
|---|
| 29 | return '/'.join(file.split('/')[:-1]) |
|---|
| 30 | |
|---|
| 31 | def determineType(self, item, fn): |
|---|
| 32 | result = 'File' |
|---|
| 33 | docmimetypes = ['text/html', 'text/htm' 'text/plain' 'text/x-rst', 'text/structured'] |
|---|
| 34 | |
|---|
| 35 | if item.has_key('type'): |
|---|
| 36 | result = type |
|---|
| 37 | elif item.has_key('Format') and item['Format'] in docmimetypes: |
|---|
| 38 | result = 'Document' |
|---|
| 39 | elif item.has_key('Format') and 'image' in item['Format']: |
|---|
| 40 | result = 'Image' |
|---|
| 41 | else: |
|---|
| 42 | """ Determine the file mimetype """ |
|---|
| 43 | site = getUtility(ISiteRoot) |
|---|
| 44 | mtr = site.mimetypes_registry |
|---|
| 45 | mimetype = mtr.lookupExtension(filename) |
|---|
| 46 | |
|---|
| 47 | if mimetype in docmimetypes: |
|---|
| 48 | result = 'Document' |
|---|
| 49 | elif 'image' in mimetype: |
|---|
| 50 | result = 'Image' |
|---|
| 51 | return result |
|---|
| 52 | |
|---|
| 53 | |
|---|
| 54 | class IMSWriter(object): |
|---|
| 55 | """ Base class for IMS writer objects. """ |
|---|
| 56 | |
|---|
| 57 | implements(IIMSManifestWriter) |
|---|
| 58 | |
|---|
| 59 | def _writeObjectData(self, obj, path): |
|---|
| 60 | """ Write file data to the destination object. """ |
|---|
| 61 | if type(obj) == type(''): |
|---|
| 62 | data = obj |
|---|
| 63 | else: |
|---|
| 64 | format = '' |
|---|
| 65 | if hasattr(obj.aq_explicit, 'Format'): |
|---|
| 66 | format = obj.Format() |
|---|
| 67 | if obj.Type() in ['File', 'Image'] and hasattr(obj.aq_explicit, 'data'): |
|---|
| 68 | data = obj.data |
|---|
| 69 | elif 'text/html' == format and hasattr(obj.aq_explicit, 'getText'): |
|---|
| 70 | data = obj.getText() |
|---|
| 71 | elif format in ['text/plain', 'text/x-rst', 'text/structured'] and hasattr(obj.aq_explicit, 'getRawText'): |
|---|
| 72 | data = obj.getRawText() |
|---|
| 73 | else: |
|---|
| 74 | data = '' |
|---|
| 75 | |
|---|
| 76 | if self.destination: |
|---|
| 77 | self.destination.writeFile(path, data) |
|---|
| 78 | |
|---|
| 79 | def _getAllObjects(self, context): |
|---|
| 80 | """ Get all sub objects. """ |
|---|
| 81 | objects = [obj.getObject() for obj in context.portal_catalog.searchResults(path={'query':('/'.join(context.getPhysicalPath())+'/'),'depth':-1})] |
|---|
| 82 | return [object for object in objects if not object.isPrincipiaFolderish or getattr(object.aq_explicit, 'getText', None)] |
|---|
| 83 | |
|---|
| 84 | def _getChildrenObjects(self, parent, objects): |
|---|
| 85 | """ Get objects in current folder """ |
|---|
| 86 | parentpath = '/'.join(parent.getPhysicalPath()) |
|---|
| 87 | children = [] |
|---|
| 88 | for object in objects: |
|---|
| 89 | rpath = '/'.join(object.getPhysicalPath()).replace(parentpath, '') |
|---|
| 90 | |
|---|
| 91 | if len(rpath.split('/')) == 1: |
|---|
| 92 | children.append(object) |
|---|
| 93 | |
|---|
| 94 | return children |
|---|
| 95 | |
|---|
| 96 | def _getObjectPath(self, obj, context): |
|---|
| 97 | """ Get the path of an object. """ |
|---|
| 98 | |
|---|
| 99 | root_path = context.aq_explicit.virtual_url_path() |
|---|
| 100 | obj_path = obj.aq_explicit.virtual_url_path() |
|---|
| 101 | |
|---|
| 102 | if obj_path.find(root_path) != 0: |
|---|
| 103 | return '' |
|---|
| 104 | |
|---|
| 105 | # Remove the path of the folder object |
|---|
| 106 | path = obj_path.replace(root_path, '') |
|---|
| 107 | if path and path[0] == '/': |
|---|
| 108 | path = path[1:] |
|---|
| 109 | |
|---|
| 110 | if not path: |
|---|
| 111 | return '' |
|---|
| 112 | |
|---|
| 113 | if hasattr(obj.aq_explicit, 'Format'): |
|---|
| 114 | if 'text/html' == obj.Format() and obj.isPrincipiaFolderish: |
|---|
| 115 | path += '.html' |
|---|
| 116 | |
|---|
| 117 | return path |
|---|
| 118 | |
|---|
| 119 | def _createPathId(self, path, pre='RES'): |
|---|
| 120 | """ Create a unique id given a path """ |
|---|
| 121 | return pre + str(md5.md5(path).hexdigest()) |
|---|
| 122 | |
|---|
| 123 | def _getCopyrightString(self, copyright, rights_holder, rights_holder_email): |
|---|
| 124 | cp = '' |
|---|
| 125 | if copyright: |
|---|
| 126 | cp += copyright |
|---|
| 127 | if rights_holder: |
|---|
| 128 | if cp: |
|---|
| 129 | cp += ', ' |
|---|
| 130 | cp += rights_holder |
|---|
| 131 | if rights_holder_email: |
|---|
| 132 | if cp: |
|---|
| 133 | cp += ', ' |
|---|
| 134 | cp += rights_holder_email |
|---|
| 135 | return cp |
|---|
| 136 | |
|---|
| 137 | def getObjSize(self, object): |
|---|
| 138 | """ Retrieves the correct size of the object""" |
|---|
| 139 | return '%d' %object.get_size() |
|---|
| 140 | |
|---|
| 141 | def writeCustomMetadata(self, object): |
|---|
| 142 | """ Write the custom metdata for the package. Overridden at lower levels. """ |
|---|
| 143 | |
|---|
| 144 | return |
|---|
| 145 | |
|---|
| 146 | |
|---|
| 147 | |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | class IMSInterchangeReader(object): |
|---|
| 151 | |
|---|
| 152 | implements(IIMSManifestReader) |
|---|
| 153 | name = _(u'IMS Interchange Reader') |
|---|
| 154 | |
|---|
| 155 | def determineType(self, context, hashref, objDict, filename): |
|---|
| 156 | """ Determine the type of the incoming object """ |
|---|
| 157 | |
|---|
| 158 | if objDict[hashref].has_key('type') and objDict[hashref]['type']: |
|---|
| 159 | return objDict[hashref]['type'] |
|---|
| 160 | elif objDict[hashref].has_key('Format') and objDict[hashref]['Format'] in ['text/html', 'text/htm' 'text/plain' 'text/x-rst', 'text/structured']: |
|---|
| 161 | return 'Document' |
|---|
| 162 | elif objDict[hashref].has_key('Format') and re.match('^image', objDict[hashref]['Format']): |
|---|
| 163 | return 'Image' |
|---|
| 164 | else: |
|---|
| 165 | return self.determineFileMimetype(filename, context) |
|---|
| 166 | |
|---|
| 167 | def createIdFromFile(self, file): |
|---|
| 168 | """ Get Id from file path """ |
|---|
| 169 | return file.split('/')[-1] |
|---|
| 170 | |
|---|
| 171 | def createPathFromFile(self, file): |
|---|
| 172 | """ Get folder path from file path """ |
|---|
| 173 | return '/'.join(file.split('/')[:-1]) |
|---|
| 174 | |
|---|
| 175 | |
|---|
| 176 | def determineFileMimetype(self, name, context): |
|---|
| 177 | """ Determine the file mimetype """ |
|---|
| 178 | portal = context.portal_url.getPortalObject() |
|---|
| 179 | registry = portal.mimetypes_registry |
|---|
| 180 | mimetype = registry.lookupExtension(name) |
|---|
| 181 | |
|---|
| 182 | if mimetype and mimetype.major() == 'text' and mimetype.minor() == 'html': |
|---|
| 183 | return 'Document' |
|---|
| 184 | elif mimetype and mimetype.major() == 'image': |
|---|
| 185 | return 'Image' |
|---|
| 186 | else: |
|---|
| 187 | return 'File' |
|---|
| 188 | |
|---|
| 189 | def parseFile(self, context, file, objDict, hashref, id, path): |
|---|
| 190 | """ parse a file object and add data to it """ |
|---|
| 191 | objDict[hashref]['file'] = file |
|---|
| 192 | objDict[hashref]['id'] = id |
|---|
| 193 | objDict[hashref]['path'] = path |
|---|
| 194 | objDict[hashref]['type'] = self.determineType(context, hashref, objDict, file) |
|---|
| 195 | |
|---|
| 196 | |
|---|
| 197 | def parseResourceMetadata(self, resourcereader, resourceid, context): |
|---|
| 198 | """ Read the resource metadata """ |
|---|
| 199 | |
|---|
| 200 | resourcereader.readGeneral() |
|---|
| 201 | resourcereader.readLifecycle() |
|---|
| 202 | resourcereader.readMetaMetadata() |
|---|
| 203 | resourcereader.readTechnical() |
|---|
| 204 | resourcereader.readRights() |
|---|
| 205 | customnode = resourcereader.getCustomData('', '') |
|---|
| 206 | if customnode: |
|---|
| 207 | metadict = resourcereader.readCustomMetadata(customnode) |
|---|
| 208 | resourcereader.appendCustomData(metadict) |
|---|
| 209 | return resourcereader.processResourceMetadata() |
|---|
| 210 | |
|---|
| 211 | def readCustomData(self, context, prefix, ns, location): |
|---|
| 212 | """ |
|---|
| 213 | Hook for reading custom metadata for additional metadata requirements. |
|---|
| 214 | Should return a dictionary of values representing attribute name and value. |
|---|
| 215 | """ |
|---|
| 216 | |
|---|
| 217 | return {} |
|---|
| 218 | |
|---|
| 219 | def getObjectDictionary(self): |
|---|
| 220 | """ Return the object dictionary """ |
|---|
| 221 | return self.objdict |
|---|
| 222 | |
|---|
| 223 | |
|---|
| 224 | def getPackageName(self): |
|---|
| 225 | |
|---|
| 226 | return self.name |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | class IMSInterchangeWriter(object): |
|---|
| 230 | |
|---|
| 231 | implements(IIMSManifestWriter) |
|---|
| 232 | name = _(u'IMS Interchange Writer') |
|---|
| 233 | |
|---|
| 234 | |
|---|
| 235 | def _writeObjectData(self, obj, path): |
|---|
| 236 | """ Write file data to the destination object. """ |
|---|
| 237 | if type(obj) == type(''): |
|---|
| 238 | data = obj |
|---|
| 239 | else: |
|---|
| 240 | format = '' |
|---|
| 241 | if hasattr(obj.aq_explicit, 'Format'): |
|---|
| 242 | format = obj.Format() |
|---|
| 243 | if obj.Type() in ['File', 'Image'] and hasattr(obj.aq_explicit, 'data'): |
|---|
| 244 | data = obj.data |
|---|
| 245 | elif 'text/html' == format and hasattr(obj.aq_explicit, 'getText'): |
|---|
| 246 | data = obj.getText() |
|---|
| 247 | elif format in ['text/plain', 'text/x-rst', 'text/structured'] and hasattr(obj.aq_explicit, 'getRawText'): |
|---|
| 248 | data = obj.getRawText() |
|---|
| 249 | else: |
|---|
| 250 | data = '' |
|---|
| 251 | |
|---|
| 252 | if self.destination: |
|---|
| 253 | self.destination.writeFile(path, data) |
|---|
| 254 | |
|---|
| 255 | def _getAllObjects(self, context): |
|---|
| 256 | """ Get all sub objects. """ |
|---|
| 257 | objects = [obj.getObject() for obj in context.portal_catalog.searchResults(path={'query':('/'.join(context.getPhysicalPath())+'/'),'depth':-1})] |
|---|
| 258 | return [object for object in objects if not object.isPrincipiaFolderish or getattr(object.aq_explicit, 'getText', None)] |
|---|
| 259 | |
|---|
| 260 | def _getChildrenObjects(self, parent, objects): |
|---|
| 261 | """ Get objects in current folder """ |
|---|
| 262 | parentpath = '/'.join(parent.getPhysicalPath()) |
|---|
| 263 | children = [] |
|---|
| 264 | for object in objects: |
|---|
| 265 | rpath = '/'.join(object.getPhysicalPath()).replace(parentpath, '') |
|---|
| 266 | |
|---|
| 267 | if len(rpath.split('/')) == 1: |
|---|
| 268 | children.append(object) |
|---|
| 269 | |
|---|
| 270 | return children |
|---|
| 271 | |
|---|
| 272 | def _getObjectPath(self, obj, context): |
|---|
| 273 | """ Get the path of an object. """ |
|---|
| 274 | |
|---|
| 275 | root_path = context.aq_explicit.virtual_url_path() |
|---|
| 276 | obj_path = obj.aq_explicit.virtual_url_path() |
|---|
| 277 | |
|---|
| 278 | if obj_path.find(root_path) != 0: |
|---|
| 279 | return '' |
|---|
| 280 | |
|---|
| 281 | # Remove the path of the folder object |
|---|
| 282 | path = obj_path.replace(root_path, '') |
|---|
| 283 | if path and path[0] == '/': |
|---|
| 284 | path = path[1:] |
|---|
| 285 | |
|---|
| 286 | if not path: |
|---|
| 287 | return '' |
|---|
| 288 | |
|---|
| 289 | if hasattr(obj.aq_explicit, 'Format'): |
|---|
| 290 | if 'text/html' == obj.Format() and obj.isPrincipiaFolderish: |
|---|
| 291 | path += '.html' |
|---|
| 292 | |
|---|
| 293 | return path |
|---|
| 294 | |
|---|
| 295 | def _createPathId(self, path, pre='RES'): |
|---|
| 296 | """ Create a unique id given a path """ |
|---|
| 297 | return pre + str(md5.md5(path).hexdigest()) |
|---|
| 298 | |
|---|
| 299 | def _getCopyrightString(self, copyright, rights_holder, rights_holder_email): |
|---|
| 300 | cp = '' |
|---|
| 301 | if copyright: |
|---|
| 302 | cp += copyright |
|---|
| 303 | if rights_holder: |
|---|
| 304 | if cp: |
|---|
| 305 | cp += ', ' |
|---|
| 306 | cp += rights_holder |
|---|
| 307 | if rights_holder_email: |
|---|
| 308 | if cp: |
|---|
| 309 | cp += ', ' |
|---|
| 310 | cp += rights_holder_email |
|---|
| 311 | return cp |
|---|
| 312 | |
|---|
| 313 | def getObjSize(self, object): |
|---|
| 314 | """ Retrieves the correct size of the object""" |
|---|
| 315 | return '%d' %object.get_size() |
|---|
| 316 | |
|---|
| 317 | def writeCustomMetadata(self, object): |
|---|
| 318 | """ Write the custom metdata for the package. Overridden at lower levels. """ |
|---|
| 319 | |
|---|
| 320 | return |
|---|
| 321 | |
|---|