class ExtensibleMetadata(Persistence.Persistent): """a replacement for CMFDefault.DublinCore.DefaultDublinCoreImpl """ # XXX This is not completely true. We need to review this later # and make sure it is true. # Just so you know, the problem here is that Title # is on BaseObject.schema, so it does implement IExtensibleMetadata # as long as both are used together. implements(IExtensibleMetadata) security = ClassSecurityInfo() schema = type = MetadataSchema( ( BooleanField( 'allowDiscussion', accessor="isDiscussable", mutator="allowDiscussion", edit_accessor="editIsDiscussable", default=None, enforceVocabulary=1, widget=BooleanWidget( label=_(u'label_allow_comments', default=u'Allow comments'), description=_(u'help_allow_comments', default=u'If selected, users can add comments ' 'to this item.') ), ), LinesField( 'subject', multiValued=1, accessor="Subject", searchable=True, widget=KeywordWidget( label=_(u'label_tags', default=u'Tags'), description=_(u'help_tags', default=u'Tags are commonly used for ad-hoc ' 'organization of content.'), ), ), TextField( 'description', default='', searchable=1, accessor="Description", default_content_type='text/plain', allowable_content_types=('text/plain',), widget=TextAreaWidget( label=_(u'label_description', default=u'Description'), description=_(u'help_description', default=u'Used in item listings and search results.'), ), ), # Location, also known as Coverage in the DC metadata standard, but we # keep the term Location here for historical reasons. StringField( 'location', # why no accessor? http://dev.plone.org/plone/ticket/6424 searchable=True, widget=StringWidget( label=_(u'label_location', default=u'Location'), description=_(u'help_location_dc', default=u'The geographical location associated with the item, if applicable.'), ), ), LinesField( 'contributors', accessor="Contributors", widget=LinesWidget( label=_(u'label_contributors', u'Contributors'), description=_(u'help_contributors', default=u"The names of people that have contributed " "to this item. Each contributor should " "be on a separate line."), ), ), LinesField( 'creators', accessor="Creators", widget=LinesWidget( label=_(u'label_creators', u'Creators'), description=_(u'help_creators', default=u"Persons responsible for creating the content of " "this item. Please enter a list of user names, one " "per line. The principal creator should come first."), rows=3 ), ), DateTimeField( 'effectiveDate', mutator='setEffectiveDate', languageIndependent=True, widget=CalendarWidget( label=_(u'label_effective_date', u'Publishing Date'), description=_(u'help_effective_date', default=u"The date when the item will be published. If no " "date is selected the item will be published immediately."), ), ), DateTimeField( 'expirationDate', mutator='setExpirationDate', languageIndependent=True, widget=CalendarWidget( label=_(u'label_expiration_date', u'Expiration Date'), description=_(u'help_expiration_date', default=u"The date when the item expires. This will automatically " "make the item invisible for others at the given date. " "If no date is chosen, it will never expire."), ), ), StringField( 'language', accessor="Language", default=config.LANGUAGE_DEFAULT, default_method='defaultLanguage', vocabulary='languages', widget=LanguageWidget( label=_(u'label_language', default=u'Language'), ), ), TextField( 'rights', accessor="Rights", default_method='defaultRights', allowable_content_types=('text/plain',), widget=TextAreaWidget( label=_(u'label_copyrights', default=u'Rights'), description=_(u'help_copyrights', default=u'Copyright statement or other rights information on this item.'), )), )) + Schema(( # XXX change this to MetadataSchema in AT 1.4 # Currently we want to stay backward compatible without migration # between beta versions so creation and modification date are using the # standard schema which leads to AttributeStorage DateTimeField( 'creation_date', accessor='created', mutator='setCreationDate', default_method=DateTime, languageIndependent=True, isMetadata=True, schemata='metadata', generateMode='mVc', widget=CalendarWidget( label=_(u'label_creation_date', default=u'Creation Date'), description=_(u'help_creation_date', default=u'Date this object was created'), visible={'edit': 'invisible', 'view': 'invisible'}), ), DateTimeField( 'modification_date', accessor='modified', mutator='setModificationDate', default_method=DateTime, languageIndependent=True, isMetadata=True, schemata='metadata', generateMode='mVc', widget=CalendarWidget( label=_(u'label_modification_date', default=u'Modification Date'), description=_(u'help_modification_date', default=u'Date this content was modified last'), visible={'edit': 'invisible', 'view': 'invisible'}), ), )) def __init__(self): pass security.declarePrivate('defaultLanguage') def defaultLanguage(self): # Retrieve the default language tool = getToolByName(self, 'portal_languages', None) if tool is not None: return tool.getDefaultLanguage() return config.LANGUAGE_DEFAULT security.declarePrivate('defaultRights') def defaultRights(self): # Retrieve the default rights. mdtool = getToolByName(self, 'portal_metadata', None) if mdtool is None: return '' for sid, schema in mdtool.listSchemas(): for pid, policy in schema.listPolicies(typ=self.Type()): if pid != 'Rights' and not policy.supply_default: continue return policy.default_value return '' security.declareProtected(permissions.View, 'isDiscussable') def isDiscussable(self, encoding=None): # Returns either True or False dtool = getToolByName(self, 'portal_discussion') return dtool.isDiscussionAllowedFor(self) security.declareProtected(permissions.View, 'editIsDiscussable') def editIsDiscussable(self, encoding=None): # Returns True, False or if None the default value result = self.rawIsDiscussable() if result is not None: return result default = self.defaultIsDiscussable() return default security.declareProtected(permissions.View, 'rawIsDiscussable') def rawIsDiscussable(self): # Returns True, False or None where None means use the default result = getattr(aq_base(self), 'allow_discussion', None) if result is not None: result = bool(result) return result security.declareProtected(permissions.View, 'defaultIsDiscussable') def defaultIsDiscussable(self): # Returns the default value, either True or False default = None typeInfo = self.getTypeInfo() if typeInfo: default = typeInfo.allowDiscussion() return default security.declareProtected(permissions.ModifyPortalContent, 'allowDiscussion') def allowDiscussion(self, allowDiscussion=None, **kw): default = self.defaultIsDiscussable() current = self.rawIsDiscussable() # If we already overwrote the default or the value we try to set is # not the default we change it. Otherwise we keep what's there. if (current is not None or (current is None and default != allowDiscussion)): dtool = getToolByName(self, 'portal_discussion', None) try: if dtool is not None: try: dtool.overrideDiscussionFor(self, allowDiscussion) except AttributeError: # CMF 2.1.0's CMFDefault.DiscussionTool # has tried to delete the class attribute. # TODO: remove this when we move to a later # CMF. pass except Unauthorized: # Catch Unauthorized exception that could be raised by the # discussion tool when the authenticated users hasn't # ModifyPortalContent permissions. # Explanation: # A user might have CreatePortalContent but not ModifyPortalContent # so allowDiscussion could raise a Unauthorized error although it's # called from trusted code. That is VERY bad inside setDefault()! log('Catched Unauthorized on discussiontool.' \ 'overrideDiscussionFor(%s)' % self.absolute_url(1), level=DEBUG) # Vocabulary methods ###################################################### security.declareProtected(permissions.View, 'languages') def languages(self): # Vocabulary method for the language field. util = None use_combined = False # Respect the combined language code setting from PloneLanguageTool lt = getToolByName(self, 'portal_languages', None) if lt is not None: use_combined = lt.use_combined_language_codes # Try the utility first if HAS_PLONE_I18N: util = queryUtility(IMetadataLanguageAvailability) # Fall back to acquiring availableLanguages if util is None: languages = getattr(self, 'availableLanguages', None) if callable(languages): languages = languages() # Fall back to static definition if languages is None: return DisplayList( (('en', 'English'), ('fr', 'French'), ('es', 'Spanish'), ('pt', 'Portuguese'), ('ru', 'Russian'))) else: languages = util.getLanguageListing(combined=use_combined) languages.sort(key=lambda x: x[1]) # Put language neutral at the top. languages.insert(0, (u'', _(u'Language neutral'))) return DisplayList(languages) # DublinCore interface query methods ##################################### security.declareProtected(permissions.View, 'CreationDate') def CreationDate(self, zone=None): # Dublin Core element - date resource created. if zone is None: zone = _zone creation = self.getField('creation_date').get(self) # return unknown if never set properly return creation is None and 'Unknown' or creation.toZone(zone).ISO8601() security.declareProtected(permissions.View, 'EffectiveDate') def EffectiveDate(self, zone=None): # Dublin Core element - date resource becomes effective. if zone is None: zone = _zone effective = self.getField('effectiveDate').get(self) return effective is None and 'None' or effective.toZone(zone).ISO8601() def _effective_date(self): # Computed attribute accessor. return self.getField('effectiveDate').get(self) security.declareProtected(permissions.View, 'effective_date') effective_date = ComputedAttribute(_effective_date, 1) security.declareProtected(permissions.View, 'ExpirationDate') def ExpirationDate(self, zone=None): # Dublin Core element - date resource expires. if zone is None: zone = _zone expires = self.getField('expirationDate').get(self) return expires is None and 'None' or expires.toZone(zone).ISO8601() def _expiration_date(self): # Computed attribute accessor. return self.getField('expirationDate').get(self) security.declareProtected(permissions.View, 'expiration_date') expiration_date = ComputedAttribute(_expiration_date, 1) security.declareProtected(permissions.View, 'Date') def Date(self, zone=None): # Dublin Core element - default date # Return effective_date if specifically set, modification date # otherwise if zone is None: zone = _zone effective = self.getField('effectiveDate').get(self) if effective is None: effective = self.modified() return (effective is None and DateTime().toZone(zone) or effective.toZone(zone).ISO8601()) security.declareProtected(permissions.View, 'Format') def Format(self): # cmf/backward compat # Dublin Core element - resource format # FIXME: get content type from marshaller return self.getContentType() security.declareProtected(permissions.ModifyPortalContent, 'setFormat') def setFormat(self, value): # cmf/backward compat: ignore setFormat. self.setContentType(value) def Identifer(self): # dublin core getId method. return self.getId() # DublinCore utility methods ############################################# security.declareProtected(permissions.View, 'contentEffective') def contentEffective(self, date): # Is the date within the resource's effective range? effective = self.getField('effectiveDate').get(self) expires = self.getField('expirationDate').get(self) pastEffective = (effective is None or effective <= date) beforeExpiration = (expires is None or expires >= date) return pastEffective and beforeExpiration security.declareProtected(permissions.View, 'contentExpired') def contentExpired(self, date=None): # Is the date after resource's expiration. if not date: date = DateTime() expires = self.getField('expirationDate').get(self) if not expires: expires = CEILING_DATE return expires <= date # CatalogableDublinCore methods ########################################## security.declareProtected(permissions.View, 'created') def created(self): # Dublin Core element - date resource created, # returned as DateTime. # allow for non-existent creation_date, existed always created = self.getField('creation_date').get(self) return created is None and FLOOR_DATE or created security.declareProtected(permissions.View, 'modified') def modified(self): # Dublin Core element - date resource last modified, # returned as DateTime. modified = self.getField('modification_date').get(self) # TODO may return None return modified security.declareProtected(permissions.View, 'effective') def effective(self): # Dublin Core element - date resource becomes effective, # returned as DateTime. effective = self.getField('effectiveDate').get(self) return effective is None and FLOOR_DATE or effective security.declareProtected(permissions.View, 'expires') def expires(self): # Dublin Core element - date resource expires, # returned as DateTime. expires = self.getField('expirationDate').get(self) return expires is None and CEILING_DATE or expires ## code below come from CMFDefault.DublinCore.DefaultDublinCoreImpl ####### ########################################################################### # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (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 # ########################################################################### # # Set-modification-date-related methods. # In DefaultDublinCoreImpl for lack of a better place. # security.declareProtected(permissions.ModifyPortalContent, 'notifyModified') def notifyModified(self): # Take appropriate action after the resource has been modified. # For now, change the modification_date. self.setModificationDate(DateTime()) if shasattr(self, 'http__refreshEtag'): self.http__refreshEtag() security.declareProtected(permissions.ManagePortal, '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: modified = DateTime() else: modified = self._datify(modification_date) self.getField('modification_date').set(self, modified) security.declareProtected(permissions.ManagePortal, 'setCreationDate') def setCreationDate(self, creation_date=None): # Set the date when the resource was created. # When called without an argument, sets the date to now. if creation_date is None: created = DateTime() else: created = self._datify(creation_date) self.getField('creation_date').set(self, created) security.declarePrivate('_datify') def _datify(self, date): # Try to convert something into a DateTime instance or None. # stupid web if date == 'None': date = None if not isinstance(date, DateTime): if date is not None: date = DateTime(date) return date # # DublinCore interface query methods # security.declareProtected(permissions.View, 'Publisher') def Publisher(self): # Dublin Core element - resource publisher # XXX: fixme using 'portal_metadata' return 'No publisher' security.declareProtected(permissions.View, 'ModificationDate') def ModificationDate(self, zone=None): # Dublin Core element - date resource last modified. if zone is None: zone = _zone modified = self.modified() return (modified is None and DateTime().toZone(zone) or modified.toZone(zone).ISO8601()) security.declareProtected(permissions.View, 'Type') def Type(self): # Dublin Core element - Object type. if hasattr(aq_base(self), 'getTypeInfo'): ti = self.getTypeInfo() if ti is not None: return ti.Title() return self.meta_type security.declareProtected(permissions.View, 'Identifier') def Identifier(self): # Dublin Core element - Object ID # XXX: fixme using 'portal_metadata' (we need to prepend the # right prefix to self.getPhysicalPath(). return self.absolute_url() security.declareProtected(permissions.View, 'listContributors') def listContributors(self): # Dublin Core element - Contributors. return self.Contributors() security.declareProtected(permissions.ModifyPortalContent, 'addCreator') def addCreator(self, creator=None): # Add creator to Dublin Core creators. if creator is None: mtool = getToolByName(self, 'portal_membership', None) if mtool is None: return creator = mtool.getAuthenticatedMember().getId() # call self.listCreators() to make sure self.creators exists curr_creators = self.listCreators() if creator and not creator in curr_creators: self.setCreators(curr_creators + (creator, )) security.declareProtected(permissions.View, 'listCreators') def listCreators(self): # List Dublin Core Creator elements - resource authors. creators = self.Schema()['creators'] if not creators.get(self): # for content created with CMF versions before 1.5 owner_tuple = self.getOwnerTuple() owner_id = owner_tuple and owner_tuple[1] if owner_id: creators.set(self, (owner_id,)) else: creators.set(self, ()) return creators.get(self) security.declareProtected(permissions.View, 'Creator') def Creator(self): # Dublin Core Creator element - resource author. creators = self.listCreators() return creators and creators[0] or '' # # DublinCore utility methods # # Deliberately *not* protected by a security declaration # See https://dev.plone.org/archetypes/ticket/712 def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return self.Format() # # CatalogableDublinCore methods # security.declareProtected(permissions.View, 'getMetadataHeaders') def getMetadataHeaders(self): # Return RFC-822-style headers. hdrlist = [] hdrlist.append(('Title', self.Title())) hdrlist.append(('Subject', string.join(self.Subject(), ', '))) hdrlist.append(('Publisher', self.Publisher())) hdrlist.append(('Description', self.Description())) hdrlist.append(('Contributors', string.join( self.Contributors(), '; '))) hdrlist.append(('Creators', string.join( self.Creators(), '; '))) 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 # # 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(permissions.ModifyPortalContent, 'manage_metadata') manage_metadata = DTMLFile('zmi_metadata', _dtmldir) security.declareProtected(permissions.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(permissions.ModifyPortalContent, 'editMetadata') def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights='', ): # Used to be: editMetadata = WorkflowAction(_editMetadata) # Need to add check for webDAV locked resource for TTW methods. 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()
# 'maximalSize': 9999, # 'type': 'identifiertypeattributes', # 'subfields': ('title', 'description'), # 'required_subfields': ('title',), # 'subfield_labels': {'title': _('Attribute Title'), # 'description': _('Description')}, # 'subfield_sizes': {'title': 20, # 'description': 35}, # 'subfield_validators': {'title': 'identifiertypeattributesvalidator'}, # }) # security = ClassSecurityInfo() PortalTypes = LinesField( 'PortalTypes', vocabulary='getPortalTypes', widget=PicklistWidget( label=_("Portal Types"), description=_("Select the types that this ID is used to identify."), ), ) # Attributes = IdentifierTypeAttributesField( # 'Attributes', # widget=BikaRecordsWidget( # label=_("Identifier attributes"), # description=_("Each item identified with this IdentifierType can " # "contain additional information. The allowed # attributes " # "can be specified here."), # ), # )