[Zope-CMF] add Metadata element to existing types
Tim Hoffman
timhoffman@cams.wa.gov.au
Wed, 27 Feb 2002 09:02:13 +0800
This is a multi-part message in MIME format.
--------------040403030808000300090105
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Siegfried Stepke wrote:
>Hello,
>
>although I found lots of information regarding adding new CMF-Types with
>their own properties I didn't find anything about adding a totally new
>element in the metadata to show up in the full_metadata_edit_form ...
>
>I succeeded in creating a new element in the portal_metadata tool; it
>shows up there and I can set its default or content-type-specific
>settings. But I don't know what to do to let it show up in the documents
>meta-data edit forms...
>
>Is this possible? (or are only the standard metadata elements supported?)
>Is this possible for the default portal-types?
>Do I have to create a new "custom/full_metadata_edit_form"?
> Which code would have to be integrated there for a subject-like element?
>
You need to patch defaultDublinCoreImpl with new setter and getter methods
and you need to modify the create and bind new __init__ and _editMetadata,
and manage_editMetadata methods
plus make a new full_metadata_edit_form
I think one thing you need to consider is that these new elements that you
are adding will be added to all CMF content types that have metadata.
I have been doing this to extend the metadata to include AGLS elements,
plus some additional ones of our own, which get coalesced into Subject.
>
>The goal is to integrate more metadata fields like target_audience_level,
>client_category, etc. to be able to create nice topics specific to that
>data and even more...
>
>
>I really searched a lot in the docs and archives and found a lot similar
>questions but all answers just pointed to new types with properties - not
>metadata.
>
I have attached the monkey patch we use. basically it is an init method
in a product directory.
You will note there are some other odd bit's in the code, like the
generation of
a unique id for every piece of content that has metadata, which get's
regenerated
if the object is cloned.
Regards
Tim
>
>thanks for any help!
>
>regards,
>siegfried
>
>
>
>
>
>_______________________________________________
>Zope-CMF maillist - Zope-CMF@zope.org
>http://lists.zope.org/mailman/listinfo/zope-cmf
>
>See http://www.zope.org/Products/PTK/Tracker for bug reports and feature requests
>
--------------040403030808000300090105
Content-Type: text/plain;
name="__init__.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="__init__.py"
#"""Extend CMF DublinCore to include AGLS and PFA MetaData"""
import string
from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
from Products.CMFCore.PortalContent import PortalContent
from Products.CMFDefault.utils import tuplize, semi_split,_dtmldir
from AccessControl import ClassSecurityInfo
from Products.CMFCore import CMFCorePermissions
from Globals import InitializeClass, DTMLFile
from DateTime.DateTime import DateTime
from Products.CMFCore.WorkflowCore import WorkflowAction
from Products.CMFCore.PortalContent import PortalContent
from Products.CMFCore.CMFCorePermissions import AccessContentsInformation
from Globals import InitializeClass
from OFS.SimpleItem import SimpleItem
from Acquisition import aq_base
import re
from zLOG import LOG, INFO, ERROR, TRACE, BLATHER
security = ClassSecurityInfo()
#Creator -----------------------------------------------------
security.declarePublic( 'Creator' )
def Creator( self ):
'''DC element - Creator'''
try:
return self.creator
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setCreator' )
def setCreator( self, creator ):
'''DC element - Creator'''
if creator:
self.creator = creator
if not creator and not self.creator:
owner = self.getOwner()
if hasattr( owner, 'getUserName' ):
self.creator = owner.getUserName()
#Jurisdiction -----------------------------------------------------
security.declarePublic( 'Jurisdiction' )
def Jurisdiction( self ):
'''AGLS element - Jurisdiction'''
try:
return self.jurisdiction
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setJurisdiction' )
def setJurisdiction( self, jurisdiction ):
'''AGLS element - Jurisdiction'''
self.jurisdiction = jurisdiction
#Location -----------------------------------------------------
security.declarePublic( 'Location' )
def Location( self ):
'''AGLS element - Location'''
try:
return self.location
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setLocation' )
def setLocation( self, location ):
'''AGLS element - Location'''
self.location = location
#Relation -----------------------------------------------------
security.declarePublic( 'Relation' )
def Relation( self ):
'''AGLS element - Relation'''
try:
return self.relation
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setRelation' )
def setRelation( self, relation ):
"AGLS element - Relation"
self.relation = relation
#Source -----------------------------------------------------
security.declarePublic( 'Source' )
def Source( self ):
'''AGLS element - Source'''
try:
return self.source
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSource' )
def setSource( self, source ):
'''AGLS element - Source'''
self.source = source
#Function -----------------------------------------------------
security.declarePublic( 'Function' )
def Function( self ):
'''AGLS element - Function'''
try:
return self.function
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setFunction' )
def setFunction( self, function ):
'''AGLS element - Function'''
self.function = function
#Audience -----------------------------------------------------
security.declarePublic( 'Audience' )
def Audience( self ):
'''AGLS element - Audience'''
try:
return self.audience
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setAudience' )
def setAudience( self, audience ):
'''AGLS element - Audience'''
self.audience = audience
#Mandate -----------------------------------------------------
security.declarePublic( 'Mandate' )
def Mandate( self ):
'''AGLS element - Mandate'''
try:
return self.mandate
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setMandate' )
def setMandate( self, mandate ):
'''AGLS element - Audience'''
self.mandate = mandate
#SubjectMedium -----------------------------------------------------
security.declarePublic( 'SubjectMedium' )
def SubjectMedium( self ):
'''Designing Futures element - SubjectMedium'''
try:
return self.subject_medium
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSubjectMedium' )
def setSubjectMedium( self, subject_medium ):
'''Designing Futures element - SubjectMedium'''
LOG('ETIMetadataExtensions.setSubjectMedium',INFO, subject_medium)
self.subject_medium = tuplize('subject_medium',subject_medium)
#SubjectColour -----------------------------------------------------
security.declarePublic( 'SubjectColour' )
def SubjectColour( self ):
'''Designing Futures element - SubjectColour'''
try:
return self.subject_colour
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSubjectColour' )
def setSubjectColour( self, subject_colour ):
'''Designing Futures element - SubjectColour'''
self.subject_colour = tuplize( 'subject_colour', subject_colour)
#SubjectMatter -----------------------------------------------------
security.declarePublic( 'SubjectMatter' )
def SubjectMatter( self ):
'''Designing Futures element - SubjectMatter'''
try:
return self.subject_matter
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSubjectMatter' )
def setSubjectMatter( self, subject_matter ):
'''Designing Futures element - SubjectMatter'''
self.subject_matter = tuplize( 'subject_matter', subject_matter)
#SubjectMedium -----------------------------------------------------
security.declarePublic( 'SubjectFocus' )
def SubjectFocus( self ):
'''Designing Futures element - SubjectFocus'''
try:
return self.subject_focus
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSubjectFocus' )
def setSubjectFocus( self, subject_focus ):
'''Designing Futures element - SubjectFocus'''
self.subject_focus = tuplize( 'subject_focus', subject_focus)
#SubjectDimensions -----------------------------------------------------
security.declarePublic( 'SubjectDimensions' )
def SubjectDimensions( self ):
'''Designing Futures element - SubjectFocus'''
try:
return self.subject_dimensions
except:
return ""
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setSubjectDimensions' )
def setSubjectDimensions( self, subject_focus ):
'''Designing Futures element - SubjectDimensions'''
self.subject_dimensions = tuplize( 'subject_dimensions', subject_dimensions)
# UniqueId -----------------------------------------------------
security.declarePublic( 'UniqueId' )
def UniqueID( self ):
'''Designing Futures element - UniqueID'''
try:
return self.unique_id
except:
return ""
#------------------------------------------------------------------
import md5, base64, time, string
def ETIMakeUniqueID(id):
''' Generate a unique id '''
oid=md5.new()
oid.update(id)
oid.update(str(time.time()))
oid=oid.digest()
oid=string.strip(base64.encodestring(oid))
return 'DF_OID_'+oid.replace('/','$')
# Contributors -------------------------------------------------------
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'setContributors' )
# Redefine setContributors so that it also builds searchableContributors so
# a textfield version of contributors is catalogued so that wild card searches
# can be performed
def Contributors(self):
return self.contributors
def setContributors( self, contributors ):
"Dublin Core element - additional contributors to resource"
# XXX: fixme
self.contributors = tuplize('contributors', contributors, semi_split)
bad_chars = r'[^A-Za-z0-9_]'
searchableContributors = []
for a in self.contributors:
searchableContributors.append(string.join(re.split(bad_chars,string.rstrip(re.sub(bad_chars,' ',a))),'_'))
self.searchableContributors = string.join(searchableContributors,' ')
security.declarePublic( 'searchableContent' )
def searchableContributors( self ):
try:
return self.searchableContributors
except:
self.searchableContributors = ''
return self.searchableContributors
# --------------------------------------------------------------------
def manage_afterClone(self,obj):
LOG('ETIMetadataExtensions._manage_afterClone',INFO, "object cloned [%s]" % obj.title_or_id())
self.unique_id = ETIMakeUniqueID(obj.title_or_id())
# --------------------------------------------------------------------
# Replace init method
def __init__( self
, title=''
, subject=()
, description=''
, contributors=()
, effective_date=None
, expiration_date=None
, format='text/html'
, language='en'
, rights=''
, jurisdiction=''
, location=''
, relation=''
, source=''
, function=''
, audience=''
, mandate=''
, subject_medium=()
, subject_colour=()
, subject_matter=()
, subject_focus=()
, subject_dimensions=''
, creator=''
):
LOG('ETIMetadataExtensions.__init__',INFO, "initialising DublinCore [%s]" % title)
self.creation_date = DateTime()
self.unique_id = ETIMakeUniqueID(title)
self._editMetadata( title
, subject
, description
, contributors
, effective_date
, expiration_date
, format
, language
, rights
, jurisdiction
, location
, relation
, source
, function
, audience
, mandate
, subject_medium
, subject_colour
, subject_matter
, subject_focus
, subject_dimensions
, creator
)
#
# Management tab methods
#
security.declarePrivate( '_editMetadata' )
def _editMetadata( self
, title=''
, subject=()
, description=''
, contributors=()
, effective_date=None
, expiration_date=None
, format='text/html'
, language='en'
, rights=''
, jurisdiction=''
, location=''
, relation=''
, source=''
, function=''
, audience=''
, mandate=''
, subject_medium=()
, subject_colour=()
, subject_matter=()
, subject_focus=()
, subject_dimensions=''
, creator=''
):
"""
Update the editable metadata for this resource.
"""
LOG('ETIMetadataExtensions._editMetadata',INFO, title)
self.setTitle( title )
self.setDescription( description )
self.setContributors( contributors )
self.setEffectiveDate( effective_date )
self.setExpirationDate( expiration_date )
self.setFormat( format )
self.setLanguage( language )
self.setRights( rights )
self.setJurisdiction( jurisdiction )
self.setLocation( location )
self.setRelation( relation )
self.setSource( source )
self.setFunction( function )
self.setAudience( audience )
self.setMandate( mandate )
self.setSubjectMedium( subject_medium )
self.setSubjectColour( subject_colour )
self.setSubjectMatter( subject_matter )
self.setSubjectFocus( subject_focus )
self.setSubjectDimensions( subject_dimensions )
self.setCreator( creator )
# Aggregate Subject from the 4 subject components
LOG('ETIMetadataExtensions._editMetadata',INFO, subject)
if (subject):
self.setSubject(subject)
else:
self.setSubject(tuplize('subject_medium',self.SubjectMedium()) + tuplize('subject_colour',self.SubjectColour()) + tuplize('subject_matter',self.SubjectMatter()) + tuplize('subject_focus',self.SubjectFocus()))
self.reindexObject()
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'manage_editMetadata' )
def manage_editMetadata( self
, title
, subject
, description
, contributors
, effective_date
, expiration_date
, format
, language
, rights
, jurisdiction
, location
, relation
, source
, function
, audience
, mandate
, subject_medium
, subject_colour
, subject_matter
, subject_focus
, subject_dimensions
, creator
, REQUEST
):
"""
Update metadata from the ZMI.
"""
LOG('ETIMetadataExtensions.editMetaData',INFO, "about to call _editMetadata [%s]" % subject)
self._editMetadata(title
, subject
, description
, contributors
, effective_date
, expiration_date
, format
, language
, rights
, jurisdiction
, location
, relation
, source
, function
, audience
, mandate
, subject_medium
, subject_colour
, subject_matter
, subject_focus
, creator
)
REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
+ '/manage_metadata'
+ '?manage_tabs_message=Metadata+updated.' )
security.declareProtected( CMFCorePermissions.ModifyPortalContent
, 'editMetadata' )
editMetadata = WorkflowAction(_editMetadata)
security.declarePublic( 'getMetadataHeaders' )
def getMetadataHeaders( self ):
"""
Return RFC-822-style headers.
"""
hdrlist = []
hdrlist.append( ( 'Creator', self.Creator() ) )
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( ( '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() ) )
hdrlist.append( ( 'Jurisdiction', self.Jurisdiction() ) )
hdrlist.append( ( 'Location', self.Location() ) )
hdrlist.append( ( 'Relation', self.Relation() ) )
hdrlist.append( ( 'Source', self.Source() ) )
hdrlist.append( ( 'Function', self.Function() ) )
hdrlist.append( ( 'Audience', self.Audience() ) )
hdrlist.append( ( 'Mandate', self.Mandate() ) )
return hdrlist
# New meta data elements
DefaultDublinCoreImpl.Jurisdiction = Jurisdiction
DefaultDublinCoreImpl.setJurisdiction = setJurisdiction
DefaultDublinCoreImpl.Location = Location
DefaultDublinCoreImpl.setLocation = setLocation
DefaultDublinCoreImpl.Relation = Relation
DefaultDublinCoreImpl.setRelation = setRelation
DefaultDublinCoreImpl.Source = Source
DefaultDublinCoreImpl.setSource = setSource
DefaultDublinCoreImpl.Function = Function
DefaultDublinCoreImpl.setFunction = setFunction
DefaultDublinCoreImpl.Audience = Audience
DefaultDublinCoreImpl.setAudience = setAudience
DefaultDublinCoreImpl.Mandate = Mandate
DefaultDublinCoreImpl.setMandate = setMandate
DefaultDublinCoreImpl.SubjectMedium = SubjectMedium
DefaultDublinCoreImpl.setSubjectMedium = setSubjectMedium
DefaultDublinCoreImpl.SubjectColour = SubjectColour
DefaultDublinCoreImpl.setSubjectColour = setSubjectColour
DefaultDublinCoreImpl.SubjectMatter = SubjectMatter
DefaultDublinCoreImpl.setSubjectMatter = setSubjectMatter
DefaultDublinCoreImpl.SubjectFocus = SubjectFocus
DefaultDublinCoreImpl.setSubjectFocus = setSubjectFocus
DefaultDublinCoreImpl.SubjectDimensions = SubjectDimensions
DefaultDublinCoreImpl.setSubjectDimensions = setSubjectDimensions
DefaultDublinCoreImpl.UniqueID = UniqueID
PortalContent.manage_afterClone = manage_afterClone
# rebind the methods
DefaultDublinCoreImpl.setContributors = setContributors
DefaultDublinCoreImpl.Contributors = Contributors
DefaultDublinCoreImpl.getMetadataHeaders = getMetadataHeaders
DefaultDublinCoreImpl.__init__ = __init__
DefaultDublinCoreImpl._editMetadata = _editMetadata
DefaultDublinCoreImpl.manage_editMetadata = manage_editMetadata
DefaultDublinCoreImpl.editMetadata = editMetadata
DefaultDublinCoreImpl.Creator = Creator
DefaultDublinCoreImpl.setCreator = setCreator
# Do we need this??
security.declareProtected(AccessContentsInformation, 'objectItems')
def objectItems(self):
"""
since 'talkback' is the only opaque item on content
right now, I will return that. Should be replaced with
a list of tuples for every opaque item!
"""
if hasattr( aq_base( self ), 'talkback' ):
talkback = self.talkback
if talkback is not None:
return ((talkback.id, talkback),)
else:
return []
PortalContent.objectItems = objectItems
--------------040403030808000300090105--