eggification
[Portfolio.git] / Products / Portfolio / photo.py
diff --git a/Products/Portfolio/photo.py b/Products/Portfolio/photo.py
new file mode 100755 (executable)
index 0000000..f0a76f5
--- /dev/null
@@ -0,0 +1,227 @@
+# -*- coding: utf-8 -*-
+############################################################
+# Copyright © 2005-2008  Benoît PIN <benoit.pin@ensmp.fr>  #
+# Plinn - http://plinn.org                                 #
+#                                                          #
+# This program is free software; you can redistribute it   #
+# and/or modify it under the terms of the Creative Commons #
+# "Attribution-Noncommercial 2.0 Generic"                  #
+# http://creativecommons.org/licenses/by-nc/2.0/           #
+############################################################
+""" CMFAware Image
+"""
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from AccessControl.requestmethod import postonly
+from DateTime import DateTime
+from Products.CMFCore.permissions import View, AccessContentsInformation, \
+                                                                                ModifyPortalContent, ManageProperties, \
+                                                                                ReviewPortalContent
+from permissions import ViewRawImage
+from zope.component.factory import Factory
+from zope.interface import implements
+from webdav.interfaces import IWriteLock
+from Products.CMFCore.interfaces import IContentish
+from Products.CMFCore.interfaces import IDynamicType
+
+from Products.CMFCore.DynamicType import DynamicType
+from Products.CMFCore.CMFCatalogAware import CMFCatalogAware
+from Products.Photo.Photo import Photo as BasePhoto
+from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
+from Products.CMFCore.utils import getToolByName, getUtilityByInterfaceName
+from Products.Photo.cache import memoizedmethod
+from Products.DCWorkflow.utils import modifyRolesForPermission
+from interfaces import IPhoto
+
+class Photo(DynamicType, CMFCatalogAware, BasePhoto, DefaultDublinCoreImpl) :
+       """ Photo CMF aware """
+       
+       implements(IPhoto, IContentish, IWriteLock, IDynamicType)
+       
+       meta_type = BasePhoto.meta_type
+       manage_options = BasePhoto.manage_options
+       security = ClassSecurityInfo()
+       
+       security.declareProtected(ViewRawImage, 'index_html')
+       security.declareProtected(ViewRawImage, 'getJpegImage')
+               
+       def __init__(self, id, title='', file='', content_type='', precondition='', **kw) :
+               DefaultDublinCoreImpl.__init__(self, title=title)
+               BasePhoto.__init__(self, id, title, file, content_type=content_type, precondition=precondition, **kw)
+               self.id = id
+               self.title = title
+               
+               now = DateTime()
+               self.creation_date = now
+               self.modification_date = now
+               
+       def update_data(self, data, content_type=None) :
+               BasePhoto.update_data(self, data, content_type=content_type)
+               # update_data can be invoked during construction
+               # in this case, reindexObject put a parasite catalag entry.
+               if self.getParentNode() :
+                       self.reindexObject()
+       
+
+       def _getAfterResizingHooks(self) :
+               pim = getToolByName(self, 'portal_image_manipulation')
+               return pim.image.objectValues(['Script (Python)'])
+
+       def _getAfterTilingHooks(self) :
+               pim = getToolByName(self, 'portal_image_manipulation')
+               return pim.tile.objectValues(['Script (Python)'])
+       
+       #
+       # Dublin Core interface
+       #
+
+       security.declareProtected(View, 'Title')
+       @memoizedmethod()
+       def Title(self):
+               """ returns dc:title from xmp
+               """
+               photoshopHeadline = self.getXmpValue('photoshop:Headline')
+               dcTitle = self.getXmpValue('dc:title')
+
+               return dcTitle or photoshopHeadline
+       
+
+       security.declareProtected(View, 'listCreators')
+       @memoizedmethod()
+       def listCreators(self):
+               """ returns creator from dc:creator from xmp
+               """
+               return self.getXmpValue('dc:creator')
+       
+
+       security.declareProtected(View, 'Description')
+       @memoizedmethod()
+       def Description(self) :
+               """ returns dc:description from xmp """
+               return self.getXmpValue('dc:description')
+       
+
+       security.declareProtected(View, 'Subject')
+       @memoizedmethod()
+       def Subject(self):
+               """ returns subject from dc:subject from xmp
+               """
+               return self.getXmpValue('dc:subject')
+       
+       security.declareProtected(View, 'Rights')
+       @memoizedmethod()
+       def Rights(self):
+               """ returns rights from dc:rights from xmp
+               """
+               return self.getXmpValue('dc:rights')
+
+       security.declareProtected(ModifyPortalContent, 'editMetadata')
+       def editMetadata(self, **kw):
+               """
+               Need to add check for webDAV locked resource for TTW methods.
+               """
+               # as per bug #69, we cant assume they use the webdav
+               # locking interface, and fail gracefully if they dont
+               if hasattr(self, 'failIfLocked'):
+                       self.failIfLocked()
+                               
+               self.setXmpFields(**kw)
+               for name in ('Title', 'listCreators', 'Description', 'Subject', 'Rights') :
+                       self._clearCacheFor(name)
+               self.reindexObject()
+
+               
+       def _clearCacheFor(self, name) :
+               try :
+                       del self._methodResultsCache[name]
+               except KeyError : pass
+               
+       
+       security.declareProtected(View, 'SearchableText')
+       def SearchableText(self):
+               """ Return textuals metadata"""
+               
+               searchable = (self.Title()
+                                        , self.Description()
+                                        , ' '.join(self.Subject())
+                                        , self.getId()
+                                        , self.Creator())
+               return ' '.join(searchable)
+               
+       security.declareProtected(View, 'DateTimeOriginal')
+       @memoizedmethod()
+       def DateTimeOriginal(self) :
+               """ return DateTimeOriginal exif tag value or created """
+               dto = self.getXmpValue('exif:DateTimeOriginal') or self.getXmpValue('xmp:CreateDate')
+               if dto :
+                       return DateTime(dto)
+               else :
+                       return self.created()
+
+       
+       CreationDate = DefaultDublinCoreImpl.CreationDate
+       
+       Format = BasePhoto.getContentType
+
+       security.declareProtected(ReviewPortalContent, 'hideForAnonymous')
+       @postonly
+       def hideForAnonymous(self, REQUEST=None):
+               ' '
+               modifyRolesForPermission(self, View, ( 'Contributor'
+                                                                                        , 'Downloader'
+                                                                                        , 'Manager'
+                                                                                        , 'Owner'
+                                                                                        , 'Reader')
+                                                                                       )
+               self._hiddenForAnon = True
+               self.reindexObjectSecurity()
+               self.reindexObject(idxs=['hiddenForAnonymous'])
+       
+       
+       security.declareProtected(ReviewPortalContent, 'resetHide')
+       @postonly
+       def resetHide(self, REQUEST=None):
+               ' '
+               modifyRolesForPermission(self, View, [])
+               self._hiddenForAnon = False
+               self.reindexObjectSecurity()
+               self.reindexObject(idxs=['hiddenForAnonymous'])
+       
+       security.declareProtected(View, 'hiddenForAnonymous')
+       def hiddenForAnonymous(self):
+               return getattr(self, '_hiddenForAnon', False)
+               
+       
+       #
+       # SimpleItem interface
+       #
+       
+       def title_or_id(self):
+               """Return the title if it is not blank and the id otherwise.
+               """
+               return self.Title().strip() or self.getId()
+
+       def title_and_id(self):
+               """Return the title if it is not blank and the id otherwise.
+
+               If the title is not blank, then the id is included in parens.
+               """
+               title = self.Title()
+               id = self.getId()
+               return title and ("%s (%s)" % (title,id)) or id
+               
+       
+InitializeClass(Photo)
+
+class _PhotoFactory(Factory) :
+    def __call__(self, *args, **kw):
+        if not kw.has_key('thumb_height') or not kw.has_key('thumb_width') :
+            utool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool')
+            portal = utool.getPortalObject()
+            size = portal.getProperty('thumb_size')
+            kw.update({'thumb_height' : size, 'thumb_width' : size })
+        return self._callable(*args, **kw)
+    
+
+PhotoFactory = _PhotoFactory(Photo)
\ No newline at end of file