def testDefaultRepository(self): """Get the default repository by calling the repo's service URL""" cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() assert repo is not None assert repo.getRepositoryId() is not None
def cmis_connect(url, username = '', password = ''): print print "** Connecting to %s" % url print "Environment variables: CMIS_URL, CMIS_USERNAME, CMIS_PASSWORD" client = CmisClient(url, username, password) print '** Connected to repository %s' % (client.getDefaultRepository().getRepositoryName()) print return client
def testTypeDefinition(self): """Get the cmis:document type and test a few props of the type.""" cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() docTypeDef = repo.getTypeDefinition('cmis:document') assert 'cmis:document' == docTypeDef.getTypeId() assert docTypeDef.baseId
def cmis_connect(self, cr, uid): """Connect to the CMIS Server and returns the document repository""" user = self.pool.get('res.users').browse(cr, uid, uid) server_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'document_cmis.server_url') if not server_url: raise osv.except_osv(_('Error!'),_("Cannot connect to the CMIS Server: No CMIS Server URL system property found")) client = CmisClient(server_url, user.login, user.password) repo = client.getDefaultRepository() return repo
def testGetRepository(self): """Get a repository by repository ID""" cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() defaultRepoId = repo.getRepositoryId() defaultRepoName = repo.getRepositoryName() repo = cmisClient.getRepository(defaultRepoId) assert defaultRepoId == repo.getRepositoryId() assert defaultRepoName == repo.getRepositoryName()
def testTypeProperties(self): """Get the properties for a type.""" cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() docTypeDef = repo.getTypeDefinition('cmis:document') assert 'cmis:document' == docTypeDef.getTypeId() props = docTypeDef.getProperties().values() assert len(props) > 0 for prop in props: if prop.queryable: assert prop.queryName assert prop.propertyType
def testTypeDescendants(self): """Get the descendant types of the repository.""" cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() typeDefs = repo.getTypeDescendants() folderDef = None for typeDef in typeDefs: if typeDef.getTypeId() == 'cmis:folder': folderDef = typeDef break assert folderDef assert folderDef.baseId
def testTypeChildren(self): """Get the child types for this repository and make sure cmis:folder is in the list.""" # This test would be more interesting if there was a standard way to # deploy a custom model. Then we could look for custom types. cmisClient = CmisClient(self.url, self.user, self.pwd, binding=self.binding, **self.ext_args) repo = cmisClient.getDefaultRepository() typeDefs = repo.getTypeChildren() folderDef = None for typeDef in typeDefs: if typeDef.getTypeId() == 'cmis:folder': folderDef = typeDef break assert folderDef assert folderDef.baseId
class RemoteClient(Client): """CMIS Client""" def __init__(self, repository_url, username, password, base_folder): self.repository_url = repository_url self.username = username self.password = password self.base_folder = base_folder self.client = CmisClient(repository_url, username, password) self.repo = self.client.getDefaultRepository() def get_descendants(self, path=""): result = [] remote_path = self.get_remote_path(path) object = self.repo.getObjectByPath(remote_path) children = object.getChildren() for child in children: properties = child.properties # Hack around some Nuxeo quirks child_name = properties['cmis:name'] if properties.has_key('cmis:path'): child_name = properties['cmis:path'].split('/')[-1] if child_name.startswith('.'): continue if path == "": child_path = child_name else: child_path = path + "/" + child_name state = self.make_state(child_path, properties) if state.type == 'folder': result += [state] + self.get_descendants(child_path) else: result += [state] return result def get_state(self, path): remote_path = self.get_remote_path(path) try: object = self.repo.getObjectByPath(remote_path) properties = object.properties return self.make_state(path, properties) except ObjectNotFoundException: return None def get_content(self, path): remote_path = self.get_remote_path(path) object = self.repo.getObjectByPath(remote_path) try: return object.getContentStream().read() except AssertionError: # No attached stream: bug in Nuxeo? return "" # Modifiers def mkdir(self, path): remote_path = self.get_remote_path(path) parent_path, name = os.path.split(remote_path) parent_folder = self.repo.getObjectByPath(parent_path) parent_folder.createFolder(name) def mkfile(self, path, content=None): remote_path = self.get_remote_path(path) parent_path, name = os.path.split(remote_path) parent_folder = self.repo.getObjectByPath(parent_path) content_file = StringIO(content) content_file.name = path.rsplit('/', 1)[-1] parent_folder.createDocument(name, contentFile=content_file) def update(self, path, content): remote_path = self.get_remote_path(path) object = self.repo.getObjectByPath(remote_path) content_file = StringIO(content) content_file.name = path.rsplit('/', 1)[-1] return object.setContentStream(content_file) # TODO: manage also mime type def delete(self, path): remote_path = self.get_remote_path(path) try: object = self.repo.getObjectByPath(remote_path) # XXX: hack, fix later try: object.delete() except: object.deleteTree() except ObjectNotFoundException: # nothing to delete pass # # Utilities # def get_remote_path(self, path): if path != "": return self.base_folder + "/" + path else: return self.base_folder def make_state(self, path, properties): if properties['cmis:baseTypeId'] == 'cmis:folder': type = 'folder' else: type = 'file' uid = properties['cmis:objectId'] mtime = properties['cmis:lastModificationDate'] return Info(path, uid, type, mtime)
class CMISStorage(Storage): """ Storage engine to upload and fetch files from a CMIS-enabled content management system, like Alfresco """ def __init__(self, base_folder=None): self.options = settings.CMIS_STORAGE_OPTIONS if 'baseFolder' not in self.options: self.options['baseFolder'] = '/' if base_folder: self.options['baseFolder'] = base_folder self.client = CmisClient(**self.options) self.repo = self.client.getDefaultRepository() def _open(self, name, mode='rb'): return File(self.open_stream(name), name=name) def open_stream(self, name): # Build the full path of the file full_path = os.path.join(self.options['baseFolder'], name.strip('./')) # Get the object from the CMS obj = self.repo.getObjectByPath(full_path) # type: cmislib.model.Document # Return the stream return obj.getContentStream() def _save(self, name, content): logger.debug("Saving file {}".format(name)) # Build the full path of the file full_path = os.path.join(self.options['baseFolder'], name.strip('.')) logger.debug("Full path at {}".format(full_path)) # Split the path dirname, filename = os.path.split(full_path) # Get the folder folder = self.repo.getObjectByPath(dirname) # Create the document newfile = folder.createDocument(filename, contentFile=content) # Get the new path for the file newfile_path = newfile.getPaths()[0] logger.debug("New path: {}".format(newfile_path)) return newfile_path def delete(self, name): logger.debug("Deleting file '{}'".format(name)) # Build the full path of the file full_path = os.path.join(self.options['baseFolder'], name.strip('./')) try: obj = self.repo.getObjectByPath(full_path) obj.delete() except cmislib.exceptions.ObjectNotFoundException: pass def exists(self, name): logger.debug("Checking if file exists '{}'".format(name)) # Build the full path of the file full_path = os.path.join(self.options['baseFolder'], name.strip('./')) try: self.repo.getObjectByPath(full_path) except cmislib.exceptions.ObjectNotFoundException: return False return True def path(self, name): return name def _props(self, name): # Build the full path of the file full_path = os.path.join(self.options['baseFolder'], name.strip('./')) # Get the object from the CMS obj = self.repo.getObjectByPath(full_path) # type: cmislib.model.Document return obj.getProperties() def modified_time(self, name): """ Returns the last modification date for the specified file """ return self._props(name).get('cmis:lastModificationDate', None) def accessed_time(self, name): return None def created_time(self, name): return self._props(name).get('cmis:creationDate', None) def size(self, name): return self._props(name).get('cmis:contentStreamLength', 0) def listdir(self, path): try: folder = self.repo.getObjectByPath(path) if not isinstance(folder, cmislib.models.Folder): return [] return [x.getName() for x in folder.getChildren()] except ObjectNotFoundException as e: return [] def url(self, name): return reverse('cmis_storage_get_file', kwargs={'path': name})
class CmisTracPlugin(Component): implements(INavigationContributor, IRequestHandler, ITemplateProvider, IPermissionRequestor) def __init__(self): Component.__init__(self) self.url_api = None self.user = None self.password = None self.base_path = None self.max_size = None self.cmis_client = None self.repository = None self.root_cmis_object = None # INavigationContributor methods def get_active_navigation_item(self, req): return 'documents' def get_navigation_items(self, req): if req.perm.has_permission('REPOSITORY_BROWSER'): yield ('mainnav', 'documents', tag.a('Documents', href=req.href.documents())) # IRequestHandler methods def match_request(self, req): '''Check if applicable to this plugin''' match = re.match('^(/documents)(/)?(workspace://SpacesStore/)?([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})?(/)?(newfolder|removefolder|renamefolder|upload|download|removedocument)?$', req.path_info) self._print("cmistracplugin: Check req.path_info: [" + req.path_info + "] match: [" + ("true" if match else "false") + "]") if match: if match.group(4) != None: req.args['objectId'] = match.group(4) if match.group(6) != None: req.args['op'] = match.group(6) return True else: return False def process_request(self, req): '''Processes the request. Input validation and call the corresponding method''' req.perm.assert_permission('REPOSITORY_BROWSER') self.load_config() xhr = req.get_header('X-Requested-With') == 'XMLHttpRequest' add_script(req, 'common/js/expand_dir.js') add_stylesheet(req, 'common/css/browser.css') add_stylesheet(req, 'hw/cmistracplugin.css') if xhr: return 'folder-entries.html', self._render_cmis_object(req, xhr), None elif 'op' in req.args and req.args['op'] == 'newfolder': if 'objectId' in req.args: return 'new-folder.html', self._prepare_newfolder_form(req), None else: self._process_newfolder_form(req) req.redirect(req.href.documents(req.args['objectId'])) elif 'op' in req.args and req.args['op'] == 'removefolder': if 'objectId' in req.args: self._process_removefolder(req) req.redirect(req.href.documents(req.args['objectId'])) elif 'op' in req.args and req.args['op'] == 'renamefolder': if 'objectId' in req.args: if req.method == 'GET': return 'rename-folder.html', self._prepare_renamefolder_form(req), None else: self._process_renamefolder_form(req) if req.args['parentId']: req.redirect(req.href.documents(req.args['parentId'])) else: req.redirect(req.href.documents(req.args['objectId'])) elif 'op' in req.args and req.args['op'] == 'upload': if 'objectId' in req.args: return 'upload-document.html', self._prepare_upload_form(req), None elif 'cancel' in req.args: req.redirect(req.href.documents(req.args['parentId'])) else: self._process_upload_form(req) req.redirect(req.href.documents(req.args['objectId'])) elif 'op' in req.args and req.args['op'] == 'download': if 'objectId' in req.args: self._process_download(req) elif 'op' in req.args and req.args['op'] == 'removedocument': if 'objectId' in req.args: self._process_removedocument(req) if req.session['lastCmisFolderIdVisited']: req.redirect(req.href.documents(req.session['lastCmisFolderIdVisited'])) else: req.redirect(req.href.documents()) else: self._print("cmistracplugin: go to 'repository-browser.html'") return 'repository-browser.html', self._render_cmis_object(req), None # ITemplateProvider methods def get_templates_dirs(self): return [pkg_resources.resource_filename(__name__, 'templates')] def get_htdocs_dirs(self): return [('hw', pkg_resources.resource_filename(__name__, 'htdocs'))] # IPermissionRequestor methods def get_permission_actions(self): return ['REPOSITORY_BROWSER', 'REPOSITORY_UPLOAD', 'REPOSITORY_DOWNLOAD', 'REPOSITORY_CREATE_FOLDER', 'REPOSITORY_REMOVE_FOLDER', 'REPOSITORY_RENAME_FOLDER', 'REPOSITORY_REMOVE_DOCUMENT'] def load_config(self): '''Read available configurations options from trac.ini''' self.url_api = self.env.config.get('cmis', 'url_api') self.user = self.env.config.get('cmis', 'user') self.password = self.env.config.get('cmis', 'password') self.base_path = self.env.config.get('cmis', 'base_path') self.max_size = self.env.config.getint('cmis', 'max_size') self.log.info('Plugin Configuration loaded') try: self.cmis_client = CmisClient(self.url_api, self.user, self.password) self.repository = self.cmis_client.getDefaultRepository() self.root_cmis_object = self.repository.getObjectByPath(self.base_path) except: raise TracError('Unable to connect to the repository. Check the configuration') def _render_cmis_object(self, req, xhr = None): if 'objectId' in req.args: selt._print("cmis: get object: [" + str(req.args['objectId']) + "]") cmis_object = self.repository.getObject(req.args['objectId']) else: cmis_object = self.root_cmis_object data = {} data['rootFolder'] = self.root_cmis_object self._print("p1: cmistracplugin: cmis:objectTypeId: " + cmis_object.getProperties()['cmis:objectTypeId']) if cmis_object.getProperties()['cmis:objectTypeId'] in ['cmis:folder', 'Folder', 'Section', 'Workspace']: #if cmis_object.getProperties()['cmis:objectTypeId'] == 'cmis:folder' || cmis_object.getProperties()['cmis:objectTypeId'] == 'cmis:Section': cmis_objects = cmis_object.getChildren().getResults() data['breadcrumb'] = render_breadcrumb(self.cmis_client, self.repository, self.root_cmis_object, cmis_object) if cmis_object.getObjectId() != self.root_cmis_object.getObjectId(): data['parentId'] = cmis_object.getProperties()['cmis:parentId'] data['cmis_objectTypeId'] = 'cmis:folder' self._print("cmistracplugin: len(cmis_object.getChildren().getResults()): " + str(len(cmis_objects))) for idx in range(len(cmis_objects)): self._printCmisObjetc(cmis_objects[idx]) data['cmis_objects'] = cmis_objects add_ctxtnav(req, tag.a('New folder', href=req.href.documents(cmis_object.getProperties()['cmis:objectId'], 'newfolder'))) add_ctxtnav(req, tag.a('Remove folder', href=req.href.documents(cmis_object.getProperties()['cmis:objectId'], 'removefolder'))) add_ctxtnav(req, tag.a('Rename folder', href=req.href.documents(cmis_object.getProperties()['cmis:objectId'], 'renamefolder'))) add_ctxtnav(req, tag.a('Upload document', href=req.href.documents(cmis_object.getProperties()['cmis:objectId'], 'upload'))) elif cmis_object.getProperties()['cmis:objectTypeId'] == 'cmis:document': data['breadcrumb'] = render_breadcrumb(self.cmis_client, self.repository, self.root_cmis_object, cmis_object) data['cmis_objectTypeId'] = 'cmis:document' data['cmis_object'] = cmis_object else: self._print("cmistracplugin: Unknow cmis:objectTypeId: " + cmis_object.getProperties()['cmis:objectTypeId']) self._printCmisObjetc(cmis_object) if cmis_object.getProperties()['cmis:objectTypeId'] == 'cmis:folder' and xhr == None: req.session['lastCmisFolderIdVisited'] = cmis_object.getObjectId() return data def _prepare_newfolder_form(self, req): req.perm.require('REPOSITORY_CREATE_FOLDER') data = { 'parentId': req.args['objectId'] } return data def _process_newfolder_form(self, req): '''Processes the request to create a new directory''' req.perm.require('REPOSITORY_CREATE_FOLDER') if req.method == 'POST' and 'name' in req.args and 'parentId' in req.args: if 'name' in req.args and req.args['name'] != '': parent_folder = self.repository.getObject(req.args['parentId']) parent_folder.createFolder(req.args['name'].encode('utf-8')) req.args['objectId'] = req.args['parentId'] del req.args['parentId'] else: raise TracError('The folder name can not be empty') self.log.info('A new folder has been created') def _process_removefolder(self, req): '''Processes the request to remove a folder''' req.perm.require('REPOSITORY_REMOVE_FOLDER') if 'objectId' in req.args: cmis_object = self.repository.getObject(req.args['objectId']) if cmis_object.getObjectId() == self.root_cmis_object.getObjectId(): raise TracError('Can\'t remove root folder') parent_folder = self.repository.getObject(cmis_object.getProperties()['cmis:parentId']) cmis_object.deleteTree() req.args['objectId'] = parent_folder.getObjectId() self.log.info('A folder has been removed') def _prepare_upload_form(self, req): req.perm.require('REPOSITORY_UPLOAD') data = { 'parentId': req.args['objectId'], 'max_size': self.max_size } return data def _process_upload_form(self, req): req.perm.require('REPOSITORY_UPLOAD') upload = req.args['document'] if not hasattr(upload, 'filename') or not upload.filename: raise TracError('No file uploaded') if hasattr(upload.file, 'fileno'): size = os.fstat(upload.file.fileno())[6] else: upload.file.seek(0, 2) # seek to end of file size = upload.file.tell() upload.file.seek(0) if size == 0: raise TracError('Can\'t upload empty document') if size > self.max_size: raise TracError('Maximum document size: %s KB' % self.max_size) # We try to normalize the filename to unicode NFC if we can. # Files uploaded from OS X might be in NFD. filename = unicodedata.normalize('NFC', unicode(upload.filename, 'utf-8')) filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) if not filename: raise TracError('No file uploaded') if 'parentId' in req.args: cmis_object = self.repository.getObject(req.args['parentId']) if cmis_object.getProperties()['cmis:objectTypeId'] == 'cmis:folder': cmis_object.createDocument(filename.encode('utf-8'), contentFile = upload.file, contentType = upload.type) req.args['objectId'] = req.args['parentId'] del req.args['parentId'] self.log.info('A document has been saved') def _process_download(self, req): req.perm.require('REPOSITORY_DOWNLOAD') cmis_object = self.repository.getObject(req.args['objectId']) # Validar que es un objecto de tipo documento content = cmis_object.getContentStream() req.send_response(200) req.send_header('Content-Type', cmis_object.getProperties()['cmis:contentStreamMimeType']) req.send_header('Content-Length', cmis_object.getProperties()['cmis:contentStreamLength']) req.send_header('Last-Modified', cmis_object.getProperties()['cmis:lastModificationDate']) req.send_header('Content-Disposition', 'attachment; filename="%s"' % cmis_object.getName()) req.end_headers() chunk = content.read(CHUNK_SIZE) while 1: if not chunk: raise RequestDone req.write(chunk) chunk = content.read(CHUNK_SIZE) self.log.info('A document has been downloaded') def _prepare_renamefolder_form(self, req): req.perm.require('REPOSITORY_RENAME_FOLDER') cmis_object = self.repository.getObject(req.args['objectId']) data = { 'cmis_object': cmis_object } return data def _process_renamefolder_form(self, req): req.perm.require('REPOSITORY_RENAME_FOLDER') folder = self.repository.getObject(req.args['objectId']) parent_folder = folder.getParent() props = { 'cmis:name': req.args['name'].encode('utf-8') } folder.updateProperties(props) if parent_folder: req.args['parentId'] = parent_folder.getObjectId() self.log.info('A folder has been renamed') def _process_removedocument(self, req): req.perm.require('REPOSITORY_REMOVE_DOCUMENT') if 'objectId' in req.args: cmis_object = self.repository.getObject(req.args['objectId']) cmis_object.delete() self.log.info('A document has been removed') def _printCmisObjetc(self, cmis_object): self._print("-- cmis:objectTypeId :: [" + cmis_object.getProperties()['cmis:objectTypeId'] + "] -- cmis:objectId :: [" + cmis_object.getProperties()['cmis:objectId'] + "]") _props = cmis_object.getProperties() for _key in _props: self._print("--- cmis_object.getProperties()['" + _key + "'] :: " + str(_props[_key])) def _print(self, _str): print _str self.log.debug(_str)
import time import base64 import xmlrpclib from cmislib.model import CmisClient, Repository server = "localhost" dbname = "natuurpunt" uid = 1 pwd = "n2aevl8w" # replace localhost wity the address of the server sock = xmlrpclib.ServerProxy("http://%s:8069/xmlrpc/object" % (server)) """Connect to the CMIS Server and returns the document repository""" client = CmisClient("http://192.168.1.225:8080/alfresco/s/cmis", "admin", "a2aevl8w") repo = client.getDefaultRepository() def process(cmis_naam, cmis_object_id): print "***** Start processing {} *****".format(cmis_naam) process_cmis_dir(repo.getObject(cmis_object_id)) print "***** End processing {} *****".format(cmis_naam) def process_cmis_dir(cmisDir): query = ( """ select cmis:objectId, cmis:name from cmis:folder where in_folder('%s') order by cmis:lastModificationDate desc
def main(): """Main method (split it if you want cleaner code. Creates a folder called "TEST", then stuffs if with the content of the local folder specified in config.py. """ client = CmisClient(REPOSITORY_URL, USERNAME, PASSWORD) repo = client.getDefaultRepository() root_folder = repo.getObjectByPath(REMOTE_PATH) # Removes the TEST folder if it already exists try: object = repo.getObjectByPath(REMOTE_PATH + "/TEST") object.deleteTree() except: pass root_folder.createFolder("TEST") start_time = time.time() for root, dirs, files in os.walk(LOCAL_PATH): root_rel = root[len(LOCAL_PATH) :] remote_parent = repo.getObjectByPath(REMOTE_PATH + "/TEST" + root_rel) for dir in dirs: # FIXME later: skip non-ascii file names if dir.encode("ascii", errors="replace") != dir: continue print "----" print ("creating dir: %s" % dir).encode("ascii", errors="replace") remote_parent.createFolder(dir) for file in files: # FIXME later: skip non-ascii file names if file.encode("ascii", errors="replace") != file: continue print "----" if os.stat(os.path.join(root, file)).st_size > 1e6: print ("File %s too big, skipping" % file).encode("ascii", errors="replace") continue print ("Creating file: %s" % file).encode("ascii", errors="replace"), try: local_fd = open(os.path.join(root, file)) created = remote_parent.createDocument(file, contentFile=local_fd) local_fd.close() print "OK" except AssertionError, e: print "KO: exception raised" print e except CmisException, e: print "KO: exception raised" print e print "nNote: remote name is:", created.properties["cmis:name"].encode("ascii", errors="replace") print ("Verifying file: %s" % file).encode("ascii", errors="replace"), try: path = REMOTE_PATH + "/TEST" + root_rel + "/" + file object = repo.getObjectByPath(path) remote_fd = object.getContentStream() local_fd = open(os.path.join(root, file)) if compare(local_fd, remote_fd): print "OK" else: print "KO: Content differs" except AssertionError, e: print "KO: exception raised" print e