class InterfaceData(object): """returns all properties data """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, object): self.object = object self.adapted = IMarkerInterfaces(self.object) security.declarePrivate('getData') def getData(self): """returns all important data""" return self.getInterfaceData() security.declarePrivate('getInterfaceData') def getInterfaceData(self): """ Returns a list of directlyProvided interfaces. Example Return: [ 'foo.bar.IDemoInterface', .... ] @return: list @rtype: list """ return self.adapted.getDirectlyProvidedNames() security.declarePrivate('setData') def setData(self, interfacedata, metadata): """ Sets a list of properties on a object. Warning: all currently set properties which are not in the properties-list wille be removed! @param object: Plone-Object to set the properties on @type object: Plone-Object @param properties: list of propertes. See ftw.publisher.sender.extractor for format details. @param type: list @return: None """ self.logger.info('Updating interface data (UID %s)' % (self.object.UID()) ) current_ifaces = set(self.adapted.getDirectlyProvidedNames()) desired_ifaces = set(interfacedata) for iface_dotted in current_ifaces - desired_ifaces: iface = resolve(iface_dotted) noLongerProvides(self.object, iface) for iface_dotted in desired_ifaces - current_ifaces: iface = resolve(iface_dotted) alsoProvides(self.object, iface)
class ShopItemVariations(object): """DataCollector adapter for Shop Item Variations. """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.object = obj security.declarePrivate('getData') def getData(self): variations_config = queryAdapter(self.object, IVariationConfig) if variations_config: data = deepcopy(variations_config.getVariationDict()) else: data = PersistentMapping() data = make_serializable(data) data = serialize_decimals(data) return data security.declarePrivate('setData') def setData(self, data, metadata): variations_config = queryAdapter(self.object, IVariationConfig) self.logger.info('Updating variations config (UID %s)' % (self.object.UID())) data = make_persistent(data) data = deserialize_decimals(data) if data in ({}, PersistentMapping()): variations_config.purge_dict() else: variations_config.updateVariationConfig(data)
class ShopCategorizableReferences(object): """DataCollector adapter for the category references of the categorizable shop types. """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.object = obj security.declarePrivate('getData') def getData(self): return [reference.UID() for reference in self.object.listCategories()] security.declarePrivate('setData') def setData(self, data, metadata): self.logger.info('Updating shop item category references (UID %s)' % (self.object.UID())) uid_catalog = getToolByName(self.object, 'uid_catalog') # Add categories available on source. for category_uid in data: brains = uid_catalog(UID=category_uid) if brains: self.object.addToCategory(brains[0].getObject()) # Remove categories no longer available on the source. existing_categories = [reference.UID() for reference in self.object.listCategories()] categories_to_be_removed = set(existing_categories) - set(data) for category in categories_to_be_removed: self.object.removeFromCategory(category)
class GeoData(object): """returns geo data """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.object = obj self.manager = queryAdapter(obj, IGeoManager) security.declarePrivate('getData') def getData(self): if self.manager: return self.manager.getCoordinates() else: return None security.declarePrivate('setData') def setData(self, geodata, metadata): self.logger.info('Updating geo data (UID %s)' % (self.object.UID())) if geodata == (None, None): self.manager.removeCoordinates() else: self.manager.setCoordinates(*geodata)
class CustomStyles(object): implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.obj = obj security.declarePrivate('getData') def getData(self): return ICustomStyles(self.obj).get_styles() security.declarePrivate('setData') def setData(self, themedata, metadata): ICustomStyles(self.obj).set_styles(themedata)
class ShopCategorizableRanks(object): """DataCollector adapter for the (category) ranks of the categorizable shop types. """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.object = obj security.declarePrivate('getData') def getData(self): return getattr(self.object, '_categoryRanks', PersistentMapping()) security.declarePrivate('setData') def setData(self, data, metadata): self.logger.info('Updating shop item ranks (UID %s)' % (self.object.UID())) self.object._categoryRanks = data
class BookLayoutRequestLayerCollector(object): """IDataCollector for supporting publishing books (ftw.publisher) with custom layouts and schema extender fields bound on layout request layer. When a custom layout is activated in the book, the request provides the layout interface as soon as traversing the book. The layout may add schema extender fields when the request provides the layout interface. In order to publish those field values correctly (with the standard FieldData collector), we need to provide the request layer before extracting data (sender) or setting data (receiver). Schema extender fields may be applied to not only the book itself but also to any content within the book. Therfore this collector should be used for all objects. The collector may be triggered when the book is traversed but also when it wasn't, therefore we cannot rely on the default book traversal adapter applying the layer interfaces to the request. """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, context): self.context = context security.declarePrivate('getData') def getData(self): book = self.get_parent_book() if not book: return None layers = [IWithinBookLayer] layout_layer_name = getattr(book, 'latex_layout', '') if layout_layer_name: layers.append(resolve(layout_layer_name)) self.provide_request_layers(layers) self.flush_schemaextender_cache() return map(dottedname, layers) security.declarePrivate('setData') def setData(self, layers_dottednames, metadata): if not layers_dottednames: return self.logger.info( 'BookLayoutRequestLayerCollector: provide request layers {0}'. format(layers_dottednames)) layers = map(resolve, layers_dottednames) self.provide_request_layers(layers) self.flush_schemaextender_cache() def get_parent_book(self): context = self.context while context and not ISiteRoot.providedBy(context): if IBook.providedBy(context): return context context = aq_parent(aq_inner(context)) return None def provide_request_layers(self, layers): """ Add a layer interface on the request """ request = self.context.REQUEST layers = [iface for iface in layers if not iface.providedBy(request)] ifaces = layers + list(directlyProvidedBy(request)) # Since we allow multiple markers here, we can't use # zope.publisher.browser.applySkin() since this filters out # IBrowserSkinType interfaces, nor can we use alsoProvides(), since # this appends the interface (in which case we end up *after* the # default Plone/CMF skin) directlyProvides(request, *ifaces) def flush_schemaextender_cache(self): """Flushes the schemaextender cache after conditions for schema extenders may have changed. """ try: delattr(self.context.REQUEST, CACHE_KEY) except AttributeError: pass
class TopicCriteraData(object): """returns all properties data """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, object): self.object = object security.declarePrivate('getData') def getData(self): """returns all important data""" return self.getTopicCriterias() security.declarePrivate('getTopicCriterias') def getTopicCriterias(self): """ extract data from topic criterions, like regular field adapter. but in a special way, because the topic criteras are no accessible by the catalog data = {'criteria_type':{field_data_adapter result}} """ criterias = {} # Use contentValues for implicit ftw.trash compatibility. for criteria in self.object.contentValues(): field_data_adapter = queryAdapter(criteria, IDataCollector, name="field_data_adapter") # this adapter must be available, otherwise we cannot go ahead if field_data_adapter is None: continue # dont add subcollections if isinstance(criteria, self.object.__class__): continue id = criteria.id data = field_data_adapter.getData() data['meta_type'] = criteria.meta_type criterias[id] = data return criterias security.declarePrivate('setData') def setData(self, topic_criteria_data, metadata): """ creates criterias fro a topic from {'criteria_type':{field_data_adapter result}} """ self.logger.info('Updating criterias for topic (UID %s)' % (self.object.UID())) # easiest way - first delete all criterias self.object.manage_delObjects([ i for i in self.object.objectIds() if i != 'syndication_information' ]) for criteria_id, data in topic_criteria_data.items(): # create criteria # sortCriteria behave a bit special if 'ATSortCriterion' not in criteria_id: criteria = self.object.addCriterion(data['field'], data['meta_type']) # add/change sort criteria if 'ATSortCriterion' in criteria_id: self.object.setSortCriterion(data['field'], data['reversed']) # we don't have to update data for for ATSortCriterion # check topic.py line 293 if 'ATSortCriterion' not in criteria_id: field_data_adapter = queryAdapter(criteria, IDataCollector, name="field_data_adapter") field_data_adapter.setData(data, metadata)
class Backreferences(object): """ Resets backreferences (pointing from another already released object to "me"). """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, obj): self.context = obj security.declarePrivate('getData') def getData(self): """ Returns backreferences: { 'uid-obj-a': { 'the-field': [ 'uid-of-another-unpublished-object', 'my-uid', 'uid-obj-b', ], }, 'uid-obj-b': { 'ref-field': 'my-uid', }, } """ data = {} if hasattr(aq_base(self.context), 'getBackReferenceImpl'): referenceable = self.context else: try: referenceable = IReferenceable(self.context) except TypeError: # could not adapt # this means we have a dexterity object without # plone.app.referenceablebehavior activated. return data old_security_manager = getSecurityManager() newSecurityManager(self.context.REQUEST, SpecialUsers.system) try: references = referenceable.getBackReferenceImpl() finally: setSecurityManager(old_security_manager) for ref in references: # get source object src = ref.getSourceObject() if src is None: continue suid = src.UID() if suid not in data.keys(): data[suid] = {} if getattr(ref, 'field', None) is None: continue if ref.field in data[suid]: # we already added this field continue else: # add the field value field = src.getField(ref.field) if field: data[suid][ref.field] = field.getRaw(src) return data security.declarePrivate('setData') def setData(self, data, metadata): self.logger.info('Updating backreferences (UID %s)' % metadata['UID']) cuid = self.context.UID() for suid, mapping in data.items(): sobj = uuidToObject(suid) if not sobj: # source object is not published continue self.logger.info('... source-obj: %s' % '/'.join( sobj.getPhysicalPath())) for fieldname, value in mapping.items(): # value maybe uid (str) or list of uids (list) if isinstance(value, str): value = [value] single = True else: single = False new_value = [] # only set the targets that exist (=may be published) for tuid in value: if tuid == cuid: new_value.append(self.context) else: tobj = reference_catalog.lookupObject(tuid) if tuid: new_value.append(tobj) # set the new value on the field field = sobj.getField(fieldname) if single and new_value: field.set(sobj, new_value[0]) elif single: field.set(sobj, None) else: field.set(sobj, new_value)
class PropertiesData(object): """returns all properties data """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, object): self.object = object security.declarePrivate('getData') def getData(self): """returns all important data""" return self.getPropertyData() security.declarePrivate('getPropertyData') def getPropertyData(self): """ Returns a list of dictonaries each representing a property. Example Return: [ { 'type' : 'string', 'id' : 'title', 'value' : 'test1', 'mode' : 'wd', }, { 'type' : 'text', 'id' : 'blubb', 'value' : 'asdfsadf asdf', }, ] @return: list of properties @rtype: list """ properties = [] for prop in self.object._propertyMap(): # create a copy (we dont want to change the effective property) prop = prop.copy() # add the value if IPloneSiteRoot.providedBy( self.object) and prop['id'] != 'layout': continue prop['value'] = self.object.getProperty(prop['id']) properties.append(prop) # property filter for special types # ex. date - we have to covert objects to strings for p in properties: if p['type'] == 'date': p['value'] = str(p['value']) return properties security.declarePrivate('setData') def setData(self, properties, metadata): """ Sets a list of properties on a object. Warning: all currently set properties which are not in the properties-list wille be removed! @param object: Plone-Object to set the properties on @type object: Plone-Object @param properties: list of propertes. See ftw.publisher.sender.extractor for format details. @param type: list @return: None """ # plone root implementation root_path = '/'.join(self.object.getPhysicalPath()) uid = hasattr(self.object, 'UID') and self.object.UID() or root_path self.logger.info('Updating properties (UID %s)' % (uid)) # we need to cleanup the properties. remove all properties # from the object propertiesToUpdateOrCreate = [p['id'] for p in properties] currentProperties = self.object.propertyIds() # delete old properties propertiesToDelete = [ id for id in currentProperties if id not in propertiesToUpdateOrCreate ] if not IPloneSiteRoot.providedBy(self.object): self.object.manage_delProperties(propertiesToDelete) elif 'layout' in currentProperties: # Delete layout property anyway - this supports removing the prop. self.object.manage_delProperties([ 'layout', ]) # get cleaned up list of properties currentProperties = self.object.propertyIds() # update or create properites for prop in properties: # we have to check for some special prop types if prop['type'] == 'date': val = DateTime(prop['value']) else: val = prop['value'] if prop['id'] in currentProperties: # update property if existing ... try: self.object._updateProperty(id=prop['id'], value=val) except AttributeError: self.logger.info( 'Could not set property "{0}" on {1}'.format( prop['id'], uid)) else: # ... otherwise self.object.manage_addProperty(id=prop['id'], value=val, type=prop['type'])
class PortletsData(object): """for plone's defautl portlet data, left and right area """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, object): self.object = object security.declarePrivate('getData') def getData(self): """returns all important data data form {'column': {portlet: {key:value} } . . . . {'blackliststatus': {category:True}, {'order': ['portlet 1', 'portlet 2']} } } """ data = {} plone_portlet_manager = [] # gets all portlet managers used on this object annotations = getattr(self.object, '__annotations__', None) if not annotations: return data has_portlets = 'plone.portlets.contextassignments' in annotations has_blacklist = 'plone.portlets.categoryblackliststatus' in annotations if not has_portlets and not has_blacklist: return data if has_portlets: plone_portlet_manager += self.object.__annotations__[ 'plone.portlets.contextassignments'].keys() if has_blacklist: plone_portlet_manager += self.object.__annotations__[ 'plone.portlets.categoryblackliststatus'].keys() EXCLUDED_FIELDS = ['__name__', '__parent__'] # XXX this is a static list, replace by a configlet option # the list contains all not serializable portlets (__module__) blacklisted_portlets = [ 'collective.dancing.browser.portlets.channelsubscribe' ] for manager_name in plone_portlet_manager: column = queryUtility(IPortletManager, name=manager_name, context=self.object) if column is None: continue # ok we have a portlet manager data[manager_name] = {} # get blackliststatus blacklist = getMultiAdapter((self.object, column), ILocalPortletAssignmentManager) data[manager_name]['blackliststatus'] = {} blacklistdata = data[manager_name]['blackliststatus'] blacklistdata[GROUP_CATEGORY] = blacklist.getBlacklistStatus( GROUP_CATEGORY) blacklistdata[USER_CATEGORY] = blacklist.getBlacklistStatus( USER_CATEGORY) blacklistdata[CONTENT_TYPE_CATEGORY] = \ blacklist.getBlacklistStatus(CONTENT_TYPE_CATEGORY) blacklistdata[CONTEXT_CATEGORY] = \ blacklist.getBlacklistStatus(CONTEXT_CATEGORY) portlets = getMultiAdapter(( self.object, column, ), IPortletAssignmentMapping, context=self.object) # portlets order - dicts are unsorted data[manager_name]['order'] = ','.join(portlets._order) for portlet_id in portlets.keys(): portlet_assignment = portlets[portlet_id] # continue if portlet is blacklisted if portlet_assignment.__module__ in blacklisted_portlets: continue # we habe a portlet data[manager_name][portlet_assignment.__name__] = {} data[manager_name][portlet_assignment.__name__]['module'] = \ portlet_assignment.__class__.__module__ data[manager_name][portlet_assignment.__name__]['assignment_class_name'] = \ portlet_assignment.__class__.__name__ # portlet settings (visibility) settings = IPortletAssignmentSettings(portlet_assignment).data data[manager_name][ portlet_assignment.__name__]['settings'] = settings # get all data for field in portlet_assignment.__dict__.keys(): if field not in EXCLUDED_FIELDS: field_value = getattr(portlet_assignment, field, '') # image field - image.portlet integration if isinstance(field_value, OFSImage): # same way as in AT field serializer field_value = { 'module': OFSImage.__module__, 'klass_name': OFSImage.__name__, 'kwargs': { 'file': base64.encodestring(field_value.data), 'id': field_value.id(), 'title': field_value.title } } elif (HAS_NAMEDFILE and INamedFile.providedBy(field_value)): klass = type(field_value) field_value = { 'module': klass.__module__, 'klass_name': klass.__name__, 'kwargs': { 'data': base64.encodestring(field_value.data), 'filename': field_value.filename, 'contentType': field_value.contentType } } data[manager_name][ portlet_assignment.__name__][field] = field_value return data security.declarePrivate('setData') def setData(self, portletsdata, metadata): """create or updates portlet informations """ for manager_name in portletsdata.keys(): column = queryUtility(IPortletManager, name=manager_name, context=self.object) if column is None: continue # ok we have a portlet manager # get all current assigned portlets portlets = getMultiAdapter(( self.object, column, ), IPortletAssignmentMapping, context=self.object) p_ids = [p for p in portlets._data.keys()] # get new order order = portletsdata[manager_name]['order'] and \ portletsdata[manager_name]['order'].split(',') or [] # set blackliststatus blacklist = getMultiAdapter((self.object, column), ILocalPortletAssignmentManager) blacklistdata = portletsdata[manager_name]['blackliststatus'] blacklist.setBlacklistStatus(GROUP_CATEGORY, blacklistdata[GROUP_CATEGORY]) blacklist.setBlacklistStatus(USER_CATEGORY, blacklistdata[USER_CATEGORY]) blacklist.setBlacklistStatus(CONTENT_TYPE_CATEGORY, blacklistdata[CONTENT_TYPE_CATEGORY]) blacklist.setBlacklistStatus(CONTEXT_CATEGORY, blacklistdata[CONTEXT_CATEGORY]) # bit clean up del portletsdata[manager_name]['blackliststatus'] del portletsdata[manager_name]['order'] # remove all currenlty assigned portlets from manager for p_id in p_ids: del portlets._data[p_id] for portlet_id in portletsdata[manager_name].keys(): portletfielddata = portletsdata[manager_name][portlet_id] # get Assignment portlet_module = modules[portletfielddata['module']] portlet_class = getattr( portlet_module, portletfielddata['assignment_class_name']) settings = portletfielddata.get('settings', None) # prepare data to pass as arguments del portletfielddata['module'] del portletfielddata['assignment_class_name'] del portletfielddata['settings'] annotations = portletfielddata.get('__annotations__', None) if '__annotations__' in portletfielddata: del portletfielddata['__annotations__'] # check for dicts for k, v in portletfielddata.items(): if isinstance(v, dict): # so we have one, now we have to turn the # serialized data into an object # this is generic, but currently only in use # by the image portlet klass = modules[v['module']].__dict__[v['klass_name']] for argname in ('file', 'data'): if argname in v['kwargs']: v['kwargs'][argname] = base64.decodestring( v['kwargs'][argname]) imgobj = klass(**v['kwargs']) portletfielddata[k] = imgobj portlets[portlet_id] = portlet_class(**portletfielddata) # XXX boolean value fix # for some reason boolean types cannpt be passed with **... # use setattr for k, v in portletfielddata.items(): if isinstance(v, bool): setattr(portlets[portlet_id], k, v) if annotations: portlets[portlet_id].__annotations__ = annotations # portlet settings (visibility) portlet_assignment = portlets[portlet_id] IPortletAssignmentSettings(portlet_assignment).data = settings # set new order afterwards portlets._order = PersistentList(order)
class FieldData(object): """returns all field data """ implements(IDataCollector) logger = getLogger() security = ClassSecurityInformation() def __init__(self, object): self.object = object security.declarePrivate('getData') def getData(self): """returns all important data""" return self.getFieldData() security.declarePrivate('getFieldData') def getFieldData(self): """ Extracts data from the object fields and creates / returns a dictionary with the data. Objects are converted to string. @return: dictionary with extracetd data @rtype: dict """ data = {} fields = self.object.Schema().fields() for field in fields: # don't serialize AT ComputedFields if isinstance(field, ComputedField): continue name = field.getName() value = field.getRaw(self.object) value = self.fieldSerialization(field, value) data[name] = value return data security.declarePrivate('fieldSerialization') def fieldSerialization(self, field, value): """ Custom serialization for fields which provide field values that are incompatible with json / JSON-standard. @param field: Field-Object from Schema @type field: Field @param value: Return-Value of the Raw-Accessor of the Field on the current context @type value: string or stream @return: JSON-optimized value @rtype: string """ if isinstance(field, DateTimeField) and value: value = str(value) elif HAS_BLOBS and IBlobWrapper.providedBy(value): file_ = value.getBlob().open() value = { 'filename': value.getFilename(), 'data': base64.encodestring(file_.read()), 'type': 'blob' } file_.close() elif isinstance(field, FileField) and isinstance(value, File): tmp = StringIO.StringIO(value.data) tmp.seek(0) value = { 'filename': value.filename, 'data': base64.encodestring(tmp.read()) } elif isinstance(field, QueryField): query = field.getRaw(self.object) # Cast "ZPublisher.HTTPRequest.record" instance to dict value = [dict(item) for item in query] return value security.declarePrivate('setData') def setData(self, fielddata, metadata): """sets all important field data """ # update with new values self.logger.info('Updating object values (UID %s)' % metadata['UID']) fields = self.object.Schema().fields() for field in fields: fieldname = field.getName() # do not update "id" field if fieldname == 'id': continue if fieldname in fielddata.keys(): field_value = fielddata[fieldname] if field.mode == 'r': continue field.getMutator(self.object)(field_value)