This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/master by this push: new a603716 KYLIN-4551 Provide interfaces to transfer cube/model/project ownership a603716 is described below commit a603716b4ab5f0fda9509c7c487d22729813d139 Author: Guangxu Cheng <gxch...@apache.org> AuthorDate: Sun Jun 28 15:44:21 2020 +0800 KYLIN-4551 Provide interfaces to transfer cube/model/project ownership --- .../java/org/apache/kylin/cube/CubeManager.java | 10 ++++ .../kylin/metadata/project/ProjectManager.java | 12 +++++ .../kylin/rest/controller/CubeController.java | 32 ++++++++++++ .../kylin/rest/controller/ModelController.java | 55 +++++++++++++++++++++ .../kylin/rest/controller/ProjectController.java | 57 ++++++++++++++++++++++ .../org/apache/kylin/rest/service/CubeService.java | 13 +++++ .../apache/kylin/rest/service/ProjectService.java | 13 +++++ .../kylin/rest/controller/CubeControllerTest.java | 25 +++++++--- .../rest/controller/ProjectControllerTest.java | 42 ++++++++++++++++ webapp/app/js/controllers/cube.js | 18 +++++++ webapp/app/js/controllers/projects.js | 23 ++++++++- webapp/app/js/services/cubes.js | 1 + webapp/app/js/services/projects.js | 3 +- webapp/app/partials/cubes/cube_detail.html | 19 +++++++- webapp/app/partials/projects/project_detail.html | 21 ++++++++ 15 files changed, 334 insertions(+), 10 deletions(-) diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java index 6e9452d..2acad37 100755 --- a/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java +++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeManager.java @@ -315,6 +315,16 @@ public class CubeManager implements IRealizationProvider { } } + public CubeInstance updateCubeOwner(CubeInstance cube, String owner) throws IOException { + try (AutoLock lock = cubeMapLock.lockForWrite()) { + cube = cube.latestCopyForWrite(); // get a latest copy + CubeUpdate update = new CubeUpdate(cube); + update.setOwner(owner); + ProjectManager.getInstance(config).touchProject(cube.getProject()); + return updateCube(update); + } + } + public CubeInstance updateCubeDropSegments(CubeInstance cube, Collection<CubeSegment> segsToDrop) throws IOException { CubeSegment[] arr = segsToDrop.toArray(new CubeSegment[segsToDrop.size()]); diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java index ebcd45c..b3bcc0e 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java @@ -242,6 +242,18 @@ public class ProjectManager { } } + // update project itself + public ProjectInstance updateProjectOwner(ProjectInstance project, String newOwner) throws IOException { + try (AutoLock lock = prjMapLock.lockForWrite()) { + project.setOwner(newOwner); + + if (project.getUuid() == null) + project.updateRandomUuid(); + + return save(project); + } + } + public void removeProjectLocal(String proj) { try (AutoLock lock = prjMapLock.lockForWrite()) { projectMap.removeLocal(proj); diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java index 11df5c1..a96cdda 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java +++ b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java @@ -129,6 +129,10 @@ public class CubeController extends BasicController { private QueryService queryService; @Autowired + @Qualifier("validateUtil") + private ValidateUtil validateUtil; + + @Autowired private AclEvaluate aclEvaluate; @RequestMapping(value = "{cubeName}/validate", method = RequestMethod.GET, produces = { "application/json" }) @@ -261,6 +265,30 @@ public class CubeController extends BasicController { } } + /** + * Update cube owner + * + * @param cubeName + * @param owner + * @throws IOException + */ + @RequestMapping(value = "/{cubeName}/owner", method = { RequestMethod.PUT }, produces = { + "application/json" }) + @ResponseBody + public CubeInstance updateCubeOwner(@PathVariable String cubeName, @RequestBody String owner) { + checkCubeExists(cubeName); + try { + validateUtil.checkIdentifiersExists(owner, true); + CubeInstance cube = cubeService.getCubeManager().getCube(cubeName); + return cubeService.updateCubeOwner(cube, owner); + } catch (AccessDeniedException accessDeniedException) { + throw new ForbiddenException("You don't have right to update this cube's owner."); + } catch (Exception e) { + logger.error(e.getLocalizedMessage(), e); + throw new InternalErrorException(e.getLocalizedMessage(), e); + } + } + @RequestMapping(value = "/{cubeName}/cost", method = { RequestMethod.PUT }, produces = { "application/json" }) @ResponseBody public CubeInstance updateCubeCost(@PathVariable String cubeName, @RequestParam(value = "cost") int cost) { @@ -1061,4 +1089,8 @@ public class CubeController extends BasicController { public void setJobService(JobService jobService) { this.jobService = jobService; } + + public void setValidateUtil(ValidateUtil validateUtil) { + this.validateUtil = validateUtil; + } } diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java index 2f30788..960b381 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java +++ b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Objects; import org.apache.commons.lang.StringUtils; import org.apache.kylin.common.KylinConfig; @@ -75,6 +76,10 @@ public class ModelController extends BasicController { @Qualifier("projectService") private ProjectService projectService; + @Autowired + @Qualifier("validateUtil") + private ValidateUtil validateUtil; + @RequestMapping(value = "/validate/{modelName}", method = RequestMethod.GET, produces = { "application/json" }) @ResponseBody public EnvelopeResponse<Boolean> validateModelName(@PathVariable String modelName) { @@ -224,6 +229,56 @@ public class ModelController extends BasicController { return modelRequest; } + + /** + * Update model owner + * + * @param modelName + * @param owner + * @throws IOException + */ + @RequestMapping(value = "/{modelName}/owner", method = { RequestMethod.PUT }, produces = { + "application/json" }) + @ResponseBody + public ModelRequest updateModelOwner(@PathVariable String modelName, @RequestBody String owner) + throws JsonProcessingException { + DataModelDesc modelDesc = null; + try { + validateUtil.checkIdentifiersExists(owner, true); + DataModelDesc desc = modelService.getDataModelManager().getDataModelDesc(modelName); + if (null == desc) { + throw new NotFoundException("Data Model with name " + modelName + " not found.."); + } + + if (Objects.equals(desc.getOwner(), owner)) { + modelDesc = desc; + } else { + DataModelDesc newModelDesc = DataModelDesc.getCopyOf(desc); + newModelDesc.setOwner(owner); + modelDesc = modelService.updateModelAndDesc(newModelDesc.getProject(), newModelDesc); + } + } catch (AccessDeniedException accessDeniedException) { + throw new ForbiddenException("You don't have right to update this model's owner."); + } catch (Exception e) { + logger.error(e.getLocalizedMessage(), e); + throw new InternalErrorException(e.getLocalizedMessage(), e); + } + + ModelRequest modelRequest = new ModelRequest(); + modelRequest.setProject(modelDesc.getProject()); + modelRequest.setModelName(modelName); + modelRequest.setUuid(modelDesc.getUuid()); + if (modelDesc.getError().isEmpty()) { + modelRequest.setSuccessful(true); + } else { + logger.warn("Model " + modelDesc.getName() + " fail to update because " + modelDesc.getError()); + updateRequest(modelRequest, false, omitMessage(modelDesc.getError())); + } + String descData = JsonUtil.writeValueAsIndentString(modelDesc); + modelRequest.setModelDescData(descData); + return modelRequest; + } + private DataModelDesc deserializeDataModelDesc(ModelRequest modelRequest) { DataModelDesc desc = null; try { diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java index 410ff11..07a70bd 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java +++ b/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java @@ -25,12 +25,15 @@ import java.util.List; import java.util.Locale; import org.apache.commons.lang.StringUtils; +import org.apache.kylin.common.persistence.AclEntity; import org.apache.kylin.common.util.JsonUtil; import org.apache.kylin.metadata.project.ProjectInstance; import org.apache.kylin.rest.exception.BadRequestException; +import org.apache.kylin.rest.exception.ForbiddenException; import org.apache.kylin.rest.exception.InternalErrorException; import org.apache.kylin.rest.exception.NotFoundException; import org.apache.kylin.rest.request.ProjectRequest; +import org.apache.kylin.rest.security.AclPermission; import org.apache.kylin.rest.service.AccessService; import org.apache.kylin.rest.service.CubeService; import org.apache.kylin.rest.service.ProjectService; @@ -40,6 +43,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.acls.model.Sid; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -67,6 +72,11 @@ public class ProjectController extends BasicController { @Autowired @Qualifier("cubeMgmtService") private CubeService cubeService; + + @Autowired + @Qualifier("validateUtil") + private ValidateUtil validateUtil; + @Autowired private AclEvaluate aclEvaluate; @@ -204,6 +214,49 @@ public class ProjectController extends BasicController { } } + @RequestMapping(value = "/{projectName}/owner", method = { RequestMethod.PUT }, produces = { + "application/json" }) + @ResponseBody + public ProjectInstance updateProjectOwner(@PathVariable String projectName, @RequestBody String owner) { + ProjectInstance updatedProj; + ProjectInstance currentProject = null; + String oldOwner = null; + boolean updateOwnerSuccess = false; + boolean updateAccessSuccess = false; + try { + validateUtil.checkIdentifiersExists(owner, true); + currentProject = projectService.getProjectManager().getProject(projectName); + if (currentProject == null) { + throw new NotFoundException("The project named " + projectName + " does not exists"); + } + oldOwner = currentProject.getOwner(); + // update project owner + updatedProj = projectService.updateProjectOwner(currentProject, owner); + updateOwnerSuccess = true; + + //grant ADMINISTRATION permission to new owner + AclEntity ae = accessService.getAclEntity("ProjectInstance", currentProject.getUuid()); + Sid sid = accessService.getSid(owner, true); + accessService.grant(ae, AclPermission.ADMINISTRATION, sid); + updateAccessSuccess = true; + } catch (AccessDeniedException accessDeniedException) { + throw new ForbiddenException("You don't have right to update this project's owner."); + } catch (Exception e) { + logger.error("Failed to deal with the request.", e); + throw new InternalErrorException(e.getLocalizedMessage(), e); + } finally { + if (!updateAccessSuccess && currentProject != null && updateOwnerSuccess) { + try { + projectService.updateProjectOwner(currentProject, oldOwner); + } catch (IOException e) { + logger.error("Failed to roll back the request.", e); + } + } + } + + return updatedProj; + } + public void setProjectService(ProjectService projectService) { this.projectService = projectService; } @@ -215,4 +268,8 @@ public class ProjectController extends BasicController { public void setCubeService(CubeService cubeService) { this.cubeService = cubeService; } + + public void setValidateUtil(ValidateUtil validateUtil) { + this.validateUtil = validateUtil; + } } diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java b/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java index e6210f4..21df411 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/CubeService.java @@ -26,6 +26,7 @@ import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.apache.commons.collections.CollectionUtils; @@ -582,6 +583,18 @@ public class CubeService extends BasicService implements InitializingBean { getCubeDescManager().updateCubeDesc(desc); } + public CubeInstance updateCubeOwner(CubeInstance cube, String owner) throws IOException { + aclEvaluate.checkProjectWritePermission(cube); + if (Objects.equals(cube.getOwner(), owner)) { + // Do nothing + return cube; + } + cube.setOwner(owner); + + CubeUpdate update = new CubeUpdate(cube.latestCopyForWrite()).setOwner(owner); + return getCubeManager().updateCube(update); + } + public CubeInstance rebuildLookupSnapshot(CubeInstance cube, String segmentName, String lookupTable) throws IOException { aclEvaluate.checkProjectOperationPermission(cube); diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java b/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java index 26ad077..40805a9 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Set; import javax.annotation.Nullable; @@ -111,6 +112,18 @@ public class ProjectService extends BasicService { return updatedProject; } + @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#currentProject, 'ADMINISTRATION')") + public ProjectInstance updateProjectOwner(ProjectInstance currentProject, String newOwner) + throws IOException { + if (Objects.equals(currentProject.getOwner(), newOwner)) { + // Do nothing + return currentProject; + } + ProjectInstance updatedProject = getProjectManager().updateProjectOwner(currentProject, newOwner); + logger.debug("Project owner updated."); + return updatedProject; + } + @PostFilter(Constant.ACCESS_POST_FILTER_READ) public List<ProjectInstance> listProjects(final Integer limit, final Integer offset) { List<ProjectInstance> projects = listAllProjects(limit, offset); diff --git a/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java b/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java index 9dd978f..a8adefe 100644 --- a/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java +++ b/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java @@ -37,6 +37,7 @@ import org.apache.kylin.rest.service.CubeService; import org.apache.kylin.rest.service.JobService; import org.apache.kylin.rest.service.ServiceTestBase; import org.apache.kylin.rest.service.StreamingService; +import org.apache.kylin.rest.util.ValidateUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -66,6 +67,10 @@ public class CubeControllerTest extends ServiceTestBase { @Qualifier("streamingMgmtService") StreamingService streamingService; + @Autowired + @Qualifier("validateUtil") + private ValidateUtil validateUtil; + @Before public void setup() throws Exception { super.setup(); @@ -73,6 +78,7 @@ public class CubeControllerTest extends ServiceTestBase { cubeController = new CubeController(); cubeController.setCubeService(cubeService); cubeController.setJobService(jobService); + cubeController.setValidateUtil(validateUtil); cubeDescController = new CubeDescController(); cubeDescController.setCubeService(cubeService); @@ -123,13 +129,20 @@ public class CubeControllerTest extends ServiceTestBase { List<String> notifyList = Lists.newArrayList(); notifyList.add("j...@example.com"); cubeController.updateNotifyList(newCubeName, notifyList); - + try { + cubeController.updateCubeOwner(newCubeName, "new_user"); + } catch (InternalErrorException e) { + Assert.assertEquals("Operation failed, user:new_user not exists, please add first.", + e.getMessage()); + } + cubeController.updateCubeOwner(newCubeName, "MODELER"); List<CubeInstanceResponse> cubeInstances = cubeController.getCubes(newCubeName, cube.getModelName(), "default", 1, 0); CubeInstance cubeInstance = cubeController.getCube(cubeInstances.get(0).getName()); Assert.assertTrue(cubeInstance.getDescriptor().getNotifyList().contains("j...@example.com")); - Assert.assertTrue(cubeInstance.getCost() == 495); + Assert.assertEquals("MODELER", cubeInstance.getOwner()); + Assert.assertEquals(495, cubeInstance.getCost()); cubeController.deleteCube(newCubeName); } @@ -190,7 +203,7 @@ public class CubeControllerTest extends ServiceTestBase { int newSegNumber = cubeService.getCubeManager().getCube(cubeName).getSegments().size(); - Assert.assertTrue(segNumber == newSegNumber + 1); + Assert.assertEquals(segNumber, newSegNumber + 1); cubeController.enableCube(cubeName); } @@ -213,17 +226,17 @@ public class CubeControllerTest extends ServiceTestBase { List<CubeSegment> holes = cubeController.getHoles(cubeName); - Assert.assertTrue(holes.size() == 1); + Assert.assertEquals(1, holes.size()); CubeSegment hole = holes.get(0); - Assert.assertTrue(hole.getTSRange().equals(new TSRange(dateEnd, dateEnd + ONEDAY))); + Assert.assertEquals(hole.getTSRange(), new TSRange(dateEnd, dateEnd + ONEDAY)); } @Test public void testGetCubes() { List<CubeInstanceResponse> cubes = cubeController.getCubes(null, null, null, 1, 0); - Assert.assertTrue(cubes.size() == 1); + Assert.assertEquals(1, cubes.size()); } @Test diff --git a/server/src/test/java/org/apache/kylin/rest/controller/ProjectControllerTest.java b/server/src/test/java/org/apache/kylin/rest/controller/ProjectControllerTest.java index 8d08d61..40d378c 100644 --- a/server/src/test/java/org/apache/kylin/rest/controller/ProjectControllerTest.java +++ b/server/src/test/java/org/apache/kylin/rest/controller/ProjectControllerTest.java @@ -25,8 +25,10 @@ import org.apache.kylin.metadata.project.ProjectInstance; import org.apache.kylin.metadata.project.ProjectManager; import org.apache.kylin.rest.exception.InternalErrorException; import org.apache.kylin.rest.request.ProjectRequest; +import org.apache.kylin.rest.service.AccessService; import org.apache.kylin.rest.service.ProjectService; import org.apache.kylin.rest.service.ServiceTestBase; +import org.apache.kylin.rest.util.ValidateUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -45,12 +47,22 @@ public class ProjectControllerTest extends ServiceTestBase { @Qualifier("projectService") ProjectService projectService; + @Autowired + @Qualifier("validateUtil") + private ValidateUtil validateUtil; + + @Autowired + @Qualifier("accessService") + private AccessService accessService; + @Before public void setup() throws Exception { super.setup(); projectController = new ProjectController(); projectController.setProjectService(projectService); + projectController.setValidateUtil(validateUtil); + projectController.setAccessService(accessService); try { projectController.deleteProject("new_project"); @@ -62,6 +74,11 @@ public class ProjectControllerTest extends ServiceTestBase { } catch (InternalErrorException e) { //project doesn't exist } + try { + projectController.deleteProject("new_project_3"); + } catch (InternalErrorException e) { + //project doesn't exist + } } @Test @@ -87,6 +104,31 @@ public class ProjectControllerTest extends ServiceTestBase { Assert.assertEquals(ProjectManager.getInstance(getTestConfig()).getProject("new_project").getDescription(), "hello world"); } + @Test + public void testUpdateProjectOwner() throws IOException { + int originalProjectCount = projectController.getProjects(null, null).size(); + + //test add project + ProjectInstance project = new ProjectInstance(); + project.setName("new_project_3"); + ProjectInstance ret = projectController.saveProject(getProjectRequest(project, null)); + + Assert.assertEquals(ret.getOwner(), "ADMIN"); + Assert.assertEquals(ProjectManager.getInstance(getTestConfig()).listAllProjects().size(), originalProjectCount + 1); + + //test update project owner only + try { + projectController.updateProjectOwner("new_project_3", "new_user"); + } catch (InternalErrorException e) { + Assert.assertTrue(e.getMessage().equals("Operation failed, user:new_user not exists, please add first.")); + } + projectController.updateProjectOwner("new_project_3", "MODELER"); + + Assert.assertEquals(ProjectManager.getInstance(getTestConfig()).listAllProjects().size(), originalProjectCount + 1); + Assert.assertNotEquals(ProjectManager.getInstance(getTestConfig()).getProject("new_project_3"), null); + Assert.assertEquals(ProjectManager.getInstance(getTestConfig()).getProject("new_project_3").getOwner(), "MODELER"); + } + @Test(expected = InternalErrorException.class) public void testAddExistingProject() throws IOException { ProjectInstance newProject = new ProjectInstance(); diff --git a/webapp/app/js/controllers/cube.js b/webapp/app/js/controllers/cube.js index 0d48dbc..fe84851 100755 --- a/webapp/app/js/controllers/cube.js +++ b/webapp/app/js/controllers/cube.js @@ -88,6 +88,24 @@ KylinApp.controller('CubeCtrl', function ($scope, $rootScope, AccessService, Mes }); }; + $scope.getOwnerString = function (cube) { + cube.newOwner = cube.owner; + }; + + $scope.updateOwner = function (cube) { + CubeService.updateOwner({cubeId: cube.name}, cube.newOwner, function () { + cube.owner = cube.newOwner; + MessageBox.successNotify('Owner updated successfully!'); + },function(e){ + if(e.data&& e.data.exception){ + var message =e.data.exception; + var msg = !!(message) ? message : 'Failed to take action.'; + SweetAlert.swal('Oops...', msg, 'error'); + }else{ + SweetAlert.swal('Oops...', "Failed to take action.", 'error'); + } + }); + }; $scope.getHbaseInfo = function (cube) { if (!cube.hbase) { CubeService.getHbaseInfo({cubeId: cube.name, propValue: null, action: null}, function (hbase) { diff --git a/webapp/app/js/controllers/projects.js b/webapp/app/js/controllers/projects.js index 885e5a2..7adc979 100644 --- a/webapp/app/js/controllers/projects.js +++ b/webapp/app/js/controllers/projects.js @@ -91,10 +91,29 @@ KylinApp } }); } - + $scope.getMapLength = function(map) { - return Object.keys(map).length; + return Object.keys(map).length; } + + $scope.getOwnerString = function (project) { + project.newOwner = project.owner; + }; + + $scope.updateOwner = function (project) { + ProjectService.updateOwner({projecId: project.name}, project.newOwner, function () { + project.owner = project.newOwner; + MessageBox.successNotify('Owner updated successfully!'); + },function(e){ + if(e.data&& e.data.exception){ + var message =e.data.exception; + var msg = !!(message) ? message : 'Failed to take action.'; + SweetAlert.swal('Oops...', msg, 'error'); + } else{ + SweetAlert.swal('Oops...', "Failed to take action.", 'error'); + } + }); + }; } ); diff --git a/webapp/app/js/services/cubes.js b/webapp/app/js/services/cubes.js index 522d043..597cc87 100644 --- a/webapp/app/js/services/cubes.js +++ b/webapp/app/js/services/cubes.js @@ -42,6 +42,7 @@ KylinApp.factory('CubeService', ['$resource', function ($resource, config) { getCube: {method: 'GET', params: {}, isArray: false}, getSql: {method: 'GET', params: {action: 'sql'}, isArray: false}, updateNotifyList: {method: 'PUT', params: {propName: 'notify_list'}, isArray: false}, + updateOwner: {method: 'PUT', params: {propName: 'owner'}, isArray: false}, cost: {method: 'PUT', params: {action: 'cost'}, isArray: false}, rebuildLookUp: {method: 'PUT', params: {propName: 'segs', action: 'refresh_lookup'}, isArray: false}, rebuildCube: {method: 'PUT', params: {action: 'rebuild'}, isArray: false}, diff --git a/webapp/app/js/services/projects.js b/webapp/app/js/services/projects.js index 84a0a89..1976b80 100644 --- a/webapp/app/js/services/projects.js +++ b/webapp/app/js/services/projects.js @@ -22,6 +22,7 @@ KylinApp.factory('ProjectService', ['$resource', function ($resource, config) { listReadable: {method: 'GET', params: {action:'readable'}, isArray: true}, save: {method: 'POST', params: {}, isArray: false}, update: {method: 'PUT', params: {}, isArray: false}, - delete: {method: 'DELETE', params: {}, isArray: false} + delete: {method: 'DELETE', params: {}, isArray: false}, + updateOwner: {method: 'PUT', params: {propName: 'owner'}, isArray: false} }); }]); diff --git a/webapp/app/partials/cubes/cube_detail.html b/webapp/app/partials/cubes/cube_detail.html index b747e84..39edb3e 100755 --- a/webapp/app/partials/cubes/cube_detail.html +++ b/webapp/app/partials/cubes/cube_detail.html @@ -37,6 +37,10 @@ ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission('cube',cube, permissions.ADMINISTRATION.mask) && !newAccess"> <a href="" ng-click="cube.visiblePage='notification';getNotifyListString(cube);">Notification</a> </li> + <li class="{{cube.visiblePage=='owner'? 'active':''}}" + ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission('cube',cube, permissions.ADMINISTRATION.mask) && !newAccess"> + <a href="" ng-click="cube.visiblePage='owner';getOwnerString(cube)">Owner</a> + </li> <li class="{{cube.visiblePage=='hbase'? 'active':''}}" ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission('cube' ,cube, permissions.ADMINISTRATION.mask) && !newAccess"> <a href="" ng-click="cube.visiblePage='hbase';getHbaseInfo(cube)">Storage</a> @@ -100,7 +104,20 @@ </div> </div> - <div class="cube-detail" ng-show="cube.visiblePage=='hbase'"> + <div class="cube-detail" ng-show="cube.visiblePage=='owner'"> + <div style="margin: 15px;"> + <h5><b>Owner:</b></h5> + <div class="form-group"> + <input ng-model="cube.newOwner" class="form-control" placeholder="User List..." /> + </div> + <div class="form-group"> + <button class="btn btn-primary btn-sm" ng-click="updateOwner(cube)">Save</button> + </div> + <div class="space-4"></div> + </div> + </div> + + <div class="cube-detail" ng-show="cube.visiblePage=='hbase'"> <div style="margin: 15px; overflow: hidden;"> <div ng-if="cube.hbase"> <div class="hr hr8 hr-double hr-dotted"></div> diff --git a/webapp/app/partials/projects/project_detail.html b/webapp/app/partials/projects/project_detail.html index 7112da6..b023cdd 100644 --- a/webapp/app/partials/projects/project_detail.html +++ b/webapp/app/partials/projects/project_detail.html @@ -28,6 +28,10 @@ <li class="{{project.visiblePage=='config'? 'active':''}}"> <a href="" ng-click="project.visiblePage='config';">Configuration Overwrites</a> </li> + <li class="{{project.visiblePage=='owner'? 'active':''}}" + ng-if="userService.hasRole('ROLE_ADMIN') || hasPermission('project',project, permissions.ADMINISTRATION.mask)"> + <a href="" ng-click="project.visiblePage='owner';getOwnerString(project)">Owner</a> + </li> </ul> <div class="cube-detail" ng-if="project.visiblePage=='cubes'"> @@ -91,4 +95,21 @@ <div class="col-xs-1"></div> </div> </div> + + <div class="cube-detail" ng-show="project.visiblePage=='owner'"> + <div class="row"> + <div class="col-xs-1"></div> + <div class="col-xs-10"> + <h5><b>Owner:</b></h5> + <div class="form-group"> + <input ng-model="project.newOwner" class="form-control" placeholder="User List..." /> + </div> + <div class="form-group"> + <button class="btn btn-primary btn-sm" ng-click="updateOwner(project)">Save</button> + </div> + <div class="space-4"></div> + </div> + <div class="col-xs-1"></div> + </div> + </div> </div>