def get_latest_version(self): """Get the latest version or the PWC""" # This always selects the latest version, and if there is a pwc, # Alfresco returns both the pwc and the latest major version, while Corsa only returns the pwc. query = CMISQuery("SELECT * FROM drc:document WHERE drc:document__uuid = '%s'") soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, statement=query(self.uuid), cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.client.request( "DiscoveryService", soap_envelope=soap_envelope.toxml() ) # Corsa raises an error for queries that return no results except CmisRuntimeException as exc: if "objectNotFound" in exc.message: error_string = f"Object met objectId '{self.objectId}' bestaat niet in het CMIS connection" raise DocumentDoesNotExistError(error_string) else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml(xml_response, "query") return extract_latest_version(type(self), extracted_data)
def get_folder(self, object_id: str) -> Folder: """Retrieve folder with given objectId""" soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, object_id=object_id, cmis_action="getObject", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.request("ObjectService", soap_envelope=soap_envelope.toxml()) except CmisRuntimeException as exc: if "objectNotFound" in exc.message: error_string = f"Folder met objectId '{object_id}' bestaat niet in het CMIS connection" raise FolderDoesNotExistError(error_string) else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getObject")[0] return Folder(extracted_data)
def delete_object(self): """ Permanently delete the object from the CMIS store, with all its versions. By default, all versions should be deleted according to the CMIS standard. If the document is currently locked (i.e. there is a private working copy), we need to cancel that checkout first. """ latest_version = self.get_latest_version() if latest_version.isVersionSeriesCheckedOut: soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=latest_version.objectId, cmis_action="cancelCheckOut", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "VersioningService", soap_envelope=soap_envelope.toxml(), ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) refreshed_document = self.get_latest_version() return refreshed_document.delete_object() return super().delete_object()
def checkout(self) -> "Document": """Checkout a private working copy of the document""" soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, cmis_action="checkOut", object_id=str(self.objectId), ) logger.debug(soap_envelope.toprettyxml()) # FIXME temporary solution due to alfresco raising a 500 AFTER locking the document try: soap_response = self.client.request( "VersioningService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "checkOut" )[0] pwc_id = extracted_data["properties"]["objectId"]["value"] except CmisRuntimeException: pwc_document = self.get_latest_version() pwc_id = pwc_document.objectId return self.get_document(pwc_id)
def test_create_document_with_filename(self): properties = { "bronorganisatie": "159351741", "integriteitwaarde": "Something", "verwijderd": "false", "ontvangstdatum": "2020-07-28", "versie": "1.0", "creatiedatum": "2018-06-27", "titel": "detailed summary", "bestandsnaam": "filename.txt", } cmis_properties = Document.build_properties(data=properties) other_folder = self.cmis_client.get_or_create_other_folder() soap_envelope = make_soap_envelope( auth=(self.cmis_client.user, self.cmis_client.password), repository_id=self.cmis_client.main_repo_id, folder_id=other_folder.objectId, properties=cmis_properties, cmis_action="createDocument", content_id=str(uuid.uuid4()), content_filename="filename.txt", ) self.assertIn("<ns:filename>filename.txt</ns:filename>", soap_envelope.toxml()) self.assertIn("<ns:mimeType>text/plain</ns:mimeType>", soap_envelope.toxml())
def get_content_object( self, object_id: str, object_type: type ) -> "CMISContentObject": """Get a content object with specified objectId :param object_id: string, objectId of the content object :param object_type: type, type of the object to return :return: CMISContentObject """ soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=object_id, cmis_action="getObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml(xml_response, "getObject")[ 0 ] return object_type(extracted_data)
def _update_properties(self, properties: dict) -> dict: """ Update properties and return the properties of the updated object. :param properties: dict, new properties to update :return: dict, properties of the updated object """ soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, properties=properties, cmis_action="updateProperties", object_id=self.objectId, ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml(), ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "updateProperties" )[0] return extracted_data
def move_object(self, target_folder: "Folder") -> "CMISContentObject": """Move a document to the specified folder""" source_folder = self.get_parent_folders()[0] soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=self.objectId, target_folder_id=target_folder.objectId, source_folder_id=source_folder.objectId, cmis_action="moveObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml(xml_response, "moveObject")[ 0 ] return type(self)(extracted_data)
def get_main_repo_id(self, cache: bool = True) -> str: configured_main_repo_id = self.config.main_repo_id if configured_main_repo_id and cache: return configured_main_repo_id if self._main_repo_id is None: # Retrieving the IDs of all repositories in the CMS soap_envelope = make_soap_envelope(auth=(self.user, self.password), cmis_action="getRepositories") logger.debug(soap_envelope.toprettyxml()) soap_response = self.request("RepositoryService", soap_envelope=soap_envelope.toxml()) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) all_repositories_ids = extract_repository_ids_from_xml( xml_response) # If no main repository ID is configured, take the ID of the first repository returned. if configured_main_repo_id == "": self._main_repo_id = all_repositories_ids[0] else: if configured_main_repo_id not in all_repositories_ids: raise CmisRepositoryDoesNotExist( "The configured repository ID does not exist.") self._main_repo_id = configured_main_repo_id return self._main_repo_id
def test_create_document_without_filename(self): # No bestandsnaam properties = { "bronorganisatie": "159351741", "integriteitwaarde": "Something", "verwijderd": "false", "ontvangstdatum": "2020-07-28", "versie": "1.0", "creatiedatum": "2018-06-27", "titel": "detailed summary", } cmis_properties = Document.build_properties(data=properties) other_folder = self.cmis_client.get_or_create_other_folder() soap_envelope = make_soap_envelope( auth=(self.cmis_client.user, self.cmis_client.password), repository_id=self.cmis_client.main_repo_id, folder_id=other_folder.objectId, properties=cmis_properties, cmis_action="createDocument", content_id=str(uuid.uuid4()), # No content_filename ) # If the pattern is not found, raises an exception. # The default filename is a random string of len 6 with characters A-Z and 0-9 re.search( r"<ns:filename>[0-9A-Z]{6}<\/ns:filename>", soap_envelope.toxml() ).group(0) self.assertIn( "<ns:mimeType>application/octet-stream</ns:mimeType>", soap_envelope.toxml() )
def get_content_object(self, drc_uuid: Union[str, UUID], object_type: str) -> CMISContentObject: """Get the gebruiksrechten/oio with specified uuid :param drc_uuid: string or UUID, the value of drc:oio__uuid or drc:gebruiksrechten__uuid :param object_type: string, either "gebruiksrechten" or "oio" :return: Either a Gebruiksrechten or ObjectInformatieObject """ assert object_type in [ "gebruiksrechten", "oio", ], "'object_type' can be only 'gebruiksrechten' or 'oio'" query = CMISQuery("SELECT * FROM drc:%s WHERE drc:%s__uuid = '%s'") soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, statement=query(object_type, object_type, str(drc_uuid)), cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) error_string = ( f"{object_type.capitalize()} {object_type} met identificatie drc:{object_type}__uuid {drc_uuid} " f"bestaat niet in het CMIS connection") does_not_exist = DocumentDoesNotExistError(error_string) try: soap_response = self.request("DiscoveryService", soap_envelope=soap_envelope.toxml()) # Corsa raises an error if the query retrieves 0 results except CmisRuntimeException as exc: if "objectNotFound" in exc.message: raise does_not_exist else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "query") if len(extracted_data) == 0: raise does_not_exist if object_type == "oio": return ObjectInformatieObject(extracted_data[0]) elif object_type == "gebruiksrechten": return Gebruiksrechten(extracted_data[0])
def create_folder(self, name: str, parent_id: str, data: dict = None) -> Folder: """Create a new folder inside a parent :param name: string, name of the new folder to create :param parent_id: string, cmis:objectId of the parent folder :param data: dict, contains the properties of the folder to create. The names of the properties are already converted to cmis names (e.g. drc:zaaktype__url) :return: Folder, the created folder """ object_type_id = CmisId("cmis:folder") properties = { "cmis:objectTypeId": { "value": object_type_id, "type": "propertyId" }, "cmis:name": { "value": name, "type": "propertyString" }, } if data is not None: properties.update(data) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, folder_id=parent_id, properties=properties, cmis_action="createFolder", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request("ObjectService", soap_envelope=soap_envelope.toxml()) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "createFolder")[0] # Creating a folder only returns the objectId folder_id = extracted_data["properties"]["objectId"]["value"] return self.get_folder(folder_id)
def get_document(self, drc_uuid: str, filters: Optional[dict] = None) -> Document: """Retrieve a document in the main repository with given uuid (drc:document__uuid) If the document series is checked out, it returns the private working copy :param drc_uuid: string, value of the cmis property drc:document__uuid :param filters: dict, filters to find the document :return: Document, latest document version """ error_string = f"Document met drc:document__uuid {drc_uuid} bestaat niet in het CMIS connection" does_not_exist = DocumentDoesNotExistError(error_string) if drc_uuid is None: raise does_not_exist # This always selects the latest version, and if there is a pwc, # Alfresco returns both the pwc and the latest major version, while Corsa only returns the pwc. query = CMISQuery( "SELECT * FROM drc:document WHERE drc:document__uuid = '%s' %s") filter_string = build_query_filters(filters, filter_string="AND ", strip_end=True) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, statement=query(drc_uuid, filter_string), cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.request("DiscoveryService", soap_envelope=soap_envelope.toxml()) # Corsa raises an error if the query retrieves 0 results except CmisRuntimeException as exc: if "objectNotFound" in exc.message: raise does_not_exist else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "query") return extract_latest_version(self.document_type, extracted_data)
def get_child_folder( self, name: str, child_type: dict = None ) -> Optional["Folder"]: """Get a folder in the current folder that has a specific name :param name: str, the cmis:name of the folder to retrieve :param child_type: dict, With keys "value" and "type". The value contains the object type ID of the children folders to retrieve. """ if child_type is not None: object_type_id = child_type["value"] # Alfresco case: the object type ID has an extra prefix (F:drc:zaakfolder, instead of drc:zaakfolder) # The prefix needs to be removed for the query if len(object_type_id.split(":")) > 2: object_type_id = ":".join(object_type_id.split(":")[1:]) else: object_type_id = "cmis:folder" query = CMISQuery( f"SELECT * FROM {object_type_id} WHERE cmis:parentId = '%s' AND cmis:name = '%s'" ) soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, statement=query(str(self.objectId), name), cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.client.request( "DiscoveryService", soap_envelope=soap_envelope.toxml() ) # Corsa raises an error if the query retrieves 0 results except CmisRuntimeException as exc: if "objectNotFound" in exc.message: return None else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml(xml_response, "query") if len(extracted_data) == 0: return None return type(self)(extracted_data[0])
def delete_object(self): """Delete all versions of an object""" soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=self.objectId, cmis_action="deleteObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response))
def delete_tree(self): """Delete the folder and all its contents""" # With Corsa, locked documents cause an error, so 'continue_on_failure' is needed soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, folder_id=self.objectId, cmis_action="deleteTree", continue_on_failure="true", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response))
def get_content_stream(self) -> BytesIO: soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=self.objectId, cmis_action="getContentStream", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml(), keep_binary=True ) xml_response = extract_xml_from_soap(soap_response, binary=True) logger.debug(pretty_xml(xml_response)) # FIXME find a better way to do this return extract_content(soap_response)
def get_all_versions(self) -> List["Document"]: object_id = self.objectId.split(";")[0] soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, cmis_action="getAllVersions", object_id=object_id, ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "VersioningService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getAllVersions" ) return [Document(data) for data in extracted_data]
def check_document_exists(self, identification: Union[str, UUID], bronorganisatie: str) -> None: """Check if a document with the same (identificatie, bronorganisatie) already exists in the repository :param identification: string, document ``identificatie`` :param bronorganisatie: string, document ``bronorganisatie`` """ cmis_identificatie = mapper("identificatie", type="document") cmis_bronorganisatie = mapper("bronorganisatie", type="document") query = CMISQuery( f"SELECT * FROM drc:document WHERE {cmis_identificatie} = '%s' AND {cmis_bronorganisatie} = '%s'" ) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, statement=query(str(identification), bronorganisatie), cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.request("DiscoveryService", soap_envelope=soap_envelope.toxml()) except CmisRuntimeException as exc: # Corsa raises an error if the query gives no results, while Alfresco a 200 if "objectNotFound" in exc.message: return else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "query") if len(extracted_data) > 0: raise DocumentExistsError( "Een document met dezelfde identificatie en bronorganisatie al bestaat." )
def checkin(self, checkin_comment: str, major: bool = True) -> "Document": soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, cmis_action="checkIn", object_id=str(self.objectId), major=str(major).lower(), checkin_comment=checkin_comment, ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "VersioningService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml(xml_response, "checkIn")[0] doc_id = extracted_data["properties"]["objectId"]["value"] return self.get_document(doc_id)
def set_content_stream(self, content: BytesIO, filename: Optional[str] = None): content_id = str(uuid.uuid4()) attachments = [(content_id, content)] soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=self.objectId, cmis_action="setContentStream", content_id=content_id, content_filename=filename, ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "ObjectService", soap_envelope=soap_envelope.toxml(), attachments=attachments, ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response))
def get_parent_folders(self) -> List["Folder"]: """Get all the parent folders of an object""" soap_envelope = make_soap_envelope( auth=(self.client.user, self.client.password), repository_id=self.client.main_repo_id, object_id=self.objectId, cmis_action="getObjectParents", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.client.request( "NavigationService", soap_envelope=soap_envelope.toxml() ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getObjectParents" ) return [Folder(data) for data in extracted_data]
def create_document( self, identification: str, bronorganisatie: str, data: dict, content: BytesIO = None, check_if_already_exists: bool = True, ) -> Document: """Create a custom Document (with the EnkelvoudigInformatieObject properties) :param identification: string, the document ``identificatie`` :param bronorganisatie: string, The identifier of the organisation. :param data: dict, the properties of the document :param content: BytesIO, the content of the document :param check_if_already_exists: Bool, whether to check if the document with given identificatie/bronorganisatie already exists in the DMS. :return: Document, the document created """ if check_if_already_exists and identification and bronorganisatie: self.check_document_exists(identification, bronorganisatie) data.setdefault("versie", "1") data.setdefault( "object_type_id", f"{self.get_object_type_id_prefix('document')}drc:document", ) data["bronorganisatie"] = bronorganisatie data["identificatie"] = identification content_id = str(uuid.uuid4()) if content is None: content = BytesIO() # Create Document in default folder other_folder = self.get_or_create_other_folder() properties = Document.build_properties(data, new=True) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, folder_id=other_folder.objectId, properties=properties, cmis_action="createDocument", content_id=content_id, content_filename=data.get("bestandsnaam"), ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request( "ObjectService", soap_envelope=soap_envelope.toxml(), attachments=[(content_id, content)], ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) # Creating the document only returns its ID extracted_data = extract_object_properties_from_xml( xml_response, "createDocument")[0] new_document_id = extracted_data["properties"]["objectId"]["value"] # Request all the properties of the newly created document soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, object_id=new_document_id, cmis_action="getObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request("ObjectService", soap_envelope=soap_envelope.toxml()) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getObject")[0] return Document(extracted_data)
def create_content_object( self, data: dict, object_type: str, destination_folder: Folder = None) -> CMISContentObject: """Create a Gebruiksrechten or a ObjectInformatieObject :param data: dict, properties of the object to create :param object_type: string, either "gebruiksrechten" or "oio" :param destination_folder: Folder, the folder in which to place the object :return: Either a Gebruiksrechten or ObjectInformatieObject """ assert object_type in [ "gebruiksrechten", "oio", ], "'object_type' can be only 'gebruiksrechten' or 'oio'" if object_type == "oio": return_type = ObjectInformatieObject data_class = Oio elif object_type == "gebruiksrechten": return_type = Gebruiksrechten data_class = GebruiksRechtDoc if destination_folder is None: other_folder = self.get_or_create_other_folder() destination_folder = self.get_or_create_folder( "Related data", other_folder) properties = return_type.build_properties(data) properties.setdefault( "cmis:objectTypeId", { "value": f"{self.get_object_type_id_prefix(object_type)}drc:{object_type}", "type": "propertyId", }, ) properties.setdefault("cmis:name", { "value": get_random_string(), "type": "propertyString" }) properties.setdefault( mapper("uuid", type=object_type), { "value": str(uuid.uuid4()), "type": get_cmis_type(data_class, "uuid") }, ) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, folder_id=destination_folder.objectId, properties=properties, cmis_action="createDocument", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request( "ObjectService", soap_envelope=soap_envelope.toxml(), ) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "createDocument")[0] new_object_id = extracted_data["properties"]["objectId"]["value"] # Request all the properties of the newly created object soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, object_id=new_object_id, cmis_action="getObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request("ObjectService", soap_envelope=soap_envelope.toxml()) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getObject")[0] return return_type(extracted_data)
def copy_gebruiksrechten(self, source_object: Gebruiksrechten, destination_folder: Folder) -> Gebruiksrechten: """Copy a gebruiksrechten to a folder :param source_object: Gebruiksrechten, the gebruiksrechten to copy :param destination_folder: Folder, the folder in which to place the copied gebruiksrechten :return: the copied object """ # copy the properties from the source document drc_properties = {} drc_url_properties = {} for property_name, property_details in source_object.properties.items( ): if ("cmis:" not in property_name and property_details["value"] is not None) or property_name == "cmis:objectTypeId": drc_property_name = reverse_mapper(property_name, type="gebruiksrechten") # Urls are handled separately, because they are already in the 'short' form if get_type(GebruiksRechtDoc, drc_property_name) == QueriableUrl: drc_url_properties[property_name] = { "value": property_details["value"], "type": "propertyString", } else: drc_properties[drc_property_name] = property_details[ "value"] cmis_properties = Gebruiksrechten.build_properties(drc_properties) cmis_properties.update( **{ "cmis:objectTypeId": { "value": source_object.objectTypeId, "type": "propertyId", }, mapper("kopie_van", type="gebruiksrechten"): { "value": source_object.objectId, "type": "propertyString", # Keep tack of where this is copied from. }, "cmis:name": { "value": get_random_string(), "type": "propertyString" }, "drc:gebruiksrechten__uuid": { "value": str(uuid.uuid4()), "type": "propertyString", }, **drc_url_properties, }) # Create copy gebruiksrechten soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, folder_id=destination_folder.objectId, properties=cmis_properties, cmis_action="createDocument", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request( "ObjectService", soap_envelope=soap_envelope.toxml(), ) # Creating the document only returns its ID xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "createDocument")[0] copy_gebruiksrechten_id = extracted_data["properties"]["objectId"][ "value"] # Request all the properties of the newly created object soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, object_id=copy_gebruiksrechten_id, cmis_action="getObject", ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request("ObjectService", soap_envelope=soap_envelope.toxml()) xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "getObject")[0] return Gebruiksrechten(extracted_data)
def copy_document(self, document: Document, destination_folder: Folder) -> Document: """Copy document to a folder :param document: Document, the document to copy :param destination_folder: Folder, the folder in which to place the copied document :return: the copied document """ # copy the properties from the source document drc_properties = {} drc_url_properties = {} for property_name, property_details in document.properties.items(): if ("cmis:" not in property_name and property_details["value"] is not None) or property_name == "cmis:objectTypeId": drc_property_name = reverse_mapper(property_name, type="document") # Urls are handled separately, because they are already in the 'short' form if (get_type(EnkelvoudigInformatieObject, drc_property_name) == QueriableUrl): drc_url_properties[property_name] = { "value": property_details["value"], "type": "propertyString", } else: drc_properties[drc_property_name] = property_details[ "value"] cmis_properties = Document.build_properties(drc_properties, new=False) cmis_properties.update( **{ "cmis:objectTypeId": { "value": document.objectTypeId, "type": "propertyId", }, mapper("titel", type="document"): { "value": f"{document.titel} - copy", "type": "propertyString", }, "drc:kopie_van": { "value": document.uuid, "type": "propertyString", }, # Keep tack of where this is copied from. "drc:document__uuid": { "value": str(uuid.uuid4()), "type": "propertyString", }, **drc_url_properties, }) # Update the cmis:name to make it more unique file_name = f"{document.titel}-{get_random_string()}" cmis_properties["cmis:name"] = { "value": file_name, "type": "propertyString" } # Create copy document content_id = str(uuid.uuid4()) soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, folder_id=destination_folder.objectId, properties=cmis_properties, cmis_action="createDocument", content_id=content_id, content_filename=drc_properties.get("bestandsnaam"), ) logger.debug(soap_envelope.toprettyxml()) soap_response = self.request( "ObjectService", soap_envelope=soap_envelope.toxml(), attachments=[(content_id, document.get_content_stream())], ) # Creating the document only returns its ID xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "createDocument")[0] copy_document_id = extracted_data["properties"]["objectId"]["value"] return document.get_document(copy_document_id)
def query(self, return_type_name: str, lhs: List[str] = None, rhs: List[str] = None) -> List[CMISBaseObject]: """Perform an SQL query in the DMS :param return_type_name: string, either Folder, Document, Oio or Gebruiksrechten :param lhs: list of strings, with the LHS of the SQL query :param rhs: list of strings, with the RHS of the SQL query :return: type, either Folder, Document, Oio or Gebruiksrechten """ return_type = self.get_return_type(return_type_name) processed_rhs = rhs # Any query that filters based on URL fields needs to be converted to use the short URL version if settings.CMIS_URL_MAPPING_ENABLED and lhs is not None and rhs is not None: processed_rhs = [] # Join all the queries and find which fields are used to filter joined_lhs = " ".join(lhs) column_names = re.findall(r"([a-z]+?:.+?__[a-z]+)", joined_lhs) for index, item_rhs in enumerate(rhs): column_name = column_names[index] property_name = reverse_mapper(column_name, type=return_type_name.lower()) if (property_name is not None and get_type( return_type.type_class, property_name) == QueriableUrl and item_rhs != ""): processed_rhs.append(shrink_url(item_rhs)) else: processed_rhs.append(item_rhs) table = return_type.table where = (" WHERE " + " AND ".join(lhs)) if lhs else "" query = CMISQuery("SELECT * FROM %s%s" % (table, where)) statement = query(*processed_rhs) if processed_rhs else query() soap_envelope = make_soap_envelope( auth=(self.user, self.password), repository_id=self.main_repo_id, statement=statement, cmis_action="query", ) logger.debug(soap_envelope.toprettyxml()) try: soap_response = self.request("DiscoveryService", soap_envelope=soap_envelope.toxml()) # Corsa raises an error if the query retrieves 0 results except CmisRuntimeException as exc: if "objectNotFound" in exc.message: return [] else: raise exc xml_response = extract_xml_from_soap(soap_response) logger.debug(pretty_xml(xml_response)) extracted_data = extract_object_properties_from_xml( xml_response, "query") return [return_type(cmis_object) for cmis_object in extracted_data]