def patch_class_security(self, klass, method_name, new_permission): """Monkey patch class security definitions to protect a method with a different permission. """ def reset_security_for_attribute(name, klass): """Remove security declarations for a particular method / attribute by filtering declarations for that attribute from __ac_permissions__. """ new_ac_permissions = [] for permission_mapping in klass.__ac_permissions__: permission, names = permission_mapping if name not in names: new_ac_permissions.append(permission_mapping) else: new_names = tuple([n for n in names if n != name]) modified_mapping = (permission, new_names) new_ac_permissions.append(modified_mapping) klass.__ac_permissions__ = tuple(new_ac_permissions) reset_security_for_attribute(method_name, klass) sec = ClassSecurityInfo() sec.declareProtected(new_permission, method_name) sec.apply(klass) InitializeClass(klass)
def disablePasResources(event): """Disable access to users/groups/roles management PAS plugins from browser as they have no protection from CSRF attacks. """ try: zport = getattr(event.app, 'zport', None) if not zport or getattr(zport.dmd, 'allowManageAccess', False): return for class_ in (ZODBUserManager.ZODBUserManager, ZODBGroupManager.ZODBGroupManager, ZODBRoleManager.ZODBRoleManager): security = ClassSecurityInfo() security.declareObjectPrivate() security.apply(class_) except AttributeError: pass
def test_security_defined_on_class(self): # wrapping a method in an interaction workflow adds a default security to # this method, but does not override existing security definition (defined # on the class) Organisation = Products.ERP5.Document.Organisation.Organisation security = ClassSecurityInfo() security.declarePrivate('doSomethingStupid') security.apply(Organisation) self.createInteractionWorkflow() self.interaction.setProperties( 'default', method_id='doSomethingStupid', after_script_name=('afterEdit',)) self.script.ZPythonScript_edit('sci', '') self.createData() self.assertEqual(self.organisation.doSomethingStupid__roles__, ())
class TransformsChain(Implicit, Item, RoleManager, Persistent): """ a transforms chain is suite of transforms to apply in order. It follows the transform API so that a chain is itself a transform. """ module = 'N/A' meta_type = 'TransformsChain' meta_types = all_meta_types = () manage_options = ( ({'label':'Configure', 'action':'manage_main'}, {'label':'Reload', 'action':'manage_reloadTransform'},) + Item.manage_options ) manage_main = PageTemplateFile('editTransformsChain', _www) manage_reloadTransform = PageTemplateFile('reloadTransform', _www) security = ClassSecurityInfo() def __init__(self, id, description, ids=()): self.id = id self.description = description self._object_ids = list(ids) self.inputs = ('application/octet-stream',) self.output = 'application/octet-stream' self._chain = None def _chain_init(self): """ build the transforms chain """ tr_tool = getToolByName(self, 'portal_transforms') self._chain = c = chain() for id in self._object_ids: object = getattr(tr_tool, id) c.registerTransform(object) self.inputs = c.inputs or ('application/octet-stream',) self.output = c.output or 'application/octet-stream' security.declarePublic('convert') def convert(self, *args, **kwargs): """ return apply the transform and return the result """ if self._chain is None: self._chain_init() return self._chain.convert(*args, **kwargs) security.declarePublic('name') def name(self): """return the name of the transform instance""" return self.id security.declarePrivate('manage_beforeDelete') def manage_beforeDelete(self, item, container): Item.manage_beforeDelete(self, item, container) if self is item: # unregister self from catalog on deletion tr_tool = getToolByName(self, 'portal_transforms') tr_tool.unregisterTransform(self.id) security.declareProtected(ManagePortal, 'manage_addObject') def manage_addObject(self, id, REQUEST=None): """ add a new transform or chain to the chain """ assert id not in self._object_ids self._object_ids.append(id) self._chain_init() if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') security.declareProtected(ManagePortal, 'manage_delObjects') def manage_delObjects(self, ids, REQUEST=None): """ delete the selected mime types """ for id in ids: self._object_ids.remove(id) self._chain_init() if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') # transforms order handling # security.declareProtected(ManagePortal, 'move_object_to_position') def move_object_to_position(self, id, newpos): """ overriden from OrderedFolder to store id instead of objects """ oldpos = self._object_ids.index(id) if (newpos < 0 or newpos == oldpos or newpos >= len(self._object_ids)): return 0 self._object_ids.pop(oldpos) self._object_ids.insert(newpos, id) self._chain_init() return 1 security.declareProtected(ManageProperties, 'move_object_up') def move_object_up(self, id, REQUEST=None): """ move object with the given id up in the list """ newpos = self._object_ids.index(id) - 1 self.move_object_to_position(id, newpos) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') security.declareProtected(ManageProperties, 'move_object_down') def move_object_down(self, id, REQUEST=None): """ move object with the given id down in the list """ newpos = self._object_ids.index(id) + 1 self.move_object_to_position(id, newpos) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') # Z transform interface # security.declareProtected(ManagePortal, 'reload') def reload(self): """ reload the module where the transformation class is defined """ for tr in self.objectValues(): tr.reload() self._chain_init() # utilities # security.declareProtected(ManagePortal, 'listAddableObjectIds') def listAddableObjectIds(self): """ return a list of addable transform """ tr_tool = getToolByName(self, 'portal_transforms') return [id for id in tr_tool.objectIds() if not (id == self.id or id in self._object_ids)] security.declareProtected(ManagePortal, 'objectIds') def objectIds(self): """ return a list of addable transform """ return tuple(self._object_ids) security.declareProtected(ManagePortal, 'objectValues') def objectValues(self): """ return a list of addable transform """ tr_tool = getToolByName(self, 'portal_transforms') return [getattr(tr_tool, id) for id in self.objectIds()]
LOGGER.info('Monkey patched webdav.LockItem.DEFAULTTIMEOUT') # -------- from plone.dexterity.content import Container # Change permission for manage_pasteObjects to "Add portal content" # See https://dev.plone.org/ticket/9177 # XXX Find a way to do this without patching __ac_permissions__ directly def drop_protected_attr_from_ac_permissions(attribute, classobj): new_mappings = [] for mapping in Container.__ac_permissions__: perm, attrs = mapping if not attribute in attrs: new_mappings.append(mapping) else: modified_attrs = tuple([a for a in attrs if not a == attribute]) modified_mapping = (perm, modified_attrs) new_mappings.append(modified_mapping) classobj.__ac_permissions__ = tuple(new_mappings) drop_protected_attr_from_ac_permissions('manage_pasteObjects', Container) sec = ClassSecurityInfo() sec.declareProtected(Products.CMFCore.permissions.AddPortalContent, 'manage_pasteObjects') sec.apply(Container) InitializeClass(Container) LOGGER.info('Monkey patched plone.dexterity.content.Container')
except ImportError: from Globals import InitializeClass from AdvancedQuery import Eq, In, Le, Ge, \ MatchGlob, MatchRegexp, \ Between, Not, And, Or, Generic, Indexed, \ _CompositeQuery, LiteralResultSet from eval import eval as _eval from ranking import RankByQueries_Sum, RankByQueries_Max ############################################################################ ## Security _allow_module('Products.AdvancedQuery') _s = ClassSecurityInfo(); _s.declarePublic('addSubquery') _CompositeQuery._s = _s; InitializeClass(_CompositeQuery) ############################################################################ ## ZCatalog extension def _makeAdvancedQuery(self,catalogSearchSpec): '''advanced query corresponding to *catalogSearchSpec* (a dictionary).''' q = And(); get = catalogSearchSpec.get for i in self.Indexes.objectIds(): vi = get(i) if vi is None or vi == '': continue if not (isinstance(vi, dict) and vi.get('query') is not None or getattr(vi, 'query', None) is not None): usage = get(i+'_usage') if usage is not None:
def default_encoding(self): try: from Products.LDAPUserFolder.utils import encoding except Exception, e: return "utf-8" else: return encoding def __init__(self, id, source_obj, title): """ constructor """ super(plugLDAPUserFolder, self).__init__(id, source_obj, title) self._user_objs = {} self.located = {} self.buffer = {} security = ClassSecurityInfo() def getUserLocation(self, user): return self.located.get(user, "-") def setUserLocation(self, user, user_location): self.located[user] = user_location self._p_changed = 1 def delUserLocation(self, user): try: del self.located[user] self._p_changed = 1 except: pass
security.declareProtected(PERMISSION_VIEW, 'getPages') getPages = BaseContainer.getItems security.declareProtected(PERMISSION_MANAGE_CONTENT, 'deletePage') deletePage = BaseContainer.deleteItem security.declareProtected(PERMISSION_VIEW, 'countPages') countPages = BaseContainer.countItems templates = ( 'zpt/page/PagesManagementHome', 'zpt/page/addPageForm', 'zpt/page/deletePageForm',) addTemplates2Class(PageContainer, templates, globals_=globals()) security = ClassSecurityInfo() security.declareProtected(PERMISSION_MANAGE_CONTENT, 'PagesManagementHome') security.declareProtected(PERMISSION_MANAGE_CONTENT, 'addPageForm') security.declareProtected(PERMISSION_MANAGE_CONTENT, 'deletePageForm') security.apply(PageContainer) InitializeClass(PageContainer) ###################################################################### ## Page ###################################################################### manage_addPageForm = PTF('zpt/page/addPageForm', globals()) def manage_addPage(context, id, title, abstract = u'', body=u'',publish_date=None, REQUEST=None):
assert getattr(self, id).meta_type == METATYPE_NEWSITEM self.manage_delObjects([id]) if REQUEST is not None: msg = "News item deleted" url = self.absolute_url()+'/NewsManagement' self.http_redirect(url, msg=msg) templates = ('zpt/NewsManagement', 'zpt/deleteNewsItemForm', ) addTemplates2Class(NewsContainer, templates, globals_=globals()) setattr(NewsContainer, 'rss.xml', NewsContainer.RSS) security = ClassSecurityInfo() security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'deleteNewsItemForm') security.apply(NewsContainer) InitializeClass(NewsContainer) #------------------------------------------------------------------------------- manage_addNewsItemForm = PTF('zpt/addNewsItemForm', globals()) def manage_suggestNewsItemId(self): """ suggest a new id """ return DateTime().strftime('newsitem-%d%b%Y')
'zpt/BlogManagementHome', 'zpt/FileManagementHome', 'zpt/search', 'dtml/manage_MenuItems', ('zpt/AdvancedManagement', 'manage_AdvancedManagement'), 'zpt/ManagementHeaderFooter', 'zpt/DocumentManagementHome', ('dtml/cms.js', 'cms_js_template'), 'zpt/page/PagesManagementHome', 'zpt/page/deletePageForm', 'zpt/faq/FAQManagementHome', ) addTemplates2Class(Homepage, templates) security = ClassSecurityInfo() security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'Management') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'NewsManagementHome') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'BlogManagementHome') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'FileManagementHome') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'DocumentManagementHome') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'PagesManagementHome') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'FAQManagementHome') #security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'addPageForm') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'deletePageForm') security.apply(Homepage) setattr(Homepage, 'cms.js', Homepage.cms_js) InitializeClass(Homepage)
class AnalysisService(BaseContent, HistoryAwareMixin): security = ClassSecurityInfo() schema = schema displayContentsTab = False implements(IAnalysisService) _at_rename_after_creation = True def _renameAfterCreation(self, check_auto_id=False): from bika.lims.idserver import renameAfterCreation return renameAfterCreation(self) security.declarePublic('getDiscountedPrice') def getDiscountedPrice(self): """ compute discounted price excl. vat """ price = self.getPrice() price = price and price or 0 discount = self.bika_setup.getMemberDiscount() discount = discount and discount or 0 return float(price) - (float(price) * float(discount)) / 100 security.declarePublic('getDiscountedCorporatePrice') def getDiscountedCorporatePrice(self): """ compute discounted corporate price excl. vat """ price = self.getCorporatePrice() price = price and price or 0 discount = self.bika_setup.getMemberDiscount() discount = discount and discount or 0 return float(price) - (float(price) * float(discount)) / 100 def getTotalPrice(self): """ compute total price """ price = self.getPrice() vat = self.getVAT() price = price and price or 0 vat = vat and vat or 0 return float(price) + (float(price) * float(vat)) / 100 def getTotalCorporatePrice(self): """ compute total price """ price = self.getCorporatePrice() vat = self.getVAT() price = price and price or 0 vat = vat and vat or 0 return float(price) + (float(price) * float(vat)) / 100 security.declarePublic('getTotalDiscountedPrice') def getTotalDiscountedPrice(self): """ compute total discounted price """ price = self.getDiscountedPrice() vat = self.getVAT() price = price and price or 0 vat = vat and vat or 0 return float(price) + (float(price) * float(vat)) / 100 security.declarePublic('getTotalDiscountedCorporatePrice') def getTotalDiscountedCorporatePrice(self): """ compute total discounted corporate price """ price = self.getDiscountedCorporatePrice() vat = self.getVAT() price = price and price or 0 vat = vat and vat or 0 return float(price) + (float(price) * float(vat)) / 100 def getDefaultVAT(self): """ return default VAT from bika_setup """ try: vat = self.bika_setup.getVAT() return vat except ValueError: return "0.00" security.declarePublic('getVATAmount') def getVATAmount(self): """ Compute VATAmount """ try: return "%.2f" % (self.getTotalPrice() - self.getPrice()) except: return "0.00" def getAnalysisCategories(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [('', '')] + [(o.UID, o.Title) for o in bsc(portal_type='AnalysisCategory', inactive_state='active')] o = self.getCategory() if o and o.UID() not in [i[0] for i in items]: items.append((o.UID(), o.Title())) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) def getMethods(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [('', '')] + [ (o.UID, o.Title) for o in bsc(portal_type='Method', inactive_state='active') ] o = self.getMethod() if o and o.UID() not in [i[0] for i in items]: items.append((o.UID(), o.Title())) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) def getInstruments(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [('', '')] + [ (o.UID, o.Title) for o in bsc(portal_type='Instrument', inactive_state='active') ] o = self.getInstrument() if o and o.UID() not in [i[0] for i in items]: items.append((o.UID(), o.Title())) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) def getCalculations(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [('', '')] + [ (o.UID, o.Title) for o in bsc(portal_type='Calculation', inactive_state='active') ] o = self.getCalculation() if o and o.UID() not in [i[0] for i in items]: items.append((o.UID(), o.Title())) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) def getDepartments(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [('', '')] + [ (o.UID, o.Title) for o in bsc(portal_type='Department', inactive_state='active') ] o = self.getDepartment() if o and o.UID() not in [i[0] for i in items]: items.append((o.UID(), o.Title())) items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items)) def getUncertainty(self, result=None): """ Return the uncertainty value, if the result falls within specified ranges for this service. """ if result is None: return None uncertainties = self.getUncertainties() if uncertainties: try: result = float(result) except: # if analysis result is not a number, then we assume in range return None for d in uncertainties: if float(d['intercept_min']) <= result <= float( d['intercept_max']): return d['errorvalue'] return None else: return None security.declarePublic('getContainers') def getContainers(self, instance=None): # On first render, the containers must be limited according to # self.Preservation(). After that, the JS takes care of it with # getContainers above. instance = instance or self return DisplayList( getContainers(instance, preservation=self.getPreservation(), allow_blank=False)) def getPreservations(self): bsc = getToolByName(self, 'bika_setup_catalog') items = [ (o.UID, o.Title) for o in bsc(portal_type='Preservation', inactive_state='active') ] items.sort(lambda x, y: cmp(x[1], y[1])) return DisplayList(list(items))
class PartitionSetupField(RecordsField): _properties = RecordsField._properties.copy() _properties.update({ 'subfields': ( 'sampletype', 'preservation', 'container', 'separate', 'vol', #'retentionperiod', ), 'subfield_labels': { 'sampletype': _('Sample Type'), 'preservation': _('Preservation'), 'container': _('Container'), 'separate': _('Separate Partition'), 'vol': _('Required Volume'), #'retentionperiod': _('Retention Period'), }, 'subfield_types': { 'separate': 'boolean', 'vol': 'int', 'container': 'selection', 'preservation': 'selection', }, 'subfield_vocabularies': { 'sampletype': 'SampleTypes', 'preservation': 'Preservations', 'container': 'Containers', }, 'subfield_sizes': { 'sampletype': 1, 'vol': 5, 'container': 5, 'preservation': 5, #'retentionperiod':10, } }) security = ClassSecurityInfo() security.declarePublic('SampleTypes') def SampleTypes(self, instance=None): instance = instance or self bsc = getToolByName(instance, 'bika_setup_catalog') items = [] for st in bsc(portal_type='SampleType', inactive_state='active', sort_on='sortable_title'): st = st.getObject() title = st.Title() if st.getUnit(): title += " %s" % (st.getUnit()) items.append((st.UID(), title)) items = [['', '']] + list(items) return DisplayList(items) security.declarePublic('Preservations') def Preservations(self, instance=None): instance = instance or self bsc = getToolByName(instance, 'bika_setup_catalog') items = [(c.UID, c.title) for c in bsc(portal_type='Preservation', inactive_state='active', sort_on='sortable_title')] items = [['', _('Any')]] + list(items) return DisplayList(items) security.declarePublic('Containers') def Containers(self, instance=None): instance = instance or self items = getContainers(instance, allow_blank=False) items = [['', _('Any')]] + list(items) return DisplayList(items)
from json import dumps from Products.CMFCore.utils import getToolByName from Products.ZCatalog.ZCatalog import manage_addZCatalog from Products.ZenModel.Device import Device from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex from Products.ZenUtils.NetworkTree import NetworkLink from Products.Zuul import getFacade from Products.ZenEvents.events2.processing import Manager from zenoss.protocols.protobufs.zep_pb2 import (SEVERITY_CRITICAL, SEVERITY_ERROR, SEVERITY_WARNING, SEVERITY_INFO, SEVERITY_DEBUG, SEVERITY_CLEAR) from zenoss.protocols.protobufs.zep_pb2 import STATUS_NEW, STATUS_ACKNOWLEDGED security = ClassSecurityInfo() NODE_IDS = dict(layer_3={ 'IpNetwork': 'networkId', 'Device': 'deviceId' }, layer_2={ 'LAN': 'lanId', 'Device': 'deviceId' }) def _getComplement(context, layer=3): key = 'layer_%d' % layer nodestuff = NODE_IDS[key] if not isinstance(context, basestring):
class FSImage(Acquisition.Implicit, Item_w__name__): """FSImages act like images but are not directly modifiable from the management interface.""" # Note that OFS.Image.Image is not a base class because it is mutable. meta_type = 'Filesystem Image' title = '' manage_options = ({ 'label': 'Customize', 'action': 'manage_main' }, #{'label':'View', 'action':'view_image_or_file'}, ) security = ClassSecurityInfo() security.declareObjectProtected(CMFCorePermissions.View) file_mod_time = 0 def __init__(self, id, filepath, fullname=None, properties=None): if properties: # Since props come from the filesystem, this should be # safe. self.__dict__.update(properties) self.__name__ = fullname or id # Use the whole filename. self.title = '' self._filepath = filepath fp = expandpath(self._filepath) try: self.file_mod_time = stat(fp)[8] except: pass self._readFile() security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = HTMLFile('dtml/custimage', globals()) security.declareProtected(ViewManagementScreens, 'manage_doCustomize') def manage_doCustomize(self, folder_path, data=None, RESPONSE=None): ''' Makes an Image with the same data. ''' custFolder = self.getCustomizableObject() fpath = tuple(split(folder_path, '/')) folder = self.restrictedTraverse(fpath) if data is None: data = self._readFile() id = self.getId() obj = Image(id, '', data) folder._verifyObjectPaste(obj, validate_src=0) folder._setObject(id, obj) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_main' % (folder.absolute_url(), id)) security.declareProtected(View, 'getImageFSPath') def getImageFSPath(self): ''' ''' return self._filepath def _readFile(self): fp = expandpath(self._filepath) file = open(fp, 'rb') try: data = file.read() finally: file.close() (self.content_type, self.width, self.height) = getImageInfo(data) return data def _updateFromFS(self): if Globals.DevelopmentMode: fp = expandpath(self._filepath) try: mtime = stat(fp)[8] except: mtime = 0 if mtime != self.file_mod_time: self.file_mod_time = mtime self._readFile() def getId(self): return self.__name__ #### The following is mainly taken from OFS/Image.py ### def __str__(self): return self.tag() security.declareProtected(View, 'tag') def tag(self, height=None, width=None, alt=None, scale=0, xscale=0, yscale=0, **args): """ Generate an HTML IMG tag for this image, with customization. Arguments to self.tag() can be any valid attributes of an IMG tag. 'src' will always be an absolute pathname, to prevent redundant downloading of images. Defaults are applied intelligently for 'height', 'width', and 'alt'. If specified, the 'scale', 'xscale', and 'yscale' keyword arguments will be used to automatically adjust the output height and width values of the image tag. """ self._updateFromFS() if height is None: height = self.height if width is None: width = self.width # Auto-scaling support xdelta = xscale or scale ydelta = yscale or scale if xdelta and width: width = str(int(width) * xdelta) if ydelta and height: height = str(int(height) * ydelta) result = '<img src="%s"' % (self.absolute_url()) if alt is None: alt = getattr(self, 'title', '') result = '%s alt="%s"' % (result, alt) if height: result = '%s height="%s"' % (result, height) if width: result = '%s width="%s"' % (result, width) if not 'border' in map(string.lower, args.keys()): result = '%s border="0"' % result for key in args.keys(): value = args.get(key) result = '%s %s="%s"' % (result, key, value) return '%s />' % result def id(self): return self.__name__ security.declareProtected(View, 'index_html') def index_html(self, REQUEST, RESPONSE): """ The default view of the contents of a File or Image. Returns the contents of the file or image. Also, sets the Content-Type HTTP header to the objects content type. """ # HTTP If-Modified-Since header handling. data = self._readFile() header = REQUEST.get_header('If-Modified-Since', None) if header is not None: header = string.split(header, ';')[0] # Some proxies seem to send invalid date strings for this # header. If the date string is not valid, we ignore it # rather than raise an error to be generally consistent # with common servers such as Apache (which can usually # understand the screwy date string as a lucky side effect # of the way they parse it). try: mod_since = long(DateTime(header).timeTime()) except: mod_since = None if mod_since is not None: last_mod = self.file_mod_time if last_mod > 0 and last_mod <= mod_since: RESPONSE.setStatus(304) return '' RESPONSE.setHeader('Last-Modified', rfc1123_date(self.file_mod_time)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', len(data)) return data security.declareProtected(View, 'view_image_or_file') def view_image_or_file(self, URL1): """ The default view of the contents of the File or Image. """ raise 'Redirect', URL1 security.declareProtected(View, 'get_size') def get_size(self): """Get the size of a file or image. Returns the size of the file or image. """ fp = expandpath(self._filepath) return path.getsize(fp) security.declareProtected(View, 'getContentType') def getContentType(self): """Get the content type of a file or image. Returns the content type (MIME type) of a file or image. """ self._updateFromFS() return self.content_type security.declareProtected(View, 'getModTime') def getModTime(self): ''' ''' self._updateFromFS() return DateTime(self.file_mod_time) security.declareProtected(View, 'manage_FTPget') manage_FTPget = index_html
class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin): """ An Person object holds the information about an person (ex. you, me, someone in the company, someone outside of the company, a member of the portal, etc.). Person objects can contain Coordinate objects (ex. Telephone, Url) as well a documents of various types. Person objects can be synchronized accross multiple sites. Person objects inherit from the Node base class (one of the 5 base classes in the ERP5 universal business model) """ meta_type = 'ERP5 Person' portal_type = 'Person' add_permission = Permissions.AddPortalContent zope.interface.implements(interfaces.INode) # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) # Declarative properties property_sheets = (PropertySheet.Base, PropertySheet.XMLObject, PropertySheet.CategoryCore, PropertySheet.DublinCore, PropertySheet.Reference, PropertySheet.Person, PropertySheet.Login, PropertySheet.Mapping, PropertySheet.Task) def _setTitle(self, value): """ Here we see that we must define a notion of priority in the way fields are updated """ if value != self.getTitle(): self.title = value security.declareProtected(Permissions.AccessContentsInformation, 'getTitle') def getTitle(self, **kw): """ Returns the title if it exists or a combination of first name, middle name and last name """ if not self.title: return ' '.join([ x for x in (self.getFirstName(), self.getMiddleName(), self.getLastName()) if x ]) else: return self.title security.declareProtected(Permissions.AccessContentsInformation, 'getTranslatedTitle') def getTranslatedTitle(self, **kw): """ Returns the title if it exists or a combination of first name, middle name and last name """ if not self.title: return ' '.join([ x for x in (self.getTranslatedFirstName(**kw), self.getTranslatedMiddleName(**kw), self.getTranslatedLastName(**kw)) if x ]) else: return self.title security.declareProtected(Permissions.AccessContentsInformation, 'title_or_id') def title_or_id(self): return self.getTitleOrId() security.declareProtected(Permissions.AccessContentsInformation, 'hasTitle') def hasTitle(self): return not not self.getTitle() def _setReference(self, value): """ Set the user id. This method is defined explicitly, because: - we want to apply a different permission - we want to prevent duplicated user ids, but only when PAS _AND_ ERP5UserManager are used """ activate_kw = {} portal = self.getPortalObject() if value: # Encode reference to hex to prevent uppercase/lowercase conflict in # activity table (when calling countMessageWithTag) activate_kw['tag'] = tag = 'Person_setReference_' + value.encode( 'hex') # Check that there no existing user acl_users = portal.acl_users if PluggableAuthService is not None and isinstance( acl_users, PluggableAuthService.PluggableAuthService. PluggableAuthService): plugin_list = acl_users.plugins.listPlugins( PluggableAuthService.interfaces.plugins. IUserEnumerationPlugin) for plugin_name, plugin_value in plugin_list: if isinstance(plugin_value, ERP5UserManager): user_list = acl_users.searchUsers(id=value, exact_match=True) if len(user_list) > 0: raise RuntimeError, 'user id %s already exist' % ( value, ) break # Check that there is no reindexation related to reference indexation if portal.portal_activities.countMessageWithTag(tag): raise RuntimeError, 'user id %s already exist' % (value, ) # Prevent concurrent transaction to set the same reference on 2 # different persons self.getParentValue().serialize() # Prevent to set the same reference on 2 different persons during the # same transaction transactional_variable = getTransactionalVariable() if tag in transactional_variable: raise RuntimeError, 'user id %s already exist' % (value, ) else: transactional_variable[tag] = None self._baseSetReference(value) self.reindexObject(activate_kw=activate_kw) # invalid the cache for ERP5Security portal_caches = portal.portal_caches portal_caches.clearCache(cache_factory_list=('erp5_content_short', )) # Time management security.declareProtected(Permissions.AccessContentsInformation, 'getAvailableTime') def getAvailableTime(self, *args, **kw): """ Calculate available time for a person See SimulationTool.getAvailableTime """ kw['node'] = [self.getUid()] portal_simulation = self.getPortalObject().portal_simulation return portal_simulation.getAvailableTime(*args, **kw) security.declareProtected(Permissions.AccessContentsInformation, 'getAvailableTimeSequence') def getAvailableTimeSequence(self, *args, **kw): """ Calculate available time for a person in a sequence See SimulationTool.getAvailableTimeSequence """ kw['node'] = [self.getUid()] portal_simulation = self.getPortalObject().portal_simulation return portal_simulation.getAvailableTimeSequence(*args, **kw) # Notifiation API security.declareProtected(Permissions.AccessContentsInformation, 'notifyMessage') def notifyMessage(self, message): """
class PlominoDocument(CatalogAware, CMFBTreeFolder, Contained): """ These represent the contents in a Plomino database. A document contains *items* that may or may not correspond to fields on one or more forms. """ security = ClassSecurityInfo() implements(interfaces.IPlominoDocument, IAttributeAnnotatable) portal_type = "PlominoDocument" meta_type = "PlominoDocument" security.declarePublic('__init__') def __init__(self, id): """ Initialization """ CMFBTreeFolder.__init__(self, id) self.id = id self.items = PersistentDict() self.plomino_modification_time = DateTime().toZone('UTC') security.declarePublic('checkBeforeOpenDocument') def checkBeforeOpenDocument(self): """ Check read permission and open view. .. NOTE:: if ``READ_PERMISSION`` is set on the ``view`` action itself, it causes an error ('maximum recursion depth exceeded') if user hasn't permission. """ if self.isReader(): return self.OpenDocument() else: raise Unauthorized, "You cannot read this content" def doc_path(self): return self.getPhysicalPath() def doc_url(self): """ return valid and nice url: - hide plomino_documents - use physicalPathToURL if REQUEST available """ path = self.doc_path() short_path = [p for p in path if p!="plomino_documents"] if hasattr(self, "REQUEST"): return self.REQUEST.physicalPathToURL(short_path) else: return "/".join(short_path) security.declarePublic('setItem') def setItem(self,name,value): """ """ items = self.items if type(value) == type(''): db = self.getParentDatabase() translation_service = getToolByName(db, 'translation_service') value = translation_service.asunicodetype(value) items[name] = value self.items = items self.plomino_modification_time = DateTime().toZone('UTC') security.declarePublic('getItem') def getItem(self,name, default=''): """ """ if(self.items.has_key(name)): return deepcopy(self.items[name]) else: return default security.declarePublic('hasItem') def hasItem(self,name): """ """ return self.items.has_key(name) security.declarePublic('removeItem') def removeItem(self,name): """ """ if(self.items.has_key(name)): items = self.items del items[name] self.items = items security.declarePublic('getItems') def getItems(self): """ """ return self.items.keys() security.declarePublic('getItemClassname') def getItemClassname(self,name): """ """ return self.getItem(name).__class__.__name__ security.declarePublic('getLastModified') def getLastModified(self,asString=False): """ """ if not hasattr(self, 'plomino_modification_time'): self.plomino_modification_time = self.bobobase_modification_time().toZone('UTC') if asString: return str(self.plomino_modification_time) else: return self.plomino_modification_time security.declarePublic('getRenderedItem') def getRenderedItem(self, itemname, form=None, formid=None, convertattachments=False): """ Return the item rendered according to the corresponding field. The used form can be, in order of precedence: - passed as the `form` parameter, - specified with the `formid` parameter and looked up, - looked up from the document. If no form or field is found, return the empty string. If `convertattachments` is True, then we assume that field attachments are text and append them to the rendered value. """ db = self.getParentDatabase() result = '' if not form: if formid: form = db.getForm(formid) else: form = self.getForm() if form: field = form.getFormField(itemname) if field: result = field.getFieldRender(form, self, False) if (field.getFieldType() == 'ATTACHMENT' and convertattachments): result += ' ' + db.getIndex().convertFileToText(self, itemname).decode('utf-8') result = result.encode('utf-8') return result security.declarePublic('tojson') def tojson(self, REQUEST=None, item=None, formid=None, rendered=False): """return item value as JSON (return all items if item=None) """ if not self.isReader(): raise Unauthorized, "You cannot read this content" datatables_format = False if REQUEST: REQUEST.RESPONSE.setHeader('content-type', 'application/json; charset=utf-8') item = REQUEST.get('item', item) formid = REQUEST.get('formid', formid) rendered_str = REQUEST.get('rendered', None) if rendered_str: rendered = True datatables_format_str = REQUEST.get('datatables', None) if datatables_format_str: datatables_format = True if not item: return json.dumps(self.items.data) if not formid: form = self.getForm() else: form = self.getParentDatabase().getForm(formid) if form: field = form.getFormField(item) if field: if field.getFieldType() == 'DATAGRID': adapt = field.getSettings() fieldvalue = adapt.getFieldValue(form, self, False, False, REQUEST) fieldvalue = adapt.rows(fieldvalue, rendered=rendered) if datatables_format: fieldvalue = { 'iTotalRecords': len(fieldvalue), 'aaData': fieldvalue } else: if rendered: fieldvalue = self.getRenderedItem(item, form) else: adapt = field.getSettings() fieldvalue = adapt.getFieldValue(form, self, False, False, REQUEST) else: fieldvalue = self.getItem(item) else: fieldvalue = self.getItem(item) return json.dumps(fieldvalue) security.declarePublic('computeItem') def computeItem(self, itemname, form=None, formid=None, store=True, report=True): """ return the item value according the formula of the field defined in the given form (use default doc form if None) and store the value in the doc (if store=True) """ result = None db = self.getParentDatabase() if not form: if not formid: form = self.getForm() else: form = db.getForm(formid) if form: result = form.computeFieldValue(itemname, self, report=report) if store: self.setItem(itemname, result) return result security.declarePublic('getPlominoReaders') def getPlominoReaders(self): """ """ if self.hasItem('Plomino_Readers'): return asList(self.Plomino_Readers) else: return ['*'] security.declarePublic('isReader') def isReader(self): """ """ return self.getParentDatabase().isCurrentUserReader(self) security.declarePublic('isAuthor') def isAuthor(self): """ """ return self.getParentDatabase().isCurrentUserAuthor(self) security.declareProtected(REMOVE_PERMISSION, 'delete') def delete(self, REQUEST=None): """delete the current doc """ db = self.getParentDatabase() db.deleteDocument(self) if not REQUEST is None: return_url = REQUEST.get('returnurl') REQUEST.RESPONSE.redirect(return_url) security.declareProtected(EDIT_PERMISSION, 'validation_errors') def validation_errors(self, REQUEST): """check submitted values """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors=form.validateInputs(REQUEST, doc=self) if len(errors)>0: return self.errors_json(errors=json.dumps({'success': False,'errors':errors})) else: return self.errors_json(errors=json.dumps({'success': True})) security.declareProtected(EDIT_PERMISSION, 'saveDocument') def saveDocument(self, REQUEST, creation=False): """save a document using the form submitted content """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors=form.validateInputs(REQUEST, doc=self) if len(errors)>0: return form.notifyErrors(errors) self.setItem('Form', form.getFormName()) # process editable fields (we read the submitted value in the request) form.readInputs(self, REQUEST, process_attachments=True) # refresh computed values, run onSave, reindex self.save(form, creation) redirect = REQUEST.get('plominoredirecturl') if not redirect: redirect = self.getItem("plominoredirecturl") if not redirect: redirect = self.absolute_url() REQUEST.RESPONSE.redirect(redirect) security.declareProtected(EDIT_PERMISSION, 'refresh') def refresh(self, form=None): """ re-compute fields and re-index document (onSave event is not called, and authors are not updated """ self.save(form, creation=False, refresh_index=True, asAuthor=False, onSaveEvent=False) security.declareProtected(EDIT_PERMISSION, 'save') def save(self, form=None, creation=False, refresh_index=True, asAuthor=True, onSaveEvent=True): """refresh values according form, and reindex the document """ # we process computed fields (refresh the value) if form is None: form = self.getForm() else: self.setItem('Form', form.getFormName()) db=self.getParentDatabase() if form: for f in form.getFormFields(includesubforms=True, doc=self, applyhidewhen=False): mode = f.getFieldMode() fieldname = f.id if mode in ["COMPUTED", "COMPUTEDONSAVE"] or (mode=="CREATION" and creation): result = form.computeFieldValue(fieldname, self) self.setItem(fieldname, result) else: # computed for display field are not stored pass # compute the document title title_formula = form.getDocumentTitle() if title_formula: # Use the formula if we have one try: title = self.runFormulaScript("form_"+form.id+"_title", self, form.DocumentTitle) if title != self.Title(): self.setTitle(title) except PlominoScriptException, e: e.reportError('Title formula failed') elif creation: # If we have no formula and we're creating, use Form's title title = form.Title() if title != self.Title(): # We may be calling save with 'creation=True' on # existing documents, in which case we may already have # a title. self.setTitle(title) # update the document id if creation and form.getDocumentId(): new_id = self.generateNewId() if new_id: transaction.savepoint(optimistic=True) db.documents.manage_renameObject(self.id, new_id) # update the Plomino_Authors field with the current user name if asAuthor: authors = self.getItem('Plomino_Authors') name = db.getCurrentUser().getUserName() if authors == '': authors = [] authors.append(name) elif name in authors: pass else: authors.append(name) self.setItem('Plomino_Authors', authors) # execute the onSaveDocument code of the form if form and onSaveEvent: try: result = self.runFormulaScript("form_"+form.id+"_onsave", self, form.onSaveDocument) if result and hasattr(self, 'REQUEST'): self.REQUEST.set('plominoredirecturl', result) except PlominoScriptException, e: if hasattr(self, 'REQUEST'): e.reportError('Document has been saved but onSave event failed.') doc_path = self.REQUEST.physicalPathToURL(self.doc_path()) self.REQUEST.RESPONSE.redirect(doc_path)
class PortalFolderBase(DynamicType, CMFCatalogAware, Folder): """Base class for portal folder """ meta_type = 'Portal Folder Base' implements(IFolderish) __implements__ = (z2IFolderish, DynamicType.__implements__, Folder.__implements__) security = ClassSecurityInfo() description = '' manage_options = (Folder.manage_options + CMFCatalogAware.manage_options) def __init__(self, id, title=''): self.id = id self.title = title # # 'MutableDublinCore' interface methods # security.declareProtected(ManageProperties, 'setTitle') def setTitle(self, title): """ Set Dublin Core Title element - resource name. """ self.title = title security.declareProtected(ManageProperties, 'setDescription') def setDescription(self, description): """ Set Dublin Core Description element - resource summary. """ self.description = description # # other methods # security.declareProtected(ManageProperties, 'edit') def edit(self, title='', description=''): """ Edit the folder title (and possibly other attributes later) """ self.setTitle(title) self.setDescription(description) self.reindexObject() security.declarePublic('allowedContentTypes') def allowedContentTypes(self): """ List type info objects for types which can be added in this folder. """ result = [] portal_types = getToolByName(self, 'portal_types') myType = portal_types.getTypeInfo(self) if myType is not None: for contentType in portal_types.listTypeInfo(self): if myType.allowType(contentType.getId()): result.append(contentType) else: result = portal_types.listTypeInfo() return filter( lambda typ, container=self: typ.isConstructionAllowed(container), result) def _filteredItems(self, ids, filt): """ Apply filter, a mapping, to child objects indicated by 'ids', returning a sequence of ( id, obj ) tuples. """ # Restrict allowed content types if filt is None: filt = {} else: # We'll modify it, work on a copy. filt = filt.copy() pt = filt.get('portal_type', []) if type(pt) is type(''): pt = [pt] types_tool = getToolByName(self, 'portal_types') allowed_types = types_tool.listContentTypes() if not pt: pt = allowed_types else: pt = [t for t in pt if t in allowed_types] if not pt: # After filtering, no types remain, so nothing should be # returned. return [] filt['portal_type'] = pt query = ContentFilter(**filt) result = [] append = result.append get = self._getOb for id in ids: obj = get(id) if query(obj): append((id, obj)) return result # # 'Folderish' interface methods # security.declarePublic('contentItems') def contentItems(self, filter=None): # List contentish and folderish sub-objects and their IDs. # (method is without docstring to disable publishing) # ids = self.objectIds() return self._filteredItems(ids, filter) security.declarePublic('contentIds') def contentIds(self, filter=None): # List IDs of contentish and folderish sub-objects. # (method is without docstring to disable publishing) # return [item[0] for item in self.contentItems(filter)] security.declarePublic('contentValues') def contentValues(self, filter=None): # List contentish and folderish sub-objects. # (method is without docstring to disable publishing) # return [item[1] for item in self.contentItems(filter)] security.declareProtected(ListFolderContents, 'listFolderContents') def listFolderContents(self, contentFilter=None): """ List viewable contentish and folderish sub-objects. """ l = [] for id, obj in self.contentItems(contentFilter): # validate() can either raise Unauthorized or return 0 to # mean unauthorized. try: if getSecurityManager().validate(self, self, id, obj): l.append(obj) except zExceptions_Unauthorized: # Catch *all* Unauths! pass return l # # webdav Resource method # # protected by 'WebDAV access' def listDAVObjects(self): # List sub-objects for PROPFIND requests. # (method is without docstring to disable publishing) # if _checkPermission(ManagePortal, self): return self.objectValues() else: return self.listFolderContents() # # 'DublinCore' interface methods # security.declareProtected(View, 'Title') def Title(self): """ Dublin Core Title element - resource name. """ return self.title security.declareProtected(View, 'Description') def Description(self): """ Dublin Core Description element - resource summary. """ return self.description 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' # # other methods # security.declarePublic('encodeFolderFilter') def encodeFolderFilter(self, REQUEST): """ Parse cookie string for using variables in dtml. """ filter = {} for key, value in REQUEST.items(): if key[:10] == 'filter_by_': filter[key[10:]] = value encoded = base64.encodestring(marshal.dumps(filter)).strip() encoded = ''.join(encoded.split('\n')) return encoded security.declarePublic('decodeFolderFilter') def decodeFolderFilter(self, encoded): """ Parse cookie string for using variables in dtml. """ filter = {} if encoded: filter.update(marshal.loads(base64.decodestring(encoded))) return filter def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return None # Ensure pure PortalFolders don't get cataloged. # XXX We may want to revisit this. def indexObject(self): pass def unindexObject(self): pass def reindexObject(self, idxs=[]): pass def reindexObjectSecurity(self): pass def PUT_factory(self, name, typ, body): """ Factory for PUT requests to objects which do not yet exist. Used by NullResource.PUT. Returns -- Bare and empty object of the appropriate type (or None, if we don't know what to do) """ registry = getToolByName(self, 'content_type_registry', None) if registry is None: return None typeObjectName = registry.findTypeName(name, typ, body) if typeObjectName is None: return None self.invokeFactory(typeObjectName, name) # invokeFactory does too much, so the object has to be removed again obj = aq_base(self._getOb(name)) self._delObject(name) return obj security.declareProtected(AddPortalContent, 'invokeFactory') def invokeFactory(self, type_name, id, RESPONSE=None, *args, **kw): """ Invokes the portal_types tool. """ pt = getToolByName(self, 'portal_types') myType = pt.getTypeInfo(self) if myType is not None: if not myType.allowType(type_name): raise ValueError('Disallowed subobject type: %s' % type_name) return pt.constructContent(type_name, self, id, RESPONSE, *args, **kw) security.declareProtected(AddPortalContent, 'checkIdAvailable') def checkIdAvailable(self, id): try: self._checkId(id) except BadRequest: return False else: return True def MKCOL_handler(self, id, REQUEST=None, RESPONSE=None): """ Handle WebDAV MKCOL. """ self.manage_addFolder(id=id, title='') def _checkId(self, id, allow_dup=0): PortalFolderBase.inheritedAttribute('_checkId')(self, id, allow_dup) if allow_dup: return # FIXME: needed to allow index_html for join code if id == 'index_html': return # Another exception: Must allow "syndication_information" to enable # Syndication... if id == 'syndication_information': return # This code prevents people other than the portal manager from # overriding skinned names and tools. if not getSecurityManager().checkPermission(ManagePortal, self): ob = self while ob is not None and not getattr(ob, '_isPortalRoot', False): ob = aq_parent(aq_inner(ob)) if ob is not None: # If the portal root has a non-contentish object by this name, # don't allow an override. if (hasattr(ob, id) and id not in ob.contentIds() and # Allow root doted prefixed object name overrides not id.startswith('.')): raise BadRequest('The id "%s" is reserved.' % id) # Don't allow ids used by Method Aliases. ti = self.getTypeInfo() if ti and ti.queryMethodID(id, context=self): raise BadRequest('The id "%s" is reserved.' % id) # Otherwise we're ok. def _verifyObjectPaste(self, object, validate_src=1): # This assists the version in OFS.CopySupport. # It enables the clipboard to function correctly # with objects created by a multi-factory. securityChecksDone = False sm = getSecurityManager() parent = aq_parent(aq_inner(object)) object_id = object.getId() mt = getattr(object, '__factory_meta_type__', None) meta_types = getattr(self, 'all_meta_types', None) if mt is not None and meta_types is not None: method_name = None permission_name = None if callable(meta_types): meta_types = meta_types() for d in meta_types: if d['name'] == mt: method_name = d['action'] permission_name = d.get('permission', None) break if permission_name is not None: if not sm.checkPermission(permission_name, self): raise AccessControl_Unauthorized, method_name if validate_src: if not sm.validate(None, parent, None, object): raise AccessControl_Unauthorized, object_id if validate_src > 1: if not sm.checkPermission(DeleteObjects, parent): raise AccessControl_Unauthorized # validation succeeded securityChecksDone = 1 # # Old validation for objects that may not have registered # themselves in the proper fashion. # elif method_name is not None: meth = self.unrestrictedTraverse(method_name) factory = getattr(meth, 'im_self', None) if factory is None: factory = aq_parent(aq_inner(meth)) if not sm.validate(None, factory, None, meth): raise AccessControl_Unauthorized, method_name # Ensure the user is allowed to access the object on the # clipboard. if validate_src: if not sm.validate(None, parent, None, object): raise AccessControl_Unauthorized, object_id if validate_src > 1: # moving if not sm.checkPermission(DeleteObjects, parent): raise AccessControl_Unauthorized securityChecksDone = 1 # Call OFS' _verifyObjectPaste if necessary if not securityChecksDone: PortalFolderBase.inheritedAttribute('_verifyObjectPaste')( self, object, validate_src) # Finally, check allowed content types if hasattr(aq_base(object), 'getPortalTypeName'): type_name = object.getPortalTypeName() if type_name is not None: pt = getToolByName(self, 'portal_types') myType = pt.getTypeInfo(self) if myType is not None and not myType.allowType(type_name): raise ValueError('Disallowed subobject type: %s' % type_name) security.setPermissionDefault(AddPortalContent, ('Owner', 'Manager')) security.declareProtected(AddPortalFolders, 'manage_addFolder') def manage_addFolder(self, id, title='', REQUEST=None): """ Add a new folder-like object with id *id*. IF present, use the parent object's 'mkdir' alias; otherwise, just add a PortalFolder. """ ti = self.getTypeInfo() method_id = ti and ti.queryMethodID('mkdir', context=self) if method_id: # call it getattr(self, method_id)(id=id) else: self.invokeFactory(type_name='Folder', id=id) ob = self._getOb(id) ob.setTitle(title) try: ob.reindexObject() except AttributeError: pass if REQUEST is not None: return self.manage_main(self, REQUEST, update_menu=1)
# Rights Reserved. # # Authors: # # Cornel Nitu, Eau de Web Romania from Products import Naaya from Products.Naaya.NyFolder import NyFolder from AccessControl import ClassSecurityInfo from Products.NaayaBase.constants import PERMISSION_PUBLISH_OBJECTS, MESSAGE_SAVEDCHANGES from Products.Naaya.constants import METATYPE_FOLDER from naaya.content.semide.news.semnews_item import METATYPE_OBJECT as METATYPE_NYSEMNEWS from naaya.content.semide.event.semevent_item import METATYPE_OBJECT as METATYPE_NYSEMEVENT from Globals import InitializeClass security = ClassSecurityInfo() def getFolders(self): return [x for x in self.objectValues(METATYPE_FOLDER) if x.submitted==1] NyFolder.getFolders = getFolders def hasContent(self): return (len(self.getObjects()) > 0) or (len(self.objectValues(METATYPE_FOLDER)) > 0) NyFolder.hasContent = hasContent def getPublishedFolders(self): return self.utSortObjsListByAttr([x for x in self.objectValues(METATYPE_FOLDER) if x.approved==1 and x.submitted==1], 'sortorder', 0) NyFolder.getPublishedFolders = getPublishedFolders security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'basketofapprovals_published_html') def basketofapprovals_published_html(self, REQUEST=None, RESPONSE=None):
security.declareProtected(PERMISSION_VIEW, 'getFAQs') getFAQs = CategoriesContainer.getItems security.declareProtected(PERMISSION_MANAGE_CONTENT, 'deleteFAQ') deleteFAQ = BaseContainer.deleteItem security.declareProtected(PERMISSION_VIEW, 'countFAQ') countFAQ = BaseContainer.countItems templates = ('zpt/faq/FAQManagement', #'zpt/faq/addPageForm', 'zpt/faq/deleteFAQForm', ) addTemplates2Class(FAQContainer, templates, globals_=globals()) security = ClassSecurityInfo() #security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'addFAQForm') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'deleteFAQForm') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'FAQManagement') security.apply(FAQContainer) InitializeClass(FAQContainer) ###################################################################### ## FAQ ###################################################################### manage_addFAQForm = PTF('zpt/faq/addFAQForm', globals()) def manage_addFAQ(dispatcher, id, title, abstract='', body='', publish_date=None, category = None, REQUEST=None): """
class ActionsTool(UniqueObject, Folder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ __implements__ = (IActionsTool, ActionProviderBase.__implements__) id = 'portal_actions' meta_type = 'CMF Actions Tool' _actions = (ActionInformation( id='folderContents', title='Folder contents', action=Expression(text='string:${folder_url}/folder_contents'), condition=Expression(text='python: folder is not object'), permissions=(ListFolderContents, ), category='folder', visible=1), ) action_providers = ('portal_membership', 'portal_actions', 'portal_registration', 'portal_types', 'portal_discussion', 'portal_undo', 'portal_syndication', 'portal_workflow', 'portal_properties') security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Action Providers', 'action': 'manage_actionProviders' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainActionsTool', _dtmldir) manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) security.declareProtected(ManagePortal, 'manage_aproviders') def manage_aproviders(self, apname='', chosen=(), add_provider=0, del_provider=0, REQUEST=None): """ Manage action providers through-the-web. """ providers = list(self.listActionProviders()) new_providers = [] if add_provider: providers.append(apname) elif del_provider: for item in providers: if item not in chosen: new_providers.append(item) providers = new_providers self.action_providers = tuple(providers) if REQUEST is not None: return self.manage_actionProviders( self, REQUEST, manage_tabs_message='Providers changed.') # # Programmatically manipulate the list of action providers # security.declareProtected(ManagePortal, 'listActionProviders') def listActionProviders(self): """ List the ids of all Action Providers queried by this tool. """ return self.action_providers security.declareProtected(ManagePortal, 'addActionProvider') def addActionProvider(self, provider_name): """ Add an Action Provider id to the providers queried by this tool. """ ap = list(self.action_providers) if hasattr(self, provider_name) and provider_name not in ap: ap.append(provider_name) self.action_providers = tuple(ap) security.declareProtected(ManagePortal, 'deleteActionProvider') def deleteActionProvider(self, provider_name): """ Delete an Action Provider id from providers queried by this tool. """ ap = list(self.action_providers) if provider_name in ap: ap.remove(provider_name) self.action_providers = tuple(ap) # # 'portal_actions' interface methods # security.declarePublic('listFilteredActionsFor') def listFilteredActionsFor(self, object=None): """ List all actions available to the user. """ #cache = None #cache_mgr = getToolByName(self, 'portal_actionscache', None) #if cache_mgr is not None: # cache = cache_mgr.ZCacheManager_getCache() #if cache is not None: # pm = getToolByName(self, 'portal_membership') # if object is None: # object_url = '' # else: # object_url = object.absolute_url() # if pm.isAnonymousUser(): # member = None # else: # member = pm.getAuthenticatedMember() # # Prepare a cache key. # keyset = {'object_url': object_url, # 'member': member, # } # result = cache.ZCache_get(ob=self, keywords=keyset) # if result is not None: # # Got a cached value. # return result actions = [] ec = getExprContext(self, object) # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getattr(self, provider_name) if IActionProvider.isImplementedBy(provider): start = time() actions.extend(provider.listActionInfos(object=object, ec=ec)) stop = time() open('/tmp/provider_times', 'a').write('%-20s: %8.3f\n' % (provider_name, (stop - start) * 1000)) else: # for Action Providers written for CMF versions before 1.5 actions.extend(self._listActionInfos(provider, object)) # Include actions from object. if object is not None: base = aq_base(object) if IActionProvider.isImplementedBy(base): actions.extend(object.listActionInfos(object=object)) elif hasattr(base, 'listActions'): # for objects written for CMF versions before 1.5 actions.extend(self._listActionInfos(object, object)) # Reorganize the actions by category. filtered_actions = { 'user': [], 'folder': [], 'object': [], 'global': [], 'workflow': [], } for action in actions: catlist = filtered_actions.setdefault(action['category'], []) catlist.append(action) #if cache is not None: # result = cache.ZCache_set(ob=self, data=filtered_actions, # keywords=keyset) return filtered_actions # listFilteredActions() is an alias. security.declarePublic('listFilteredActions') listFilteredActions = listFilteredActionsFor security.declarePrivate('ZCacheable_getModTime') def ZCacheable_getModTime(self, mtime_func=None): '''Returns the highest of the last mod times.''' # Based on: # mtime_func # self.mtime # self.__class__.mtime # (if in a ZClass) zclass_instance.mtime # zclass_instance.__class__.mtime mtime = mtime_func and mtime_func() or 0 base = aq_base(self) return max(getattr(base, '_p_mtime', mtime), mtime) # # Helper method for backwards compatibility # def _listActionInfos(self, provider, object): """ for Action Providers written for CMF versions before 1.5 """ warn( 'ActionProvider interface not up to date. In CMF 1.6 ' 'portal_actions will ignore listActions() of \'%s\'.' % provider.getId(), DeprecationWarning) info = getOAI(self, object) actions = provider.listActions(info) action_infos = [] if actions and not isinstance(actions[0], dict): ec = getExprContext(self, object) for ai in actions: if not ai.getVisibility(): continue permissions = ai.getPermissions() if permissions: category = ai.getCategory() if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue if not ai.testCondition(ec): continue action_infos.append(ai.getAction(ec)) else: for i in actions: if not i.get('visible', 1): continue permissions = i.get('permissions', None) if permissions: category = i['category'] if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue action_infos.append(i) return action_infos
from Products.DCWorkflow.utils import Message as _ from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION from Products.CMFCore.utils import getToolByName from Products.ZSQLCatalog.SQLCatalog import SimpleQuery, AutoQuery, ComplexQuery, NegatedQuery from Products.CMFCore.utils import _getAuthenticatedUser from Products.ERP5Type import Permissions from Products.ERP5Type.Cache import CachingMethod from sets import ImmutableSet from Acquisition import aq_base from Persistence import Persistent from Products.ERP5Type.Globals import PersistentMapping from MySQLdb import ProgrammingError, OperationalError from DateTime import DateTime security = ClassSecurityInfo() WorkflowTool.security = security def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, transition_list, args=None, kw=None): """ Allows the system to request a workflow action. This method must perform its own security checks. """ if type(transition_list) in StringTypes: method_id = transition_list elif len(transition_list) == 1: method_id = transition_list[0] else: raise ValueError("WorkflowMethod should be attached to exactly 1 transition per DCWorkflow instance.") sdef = self._getWorkflowStateOf(ob)
class BusinessProcessConfiguratorItem(ConfiguratorItemMixin, XMLObject): """ Setup Rules. """ meta_type = 'ERP5 Business Process Configurator Item' portal_type = 'Business Process Configurator Item' add_permission = Permissions.AddPortalContent isPortalContent = 1 isRADContent = 1 # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) # Declarative interfaces zope.interface.implements(interfaces.IConfiguratorItem) # Declarative properties property_sheets = (PropertySheet.Base, PropertySheet.XMLObject, PropertySheet.CategoryCore, PropertySheet.DublinCore, PropertySheet.ConfiguratorItem, PropertySheet.Reference) def _build(self, business_configuration): portal = self.getPortalObject() business_process = portal.business_process_module.newContent( portal_type="Business Process", reference=self.getReference(), title=self.getTitle()) business_configuration.setGlobalConfigurationAttr(\ business_process_id=business_process.getId()) business_process_dict = self._getBusinessProcessDict() int_index = 0 for path_dict in business_process_dict["Trade Model Path"]: int_index += 1 path_dict.setdefault("int_index", int_index) title = path_dict.pop('title') trade_phase = path_dict.pop('trade_phase') trade_date = path_dict.pop('trade_date') for key in path_dict: if path_dict[key] is None: path_dict.pop(key) self._addTradeModelPath(business_process=business_process, title=title, trade_phase=trade_phase, trade_date=trade_date, **path_dict) int_index = 0 for link_dict in business_process_dict["Business Link"]: int_index += 1 link_dict.setdefault("int_index", int_index) title = link_dict.pop('title') trade_phase = link_dict.pop('trade_phase') delivery_builder = link_dict.pop('delivery_builder', None) predecessor = link_dict.pop('predecessor', None) successor = link_dict.pop('successor', None) for key in path_dict: if path_dict[key] is None: path_dict.pop(key) self._addBusinessLink(business_process=business_process, title=title, trade_phase=trade_phase, predecessor=predecessor, successor=successor, delivery_builder=delivery_builder, **link_dict) business_process.validate( comment=translateString('Validated by configurator')) self.install(business_process, business_configuration) def _getBusinessProcessDict(self): """ Read the spreadsheet and return the configuration for Trade Model Paths and Business Links. """ return self.ConfigurationTemplate_readOOCalcFile( "standard_business_process.ods", data=self.getDefaultConfigurationSpreadsheetData()) def _addTradeModelPath(self, business_process, title, trade_phase, trade_date, **kw): """ Add a trade model path to the business process. """ reference = "TMP-%s" % "-".join(title.upper().strip().split(" ")) path_id = "%s_path" % "_".join(title.lower().strip().split(" ")) trade_model_path = business_process.newContent( portal_type="Trade Model Path", id=path_id, title=title, reference=reference, **kw) trade_model_path.setTradePhase(trade_phase) if trade_date is not None: trade_model_path.setTradeDate('trade_phase/%s' % trade_date) def _addBusinessLink(self, business_process, title, trade_phase, predecessor, successor, delivery_builder, **kw): link_id = "%s_link" % "_".join(title.lower().strip().split(" ")) business_link = business_process.newContent( portal_type="Business Link", id=link_id, title=title, **kw) completed_state = kw.pop("completed_state", None) if completed_state is not None: business_link.setCompletedStateList(completed_state.split(",")) frozen_state = kw.pop("frozen_state", None) if frozen_state is not None: business_link.setFrozenStateList(frozen_state.split(",")) business_link.setTradePhase(trade_phase) if successor is not None: business_link.setSuccessor("trade_state/%s" % successor) if predecessor is not None: business_link.setPredecessor("trade_state/%s" % predecessor) if delivery_builder is not None: business_link.setDeliveryBuilderList( ["delivery_builder/portal_deliveries/%s" % \ i for i in delivery_builder.split(",")])
try: return int(num) except ValueError: raise e def page(self, number, softlimit=False): try: return super(ExPaginator, self).page(number) except InvalidPage, e: number = self._ensure_int(number, e) if number > self.num_pages and softlimit: return self.page(self.num_pages, softlimit=False) else: raise e security = ClassSecurityInfo() security.setDefaultAccess("allow") InitializeClass(ExPaginator) class DiggPaginator(ExPaginator): """ Based on Django's default paginator, it adds "Digg-style" page ranges with a leading block of pages, an optional middle block, and another block at the end of the page range. They are available as attributes on the page: {# with: page = digg_paginator.page(1) #} {% for num in page.leading_range %} ... {% for num in page.main_range %} ... {% for num in page.trailing_range %} ...
class AvailabilityColl(object): security = ClassSecurityInfo() security.setDefaultAccess('allow') @staticmethod def getDefaultAvailabilityStart(dmd): return time.time( ) - dmd.ZenEventManager.defaultAvailabilityDays * 24 * 60 * 60 @staticmethod def getDefaultAvailabilityEnd(): return time.time() # Simple record for holding availability information def __init__(self, device, component, downtime, total, DeviceGroup='', System='', Location='', DeviceClass='', link='', title=''): self.device = device self.component = component self.systems = System self.location = Location self.groups = DeviceGroup self.DeviceClass = DeviceClass self.link = link self.title = title # Guard against endDate being equal to or less than startDate. if total <= 0: self.availability = 0 if downtime else 1 else: self.availability = max(0, 1 - (float(downtime) / total)) def floatStr(self): return '%2.3f%%' % (self.availability * 100) def __str__(self): return self.floatStr() def __repr__(self): return '[%s %s %s]' % (self.device, self.component, self.floatStr()) def __float__(self): return float(self.availability) def __int__(self): return int(self.availability * 100) def __cmp__(self, other): return cmp((self.availability, self.device, self.component()), (other.availability, other.device, other.component())) def getDevice(self, dmd): return dmd.Devices.findDevice(self.device) def getComponent(self, dmd): if self.device and self.component: device = self.getDevice(dmd) if device: return _findComponent(device, self.component) return None def getDeviceLink(self, dmd=None): if self.link: return self.link if dmd: device = self.getDevice(dmd) if device: return device.getDeviceLink() return None
REQUEST['msg'] = msg return self.editCommentsForm(self,REQUEST) else: return msg templates = ('zpt/tabComments', 'zpt/editCommentsForm', 'zpt/mail_newCommentToWebmaster', 'zpt/mail_newCommentToParent', 'zpt/mail_rejectCommentToAuthor', 'zpt/mail_deleteCommentToAuthor', 'zpt/mail_approveCommentToAuthor', ) addTemplates2Class(CommentsStorage, templates, globals_=globals()) security = ClassSecurityInfo() security.declareProtected(VMS, 'tabComments') security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'editCommentsForm') security.declarePrivate('mail_newCommentToWebmaster') security.declarePrivate('mail_newCommentToParent') security.declarePrivate('mail_rejectCommentToAuthor') security.declarePrivate('mail_deleteCommentToAuthor') security.declarePrivate('mail_approveCommentToAuthor') security.apply(CommentsStorage) import unittest import sys class CommentsStorageTests(unittest.TestCase): """ Test class for CommentsStorage class
class ScriptChannel(PythonScript, utils): """ """ implements(IScriptChannel) meta_type = METATYPE_SCRIPTCHANNEL icon = 'misc_/NaayaCore/ScriptChannel.gif' manage_options = (({ 'label': 'Properties', 'action': 'manage_properties_html' }, ) + (PythonScript.manage_options[0], ) + PythonScript.manage_options[2:]) security = ClassSecurityInfo() def __init__(self, id, title, description, language, type, numberofitems): """ """ PythonScript.__dict__['__init__'](self, id) self.id = id self.title = title self.description = description self.language = language self.type = type self.numberofitems = numberofitems def ZPythonScript_setTitle(self, title): if isinstance(title, str): title = title.decode('utf-8') self.title = title self.ZCacheable_invalidate() security.declarePrivate('syndicateThis') def syndicateThis(self): xml = rss_item_for_channel(self) return etree.tostring(xml, xml_declaration=False, encoding="utf-8") security.declareProtected(view_management_screens, 'manageProperties') def manageProperties(self, title='', description='', language=None, type='', numberofitems='', REQUEST=None): """ """ if language is None: language = self.gl_get_selected_language() try: numberofitems = abs(int(numberofitems)) except: numberofitems = 0 self.title = title self.description = description self.language = language self.type = type self.numberofitems = numberofitems self._p_changed = 1 if REQUEST: REQUEST.RESPONSE.redirect('manage_properties_html') def get_objects_for_rdf(self, attr=None, reversed=False): # return the objects to be syndicated # sorted by the attribute attr objects = self._exec({'context': self, 'container': self}, {}, {}) if not objects: objects = [] now = DateTime() objects = [ ob for ob in objects if getattr(ob, 'topitem', None) or getattr(ob, 'expirationdate', now) is None or getattr(ob, 'expirationdate', now) + 1 > now ] if attr is not None: return utils.utSortObjsListByAttr(self, objects, attr, reversed) return objects security.declareProtected(view, 'index_html') def index_html(self, feed='', REQUEST=None, RESPONSE=None): """ """ if feed == 'atom': return self.syndicateAtom(self, self.get_objects_for_rdf(), self.language) s = self.getSite() lang = self.language if lang == 'auto': lang = self.gl_get_selected_language() l_items = self.get_objects_for_rdf() namespaces = self.getNamespaceItemsList() nsmap = get_nsmap(namespaces) header = [] for n in namespaces: header.append(str(n)) rdf_namespace = nsmap['rdf'] Rdf = ElementMaker(namespace=rdf_namespace, nsmap=nsmap) E = ElementMaker(None, nsmap=nsmap) xml = Rdf.RDF(rss_channel_for_channel(self, lang)) channel = xml[0] items = channel[-1] seq = etree.SubElement(items, '{%s}Seq' % rdf_namespace) for i in l_items: x = etree.SubElement(seq, '{%s}li' % rdf_namespace, resource=i.absolute_url()) if self.hasImage(): image = E.image(E.title(self.title), E.url(self.getImagePath()), E.link(s.absolute_url()), E.description(self.utToUtf8(self.description))) xml.append(image) received_items = ''.join([i.syndicateThis() for i in l_items]) received = '<rdf:RDF %s>%s</rdf:RDF>' % (''.join(header), received_items) xml_received = etree.XML(received, etree.XMLParser(strip_cdata=False)) xml.extend(xml_received) self.REQUEST.RESPONSE.setHeader('content-type', 'text/xml') return etree.tostring(xml, xml_declaration=True, encoding="utf-8") # zmi pages security.declareProtected(view_management_screens, 'manage_properties_html') manage_properties_html = PageTemplateFile('zpt/scriptchannel_properties', globals())
extension = filename.lower()[filename.rfind('.')+1:] if ICON_ASSOCIATIONS.has_key(extension): return '%s/%s'%(icon_location, ICON_ASSOCIATIONS[extension]) else: return default #security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'FileManagement') templates = ('zpt/FileManagement', 'zpt/deleteFileForm', ) addTemplates2Class(FilesContainer, templates, globals_=globals()) security = ClassSecurityInfo() security.declareProtected(MANAGE_CONTENT_PERMISSIONS, 'FileManagement') security.apply(FilesContainer) InitializeClass(FilesContainer) #------------------------------------------------------------------------------- manage_addFileForm = PTF('zpt/addFileForm', globals()) def manage_addFile(dispatcher, title, file, fileid='', abstract=u'', REQUEST=None): """ create """
class SetupTool(Folder): """ Profile-based site configuration manager. """ implements(ISetupTool) meta_type = 'Generic Setup Tool' _baseline_context_id = '' # BBB _import_context_id is a vestige of a stateful import context _import_context_id = '' _profile_upgrade_versions = {} security = ClassSecurityInfo() def __init__(self, id): self.id = str(id) self._import_registry = ImportStepRegistry() self._export_registry = ExportStepRegistry() self._toolset_registry = ToolsetRegistry() # # ISetupTool API # security.declareProtected(ManagePortal, 'getEncoding') def getEncoding(self): """ See ISetupTool. """ return 'utf-8' security.declareProtected(ManagePortal, 'getImportContextID') def getImportContextID(self): """ See ISetupTool. """ warn( 'getImportContextId, and the very concept of a stateful ' 'active import context, is deprecated. You can find the ' 'base profile that was applied using getBaselineContextID.', DeprecationWarning, stacklevel=2) return self._import_context_id security.declareProtected(ManagePortal, 'getBaselineContextID') def getBaselineContextID(self): """ See ISetupTool. """ return self._baseline_context_id security.declareProtected(ManagePortal, 'setImportContext') def setImportContext(self, context_id, encoding=None): """ See ISetupTool. """ warn( 'setImportContext is deprecated. Use setBaselineContext to ' 'specify the baseline context, and/or runImportStepFromProfile ' 'to run the steps from a specific import context.', DeprecationWarning, stacklevel=2) self._import_context_id = context_id context_type = BASE # snapshots are always baseline contexts if context_id.startswith('profile-'): profile_info = _profile_registry.getProfileInfo(context_id[8:]) context_type = profile_info['type'] if context_type == BASE: self.setBaselineContext(context_id, encoding) security.declareProtected(ManagePortal, 'setBaselineContext') def setBaselineContext(self, context_id, encoding=None): """ See ISetupTool. """ self._baseline_context_id = context_id self.applyContextById(context_id, encoding) security.declareProtected(ManagePortal, 'applyContextById') def applyContextById(self, context_id, encoding=None): context = self._getImportContext(context_id) self.applyContext(context, encoding) security.declareProtected(ManagePortal, 'applyContext') def applyContext(self, context, encoding=None): self._updateImportStepsRegistry(context, encoding) self._updateExportStepsRegistry(context, encoding) security.declareProtected(ManagePortal, 'getImportStepRegistry') def getImportStepRegistry(self): """ See ISetupTool. """ return self._import_registry security.declareProtected(ManagePortal, 'getExportStepRegistry') def getExportStepRegistry(self): """ See ISetupTool. """ return self._export_registry security.declareProtected(ManagePortal, 'getExportStep') def getExportStep(self, step, default=None): """Simple wrapper to query both the global and local step registry.""" res = _export_step_registry.getStep(step, default) if res is not default: return res return self._export_registry.getStep(step, default) security.declareProtected(ManagePortal, 'listExportSteps') def listExportSteps(self): steps = _export_step_registry.listSteps() + \ self._export_registry.listSteps() return tuple(set(steps)) security.declareProtected(ManagePortal, 'getImportStep') def getImportStep(self, step, default=None): """Simple wrapper to query both the global and local step registry.""" res = _import_step_registry.getStep(step, default) if res is not default: return res return self._import_registry.getStep(step, default) security.declareProtected(ManagePortal, 'getSortedImportSteps') def getSortedImportSteps(self): steps = _import_step_registry.listSteps() + \ self._import_registry.listSteps() step_infos = [self.getImportStepMetadata(step) for step in set(steps)] return tuple(_computeTopologicalSort(step_infos)) security.declareProtected(ManagePortal, 'getImportStepMetadata') def getImportStepMetadata(self, step, default=None): """Simple wrapper to query both the global and local step registry.""" res = self._import_registry.getStepMetadata(step, default) if res is not default: return res return _import_step_registry.getStepMetadata(step, default) security.declareProtected(ManagePortal, 'getExportStepMetadata') def getExportStepMetadata(self, step, default=None): """Simple wrapper to query both the global and local step registry.""" res = self._export_registry.getStepMetadata(step, default) if res is not default: return res return _export_step_registry.getStepMetadata(step, default) security.declareProtected(ManagePortal, 'getToolsetRegistry') def getToolsetRegistry(self): """ See ISetupTool. """ return self._toolset_registry security.declareProtected(ManagePortal, 'runImportStepFromProfile') def runImportStepFromProfile(self, profile_id, step_id, run_dependencies=True, purge_old=None): """ See ISetupTool. """ old_context = self._import_context_id context = self._getImportContext(profile_id, purge_old) self.applyContext(context) info = self.getImportStepMetadata(step_id) if info is None: self._import_context_id = old_context raise ValueError, 'No such import step: %s' % step_id dependencies = info.get('dependencies', ()) messages = {} steps = [] if run_dependencies: for dependency in dependencies: if dependency not in steps: steps.append(dependency) steps.append(step_id) full_import = (set(steps) == set(self.getSortedImportSteps())) event.notify( BeforeProfileImportEvent(self, profile_id, steps, full_import)) for step in steps: message = self._doRunImportStep(step, context) messages[step] = message or '' message_list = filter(None, [message]) message_list.extend(['%s: %s' % x[1:] for x in context.listNotes()]) messages[step_id] = '\n'.join(message_list) self._import_context_id = old_context event.notify(ProfileImportedEvent(self, profile_id, steps, full_import)) return {'steps': steps, 'messages': messages} security.declareProtected(ManagePortal, 'runImportStep') def runImportStep(self, step_id, run_dependencies=True, purge_old=None): """ See ISetupTool. """ warn( 'The runImportStep method is deprecated. Please use ' 'runImportStepFromProfile instead.', DeprecationWarning, stacklevel=2) return self.runImportStepFromProfile( self._import_context_id, step_id, run_dependencies, purge_old, ) security.declareProtected(ManagePortal, 'runAllImportStepsFromProfile') def runAllImportStepsFromProfile(self, profile_id, purge_old=None, ignore_dependencies=False, archive=None): """ See ISetupTool. """ __traceback_info__ = profile_id old_context = self._import_context_id result = self._runImportStepsFromContext( purge_old=purge_old, profile_id=profile_id, archive=archive, ignore_dependencies=ignore_dependencies) if profile_id is None: prefix = 'import-all-from-tar' else: prefix = 'import-all-%s' % profile_id.replace(':', '_') name = self._mangleTimestampName(prefix, 'log') self._createReport(name, result['steps'], result['messages']) self._import_context_id = old_context return result security.declareProtected(ManagePortal, 'runAllImportSteps') def runAllImportSteps(self, purge_old=None): """ See ISetupTool. """ warn( 'The runAllImportSteps method is deprecated. Please use ' 'runAllImportStepsFromProfile instead.', DeprecationWarning, stacklevel=2) context_id = self._import_context_id return self.runAllImportStepsFromProfile(self._import_context_id, purge_old) security.declareProtected(ManagePortal, 'runExportStep') def runExportStep(self, step_id): """ See ISetupTool. """ return self._doRunExportSteps([step_id]) security.declareProtected(ManagePortal, 'runAllExportSteps') def runAllExportSteps(self): """ See ISetupTool. """ return self._doRunExportSteps(self.listExportSteps()) security.declareProtected(ManagePortal, 'createSnapshot') def createSnapshot(self, snapshot_id): """ See ISetupTool. """ context = SnapshotExportContext(self, snapshot_id) messages = {} steps = self.listExportSteps() for step_id in steps: handler = self.getExportStep(step_id) if handler is None: logger = logging.getLogger('GenericSetup') logger.error('Step %s has an invalid handler' % step_id) continue messages[step_id] = handler(context) return { 'steps': steps, 'messages': messages, 'url': context.getSnapshotURL(), 'snapshot': context.getSnapshotFolder() } security.declareProtected(ManagePortal, 'compareConfigurations') def compareConfigurations( self, lhs_context, rhs_context, missing_as_empty=False, ignore_blanks=False, skip=SKIPPED_FILES, ): """ See ISetupTool. """ differ = ConfigDiff( lhs_context, rhs_context, missing_as_empty, ignore_blanks, skip, ) return differ.compare() security.declareProtected(ManagePortal, 'markupComparison') def markupComparison(self, lines): """ See ISetupTool. """ result = [] for line in lines.splitlines(): if line.startswith('** '): if line.find('File') > -1: if line.find('replaced') > -1: result.append(('file-to-dir', line)) elif line.find('added') > -1: result.append(('file-added', line)) else: result.append(('file-removed', line)) else: if line.find('replaced') > -1: result.append(('dir-to-file', line)) elif line.find('added') > -1: result.append(('dir-added', line)) else: result.append(('dir-removed', line)) elif line.startswith('@@'): result.append(('diff-range', line)) elif line.startswith(' '): result.append(('diff-context', line)) elif line.startswith('+'): result.append(('diff-added', line)) elif line.startswith('-'): result.append(('diff-removed', line)) elif line == '\ No newline at end of file': result.append(('diff-context', line)) else: result.append(('diff-header', line)) return '<pre>\n%s\n</pre>' % ('\n'.join( [('<span class="%s">%s</span>' % (cl, escape(l))) for cl, l in result])) # # ZMI # manage_options = ( Folder.manage_options[:1] + ( { 'label': 'Profiles', 'action': 'manage_tool' }, { 'label': 'Import', 'action': 'manage_importSteps' }, { 'label': 'Export', 'action': 'manage_exportSteps' }, { 'label': 'Upgrades', 'action': 'manage_upgrades' }, { 'label': 'Snapshots', 'action': 'manage_snapshots' }, { 'label': 'Comparison', 'action': 'manage_showDiff' }, { 'label': 'Manage', 'action': 'manage_stepRegistry' }, ) + Folder.manage_options[3:] # skip "View", "Properties" ) security.declareProtected(ManagePortal, 'manage_tool') manage_tool = PageTemplateFile('sutProperties', _wwwdir) security.declareProtected(ManagePortal, 'manage_updateToolProperties') def manage_updateToolProperties(self, context_id, RESPONSE): """ Update the tool's settings. """ self.setBaselineContext(context_id) RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s' % (self.absolute_url(), 'Properties+updated.')) security.declareProtected(ManagePortal, 'manage_importSteps') manage_importSteps = PageTemplateFile('sutImportSteps', _wwwdir) security.declareProtected(ManagePortal, 'manage_importSelectedSteps') def manage_importSelectedSteps(self, ids, run_dependencies, context_id=None): """ Import the steps selected by the user. """ messages = {} if not ids: summary = 'No steps selected.' else: if context_id is None: context_id = self.getBaselineContextID() steps_run = [] for step_id in ids: result = self.runImportStepFromProfile(context_id, step_id, run_dependencies) steps_run.extend(result['steps']) messages.update(result['messages']) summary = 'Steps run: %s' % ', '.join(steps_run) name = self._mangleTimestampName('import-selected', 'log') self._createReport(name, result['steps'], result['messages']) return self.manage_importSteps(manage_tabs_message=summary, messages=messages) security.declareProtected(ManagePortal, 'manage_importSelectedSteps') def manage_importAllSteps(self, context_id=None): """ Import all steps. """ if context_id is None: context_id = self.getBaselineContextID() result = self.runAllImportStepsFromProfile(context_id, purge_old=None) steps_run = 'Steps run: %s' % ', '.join(result['steps']) return self.manage_importSteps(manage_tabs_message=steps_run, messages=result['messages']) security.declareProtected(ManagePortal, 'manage_importExtensions') def manage_importExtensions(self, RESPONSE, profile_ids=()): """ Import all steps for the selected extension profiles. """ detail = {} if len(profile_ids) == 0: message = 'Please select one or more extension profiles.' RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s' % (self.absolute_url(), message)) else: message = 'Imported profiles: %s' % ', '.join(profile_ids) for profile_id in profile_ids: result = self.runAllImportStepsFromProfile(profile_id) for k, v in result['messages'].items(): detail['%s:%s' % (profile_id, k)] = v return self.manage_importSteps(manage_tabs_message=message, messages=detail) security.declareProtected(ManagePortal, 'manage_importTarball') def manage_importTarball(self, tarball): """ Import steps from the uploaded tarball. """ if getattr(tarball, 'read', None) is not None: tarball = tarball.read() result = self.runAllImportStepsFromProfile(None, True, archive=tarball) steps_run = 'Steps run: %s' % ', '.join(result['steps']) return self.manage_importSteps(manage_tabs_message=steps_run, messages=result['messages']) security.declareProtected(ManagePortal, 'manage_exportSteps') manage_exportSteps = PageTemplateFile('sutExportSteps', _wwwdir) security.declareProtected(ManagePortal, 'manage_exportSelectedSteps') def manage_exportSelectedSteps(self, ids, RESPONSE): """ Export the steps selected by the user. """ if not ids: RESPONSE.redirect('%s/manage_exportSteps?manage_tabs_message=%s' % (self.absolute_url(), 'No+steps+selected.')) result = self._doRunExportSteps(ids) RESPONSE.setHeader('Content-type', 'application/x-gzip') RESPONSE.setHeader('Content-disposition', 'attachment; filename=%s' % result['filename']) return result['tarball'] security.declareProtected(ManagePortal, 'manage_exportAllSteps') def manage_exportAllSteps(self, RESPONSE): """ Export all steps. """ result = self.runAllExportSteps() RESPONSE.setHeader('Content-type', 'application/x-gzip') RESPONSE.setHeader('Content-disposition', 'attachment; filename=%s' % result['filename']) return result['tarball'] security.declareProtected(ManagePortal, 'manage_upgrades') manage_upgrades = PageTemplateFile('setup_upgrades', _wwwdir) security.declareProtected(ManagePortal, 'upgradeStepMacro') upgradeStepMacro = PageTemplateFile('upgradeStep', _wwwdir) security.declareProtected(ManagePortal, 'manage_snapshots') manage_snapshots = PageTemplateFile('sutSnapshots', _wwwdir) security.declareProtected(ManagePortal, 'listSnapshotInfo') def listSnapshotInfo(self): """ Return a list of mappings describing available snapshots. o Keys include: 'id' -- snapshot ID 'title' -- snapshot title or ID 'url' -- URL of the snapshot folder """ result = [] snapshots = self._getOb('snapshots', None) if snapshots: for id, folder in snapshots.objectItems('Folder'): result.append({ 'id': id, 'title': folder.title_or_id(), 'url': folder.absolute_url() }) return result security.declareProtected(ManagePortal, 'listProfileInfo') def listProfileInfo(self): """ Return a list of mappings describing registered profiles. Base profile is listed first, extensions are sorted. o Keys include: 'id' -- profile ID 'title' -- profile title or ID 'description' -- description of the profile 'path' -- path to the profile within its product 'product' -- name of the registering product """ base = [] ext = [] for info in _profile_registry.listProfileInfo(): if info.get('type', BASE) == BASE: base.append(info) else: ext.append(info) ext.sort(lambda x, y: cmp(x['id'], y['id'])) return base + ext security.declareProtected(ManagePortal, 'listContextInfos') def listContextInfos(self): """ List registered profiles and snapshots. """ def readableType(x): if x is BASE: return 'base' elif x is EXTENSION: return 'extension' return 'unknown' s_infos = [{ 'id': 'snapshot-%s' % info['id'], 'title': info['title'], 'type': 'snapshot', } for info in self.listSnapshotInfo()] p_infos = [{ 'id': 'profile-%s' % info['id'], 'title': info['title'], 'type': readableType(info['type']), } for info in self.listProfileInfo()] return tuple(s_infos + p_infos) security.declareProtected(ManagePortal, 'getProfileImportDate') def getProfileImportDate(self, profile_id): """ See ISetupTool. """ prefix = ('import-all-%s-' % profile_id).replace(':', '_') candidates = [ x for x in self.objectIds('File') if x[:-18] == prefix and x.endswith('.log') ] if len(candidates) == 0: return None candidates.sort() last = candidates[-1] stamp = last[-18:-4] return '%s-%s-%sT%s:%s:%sZ' % ( stamp[0:4], stamp[4:6], stamp[6:8], stamp[8:10], stamp[10:12], stamp[12:14], ) security.declareProtected(ManagePortal, 'manage_createSnapshot') def manage_createSnapshot(self, RESPONSE, snapshot_id=None): """ Create a snapshot with the given ID. o If no ID is passed, generate one. """ if snapshot_id is None: snapshot_id = self._mangleTimestampName('snapshot') self.createSnapshot(snapshot_id) RESPONSE.redirect('%s/manage_snapshots?manage_tabs_message=%s' % (self.absolute_url(), 'Snapshot+created.')) return "" security.declareProtected(ManagePortal, 'manage_showDiff') manage_showDiff = PageTemplateFile('sutCompare', _wwwdir) def manage_downloadDiff( self, lhs, rhs, missing_as_empty, ignore_blanks, RESPONSE, ): """ Crack request vars and call compareConfigurations. o Return the result as a 'text/plain' stream, suitable for framing. """ comparison = self.manage_compareConfigurations( lhs, rhs, missing_as_empty, ignore_blanks, ) RESPONSE.setHeader('Content-Type', 'text/plain') return _PLAINTEXT_DIFF_HEADER % (lhs, rhs, comparison) security.declareProtected(ManagePortal, 'manage_compareConfigurations') def manage_compareConfigurations( self, lhs, rhs, missing_as_empty, ignore_blanks, ): """ Crack request vars and call compareConfigurations. """ lhs_context = self._getImportContext(lhs) rhs_context = self._getImportContext(rhs) return self.compareConfigurations( lhs_context, rhs_context, missing_as_empty, ignore_blanks, ) security.declareProtected(ManagePortal, 'manage_stepRegistry') manage_stepRegistry = PageTemplateFile('sutManage', _wwwdir) security.declareProtected(ManagePortal, 'manage_deleteImportSteps') def manage_deleteImportSteps(self, ids, request=None): if request is None: request = self.REQUEST for id in ids: self._import_registry.unregisterStep(id) self._p_changed = True url = self.absolute_url() request.RESPONSE.redirect("%s/manage_stepRegistry" % url) security.declareProtected(ManagePortal, 'manage_deleteExportSteps') def manage_deleteExportSteps(self, ids, request=None): if request is None: request = self.REQUEST for id in ids: self._export_registry.unregisterStep(id) self._p_changed = True url = self.absolute_url() request.RESPONSE.redirect("%s/manage_stepRegistry" % url) # # Upgrades management # security.declareProtected(ManagePortal, 'getLastVersionForProfile') def getLastVersionForProfile(self, profile_id): """Return the last upgraded version for the specified profile. """ version = self._profile_upgrade_versions.get(profile_id, 'unknown') return version security.declareProtected(ManagePortal, 'setLastVersionForProfile') def setLastVersionForProfile(self, profile_id, version): """Set the last upgraded version for the specified profile. """ if isinstance(version, basestring): version = tuple(version.split('.')) prof_versions = self._profile_upgrade_versions.copy() prof_versions[profile_id] = version self._profile_upgrade_versions = prof_versions security.declareProtected(ManagePortal, 'getVersionForProfile') def getVersionForProfile(self, profile_id): """Return the registered filesystem version for the specified profile. """ return self.getProfileInfo(profile_id).get('version', 'unknown') security.declareProtected(ManagePortal, 'profileExists') def profileExists(self, profile_id): """Check if a profile exists.""" try: self.getProfileInfo(profile_id) except KeyError: return False else: return True security.declareProtected(ManagePortal, "getProfileInfo") def getProfileInfo(self, profile_id): if profile_id.startswith("profile-"): profile_id = profile_id[len('profile-'):] elif profile_id.startswith("snapshot-"): profile_id = profile_id[len('snapshot-'):] return _profile_registry.getProfileInfo(profile_id) security.declareProtected(ManagePortal, 'getDependenciesForProfile') def getDependenciesForProfile(self, profile_id): if profile_id.startswith("snapshot-"): return () if not self.profileExists(profile_id): raise KeyError, profile_id try: return self.getProfileInfo(profile_id).get('dependencies', ()) except KeyError: return () security.declareProtected(ManagePortal, 'listProfilesWithUpgrades') def listProfilesWithUpgrades(self): return listProfilesWithUpgrades() security.declarePrivate('_massageUpgradeInfo') def _massageUpgradeInfo(self, info): """Add a couple of data points to the upgrade info dictionary. """ info = info.copy() info['haspath'] = info['source'] and info['dest'] info['ssource'] = '.'.join(info['source'] or ('all', )) info['sdest'] = '.'.join(info['dest'] or ('all', )) return info security.declareProtected(ManagePortal, 'listUpgrades') def listUpgrades(self, profile_id, show_old=False): """Get the list of available upgrades. """ if show_old: source = None else: source = self.getLastVersionForProfile(profile_id) upgrades = listUpgradeSteps(self, profile_id, source) res = [] for info in upgrades: if type(info) == list: subset = [] for subinfo in info: subset.append(self._massageUpgradeInfo(subinfo)) res.append(subset) else: res.append(self._massageUpgradeInfo(info)) return res security.declareProtected(ManagePortal, 'manage_doUpgrades') def manage_doUpgrades(self, request=None): """Perform all selected upgrade steps. """ if request is None: request = self.REQUEST logger = logging.getLogger('GenericSetup') steps_to_run = request.form.get('upgrades', []) profile_id = request.get('profile_id', '') for step_id in steps_to_run: step = _upgrade_registry.getUpgradeStep(profile_id, step_id) if step is not None: step.doStep(self) msg = "Ran upgrade step %s for profile %s" % (step.title, profile_id) logger.log(logging.INFO, msg) # XXX should be a bit smarter about deciding when to up the # profile version profile_info = _profile_registry.getProfileInfo(profile_id) version = profile_info.get('version', None) if version is not None: self.setLastVersionForProfile(profile_id, version) url = self.absolute_url() request.RESPONSE.redirect("%s/manage_upgrades?saved=%s" % (url, profile_id)) # # Helper methods # security.declarePrivate('_getImportContext') def _getImportContext(self, context_id, should_purge=None, archive=None): """ Crack ID and generate appropriate import context. """ encoding = self.getEncoding() if context_id is not None: if context_id.startswith('profile-'): context_id = context_id[len('profile-'):] info = _profile_registry.getProfileInfo(context_id) if info.get('product'): path = os.path.join(_getProductPath(info['product']), info['path']) else: path = info['path'] if should_purge is None: should_purge = (info.get('type') != EXTENSION) return DirectoryImportContext(self, path, should_purge, encoding) elif context_id.startswith('snapshot-'): context_id = context_id[len('snapshot-'):] if should_purge is None: should_purge = True return SnapshotImportContext(self, context_id, should_purge, encoding) if archive is not None: return TarballImportContext( tool=self, archive_bits=archive, encoding='UTF8', should_purge=should_purge, ) raise KeyError, 'Unknown context "%s"' % context_id security.declarePrivate('_updateImportStepsRegistry') def _updateImportStepsRegistry(self, context, encoding): """ Update our import steps registry from our profile. """ if context is None: context = self._getImportContext(self._import_context_id) xml = context.readDataFile(IMPORT_STEPS_XML) if xml is None: return info_list = self._import_registry.parseXML(xml, encoding) for step_info in info_list: id = step_info['id'] version = step_info['version'] handler = step_info['handler'] dependencies = tuple(step_info.get('dependencies', ())) title = step_info.get('title', id) description = ''.join(step_info.get('description', [])) self._import_registry.registerStep( id=id, version=version, handler=handler, dependencies=dependencies, title=title, description=description, ) security.declarePrivate('_updateExportStepsRegistry') def _updateExportStepsRegistry(self, context, encoding): """ Update our export steps registry from our profile. """ if context is None: context = self._getImportContext(self._import_context_id) xml = context.readDataFile(EXPORT_STEPS_XML) if xml is None: return info_list = self._export_registry.parseXML(xml, encoding) for step_info in info_list: id = step_info['id'] handler = step_info['handler'] title = step_info.get('title', id) description = ''.join(step_info.get('description', [])) self._export_registry.registerStep( id=id, handler=handler, title=title, description=description, ) security.declarePrivate('_doRunImportStep') def _doRunImportStep(self, step_id, context): """ Run a single import step, using a pre-built context. """ __traceback_info__ = step_id marker = object() handler = self.getImportStep(step_id) if handler is marker: raise ValueError('Invalid import step: %s' % step_id) if handler is None: msg = 'Step %s has an invalid import handler' % step_id logger = logging.getLogger('GenericSetup') logger.error(msg) return 'ERROR: ' + msg return handler(context) security.declarePrivate('_doRunExportSteps') def _doRunExportSteps(self, steps): """ See ISetupTool. """ context = TarballExportContext(self) messages = {} marker = object() for step_id in steps: handler = self.getExportStep(step_id, marker) if handler is marker: raise ValueError('Invalid export step: %s' % step_id) if handler is None: msg = 'Step %s has an invalid import handler' % step_id logger = logging.getLogger('GenericSetup') logger.error(msg) messages[step_id] = msg else: messages[step_id] = handler(context) return { 'steps': steps, 'messages': messages, 'tarball': context.getArchive(), 'filename': context.getArchiveFilename() } security.declareProtected(ManagePortal, 'getProfileDependencyChain') def getProfileDependencyChain(self, profile_id, seen=None): if seen is None: seen = set() elif profile_id in seen: return [] # cycle break seen.add(profile_id) chain = [] dependencies = self.getDependenciesForProfile(profile_id) for dependency in dependencies: chain.extend(self.getProfileDependencyChain(dependency, seen)) chain.append(profile_id) return chain security.declarePrivate('_runImportStepsFromContext') def _runImportStepsFromContext(self, steps=None, purge_old=None, profile_id=None, archive=None, ignore_dependencies=False, seen=None): if profile_id is not None and not ignore_dependencies: try: chain = self.getProfileDependencyChain(profile_id) except KeyError, e: logger = logging.getLogger('GenericSetup') logger.error('Unknown step in dependency chain: %s' % str(e)) raise else:
cropbox = (0, 0, 50, 50) img = img.crop(cropbox) img.save(imagefilepath, fmt) thumbimage = open(imagefilepath, 'rb') ext = p.getId().split('.')[-1] id = 'tumnagel.%s' % ext self.uploadThumbnail(file=thumbimage.read(), id=id) templates = (#'dtml/something', 'zpt/editBustForm', ) addTemplates2Class(Bust, templates) security = ClassSecurityInfo() security.declareProtected(VMS, 'editBustForm') security.apply(Bust) InitializeClass(Bust) #----------------------------------------------------------------------------- manage_addBustFolderForm = PTF('zpt/addBustFolderForm', globals()) def manage_addBustFolder(dispatcher, id, title, REQUEST=None, redirect_to=None): """ create instance """ dest = dispatcher.Destination()
security.declareProtected(VMS, 'manage_UpdatePlogRank') def manage_UpdatePlogRank(self): """ use PlogMatrix to calculate every plogrank """ return UpdatePlogRank(self) zpts = (('zpt/blogcontainer_index', 'index_html'),) addTemplates2Class(PeterbeBlogContainer, zpts, extension='zpt') dtmls = (('dtml/blogcontainer_stats','manage_Statistics'), 'dtml/blogcontainer_calendar', ) addTemplates2Class(PeterbeBlogContainer, dtmls, extension='dtml') setattr(PeterbeBlogContainer, 'rss.xml', PeterbeBlogContainer.RSS10) security = ClassSecurityInfo() security.declareProtected(VMS, 'manage_Statistics') security.apply(PeterbeBlogContainer) InitializeClass(PeterbeBlogContainer)
class BadFile(FSObject): """ Represent a file which was not readable or parseable as its intended type. """ meta_type = 'Bad File' icon = 'p_/broken' BAD_FILE_VIEW = """\ <dtml-var manage_page_header> <dtml-var manage_tabs> <h2> Bad Filesystem Object: &dtml-getId; </h2> <h3> File Path </h3> <pre> <dtml-var getFilePath> </pre> <h3> File Contents </h3> <pre> <dtml-var getFileContents> </pre> <h3> Exception </h3> <pre> <dtml-var getExceptionText> </pre> <dtml-var manage_page_footer> """ manage_options = ({'label': 'Error', 'action': 'manage_showError'}, ) def __init__(self, id, package=None, entry_subpath=None, filepath=None, fullname=None, properties=None, exc_str=''): id = fullname or id # Use the whole filename. self.exc_str = exc_str self.file_contents = '' FSObject.__init__(self, id, package, entry_subpath, filepath, fullname, properties) security = ClassSecurityInfo() security.declarePrivate('showError') showError = Globals.HTML(BAD_FILE_VIEW) security.declarePrivate('_readFile') def _readFile(self, reparse): """ Stub this out. """ pass security.declareProtected(ManagePortal, 'manage_showError') def manage_showError(self, REQUEST): """ Render the error page. """ return self.showError(self, REQUEST) security.declarePublic('getFilePath') def getFilePath(self): """ Return the path to the file. """ if self._filepath: return self._filepath else: return 'package: %s, subpath: %s' % (self._package, self._entry_subpath) security.declarePublic('getFileContents') def getFileContents(self): """ Return the contents of the file, if we could read it. """ return self.file_contents security.declarePublic('getExceptionText') def getExceptionText(self): """ Return the exception thrown while reading or parsing the file. """ return self.exc_str
class ERP5UserManager(BasePlugin): """ PAS plugin for managing users in ERP5 """ meta_type = 'ERP5 User Manager' security = ClassSecurityInfo() def __init__(self, id, title=None): self._id = self.id = id self.title = title # # IAuthenticationPlugin implementation # security.declarePrivate('authenticateCredentials') def authenticateCredentials(self, credentials): """ See IAuthenticationPlugin. o We expect the credentials to be those returned by ILoginPasswordExtractionPlugin. """ login = credentials.get('login') ignore_password = False if not login: # fallback to support plugins using external tools to extract login # those are not using login/password pair, they just extract login # from remote system (eg. SSL certificates) login = credentials.get('external_login') ignore_password = True # Forbidden the usage of the super user. if login == ERP5Security.SUPER_USER: return None @UnrestrictedMethod def _authenticateCredentials(login, password, path, ignore_password=False): if not login or not (password or ignore_password): return None user_list = self.getUserByLogin(login) if not user_list: raise _AuthenticationFailure() user = user_list[0] try: if (ignore_password or pw_validate(user.getPassword(), password)) and \ len(getValidAssignmentList(user)) and user \ .getValidationState() != 'deleted': #user.getCareerRole() == 'internal': return login, login # use same for user_id and login finally: pass raise _AuthenticationFailure() _authenticateCredentials = CachingMethod( _authenticateCredentials, id='ERP5UserManager_authenticateCredentials', cache_factory='erp5_content_short') try: authentication_result = _authenticateCredentials( login=login, password=credentials.get('password'), path=self.getPhysicalPath(), ignore_password=ignore_password) except _AuthenticationFailure: authentication_result = None if not self.getPortalObject( ).portal_preferences.isAuthenticationPolicyEnabled(): # stop here, no authentication policy enabled # so just return authentication check result return authentication_result # authentication policy enabled, we need person object anyway user_list = self.getUserByLogin(credentials.get('login')) if not user_list: # not an ERP5 Person object return None user = user_list[0] if authentication_result is None: # file a failed authentication attempt user.notifyLoginFailure() return None # check if password is expired if user.isPasswordExpired(): user.notifyPasswordExpire() return None # check if user account is blocked if user.isLoginBlocked(): return None return authentication_result # # IUserEnumerationPlugin implementation # security.declarePrivate('enumerateUsers') def enumerateUsers(self, id=None, login=None, exact_match=False, sort_by=None, max_results=None, **kw): """ See IUserEnumerationPlugin. """ # Note: this plugin totally ignores the distinction between login and id. if id is None: id = login if isinstance(id, str): id = (id, ) unrestrictedSearchResults = self.getPortalObject( ).portal_catalog.unrestrictedSearchResults searchUser = lambda **kw: unrestrictedSearchResults( select_list=('reference', ), portal_type='Person', **kw).dictionaries() # Only search by id if login is not given. Same logic as in # PluggableAuthService.searchUsers. if isinstance(id, str): id = (id, ) id_list = [] has_super_user = False for user_id in id: if user_id == ERP5Security.SUPER_USER: has_super_user = True elif user_id: id_list.append(user_id) if id_list: if exact_match: requested = set(id_list).__contains__ else: requested = lambda x: True user_list = [ x for x in searchUser( reference={ 'query': id_list, 'key': 'ExactMatch' if exact_match else 'Keyword', }, limit=max_results, ) if requested(x['reference']) ] else: user_list = [] if has_super_user: user_list.append({ 'uid': None, 'path': None, 'reference': ERP5Security.SUPER_USER }) plugin_id = self.getId() return tuple([ { 'id': user['reference'], # Note: PAS forbids us from returning more than one entry per given id, # so take any available login. 'login': user['reference'], 'pluginid': plugin_id, # Extra properties, specific to ERP5 'path': user['path'], 'uid': user['uid'], 'login_list': user['path'] and [{ 'reference': user['reference'], 'path': user['path'], 'uid': user['uid'], }] or [], } for user in user_list ]) security.declarePrivate('updateUser') def updateUser(self, user_id, login_name): # Operation not supported here return False security.declarePrivate('updateEveryLoginName') def updateEveryLoginName(self, quit_on_first_error=True): # Operation not supported here raise NotImplementedError() def getUserByLogin(self, login, exact_match=True): # Search the Catalog for login and return a list of person objects # login can be a string or a list of strings # (no docstring to prevent publishing) if not login: return [] if isinstance(login, list): login = tuple(login) elif not isinstance(login, (tuple, str)): login = login.getUserName() try: return getUserByLogin(self.getPortalObject(), login, exact_match) except ConflictError: raise except: LOG('ERP5Security', PROBLEM, 'getUserByLogin failed', error=True) # Here we must raise an exception to prevent callers from caching # a result of a degraded situation. # The kind of exception does not matter as long as it's catched by # PAS and causes a lookup using another plugin or user folder. # As PAS does not define explicitely such exception, we must use # the _SWALLOWABLE_PLUGIN_EXCEPTIONS list. raise _SWALLOWABLE_PLUGIN_EXCEPTIONS[0]
from AccessControl import ClassSecurityInfo from Products.CMFCore.permissions import View from collective.downloadtracker import add_download_record security = ClassSecurityInfo() security.declareProtected(View, 'index_html') def index_html(self, instance, REQUEST=None, RESPONSE=None, **kwargs): """ make it directly viewable when entering the objects URL """ blob = self.get(instance, raw=True) # TODO: why 'raw'? charset = instance.getCharset() add_download_record(instance) return blob.index_html( REQUEST=REQUEST, RESPONSE=RESPONSE, charset=charset, **kwargs )
class FSObject(Implicit, Item, RoleManager, Cacheable): """FSObject is a base class for all filesystem based look-alikes. Subclasses of this class mimic ZODB based objects like Image and DTMLMethod, but are not directly modifiable from the management interface. They provide means to create a TTW editable copy, however. """ # Always empty for FS based, non-editable objects. title = '' security = ClassSecurityInfo() security.declareObjectProtected(View) _filepath = None _package = None _entry_subpath = None _file_mod_time = 0 _file_size = 0 _parsed = 0 def __init__(self, id, package=None, entry_subpath=None, filepath=None, fullname=None, properties=None): MESSAGE = ("Either 'filepath' or 'package' + 'entry_subpath' must " "be supplied.") if filepath is None: if package is None or entry_subpath is None: raise ValueError(MESSAGE) self._package = package self._entry_subpath = entry_subpath else: if package is not None or entry_subpath is not None: raise ValueError(MESSAGE) self._filepath = filepath if properties: # Since props come from the filesystem, this should be # safe. self.__dict__.update(properties) if fullname and properties.get('keep_extension', 0): id = fullname cache = properties.get('cache') if cache: self.ZCacheable_setManagerId(cache) self.id = id self.__name__ = id # __name__ is used in traceback reporting self._updateFromFS(reparse=1) security.declareProtected(ViewManagementScreens, 'manage_doCustomize') def manage_doCustomize(self, folder_path, RESPONSE=None): """Makes a ZODB Based clone with the same data. Calls _createZODBClone for the actual work. """ obj = self._createZODBClone() parent = aq_parent(aq_inner(self)) # Preserve cache manager associations cachemgr_id = self.ZCacheable_getManagerId() if (cachemgr_id and getattr(obj, 'ZCacheable_setManagerId', None) is not None): obj.ZCacheable_setManagerId(cachemgr_id) # If there are proxy roles we preserve them proxy_roles = getattr(aq_base(self), '_proxy_roles', None) if proxy_roles is not None and isinstance(proxy_roles, tuple): obj._proxy_roles = tuple(self._proxy_roles) # Also, preserve any permission settings that might have come # from a metadata file or from fiddling in the ZMI old_info = [x[:2] for x in self.ac_inherited_permissions(1)] for old_perm, value in old_info: p = Permission(old_perm, value, self) acquired = int(isinstance(p.getRoles(default=[]), list)) rop_info = self.rolesOfPermission(old_perm) roles = [x['name'] for x in rop_info if x['selected'] != ''] try: # if obj is based on OFS.ObjectManager an acquisition context is # required for _subobject_permissions() obj.__of__(parent).manage_permission(old_perm, roles=roles, acquire=acquired) except ValueError: # The permission was invalid, never mind pass skins_tool_namegetter = getattr(self, 'getSkinsFolderName', None) if skins_tool_namegetter is not None: skins_tool_name = skins_tool_namegetter() else: skins_tool_name = 'portal_skins' id = obj.getId() fpath = tuple(folder_path.split('/')) portal_skins = getToolByName(self, skins_tool_name) folder = portal_skins.restrictedTraverse(fpath) if id in folder.objectIds(): # we cant catch the badrequest so # we'll that to check before hand obj = folder._getOb(id) if RESPONSE is not None: RESPONSE.redirect( '%s/manage_main?manage_tabs_message=%s' % (obj.absolute_url(), html_quote("An object with this id already exists"))) else: folder._verifyObjectPaste(obj, validate_src=0) folder._setObject(id, obj) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_main' % (folder.absolute_url(), id)) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_main' % (folder.absolute_url(), id)) def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" raise NotImplementedError, "This should be implemented in a subclass." def _readFile(self, reparse): """Read the data from the filesystem. Read the file indicated by exandpath(self._filepath), and parse the data if necessary. 'reparse' is set when reading the second time and beyond. """ raise NotImplementedError, "This should be implemented in a subclass." # Refresh our contents from the filesystem if that is newer and we are # running in debug mode. def _updateFromFS(self, reparse=1): parsed = self._parsed if parsed and not Globals.DevelopmentMode: return if self._filepath: fp = expandpath(self._filepath) try: statinfo = os.stat(fp) size, mtime = statinfo[6], statinfo[8] except: size = mtime = 0 else: size, mtime = _getResourceStatInfo(self._package, self._entry_subpath) if not parsed or mtime != self._file_mod_time: # if we have to read the file again, remove the cache self.ZCacheable_invalidate() data = self._readFile(reparse) self._file_mod_time = mtime self._file_size = size self._parsed = 1 security.declareProtected(View, 'get_size') def get_size(self): """Get the size of the underlying file. """ self._updateFromFS() return self._file_size security.declareProtected(View, 'getModTime') def getModTime(self): """Return the last_modified date of the file we represent. Returns a DateTime instance. """ self._updateFromFS() return DateTime(self._file_mod_time) security.declareProtected(ViewManagementScreens, 'getObjectFSPath') def getObjectFSPath(self): """Return the path of the file we represent""" self._updateFromFS() if self._filepath is not None: return self._filepath return '<zipimport: %s, %s>' % self._package, self._entry_subpath security.declarePrivate('_readFileAsResourceOrDirect') def _readFileAsResourceOrDirect(self): """ Return our file's bits, looking in the appropriate place. """ if self._filepath is None: return resource_string(self._package, self._entry_subpath) else: fp = expandpath(self._filepath) file = open(fp, 'r') # not 'rb', as this is a text file! try: return file.read() finally: file.close()
from zope import schema from zope.annotation.interfaces import IAnnotations from zope.component import queryUtility from zope.container.contained import ObjectRemovedEvent from zope import event from zope.interface import implements from .. import _, config from ..accesscontrol import AccessControl from ..exceptions import PlominoCacheException, PlominoScriptException from ..interfaces import IPlominoContext from ..design import DesignManager from ..replication import ReplicationManager from ..document import addPlominoDocument security = ClassSecurityInfo() class IPlominoDatabase(model.Schema): """ Plomino database schema """ indexAttachments = schema.Bool( title=_('CMFPlomino_label_IndexAttachments', default="Index file attachments"), description=_('CMFPlomino_help_IndexAttachments', default="If enabled, files attached in File Attachment fields " "will be indexed. It might increase the index size."), default=False, )
class ElementSpec(SimpleItem): """ Represent all the tool knows about a single metadata element. """ security = ClassSecurityInfo() # # Default values. # is_multi_valued = 0 def __init__(self, is_multi_valued): self.is_multi_valued = is_multi_valued self.policies = PersistentMapping() self.policies[None] = self._makePolicy() # set default policy security.declarePrivate('_makePolicy') def _makePolicy(self): return MetadataElementPolicy(self.is_multi_valued) security.declareProtected(View, 'isMultiValued') def isMultiValued(self): """ Is this element multi-valued? """ return self.is_multi_valued security.declareProtected(View, 'getPolicy') def getPolicy(self, typ=None): """ Find the policy this element for objects whose type object name is 'typ'; return a default, if none found. """ try: return self.policies[typ].__of__(self) except KeyError: return self.policies[None].__of__(self) security.declareProtected(View, 'listPolicies') def listPolicies(self): """ Return a list of all policies for this element. """ res = [] for k, v in self.policies.items(): res.append((k, v.__of__(self))) return res security.declareProtected(ManagePortal, 'addPolicy') def addPolicy(self, typ): """ Add a policy to this element for objects whose type object name is 'typ'. """ if typ is None: raise MetadataError, "Can't replace default policy." if self.policies.has_key(typ): raise MetadataError, "Existing policy for content type:" + typ self.policies[typ] = self._makePolicy() security.declareProtected(ManagePortal, 'removePolicy') def removePolicy(self, typ): """ Remove the policy from this element for objects whose type object name is 'typ' (*not* the default, however). """ if typ is None: raise MetadataError, "Can't remove default policy." del self.policies[typ]
try: from IOBTree import Bucket except: Bucket=lambda:{} from Shared.DC.ZRDB.Aqueduct import decodestring, parse from Shared.DC.ZRDB.DA import DA, DatabaseError, SQLMethodTracebackSupplement from Shared.DC.ZRDB import RDB from Shared.DC.ZRDB.Results import Results from App.Extensions import getBrain from AccessControl import ClassSecurityInfo, getSecurityManager from Products.ERP5Type.Globals import InitializeClass from Acquisition import aq_base, aq_parent from zLOG import LOG, INFO, ERROR from cStringIO import StringIO from Products.ERP5Type import Permissions import sys security = ClassSecurityInfo() DA.security = security def DA_fromFile(self, filename): """ Read the file and update self """ f = file(filename) s = f.read() f.close() self.fromText(s) def DA_fromText(self, text): """ Read the string 'text' and updates self """
class MetadataTool(UniqueObject, SimpleItem, ActionProviderBase): implements(IMetadataTool) __implements__ = (z2IMetadataTool, ActionProviderBase.__implements__) id = 'portal_metadata' meta_type = 'Default Metadata Tool' # # Default values. # publisher = '' element_specs = None #initial_values_hook = None #validation_hook = None security = ClassSecurityInfo() def __init__( self, publisher=None #, initial_values_hook=None #, validation_hook=None , element_specs=DEFAULT_ELEMENT_SPECS): self.editProperties(publisher #, initial_values_hook #, validation_hook ) self.element_specs = PersistentMapping() for name, is_multi_valued in element_specs: self.element_specs[name] = ElementSpec(is_multi_valued) # # ZMI methods # manage_options = ( ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, { 'label': 'Properties', 'action': 'propertiesForm' }, { 'label': 'Elements', 'action': 'elementPoliciesForm' } # TODO , { 'label' : 'Types' # , 'action' : 'typesForm' # } ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainMetadataTool', _dtmldir) security.declareProtected(ManagePortal, 'propertiesForm') propertiesForm = DTMLFile('metadataProperties', _dtmldir) security.declareProtected(ManagePortal, 'editProperties') def editProperties( self, publisher=None # TODO , initial_values_hook=None # TODO , validation_hook=None , REQUEST=None): """ Form handler for "tool-wide" properties (including list of metadata elements). """ if publisher is not None: self.publisher = publisher # TODO self.initial_values_hook = initial_values_hook # TODO self.validation_hook = validation_hook if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Tool+updated.') security.declareProtected(ManagePortal, 'elementPoliciesForm') elementPoliciesForm = DTMLFile('metadataElementPolicies', _dtmldir) security.declareProtected(ManagePortal, 'addElementPolicy') def addElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Add a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.addPolicy(content_type) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+added.') security.declareProtected(ManagePortal, 'removeElementPolicy') def removeElementPolicy(self, element, content_type, REQUEST=None): """ Remvoe a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.removePolicy(content_type) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+removed.') security.declareProtected(ManagePortal, 'updateElementPolicy') def updateElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Update a policy for one of our elements ('content_type' will be '<default>' when we edit the default). """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+updated.') # # Element spec manipulation. # security.declareProtected(ManagePortal, 'listElementSpecs') def listElementSpecs(self): """ Return a list of ElementSpecs representing the elements managed by the tool. """ res = [] for k, v in self.element_specs.items(): res.append((k, v.__of__(self))) return res security.declareProtected(ManagePortal, 'getElementSpec') def getElementSpec(self, element): """ Return an ElementSpec representing the tool's knowledge of 'element'. """ return self.element_specs[element].__of__(self) security.declareProtected(ManagePortal, 'addElementSpec') def addElementSpec(self, element, is_multi_valued, REQUEST=None): """ Add 'element' to our list of managed elements. """ # Don't replace. if self.element_specs.has_key(element): return self.element_specs[element] = ElementSpec(is_multi_valued) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+added.') security.declareProtected(ManagePortal, 'removeElementSpec') def removeElementSpec(self, element, REQUEST=None): """ Remove 'element' from our list of managed elements. """ del self.element_specs[element] if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+removed.') security.declareProtected(ManagePortal, 'listPolicies') def listPolicies(self, typ=None): """ Show all policies for a given content type, or the default if None. """ result = [] for element, spec in self.listElementSpecs(): result.append((element, spec.getPolicy(typ))) return result # # 'portal_metadata' interface # security.declarePrivate('getFullName') def getFullName(self, userid): """ Convert an internal userid to a "formal" name, if possible, perhaps using the 'portal_membership' tool. Used to map userid's for Creator, Contributor DCMI queries. """ return userid # TODO: do lookup here security.declarePublic('getPublisher') def getPublisher(self): """ Return the "formal" name of the publisher of the portal. """ return self.publisher security.declarePublic('listAllowedVocabulary') def listAllowedVocabulary(self, element, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ spec = self.getElementSpec(element) if content_type is None and content: content_type = content.getPortalTypeName() return spec.getPolicy(content_type).allowedVocabulary() security.declarePublic('listAllowedSubjects') def listAllowedSubjects(self, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ return self.listAllowedVocabulary('Subject', content, content_type) security.declarePublic('listAllowedFormats') def listAllowedFormats(self, content=None, content_type=None): """ List the allowed 'Content-type' values for a particular portal_type, or all possible formats if none supplied. """ return self.listAllowedVocabulary('Format', content, content_type) security.declarePublic('listAllowedLanguages') def listAllowedLanguages(self, content=None, content_type=None): """ List the allowed language values. """ return self.listAllowedVocabulary('Language', content, content_type) security.declarePublic('listAllowedRights') def listAllowedRights(self, content=None, content_type=None): """ List the allowed values for a "Rights" selection list; this gets especially important where syndication is involved. """ return self.listAllowedVocabulary('Rights', content, content_type) security.declareProtected(ModifyPortalContent, 'setInitialMetadata') def setInitialMetadata(self, content): """ Set initial values for content metatdata, supplying any site-specific defaults. """ for element, policy in self.listPolicies(content.getPortalTypeName()): if not getattr(content, element)(): if policy.supplyDefault(): setter = getattr(content, 'set%s' % element) setter(policy.defaultValue()) elif policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element # TODO: Call initial_values_hook, if present security.declareProtected(View, 'validateMetadata') def validateMetadata(self, content): """ Enforce portal-wide policies about DCI, e.g., requiring non-empty title/description, etc. Called by the CMF immediately before saving changes to the metadata of an object. """ for element, policy in self.listPolicies(content.getPortalTypeName()): value = getattr(content, element)() if not value and policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element if value and policy.enforceVocabulary(): values = policy.isMultiValued() and value or [value] for value in values: if not value in policy.allowedVocabulary(): raise MetadataError, \ 'Value %s is not in allowed vocabulary for ' \ 'metadata element %s.' % ( value, element )
Or, Generic, Indexed, _CompositeQuery, LiteralResultSet, ) from eval import eval as _eval from ranking import RankByQueries_Sum, RankByQueries_Max ############################################################################ ## Security _allow_module("Products.AdvancedQuery") _s = ClassSecurityInfo() _s.declarePublic("addSubquery") _CompositeQuery._s = _s InitializeClass(_CompositeQuery) ############################################################################ ## ZCatalog extension def _makeAdvancedQuery(self, catalogSearchSpec): """advanced query corresponding to *catalogSearchSpec* (a dictionary).""" q = And() get = catalogSearchSpec.get for i in self.Indexes.objectIds(): vi = get(i) if vi is None or vi == "": continue
class MetadataElementPolicy(SimpleItem): """ Represent a type-specific policy about a particular DCMI element. """ security = ClassSecurityInfo() # # Default values. # is_required = 0 supply_default = 0 default_value = '' enforce_vocabulary = 0 allowed_vocabulary = () def __init__(self, is_multi_valued=False): self.is_multi_valued = bool(is_multi_valued) # # Mutator. # security.declareProtected(ManagePortal, 'edit') def edit(self, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary): self.is_required = bool(is_required) self.supply_default = bool(supply_default) self.default_value = default_value self.enforce_vocabulary = bool(enforce_vocabulary) self.allowed_vocabulary = tuple(allowed_vocabulary) # # Query interface # security.declareProtected(View, 'isMultiValued') def isMultiValued(self): """ Can this element hold multiple values? """ return self.is_multi_valued security.declareProtected(View, 'isRequired') def isRequired(self): """ Must this element be supplied? """ return self.is_required security.declareProtected(View, 'supplyDefault') def supplyDefault(self): """ Should the tool supply a default? """ return self.supply_default security.declareProtected(View, 'defaultValue') def defaultValue(self): """ If so, what is the default? """ return self.default_value security.declareProtected(View, 'enforceVocabulary') def enforceVocabulary(self): """ """ return self.enforce_vocabulary security.declareProtected(View, 'allowedVocabulary') def allowedVocabulary(self): """ """ return self.allowed_vocabulary
""" Patches for Products.CMFCore """ from AccessControl import ClassSecurityInfo from eea.workflow.events import InitialStateCreatedEvent from zope.event import notify security = ClassSecurityInfo() security.declarePrivate('notifyCreated') def notifyCreated(self, ob): """ Notify all applicable workflows that an object has been created and put in its new place. The patch adds a single line that uses zope.event to notify of the IInitialStateCreatedEvent event """ self._old_notifyCreated(ob) notify(InitialStateCreatedEvent(ob))
class UniqueIdHandlerTool(UniqueObject, SimpleItem): __doc__ = __doc__ # copy from module implements(IUniqueIdHandler, IUniqueIdBrainQuery, IUniqueIdUnrestrictedQuery) __implements__ = (SimpleItem.__implements__, ) id = 'portal_uidhandler' manage_options = (({ 'label': 'Query', 'action': 'manage_queryObject' }, ) + SimpleItem.manage_options) alternative_id = "portal_standard_uidhandler" meta_type = 'Unique Id Handler Tool' # make the uid attribute name available for the unit tests # not meant to be altered as long you don't know what you do!!! UID_ATTRIBUTE_NAME = UID_ATTRIBUTE_NAME # make the exception class available through the tool UniqueIdError = UniqueIdError security = ClassSecurityInfo() def _reindexObject(self, obj): # XXX: this method violates the rules for tools/utilities: # it depends on a non-utility tool # add uid index and colums to catalog if not yet done UID_ATTRIBUTE_NAME = self.UID_ATTRIBUTE_NAME catalog = getToolByName(obj, 'portal_catalog') if UID_ATTRIBUTE_NAME not in catalog.indexes(): catalog.addIndex(UID_ATTRIBUTE_NAME, 'FieldIndex') catalog.addColumn(UID_ATTRIBUTE_NAME) # reindex catalog.reindexObject(obj, idxs=[UID_ATTRIBUTE_NAME]) def _setUid(self, obj, uid): """Attaches a unique id to the object and does reindexing. """ # attach a unique id annotation to the object anno_tool = getUtility(IUniqueIdAnnotationManagement) annotation = anno_tool(obj, self.UID_ATTRIBUTE_NAME) annotation.setUid(uid) # reindex the object self._reindexObject(obj) security.declarePublic('register') def register(self, obj): """See IUniqueIdSet. """ uid = self.queryUid(obj, default=None) if uid is None: # generate a new unique id and set it generator = getUtility(IUniqueIdGenerator) uid = generator() self._setUid(obj, uid) return uid security.declareProtected(ManagePortal, 'unregister') def unregister(self, obj): """See IUniqueIdSet. """ UID_ATTRIBUTE_NAME = self.UID_ATTRIBUTE_NAME if getattr(aq_base(obj), UID_ATTRIBUTE_NAME, None) is None: raise UniqueIdError, \ "No unique id available to be unregistered on '%s'" % obj # delete the uid and reindex delattr(obj, UID_ATTRIBUTE_NAME) self._reindexObject(obj) security.declarePublic('queryUid') def queryUid(self, obj, default=None): """See IUniqueIdQuery. """ uid = getattr(aq_base(obj), self.UID_ATTRIBUTE_NAME, None) # If 'obj' is a content object the 'uid' attribute is usually a # callable object. If 'obj' is a catalog brain the uid attribute # is non callable and possibly equals the 'Missing.MV' value. if uid is Missing.MV or uid is None: return default if callable(uid): return uid() return uid security.declarePublic('getUid') def getUid(self, obj): """See IUniqueIdQuery. """ uid = self.queryUid(obj, None) if uid is None: raise UniqueIdError, "No unique id available on '%s'" % obj return uid security.declarePrivate('setUid') def setUid(self, obj, uid, check_uniqueness=True): """See IUniqueIdSet. """ # None is the only value a unique id shall never have! if uid is None: raise UniqueIdError, "It's forbidden to set a unique id to 'None'." # check for uniqueness if enabled if check_uniqueness: result = self.queryObject(uid) if result is not None and result != obj: if callable(uid): uid = uid() raise UniqueIdError, \ "The unique id '%s' is already in use" % uid # everything is ok: set it! self._setUid(obj, uid) def _queryBrain(self, uid, searchMethodName, default=None): """This helper method does the "hard work" of querying the catalog and interpreting the results. """ # XXX: this method violates the rules for tools/utilities: # it depends on a non-utility tool if uid is None: return default # convert the uid to the right format generator = getUtility(IUniqueIdGenerator) uid = generator.convert(uid) catalog = getToolByName(self, 'portal_catalog') searchMethod = getattr(catalog, searchMethodName) result = searchMethod({self.UID_ATTRIBUTE_NAME: uid}) len_result = len(result) # return None if no object found with this uid if len_result == 0: return default # print a message to the log if more than one object has # the same uid (uups!) if len_result > 1: logging.getLogger('CMFUid').error( "ASSERT: %d objects have %r as uid!!!", len_result, uid) return result[0] security.declarePublic('queryBrain') def queryBrain(self, uid, default=None): """See IUniqueIdBrainQuery. """ return self._queryBrain(uid, 'searchResults', default) def _getBrain(self, uid, queryBrainMethod): brain = queryBrainMethod(uid, default=None) if brain is None: raise UniqueIdError, "No object found with '%s' as uid." % uid return brain security.declarePublic('getBrain') def getBrain(self, uid): """See IUniqueIdBrainQuery. """ return self._getBrain(uid, self.queryBrain) security.declarePublic('getObject') def getObject(self, uid): """See IUniqueIdQuery. """ return self.getBrain(uid).getObject() security.declarePublic('queryObject') def queryObject(self, uid, default=None): """See IUniqueIdQuery. """ try: return self.getObject(uid) except UniqueIdError: return default security.declarePrivate('unrestrictedQueryBrain') def unrestrictedQueryBrain(self, uid, default=None): """See IUniqueIdUnrestrictedQuery. """ return self._queryBrain(uid, 'unrestrictedSearchResults', default) security.declarePrivate('unrestrictedGetBrain') def unrestrictedGetBrain(self, uid): """See IUniqueIdUnrestrictedQuery. """ return self._getBrain(uid, self.unrestrictedQueryBrain) security.declarePrivate('unrestrictedGetObject') def unrestrictedGetObject(self, uid): """See IUniqueIdUnrestrictedQuery. """ return self.unrestrictedGetBrain(uid).getObject() security.declarePrivate('unrestrictedQueryObject') def unrestrictedQueryObject(self, uid, default=None): """See IUniqueIdUnrestrictedQuery. """ try: return self.unrestrictedGetObject(uid) except UniqueIdError: return default security.declareProtected(ManagePortal, 'manage_queryObject') manage_queryObject = PageTemplateFile('queryUID.pt', _wwwdir)
## BetterSiteErrorLog ## An attempt to make the Zope error_log a bit more useful. ## License: ZPL ## By: Peter Bengtsson, Fry-IT, [email protected] ## import logging import os from Globals import package_home from AccessControl import ClassSecurityInfo from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.SiteErrorLog.SiteErrorLog import SiteErrorLog logger = logging.getLogger('BetterSiteErrorLog') security = ClassSecurityInfo() # Set __version__ to SiteErrorLog __version__=open(os.path.join(package_home(globals()), 'version.txt')).read().strip() setattr(SiteErrorLog, 'BetterSiteErrorLog_version', __version__) # Patch manage_main _www = os.path.join(os.path.dirname(__file__), 'www') setattr(SiteErrorLog, 'manage_main', PageTemplateFile('main.pt', _www)) #logger.info("Patched SiteErrorLog's manage_main") # Add an RSS version _www = os.path.join(os.path.dirname(__file__), 'www') setattr(SiteErrorLog, 'manage_rss_errorlog', PageTemplateFile('rss.pt', _www))
class CachingPolicyManager(SimpleItem): """ Manage the set of CachingPolicy objects for the site; dispatch to them from skin methods. """ __implements__ = ICachingPolicyManager id = 'caching_policy_manager' meta_type = 'CMF Caching Policy Manager' security = ClassSecurityInfo() def __init__(self): self._policy_ids = () self._policies = PersistentMapping() # # ZMI # manage_options = (({ 'label': 'Policies', 'action': 'manage_cachingPolicies', 'help': ('CMFCore', 'CPMPolicies.stx') }, ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'manage_cachingPolicies') manage_cachingPolicies = DTMLFile('cachingPolicies', _dtmldir) security.declarePublic('listPolicies') def listPolicies(self): """ Return a sequence of tuples, '( policy_id, ( policy, typeObjectName ) )' for all policies in the registry """ result = [] for policy_id in self._policy_ids: result.append((policy_id, self._policies[policy_id])) return tuple(result) security.declareProtected(ManagePortal, 'addPolicy') def addPolicy( self, policy_id, predicate # TALES expr (def. 'python:1') , mtime_func # TALES expr (def. 'object/modified') , max_age_secs # integer, seconds (def. 0) , no_cache # boolean (def. 0) , no_store # boolean (def. 0) , must_revalidate # boolean (def. 0) , vary # string value , etag_func # TALES expr (def. '') , REQUEST=None): """ Add a caching policy. """ self._addPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=' + 'Policy+added.') security.declareProtected(ManagePortal, 'updatePolicy') def updatePolicy( self, policy_id, predicate # TALES expr (def. 'python:1') , mtime_func # TALES expr (def. 'object/modified') , max_age_secs # integer, seconds , no_cache # boolean (def. 0) , no_store # boolean (def. 0) , must_revalidate # boolean (def. 0) , vary # string value , etag_func # TALES expr (def. '') , REQUEST=None): """ Update a caching policy. """ self._updatePolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=' + 'Policy+updated.') security.declareProtected(ManagePortal, 'movePolicyUp') def movePolicyUp(self, policy_id, REQUEST=None): """ Move a caching policy up in the list. """ policy_ids = list(self._policy_ids) ndx = policy_ids.index(policy_id) if ndx == 0: msg = "Policy+already+first." else: self._reorderPolicy(policy_id, ndx - 1) msg = "Policy+moved." if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'movePolicyDown') def movePolicyDown(self, policy_id, REQUEST=None): """ Move a caching policy down in the list. """ policy_ids = list(self._policy_ids) ndx = policy_ids.index(policy_id) if ndx == len(policy_ids) - 1: msg = "Policy+already+last." else: self._reorderPolicy(policy_id, ndx + 1) msg = "Policy+moved." if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'removePolicy') def removePolicy(self, policy_id, REQUEST=None): """ Remove a caching policy. """ self._removePolicy(policy_id) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=Policy+removed.') # # Policy manipulation methods. # security.declarePrivate('_addPolicy') def _addPolicy(self, policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func): """ Add a policy to our registry. """ policy_id = str(policy_id).strip() if not policy_id: raise ValueError, "Policy ID is required!" if policy_id in self._policy_ids: raise KeyError, "Policy %s already exists!" % policy_id self._policies[policy_id] = CachingPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) idlist = list(self._policy_ids) idlist.append(policy_id) self._policy_ids = tuple(idlist) security.declarePrivate('_updatePolicy') def _updatePolicy(self, policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func): """ Update a policy in our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id self._policies[policy_id] = CachingPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) security.declarePrivate('_reorderPolicy') def _reorderPolicy(self, policy_id, newIndex): """ Reorder a policy in our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id idlist = list(self._policy_ids) ndx = idlist.index(policy_id) pred = idlist[ndx] idlist = idlist[:ndx] + idlist[ndx + 1:] idlist.insert(newIndex, pred) self._policy_ids = tuple(idlist) security.declarePrivate('_removePolicy') def _removePolicy(self, policy_id): """ Remove a policy from our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id del self._policies[policy_id] idlist = list(self._policy_ids) ndx = idlist.index(policy_id) idlist = idlist[:ndx] + idlist[ndx + 1:] self._policy_ids = tuple(idlist) # # 'portal_caching' interface methods # security.declareProtected(View, 'getHTTPCachingHeaders') def getHTTPCachingHeaders(self, content, view_method, keywords, time=None): """ Return a list of HTTP caching headers based on 'content', 'view_method', and 'keywords'. """ context = createCPContext(content, view_method, keywords, time=time) for policy_id, policy in self.listPolicies(): headers = policy.getHeaders(context) if headers: return headers return ()
p = subprocess.Popen((DCWorkflowGraph.bin_search(DOT_EXE), '-Nfontname=IPAexGothic', '-Nfontsize=10', '-Efontname=IPAexGothic', '-Efontsize=10', '-T%s' % format), stdin=subprocess.PIPE, stdout=subprocess.PIPE) result = p.communicate(pot)[0] setHeader('Content-Type', 'image/%s' % format) else: filename = wf_id or self.getId() setHeader('Content-Type', 'text/x-graphviz') setHeader('Content-Disposition', 'attachment; filename=%s.dot' % filename) if not result: LOG("ERP5Type.patches.DCWorkflowGraph", WARNING, "Empty %s graph file" % format) return result DCWorkflowGraph.getGraph = getGraph from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition DCWorkflowDefinition.getGraph = getGraph DCWorkflowDefinition.getPOT = DCWorkflowGraph.getPOT security = ClassSecurityInfo() security.declareProtected(Permissions.ManagePortal, 'getPOT') security.declareProtected(Permissions.ManagePortal, 'getGraph') DCWorkflowDefinition.security = security InitializeClass(DCWorkflowDefinition)
class RolemapConfigurator(ConfiguratorBase): """ Synthesize XML description of sitewide role-permission settings. """ security = ClassSecurityInfo() security.declareProtected(ManagePortal, 'listRoles') def listRoles(self): """ List the valid role IDs for our site. """ return self._site.valid_roles() security.declareProtected(ManagePortal, 'listPermissions') def listPermissions(self): """ List permissions for export. o Returns a sqeuence of mappings describing locally-modified permission / role settings. Keys include: 'permission' -- the name of the permission 'acquire' -- a flag indicating whether to acquire roles from the site's container 'roles' -- the list of roles which have the permission. o Do not include permissions which both acquire and which define no local changes to the acquired policy. """ permissions = [] valid_roles = self.listRoles() for perm in self._site.ac_inherited_permissions(1): name = perm[0] p = Permission(name, perm[1], self._site) roles = p.getRoles(default=[]) acquire = isinstance(roles, list) # tuple means don't acquire roles = [r for r in roles if r in valid_roles] if roles or not acquire: permissions.append({ 'name': name, 'acquire': acquire, 'roles': roles }) return permissions def _getExportTemplate(self): return PageTemplateFile('rmeExport.xml', _xmldir) def _getImportMapping(self): return { 'rolemap': { 'roles': { CONVERTER: self._convertToUnique }, 'permissions': { CONVERTER: self._convertToUnique } }, 'roles': { 'role': { KEY: None } }, 'role': { 'name': { KEY: None } }, 'permissions': { 'permission': { KEY: None, DEFAULT: () } }, 'permission': { 'name': {}, 'role': { KEY: 'roles' }, 'acquire': { CONVERTER: self._convertToBoolean } } }
""" Folder_original__setOb(self, id, object) aq_chain = getattr(self, 'aq_chain', None) if aq_chain is None: # Not in acquisition context return if len(aq_chain) < 2: # Acquisition context is not deep enough for context to possibly be below portal skins. return portal_skins = aq_chain[1] if getattr(portal_skins, 'meta_type', '') != 'CMF Skins Tool' : # It is not a skin tool we're below. return _updateCacheEntry = getattr(portal_skins.aq_base, '_updateCacheEntry', None) if _updateCacheEntry is None: return _updateCacheEntry(self.id, id) Folder._setOb = Folder_setOb def Folder_isERP5SitePresent(self): """ Return True if a ERP5 Site is present as subobject. This is usefull to identify if a erp5 is present already on a Zope Setup. """ return len(self.objectIds("ERP5 Site")) > 0 Folder.isERP5SitePresent = Folder_isERP5SitePresent security = ClassSecurityInfo() security.declareProtected(Permissions.ManagePortal, 'isERP5SitePresent') Folder.security = security InitializeClass(Folder)
class VariableDefinition(SimpleItem): """Variable definition""" meta_type = 'Workflow Variable' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) description = '' for_catalog = 1 for_status = 1 default_value = '' default_expr = None # Overrides default_value if set info_guard = None update_always = 1 manage_options = ( {'label': 'Properties', 'action': 'manage_properties'}, ) def __init__(self, id): self.id = id def getDefaultExprText(self): if not self.default_expr: return '' else: return self.default_expr.text def getInfoGuard(self): if self.info_guard is not None: return self.info_guard else: return Guard().__of__(self) # Create a temporary guard. def getInfoGuardSummary(self): res = None if self.info_guard is not None: res = self.info_guard.getSummary() return res _properties_form = DTMLFile('variable_properties', _dtmldir) def manage_properties(self, REQUEST, manage_tabs_message=None): ''' ''' return self._properties_form(REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, description, default_value='', default_expr='', for_catalog=0, for_status=0, update_always=0, props=None, REQUEST=None): ''' ''' self.description = str(description) self.default_value = str(default_value) if default_expr: self.default_expr = Expression(default_expr) else: self.default_expr = None g = Guard() if g.changeFromProperties(props or REQUEST): self.info_guard = g else: self.info_guard = None self.for_catalog = bool(for_catalog) self.for_status = bool(for_status) self.update_always = bool(update_always) if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.')
# FOR A PARTICULAR PURPOSE # ############################################################################## from Products.DCWorkflow.Guard import Guard from Products.PythonScripts.PythonScript import PythonScript from App.special_dtml import DTMLFile from Products.ERP5Type import _dtmldir from AccessControl import ClassSecurityInfo, getSecurityManager from AccessControl.class_init import InitializeClass from AccessControl.PermissionRole import rolesForPermissionOn from OFS.misc_ import p_ from App.ImageFile import ImageFile from Acquisition import aq_base, aq_parent from zExceptions import Forbidden security = ClassSecurityInfo() PythonScript.security = security def haveProxyRole(self): """if a script has proxy role, return True""" return bool(self._proxy_roles) def om_icons(self): """Return a list of icon URLs to be displayed by an ObjectManager""" icons = ({'path': 'misc_/PythonScripts/pyscript.gif', 'alt': self.meta_type, 'title': self.meta_type},) if self.haveProxyRole(): icons = ({'path': 'p_/PythonScript_ProxyRole_icon', 'alt': 'Proxy Roled Python Script', 'title': 'This script has proxy role.'},) return icons
class VersionsTool(UniqueObject, SimpleItemWithProperties): __doc__ = __doc__ # copy from module id = 'portal_versions' meta_type = 'Portal Versions Tool' security = ClassSecurityInfo() manage_options = ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItemWithProperties.manage_options # With auto_copy_forward turned on, the versions tool lets users # check out an object even if it is not updated to the latest # revision. It copies the old revision forward. Note that # this feature really shouldn't be enabled unless users also have the # ability to revert to specific revisions. auto_copy_forward = 1 repository_name = 'VersionRepository' _properties = ( { 'id': 'repository_name', 'type': 'string', 'mode': 'w', 'label': 'ID of the version repository' }, { 'id': 'auto_copy_forward', 'type': 'boolean', 'mode': 'w', 'label': 'Copy old revisions forward rather than disallow checkout' }, ) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainVersionsTool', _wwwdir) # helper methods def _getVersionRepository(self): repo = aq_acquire(self, self.repository_name, containment=1) return repo def _getBranchName(self, info): parts = info.version_id.split('.') if len(parts) > 1: return parts[-2] return 'mainline' # public methods security.declarePublic('isUnderVersionControl') def isUnderVersionControl(self, obj): """Returns a true value if the object is under version control. """ obj = unproxied(obj) repo = self._getVersionRepository() return repo.isUnderVersionControl(obj) security.declarePublic('isCheckedOut') def isCheckedOut(self, obj): """Returns a true value if the object is checked out. """ obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): return 0 info = repo.getVersionInfo(obj) return (info.status == info.CHECKED_OUT) security.declarePublic('isResourceUpToDate') def isResourceUpToDate(self, obj, require_branch=0): """Return true if a version-controlled resource is up to date. """ obj = unproxied(obj) repo = self._getVersionRepository() return repo.isResourceUpToDate(obj, require_branch) # protected methods security.declarePublic('checkout') def checkout(self, obj): """Opens the object for development. Returns the object, which might be different from what was passed to the method if the object was replaced. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() old_state = None if not repo.isUnderVersionControl(obj): repo.applyVersionControl(obj) elif self.auto_copy_forward: if not repo.isResourceUpToDate(obj, require_branch=1): # The object is not at the latest revision or has a # sticky tag. Get it unstuck by copying the old state # forward after the object has been checked out. info = repo.getVersionInfo(obj) old_state = repo.getVersionOfResource(info.history_id, info.version_id) # Momentarily revert to the branch. obj = repo.updateResource(obj, self._getBranchName(info)) obj = repo.checkoutResource(obj) # Copy the old state into the object, minus __vc_info__. # XXX There ought to be some way to do this more cleanly. obj._p_changed = 1 for key in obj.__dict__.keys(): if key != '__vc_info__': if not old_state.__dict__.has_key(key): del obj.__dict__[key] for key, value in old_state.__dict__.items(): if key != '__vc_info__': obj.__dict__[key] = value # Check in as a copy. obj = repo.checkinResource( obj, 'Copied from revision %s' % info.version_id) repo.checkoutResource(obj) return None security.declarePublic('checkin') def checkin(self, obj, message=None): """Checks in a new version. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): repo.applyVersionControl(obj, message) else: if (not repo.isResourceUpToDate(obj, require_branch=1) and self.isCheckedOut(obj)): # This is a strange state, but it can be fixed. # Revert the object to the branch, replace the # reverted state with the new state, and check in. new_dict = obj.__dict__.copy() # Uncheckout obj = repo.uncheckoutResource(obj) info = repo.getVersionInfo(obj) obj = repo.updateResource(obj, self._getBranchName(info)) # Checkout obj = repo.checkoutResource(obj) # Restore the new state for key in obj.__dict__.keys(): if key != '__vc_info__': if not new_dict.has_key(key): del obj.__dict__[key] for key, value in new_dict.items(): if key != '__vc_info__': obj.__dict__[key] = value repo.checkinResource(obj, message or '') return None security.declarePublic('getLogEntries') def getLogEntries(self, obj, only_checkins=0): """Returns the log entries for an object as a sequence of mappings. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): return [] entries = repo.getLogEntries(obj) res = [] for entry in entries: a = entry.action if a == entry.ACTION_CHECKOUT: action = 'checkout' elif a == entry.ACTION_CHECKIN: action = 'checkin' elif a == entry.ACTION_UNCHECKOUT: action = 'uncheckout' elif a == entry.ACTION_UPDATE: action = 'update' else: action = '?' if only_checkins and action != 'checkin': continue res.append({ 'timestamp': entry.timestamp, 'version_id': entry.version_id, 'action': action, 'message': entry.message, 'user_id': entry.user_id, 'path': entry.path, }) return res security.declarePublic('getVersionId') def getVersionId(self, obj, plus=0): """Returns the version ID of the current revision. If the 'plus' flag is set and the object is checked out, the version ID will include a plus sign to indicate that when the object is checked in, it will have a higher version number. """ obj = unproxied(obj) repo = self._getVersionRepository() if repo.isUnderVersionControl(obj): info = repo.getVersionInfo(obj) res = info.version_id if plus and info.status == info.CHECKED_OUT: res += '+' return res else: return '' security.declarePublic('getVersionIds') def getVersionIds(self, obj): """Returns the version IDs of all revisions for an object. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() ids = repo.getVersionIds(obj) ids = map(int, ids) ids.sort() return map(str, ids) security.declarePublic('getHistoryId') def getHistoryId(self, obj): """Returns the version history ID of the object. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() return repo.getVersionInfo(obj).history_id security.declarePublic('revertToVersion') def revertToVersion(self, obj, version_id): """Reverts the object to the given version. If make_new_revision, a new revision is created, so that the object's state can progress along a new line without making the user deal with branches, labels, etc. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() # Verify the object is under version control. repo.getVersionInfo(obj) if self.isCheckedOut(obj): # Save the current data. self.checkin(obj, 'Auto-saved') repo.updateResource(obj, version_id)
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## import logging logger = logging.getLogger(__name__) from Products.ERP5Type.Globals import InitializeClass from AccessControl import ClassSecurityInfo from Products.CMFCore.ActionsTool import ActionsTool from Products.CMFCore.interfaces import IActionProvider from Products.CMFCore.permissions import ManagePortal security = ClassSecurityInfo() def migrateNonProviders(portal_actions): portal_actions_path = '/'.join(portal_actions.getPhysicalPath()) portal = portal_actions.getPortalObject() action_providers = list(portal_actions.action_providers) for provider_name in portal_actions.listActionProviders(): provider = getattr(portal, provider_name) if ( getattr(provider, '_actions', ()) and getattr(provider, 'listActionInfos', None) is None ): logger.info('migrating actions from %r to %r', portal_actions_path, '/'.join(provider.getPhysicalPath())) portal_actions._actions += provider._actions del provider._actions if (getattr(provider, 'listActionInfos', None) is None and getattr(provider, 'getActionListFor', None) is None and
class SkinnableObjectManager(ObjectManager): _v_skindata = None security = ClassSecurityInfo() security.declarePrivate('getSkinsFolderName') def getSkinsFolderName(self): # Not implemented. return None def __getattr__(self, name): ''' Looks for the name in an object with wrappers that only reach up to the root skins folder. This should be fast, flexible, and predictable. ''' if not name.startswith('_') and not name.startswith('aq_'): sd = self._v_skindata if sd is not None: request, ob, ignore = sd if not ignore.has_key(name): subob = getattr(ob, name, _marker) if subob is not _marker: # Return it in context of self, forgetting # its location and acting as if it were located # in self. return aq_base(subob) else: ignore[name] = 1 if superGetAttr is None: raise AttributeError, name return superGetAttr(self, name) security.declarePublic('setupCurrentSkin') def setupCurrentSkin(self, REQUEST=None): ''' Sets up _v_skindata so that __getattr__ can find it. Can also be called manually, allowing the user to change skins in the middle of a request. ''' if REQUEST is None: REQUEST = getattr(self, 'REQUEST', None) if REQUEST is None: # We are traversing without a REQUEST at the root. # Don't change the skin right now. (Otherwise # [un]restrictedTraverse messes up the skin data.) return if self._v_skindata is not None and self._v_skindata[0] is REQUEST: # Already set up for this request. return self._v_skindata = None sfn = self.getSkinsFolderName() if sfn is not None: # Note that our custom __getattr__ won't get confused # by skins at the moment because _v_skindata is None. sf = getattr(self, sfn, None) if sf is not None: try: sd = sf.getSkin(REQUEST) except: import sys from zLOG import LOG, ERROR LOG('CMFCore', ERROR, 'Unable to get skin', error=sys.exc_info()) else: if sd is not None: # Hide from acquisition. self._v_skindata = (REQUEST, sd, {}) def __of__(self, parent): ''' Sneakily sets up the portal skin then returns the wrapper that Acquisition.Implicit.__of__() would return. ''' w_self = ImplicitAcquisitionWrapper(self, parent) w_self.setupCurrentSkin() return w_self def _checkId(self, id, allow_dup=0): ''' Override of ObjectManager._checkId(). Allows the user to create objects with IDs that match the ID of a skin object. ''' superCheckId = SkinnableObjectManager.inheritedAttribute('_checkId') if not allow_dup: # Temporarily disable _v_skindata. # Note that this depends heavily on Zope's current thread # behavior. sd = self._v_skindata self._v_skindata = None try: base = getattr(self, 'aq_base', self) if not hasattr(base, id): # Cause _checkId to not check for duplication. return superCheckId(self, id, allow_dup=1) finally: self._v_skindata = sd return superCheckId(self, id, allow_dup)
""" Very simple volatile-attribute-based caching. Especially useful to cache processed pseudo-constants in PythonScripts: cached value will be set as a volatile on the PythonScript, so it gets flushed when script is edited. For such use, it would be even better to be able to put evaluate-once code in PythonScripts (ie, make python scripts really become Python *Scripts*, not "python-function-body-and-parameters"). NOTE: This patches OFS.Item.SimpleItem as it's the lowest patchable class before persistence.Persistent, where this patch would actually belong. """ security = ClassSecurityInfo() security.declarePublic('volatileCached') def volatileCached(self, func): """ Cache "func()" return value using a volatile on self. Return that value, calling func only if needed. Usual volatile rules apply: - outlives transaction duration - bound to a thread only while a transaction is executed (ie, it can be reused by a different thread on next processed transaction) - destroyed when object is modified by another transaction - destroyed when object is modified by transaction and transaction gets aborted - destroyed when connection cache is minimized and holder (self) is pruned (minimization can be triggered in many places...)
class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin, CompositionMixin, AmountGeneratorMixin): """ Each time delivery is modified, it MUST launch a reindexing of inventories which are related to the resources contained in the Delivery """ # CMF Type Definition meta_type = 'ERP5 Delivery' portal_type = 'Delivery' isDelivery = ConstantGetter('isDelivery', value=True) # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) # Default Properties property_sheets = ( PropertySheet.Base , PropertySheet.XMLObject , PropertySheet.CategoryCore , PropertySheet.DublinCore , PropertySheet.Task , PropertySheet.Arrow , PropertySheet.Movement , PropertySheet.Delivery , PropertySheet.Reference , PropertySheet.Price ) # Declarative interfaces zope.interface.implements(interfaces.IAmountGenerator, interfaces.IDivergenceController, interfaces.IMovementCollection) security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable') def isAccountable(self): """ Returns 1 if this needs to be accounted Only account movements which are not associated to a delivery Whenever delivery is there, delivery has priority """ return 1 security.declareProtected( Permissions.AccessContentsInformation, 'getTotalPrice') def getTotalPrice(self, fast=0, src__=0, base_contribution=None, rounding=False, **kw): """ Returns the total price for this order if the `fast` argument is set to a true value, then it use SQLCatalog to compute the price, otherwise it sums the total price of objects one by one. So if the order is not in the catalog, getTotalPrice(fast=1) will return 0, this is not a bug. base_contribution must be a relative url of a category. If passed, then fast parameter is ignored. """ if 'portal_type' not in kw: kw['portal_type'] = self.getPortalObject() \ .getPortalDeliveryMovementTypeList() if base_contribution is None: if fast: # XXX fast ignores base_contribution for now, but it should be possible # to use a related key kw['section_uid'] = self.getDestinationSectionUid() kw['stock.explanation_uid'] = self.getUid() return self.getPortalObject()\ .portal_simulation.getInventoryAssetPrice(**kw) result = sum([ line.getTotalPrice(fast=0) for line in self.objectValues(**kw) ]) else: # Find amounts from movements in the delivery. if isinstance(base_contribution, (tuple, list)): base_contribution_list = base_contribution else: base_contribution_list = (base_contribution,) base_contribution_value_list = [] portal_categories = self.portal_categories for relative_url in base_contribution_list: base_contribution_value = portal_categories.getCategoryValue(relative_url) if base_contribution_value is not None: base_contribution_value_list.append(base_contribution_value) if not base_contribution_value_list: # We cannot find any amount so that the result is 0. result = 0 else: matched_movement_list = [ movement for movement in self.getMovementList() if set(movement.getBaseContributionValueList()).intersection(base_contribution_value_list)] if rounding: portal_roundings = self.portal_roundings matched_movement_list = [ portal_roundings.getRoundingProxy(movement) for movement in matched_movement_list] result = sum([movement.getTotalPrice() for movement in matched_movement_list]) method = self._getTypeBasedMethod('convertTotalPrice') if method is not None: return method(result) return result security.declareProtected(Permissions.AccessContentsInformation, 'getTotalNetPrice') def getTotalNetPrice(self, fast=0, src__=0, **kw): """ Same as getTotalPrice, but including Tax and Discount (from legacy simulation). This method is deprecated because it uses deprecated Tax & Discount portal types. You should use getTotalPrice(base_contribution=) instead. """ total_price = self.getTotalPrice(fast=fast, src__=src__, **kw) kw['portal_type'] = self.getPortalObject().getPortalTaxMovementTypeList() return total_price + self.getTotalPrice(fast=fast, src__=src__, **kw) security.declareProtected(Permissions.AccessContentsInformation, 'getTotalQuantity') def getTotalQuantity(self, fast=0, src__=0, **kw): """ Returns the total quantity of this order. if the `fast` argument is set to a true value, then it use SQLCatalog to compute the quantity, otherwise it sums the total quantity of objects one by one. So if the order is not in the catalog, getTotalQuantity(fast=1) will return 0, this is not a bug. """ if 'portal_type' not in kw: kw['portal_type'] = self.getPortalObject() \ .getPortalDeliveryMovementTypeList() if fast: kw['section_uid'] = self.getDestinationSectionUid() kw['stock.explanation_uid'] = self.getUid() return self.getPortalObject().portal_simulation.getInventory(**kw) return sum([ line.getTotalQuantity(fast=0) for line in self.objectValues(**kw) ]) security.declareProtected(Permissions.AccessContentsInformation, 'getDeliveryUid') def getDeliveryUid(self): return self.getUid() security.declareProtected(Permissions.AccessContentsInformation, 'getDeliveryValue') def getDeliveryValue(self): """ Deprecated, we should use getRootDeliveryValue instead """ return self security.declareProtected(Permissions.AccessContentsInformation, 'getRootDeliveryValue') def getRootDeliveryValue(self): """ This method returns the delivery, it is usefull to retrieve the delivery from a line or a cell """ return self security.declareProtected(Permissions.AccessContentsInformation, 'getDelivery') def getDelivery(self): return self.getRelativeUrl() security.declareProtected(Permissions.AccessContentsInformation, '_getMovementList') def _getMovementList(self, portal_type=None, **kw): """ Return a list of movements """ movement_portal_type_set = set( self.getPortalObject().getPortalMovementTypeList()) movement_list = self.objectValues( portal_type=movement_portal_type_set, **kw) if movement_list: if isinstance(portal_type, str): portal_type = portal_type, elif isinstance(portal_type, (list, tuple)): portal_type = set(portal_type) # Browse lines recursively and collect leafs. stack = [iter(movement_list)] movement_list = [] while stack: for sub_object in stack[-1]: content_list = sub_object.objectValues( portal_type=movement_portal_type_set, **kw) if sub_object.hasCellContent(): cell_list = sub_object.getCellValueList() if len(cell_list) != len(content_list): content_list = set(content_list).difference(cell_list) if content_list: stack.append(iter(content_list)) break else: movement_list.extend(x for x in content_list if portal_type is None or x.getPortalType() in portal_type) elif content_list: stack.append(iter(content_list)) break elif portal_type is None or \ sub_object.getPortalType() in portal_type: movement_list.append(sub_object) else: del stack[-1] return movement_list security.declareProtected(Permissions.AccessContentsInformation, 'getMovementList') def getMovementList(self, portal_type=None, **kw): """ Return a list of movements. """ return self._getMovementList(portal_type=portal_type, **kw) security.declareProtected(Permissions.AccessContentsInformation, 'getSimulatedMovementList') def getSimulatedMovementList(self): """ Return a list of simulated movements. This does not contain Container Line or Container Cell. """ return self.getMovementList(portal_type= self.getPortalObject().getPortalSimulatedMovementTypeList()) security.declareProtected(Permissions.AccessContentsInformation, 'getInvoiceMovementList') def getInvoiceMovementList(self): """ Return a list of simulated movements. This does not contain Container Line or Container Cell. """ return self.getMovementList(portal_type= self.getPortalObject().getPortalInvoiceMovementTypeList()) security.declareProtected(Permissions.AccessContentsInformation, 'getContainerList') def getContainerList(self): """ Return a list of root containers. This does not contain sub-containers. """ return self.objectValues(portal_type= self.getPortalObject().getPortalContainerTypeList()) ####################################################### # Causality computation security.declareProtected(Permissions.AccessContentsInformation, 'isConvergent') def isConvergent(self,**kw): """ Returns 0 if the target is not met """ return bool(not self.isDivergent(**kw)) security.declareProtected(Permissions.AccessContentsInformation, 'isSimulated') def isSimulated(self): """ Returns 1 if all non-null movements have a delivery counterpart in the simulation """ for m in self.getMovementList(): if m.getQuantity() and not m.isSimulated(): return 0 return 1 security.declareProtected(Permissions.AccessContentsInformation, 'isDivergent') def isDivergent(self, fast=0, **kw): """Return True if this movement diverges from the its simulation. """ ## Note that fast option was removed. Now, fast=1 is ignored. # Check if the total quantity equals the total of each simulation movement quantity for simulation_movement in self._getAllRelatedSimulationMovementList(): if simulation_movement.isDivergent(): return True return False security.declareProtected(Permissions.AccessContentsInformation, 'getDivergenceList') def getDivergenceList(self, **kw): """ Return a list of messages that contains the divergences """ divergence_list = [] for simulation_movement in self._getAllRelatedSimulationMovementList(): divergence_list.extend(simulation_movement.getDivergenceList()) return divergence_list security.declareProtected(Permissions.AccessContentsInformation, 'updateCausalityState') @UnrestrictedMethod def updateCausalityState(self, solve_automatically=True, **kw): """ This is often called as an activity, it will check if the deliver is convergent, and if so it will put the delivery in a solved state, if not convergent in a diverged state """ isTransitionPossible = \ self.getPortalObject().portal_workflow.isTransitionPossible if isTransitionPossible(self, 'diverge') and \ isTransitionPossible(self, 'converge'): if self.isDivergent(**kw): if solve_automatically and \ isTransitionPossible(self, 'solve_automatically'): self.solveAutomatically() else: self.diverge() else: self.converge() def updateSimulation(self, calculate=False, **kw): if calculate: path = self.getPath() self.activate( after_tag='build:'+path, after_path_and_method_id=(path, '_localBuild'), ).updateCausalityState() if kw: super(Delivery, self).updateSimulation(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'splitAndDeferMovementList') def splitAndDeferMovementList(self, start_date=None, stop_date=None, movement_uid_list=[], delivery_solver=None, target_solver='CopyToTarget', delivery_builder=None): """ this method will unlink and delete movements in movement_uid_list and rebuild a new Packing List with them. 1/ change date in simulation, call TargetSolver and expand 2/ detach simulation movements from to-be-deleted movements 3/ delete movements XXX make sure that all detached movements are deleted at the same time, else the interaction workflow would reattach them to a delivery rule. 4/ call builder """ tag_list = [] movement_list = [x for x in self.getMovementList() if x.getUid() in movement_uid_list] if not movement_list: return deferred_simulation_movement_list = [] # defer simulation movements if start_date is not None or stop_date is not None: for movement in movement_list: start_date = start_date or movement.getStartDate() stop_date = stop_date or movement.getStopDate() for s_m in movement.getDeliveryRelatedValueList(): if s_m.getStartDate() != start_date or \ s_m.getStopDate() != stop_date: s_m.edit(start_date=start_date, stop_date=stop_date) deferred_simulation_movement_list.append(s_m) solver_tag = '%s_splitAndDefer_solver' % self.getRelativeUrl() expand_tag = '%s_splitAndDefer_expand' % self.getRelativeUrl() detach_tag = '%s_splitAndDefer_detach' % self.getRelativeUrl() build_tag = '%s_splitAndDefer_build' % self.getRelativeUrl() # call solver and expand on deferrd movements for movement in movement_list: movement.activate(tag=solver_tag).Movement_solveMovement( delivery_solver, target_solver) tag_list.append(solver_tag) kw = {'after_tag': tag_list[:], 'tag': expand_tag} for s_m in deferred_simulation_movement_list: s_m.expand('deferred', activate_kw=kw) tag_list.append(expand_tag) detached_movement_url_list = [] deleted_movement_uid_list = [] #detach simulation movements for movement in movement_list: movement_url = movement.getRelativeUrl() movement_uid = getattr(movement,'uid',None) if movement_uid: deleted_movement_uid_list.append(movement_uid) for s_m in movement.getDeliveryRelatedValueList(): delivery_list = \ [x for x in s_m.getDeliveryList() if x != movement_url] s_m.activate(after_tag=tag_list[:], tag=detach_tag).setDeliveryList( delivery_list) detached_movement_url_list.append(s_m.getRelativeUrl()) tag_list.append(detach_tag) #delete delivery movements # deleteContent uses the uid as a activity tag self.activate(after_tag=tag_list[:]).deleteContent([movement.getId() for movement in movement_list]) tag_list.extend(deleted_movement_uid_list) # update causality state on self, after deletion self.activate(after_tag=tag_list[:], activity='SQLQueue').updateCausalityState() # call builder on detached movements builder = getattr(self.portal_deliveries, delivery_builder) builder.activate(after_tag=tag_list[:], tag=build_tag).build( movement_relative_url_list=detached_movement_url_list) ####################################################### # Defer indexing process def reindexObject(self, *k, **kw): """ Reindex children and simulation """ self.recursiveReindexObject(*k, **kw) # do not reexpand simulation: this is a task for DSolver / TSolver ####################################################### # Stock Management def _getMovementResourceList(self): resource_set = {m.getResource() for m in self.objectValues(portal_type= self.getPortalObject().getPortalMovementTypeList())} resource_set.discard(None) return list(resource_set) security.declareProtected(Permissions.AccessContentsInformation, 'getInventory') def getInventory(self, **kw): """ Returns inventory """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventory(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventory') def getCurrentInventory(self, **kw): """ Returns current inventory """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getCurrentInventory(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getAvailableInventory') def getAvailableInventory(self, **kw): """ Returns available inventory (current inventory - deliverable) """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getAvailableInventory(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventory') def getFutureInventory(self, **kw): """ Returns inventory at infinite """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getFutureInventory(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryList') def getInventoryList(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventoryList(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryList') def getCurrentInventoryList(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getCurrentInventoryList(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryList') def getFutureInventoryList(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getFutureInventoryList(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryStat') def getInventoryStat(self, **kw): """ Returns statistics of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventoryStat(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryStat') def getCurrentInventoryStat(self, **kw): """ Returns statistics of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getCurrentInventoryStat(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryStat') def getFutureInventoryStat(self, **kw): """ Returns statistics of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getFutureInventoryStat(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryChart') def getInventoryChart(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventoryChart(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryChart') def getCurrentInventoryChart(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getCurrentInventoryChart(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryChart') def getFutureInventoryChart(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getFutureInventoryChart(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryHistoryList') def getInventoryHistoryList(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventoryHistoryList(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryHistoryChart') def getInventoryHistoryChart(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getInventoryHistoryChart(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getMovementHistoryList') def getMovementHistoryList(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getMovementHistoryList(**kw) security.declareProtected(Permissions.AccessContentsInformation, 'getMovementHistoryStat') def getMovementHistoryStat(self, **kw): """ Returns list of inventory grouped by section or site """ kw['resource'] = self._getMovementResourceList() return self.portal_simulation.getMovementHistoryStat(**kw) # JPS: We must still decide if getInventoryAssetPrice is part of the Delivery API # security.declareProtected(Permissions.AccessContentsInformation, 'getInventoryAssetPrice') # def getInventoryAssetPrice(self, **kw): # """ # Returns asset at infinite # """ # kw['category'] = self._getMovementResourceList() # return self.portal_simulation.getInventoryAssetPrice(**kw) # # security.declareProtected(Permissions.AccessContentsInformation, 'getFutureInventoryAssetPrice') # def getFutureInventoryAssetPrice(self, **kw): # """ # Returns asset at infinite # """ # kw['category'] = self._getMovementResourceList() # return self.portal_simulation.getFutureInventoryAssetPrice(**kw) # # security.declareProtected(Permissions.AccessContentsInformation, 'getCurrentInventoryAssetPrice') # def getCurrentInventoryAssetPrice(self, **kw): # """ # Returns asset at infinite # """ # kw['category'] = self._getMovementResourceList() # return self.portal_simulation.getCurrentInventoryAssetPrice(**kw) # # security.declareProtected(Permissions.AccessContentsInformation, 'getAvailableInventoryAssetPrice') # def getAvailableInventoryAssetPrice(self, **kw): # """ # Returns asset at infinite # """ # kw['category'] = self._getMovementResourceList() # return self.portal_simulation.getAvailableInventoryAssetPrice(**kw) ########################################################################## # Applied Rule stuff security.declareProtected(Permissions.AccessContentsInformation, 'localBuild') def localBuild(self, activity_kw=()): """Activate builders for this delivery The generated activity will find all buildable business links for this delivery, and call related builders, which will select all simulation movements part of the same explanation(s) as the delivery. XXX: Consider moving it to SimulableMixin if it's useful for Subscription Items. """ # XXX: Previous implementation waited for expand activities of related # documents and even suggested to look at explanation tree, # instead of causalities. Is it required ? kw = {'priority': 3} kw.update(activity_kw) after_tag = kw.pop('after_tag', None) if isinstance(after_tag, basestring): after_tag = [after_tag] else: after_tag = list(after_tag) if after_tag else [] after_tag.append('build:' + self.getPath()) sm = getSecurityManager() newSecurityManager(None, nobody) try: unrestricted_apply(self.activate(after_tag=after_tag, **kw)._localBuild) finally: setSecurityManager(sm) def _localBuild(self): """Do an immediate local build for this delivery""" return self.asComposedDocument().build(explanation=self) def _createRootAppliedRule(self): # Only create RAR if we are not in a "too early" or "too late" state. state = self.getSimulationState() if (state != 'deleted' and state not in self.getPortalObject().getPortalDraftOrderStateList()): return super(Delivery, self)._createRootAppliedRule() security.declareProtected( Permissions.AccessContentsInformation, 'getRootCausalityValueList') def getRootCausalityValueList(self): """ Returns the initial causality value for this movement. This method will look at the causality and check if the causality has already a causality """ seen_set = set() def recursive(self): if self in seen_set: return [] seen_set.add(self) causality_value_list = self.getCausalityValueList() if causality_value_list: initial_list = [] for causality in causality_value_list: # The causality may be something which has not this method # (e.g. item) if getattr(causality, 'getRootCausalityValueList', None) is None: continue assert causality != self initial_list += [x for x in recursive(causality) if x not in initial_list] return initial_list return [self] return recursive(self) # XXX Temp hack, should be removed has soon as the structure of # the order/delivery builder will be reviewed. It might # be reviewed if we plan to configure movement groups in the zmi security.declareProtected( Permissions.ModifyPortalContent, 'setRootCausalityValueList') def setRootCausalityValueList(self,value): """ This is a hack """ pass security.declareProtected( Permissions.AccessContentsInformation, 'getParentExplanationValue') def getParentExplanationValue(self): """ This method should be removed as soon as movement groups will be rewritten. It is a temp hack """ return self # XXX Temp hack, should be removed has soon as the structure of # the order/delivery builder will be reviewed. It might # be reviewed if we plan to configure movement groups in the zmi security.declareProtected( Permissions.ModifyPortalContent, 'setParentExplanationValue') def setParentExplanationValue(self,value): """ This is a hack """ pass security.declareProtected(Permissions.AccessContentsInformation, 'getBuilderList') def getBuilderList(self): """Returns appropriate builder list.""" return self._getTypeBasedMethod('getBuilderList')() # XXX - quite a hack, since no way to know... # propper implementation should use business path definition # however, the real question is "is this really necessary" # since the main purpose of this method is superceded # by IDivergenceController security.declareProtected( Permissions.AccessContentsInformation, 'getRootSpecialiseValue') def getRootSpecialiseValue(self, portal_type_list): """Returns first specialise value matching portal type""" def findSpecialiseValue(context): if context.getPortalType() in portal_type_list: return context if getattr(context, 'getSpecialiseValueList', None) is not None: for specialise in context.getSpecialiseValueList(): specialise_value = findSpecialiseValue(specialise) if specialise_value is not None: return specialise_value return None return findSpecialiseValue(self) security.declareProtected( Permissions.ModifyPortalContent, 'disconnectSimulationMovementList') def disconnectSimulationMovementList(self, movement_list=None): """Disconnects simulation movements from delivery's lines If movement_list is passed only those movements will be disconnected from simulation. If movements in movement_list do not belong to current delivery they are silently ignored. Returns list of disconnected Simulation Movements. Known issues and open questions: * how to protect disconnection from completed delivery? * what to do if movements from movement_list do not belong to delivery? * it is required to remove causality relation from delivery or delivery lines?? """ delivery_movement_value_list = self.getMovementList() if movement_list is not None: movement_value_list = [self.restrictedTraverse(movement) for movement in movement_list] # only those how are in this delivery movement_value_list = [movement_value for movement_value in movement_value_list if movement_value in delivery_movement_value_list] else: movement_value_list = delivery_movement_value_list disconnected_simulation_movement_list = [] for movement_value in movement_value_list: # Note: Relies on fact that is invoked, when simulation movements are # indexed properly for simulation_movement in movement_value \ .getDeliveryRelatedValueList(portal_type='Simulation Movement'): simulation_movement.edit( delivery = None, delivery_ratio = None ) disconnected_simulation_movement_list.append( simulation_movement.getRelativeUrl()) return disconnected_simulation_movement_list def _getAllRelatedSimulationMovementList(self): result = [] for movement in self.getMovementList(): result += movement.getDeliveryRelatedValueList() return result security.declareProtected(Permissions.AccessContentsInformation, 'getDivergentTesterAndSimulationMovementList') def getDivergentTesterAndSimulationMovementList(self): """ This method returns a list of (tester, simulation_movement) for each divergence. """ divergent_tester_list = [] for simulation_movement in self._getAllRelatedSimulationMovementList(): simulation_movement = simulation_movement.getObject() rule = simulation_movement.getParentValue().getSpecialiseValue() for tester in rule._getDivergenceTesterList(exclude_quantity=False): if tester.explain(simulation_movement) not in (None, []): divergent_tester_list.append((tester, simulation_movement)) return divergent_tester_list # XXX: Dirty but required for erp5_banking_core getBaobabSourceUid = lambda x: x.getSourceUid() getBaobabSourceUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationUid = lambda x: x.getDestinationUid() getBaobabDestinationUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceSectionUid = lambda x: x.getSourceSectionUid() getBaobabSourceSectionUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationSectionUid = lambda x: x.getDestinationSectionUid() getBaobabDestinationSectionUid__roles__ = PermissionRole(Permissions.View) getBaobabSourcePaymentUid = lambda x: x.getSourcePaymentUid() getBaobabSourcePaymentUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationPaymentUid = lambda x: x.getDestinationPaymentUid() getBaobabDestinationPaymentUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceFunctionUid = lambda x: x.getSourceFunctionUid() getBaobabSourceFunctionUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationFunctionUid = lambda x: x.getDestinationFunctionUid() getBaobabDestinationFunctionUid__roles__ = PermissionRole(Permissions.View) getBaobabSourceProjectUid = lambda x: x.getSourceProjectUid() getBaobabSourceProjectUid__roles__ = PermissionRole(Permissions.View) getBaobabDestinationProjectUid = lambda x: x.getDestinationProjectUid() getBaobabDestinationProjectUid__roles__ = PermissionRole(Permissions.View)
class DCWorkflowDefinition(WorkflowUIMixin, Folder): ''' This class is the workflow engine and the container for the workflow definition. UI methods are in WorkflowUIMixin. ''' implements(IDCWorkflowDefinition, IWorkflowDefinition) __implements__ = z2IWorkflowDefinition title = 'DC Workflow Definition' description = '' state_var = 'state' initial_state = None states = None transitions = None variables = None worklists = None scripts = None permissions = () groups = () # Names of groups managed by this workflow. roles = None # The role names managed by this workflow. # If roles is None, listRoles() provides a default. creation_guard = None # The guard that can veto object creation. manager_bypass = 0 # Boolean: 'Manager' role bypasses guards manage_options = ( { 'label': 'Properties', 'action': 'manage_properties' }, { 'label': 'States', 'action': 'states/manage_main' }, { 'label': 'Transitions', 'action': 'transitions/manage_main' }, { 'label': 'Variables', 'action': 'variables/manage_main' }, { 'label': 'Worklists', 'action': 'worklists/manage_main' }, { 'label': 'Scripts', 'action': 'scripts/manage_main' }, { 'label': 'Permissions', 'action': 'manage_permissions' }, { 'label': 'Groups', 'action': 'manage_groups' }, ) security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) def __init__(self, id): self.id = id from States import States self._addObject(States('states')) from Transitions import Transitions self._addObject(Transitions('transitions')) from Variables import Variables self._addObject(Variables('variables')) from Worklists import Worklists self._addObject(Worklists('worklists')) from Scripts import Scripts self._addObject(Scripts('scripts')) def _addObject(self, ob): id = ob.getId() setattr(self, id, ob) self._objects = self._objects + ({ 'id': id, 'meta_type': ob.meta_type }, ) # # Workflow engine. # def _getStatusOf(self, ob): tool = aq_parent(aq_inner(self)) status = tool.getStatusOf(self.id, ob) if status is None: return {} else: return status def _getWorkflowStateOf(self, ob, id_only=0): tool = aq_parent(aq_inner(self)) status = tool.getStatusOf(self.id, ob) if status is None: state = self.initial_state else: state = status.get(self.state_var, None) if state is None: state = self.initial_state if id_only: return state else: return self.states.get(state, None) def _getPortalRoot(self): return aq_parent(aq_inner(aq_parent(aq_inner(self)))) security.declarePrivate('getCatalogVariablesFor') def getCatalogVariablesFor(self, ob): ''' Allows this workflow to make workflow-specific variables available to the catalog, making it possible to implement worklists in a simple way. Returns a mapping containing the catalog variables that apply to ob. ''' res = {} status = self._getStatusOf(ob) for id, vdef in self.variables.items(): if vdef.for_catalog: if status.has_key(id): value = status[id] # Not set yet. Use a default. elif vdef.default_expr is not None: ec = createExprContext(StateChangeInfo(ob, self, status)) value = vdef.default_expr(ec) else: value = vdef.default_value res[id] = value # Always provide the state variable. state_var = self.state_var res[state_var] = status.get(state_var, self.initial_state) return res security.declarePrivate('listObjectActions') def listObjectActions(self, info): ''' Allows this workflow to include actions to be displayed in the actions box. Called only when this workflow is applicable to info.object. Returns the actions to be displayed to the user. ''' ob = info.object sdef = self._getWorkflowStateOf(ob) if sdef is None: return None res = [] for tid in sdef.transitions: tdef = self.transitions.get(tid, None) if tdef is not None and tdef.trigger_type == TRIGGER_USER_ACTION: if tdef.actbox_name: if self._checkTransitionGuard(tdef, ob): res.append(( tid, { 'id': tid, 'name': tdef.actbox_name % info, 'url': tdef.actbox_url % info, 'permissions': (), # Predetermined. 'category': tdef.actbox_category, 'transition': tdef })) res.sort() return [result[1] for result in res] security.declarePrivate('listGlobalActions') def listGlobalActions(self, info): ''' Allows this workflow to include actions to be displayed in the actions box. Called on every request. Returns the actions to be displayed to the user. ''' if not self.worklists: return None # Optimization sm = getSecurityManager() portal = self._getPortalRoot() res = [] fmt_data = None for id, qdef in self.worklists.items(): if qdef.actbox_name: guard = qdef.guard if guard is None or guard.check(sm, self, portal): searchres = None var_match_keys = qdef.getVarMatchKeys() if var_match_keys: # Check the catalog for items in the worklist. catalog = getToolByName(self, 'portal_catalog') kw = {} for k in var_match_keys: v = qdef.getVarMatch(k) kw[k] = [x % info for x in v] searchres = catalog.searchResults(**kw) if not searchres: continue if fmt_data is None: fmt_data = TemplateDict() fmt_data._push(info) fmt_data._push({'count': len(searchres)}) res.append(( id, { 'id': id, 'name': qdef.actbox_name % fmt_data, 'url': qdef.actbox_url % fmt_data, 'permissions': (), # Predetermined. 'category': qdef.actbox_category })) fmt_data._pop() res.sort() return [result[1] for result in res] security.declarePrivate('isActionSupported') def isActionSupported(self, ob, action, **kw): ''' Returns a true value if the given action name is possible in the current state. ''' sdef = self._getWorkflowStateOf(ob) if sdef is None: return 0 if action in sdef.transitions: tdef = self.transitions.get(action, None) if (tdef is not None and tdef.trigger_type == TRIGGER_USER_ACTION and self._checkTransitionGuard(tdef, ob, **kw)): return 1 return 0 security.declarePrivate('doActionFor') def doActionFor(self, ob, action, comment='', **kw): ''' Allows the user to request a workflow action. This method must perform its own security checks. ''' kw['comment'] = comment sdef = self._getWorkflowStateOf(ob) if sdef is None: raise WorkflowException(_(u'Object is in an undefined state.')) if action not in sdef.transitions: raise Unauthorized(action) tdef = self.transitions.get(action, None) if tdef is None or tdef.trigger_type != TRIGGER_USER_ACTION: msg = _( u"Transition '${action_id}' is not triggered by a user " u"action.", mapping={'action_id': action}) raise WorkflowException(msg) if not self._checkTransitionGuard(tdef, ob, **kw): raise Unauthorized(action) self._changeStateOf(ob, tdef, kw) security.declarePrivate('isInfoSupported') def isInfoSupported(self, ob, name): ''' Returns a true value if the given info name is supported. ''' if name == self.state_var: return 1 vdef = self.variables.get(name, None) if vdef is None: return 0 return 1 security.declarePrivate('getInfoFor') def getInfoFor(self, ob, name, default): ''' Allows the user to request information provided by the workflow. This method must perform its own security checks. ''' if name == self.state_var: return self._getWorkflowStateOf(ob, 1) vdef = self.variables[name] if vdef.info_guard is not None and not vdef.info_guard.check( getSecurityManager(), self, ob): return default status = self._getStatusOf(ob) if status is not None and status.has_key(name): value = status[name] # Not set yet. Use a default. elif vdef.default_expr is not None: ec = createExprContext(StateChangeInfo(ob, self, status)) value = vdef.default_expr(ec) else: value = vdef.default_value return value security.declarePrivate('allowCreate') def allowCreate(self, container, type_name): """Returns true if the user is allowed to create a workflow instance. The object passed to the guard is the prospective container. """ if self.creation_guard is not None: return self.creation_guard.check(getSecurityManager(), self, container) return 1 security.declarePrivate('notifyCreated') def notifyCreated(self, ob): """Notifies this workflow after an object has been created and added. """ try: self._changeStateOf(ob, None) except (ObjectDeleted, ObjectMoved): # Swallow. pass security.declarePrivate('notifyBefore') def notifyBefore(self, ob, action): ''' Notifies this workflow of an action before it happens, allowing veto by exception. Unless an exception is thrown, either a notifySuccess() or notifyException() can be expected later on. The action usually corresponds to a method name. ''' pass security.declarePrivate('notifySuccess') def notifySuccess(self, ob, action, result): ''' Notifies this workflow that an action has taken place. ''' pass security.declarePrivate('notifyException') def notifyException(self, ob, action, exc): ''' Notifies this workflow that an action failed. ''' pass security.declarePrivate('updateRoleMappingsFor') def updateRoleMappingsFor(self, ob): """Changes the object permissions according to the current state. """ changed = 0 sdef = self._getWorkflowStateOf(ob) if sdef is None: return 0 # Update the role -> permission map. if self.permissions: for p in self.permissions: roles = [] if sdef.permission_roles is not None: roles = sdef.permission_roles.get(p, roles) if modifyRolesForPermission(ob, p, roles): changed = 1 # Update the group -> role map. groups = self.getGroups() managed_roles = self.getRoles() if groups and managed_roles: for group in groups: roles = () if sdef.group_roles is not None: roles = sdef.group_roles.get(group, ()) if modifyRolesForGroup(ob, group, roles, managed_roles): changed = 1 return changed def _checkTransitionGuard(self, t, ob, **kw): guard = t.guard if guard is None: return 1 if guard.check(getSecurityManager(), self, ob, **kw): return 1 return 0 def _findAutomaticTransition(self, ob, sdef): tdef = None for tid in sdef.transitions: t = self.transitions.get(tid, None) if t is not None and t.trigger_type == TRIGGER_AUTOMATIC: if self._checkTransitionGuard(t, ob): tdef = t break return tdef def _changeStateOf(self, ob, tdef=None, kwargs=None): ''' Changes state. Can execute multiple transitions if there are automatic transitions. tdef set to None means the object was just created. ''' moved_exc = None while 1: try: sdef = self._executeTransition(ob, tdef, kwargs) except ObjectMoved, moved_exc: ob = moved_exc.getNewObject() sdef = self._getWorkflowStateOf(ob) # Re-raise after all transitions. if sdef is None: break tdef = self._findAutomaticTransition(ob, sdef) if tdef is None: # No more automatic transitions. break # Else continue. if moved_exc is not None: # Re-raise. raise moved_exc
class FSPythonScript(FSObject, Script): """FSPythonScripts act like Python Scripts but are not directly modifiable from the management interface.""" meta_type = 'Filesystem Script (Python)' _params = _body = '' _v_f = None _proxy_roles = () _owner = None # Unowned manage_options = ( { 'label': 'Customize', 'action': 'manage_main' }, { 'label': 'Test', 'action': 'ZScriptHTML_tryForm', 'help': ('PythonScripts', 'PythonScript_test.stx') }, ) security = ClassSecurityInfo() security.declareObjectProtected(View) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = DTMLFile('custpy', _dtmldir) security.declareProtected( View, 'index_html', ) # Prevent the bindings from being edited TTW security.declarePrivate('ZBindings_edit', 'ZBindingsHTML_editForm', 'ZBindingsHTML_editAction') def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" return CustomizedPythonScript(self.getId(), self.read()) def _readFile(self, reparse): """Read the data from the filesystem. """ file = open(self._filepath, 'rU') try: data = file.read() finally: file.close() if reparse: self._write(data, reparse) def _validateProxy(self, roles=None): pass def __render_with_namespace__(self, namespace): '''Calls the script.''' self._updateFromFS() return Script.__render_with_namespace__(self, namespace) def __call__(self, *args, **kw): '''Calls the script.''' self._updateFromFS() return Script.__call__(self, *args, **kw) #### The following is mainly taken from PythonScript.py ### def _exec(self, bound_names, args, kw): """Call a Python Script Calling a Python Script is an actual function invocation. """ # do caching keyset = None if self.ZCacheable_isCachingEnabled(): # Prepare a cache key. keyset = kw.copy() asgns = self.getBindingAssignments() name_context = asgns.getAssignedName('name_context', None) if name_context: keyset[name_context] = self.aq_parent.getPhysicalPath() name_subpath = asgns.getAssignedName('name_subpath', None) if name_subpath: keyset[name_subpath] = self._getTraverseSubpath() # Note: perhaps we should cache based on name_ns also. keyset['*'] = args result = self.ZCacheable_get(keywords=keyset, default=_marker) if result is not _marker: # Got a cached value. return result # Prepare the function. f = self._v_f if f is None: # The script has errors. __traceback_supplement__ = (FSPythonScriptTracebackSupplement, self, 0) raise RuntimeError, '%s has errors.' % self._filepath # Updating func_globals directly is not thread safe here. # In normal PythonScripts, every thread has its own # copy of the function. But in FSPythonScripts # there is only one copy. So here's another way. new_globals = f.func_globals.copy() new_globals['__traceback_supplement__'] = ( FSPythonScriptTracebackSupplement, self) new_globals['__file__'] = self._filepath if bound_names: new_globals.update(bound_names) if f.func_defaults: f = new.function(f.func_code, new_globals, f.func_name, f.func_defaults) else: f = new.function(f.func_code, new_globals, f.func_name) # Execute the function in a new security context. security = getSecurityManager() security.addContext(self) try: result = f(*args, **kw) if keyset is not None: # Store the result in the cache. self.ZCacheable_set(result, keywords=keyset) return result finally: security.removeContext(self) security.declareProtected(ViewManagementScreens, 'getModTime') # getModTime defined in FSObject security.declareProtected(ViewManagementScreens, 'ZScriptHTML_tryForm') # ZScriptHTML_tryForm defined in Shared.DC.Scripts.Script.Script def ZScriptHTML_tryParams(self): """Parameters to test the script with.""" param_names = [] for name in self._params.split(','): name = name.strip() if name and name[0] != '*': param_names.append(name.split('=', 1)[0]) return param_names security.declareProtected(ViewManagementScreens, 'read') def read(self): self._updateFromFS() return self._source security.declareProtected(ViewManagementScreens, 'document_src') def document_src(self, REQUEST=None, RESPONSE=None): """Return unprocessed document source.""" if RESPONSE is not None: RESPONSE.setHeader('Content-Type', 'text/plain') return self._source security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource') def PrincipiaSearchSource(self): "Support for searching - the document's contents are searched." return "%s\n%s" % (self._params, self._body) security.declareProtected(ViewManagementScreens, 'params') def params(self): return self._params security.declareProtected(ViewManagementScreens, 'manage_haveProxy') manage_haveProxy = PythonScript.manage_haveProxy.im_func security.declareProtected(ViewManagementScreens, 'body') def body(self): return self._body security.declareProtected(ViewManagementScreens, 'get_size') def get_size(self): return len(self.read()) security.declareProtected(FTPAccess, 'manage_FTPget') def manage_FTPget(self): "Get source for FTP download" self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/plain') return self.read() def _write(self, text, compile): ''' Parses the source, storing the body, params, title, bindings, and source in self. If compile is set, compiles the function. ''' ps = PythonScript(self.id) ps.write(text) if compile: ps._makeFunction(1) self._v_f = f = ps._v_f if f is not None: self.func_code = f.func_code self.func_defaults = f.func_defaults else: # There were errors in the compile. # No signature. self.func_code = bad_func_code() self.func_defaults = None self._body = ps._body self._params = ps._params self.title = ps.title self._setupBindings(ps.getBindingAssignments().getAssignedNames()) self._source = ps.read() # Find out what the script sees. def func_defaults(self): # This ensures func_code and func_defaults are # set when the code hasn't been compiled yet, # just in time for mapply(). Truly odd, but so is mapply(). :P self._updateFromFS() return self.__dict__.get('func_defaults', None) func_defaults = ComputedAttribute(func_defaults, 1) def func_code(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('func_code', None) func_code = ComputedAttribute(func_code, 1) def title(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('title', None) title = ComputedAttribute(title, 1) def getBindingAssignments(self): # Override of the version in Bindings.py. # This version ensures that bindings get loaded on demand. if not hasattr(self, '_bind_names'): # Set a default first to avoid recursion self._setupBindings() # Now do it for real self._updateFromFS() return self._bind_names
from Products.DCWorkflow.utils import Message as _ from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION from Products.CMFCore.utils import getToolByName from Products.ZSQLCatalog.SQLCatalog import SimpleQuery, AutoQuery, ComplexQuery, NegatedQuery from Products.CMFCore.utils import _getAuthenticatedUser from Products.ERP5Type import Permissions from Products.ERP5Type.Cache import CachingMethod from sets import ImmutableSet from Acquisition import aq_base from Persistence import Persistent from Products.ERP5Type.Globals import PersistentMapping from MySQLdb import ProgrammingError, OperationalError from DateTime import DateTime security = ClassSecurityInfo() WorkflowTool.security = security def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, transition_list, args=None, kw=None): ''' Allows the system to request a workflow action. This method must perform its own security checks. ''' if type(transition_list) in StringTypes: method_id = transition_list elif len(transition_list) == 1: method_id = transition_list[0] else: raise ValueError('WorkflowMethod should be attached to exactly 1 transition per DCWorkflow instance.') sdef = self._getWorkflowStateOf(ob) if sdef is None:
class CalendarTool(UniqueObject, SimpleItem): """ a calendar tool for encapsualting how calendars work and are displayed """ id = 'portal_calendar' meta_type = 'CMF Calendar Tool' security = ClassSecurityInfo() plone_tool = 1 manage_options = (( { 'label': 'Overview', 'action': 'manage_overview' }, { 'label': 'Configure', 'action': 'manage_configure' }, ) + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = PageTemplateFile('www/explainCalendarTool', globals(), __name__='manage_overview') security.declareProtected(ManagePortal, 'manage_configure') manage_configure = PageTemplateFile('www/configureCalendarTool', globals(), __name__='manage_configure') def __init__(self): self.calendar_types = ['Event'] self.use_session = "" security.declareProtected(ManagePortal, 'edit_configuration') def edit_configuration(self, show_types, use_session): """ Change the configuration of the calendar tool """ self.calendar_types = show_types self.use_session = use_session if hasattr(self.REQUEST, 'RESPONSE'): self.REQUEST.RESPONSE.redirect('manage_configure') security.declarePublic('getCalendarTypes') def getCalendarTypes(self): """ Returns a list of type that will show in the calendar """ return self.calendar_types security.declarePublic('getUseSession') def getUseSession(self): """ Returns the Use_Session option """ return self.use_session security.declarePublic('getDays') def getDays(self): """ Returns a list of days with the correct start day first """ return calendar.weekheader(2).split() security.declarePublic('getWeeksList') def getWeeksList(self, month='1', year='2002'): """Creates a series of weeks, each of which contains an integer day number. A day number of 0 means that day is in the previous or next month. """ # daysByWeek is a list of days inside a list of weeks, like so: # [[0, 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, 0, 0, 0]] daysByWeek = calendar.monthcalendar(year, month) return daysByWeek security.declarePublic('getEventsForCalendar') def getEventsForCalendar(self, month='1', year='2002'): """ recreates a sequence of weeks, by days each day is a mapping. {'day': #, 'url': None} """ year = int(year) month = int(month) # daysByWeek is a list of days inside a list of weeks, like so: # [[0, 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, 0, 0, 0]] daysByWeek = calendar.monthcalendar(year, month) weeks = [] events = self.catalog_getevents(year, month) for week in daysByWeek: days = [] for day in week: if events.has_key(day): days.append(events[day]) else: days.append({'day': day, 'event': 0, 'eventslist': []}) weeks.append(days) return weeks security.declarePublic('catalog_getevents') def catalog_getevents(self, year, month): """ given a year and month return a list of days that have events """ first_date = DateTime(str(month) + '/1/' + str(year)) last_day = calendar.monthrange(year, month)[1] ## This line was cropping the last day of the month out of the ## calendar when doing the query ## last_date=DateTime(str(month)+'/'+str(last_day)+'/'+str(year)) last_date = first_date + last_day query = self.portal_catalog(portal_type=self.calendar_types, review_state='published', start={ 'query': last_date, 'range': 'max' }, end={ 'query': first_date, 'range': 'min' }, sort_on='start') # compile a list of the days that have events eventDays = {} for daynumber in range(1, 32): # 1 to 31 eventDays[daynumber] = { 'eventslist': [], 'event': 0, 'day': daynumber } includedevents = [] for result in query: if result.getRID() in includedevents: break else: includedevents.append(result.getRID()) event = {} # we need to deal with events that end next month if result.end.month( ) != month: # doesn't work for events that last ~12 months - fix it if it's a problem, otherwise ignore eventEndDay = last_day event['end'] = None else: eventEndDay = result.end.day() event['end'] = result.end.Time() # and events that started last month if result.start.month( ) != month: # same as above re: 12 month thing eventStartDay = 1 event['start'] = None else: eventStartDay = result.start.day() event['start'] = result.start.Time() event['title'] = result.Title or result.id if eventStartDay != eventEndDay: allEventDays = range(eventStartDay, eventEndDay + 1) eventDays[eventStartDay]['eventslist'].append({ 'end': None, 'start': result.start.Time(), 'title': result.Title }) eventDays[eventStartDay]['event'] = 1 for eventday in allEventDays[1:-1]: eventDays[eventday]['eventslist'].append({ 'end': None, 'start': None, 'title': result.Title }) eventDays[eventday]['event'] = 1 eventDays[eventEndDay]['eventslist'].append({ 'end': result.end.Time(), 'start': None, 'title': result.Title }) eventDays[eventEndDay]['event'] = 1 else: eventDays[eventStartDay]['eventslist'].append(event) eventDays[eventStartDay]['event'] = 1 # This list is not uniqued and isn't sorted # uniquing and sorting only wastes time # and in this example we don't need to because # later we are going to do an 'if 2 in eventDays' # so the order is not important. # example: [23, 28, 29, 30, 31, 23] return eventDays security.declarePublic('getEventsForThisDay') def getEventsForThisDay(self, thisDay): """ given an exact day return ALL events that: A) Start on this day OR B) End on this day OR C) Start before this day AND end after this day""" catalog = self.portal_catalog first_date, last_date = self.getBeginAndEndTimes( thisDay.day(), thisDay.month(), thisDay.year()) #first_date=DateTime(thisDay.Date()+" 00:00:00") #last_date=DateTime(thisDay.Date()+" 23:59:59") # Get all events that Start on this day query = self.portal_catalog(portal_type=self.calendar_types, review_state='published', start={ 'query': (first_date, last_date), 'range': 'min:max' }) # Get all events that End on this day query += self.portal_catalog(portal_type=self.calendar_types, review_state='published', end={ 'query': (first_date, last_date), 'range': 'min:max' }) # Get all events that Start before this day AND End after this day query += self.portal_catalog(portal_type=self.calendar_types, review_state='published', start={ 'query': first_date, 'range': 'max' }, end={ 'query': last_date, 'range': 'min' }) # Unique the results results = [] rids = [] for item in query: rid = item.getRID() if not rid in rids: results.append(item) rids.append(rid) def sort_function(x, y): z = cmp(x.start, y.start) if not z: return cmp(x.end, y.end) return z # Sort by start date results.sort(sort_function) return results security.declarePublic('getPreviousMonth') def getPreviousMonth(self, month, year): # given any particular year and month, this method will return a datetime object # for one month prior try: month = int(month) except: raise "Calendar Type Error", month try: year = int(year) except: raise "Calendar Type Error", year if month == 0 or month == 1: month, year = 12, year - 1 else: month -= 1 return DateTime(str(month) + '/1/' + str(year)) security.declarePublic('getNextMonth') def getNextMonth(self, month, year): # given any particular year and month, this method will return a datetime object # for one month after try: month = int(month) except: raise "Calendar Type Error", month try: year = int(year) except: raise "Calendar Type Error", year if month == 12: month, year = 1, year + 1 else: month += 1 return DateTime(str(month) + '/1/' + str(year)) security.declarePublic('getBeginAndEndTimes') def getBeginAndEndTimes(self, day, month, year): # Given any day, month and year this method returns 2 DateTime objects # That represent the exact start and the exact end of that particular day. day = str(day) month = str(month) year = str(year) begin = DateTime(month + '/' + day + '/' + year + ' 12:00:00AM') end = DateTime(month + '/' + day + '/' + year + ' 11:59:59PM') return (begin, end)
""" Patches to resource registries """ from AccessControl import ClassSecurityInfo from Products.CMFCore.utils import getToolByName from Products.ResourceRegistries import permissions from zope.lifecycleevent import ObjectModifiedEvent from zope.event import notify security = ClassSecurityInfo() def invalidateClientsCache(self, REQUEST=None): """ Invalidate client cache """ notify(ObjectModifiedEvent(self)) if REQUEST: portal_url = getToolByName(self, 'portal_url')() return REQUEST.RESPONSE.redirect(portal_url + '/@@invalidateClientsCache') security.declareProtected(permissions.ManagePortal, 'manage_saveStylesheets') def manage_saveStylesheets(self, REQUEST=None): """ Save stylesheets from the ZMI. Updates the whole sequence. For editing and reordering. """ self._old_manage_saveStylesheets(REQUEST) invalidateClientsCache(self, REQUEST) security.declareProtected(permissions.ManagePortal, 'manage_saveScripts') def manage_saveScripts(self, REQUEST=None): """ Save scripts from the ZMI. Updates the whole sequence. For editing and reordering.
class ARAnalysesField(ObjectField): """A field that stores Analyses instances """ implements(IARAnalysesField) security = ClassSecurityInfo() _properties = Field._properties.copy() _properties.update({ "type": "analyses", "default": None, }) security.declarePrivate('get') def get(self, instance, **kwargs): """Returns a list of Analyses assigned to this AR Return a list of catalog brains unless `full_objects=True` is passed. Other keyword arguments are passed to bika_analysis_catalog :param instance: Analysis Request object :param kwargs: Keyword arguments to inject in the search query :returns: A list of Analysis Objects/Catalog Brains """ catalog = getToolByName(instance, CATALOG_ANALYSIS_LISTING) query = dict([(k, v) for k, v in kwargs.items() if k in catalog.indexes()]) query["portal_type"] = "Analysis" query["getRequestUID"] = api.get_uid(instance) analyses = catalog(query) if not kwargs.get("full_objects", False): return analyses return map(api.get_object, analyses) security.declarePrivate('set') def set(self, instance, items, prices=None, specs=None, hidden=None, **kw): """Set/Assign Analyses to this AR :param items: List of Analysis objects/brains, AnalysisService objects/brains and/or Analysis Service uids :type items: list :param prices: Mapping of AnalysisService UID -> price :type prices: dict :param specs: List of AnalysisService UID -> Result Range mappings :type specs: list :param hidden: List of AnalysisService UID -> Hidden mappings :type hidden: list :returns: list of new assigned Analyses """ # This setter returns a list of new set Analyses new_analyses = [] # Current assigned analyses analyses = instance.objectValues("Analysis") # Analyses which are in a non-open state must be retained, except those # that are in a registered state (the sample has not been received) non_open_analyses = filter(lambda an: not an.isOpen(), analyses) non_open_analyses = filter( lambda an: api.get_workflow_status_of(an) != "registered", non_open_analyses) # Prevent removing all analyses # # N.B.: Non-open analyses are rendered disabled in the HTML form. # Therefore, their UIDs are not included in the submitted UIDs. if not items and not non_open_analyses: logger.warn("Not allowed to remove all Analyses from AR.") return new_analyses # Bail out if the items is not a list type if not isinstance(items, (list, tuple)): raise TypeError( "Items parameter must be a tuple or list, got '{}'".format( type(items))) # Bail out if the AR is inactive if not api.is_active(instance): raise Unauthorized( "Inactive ARs can not be modified".format(AddAnalysis)) # Bail out if the user has not the right permission if not check_permission(AddAnalysis, instance): raise Unauthorized( "You do not have the '{}' permission".format(AddAnalysis)) # Convert the items to a valid list of AnalysisServices services = filter(None, map(self._to_service, items)) # Calculate dependencies # FIXME Infinite recursion error possible here, if the formula includes # the Keyword of the Service that includes the Calculation dependencies = map(lambda s: s.getServiceDependencies(), services) dependencies = list(itertools.chain.from_iterable(dependencies)) # Merge dependencies and services services = set(services + dependencies) # Modify existing AR specs with new form values of selected analyses. self._update_specs(instance, specs) # Create a mapping of Service UID -> Hidden status if hidden is None: hidden = [] hidden = dict(map(lambda d: (d.get("uid"), d.get("hidden")), hidden)) # Ensure we have a prices dictionary if prices is None: prices = dict() # CREATE/MODIFY ANALYSES for service in services: service_uid = api.get_uid(service) keyword = service.getKeyword() # Create the Analysis if it doesn't exist if shasattr(instance, keyword): analysis = instance._getOb(keyword) else: analysis = create_analysis(instance, service) new_analyses.append(analysis) # set the hidden status analysis.setHidden(hidden.get(service_uid, False)) # Set the price of the Analysis analysis.setPrice(prices.get(service_uid, service.getPrice())) # DELETE ANALYSES # Service UIDs service_uids = map(api.get_uid, services) # Analyses IDs to delete delete_ids = [] # Assigned Attachments assigned_attachments = [] for analysis in analyses: service_uid = analysis.getServiceUID() # Skip if the Service is selected if service_uid in service_uids: continue # Skip non-open Analyses if analysis in non_open_analyses: continue # Remember assigned attachments # https://github.com/senaite/senaite.core/issues/1025 assigned_attachments.extend(analysis.getAttachment()) analysis.setAttachment([]) # If it is assigned to a worksheet, unassign it before deletion. worksheet = analysis.getWorksheet() if worksheet: worksheet.removeAnalysis(analysis) delete_ids.append(analysis.getId()) if delete_ids: # Note: subscriber might promote the AR instance.manage_delObjects(ids=delete_ids) # Remove orphaned attachments for attachment in assigned_attachments: # only delete attachments which are no further linked if not attachment.getLinkedAnalyses(): logger.info("Deleting attachment: {}".format( attachment.getId())) attachment_id = api.get_id(attachment) api.get_parent(attachment).manage_delObjects(attachment_id) return new_analyses def _get_services(self, full_objects=False): """Fetch and return analysis service objects """ bsc = api.get_tool("bika_setup_catalog") brains = bsc(portal_type="AnalysisService") if full_objects: return map(api.get_object, brains) return brains def _to_service(self, thing): """Convert to Analysis Service :param thing: UID/Catalog Brain/Object/Something :returns: Analysis Service object or None """ # Convert UIDs to objects if api.is_uid(thing): thing = api.get_object_by_uid(thing, None) # Bail out if the thing is not a valid object if not api.is_object(thing): logger.warn("'{}' is not a valid object!".format(repr(thing))) return None # Ensure we have an object here and not a brain obj = api.get_object(thing) if IAnalysisService.providedBy(obj): return obj if IAnalysis.providedBy(obj): return obj.getAnalysisService() # An object, but neither an Analysis nor AnalysisService? # This should never happen. portal_type = api.get_portal_type(obj) logger.error("ARAnalysesField doesn't accept objects from {} type. " "The object will be dismissed.".format(portal_type)) return None def _update_specs(self, instance, specs): """Update AR specifications :param instance: Analysis Request :param specs: List of Specification Records """ if specs is None: return # N.B. we copy the records here, otherwise the spec will be written to # the attached specification of this AR rr = { item["keyword"]: item.copy() for item in instance.getResultsRange() } for spec in specs: keyword = spec.get("keyword") if keyword in rr: # overwrite the instance specification only, if the specific # analysis spec has min/max values set if all([spec.get("min"), spec.get("max")]): rr[keyword].update(spec) else: rr[keyword] = spec else: rr[keyword] = spec return instance.setResultsRange(rr.values())