def __str__(self): url = super(TransientTileAbsoluteURL, self).__str__() manager = ITileDataManager(self.context) # Transient looking tile with id is only really transient # if it caches its decoded query data in request annotations transient = manager.storage == IAnnotations(self.request) # When transient looking tile with id is not really transient, # its data should not be encoded into query string if self.context.id and not transient: return url # All tiles don't need / have configuration data at all. data = manager.get() if not data: return url # But when configuration data is really read from query string # and not persisted, it should also be kept in query string tileType = queryUtility(ITileType, name=self.context.__name__) if tileType is not None and tileType.schema is not None: if '?' in url: url += '&' + encode(data, tileType.schema) else: url += '?' + encode(data, tileType.schema) return url
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse('@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) # We need to check first for existing content in order to not loose # fields that weren't sent with the form. old_data = dataManager.get() for item in data: if data[item] is not None: old_data[item] = data[item] dataManager.set(old_data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) notify(ObjectModifiedEvent(tile)) # Get the tile URL, possibly with encoded data IStatusMessage(self.request).addStatusMessage(_(u"Tile saved",), type=u'info') self.request.response.redirect(tileURL)
def results(self): """Return the list of objects stored in the tile as UUID. If an UUID has no object associated with it, removes the UUID from the list. :returns: a list of objects. """ self.set_limit() # always get the latest data uuids = ITileDataManager(self).get().get('uuids', None) results = list() if uuids: ordered_uuids = [(k, v) for k, v in uuids.items()] ordered_uuids.sort(key=lambda x: x[1]['order']) for uuid in [i[0] for i in ordered_uuids]: obj = uuidToObject(uuid) if obj: results.append(obj) else: # maybe the user has no permission to access the object # so we try to get it bypassing the restrictions catalog = api.portal.get_tool('portal_catalog') brain = catalog.unrestrictedSearchResults(UID=uuid) if not brain: # the object was deleted; remove it from the tile self.remove_item(uuid) logger.debug( 'Nonexistent object {0} removed from ' 'tile'.format(uuid) ) return results[:self.limit]
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) # initialize the tile with all fields needed for its rendering # note that we include here 'date' and 'subjects', but we do not # really care about their value: they came directly from the catalog # brain data = { 'title': safe_unicode(obj.Title()), 'description': safe_unicode(obj.Description()), 'uuid': IUUID(obj), 'date': True, 'subjects': True, 'image': self.get_image_data(obj) } if data['image']: # clear scales if new image is getting saved self.clear_scales() data_mgr = ITileDataManager(self) data_mgr.set(data) msg = 'tile "{0}"" populated with data: {1}' logger.debug(msg.format(self.id, data))
def test_basic_tile_purge_cache(self): provideHandler(queuePurge) request = self.request alsoProvides(request, IAttributeAnnotatable) setRequest(request) registry = queryUtility(IRegistry) registry.registerInterface(ICachePurgingSettings) provideUtility(registry, IRegistry) settings = registry.forInterface(ICachePurgingSettings) settings.enabled = True settings.cachingProxies = ('http://*****:*****@@collective.cover.basic/test', '/c1/@@collective.cover.basic/test/@@images/image', '/c1/@@collective.cover.basic/test/@@images/icon', '/c1/@@collective.cover.basic/test/@@images/mini', '/c1/@@collective.cover.basic/test/@@images/large', '/c1/@@collective.cover.basic/test/@@images/listing', '/c1/@@collective.cover.basic/test/@@images/thumb', '/c1/@@collective.cover.basic/test/@@images/preview', '/c1/@@collective.cover.basic/test/@@images/tile']), IAnnotations(request)['plone.cachepurging.urls'])
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse( '@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) dataManager.set(data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) notify(ObjectModifiedEvent(tile)) logger.debug(u"Tile edited at {0}".format(tileURL)) try: url = self.nextURL(tile) except NotImplementedError: url = tileURL self.request.response.redirect(url)
def populate_with_object(self, obj): """ Fará o set do uuid do objeto recebido por drag drop """ super(ListFolderContentsTile, self).populate_with_object(obj) uuid = IUUID(obj, None) data_mgr = ITileDataManager(self) data_mgr.set({'uuid': uuid})
def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ generator = getUtility(IUUIDGenerator) tileId = generator() # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse( '@@%s/%s' % (typeName, tileId,)) dataManager = ITileDataManager(tile) new_data = {} form.applyChanges(self, new_data, data) dataManager.set(new_data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) notify(ObjectCreatedEvent(tile)) notify(ObjectAddedEvent(tile, self.context, tileId)) logger.debug(u"Tile created at {0}".format(tileURL)) try: url = self.nextURL(tile) except NotImplementedError: url = tileURL self.request.response.redirect(url)
def test_fix_image_field_modification_time(self): from persistent.dict import PersistentDict title = u'Fix image field modification time' step = self._get_upgrade_step(title) assert step is not None # simulate state on previous version cover = self._create_cover('test-cover', 'Empty layout') cover.cover_layout = ( '[{"type": "row", "children": [{"column-size": 16, "type": ' '"group", "children": [{"tile-type": ' '"collective.cover.basic", "type": "tile", "id": ' '"ca6ba6675ef145e4a569c5e410af7511"}], "roles": ["Manager"]}]}]' ) tile = cover.get_tile('ca6ba6675ef145e4a569c5e410af7511') obj = self.portal['my-image'] tile.populate_with_object(obj) dmgr = ITileDataManager(tile) old_data = dmgr.get() old_data['image_mtime'] = repr(old_data['image_mtime']) dmgr.annotations[dmgr.key] = PersistentDict(old_data) data = dmgr.get() assert isinstance(data['image_mtime'], str) # run the upgrade step to validate the update self._do_upgrade_step(step) data = dmgr.get() self.assertIsInstance(data['image_mtime'], float)
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse('@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) dataManager.set(data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) tileRelativeURL = tileURL if tileURL.startswith(contextURL): tileRelativeURL = '.' + tileURL[len(contextURL):] notify(ObjectModifiedEvent(tile)) # Get the tile URL, possibly with encoded data IStatusMessage(self.request).addStatusMessage(_(u"Tile saved",), type=u'info') self.request.response.redirect(tileURL)
def populate_with_object(self, obj): super(ContentBodyTile, self).populate_with_object(obj) data = {"uuid": IUUID(obj)} data_mgr = ITileDataManager(self) data_mgr.set(data)
def populate_with_object(self, obj): # XXX: Pode ser removido? # super(NoticiasHomeTile, self).populate_with_object(obj) if obj.portal_type in self.accepted_ct(): uuid = IUUID(obj, None) data_mgr = ITileDataManager(self) data_mgr.set({'uuid': uuid})
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) title = safe_unicode(obj.Title()) description = safe_unicode(obj.Description()) image = self.get_image_data(obj) if image: # clear scales if new image is getting saved self.clear_scales() # initialize the tile with all fields needed for its rendering # note that we include here 'date' and 'subjects', but we do not # really care about their value: they came directly from the catalog # brain data = { 'title': title, 'description': description, 'uuid': IUUID(obj), 'date': True, 'subjects': True, 'image': image, # FIXME: https://github.com/collective/collective.cover/issues/778 'alt_text': description or title, } data_mgr = ITileDataManager(self) data_mgr.set(data) msg = 'tile "{0}"" populated with data: {1}' logger.debug(msg.format(self.id, data))
def test_crud(self): self.assertTrue(self.tile.is_empty()) obj = self.portal['my-image'] obj2 = self.portal['my-image1'] obj3 = self.portal['my-image2'] self.tile.populate_with_object(obj) self.tile.populate_with_object(obj2) self.tile.populate_with_object(obj3) self.tile = self.portal.restrictedTraverse( '@@{0}/{1}'.format('brasil.gov.tiles.photogallery', 'test-tile')) self.assertEqual(len(self.tile.results()), 3) self.assertIn(obj, self.tile.results()) self.assertIn(obj2, self.tile.results()) self.assertIn(obj3, self.tile.results()) data = self.tile.data data['tile_title'] = 'My title' data_mgr = ITileDataManager(self.tile) data_mgr.set(data) self.tile = self.portal.restrictedTraverse( '@@{0}/{1}'.format('brasil.gov.tiles.photogallery', 'test-tile')) self.assertEqual(self.tile.tile_title, 'My title')
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return # Traverse to a new tile in the context, with no data typeName = self.tileType.__name__ tile = self.context.restrictedTraverse('@@{0}/{1}'.format(typeName, self.tileId)) # We need to check first for existing content in order not not loose # fields that weren't sent with the form dataManager = ITileDataManager(tile) old_data = dataManager.get() for item in data: old_data[item] = data[item] dataManager.set(old_data) # notify about modification notify(ObjectModifiedEvent(tile)) api.portal.show_message(_(u'Tile saved'), self.request, type='info') # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) self.request.response.redirect(tileURL)
def populate_with_object(self, obj): super(AudioTile, self).populate_with_object(obj) # check permissions if obj.portal_type in self.accepted_ct(): title = obj.Title() description = obj.Description() rights = obj.Rights() mp3 = obj.return_mp3() if mp3: url = mp3.absolute_url() content_type = "audio/mp3" else: url = obj.absolute_url() content_type = "" uuid = IUUID(obj) data_mgr = ITileDataManager(self) data_mgr.set( { "title": title, "description": description, "url": url, "credit": rights, "uuid": uuid, "content_type": content_type, } )
def populate_with_object(self, obj): # check permissions super(ImageTile, self).populate_with_object(obj) data_mgr = ITileDataManager(self) data_mgr.set({'image': NamedBlobImage(obj.getImage().data)})
def populate_with_object(self, obj): super(SectionNavTile, self).populate_with_object(obj) # check permission if obj.portal_type in self.accepted_ct(): data_mgr = ITileDataManager(self) data_mgr.set({'uuid': IUUID(obj)})
def populate_with_object(self, obj): super(PhotoGalleryTile, self).populate_with_object(obj) # check permissions if obj.portal_type in self.accepted_ct(): uuid = IUUID(obj) data_mgr = ITileDataManager(self) data_mgr.set(dict(uuid=uuid))
def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse( '@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) content = {} applyChanges(self, content, data) dataManager.set(content) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) notify(ObjectCreatedEvent(tile)) notify(ObjectAddedEvent(tile, self.context, self.tileId)) IStatusMessage(self.request).addStatusMessage( _(u"Tile created at ${url}", mapping={'url': tileURL}), type=u'info', ) self.request.response.redirect(contextURL)
def test_render_text(self): text = u'Achievement Unlocked: a11y' data_mgr = ITileDataManager(self.tile) data_mgr.set({'title': text}) self.tile = self.portal.restrictedTraverse( '@@{0}/{1}'.format(self.name, 'test')) self.assertIn(text, self.tile())
def populate_with_object(self, obj): """Tile can be populated with images and links; in this case we're not going to take care of any modification of the original object; we just copy the data to the tile and deal with it. """ if obj.portal_type not in self.accepted_ct(): return super(BannerTile, self).populate_with_object(obj) # check permissions obj = aq_base(obj) # avoid acquisition title = obj.Title() rights = obj.Rights() if hasattr(obj, 'Rights') else None # if image, store a copy of its data if obj.portal_type == 'Image': if hasattr(obj, 'getImage'): data = obj.getImage().data else: data = obj.image.data image = NamedBlobImage(data) else: image = None image_description = obj.Description() or obj.Title() remote_url = obj.getRemoteUrl() if obj.portal_type == 'Link' else None data_mgr = ITileDataManager(self) data_mgr.set({ 'title': title, 'image': image, 'image_description': image_description, 'remote_url': remote_url, 'rights': rights, })
def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ context = self.context # Look up if our context supports tiles, if not # pick default view instead if not ILayoutAware(context, None): default_page_view = getMultiAdapter((context, self.request), name='default_page') default_page = default_page_view.getDefaultPage() context = default_page and context[default_page] or context context = ILayoutAware(context, None) # Traverse to a new tile in the context, with no data tile = context.restrictedTraverse( '@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) dataManager.set(data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) tileRelativeURL = tileURL if tileURL.startswith(contextURL): tileRelativeURL = '.' + tileURL[len(contextURL):] notify(ObjectCreatedEvent(tile)) notify(ObjectAddedEvent(tile, self.context, self.tileId)) IStatusMessage(self.request).addStatusMessage( _(u"Tile created at ${url}", mapping={'url': tileURL}), type=u'info', ) # Calculate the edit URL and append some data in a JSON structure, # to help the UI know what to do. url = getEditTileURL(tile, self.request) tileDataJson = {} tileDataJson['action'] = "save" tileDataJson['mode'] = "add" tileDataJson['url'] = tileRelativeURL tileDataJson['tile_type'] = typeName tileDataJson['id'] = tile.id url = appendJSONData(url, 'tiledata', tileDataJson) self.request.response.redirect(url)
def storage(self): tile = self.context manager = ITileDataManager(tile) data = manager.get() if IMAGESCALES_KEY not in data: data[IMAGESCALES_KEY] = PersistentDict() manager.set(data) return data[IMAGESCALES_KEY]
def remove_item(self, uid): super(ListTile, self).remove_item(uid) data_mgr = ITileDataManager(self) uids = data_mgr.get()['uuids'] if uid in uids: del uids[uids.index(uid)] data_mgr.set({'uuids': uids})
def populate_with_object(self, obj): super(CollectionTile, self).populate_with_object(obj) # check permission if obj.portal_type in self.accepted_ct(): header = safe_unicode(obj.Title()) # use collection's title as header footer = _(u"More…") # XXX: can we use field's default? data_mgr = ITileDataManager(self) data_mgr.set({"header": header, "footer": footer, "uuid": IUUID(obj)})
def remove_item(self, uid): super(ListTile, self).remove_item(uid) data_mgr = ITileDataManager(self) old_data = data_mgr.get() uids = data_mgr.get()['uuids'] if uid in uids: del uids[uids.index(uid)] old_data['uuids'] = uids data_mgr.set(old_data)
def populate_with_object(self, obj): super(ContentBodyTile, self).populate_with_object(obj) data = { 'uuid': IUUID(obj, None), # XXX: can we get None here? see below } data_mgr = ITileDataManager(self) data_mgr.set(data)
def replace_with_objects(self, objs): super(ListTile, self).replace_with_objects(objs) data_mgr = ITileDataManager(self) if type(objs) == list: objs = objs[:self.limit] else: objs = [objs] data_mgr.set({'uuids': objs})
def populate_with_object(self, obj): super(LinkTile, self).populate_with_object(obj) # check permissions title = obj.Title() description = obj.Description() remote_url = obj.getRemoteUrl() uuid = IUUID(obj, None) data_mgr = ITileDataManager(self) data_mgr.set({"title": title, "description": description, "remote_url": remote_url, "uuid": uuid})
def __call__(self): template = self.template if 'form.submitted' not in self.request: return template.render(self) annotations = IAnnotations(self.context) current_tiles = annotations.get('current_tiles', {}) tile_id = self.request.get('wid', None) if tile_id in current_tiles: widget_type = current_tiles[tile_id]['type'] #Let's remove all traces of the value stored in the tile widget_uri = '@@%s/%s' % ( widget_type, tile_id, ) tile = self.context.restrictedTraverse(widget_uri) dataManager = ITileDataManager(tile) dataManager.delete()
def populate_with_object(self, obj): # check permissions super(ImageTile, self).populate_with_object(obj) data = {} obj = aq_inner(obj) try: scales = queryMultiAdapter((obj, self.request), name="images") data['image'] = NamedImageFile(str(scales.scale('image').data)) except AttributeError: pass data_mgr = ITileDataManager(self) data_mgr.set(data) tile_storage = AnnotationStorage(self) obj_storage = BaseAnnotationStorage(obj) for k, v in obj_storage.items(): tile_storage.storage[k] = v tile_storage.storage[k]['modified'] = '%f' % time.time() scale_data = obj_storage.storage[k]['data'].open().read() tile_storage.storage[k]['data'] = NamedImageFile(str(scale_data))
def transmogrify(self, item): if item['_type'] == 'collective.cover.content': path = item['_path'] if path.startswith('/'): path = path[1:] cover = self.context.restrictedTraverse(str(path)) tiles = item['tile_data'] for tile_id, tile_info in tiles.items(): tile_data = tile_info['data'] tile_config = tile_info['config'] tile = cover.restrictedTraverse(str(tile_id)) tile.set_tile_configuration(tile_config) if tile_data.get('image', None): value = base64.b64decode(tile_data['image']['data']) filename = tile_data['image']['filename'] wrapped_data = NamedBlobImage(data=value, filename=filename) tile_data['image'] = wrapped_data data_mgr = ITileDataManager(tile) data_mgr.set(tile_data)
def __str__(self): url = super(TransientTileAbsoluteURL, self).__str__() data = ITileDataManager(self.context).get() if data: tileType = queryUtility(ITileType, name=self.context.__name__) if tileType is not None and tileType.schema is not None: if '?' in url: url += '&' + encode(data, tileType.schema) else: url += '?' + encode(data, tileType.schema) return url
def get_description(self, item): """Get the description of the item, or the custom description if set. :param item: [required] The item for which we want the description :type item: Content object :returns: the item description :rtype: unicode """ # First we get the url for the item itself description = item.Description() uuid = self.get_uuid(item) data_mgr = ITileDataManager(self) data = data_mgr.get() uuids = data['uuids'] if uuid in uuids: if uuids[uuid].get('custom_description', u''): # If we had a custom description set, then get that description = uuids[uuid].get('custom_description') return description
def delete(self): """ Remove the persistent data associated with the tile and notify the cover object was modified. """ logger.debug("Deleting tile {0}".format(self.id)) data_mgr = ITileDataManager(self) data_mgr.delete() # Remove permission data permissions = getMultiAdapter((self.context, self.request, self), ITilesPermissions) permissions.delete() # Remove configuration data configuration = getMultiAdapter((self.context, self.request, self), ITilesConfigurationScreen) configuration.delete() notify(ObjectModifiedEvent(self.context))
def upgrade_carousel_tiles_custom_url(context): """Update structure of tiles inheriting from the list tile.""" # Get covers covers = context.portal_catalog(portal_type='collective.cover.content') logger.info('About to update {0} objects'.format(len(covers))) tiles_to_update = _get_tiles_inherit_from_list(context) logger.info('{0} tile types will be updated ({1})'.format( len(tiles_to_update), ', '.join(tiles_to_update))) for cover in covers: obj = cover.getObject() tile_ids = obj.list_tiles(types=tiles_to_update) for tile_id in tile_ids: tile = obj.get_tile(tile_id) old_data = ITileDataManager(tile).get() uuids = old_data['uuids'] if isinstance(uuids, dict): # This tile is fixed, carry on logger.info('Tile %s at %s was already updated' % (tile_id, cover.getPath())) continue if not uuids: # This tile did not have data, so ignore logger.info('Tile %s at %s did not have any data' % (tile_id, cover.getPath())) continue new_data = dict() order = 0 for uuid in uuids: if uuid not in new_data.keys(): entry = dict() entry[u'order'] = unicode(order) new_data[uuid] = entry order += 1 old_data['uuids'] = new_data ITileDataManager(tile).set(old_data) logger.info('Tile %s at %s updated' % (tile_id, cover.getPath())) logger.info('Done')
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) # initialize the tile with all fields needed for its rendering # note that we include here 'date' and 'subjects', but we do not # really care about their value: they came directly from the catalog # brain data = { 'title': safe_unicode(obj.Title()), 'description': safe_unicode(obj.Description()), 'uuid': IUUID(obj, None), # XXX: can we get None here? see below 'date': True, 'subjects': True, } # TODO: if a Dexterity object does not have the IReferenceable # behaviour enable then it will not work here # we need to figure out how to enforce the use of # plone.app.referenceablebehavior data_mgr = ITileDataManager(self) data_mgr.set(data)
def get_url(self, item): """Get the URL of the item, or the custom URL if set. :param item: [required] The item for which we want the URL :type item: Content object :returns: the item URL :rtype: str """ # First we get the url for the item itself url = item.absolute_url() if item.portal_type in get_types_use_view_action_in_listings(): url += '/view' uuid = self.get_uuid(item) data_mgr = ITileDataManager(self) data = data_mgr.get() uuids = data['uuids'] if uuid in uuids: if uuids[uuid].get('custom_url', u''): # If we had a custom url set, then get that url = uuids[uuid].get('custom_url') return url
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) if INITF.providedBy(obj): image = obj.image() data = dict( title=obj.title, description=obj.description, subtitle=obj.subtitle, section=obj.section, uuid=IUUID(obj), date=True, subjects=True, image=self.get_image_data(image), media_producer=obj.media_producer(), ) # clear scales as new image is getting saved self.clear_scales() data_mgr = ITileDataManager(self) data_mgr.set(data)
def make_iframe_embed_tile(cover, url): id = getUtility(IUUIDGenerator)() type_name = 'collective.cover.embed' tile = cover.restrictedTraverse('@@%s/%s' % (type_name, id)) embed = """<iframe class='ace-iframe' frameborder='0' style='min-width:700px;min-height:800px' width='100%%' src='%s'></iframe>""" % url ITileDataManager(tile).set({'title': '', 'embed': embed}) return {'tile-type': 'collective.cover.embed', 'type': 'tile', 'id': id}
def populate_with_object(self, obj): """Tile can be populated with any content type with image or getImage attribute; in this case we're not going to take care of any modification of the original object; we just copy the data to the tile and deal with it. """ if obj.portal_type not in self.accepted_ct(): return super(BannerTile, self).populate_with_object(obj) # check permissions if obj.portal_type == 'Link': try: remote_url = obj.getRemoteUrl() # Archetypes except AttributeError: remote_url = obj.remoteUrl # Dexterity else: remote_url = obj.absolute_url() if obj.portal_type in get_types_use_view_action_in_listings(): remote_url += '/view' image = self.get_image_data(obj) if image: # clear scales if new image is getting saved self.clear_scales() obj = aq_base(obj) # avoid acquisition title = safe_unicode(obj.Title()) description = safe_unicode(obj.Description()) data_mgr = ITileDataManager(self) data_mgr.set({ 'title': title, 'description': description, 'uuid': IUUID(obj), 'image': image, # FIXME: https://github.com/scmos.scmos.cover/issues/778 'alt_text': description or title, 'remote_url': remote_url, })
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse('@@%s/%s' % ( typeName, self.tileId, )) dataManager = ITileDataManager(tile) # We need to check first for existing content in order to not loose # fields that weren't sent with the form. old_data = dataManager.get() for item in data: old_data[item] = data[item] dataManager.set(old_data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) tileRelativeURL = tileURL if tileURL.startswith(contextURL): tileRelativeURL = '.' + tileURL[len(contextURL):] notify(ObjectModifiedEvent(tile)) # Get the tile URL, possibly with encoded data IStatusMessage(self.request).addStatusMessage(_(u"Tile saved", ), type=u'info') self.request.response.redirect(tileURL)
def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ generator = getUtility(IUUIDGenerator) tileId = generator() # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse('@@%s/%s' % ( typeName, tileId, )) dataManager = ITileDataManager(tile) dataManager.set(data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) tileRelativeURL = tileURL if tileURL.startswith(contextURL): tileRelativeURL = '.' + tileURL[len(contextURL):] IStatusMessage(self.request).addStatusMessage( _(u"Tile created at ${url}", mapping={'url': tileURL}), type=u'info', ) notify(ObjectCreatedEvent(tile)) notify(ObjectAddedEvent(tile, self.context, tileId)) self.request.response.redirect(tileURL)
def test_uuids_converted_to_dict(self): title = u'Revert PersistentMapping back to dict' step = self._get_upgrade_step(title) self.assertIsNotNone(step) # simulate state on previous version with api.env.adopt_roles(['Manager']): api.content.create( self.portal, 'collective.cover.content', 'test-cover', template_layout='Empty layout', ) cover = self.portal['test-cover'] cover.cover_layout = ( '[{"type": "row", "children": [{"data": {"layout-type": "column", ' '"column-size": 16}, "type": "group", "children": [{"tile-type": ' '"collective.cover.carousel", "type": "tile", "id": ' '"ca6ba6675ef145e4a569c5e410af7511"}], "roles": ["Manager"]}]}]' ) tile = cover.get_tile('ca6ba6675ef145e4a569c5e410af7511') old_data = ITileDataManager(tile).get() old_dict = PersistentMapping() old_dict['uuid1'] = {'order': u'0'} old_dict['uuid2'] = {'order': u'1'} old_dict['uuid3'] = {'order': u'2'} old_data['uuids'] = old_dict ITileDataManager(tile).set(old_data) # run the upgrade step to validate the update self._do_upgrade_step(step) old_data = ITileDataManager(tile).get() self.assertFalse(isinstance(old_data['uuids'], PersistentMapping)) self.assertTrue(isinstance(old_data['uuids'], dict)) self.assertEqual(old_data['uuids']['uuid1']['order'], u'0') self.assertEqual(old_data['uuids']['uuid2']['order'], u'1') self.assertEqual(old_data['uuids']['uuid3']['order'], u'2')
def __str__(self): url = super(FragmentTileAbsoluteURL, self).__str__().split('?')[0] data = ITileDataManager(self.context).get() if data and 'fragment' in data: fragment = data['fragment'] if fragment: if '?' in url: url += '&fragment=' + fragment else: url += '?fragment=' + fragment for schema_ in getFragmentSchemata(fragment): url += '&' + encode(data, schema_) return url
def __call__(self): # Set up draft information if required currentDraft = ICurrentDraftManagement(self.request) currentDraft.mark() self.request['disable_border'] = True confirm = self.request.form.get('confirm', False) self.tileTypeName = self.request.form.get('type', None) self.tileId = self.request.form.get('id', None) self.deleted = False if confirm and self.tileTypeName and self.tileId: tileType = getUtility(ITileType, name=self.tileTypeName) if not checkPermission(tileType.add_permission, self.context): raise Unauthorized("You are not allowed to modify this " + \ "tile type") tile = self.context.restrictedTraverse( '@@%s/%s' % (self.tileTypeName, self.tileId,)) dm = ITileDataManager(tile) dm.delete() notify(ObjectRemovedEvent(tile, self.context, self.tileId)) self.deleted = True elif 'form.button.Ok' in self.request.form: self.request.response.redirect( self.context.absolute_url() + '/view') return '' return self.index()
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) data = {'title': obj.Title(), 'description': obj.Description(), 'uuid': IUUID(obj, None), 'date': obj.effective_date and \ DT2dt(obj.effective_date) or None, 'subjects': obj.Subject(), } # XXX: Implements a better way to detect image fields. try: data['image'] = NamedImageFile(str(obj.getImage().data)) except AttributeError: try: data['image'] = NamedImageFile(str(obj.image.data)) except AttributeError: pass data_mgr = ITileDataManager(self) data_mgr.set(data)
def populate_with_object(self, obj): super(BasicTile, self).populate_with_object(obj) # initialize the tile with all fields needed for its rendering # note that we include here 'date' and 'subjects', but we do not # really care about their value: they came directly from the catalog # brain data = { 'title': safe_unicode(obj.Title()), 'description': safe_unicode(obj.Description()), 'uuid': IUUID(obj), 'date': True, 'subjects': True, 'image': self.get_image_data(obj) } if data['image']: # clear scales if new image is getting saved self.clear_scales() data_mgr = ITileDataManager(self) data_mgr.set(data)
def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return tile = self.getTile() # We need to check first for existing content in order not not loose # fields that weren't sent with the form dataManager = ITileDataManager(tile) old_data = dataManager.get() for item in data: old_data[item] = data[item] dataManager.set(old_data) api.portal.show_message(_(u'Tile saved'), self.request, type='info') # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) self.request.response.redirect(tileURL)
def fix_persistentmap_to_dict(context): """Internal structure was reverted from using PersistentMapping. Fix tiles here""" # Get covers covers = context.portal_catalog(portal_type='collective.cover.content') logger.info('About to update {0} objects'.format(len(covers))) tiles_to_update = _get_tiles_inherit_from_list(context) logger.info('{0} tile types will be updated ({1})'.format( len(tiles_to_update), ', '.join(tiles_to_update))) for cover in covers: obj = cover.getObject() tile_ids = obj.list_tiles(types=tiles_to_update) for tile_id in tile_ids: tile = obj.get_tile(tile_id) old_data = ITileDataManager(tile).get() uuids = old_data['uuids'] if isinstance(uuids, dict): # This tile is fixed, carry on msg = 'Tile {0} at {1} was already updated' logger.info(msg.format(tile_id, cover.getPath())) continue if not uuids: # This tile did not have data, so ignore msg = 'Tile {0} at {1} did not have any data' logger.info(msg.format(tile_id, cover.getPath())) continue new_data = dict() for k, v in uuids.items(): new_data[k] = v old_data['uuids'] = new_data ITileDataManager(tile).set(old_data) msg = 'Tile {0} at {1} updated' logger.info(msg.format(tile_id, cover.getPath())) logger.info('Done')
def fix_image_field_modification_time(context): """Fix image modification time to be float timestamp instead of string.""" covers = context.portal_catalog(object_provides=ICover.__identifier__) logger.info('About to update {0} objects'.format(len(covers))) for cover in covers: obj = cover.getObject() for tile_id in obj.list_tiles(): tile = obj.get_tile(tile_id) dmgr = ITileDataManager(tile) data = dmgr.get() for k, v in data.items(): if not INamedImage.providedBy(v): continue mtime_key = '{0}_mtime'.format(k) data[mtime_key] = float(data[mtime_key]) # need to set changes directly into annotation dmgr.annotations[dmgr.key] = PersistentDict(data) msg = 'Tile {0} at {1} updated' logger.info(msg.format(tile_id, cover.getPath())) logger.info('Done')
def test_render_with_image(self): obj1 = self.portal['my-image'] obj2 = self.portal['my-document'] self.tile.populate_with_object(obj1) data = self.tile.data data['tile_title'] = 'Carousel title' data['tile_description'] = 'Carousel description' data['more_link'] = api.content.get_uuid(obj2) data['more_link_text'] = 'Read much more...' data_mgr = ITileDataManager(self.tile) data_mgr.set(data) rendered = self.tile() self.assertFalse(self.tile.is_empty()) self.assertIn('<img ', rendered) self.assertIn('alt="This image was created for testing purposes"', rendered) self.assertIn('<h2>Carousel title</h2>', rendered) self.assertIn('<p>Carousel description</p>', rendered) self.assertIn('Read much more...', rendered) self.assertIn('<a href="http://nohost/plone/my-document"', rendered)
def test_custom_description(self): # we start with an empty tile self.assertTrue(self.tile.is_empty()) uuids = ITileDataManager(self.tile).get().get('uuids', None) self.assertIsNone(uuids) # now we 2 elements obj1 = self.portal['my-document'] obj2 = self.portal['my-image'] self.tile.populate_with_uuids([obj1.UID(), obj2.UID()]) # For obj2 we will assign a custom_description uuids = ITileDataManager(self.tile).get().get('uuids', None) uuids[obj2.UID()]['custom_description'] = u'New Description' description1 = self.tile.get_description(obj1) description2 = self.tile.get_description(obj2) # Document object should be the same as Description self.assertEqual(description1, obj1.Description()) # First image should return the custom URL self.assertEqual(description2, u'New Description')
def test_custom_title(self): # we start with an empty tile self.assertTrue(self.tile.is_empty()) uuids = ITileDataManager(self.tile).get().get('uuids', None) self.assertIsNone(uuids) # now we 2 elements obj1 = self.portal['my-document'] obj2 = self.portal['my-image'] self.tile.populate_with_uuids([obj1.UID(), obj2.UID()]) # For obj2 we will assign a custom_title uuids = ITileDataManager(self.tile).get().get('uuids', None) uuids[obj2.UID()]['custom_title'] = u'New Title' title1 = self.tile.get_title(obj1) title2 = self.tile.get_title(obj2) # Document object should be the same as Title self.assertEqual(title1, obj1.Title()) # First image should return the custom Title self.assertEqual(title2, u'New Title')
def remove_item(self, uid): super(ListTile, self).remove_item(uid) data_mgr = ITileDataManager(self) old_data = data_mgr.get() uids = data_mgr.get()['uuids'] if uid in uids: del uids[uids.index(uid)] old_data['uuids'] = uids data_mgr.set(old_data)
def populate_with_object(self, obj): super(AudioTile, self).populate_with_object(obj) # check permissions if obj.portal_type in self.accepted_ct(): title = obj.Title() description = obj.Description() rights = obj.Rights() mp3 = obj.return_mp3() if mp3: url = mp3.absolute_url() content_type = 'audio/mp3' else: url = obj.absolute_url() content_type = '' uuid = api.content.get_uuid(obj) data_mgr = ITileDataManager(self) data_mgr.set({ 'title': title, 'description': description, 'url': url, 'credit': rights, 'uuid': uuid, 'content_type': content_type })
def test_basic_tile_purge_cache(self): provideHandler(queuePurge) request = self.request alsoProvides(request, IAttributeAnnotatable) setRequest(request) registry = queryUtility(IRegistry) registry.registerInterface(ICachePurgingSettings) provideUtility(registry, IRegistry) settings = registry.forInterface(ICachePurgingSettings) settings.enabled = True settings.cachingProxies = ('http://*****:*****@@collective.cover.basic/test-basic-tile', '/@@collective.cover.basic/test-basic-tile/@@images/image', '/@@collective.cover.basic/test-basic-tile/@@images/icon', '/@@collective.cover.basic/test-basic-tile/@@images/mini', '/@@collective.cover.basic/test-basic-tile/@@images/large', '/@@collective.cover.basic/test-basic-tile/@@images/listing', '/@@collective.cover.basic/test-basic-tile/@@images/thumb', '/@@collective.cover.basic/test-basic-tile/@@images/preview', '/@@collective.cover.basic/test-basic-tile/@@images/tile' ]), IAnnotations(request)['plone.cachepurging.urls'])
def handleDelete(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ # Traverse to a new tile in the context, with no data tile = self.context.restrictedTraverse( '@@%s/%s' % (typeName, self.tileId,)) # Look up the URL - we need to do this before we've deletd the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) dataManager = ITileDataManager(tile) dataManager.delete() notify(ObjectRemovedEvent(tile)) logger.debug(u"Tile deleted at {0}".format(tileURL)) # Skip form rendering for AJAX requests if self.request.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest': IStatusMessage(self.request).addStatusMessage( _(u"Tile deleted at ${url}", mapping={'url': tileURL}), type=u'info' ) self.template = lambda: u'' return try: url = self.nextURL(tile) except NotImplementedError: url = self.context.absolute_url() self.request.response.redirect(url)
def populate_with_object(self, obj): super(POTDTile, self).populate_with_object(obj) title = safe_unicode(obj.Title()) description = safe_unicode(obj.Description()) rights = safe_unicode(obj.Rights()) image = self.get_image_data(obj) if image: # clear scales if new image is getting saved self.clear_scales() data = { 'title': title, 'description': description, 'uuid': api.content.get_uuid(obj=obj), 'image': image, 'photo_credits': rights, # FIXME: https://github.com/collective/collective.cover/issues/778 'alt_text': description or title, } data_mgr = ITileDataManager(self) data_mgr.set(data)