def get_or_create_speaker(self, data): """ Returns already created speaker or newly created speaker """ container = self.speakers_container() if not container: raise Exception('Unable to create a talk proposal. ' 'Folder "speakers" not available.') title = data.get('name', None) pc = api.portal.get_tool(name='portal_catalog') speakers = pc.unrestrictedSearchResults( portal_type='Person', path='/'.join(container.getPhysicalPath()), Title=title, ) if speakers: speaker = speakers[0]._unrestrictedGetObject() # self.update_speaker_fields(speaker=speaker, data=data) # notify(ObjectModifiedEvent(speaker)) return speaker speaker = self.create_obj(data=data, type_='Person', title=title, container=container) if isinstance(speaker, dict): # error occurred return speaker self.update_speaker_fields(speaker=speaker, data=data) notify(ObjectCreatedEvent(speaker)) speaker = add(container, speaker, rename=False) return speaker
def create_or_modify_content(self, tus_upload): metadata = tus_upload.metadata() filename = metadata.get("filename", "") content_type = metadata.get("content-type", "application/octet-stream") mode = metadata.get("mode", "create") fieldname = metadata.get("fieldname") if mode == "create": type_ = metadata.get("@type") if type_ is None: ctr = getToolByName(self.context, "content_type_registry") type_ = ctr.findTypeName(filename.lower(), content_type, "") or "File" obj = create(self.context, type_) else: obj = self.context if not fieldname: info = IPrimaryFieldInfo(obj, None) if info is not None: fieldname = info.fieldname elif base_hasattr(obj, "getPrimaryField"): field = obj.getPrimaryField() fieldname = field.getName() if not fieldname: return self.error("Bad Request", "Fieldname required", 400) # Acquisition wrap temporarily for deserialization temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, "aq_base"): obj = obj.__of__(self.context) temporarily_wrapped = True # Update field with file data deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: return self.error( "Not Implemented", f"Cannot deserialize type {obj.portal_type}", 501, ) try: deserializer(data={fieldname: tus_upload}, create=mode == "create") except DeserializationError as e: return self.error("Deserialization Error", str(e), 400) if temporarily_wrapped: obj = aq_base(obj) if mode == "create": if not getattr(deserializer, "notifies_create", False): notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj) tus_upload.close() tus_upload.cleanup() self.request.response.setHeader("Location", obj.absolute_url())
def setUp(self): self.portal = self.layer['portal'] self.request = self.layer['request'] self.folder = self.portal[self.portal.invokeFactory('Folder', id='folder', title='My Folder')] self.obj = add(self.folder, create(self.folder, 'Document', title='My Document'))
def setUp(self): self.portal = self.layer['portal'] self.request = self.layer['request'] setRoles(self.portal, TEST_USER_ID, ['Contributor']) self.folder = self.portal[self.portal.invokeFactory('Folder', id='folder', title='My Folder')] self.obj = add(self.folder, create(self.folder, 'Document', title='My Document'))
def test_add_content_to_container_and_move_on_added_event(self): sm = getGlobalSiteManager() def move_object(event): self.portal.manage_pasteObjects( cb_copy_data=self.folder.manage_cutObjects( ids=['my-document'])) sm.registerHandler(move_object, (IObjectAddedEvent, )) obj = add(self.folder, self.obj) self.assertEqual(aq_parent(obj), self.portal) sm.unregisterHandler(move_object, (IObjectAddedEvent, ))
def create_talk(self, data, speaker): container = self.talks_container() if not container: raise Exception('Unable to create a talk proposal. ' 'Folder "talks" not available.') title = data.get('title', None) talk = self.create_obj(data=data, type_='Talk', title=title, container=container) talk_fields = getFields(ITalk) for k, v in data.items(): if k in talk_fields.keys(): setattr(talk, k, v) # add speaker/talk relation intids = getUtility(IIntIds) to_id = intids.getId(speaker) talk.related_people = [RelationValue(to_id)] notify(ObjectCreatedEvent(talk)) talk = add(container, talk, rename=False) return talk
def create_content_from_fhir_json(container, fhir_json): """ """ body = { "@type": fhir_json["resourceType"], "title": "{0}/{1}".format(fhir_json["resourceType"], fhir_json["id"]), "{0}_resource".format(fhir_json["resourceType"].lower()): fhir_json, } request = TestRequest(BODY=json.dumps(body)) obj = create(container, body["@type"], id_=fhir_json["id"], title=body["title"]) deserializer = queryMultiAdapter((obj, request), IDeserializeFromJson) notify(ObjectCreatedEvent(obj)) deserializer(validate_all=True) obj = add(container, obj, False) return obj
def create_or_modify_content(self, tus_upload): metadata = tus_upload.metadata() filename = metadata.get('filename', '') content_type = metadata.get('content-type', 'application/octet-stream') mode = metadata.get('mode', 'create') fieldname = metadata.get('fieldname') if mode == 'create': type_ = metadata.get('@type') if type_ is None: ctr = getToolByName(self.context, 'content_type_registry') type_ = ctr.findTypeName( filename.lower(), content_type, '') or 'File' obj = create(self.context, type_) else: obj = self.context if not fieldname: info = IPrimaryFieldInfo(obj, None) if info is not None: fieldname = info.fieldname elif base_hasattr(obj, 'getPrimaryField'): field = obj.getPrimaryField() fieldname = field.getName() if not fieldname: return self.error('Bad Request', 'Fieldname required', 400) # Acquisition wrap temporarily for deserialization temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, 'aq_base'): obj = obj.__of__(self.context) temporarily_wrapped = True # Update field with file data deserializer = queryMultiAdapter( (obj, self.request), IDeserializeFromJson) if deserializer is None: return self.error( 'Not Implemented', 'Cannot deserialize type {}'.format( obj.portal_type), 501) try: deserializer( data={fieldname: tus_upload}, create=mode == 'create') except DeserializationError as e: return self.error( 'Deserialization Error', str(e), 400) if temporarily_wrapped: obj = aq_base(obj) if mode == 'create': if not getattr(deserializer, 'notifies_create', False): notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj) tus_upload.close() tus_upload.cleanup() self.request.response.setHeader('Location', obj.absolute_url())
def test_add_content_to_container_keeps_id(self): obj = create(self.folder, "Document", "doc-1", "My Document") obj = add(self.folder, obj, rename=False) self.assertEqual(obj.getId(), "doc-1")
def test_add_content_to_container_renames_id(self): obj = create(self.folder, "Document", title="My Document") obj = add(self.folder, obj) self.assertEqual(obj.getId(), "my-document")
def test_add_content_to_container(self): obj = create(self.folder, "Document", "my-document") obj = add(self.folder, obj) self.assertEqual(aq_parent(obj), self.folder)
def reply(self): tus_upload = self.tus_upload() if tus_upload is None: return self.error('Not Found', '', 404) metadata = tus_upload.metadata() self.check_add_modify_permission(metadata.get('mode', 'create')) if not self.check_tus_version(): return self.unsupported_version() content_type = self.request.getHeader('Content-Type') if content_type != 'application/offset+octet-stream': return self.error('Bad Request', 'Missing or invalid Content-Type header') offset = self.request.getHeader('Upload-Offset', '') try: offset = int(offset) except ValueError: return self.error('Bad Request', 'Missing or invalid Upload-Offset header') tus_upload.write(self.request._file, offset) if tus_upload.finished: offset = tus_upload.offset() filename = metadata.get('filename', '') content_type = metadata.get('content-type', 'application/octet-stream') mode = metadata.get('mode', 'create') fieldname = metadata.get('fieldname') if mode == 'create': type_ = metadata.get('@type') if type_ is None: ctr = getToolByName(self.context, 'content_type_registry') type_ = ctr.findTypeName(filename.lower(), content_type, '') or 'File' obj = create(self.context, type_) notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj) else: obj = self.context if not fieldname: info = IPrimaryFieldInfo(obj, None) if info is not None: fieldname = info.fieldname elif base_hasattr(obj, 'getPrimaryField'): field = obj.getPrimaryField() fieldname = field.getName() if not fieldname: return self.error('Bad Request', 'Fieldname required', 400) # Update field with file data deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: return self.error( 'Not Implemented', 'Cannot deserialize type {}'.format(obj.portal_type), 501) try: deserializer(data={fieldname: tus_upload}) except DeserializationError as e: return self.error('Deserialization Error', str(e), 400) if mode == 'create': rename(obj) tus_upload.close() tus_upload.cleanup() self.request.response.setHeader('Location', obj.absolute_url()) else: offset = tus_upload.offset() self.request.response.setHeader('Upload-Expires', tus_upload.expires()) self.request.response.setHeader('Tus-Resumable', '1.0.0') self.request.response.setHeader('Upload-Offset', '{}'.format(offset)) self.request.response.setStatus(204, lock=1) return super(UploadPatch, self).reply()
def test_add_content_to_container(self): obj = add(self.folder, self.obj) self.assertEqual(aq_parent(obj), self.folder)
def import_item(self, dirpath, *filenames): __traceback_info__ = dirpath logger.info("Importing item at %s", dirpath) all_info = {} blobs = {} for name in filenames: filepath = os.path.join(dirpath, name) key, ext = os.path.splitext(name) if ext != ".json": logger.info("Found non json file, will use as blob, at %s", filepath) blobs[key] = filepath continue logger.info("Reading %s", filepath) with open(filepath) as myfile: content = json.loads(myfile.read()) all_info[key] = content # Get meta info. We might also get some of this from default.json. # Maybe we need less in meta. meta = all_info["meta"] # if "front-page" in meta.get("path", ""): # import pdb; pdb.set_trace() # See if the object already exists. obj = self.get_object(**meta) if obj is None: # We need to get some parent, either from default["parent"] or meta. path = meta["path"] parent_path = path.rpartition("/")[0] parent_obj = self.get_object(path=parent_path) if parent_obj is None: logger.warning( "Parent object not found, cannot create content for %s", path) return default = all_info["default"] # Code taken from plone.restapi add.py FolderPost.reply. # It would be nice if we could call that method directly, but it does too much. # We would need to split it a bit, especially: # don't get json from the request body, and don't change the response. type_ = default.get("@type", None) id_ = default.get("id", None) title = default.get("title", None) translation_of = default.get("translation_of", None) language = default.get("language", None) # except Unauthorized / BadRequest obj = create(parent_obj, type_, id_=id_, title=title) # Acquisition wrap temporarily to satisfy things like vocabularies # depending on tools temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, "aq_base"): obj = obj.__of__(self.context) temporarily_wrapped = True deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: logger.error("Cannot deserialize type %s", obj.portal_type) return if blobs: for fieldname, path in blobs.items(): if fieldname in default: with open(path, "rb") as myfile: default[fieldname]["data"] = myfile.read() # except DeserializationError as e: deserializer(validate_all=True, data=default, create=True) if temporarily_wrapped: obj = aq_base(obj) if not getattr(deserializer, "notifies_create", False): notify(ObjectCreatedEvent(obj)) obj = add(parent_obj, obj, rename=not bool(id_)) obj_path = "/".join(obj.getPhysicalPath()) logger.info("Created %s at %s", type_, obj_path) # Link translation given the translation_of property if PAM_INSTALLED: # Note: untested. from plone.app.multilingual.interfaces import ( IPloneAppMultilingualInstalled, ) # noqa from plone.app.multilingual.interfaces import ITranslationManager if (IPloneAppMultilingualInstalled.providedBy(self.request) and translation_of and language): source = self.get_object(translation_of) if source: manager = ITranslationManager(source) manager.register_translation(language, obj) # TODO: call other, named deserializers, but they do not work currently anyway. else: obj_path = "/".join(obj.getPhysicalPath()) if is_locked(obj, self.request): # TODO: We could throw an error, but we should probably just unlock. logger.warning("Content is locked: %s", obj_path) logger.info("Updating existing content at %s", obj_path) deserializers = getAdapters((obj, self.request), IDeserializeFromJson) if not deserializers: logger.error("Cannot deserialize type %s", obj.portal_type) return for name, deserializer in deserializers: if not name: name = "default" # XXX This traceback info overrides the previous. # When done in a separate method, it should be fine. # __traceback_info__ = name __traceback_info__ = dirpath, name content = all_info[name] if name == "local_roles": # TODO Fix this in plone.restapi. logger.info( "Ignoring local_roles deserializer for now, as it does not accept a content parameter." ) continue if name == "default" and blobs: for fieldname, path in blobs.items(): if fieldname in content: with open(path, "rb") as myfile: content[fieldname]["data"] = myfile.read() try: deserializer(data=content) except TypeError: # Happens for site root. But I want to fix it there too, if that is acceptable. logger.info( "TypeError, likely because deserializer does not accept data keyword argument: %s", deserializer) # TODO: maybe try / except DeserializationError # Report back that we made an import. return True
def add_object_to_context(self): self.obj = add(self.context, self.obj, rename=not bool(self.id_))
def create_item_runner( container, content_structure, auto_id=False, default_lang=None, default_wf_action=None, ignore_wf_types=['Image', 'File'], logger=logger): """Create Dexterity contents from plone.restapi compatible structures. :param container: The context in which the item should be created. :type container: Plone content object :param content_structure: Python dictionary with content structure. :type content_structure: dict :param default_lang: Default language. :type default_lang: string :param default_wf_action: Default workflow transition action. :type default_wf_action: string :param ignore_wf_types: Ignore to apply the workflow transition if item is one of these types. :type ignore_wf_types: list (default: ['Image', 'File']) :param logger: Logger to use. :type logger: Python logging instance. The datastructure of content defined by plone.restapi: https://plonerestapi.readthedocs.io/en/latest/content.html#creating-a-resource-with-post [ { "type": "", "id": "", "title": "", "description": "" "items": [], "opts": { "default_page": "", "locally_allowed_types": [], "immediately_allowed_types": [], } } ] Use the same structure for each child. Leave out, what you don't need. """ request = getRequest() for data in content_structure: type_ = data.get('@type', None) id_ = data.get('id', None) title = data.get('title', None) if not type_: raise BadRequest("Property '@type' is required") obj = create(container, type_, id_=id_, title=title) # Acquisition wrap temporarily to satisfy things like vocabularies # depending on tools temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, 'aq_base'): obj = obj.__of__(container) temporarily_wrapped = True deserializer = queryMultiAdapter((obj, request), IDeserializeFromJson) if deserializer is None: raise BadRequest( 'Canno deserialize type {}'.format(obj.portal_type)) # defaults if not data.get('language'): data['language'] = default_lang if not data.get('review_state'): data['review_state'] = default_wf_action deserializer(validate_all=True, data=data, create=True) if temporarily_wrapped: obj = aq_base(obj) if not getattr(deserializer, 'notifies_create', False): notify(ObjectCreatedEvent(obj)) obj = add(container, obj, rename=not bool(id_)) # set default opts = data.get('opts', {}) if opts.get('default_page', False): container.setDefaultPage(obj.id) # CONSTRAIN TYPES locally_allowed_types = opts.get('locally_allowed_types', False) immediately_allowed_types = opts.get('immediately_allowed_types', False) if locally_allowed_types or immediately_allowed_types: be = ISelectableConstrainTypes(obj, None) if be: be.setConstrainTypesMode(behaviors.constrains.ENABLED) if locally_allowed_types: be.setLocallyAllowedTypes = locally_allowed_types logger.debug('{0}: locally_allowed_types {1}'.format(path, locally_allowed_types)) # noqa if immediately_allowed_types: be.setImmediatelyAddableTypes = immediately_allowed_types logger.debug('{0}: immediately_allowed_types {1}'.format(path, immediately_allowed_types)) # noqa id_ = obj.id # get the real id path = '/'.join(obj.getPhysicalPath()) logger.info('{0}: created'.format(path)) # Call recursively create_item_runner( obj, content_structure=data.get('items', []), default_lang=default_lang, default_wf_action=default_wf_action, logger=logger, )
def do_reply(self): """This is the reply method from plone.restapi, overrided to manage returning the fullobject after creation or the summary.""" # imio.restapi, nothing changed until next comment "imio.restapi ..." comment data = json_body(self.request) type_ = data.get("@type", None) id_ = data.get("id", None) title = data.get("title", None) translation_of = data.get("translation_of", None) language = data.get("language", None) if not type_: raise BadRequest("Property '@type' is required") # Disable CSRF protection if "IDisableCSRFProtection" in dir(plone.protect.interfaces): alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) try: obj = create(self.context, type_, id_=id_, title=title) except Unauthorized as exc: self.request.response.setStatus(403) return dict(error=dict(type="Forbidden", message=str(exc))) except BadRequest as exc: self.request.response.setStatus(400) return dict(error=dict(type="Bad Request", message=str(exc))) # Acquisition wrap temporarily to satisfy things like vocabularies # depending on tools temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, "aq_base"): obj = obj.__of__(self.context) temporarily_wrapped = True # Update fields deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: self.request.response.setStatus(501) return dict( error=dict(message="Cannot deserialize type {}".format(obj.portal_type)) ) try: deserializer(validate_all=True, create=True) except DeserializationError as e: self.request.response.setStatus(400) return dict(error=dict(type="DeserializationError", message=str(e))) if temporarily_wrapped: obj = aq_base(obj) if not getattr(deserializer, "notifies_create", False): notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj, rename=not bool(id_)) # Link translation given the translation_of property if PAM_INSTALLED and PLONE5: from plone.app.multilingual.interfaces import ( IPloneAppMultilingualInstalled, ) # noqa from plone.app.multilingual.interfaces import ITranslationManager if ( IPloneAppMultilingualInstalled.providedBy(self.request) and translation_of and language ): source = self.get_object(translation_of) if source: manager = ITranslationManager(source) manager.register_translation(language, obj) self.request.response.setStatus(201) self.request.response.setHeader("Location", obj.absolute_url()) # imio.restapi, begin changes, manage returning full object or summary return_full_object = data.get( "return_fullobject", get_return_fullobject_after_creation_default()) if return_full_object: serializer = queryMultiAdapter((obj, self.request), ISerializeToJson) else: serializer = queryMultiAdapter((obj, self.request), ISerializeToJsonSummary) serialized_obj = serializer() # imio.restapi, end changes, manage returning full object or summary # HypermediaBatch can't determine the correct canonical URL for # objects that have just been created via POST - so we make sure # to set it here serialized_obj["@id"] = obj.absolute_url() return serialized_obj
def test_add_content_to_container_keeps_id(self): obj = create(self.folder, 'Document', 'doc-1', 'My Document') obj = add(self.folder, obj, rename=False) self.assertEqual(obj.getId(), 'doc-1')
def reply(self): data = json_body(self.request) type_ = data.get('@type', None) id_ = data.get('id', None) title = data.get('title', None) if not type_: raise BadRequest("Property '@type' is required") # Disable CSRF protection if 'IDisableCSRFProtection' in dir(plone.protect.interfaces): alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) try: obj = create(self.context, type_, id_=id_, title=title) except Unauthorized as exc: self.request.response.setStatus(403) return dict(error=dict(type='Forbidden', message=exc.message)) except BadRequest as exc: self.request.response.setStatus(400) return dict(error=dict(type='Bad Request', message=exc.message)) # Acquisition wrap temporarily to satisfy things like vocabularies # depending on tools temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, 'aq_base'): obj = obj.__of__(self.context) temporarily_wrapped = True # Update fields deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: self.request.response.setStatus(501) return dict(error=dict( message='Cannot deserialize type {}'.format(obj.portal_type))) try: deserializer(validate_all=True, create=True) except DeserializationError as e: self.request.response.setStatus(400) return dict( error=dict(type='DeserializationError', message=str(e))) if temporarily_wrapped: obj = aq_base(obj) if not getattr(deserializer, 'notifies_create', False): notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj, rename=not bool(id_)) self.request.response.setStatus(201) self.request.response.setHeader('Location', obj.absolute_url()) serializer = queryMultiAdapter((obj, self.request), ISerializeToJson) serialized_obj = serializer() # HypermediaBatch can't determine the correct canonical URL for # objects that have just been created via POST - so we make sure # to set it here serialized_obj['@id'] = obj.absolute_url() return serialized_obj
def reply(self): data = json_body(self.request) type_ = data.get("@type", None) id_ = data.get("id", None) title = data.get("title", None) translation_of = data.get("translation_of", None) language = data.get("language", None) uid = data.get("UID", None) if not type_: raise BadRequest("Property '@type' is required") # Disable CSRF protection if "IDisableCSRFProtection" in dir(plone.protect.interfaces): alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) sm = getSecurityManager() # ManagePortal is required to set the uid of an object during creation if uid and not sm.checkPermission(ManagePortal, self.context): self.request.response.setStatus(403) msg = "Setting UID of an object requires Manage Portal permission" return dict(error=dict(type="Forbidden", message=msg)) try: obj = create(self.context, type_, id_=id_, title=title) except Unauthorized as exc: self.request.response.setStatus(403) return dict(error=dict(type="Forbidden", message=str(exc))) except BadRequest as exc: self.request.response.setStatus(400) return dict(error=dict(type="Bad Request", message=str(exc))) # Acquisition wrap temporarily to satisfy things like vocabularies # depending on tools temporarily_wrapped = False if IAcquirer.providedBy(obj) and not safe_hasattr(obj, "aq_base"): obj = obj.__of__(self.context) temporarily_wrapped = True # Update fields deserializer = queryMultiAdapter((obj, self.request), IDeserializeFromJson) if deserializer is None: self.request.response.setStatus(501) return dict(error=dict( message=f"Cannot deserialize type {obj.portal_type}")) try: deserializer(validate_all=True, create=True) except DeserializationError as e: self.request.response.setStatus(400) return dict( error=dict(type="DeserializationError", message=str(e))) if temporarily_wrapped: obj = aq_base(obj) if uid: setattr(obj, "_plone.uuid", uid) if not getattr(deserializer, "notifies_create", False): notify(ObjectCreatedEvent(obj)) obj = add(self.context, obj, rename=not bool(id_)) # Link translation given the translation_of property if (IPloneAppMultilingualInstalled.providedBy(self.request) and translation_of and language): source = self.get_object(translation_of) if source: manager = ITranslationManager(source) manager.register_translation(language, obj) self.request.response.setStatus(201) self.request.response.setHeader("Location", obj.absolute_url()) serializer = queryMultiAdapter((obj, self.request), ISerializeToJson) serialized_obj = serializer() # HypermediaBatch can't determine the correct canonical URL for # objects that have just been created via POST - so we make sure # to set it here serialized_obj["@id"] = obj.absolute_url() return serialized_obj