diff --git a/core/src/core/doc/api2.json b/core/src/core/doc/api2.json
index b6d9d45932..f7381641e6 100644
--- a/core/src/core/doc/api2.json
+++ b/core/src/core/doc/api2.json
@@ -1 +1 @@
-{"swagger":"2.0","host":"localhost","schemes":["http"],"basePath":"/api/v2","info":{"version":"2.0.0","title":"Pydio API V2","description":"Access to a Pydio Server. Second version of the API."},"paths":{"/fs/{path}":{"get":{"x-pydio-action":"ls","description":"Get information about a node and its metadata. By default, it will return \nPydio \"primary\" metadata (stat, internal informations). Extended metadata can\nbe added by some plugins. \nFor collections (folders), pass the **children** parameter to list its content. \nTo access the actual content of the nodes, see the I/O API.\n","operationId":"getNodeInfos","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"meta","in":"query","description":"Level of precision for expected metadata","type":"string","enum":["minimal","standard","extended"],"required":true,"default":"standard"},{"name":"children","in":"query","description":"Load children if node is a collection","required":false,"type":"string","enum":["dfz","d","df","f","fz","z","dz"]},{"name":"recursive","in":"formData","description":"If requiring children, load grandchildren recursively","type":"boolean","required":false},{"name":"max_depth","in":"formData","description":"If requiring children recursively, stop at the given depth. If -1, no limit.","type":"integer","required":false,"default":-1},{"name":"max_nodes","in":"formData","description":"If requiring children recursively, stop at the given depth. If -1, no limit.","type":"integer","required":false,"default":-1},{"name":"remote_order","in":"formData","description":"Apply server-side sorting","type":"boolean","required":false,"default":false},{"name":"order_column","in":"formData","description":"Order column to use for server-side sorting","type":"string","required":false},{"name":"order_direction","in":"formData","description":"Order direction to use for server-side sorting (asc or desc)","type":"string","required":false},{"name":"page_position","in":"formData","description":"For a single file, try to detect the page position in the parent node listing.","type":"boolean","required":false,"default":false},{"name":"X-Indexation-Required","in":"header","description":"Invalidate current index and trigger a background indexation","type":"boolean","required":false}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Node"}}},"tags":["File"]},"post":{"x-pydio-action":"fs_create_resource","description":"Create new resources or move/copy existing resources:\n+ Create a new folder (pass a path **with a trailing slash**), or a new empty file (no trailing slash).\n+ Copy a resource to a new destination: pass destination as {path}, and origin via copy_from parameter.\n+ Rename / Move a resource : basically a copy operation followed by a delete of original\n","operationId":"createNode","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"copy_source","in":"query","description":"If it's a move or a copy, indicated the path of the original node","type":"string","required":false},{"name":"delete_source","in":"query","description":"If it's a move/rename, will remove original after copy operation","required":false,"type":"boolean"},{"name":"override","in":"query","description":"Ignore existing resource and override it","required":false,"type":"boolean","default":false}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"patch":{"x-pydio-action":"fs_update_metadata","description":"Update existing resources metadata (see I/O for content modification). Basic metadata is provided by core plugins, but they can be extended by other plugins.\nFor example :\n`{\"core\": {\"chmod\": 777}}, {\"user_meta\":[{\"metaName\":\"metaValue\"}]}`\n`{\"bookmarks\":{\"bookmarked\": true}, \"locks\":{\"locked\":true}, \"meta.watch\":{\"watch\":true}}`\netc...\n","operationId":"updateNode","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"metadata","in":"formData","description":"Json-serialized metadata to update","type":"string","required":true}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"delete":{"x-pydio-action":"delete","description":"Delete existing resource\n","operationId":"deleteNode","parameters":[{"$ref":"#/parameters/pathParameter"}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]}},"/io/{path}":{"get":{"x-pydio-action":"download","description":"Get resource content. Depending on the attachment parameter, will try to either trigger a download, or send binary stream with appropriate headers. Depending on the active plugins, may be able to serve: + Plain text + MP3/Wav Stream + MP4 Stream + On-the-fly generated images + On-the-fly generated thumbnails for images or pdf\n","operationId":"download","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"attachment","in":"query","description":"if set, send back a force-download, otherwise use Accept header to try to find the best response Content-Type.","type":"boolean","required":false},{"name":"additional_parameters","in":"query","description":"some plugin can take more parameters to send various contents\nderived from main resource. For example, for images, you can pass\nget_thumb & dimension\n","type":"string","required":false}],"produces":["application/octet-stream"],"responses":{"200":{"description":"Successful Response","schema":{"type":"file"}}},"tags":["File"]},"put":{"x-pydio-action":"upload","description":"Create resource by posting to Input Stream\n","operationId":"uploadStream","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"inputStream","in":"body","description":"binary data","required":true,"schema":{"$ref":"#/definitions/InputStream"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"post":{"x-pydio-action":"upload","description":"Create resource by posting via form Data\n","operationId":"upload","consumes":["multipart/form-data"],"parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"userfile_0","in":"formData","description":"File to upload","required":true,"type":"file"}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"patch":{"x-pydio-action":"upload","description":"Update existing resource via form Data\n","operationId":"appendData","consumes":["multipart/form-data"],"parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"append","in":"formData","description":"wether to replace content or append at the end of the existing resource","required":true,"default":true,"type":"boolean"},{"name":"userfile_0","in":"formData","description":"File to upload","required":true,"type":"file"}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]}},"/tasks":{"get":{"description":"List tasks currently running on the server (and visible to the current user).\n","operationId":"listTasks","x-pydio-plugin":"core.tasks","x-pydio-action":"tasks_list","parameters":[{"name":"filter","in":"formData","description":"additional filters for task listing (JSON serialized)","type":"string","required":false},{"$ref":"#/parameters/workspaceIdFormParameter"},{"$ref":"#/parameters/nodeSelectionParameter"}],"responses":{"200":{"description":"Successful Response","schema":{"type":"array","items":{"$ref":"#/definitions/Task"}}}},"tags":["Task"]}},"/tasks/{taskId}":{"get":{"description":"Get information about a currently running task Id\n","operationId":"getTaskInfo","x-pydio-plugin":"core.tasks","x-pydio-action":"task_info","parameters":[{"name":"taskId","in":"path","description":"Task to monitor on the server","type":"string","required":true}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"post":{"description":"Create a task on the server. This will generally trigger a server-side background \"Task\", which ID will be returned in the PydioResponse['tasks'] array\n","operationId":"createTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_create","consumes":["application/json"],"parameters":[{"name":"taskId","in":"path","description":"Task to launch on the server","type":"string","required":true},{"name":"request_body","in":"body","description":"JSON Task object","schema":{"$ref":"#/definitions/Task"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"patch":{"description":"Update a task on the server.\n","operationId":"updateTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_update","consumes":["application/json"],"parameters":[{"name":"taskId","in":"path","description":"Task to update on the server","type":"string","required":true},{"name":"request_body","in":"body","description":"JSON Diff describing the patches to apply on the task object","schema":{"$ref":"#/definitions/Task"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"delete":{"description":"Update a task on the server.\n","operationId":"deleteTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_delete","parameters":[{"name":"taskId","in":"path","description":"Task to delete on the server","type":"string","required":true}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]}},"/workspaces":{"get":{"description":"List accessible workspace for currently logged user. Alias for /state/?xPath=user/repositories\n","operationId":"listWorkspaces","produces":["application/json"],"x-pydio-plugin":"meta.quota","x-pydio-action":"monitor_quota","responses":{"200":{"description":"Successful Response","schema":{"type":"object"}}},"tags":["Workspace"]}},"/workspaces/{workspaceId}":{"get":{"description":"Get information about the given workspace.\nInfo can be gathered via various plugins. Pass the expected metadata type via the X-Pydio-Ws-Info header. Currently supported values are quota|info|changes\n","operationId":"getWorkspaceInfo","produces":["application/json"],"parameters":[{"name":"X-Pydio-WS-Info","in":"header","required":true,"type":"string","enum":["quota","info"]},{"$ref":"#/parameters/workspaceIdParameter"}],"x-pydio-plugin":"meta.quota","x-pydio-action":"monitor_quota","responses":{"200":{"description":"Successful Response","schema":{"type":"object","properties":{"USAGE":{"type":"integer"},"TOTAL":{"type":"integer"}}}}},"tags":["Workspace"]}},"/workspaces/{workspaceId}/changes/{sequenceId}":{"get":{"description":"Sends back all changes since a given sequence ID. \n\nThis plugin requires **meta.syncable** active on the workspace.\n","operationId":"changes","produces":["application/json"],"parameters":[{"name":"sequenceId","in":"path","description":"File to upload","required":true,"type":"integer"},{"$ref":"#/parameters/workspaceIdParameter"}],"x-pydio-plugin":"meta.syncable","x-pydio-action":"changes","responses":{"200":{"description":"Successful Response","schema":{"type":"array","items":{"type":"object","properties":{"seq_id":{"type":"integer"},"node":{"$ref":"#/definitions/Node"}}}}}},"tags":["Workspace"]}},"/admin/roles":{"get":{"x-pydio-action":"ls","description":"List roles\n","operationId":"getRoles","produces":["application/json","application/xml"],"responses":{"200":{"description":"A list of roles represented as standard nodes","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]}},"/admin/roles/{roleId}":{"get":{"x-pydio-action":"edit_role","description":"Get Role by Id\n","operationId":"getRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"load_fill_values","in":"query","description":"Load additional data to build a form for editing this role","type":"boolean","required":false}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]},"delete":{"x-pydio-action":"delete","description":"Delete Role by Id\n","operationId":"deleteRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to delete","type":"string","required":true}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"post":{"x-pydio-action":"create_role","description":"Create a new role with this ID\n","operationId":"createRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"role","in":"body","schema":{"$ref":"#/definitions/Role"},"description":"JSON description of the new role","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]},"patch":{"x-pydio-action":"post_json_role","description":"Update the role\n","operationId":"updateRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"role","in":"body","schema":{"$ref":"#/definitions/Role"},"description":"JSON description of the new role","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]}},"/admin/people/{path}":{"get":{"x-pydio-action":"ls","description":"List roles\n","operationId":"getPeople","produces":["application/json","application/xml"],"parameters":[{"$ref":"#/parameters/peopleParameterOptional"},{"name":"list","in":"query","description":"list children of the current resource","type":"boolean","default":true}],"responses":{"200":{"description":"A user/group or list of users and groups","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]},"delete":{"x-pydio-action":"people-delete-resource","description":"Delete Role by Id\n","operationId":"deletePeople","parameters":[{"$ref":"#/parameters/peopleParameter"}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"post":{"x-pydio-action":"people-create-resource","description":"Create a new user or a new group with this path. To create a user, make sure to pass a userPass parameter. Otherwise it will create a group.\n","operationId":"createPeople","parameters":[{"$ref":"#/parameters/peopleParameter"},{"name":"resourceType","in":"formData","type":"string","enum":["user","group"],"description":"Wether it's a user or a group","required":true},{"name":"groupLabel","in":"formData","type":"string","description":"Label of the new group if we are creating a group","required":false},{"name":"userPass","in":"formData","type":"string","description":"Password of the new user if we are creating a user","required":false}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"patch":{"x-pydio-action":"people-patch-resource","description":"Update user or group specific data with this path. Use resourceType parameter to discriminate, and send a parameterName/parameterValue couple to be patched.\n\nAuthorized parameterName values are described below, along with the parameterValue corresponding specification: \n- For groups\n - groupLabel : relabel an existing group\n- For users\n - userPass: change user password\n - userProfile: update user profile\n - userLock: set/remove a lock on a user. Value must be a lockname:lockvalue string where lockvalue is \"true\" or \"fale\".\n - userRoles: Bunch update roles, eventually reorder them, as a JSON encoded array.\n - userAddRole: add a role to the user\n - userRemoveRole: remove a role currently applied to the user.\n - userPreferences: a JSON associative array of key/values to update.\n\nTo edit user/group permissions or parameters, use the role api instead, using the object specific role_id (AJXP_GRP_/groupPath or AJXP_USR_/userId).\n","operationId":"patchPeople","parameters":[{"$ref":"#/parameters/peopleParameter"},{"name":"resourceType","in":"query","type":"string","enum":["user","group"],"description":"Wether it's a user or a group","required":true},{"name":"patch-tuple","in":"body","schema":{"$ref":"#/definitions/PeoplePatch"},"description":"parameterName / parameterValue association","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]}},"/admin/workspaces":{"get":{"x-pydio-action":"ls","description":"List Workspaces\n","operationId":"adminListWorkspaces","produces":["application/json","application/xml"],"responses":{"200":{"description":"A list of workspaces represented as standard nodes","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]}},"/admin/workspaces/{workspaceId}":{"get":{"x-pydio-action":"edit_repository","description":"Load detail of a workspace\n","operationId":"adminGetWorkspace","parameters":[{"name":"workspaceId","in":"path","description":"Load detail of this workspace","type":"string","required":true}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"A workspace represented as a node","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]}}},"parameters":{"pathParameter":{"name":"path","in":"path","description":"Workspace id or alias + full path to the node","required":true,"type":"string"},"workspaceIdParameter":{"name":"workspaceId","in":"path","description":"Id or Alias of the workspace","required":true,"type":"string"},"workspaceIdFormParameter":{"name":"workspaceId","in":"formData","description":"Id or Alias of the workspace","required":true,"type":"string"},"nodeSelectionParameter":{"name":"path","in":"formData","description":"One or more node pathes","required":false,"type":"array","items":{"type":"string"},"collectionFormat":"multi"},"peopleParameter":{"name":"path","in":"path","description":"User or group identifier, including full group path","required":true,"type":"string"},"peopleParameterOptional":{"name":"path","in":"path","description":"User or group identifier, including full group path (optional)","required":true,"type":"string"}},"definitions":{"PydioResponse":{"title":"PydioResponse","description":"Generic container for messages after successful operations or errors","type":"object","properties":{"message":{"type":"string"},"level":{"type":"string"},"errorCode":{"type":"integer"},"nodesDiff":{"$ref":"#/definitions/NodesDiff"},"bgAction":{"$ref":"#/definitions/BgAction"},"tasks":{"type":"array","items":{"$ref":"#/definitions/Task"}}}},"Task":{"title":"Task","description":"Background operation started on the server. It's the client mission to check it on a regular basis.","type":"object","properties":{"id":{"type":"string"},"status":{"type":"integer"},"label":{"type":"string"},"description":{"type":"string"},"userId":{"type":"string"},"wsId":{"type":"string"},"actionName":{"type":"string"},"schedule":{"type":"object","properties":{"scheduleType":{"type":"string"},"scheduleValue":{"type":"string"}}},"parameters":{"type":"object"}}},"BgAction":{"title":"BgAction","description":"triggers a background action on the client side","type":"object","properties":{"actionName":{"type":"string"},"delay":{"type":"integer"}}},"Node":{"title":"Node","description":"A file or folder represented as a generic resource, including metadata and children. Properties before children are part of the \"standard\" metadat set, properties after are returned by the \"extended\" metadata set.","type":"object","properties":{"path":{"type":"string"},"is_leaf":{"type":"boolean"},"label":{"type":"string"},"ajxp_modiftime":{"type":"integer"},"bytesize":{"type":"integer"},"children":{"$ref":"#/definitions/NodeList"},"stat":{"type":"object"},"ajxp_relativetime":{"type":"string"},"ajxp_description":{"type":"string"},"icon":{"type":"string"},"filesize":{"type":"string"},"mimestring_id":{"type":"string"},"ajxp_readonly":{"type":"boolean"},"file_perms":{"type":"string"},"repo_has_recycle":{"type":"boolean"},"childrenPagination":{"$ref":"#/definitions/PaginationData"}}},"NodesDiff":{"title":"NodesDiff","description":"Description of node removed / added / updated in the backend","type":"object","properties":{"add":{"type":"array","items":{"$ref":"#/definitions/Node"}},"update":{"type":"array","description":"Nodes may have an additional attribute original_path","items":{"$ref":"#/definitions/Node"}},"remove":{"type":"array","items":{"type":"string"}}}},"NodeList":{"title":"NodeList","description":"List of Node objects","type":"array","items":{"$ref":"#/definitions/Node"}},"PaginationData":{"title":"PaginationData","description":"Additional metadata attached to a NodeList for pagination. Could be sent through headers instead.","type":"object","properties":{"count":{"type":"integer","description":"total number of children"},"current":{"type":"integer","description":"current page"},"total":{"type":"integer","description":"total number of pages"},"dirs":{"type":"integer","description":"total number of \"collection\" childrens"},"remoteSort":{"type":"object","description":"additional attributes describing current server-side sorting"}}},"InputStream":{"title":"InputStream","description":"Simple binary stream","type":"string"},"Role":{"title":"Role","description":"Representation of a Role, central container of permissions, actions and parameters.","type":"object","properties":{"ACL":{"type":"object","description":"Key/value associating workspace IDs and rights strings (r/w)"},"MASKS":{"type":"object","description":"Folders permissions masks"},"PARAMETERS":{"type":"object","description":"Refined values of plugins parameters"},"ACTIONS":{"type":"object","description":"Enabled/disabled actions of plugins"},"APPLIES":{"type":"object","description":"Set of profiles on which this role automatically applies"}}},"PeoplePatch":{"title":"PeoplePatch","description":"a key / value tuple describing which parameter to patch","type":"object","properties":{"resourceType":{"type":"string","enum":["user","group"]},"parameterName":{"type":"string","enum":["groupLabel","userPass","userProfile","userLock","userRoles","userAddRole","userRemoveRole","userPreferences"]},"parameterValue":{"type":"string"}}}}}
\ No newline at end of file
+{"swagger":"2.0","host":"localhost","schemes":["http"],"basePath":"/api/v2","info":{"version":"2.0.0","title":"Pydio API V2","description":"Access to a Pydio Server. Second version of the API."},"paths":{"/fs/{path}":{"get":{"x-pydio-action":"ls","description":"Get information about a node and its metadata. By default, it will return \nPydio \"primary\" metadata (stat, internal informations). Extended metadata can\nbe added by some plugins. \nFor collections (folders), pass the **children** parameter to list its content. \nTo access the actual content of the nodes, see the I/O API.\n","operationId":"getNodeInfos","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"meta","in":"query","description":"Level of precision for expected metadata","type":"string","enum":["minimal","standard","extended"],"required":true,"default":"standard"},{"name":"children","in":"query","description":"Load children if node is a collection","required":false,"type":"string","enum":["dfz","d","df","f","fz","z","dz"]},{"name":"recursive","in":"formData","description":"If requiring children, load grandchildren recursively","type":"boolean","required":false},{"name":"max_depth","in":"formData","description":"If requiring children recursively, stop at the given depth. If -1, no limit.","type":"integer","required":false,"default":-1},{"name":"max_nodes","in":"formData","description":"If requiring children recursively, stop at the given depth. If -1, no limit.","type":"integer","required":false,"default":-1},{"name":"remote_order","in":"formData","description":"Apply server-side sorting","type":"boolean","required":false,"default":false},{"name":"order_column","in":"formData","description":"Order column to use for server-side sorting","type":"string","required":false},{"name":"order_direction","in":"formData","description":"Order direction to use for server-side sorting (asc or desc)","type":"string","required":false},{"name":"page_position","in":"formData","description":"For a single file, try to detect the page position in the parent node listing.","type":"boolean","required":false,"default":false},{"name":"X-Indexation-Required","in":"header","description":"Invalidate current index and trigger a background indexation","type":"boolean","required":false}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Node"}}},"tags":["File"]},"post":{"x-pydio-action":"fs_create_resource","description":"Create new resources or move/copy existing resources:\n+ Create a new folder (pass a path **with a trailing slash**), or a new empty file (no trailing slash).\n+ Copy a resource to a new destination: pass destination as {path}, and origin via copy_from parameter.\n+ Rename / Move a resource : basically a copy operation followed by a delete of original\n","operationId":"createNode","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"copy_source","in":"query","description":"If it's a move or a copy, indicated the path of the original node","type":"string","required":false},{"name":"delete_source","in":"query","description":"If it's a move/rename, will remove original after copy operation","required":false,"type":"boolean"},{"name":"override","in":"query","description":"Ignore existing resource and override it","required":false,"type":"boolean","default":false}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"patch":{"x-pydio-action":"fs_update_metadata","description":"Update existing resources metadata (see I/O for content modification). Basic metadata is provided by core plugins, but they can be extended by other plugins.\nFor example :\n`{\"core\": {\"chmod\": 777}}, {\"user_meta\":[{\"metaName\":\"metaValue\"}]}`\n`{\"bookmarks\":{\"bookmarked\": true}, \"locks\":{\"locked\":true}, \"meta.watch\":{\"watch\":true}}`\netc...\n","operationId":"updateNode","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"metadata","in":"formData","description":"Json-serialized metadata to update","type":"string","required":true}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"delete":{"x-pydio-action":"delete","description":"Delete existing resource\n","operationId":"deleteNode","parameters":[{"$ref":"#/parameters/pathParameter"}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]}},"/io/{path}":{"get":{"x-pydio-action":"download","description":"Get resource content. Depending on the attachment parameter, will try to either trigger a download, or send binary stream with appropriate headers. Depending on the active plugins, may be able to serve: + Plain text + MP3/Wav Stream + MP4 Stream + On-the-fly generated images + On-the-fly generated thumbnails for images or pdf\n","operationId":"download","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"attachment","in":"query","description":"if set, send back a force-download, otherwise use Accept header to try to find the best response Content-Type.","type":"boolean","required":false},{"name":"additional_parameters","in":"query","description":"some plugin can take more parameters to send various contents\nderived from main resource. For example, for images, you can pass\nget_thumb & dimension\n","type":"string","required":false}],"produces":["application/octet-stream"],"responses":{"200":{"description":"Successful Response","schema":{"type":"file"}}},"tags":["File"]},"put":{"x-pydio-action":"upload","description":"Create resource by posting to Input Stream\n","operationId":"uploadStream","parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"inputStream","in":"body","description":"binary data","required":true,"schema":{"$ref":"#/definitions/InputStream"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"post":{"x-pydio-action":"upload","description":"Create resource by posting via form Data\n","operationId":"upload","consumes":["multipart/form-data"],"parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"userfile_0","in":"formData","description":"File to upload","required":true,"type":"file"}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]},"patch":{"x-pydio-action":"upload","description":"Update existing resource via form Data\n","operationId":"appendData","consumes":["multipart/form-data"],"parameters":[{"$ref":"#/parameters/pathParameter"},{"name":"append","in":"formData","description":"wether to replace content or append at the end of the existing resource","required":true,"default":true,"type":"boolean"},{"name":"userfile_0","in":"formData","description":"File to upload","required":true,"type":"file"}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["File"]}},"/tasks":{"get":{"description":"List tasks currently running on the server (and visible to the current user).\n","operationId":"listTasks","x-pydio-plugin":"core.tasks","x-pydio-action":"tasks_list","parameters":[{"name":"filter","in":"formData","description":"additional filters for task listing (JSON serialized)","type":"string","required":false},{"$ref":"#/parameters/workspaceIdFormParameter"},{"$ref":"#/parameters/nodeSelectionParameter"}],"responses":{"200":{"description":"Successful Response","schema":{"type":"array","items":{"$ref":"#/definitions/Task"}}}},"tags":["Task"]}},"/tasks/{taskId}":{"get":{"description":"Get information about a currently running task Id\n","operationId":"getTaskInfo","x-pydio-plugin":"core.tasks","x-pydio-action":"task_info","parameters":[{"name":"taskId","in":"path","description":"Task to monitor on the server","type":"string","required":true}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"post":{"description":"Create a task on the server. This will generally trigger a server-side background \"Task\", which ID will be returned in the PydioResponse['tasks'] array\n","operationId":"createTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_create","consumes":["application/json"],"parameters":[{"name":"taskId","in":"path","description":"Task to launch on the server","type":"string","required":true},{"name":"request_body","in":"body","description":"JSON Task object","schema":{"$ref":"#/definitions/Task"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"patch":{"description":"Update a task on the server.\n","operationId":"updateTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_update","consumes":["application/json"],"parameters":[{"name":"taskId","in":"path","description":"Task to update on the server","type":"string","required":true},{"name":"request_body","in":"body","description":"JSON Diff describing the patches to apply on the task object","schema":{"$ref":"#/definitions/Task"}}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]},"delete":{"description":"Update a task on the server.\n","operationId":"deleteTask","x-pydio-plugin":"core.tasks","x-pydio-action":"task_delete","parameters":[{"name":"taskId","in":"path","description":"Task to delete on the server","type":"string","required":true}],"responses":{"200":{"description":"Successful Response","schema":{"$ref":"#/definitions/Task"}}},"tags":["Task"]}},"/workspaces":{"get":{"description":"List accessible workspace for currently logged user. Alias for /state/?xPath=user/repositories\n","operationId":"listWorkspaces","produces":["application/json"],"x-pydio-plugin":"meta.quota","x-pydio-action":"monitor_quota","responses":{"200":{"description":"Successful Response","schema":{"type":"object"}}},"tags":["Workspace"]}},"/workspaces/{workspaceId}":{"get":{"description":"Get information about the given workspace.\nInfo can be gathered via various plugins. Pass the expected metadata type via the X-Pydio-Ws-Info header. Currently supported values are quota|info|changes\n","operationId":"getWorkspaceInfo","produces":["application/json"],"parameters":[{"name":"X-Pydio-WS-Info","in":"header","required":true,"type":"string","enum":["quota","info"]},{"$ref":"#/parameters/workspaceIdParameter"}],"x-pydio-plugin":"meta.quota","x-pydio-action":"monitor_quota","responses":{"200":{"description":"Successful Response","schema":{"type":"object","properties":{"USAGE":{"type":"integer"},"TOTAL":{"type":"integer"}}}}},"tags":["Workspace"]}},"/workspaces/{workspaceId}/changes/{sequenceId}":{"get":{"description":"Sends back all changes since a given sequence ID. \n\nThis plugin requires **meta.syncable** active on the workspace.\n","operationId":"changes","produces":["application/json"],"parameters":[{"name":"sequenceId","in":"path","description":"File to upload","required":true,"type":"integer"},{"$ref":"#/parameters/workspaceIdParameter"}],"x-pydio-plugin":"meta.syncable","x-pydio-action":"changes","responses":{"200":{"description":"Successful Response","schema":{"type":"array","items":{"type":"object","properties":{"seq_id":{"type":"integer"},"node":{"$ref":"#/definitions/Node"}}}}}},"tags":["Workspace"]}},"/admin/roles":{"get":{"x-pydio-action":"ls","description":"List roles\n","operationId":"getRoles","produces":["application/json","application/xml"],"responses":{"200":{"description":"A list of roles represented as standard nodes","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]}},"/admin/roles/{roleId}":{"get":{"x-pydio-action":"edit_role","description":"Get Role by Id\n","operationId":"getRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"load_fill_values","in":"query","description":"Load additional data to build a form for editing this role","type":"boolean","required":false}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]},"delete":{"x-pydio-action":"delete","description":"Delete Role by Id\n","operationId":"deleteRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to delete","type":"string","required":true}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"post":{"x-pydio-action":"create_role","description":"Create a new role with this ID\n","operationId":"createRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"role","in":"body","schema":{"$ref":"#/definitions/Role"},"description":"JSON description of the new role","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]},"patch":{"x-pydio-action":"post_json_role","description":"Update the role\n","operationId":"updateRole","parameters":[{"name":"roleId","in":"path","description":"Id of the role to load","type":"string","required":true},{"name":"role","in":"body","schema":{"$ref":"#/definitions/Role"},"description":"JSON description of the new role","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/Role"}}},"tags":["Provisioning"]}},"/admin/people/{path}":{"get":{"x-pydio-action":"ls","description":"List roles\n","operationId":"getPeople","produces":["application/json","application/xml"],"parameters":[{"$ref":"#/parameters/peopleParameterOptional"},{"name":"list","in":"query","description":"list children of the current resource","type":"boolean","default":true}],"responses":{"200":{"description":"A user/group or list of users and groups","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]},"delete":{"x-pydio-action":"people-delete-resource","description":"Delete Role by Id\n","operationId":"deletePeople","parameters":[{"$ref":"#/parameters/peopleParameter"}],"produces":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"post":{"x-pydio-action":"people-create-resource","description":"Create a new user or a new group with this path. To create a user, make sure to pass a userPass parameter. Otherwise it will create a group.\n","operationId":"createPeople","parameters":[{"$ref":"#/parameters/peopleParameter"},{"name":"resourceType","in":"formData","type":"string","enum":["user","group"],"description":"Wether it's a user or a group","required":true},{"name":"groupLabel","in":"formData","type":"string","description":"Label of the new group if we are creating a group","required":false},{"name":"userPass","in":"formData","type":"string","description":"Password of the new user if we are creating a user","required":false}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]},"patch":{"x-pydio-action":"people-patch-resource","description":"Update user or group specific data with this path. Use resourceType parameter to discriminate, and send a parameterName/parameterValue couple to be patched.\n\nAuthorized parameterName values are described below, along with the parameterValue corresponding specification: \n- For groups\n - groupLabel : relabel an existing group\n- For users\n - userPass: change user password\n - userProfile: update user profile\n - userLock: set/remove a lock on a user. Value must be a lockname:lockvalue string where lockvalue is \"true\" or \"fale\".\n - userRoles: Bunch update roles, eventually reorder them, as a JSON encoded array.\n - userAddRole: add a role to the user\n - userRemoveRole: remove a role currently applied to the user.\n - userPreferences: a JSON associative array of key/values to update.\n\nTo edit user/group permissions or parameters, use the role api instead, using the object specific role_id (AJXP_GRP_/groupPath or AJXP_USR_/userId).\n","operationId":"patchPeople","parameters":[{"$ref":"#/parameters/peopleParameter"},{"name":"resourceType","in":"query","type":"string","enum":["user","group"],"description":"Wether it's a user or a group","required":true},{"name":"patch-tuple","in":"body","schema":{"$ref":"#/definitions/PeoplePatch"},"description":"parameterName / parameterValue association","required":true}],"produces":["application/json"],"consumes":["application/json"],"responses":{"200":{"description":"Successful response","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]}},"/admin/workspaces":{"get":{"x-pydio-action":"ls","description":"List Workspaces\n","operationId":"adminListWorkspaces","produces":["application/json","application/xml"],"responses":{"200":{"description":"A list of workspaces represented as standard nodes","schema":{"$ref":"#/definitions/Node"}}},"tags":["Provisioning"]}},"/admin/workspaces/{workspaceId}":{"get":{"x-pydio-action":"edit_repository","description":"Load detail of a workspace\n","operationId":"adminGetWorkspace","parameters":[{"name":"workspaceId","in":"path","description":"Load detail of this workspace","type":"string","required":true},{"name":"load_fill_values","in":"query","description":"Load additional data to build a form for editing this role","type":"boolean","required":false}],"produces":["application/json","application/xml"],"responses":{"200":{"description":"A workspace represented as a node","schema":{"$ref":"#/definitions/PydioResponse"}}},"tags":["Provisioning"]}}},"parameters":{"pathParameter":{"name":"path","in":"path","description":"Workspace id or alias + full path to the node","required":true,"type":"string"},"workspaceIdParameter":{"name":"workspaceId","in":"path","description":"Id or Alias of the workspace","required":true,"type":"string"},"workspaceIdFormParameter":{"name":"workspaceId","in":"formData","description":"Id or Alias of the workspace","required":true,"type":"string"},"nodeSelectionParameter":{"name":"path","in":"formData","description":"One or more node pathes","required":false,"type":"array","items":{"type":"string"},"collectionFormat":"multi"},"peopleParameter":{"name":"path","in":"path","description":"User or group identifier, including full group path","required":true,"type":"string"},"peopleParameterOptional":{"name":"path","in":"path","description":"User or group identifier, including full group path (optional)","required":true,"type":"string"}},"definitions":{"PydioResponse":{"title":"PydioResponse","description":"Generic container for messages after successful operations or errors","type":"object","properties":{"message":{"type":"string"},"level":{"type":"string"},"errorCode":{"type":"integer"},"nodesDiff":{"$ref":"#/definitions/NodesDiff"},"bgAction":{"$ref":"#/definitions/BgAction"},"tasks":{"type":"array","items":{"$ref":"#/definitions/Task"}}}},"Task":{"title":"Task","description":"Background operation started on the server. It's the client mission to check it on a regular basis.","type":"object","properties":{"id":{"type":"string"},"status":{"type":"integer"},"label":{"type":"string"},"description":{"type":"string"},"userId":{"type":"string"},"wsId":{"type":"string"},"actionName":{"type":"string"},"schedule":{"type":"object","properties":{"scheduleType":{"type":"string"},"scheduleValue":{"type":"string"}}},"parameters":{"type":"object"}}},"BgAction":{"title":"BgAction","description":"triggers a background action on the client side","type":"object","properties":{"actionName":{"type":"string"},"delay":{"type":"integer"}}},"Node":{"title":"Node","description":"A file or folder represented as a generic resource, including metadata and children. Properties before children are part of the \"standard\" metadat set, properties after are returned by the \"extended\" metadata set.","type":"object","properties":{"path":{"type":"string"},"is_leaf":{"type":"boolean"},"label":{"type":"string"},"ajxp_modiftime":{"type":"integer"},"bytesize":{"type":"integer"},"children":{"$ref":"#/definitions/NodeList"},"stat":{"type":"object"},"ajxp_relativetime":{"type":"string"},"ajxp_description":{"type":"string"},"icon":{"type":"string"},"filesize":{"type":"string"},"mimestring_id":{"type":"string"},"ajxp_readonly":{"type":"boolean"},"file_perms":{"type":"string"},"repo_has_recycle":{"type":"boolean"},"childrenPagination":{"$ref":"#/definitions/PaginationData"}}},"NodesDiff":{"title":"NodesDiff","description":"Description of node removed / added / updated in the backend","type":"object","properties":{"add":{"type":"array","items":{"$ref":"#/definitions/Node"}},"update":{"type":"array","description":"Nodes may have an additional attribute original_path","items":{"$ref":"#/definitions/Node"}},"remove":{"type":"array","items":{"type":"string"}}}},"NodeList":{"title":"NodeList","description":"List of Node objects","type":"array","items":{"$ref":"#/definitions/Node"}},"PaginationData":{"title":"PaginationData","description":"Additional metadata attached to a NodeList for pagination. Could be sent through headers instead.","type":"object","properties":{"count":{"type":"integer","description":"total number of children"},"current":{"type":"integer","description":"current page"},"total":{"type":"integer","description":"total number of pages"},"dirs":{"type":"integer","description":"total number of \"collection\" childrens"},"remoteSort":{"type":"object","description":"additional attributes describing current server-side sorting"}}},"InputStream":{"title":"InputStream","description":"Simple binary stream","type":"string"},"Role":{"title":"Role","description":"Representation of a Role, central container of permissions, actions and parameters.","type":"object","properties":{"ACL":{"type":"object","description":"Key/value associating workspace IDs and rights strings (r/w)"},"MASKS":{"type":"object","description":"Folders permissions masks"},"PARAMETERS":{"type":"object","description":"Refined values of plugins parameters"},"ACTIONS":{"type":"object","description":"Enabled/disabled actions of plugins"},"APPLIES":{"type":"object","description":"Set of profiles on which this role automatically applies"}}},"PeoplePatch":{"title":"PeoplePatch","description":"a key / value tuple describing which parameter to patch","type":"object","properties":{"resourceType":{"type":"string","enum":["user","group"]},"parameterName":{"type":"string","enum":["groupLabel","userPass","userProfile","userLock","userRoles","userAddRole","userRemoveRole","userPreferences"]},"parameterValue":{"type":"string"}}}}}
\ No newline at end of file
diff --git a/core/src/plugins/access.ajxp_conf/src/RepositoriesManager.php b/core/src/plugins/access.ajxp_conf/src/RepositoriesManager.php
index 7f50f1cff3..ca305ba50f 100644
--- a/core/src/plugins/access.ajxp_conf/src/RepositoriesManager.php
+++ b/core/src/plugins/access.ajxp_conf/src/RepositoriesManager.php
@@ -22,9 +22,11 @@
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
+use Pydio\Access\Core\AbstractAccessDriver;
use Pydio\Access\Core\Filter\AJXP_PermissionMask;
use Pydio\Access\Core\Model\AJXP_Node;
use Pydio\Access\Core\Model\NodesList;
+use Pydio\Access\Core\Model\Repository;
use Pydio\Core\Controller\XMLWriter;
use Pydio\Core\Exception\PydioException;
use Pydio\Core\Http\Message\ReloadMessage;
@@ -33,6 +35,7 @@
use Pydio\Core\Http\Response\SerializableResponseStream;
use Pydio\Core\Model\Context;
use Pydio\Core\Model\ContextInterface;
+use Pydio\Core\Model\RepositoryInterface;
use Pydio\Core\PluginFramework\Plugin;
use Pydio\Core\PluginFramework\PluginsService;
use Pydio\Core\Services\AuthService;
@@ -224,6 +227,8 @@ public function repositoriesActions(ServerRequestInterface $requestInterface, Re
}else{
$repId = $httpVars["repository_id"];
}
+ $format = isSet($httpVars["format"]) && $httpVars["format"] == "json" ? "json" : "xml";
+
$repository = RepositoryService::getRepositoryById($repId);
if ($repository == null) {
throw new \Exception("Cannot find workspace with id $repId");
@@ -232,11 +237,11 @@ public function repositoriesActions(ServerRequestInterface $requestInterface, Re
throw new \Exception("You are not allowed to edit this workspace!");
}
$pServ = PluginsService::getInstance($ctx);
+ /** @var AbstractAccessDriver $plug */
$plug = $pServ->getPluginById("access.".$repository->getAccessType());
if ($plug == null) {
throw new \Exception("Cannot find access driver (".$repository->getAccessType().") for workspace!");
}
- $buffer = "";
$slug = $repository->getSlug();
if ($slug == "" && $repository->isWriteable()) {
$repository->setSlug();
@@ -250,105 +255,21 @@ public function repositoriesActions(ServerRequestInterface $requestInterface, Re
$repository->setWriteable(false);
}
}
- $nested = array();
- $definitions = $plug->getConfigsDefinitions();
- $buffer .= "securityScope()."\"";
- foreach ($repository as $name => $option) {
- if(strstr($name, " ")>-1) continue;
- if ($name == "driverInstance") continue;
- if (!is_array($option)) {
- if (is_bool($option)) {
- $option = ($option?"true":"false");
- }
- $buffer .= " $name=\"".TextEncoder::toUTF8(StringHelper::xmlEntities($option))."\" ";
- } else if (is_array($option)) {
- $nested[] = $option;
- }
- }
- if (count($nested)) {
- $buffer .= ">" ;
- foreach ($nested as $option) {
- foreach ($option as $key => $optValue) {
- if (is_array($optValue) && count($optValue)) {
- $buffer .= "" ;
- } else if (is_object($optValue)){
- $buffer .= "";
- } else {
- if (is_bool($optValue)) {
- $optValue = ($optValue?"true":"false");
- } else if(isSet($definitions[$key]) && $definitions[$key]["type"] == "password" && !empty($optValue)){
- $optValue = "__AJXP_VALUE_SET__";
- }
-
- $optValue = StringHelper::xmlEntities($optValue, true);
- $buffer .= "";
- }
- }
- }
- // Add SLUG
- if(!$repository->isTemplate()) {
- $buffer .= "getSlug()."\"/>";
- }
- if ($repository->getGroupPath() != null) {
- $groupPath = $repository->getGroupPath();
- if($currentAdminBasePath != "/") $groupPath = substr($repository->getGroupPath(), strlen($currentAdminBasePath));
- $buffer .= "";
- }
- $buffer .= "";
- } else {
- $buffer .= "/>";
- }
- if ($repository->hasParent()) {
- $parent = RepositoryService::getRepositoryById($repository->getParentId());
- if (isSet($parent) && $parent->isTemplate()) {
- $parentLabel = $parent->getDisplay();
- $parentType = $parent->getAccessType();
- $buffer .= "getParentId()."\" repository_label=\"$parentLabel\" repository_type=\"$parentType\">";
- foreach ($parent->getOptionsDefined() as $parentOptionName) {
- $buffer .= "";
- }
- }
- $manifest = $plug->getManifestRawContent("server_settings/param");
- $manifest = XMLWriter::replaceAjxpXmlKeywords($manifest);
- $clientSettings = $plug->getManifestRawContent("client_settings", "xml");
- $iconClass = "";$descriptionTemplate = "";
- if($clientSettings->length){
- $iconClass = $clientSettings->item(0)->getAttribute("iconClass");
- $descriptionTemplate = $clientSettings->item(0)->getAttribute("description_template");
- }
- $buffer .= "getAccessType()."\" label=\"". StringHelper::xmlEntities($plug->getManifestLabel()) ."\" iconClass=\"$iconClass\" description_template=\"$descriptionTemplate\" description=\"". StringHelper::xmlEntities($plug->getManifestDescription()) ."\">$manifest";
- $buffer .= "";
- $metas = $pServ->getPluginsByType("metastore");
- $metas = array_merge($metas, $pServ->getPluginsByType("meta"));
- $metas = array_merge($metas, $pServ->getPluginsByType("index"));
- /** @var Plugin $metaPlug */
- foreach ($metas as $metaPlug) {
- $buffer .= "getId()."\" label=\"". StringHelper::xmlEntities($metaPlug->getManifestLabel()) ."\" description=\"". StringHelper::xmlEntities($metaPlug->getManifestDescription()) ."\">";
- $manifest = $metaPlug->getManifestRawContent("server_settings/param");
- $manifest = XMLWriter::replaceAjxpXmlKeywords($manifest);
- $buffer .= $manifest;
- $buffer .= "";
- }
- $buffer .= "";
- if(!$repository->isTemplate()){
- $buffer .= "";
- $users = UsersService::countUsersForRepository($ctx, $repId, false, true);
- $cursor = ["count"];
- $shares = ConfService::getConfStorageImpl()->simpleStoreList("share", $cursor, "", "serial", '', $repId);
- $buffer .= '';
- $buffer .= '';
- $rootGroup = RolesService::getRole("AJXP_GRP_/");
- if($rootGroup !== false && $rootGroup->hasMask($repId)){
- $buffer .= "getMask($repId))."]]>";
+ $definitions = $plug->getConfigsDefinitions();
+ if($format === "json"){
+ $data = $this->serializeRepositoryToJSON($ctx, $repository, $definitions, $currentAdminBasePath);
+ if(isSet($httpVars["load_fill_values"]) && $httpVars["load_fill_values"] === "true"){
+ $data["PARAMETERS_INFO"] = $this->serializeRepositoryDriverInfos($pServ, $format, $plug, $repository);
}
- $buffer .= "";
+ $responseInterface = new JsonResponse($data);
+ }else{
+ $buffer = "";
+ $buffer .= $this->serializeRepositoryToXML($ctx, $repository, $definitions, $currentAdminBasePath);
+ $buffer .= $this->serializeRepositoryDriverInfos($pServ, $format, $plug, $repository);
+ $buffer .= "";
+ $responseInterface = $responseInterface->withBody(new SerializableResponseStream(new XMLDocMessage($buffer)));
}
- $buffer .= "";
-
- $responseInterface = $responseInterface->withBody(new SerializableResponseStream(new XMLDocMessage($buffer)));
break;
@@ -809,6 +730,248 @@ public function metaSourceOrderingFunction($key1, $key2)
return strcmp($key1, $key2);
}
+ /**
+ * @param ContextInterface $ctx
+ * @param RepositoryInterface $repository
+ * @param array $definitions
+ * @param string $currentAdminBasePath
+ * @return array
+ */
+ protected function serializeRepositoryToJSON(ContextInterface $ctx, $repository, $definitions, $currentAdminBasePath){
+ $nested = [];
+ $buffer = [
+ "id" => $repository->getId(),
+ "securityScope" => $repository->securityScope()
+ ];
+ if(!$repository->isTemplate()){
+ $buffer["slug"] = $repository->getSlug();
+ }
+ $groupPath = $repository->getGroupPath();
+ if ($groupPath != null) {
+ if($currentAdminBasePath != "/") {
+ $groupPath = substr($repository->getGroupPath(), strlen($currentAdminBasePath));
+ }
+ $buffer["groupPath"]= $groupPath;
+ }
+ foreach ($repository as $name => $option) {
+ if(strstr($name, " ")>-1) continue;
+ if ($name == "driverInstance") continue;
+ if(is_array($option)) {
+ $nested[] = $option;
+ } else{
+ $buffer[$name] = $option;
+ }
+ }
+ if (count($nested)) {
+ $buffer["PARAMETERS"]= [];
+
+ foreach ($nested as $option) {
+ foreach ($option as $key => $optValue) {
+ if(isSet($definitions[$key]) && $definitions[$key]["type"] == "password" && !empty($optValue)){
+ $optValue = "__AJXP_VALUE_SET__";
+ }
+ $buffer["PARAMETERS"][$key] = $optValue;
+ }
+ }
+ // Add SLUG
+ if(!empty($buffer["slug"])) {
+ $buffer["PARAMETERS"]["AJXP_SLUG"] = $buffer["slug"];
+ }
+ if(!empty($buffer["groupPath"])) {
+ $buffer["PARAMETERS"]["AJXP_GROUP_PATH_PARAMETER"] = $buffer["groupPath"];
+ }
+ }
+ if(!$repository->isTemplate()){
+ $buffer["INFO"]= [];
+ $users = UsersService::countUsersForRepository($ctx, $repository->getId(), false, true);
+ $cursor = ["count"];
+ $shares = ConfService::getConfStorageImpl()->simpleStoreList("share", $cursor, "", "serial", '', $repository->getId());
+ $buffer["INFO"] = [
+ "users" => $users,
+ "shares" => count($shares)
+ ];
+ $rootGroup = RolesService::getRole("AJXP_GRP_/");
+ if($rootGroup !== false && $rootGroup->hasMask($repository->getId())){
+ $buffer["MASK"]= $rootGroup->getMask($repository->getId());
+ }
+ }
+ if ($repository->hasParent()) {
+ $parent = RepositoryService::getRepositoryById($repository->getParentId());
+ if (isSet($parent) && $parent->isTemplate()) {
+ $parentLabel = $parent->getDisplay();
+ $parentType = $parent->getAccessType();
+ $buffer["TEMPLATE"] = [
+ "id" => $repository->getParentId(),
+ "label" => $parentLabel,
+ "type" => $parentType,
+ "DEFINED_PARAMETERS" => []
+ ];
+ foreach ($parent->getOptionsDefined() as $parentOptionName) {
+ $buffer["TEMPLATE"]["DEFINED_PARAMETERS"][] = $parentOptionName;
+ }
+ }
+ }
+ return $buffer;
+ }
+
+ /**
+ * @param ContextInterface $ctx
+ * @param RepositoryInterface $repository
+ * @param array $definitions
+ * @param string $currentAdminBasePath
+ * @return string
+ */
+ protected function serializeRepositoryToXML(ContextInterface $ctx, $repository, $definitions, $currentAdminBasePath){
+ $nested = [];
+ $buffer = "getId()."\" securityScope=\"".$repository->securityScope()."\"";
+ foreach ($repository as $name => $option) {
+ if(strstr($name, " ")>-1) continue;
+ if ($name == "driverInstance") continue;
+ if (!is_array($option)) {
+ if (is_bool($option)) {
+ $option = ($option?"true":"false");
+ }
+ $buffer .= " $name=\"".TextEncoder::toUTF8(StringHelper::xmlEntities($option))."\" ";
+ } else if (is_array($option)) {
+ $nested[] = $option;
+ }
+ }
+ if (count($nested)) {
+ $buffer .= ">" ;
+ foreach ($nested as $option) {
+ foreach ($option as $key => $optValue) {
+ if (is_array($optValue) && count($optValue)) {
+ $buffer .= "" ;
+ } else if (is_object($optValue)){
+ $buffer .= "";
+ } else {
+ if (is_bool($optValue)) {
+ $optValue = ($optValue?"true":"false");
+ } else if(isSet($definitions[$key]) && $definitions[$key]["type"] == "password" && !empty($optValue)){
+ $optValue = "__AJXP_VALUE_SET__";
+ }
+
+ $optValue = StringHelper::xmlEntities($optValue, true);
+ $buffer .= "";
+ }
+ }
+ }
+ // Add SLUG
+ if(!$repository->isTemplate()) {
+ $buffer .= "getSlug()."\"/>";
+ }
+ if ($repository->getGroupPath() != null) {
+ $groupPath = $repository->getGroupPath();
+ if($currentAdminBasePath != "/") $groupPath = substr($repository->getGroupPath(), strlen($currentAdminBasePath));
+ $buffer .= "";
+ }
+
+ $buffer .= "";
+ } else {
+ $buffer .= "/>";
+ }
+ if ($repository->hasParent()) {
+ $parent = RepositoryService::getRepositoryById($repository->getParentId());
+ if (isSet($parent) && $parent->isTemplate()) {
+ $parentLabel = $parent->getDisplay();
+ $parentType = $parent->getAccessType();
+ $buffer .= "getParentId()."\" repository_label=\"$parentLabel\" repository_type=\"$parentType\">";
+ foreach ($parent->getOptionsDefined() as $parentOptionName) {
+ $buffer .= "";
+ }
+ }
+ if(!$repository->isTemplate()){
+ $buffer .= "";
+ $users = UsersService::countUsersForRepository($ctx, $repository->getId(), false, true);
+ $cursor = ["count"];
+ $shares = ConfService::getConfStorageImpl()->simpleStoreList("share", $cursor, "", "serial", '', $repository->getId());
+ $buffer .= '';
+ $buffer .= '';
+ $rootGroup = RolesService::getRole("AJXP_GRP_/");
+ if($rootGroup !== false && $rootGroup->hasMask($repository->getId())){
+ $buffer .= "getMask($repository->getId()))."]]>";
+ }
+ $buffer .= "";
+ }
+ return $buffer;
+ }
+
+ /**
+ * @param PluginsService $pServ
+ * @param string $format
+ * @param AbstractAccessDriver $plug
+ * @param RepositoryInterface $repository
+ * @return string|array
+ */
+ protected function serializeRepositoryDriverInfos(PluginsService $pServ, $format, $plug, $repository){
+ $manifest = $plug->getManifestRawContent("server_settings/param");
+ $manifest = XMLWriter::replaceAjxpXmlKeywords($manifest);
+ $clientSettings = $plug->getManifestRawContent("client_settings", "xml");
+ $iconClass = "";$descriptionTemplate = "";
+ if($clientSettings->length){
+ $iconClass = $clientSettings->item(0)->getAttribute("iconClass");
+ $descriptionTemplate = $clientSettings->item(0)->getAttribute("description_template");
+ }
+ $metas = $pServ->getPluginsByType("metastore");
+ $metas = array_merge($metas, $pServ->getPluginsByType("meta"));
+ $metas = array_merge($metas, $pServ->getPluginsByType("index"));
+
+ if($format === "xml"){
+ $buffer = "getAccessType()."\" label=\"". StringHelper::xmlEntities($plug->getManifestLabel()) ."\"
+ iconClass=\"$iconClass\" description_template=\"$descriptionTemplate\"
+ description=\"". StringHelper::xmlEntities($plug->getManifestDescription()) ."\">$manifest";
+
+ $buffer .= "";
+ /** @var Plugin $metaPlug */
+ foreach ($metas as $metaPlug) {
+ $buffer .= "getId()."\" label=\"". StringHelper::xmlEntities($metaPlug->getManifestLabel()) ."\" description=\"". StringHelper::xmlEntities($metaPlug->getManifestDescription()) ."\">";
+ $manifest = $metaPlug->getManifestRawContent("server_settings/param");
+ $manifest = XMLWriter::replaceAjxpXmlKeywords($manifest);
+ $buffer .= $manifest;
+ $buffer .= "";
+ }
+ $buffer .= "";
+ return $buffer;
+ }else{
+ $dData = [
+ "name" => $repository->getAccessType(),
+ "label" => $plug->getManifestLabel(),
+ "description" => $plug->getManifestDescription(),
+ "iconClass" => $iconClass,
+ "descriptionTemplate" => $descriptionTemplate,
+ "parameters" => $this->xmlServerParamsToArray($manifest)
+ ];
+ $metaSources = [];
+ /** @var Plugin $metaPlug */
+ foreach($metas as $metaPlug){
+ $metaSources[$metaPlug->getId()] = [
+ "id" => $metaPlug->getId(),
+ "label" => $metaPlug->getManifestLabel(),
+ "description" => $metaPlug->getManifestDescription(),
+ "parameters" => $this->xmlServerParamsToArray(XMLWriter::replaceAjxpXmlKeywords($metaPlug->getManifestRawContent("server_settings/param")))
+ ];
+ }
+ $data = ["driver" => $dData, "metasources" => $metaSources];
+ return $data;
+ }
+ }
+
+ /**
+ * @param string $xmlParamsString
+ * @return array
+ */
+ protected function xmlServerParamsToArray($xmlParamsString){
+ $doc = new \DOMDocument();
+ $doc->loadXML("$xmlParamsString");
+ $result = XMLWriter::xmlToArray($doc, ["attributePrefix" => ""]);
+ if(isSet($result["parameters"]["param"])){
+ return $result["parameters"]["param"];
+ }else{
+ return [];
+ }
+ }
/**
* Search the manifests declaring ajxpdriver as their root node. Remove ajxp_* drivers