/
DublinCore.py
478 lines (365 loc) · 16.5 KB
/
DublinCore.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2001 Zope Foundation and Contributors.
#
# 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.
#
##############################################################################
""" Dublin Core support for content types. """
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from Acquisition import aq_base
from App.class_init import InitializeClass
from App.special_dtml import DTMLFile
from DateTime.DateTime import DateTime
from OFS.PropertyManager import PropertyManager
from zope.interface import implementer
from Products.CMFCore.interfaces import ICatalogableDublinCore
from Products.CMFCore.interfaces import IDublinCore
from Products.CMFCore.interfaces import IMutableDublinCore
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.permissions import ModifyPortalContent
from Products.CMFPlone.permissions import View
from Products.CMFPlone.utils import WWW_DIR
_marker = []
# For http://www.zope.org/Collectors/CMF/325
# We only really need this once, at startup.
_zone = DateTime().timezone()
def seq_strip(seq, stripper=lambda x: x.strip()):
""" Strip a sequence of strings.
"""
if isinstance(seq, list):
return map(stripper, seq)
if isinstance(seq, tuple):
return tuple(map(stripper, seq))
raise ValueError, "%s of unsupported sequencetype %s" % (seq, type(seq))
def tuplize(valueName, value, splitter=lambda x: x.split()):
if isinstance(value, tuple):
return seq_strip(value)
if isinstance(value, list):
return seq_strip(tuple(value))
if isinstance(value, basestring):
return seq_strip(tuple(splitter(value)))
raise ValueError, "%s of unsupported type" % valueName
@implementer(IDublinCore, ICatalogableDublinCore, IMutableDublinCore)
class DefaultDublinCoreImpl(PropertyManager):
""" Mix-in class which provides Dublin Core methods.
"""
security = ClassSecurityInfo()
def __init__(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='', rights=''
):
now = DateTime()
self.creation_date = now
self.modification_date = now
self.creators = ()
self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights
)
#
# Set-modification-date-related methods.
# In DefaultDublinCoreImpl for lack of a better place.
#
# Class variable default for an upgrade.
modification_date = None
security.declarePrivate('notifyModified')
def notifyModified(self):
# Take appropriate action after the resource has been modified.
# Update creators and modification_date.
self.addCreator()
self.setModificationDate()
security.declareProtected(ModifyPortalContent, 'addCreator')
def addCreator(self, creator=None):
# Add creator to Dublin Core creators.
if creator is None:
user = getSecurityManager().getUser()
creator = user and user.getId()
# call self.listCreators() to make sure self.creators exists
if creator and not creator in self.listCreators():
self.creators = self.creators + (creator, )
security.declareProtected(ModifyPortalContent, 'setModificationDate')
def setModificationDate(self, modification_date=None):
# Set the date when the resource was last modified.
# When called without an argument, sets the date to now.
if modification_date is None:
self.modification_date = DateTime()
else:
self.modification_date = self._datify(modification_date)
#
# DublinCore interface query methods
#
security.declareProtected(View, 'Title')
def Title(self):
# Dublin Core Title element - resource name.
return self.title
security.declareProtected(View, 'listCreators')
def listCreators(self):
# List Dublin Core Creator elements - resource authors.
if not hasattr(aq_base(self), 'creators'):
# for content created with CMF versions before 1.5
owner_tuple = self.getOwnerTuple()
if owner_tuple:
self.creators = (owner_tuple[1],)
else:
self.creators = ()
return self.creators
security.declareProtected(View, 'Creator')
def Creator(self):
# Dublin Core Creator element - resource author.
creators = self.listCreators()
return creators and creators[0] or ''
security.declareProtected(View, 'Subject')
def Subject(self):
# Dublin Core Subject element - resource keywords.
return getattr(self, 'subject', ()) # compensate for *old* content
security.declareProtected(View, 'Description')
def Description(self):
# Dublin Core Description element - resource summary.
return self.description
security.declareProtected(View, 'Publisher')
def Publisher(self):
# Dublin Core Publisher element - resource publisher.
tool = getToolByName(self, 'portal_metadata', None)
if tool is not None:
return tool.getPublisher()
return 'No publisher'
security.declareProtected(View, 'listContributors')
def listContributors(self):
# Dublin Core Contributor elements - resource collaborators.
return self.contributors
security.declareProtected(View, 'Contributors')
def Contributors(self):
# Deprecated alias of listContributors.
return self.listContributors()
security.declareProtected(View, 'Date')
def Date(self, zone=None):
# Dublin Core Date element - default date.
if zone is None:
zone = _zone
# Return effective_date if set, modification date otherwise
date = getattr(self, 'effective_date', None)
if date is None:
date = self.modified()
return date.toZone(zone).ISO()
security.declareProtected(View, 'CreationDate')
def CreationDate(self, zone=None):
# Dublin Core Date element - date resource created.
if zone is None:
zone = _zone
# return unknown if never set properly
if self.creation_date:
return self.creation_date.toZone(zone).ISO()
else:
return 'Unknown'
security.declareProtected(View, 'EffectiveDate')
def EffectiveDate(self, zone=None):
# Dublin Core Date element - date resource becomes effective.
if zone is None:
zone = _zone
ed = getattr(self, 'effective_date', None)
return ed and ed.toZone(zone).ISO() or 'None'
security.declareProtected(View, 'ExpirationDate')
def ExpirationDate(self, zone=None):
# Dublin Core Date element - date resource expires.
if zone is None:
zone = _zone
ed = getattr(self, 'expiration_date', None)
return ed and ed.toZone(zone).ISO() or 'None'
security.declareProtected(View, 'ModificationDate')
def ModificationDate(self, zone=None):
# Dublin Core Date element - date resource last modified.
if zone is None:
zone = _zone
return self.modified().toZone(zone).ISO()
security.declareProtected(View, 'Type')
def Type(self):
# Dublin Core Type element - resource type.
ti = self.getTypeInfo()
return ti is not None and ti.Title() or 'Unknown'
security.declareProtected(View, 'Format')
def Format(self):
# Dublin Core Format element - resource format.
return self.format
security.declareProtected(View, 'Identifier')
def Identifier(self):
# Dublin Core Identifier element - resource ID.
# XXX: fixme using 'portal_metadata' (we need to prepend the
# right prefix to self.getPhysicalPath().
return self.absolute_url()
security.declareProtected(View, 'Language')
def Language(self):
# Dublin Core Language element - resource language.
return self.language
security.declareProtected(View, 'Rights')
def Rights(self):
# Dublin Core Rights element - resource copyright.
return self.rights
#
# DublinCore utility methods
#
def content_type(self):
""" WebDAV needs this to do the Right Thing (TM).
"""
return self.Format()
__FLOOR_DATE = DateTime(1970, 0) # always effective
security.declareProtected(View, 'isEffective')
def isEffective(self, date):
# Is the date within the resource's effective range?
pastEffective = (self.effective_date is None
or self.effective_date <= date)
beforeExpiration = (self.expiration_date is None
or self.expiration_date >= date)
return pastEffective and beforeExpiration
#
# CatalogableDublinCore methods
#
security.declareProtected(View, 'created')
def created(self):
# Dublin Core Date element - date resource created.
# allow for non-existent creation_date, existed always
date = getattr(self, 'creation_date', None)
return date is None and self.__FLOOR_DATE or date
security.declareProtected(View, 'effective')
def effective(self):
# Dublin Core Date element - date resource becomes effective.
marker = []
date = getattr(self, 'effective_date', marker)
if date is marker:
date = getattr(self, 'creation_date', None)
return date is None and self.__FLOOR_DATE or date
__CEILING_DATE = DateTime(2500, 0) # never expires
security.declareProtected(View, 'expires')
def expires(self):
# Dublin Core Date element - date resource expires.
date = getattr(self, 'expiration_date', None)
return date is None and self.__CEILING_DATE or date
security.declareProtected(View, 'modified')
def modified(self):
# Dublin Core Date element - date resource last modified.
date = self.modification_date
if date is None:
# Upgrade.
date = DateTime(self._p_mtime)
self.modification_date = date
return date
security.declareProtected(View, 'getMetadataHeaders')
def getMetadataHeaders(self):
# Return RFC-822-style headers.
hdrlist = []
hdrlist.append(('Title', self.Title()))
hdrlist.append(('Subject', ', '.join(self.Subject())))
hdrlist.append(('Publisher', self.Publisher()))
hdrlist.append(('Description', self.Description()))
hdrlist.append(('Contributors', '; '.join(self.Contributors())))
hdrlist.append(('Effective_date', self.EffectiveDate()))
hdrlist.append(('Expiration_date', self.ExpirationDate()))
hdrlist.append(('Type', self.Type()))
hdrlist.append(('Format', self.Format()))
hdrlist.append(('Language', self.Language()))
hdrlist.append(('Rights', self.Rights()))
return hdrlist
#
# MutableDublinCore methods
#
security.declarePrivate('_datify')
def _datify(self, attrib):
if attrib == 'None':
attrib = None
elif not isinstance(attrib, DateTime):
if attrib is not None:
attrib = DateTime(attrib)
return attrib
security.declareProtected(ModifyPortalContent, 'setTitle')
def setTitle(self, title):
# Set Dublin Core Title element - resource name.
self.title = title
security.declareProtected(ModifyPortalContent, 'setCreators')
def setCreators(self, creators):
# Set Dublin Core Creator elements - resource authors.
self.creators = tuplize('creators', creators)
security.declareProtected(ModifyPortalContent, 'setSubject')
def setSubject(self, subject):
# Set Dublin Core Subject element - resource keywords.
self.subject = tuplize('subject', subject)
security.declareProtected(ModifyPortalContent, 'setDescription')
def setDescription(self, description):
# Set Dublin Core Description element - resource summary.
self.description = description
security.declareProtected(ModifyPortalContent, 'setContributors')
def setContributors(self, contributors):
# Set Dublin Core Contributor elements - resource collaborators.
semi_split = lambda s: map(lambda x: x.strip(), s.split(';'))
self.contributors = tuplize('contributors', contributors, semi_split)
security.declareProtected(ModifyPortalContent, 'setEffectiveDate')
def setEffectiveDate(self, effective_date):
# Set Dublin Core Date element - date resource becomes effective.
self.effective_date = self._datify(effective_date)
security.declareProtected(ModifyPortalContent, 'setExpirationDate')
def setExpirationDate(self, expiration_date):
# Set Dublin Core Date element - date resource expires.
self.expiration_date = self._datify(expiration_date)
security.declareProtected(ModifyPortalContent, 'setFormat')
def setFormat(self, format):
# Set Dublin Core Format element - resource format.
self.format = format
security.declareProtected(ModifyPortalContent, 'setLanguage')
def setLanguage(self, language):
# Set Dublin Core Language element - resource language.
self.language = language
security.declareProtected(ModifyPortalContent, 'setRights')
def setRights(self, rights):
# Set Dublin Core Rights element - resource copyright.
self.rights = rights
#
# Management tab methods
#
security.declarePrivate('_editMetadata')
def _editMetadata(self, title=_marker, subject=_marker, description=_marker, contributors=_marker, effective_date=_marker, expiration_date=_marker, format=_marker, language=_marker, rights=_marker
):
# Update the editable metadata for this resource.
if title is not _marker:
self.setTitle(title)
if subject is not _marker:
self.setSubject(subject)
if description is not _marker:
self.setDescription(description)
if contributors is not _marker:
self.setContributors(contributors)
if effective_date is not _marker:
self.setEffectiveDate(effective_date)
if expiration_date is not _marker:
self.setExpirationDate(expiration_date)
if format is not _marker:
self.setFormat(format)
if language is not _marker:
self.setLanguage(language)
if rights is not _marker:
self.setRights(rights)
security.declareProtected(ModifyPortalContent, 'manage_metadata')
manage_metadata = DTMLFile('zmi_metadata', WWW_DIR)
security.declareProtected(ModifyPortalContent, 'manage_editMetadata')
def manage_editMetadata(self, title, subject, description, contributors, effective_date, expiration_date, format, language, rights, REQUEST
):
""" Update metadata from the ZMI.
"""
self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights
)
REQUEST['RESPONSE'].redirect(self.absolute_url()
+ '/manage_metadata'
+ '?manage_tabs_message=Metadata+updated.')
security.declareProtected(ModifyPortalContent, 'editMetadata')
def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights=''
):
# Need to add check for webDAV locked resource for TTW methods.
# As per bug #69, we can't assume they use the webdav
# locking interface, and fail gracefully if they don't.
if hasattr(self, 'failIfLocked'):
self.failIfLocked()
self._editMetadata(title=title, subject=subject, description=description, contributors=contributors, effective_date=effective_date, expiration_date=expiration_date, format=format, language=language, rights=rights
)
self.reindexObject()
InitializeClass(DefaultDublinCoreImpl)