/* * Copyright 2007-2017 Charles du Jeu - Abstrium SAS * This file is part of Pydio. * * Pydio is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Pydio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Pydio. If not, see . * * The latest code can be found at . */ const React = require('react') const LangUtils = require('pydio/util/lang') const PathUtils = require('pydio/util/path') const {FormPanel} = require('pydio').requireLib('form') const {PaperEditorLayout, PaperEditorNavEntry, PaperEditorNavHeader} = require('pydio').requireLib('components') const {FlatButton, RaisedButton} = require('material-ui') import EditorCache from './util/EditorCache' import UserPasswordDialog from './user/UserPasswordDialog' import UserRolesPicker from './user/UserRolesPicker' import WorkspacesList from './panel/WorkspacesList' import SharesList from './panel/SharesList' class Editor extends React.Component{ constructor(props, context){ super(props, context); this.state = this._nodeToState(props.node); } getChildContext() { const messages = this.context.pydio.MessageHash; return { messages: messages, getMessage: function (messageId, namespace = 'pydio_role') { return messages[namespace + (namespace ? "." : "") + messageId] || messageId; }, getPydioRoleMessage: function (messageId) { return messages['role_editor.' + messageId] || messageId; }, getRootMessage: function (messageId) { return messages[messageId] || messageId; } }; } getMessage(messageId, namespace='pydio_role'){ return this.getChildContext().getMessage(messageId, namespace); } getPydioRoleMessage(messageId){ return this.getChildContext().getMessage(messageId, 'role_editor'); } getRootMessage(messageId){ return this.getChildContext().getMessage(messageId, ''); } _loadRoleData(showLoader){ if(showLoader) { this.setState({loadingMessage:this.getMessage('home.6', 'ajxp_admin')}); } PydioApi.getClient().request({ get_action:"edit", sub_action:"edit_role", role_id: this.state.roleId, format:'json' }, function(transport){ //if(!this.isMounted()) return; this._loadPluginsDataToCache(function(){ this.setState({loadingMessage:null}); this._parseRoleResponse(transport.responseJSON); }.bind(this)); }.bind(this)); } _parsePluginsDataForCache(response){ let map = new Map(); for(let pluginName in response.LIST){ if(!response.LIST.hasOwnProperty(pluginName)) continue; var pData = response.LIST[pluginName]; var submap = new Map(); for(var key in pData){ if(!pData.hasOwnProperty(key)) continue; var entry = pData[key]; if(entry['action']) submap.set(entry['action'], {label:entry['label']}); else if(entry['parameter']) submap.set(entry['parameter'], entry['attributes']); } map.set(pluginName, submap); } return map; } _loadPluginsDataToCache(callback){ if(EditorCache.CACHE){ callback(); }else{ const client = PydioApi.getClient(); EditorCache.CACHE = {}; this.setState({loadingMessage:this.getMessage('22')}); client.request({get_action:'list_all_plugins_actions'}, function(transport1){ EditorCache.CACHE['ACTIONS'] = this._parsePluginsDataForCache(transport1.responseJSON); this.setState({loadingMessage:this.getMessage('23')}); client.request({get_action:'list_all_plugins_parameters'}, function(transport2){ EditorCache.CACHE['PARAMETERS'] = this._parsePluginsDataForCache(transport2.responseJSON); callback(); }.bind(this)); }.bind(this)); global.pydio.observe("admin_clear_plugins_cache", function(){ EditorCache.CACHE = null; }); } } _scopeParamsToScope(roleData, roleRead){ var SCOPE = {}; for (var key in roleData.SCOPE_PARAMS){ if(!roleData.SCOPE_PARAMS.hasOwnProperty(key)) continue; var param = roleData.SCOPE_PARAMS[key]; var nameParts = param.name.split('/'); var repoScope = nameParts[0]; var pluginName = nameParts[1]; var paramName = nameParts[2]; if(!SCOPE[repoScope]) SCOPE[repoScope] = {}; if(!SCOPE[repoScope][pluginName]) SCOPE[repoScope][pluginName] = {}; var value; if(roleRead['PARAMETERS'][repoScope] && roleRead['PARAMETERS'][repoScope][pluginName] && roleRead['PARAMETERS'][repoScope][pluginName][paramName] !== undefined ){ value = roleRead['PARAMETERS'][repoScope][pluginName][paramName]; }else{ value = param.default!==undefined?param.default:''; if(param.type == 'boolean') value = (value == "true" || value === true); else if(param.type == 'integer') value = parseInt(value); } SCOPE[repoScope][pluginName][paramName] = value; } return {ACL:{},ACTIONS:{},PARAMETERS:SCOPE}; } _parseRoleResponse(roleData){ LangUtils.forceJSONArrayToObject(roleData.ROLE, "ACL"); LangUtils.forceJSONArrayToObject(roleData.ROLE, "ACTIONS"); LangUtils.forceJSONArrayToObject(roleData.ROLE, "PARAMETERS"); var roleWrite = LangUtils.deepCopy(roleData.ROLE); var roleParent = {}; if(roleData.PARENT_ROLE){ roleParent = roleData.PARENT_ROLE; LangUtils.forceJSONArrayToObject(roleParent, "ACL"); LangUtils.forceJSONArrayToObject(roleParent, "ACTIONS"); LangUtils.forceJSONArrayToObject(roleParent, "PARAMETERS"); } var roleRead = this._recomputeRoleRead(roleParent, roleWrite); roleData.SCOPE = this._scopeParamsToScope(roleData, roleRead); this.setState({ roleData:roleData, roleScope:roleData.SCOPE, roleParent:roleParent, roleWrite:roleWrite, roleRead:roleRead, dirty:false }); } _recomputeRoleRead(roleParent, roleMain, skipSetState=true){ var roleRead = roleMain; if(roleParent) { roleRead = LangUtils.mergeObjectsRecursive(roleParent, roleMain); } if(!skipSetState){ this.setState({roleRead:roleRead}); } return roleRead; } _nodeToState(node){ const mime = node.getAjxpMime(); let scope = mime; let roleId; if(mime == "role"){ roleId = node.getMetadata().get("role_id"); }else if(mime == "group"){ roleId = "AJXP_GRP_" + node.getPath().replace("/data/users", ""); }else if(mime == "user" || mime == "user_editable"){ roleId = "AJXP_USR_/" + PathUtils.getBasename(node.getPath()); scope = "user"; } return { roleId:roleId, roleLabel:PathUtils.getBasename(node.getPath()), roleType:scope, dirty:false, roleData:{}, roleParent:{}, roleWrite:{}, roleRead:{}, roleScope:{}, localModalContent:{}, currentPane:'info', loadingMessage:this.getMessage('home.6', 'ajxp_admin'), Controller:this.getController() }; } _toggleUserLock(userId, currentLock, buttonAction){ var reqParams = { get_action:"edit", sub_action:"user_set_lock", user_id : userId }; if(buttonAction == "user_set_lock-lock"){ reqParams["lock"] = (currentLock.indexOf("logout") > -1 ? "false" : "true"); reqParams["lock_type"] = "logout"; }else{ reqParams["lock"] = (currentLock.indexOf("pass_change") > -1 ? "false" : "true"); reqParams["lock_type"] = "pass_change"; } PydioApi.getClient().request(reqParams, function(transport){ this._loadRoleData(); }.bind(this)); } setSelectedPane(key){ this.setState({currentPane:key}); } componentWillReceiveProps(newProps){ var oldN = this.props.node ? this.props.node.getPath() : 'EMPTY'; var newN = newProps.node ? newProps.node.getPath(): 'EMPTY'; if(newN != oldN){ this.setState(this._nodeToState(newProps.node), function(){ this._loadRoleData(true); }.bind(this)); } } componentDidMount(){ this._loadRoleData(true); if(this.props.registerCloseCallback){ this.props.registerCloseCallback(function(){ if(this.state && this.state.dirty && !global.confirm(this.getPydioRoleMessage('19'))){ return false; } }.bind(this)); } } showModal(modal){ this.setState({modal:modal}); } hideModal(){ this.setState({modal:null}); } updateRoleWrite(roleWrite, dirty=true){ const roleRead = this._recomputeRoleRead(this.state.roleParent, roleWrite); this.setState({ dirty:dirty, roleWrite:roleWrite, roleRead:roleRead, roleScope:this._scopeParamsToScope(this.state.roleData, roleRead) }); } resetRoleChanges(){ this.updateRoleWrite(LangUtils.deepCopy(this.state.roleData.ROLE), false); } saveRoleChanges(reload=false){ let jsonData = { ROLE:this.state.roleWrite, METADATA:this.state.parametersMetaData || {} }; if(this.state.roleWrite.USER){ jsonData["USER"] = this.state.roleWrite.USER; }else if(this.state.roleWrite.GROUP && this.state.roleWrite.GROUP.LABEL){ jsonData["GROUP_LABEL"] = this.state.roleWrite.GROUP.LABEL; } PydioApi.getClient().request({ get_action:'edit', sub_action:'post_json_role', role_id:this.state.roleId, json_data:JSON.stringify(jsonData) }, function(transport){ this.logAction(this.getPydioRoleMessage('20')); if(reload){ this._loadRoleData(); }else{ this.setState({dirty:false}); } if(this.props.node.getParent()){ this.props.node.getParent().reload(); } }.bind(this)); } logAction(message){ this.setState({snackbar:message}, function(){ this.refs.snack.show(); }.bind(this)); } hideSnackBar(){ this.setState({snackbar:""}, function(){ this.refs.snack.dismiss(); }.bind(this)); } controllerUpdateParameter(type, crudAction, scope, pluginName, paramName, paramValue, additionalFormData=null){ let role = this.state.roleWrite; let metaData = this.state.parametersMetaData || {PARAMETERS:{},ACTIONS:{}}; const key = (type == 'parameter' ? 'PARAMETERS' : 'ACTIONS'); if(crudAction == 'add' || crudAction == 'update'){ if(!role[key]) role[key] = {}; if(!role[key][scope]) role[key][scope] = {}; if(!role[key][scope][pluginName]) role[key][scope][pluginName] = {}; role[key][scope][pluginName][paramName] = (crudAction == 'add'?(paramValue !== undefined?paramValue:''):paramValue); if(additionalFormData){ additionalFormData['ajxp_form_element'] = paramName; if(!metaData[key][scope]) metaData[key][scope] = {}; if(!metaData[key][scope][pluginName]) metaData[key][scope][pluginName] = {}; metaData[key][scope][pluginName][paramName] = additionalFormData; //this.setState({parametersMetaData:metaData}); } this.updateRoleWrite(role); }else if(crudAction == 'delete'){ try{ let parent = role[key][scope][pluginName]; if(parent){ delete parent[paramName]; this.updateRoleWrite(role); } }catch(e){} } if(additionalFormData && additionalFormData['type']){ // Trigger save now for uploaded images this.setState({parametersMetaData:metaData}, function(){ this.saveRoleChanges(true); }.bind(this)); } } controllerUpdateAcl(scope, acl){ var role = this.state.roleWrite; if(role.ACL){ role.ACL[scope] = acl; this.updateRoleWrite(role); } } controllerUpdateMask(wsId, mask){ var role = this.state.roleWrite; if(role['MASKS']){ role['MASKS'][wsId] = mask; this.updateRoleWrite(role); } } controllerUpdateUserProfile(profile){ var role = this.state.roleWrite; if(!role.USER) role.USER = this.state.roleData.USER; role.USER.PROFILE = profile; this.updateRoleWrite(role); } controllerOrderUserRoles(roles){ var currentUserId = this.state.roleId.replace("AJXP_USR_/", ""); var stateRoles = []; this.state.roleData.USER.ROLES.map(function(r){ if(r.startsWith('AJXP_USR_/') || r.startsWith('AJXP_GRP_/')) stateRoles.push(r); }); stateRoles = stateRoles.concat(roles); this.state.roleData.USER.ROLES = stateRoles; PydioApi.getClient().request({ get_action:"edit", sub_action:"user_reorder_roles", user_id:currentUserId, roles:JSON.stringify(roles) }, function(transport){ this._loadRoleData(); }.bind(this)); } controllerUpdateUserRoles(roles){ var currentUserId = this.state.roleId.replace("AJXP_USR_/", ""); var previousRoles = this.state.roleData.USER.ROLES || []; var remove = previousRoles.slice(0), add = roles.slice(0); for(var i=0; i< previousRoles.length; i++){ add = LangUtils.arrayWithout(add, add.indexOf(previousRoles[i])); } for(i=0; i< roles.length; i++){ remove = LangUtils.arrayWithout(remove, remove.indexOf(roles[i])); } if(!add.length && !remove.length) return; var stateRoles = []; this.state.roleData.USER.ROLES.map(function(r){ if(r.startsWith('AJXP_USR_/') || r.startsWith('AJXP_GRP_/')) stateRoles.push(r); }); stateRoles = stateRoles.concat(roles); this.state.roleData.USER.ROLES = stateRoles; var jsonData = {users:[currentUserId], roles:{add:add,remove:remove}}; PydioApi.getClient().request({ get_action:"edit", sub_action:"users_bulk_update_roles", json_data:JSON.stringify(jsonData) }, function(transport){ this._loadRoleData(); }.bind(this)); } controllerGetBinaryContext(){ if(this.state.roleType == "user"){ return "user_id="+this.state.roleId.replace("AJXP_USR_/", ""); }else if(this.state.roleType == "group"){ return "group_id="+this.state.roleId.replace("AJXP_GRP_/", ""); }else{ return "role_id="+this.state.roleId; } } getController(){ let controller = {}; controller.updateParameter = this.controllerUpdateParameter.bind(this); controller.updateAcl = this.controllerUpdateAcl.bind(this); controller.updateMask = this.controllerUpdateMask.bind(this); controller.updateUserProfile = this.controllerUpdateUserProfile.bind(this); controller.updateUserRoles = this.controllerUpdateUserRoles.bind(this); controller.orderUserRoles = this.controllerOrderUserRoles.bind(this); controller.getBinaryContext = this.controllerGetBinaryContext.bind(this); return controller; } render(){ var filterPages = function(wsId, role){ return (wsId.startsWith('ajxp_')); }; var filterNoPages = function(wsId, role){ return (!wsId.startsWith('ajxp_')); }; var title = PathUtils.getBasename(this.props.node.getPath()); var infoTitle = ""; var infoMenuTitle = this.getMessage('24'); // user information var testTitle; var defs, values, otherForm, changeListener; if(this.state.roleType == 'user' && this.state.roleData && this.state.roleData.ALL) { try { testTitle = this.state.roleRead['PARAMETERS']['AJXP_REPO_SCOPE_ALL']['core.conf']['USER_DISPLAY_NAME']; if(testTitle) title = testTitle; } catch (e) {} var userId = PathUtils.getBasename(this.props.node.getPath()); var locked = this.state.roleData.USER.LOCK || ""; defs = [ {"name":"password",group:this.getMessage('24'),label:this.getPydioRoleMessage('25'), description:"","type":"button", choices:"update_user_pwd"}, {"name":"lockout",group:this.getMessage('24'),label:this.getPydioRoleMessage((locked.indexOf('logout') > -1?'27':'26')), description:"","type":"button", choices:"user_set_lock-lock"}, {"name":"passchange",group:this.getMessage('24'),label:this.getPydioRoleMessage((locked.indexOf('pass_change') > -1?'28b':'28')), description:"","type":"button", choices:"user_set_lock-pass_change"} ]; values = {}; var buttonCallback = function(parameters, cb){ var action = parameters['get_action']; if(action == "update_user_pwd"){ this.props.pydio.UI.openComponentInModal('AdminPeople', 'UserPasswordDialog', {userId: userId}); }else{ this._toggleUserLock(userId, locked, action); } }.bind(this); otherForm = ( ); }else if(this.state.roleType == 'group'){ // GROUP MAIN INFO infoTitle = this.getMessage('26'); // group information infoMenuTitle = this.getMessage('27'); try { testTitle = (this.state.roleWrite.GROUP &&this.state.roleWrite.GROUP.LABEL ) ? this.state.roleWrite.GROUP.LABEL : this.state.roleData.GROUP.LABEL; if(testTitle) title = testTitle; } catch (e) {} if(this.state.roleData.GROUP){ defs = [ {"name":"groupPath",label:this.getPydioRoleMessage('34'),"type":"string", readonly:true}, {"name":"groupLabel",label:this.getPydioRoleMessage('35'),"type":"string", } ]; let label = (this.state.roleWrite.GROUP &&this.state.roleWrite.GROUP.LABEL ) ? this.state.roleWrite.GROUP.LABEL : this.state.roleData.GROUP.LABEL; values = { groupPath :this.state.roleData.GROUP.PATH || "/", groupLabel:label }; changeListener = function(paramName, newValue, oldValue){ if(!this.state.roleWrite.GROUP) this.state.roleWrite.GROUP = {}; this.state.roleWrite.GROUP.LABEL = newValue; this.updateRoleWrite(this.state.roleWrite); }.bind(this); otherForm = ( ); } }else if(this.state.roleType == 'role'){ // ROLE MAIN INFO infoTitle = this.getMessage('28'); // role information infoMenuTitle = this.getMessage('29'); try { testTitle = this.state.roleRead['PARAMETERS']['AJXP_REPO_SCOPE_ALL']['core.conf']['ROLE_DISPLAY_NAME']; if(testTitle) title = testTitle; } catch (e) {} if(this.state.roleData.ALL){ defs = [ {"name":"roleId",label:this.getPydioRoleMessage('31'),"type":"string", readonly:true}, {"name":"applies",label:this.getPydioRoleMessage('33'),"type":"select", multiple:true, choices:this.state.roleData.ALL.PROFILES.join(",")} ]; values = { roleId:this.state.roleId, applies:LangUtils.objectValues(this.state.roleRead.APPLIES) }; changeListener = function(paramName, newValue, oldValue){ this.state.roleWrite.APPLIES= newValue.split(','); this.updateRoleWrite(this.state.roleWrite); }.bind(this); otherForm = ( ); } } var crtPane = this.state.currentPane; var rolesPane, rolesPaneMenu; var shares, sharesMenu; if(this.state.roleType == 'user'){ var filterUserId = PathUtils.getBasename(this.props.node.getPath()); // PROFILES & ROLES PANE - SHARE PANE rolesPaneMenu = ; sharesMenu = ; if(this.state.roleData && this.state.roleData.ALL){ var profilesChoices = this.state.roleData.ALL.PROFILES.join(","); defs = [ {"name":"login",group:"User Profile", label:this.getPydioRoleMessage('21'),description:this.getMessage('31'),"type":"string", readonly:true}, {"name":"profile",group:"User Profile",label:this.getPydioRoleMessage('22'), description:this.getMessage('32'),"type":"select", choices:profilesChoices} ]; values = { login:filterUserId, profile:this.state.roleData.USER.PROFILE }; changeListener = function(paramName, newValue, oldValue){ var controller = this.state.Controller; if(paramName == "profile") { controller.updateUserProfile(newValue); } }.bind(this); rolesPane = (
); if(this.state.currentPane === 'shares'){ shares = ( ); }else{ shares =
; } } } var changes = !this.state.dirty; var save = function(){ this.saveRoleChanges(); }.bind(this); const close = () => { this.props.onRequestTabClose(); }; var rightButtons = (
); var leftNav = [ , , rolesPaneMenu, , , , sharesMenu, , , , ]; var panes = []; var classFor = function(key){return crtPane == key ? 'layout-fill' : ''}; var styleFor = function(key){return crtPane == key ? {overflow:'auto'}:{height:0,overflow:'hidden'}}; if(rolesPane){ panes.push(
{rolesPane}
) } if(shares){ panes.push(
{shares}
); } panes.push(
{infoTitle && !this.state.loadingMessage ?

{infoTitle}

: null} {otherForm}
); panes.push(

{this.getMessage('41')}
{this.getMessage('42')}

); panes.push(

{this.getRootMessage('250')}
{this.getMessage('43')}
read write deny

); panes.push(

{this.getMessage('44')}
{this.getMessage('45')}
{this.getMessage('react.5a', 'ajxp_admin')} {this.getMessage('react.5b', 'ajxp_admin')} {this.getMessage('react.5', 'ajxp_admin')}

); panes.push(

{this.getMessage('46')}
{this.getMessage('47')}

); panes.push(

{this.getMessage('40')}
{this.getMessage('48')}

); var modal = this.state.modal || null; var loadingMessage = null; if(this.state.loadingMessage){ loadingMessage = (
{this.state.loadingMessage}
); } return ( {modal} {loadingMessage} {panes} ); } } Editor.contextTypes = { pydio:React.PropTypes.instanceOf(Pydio) }; Editor.childContextTypes = { messages:React.PropTypes.object, getMessage:React.PropTypes.func, getPydioRoleMessage:React.PropTypes.func, getRootMessage:React.PropTypes.func }; Editor.propTypes ={ node: React.PropTypes.instanceOf(AjxpNode), closeEditor:React.PropTypes.func, registerCloseCallback:React.PropTypes.func }; export {Editor as default}