Repository: kylin
Updated Branches:
  refs/heads/2.0-rc bb29fb11a -> 5d10249f1


KYLIN-1365, Kylin ACL enhancement remove projects box from login page and 
access control to project on UI


Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/5d10249f
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/5d10249f
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/5d10249f

Branch: refs/heads/2.0-rc
Commit: 5d10249f17c0d437948e15a790197fed694c5e81
Parents: bb29fb1
Author: janzhongi <zhongj...@apache.org>
Authored: Mon Jan 25 12:58:54 2016 +0800
Committer: janzhongi <zhongj...@apache.org>
Committed: Mon Jan 25 12:59:06 2016 +0800

----------------------------------------------------------------------
 .../rest/controller/ProjectController.java      | 152 ++++++++++++++-
 .../kylin/rest/controller/UserController.java   |   8 +-
 .../apache/kylin/rest/service/CubeService.java  |   2 +-
 server/src/main/resources/kylinSecurity.xml     |   2 +-
 webapp/app/js/controllers/auth.js               |  12 +-
 webapp/app/js/controllers/cubeSchema.js         |   2 +-
 webapp/app/js/controllers/models.js             |   8 +-
 webapp/app/js/controllers/page.js               |  41 ++--
 webapp/app/js/controllers/projects.js           | 192 +++++++++----------
 webapp/app/js/listeners.js                      |  61 +++++-
 webapp/app/js/model/modelsManager.js            |   2 +
 webapp/app/js/model/projectModel.js             |  34 +++-
 webapp/app/js/services/projects.js              |   1 +
 webapp/app/partials/login.html                  |  16 +-
 webapp/app/partials/models/models_tree.html     |   6 +-
 15 files changed, 368 insertions(+), 171 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/server/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
----------------------------------------------------------------------
diff --git 
a/server/src/main/java/org/apache/kylin/rest/controller/ProjectController.java 
b/server/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
index a561e97..abebdd8 100644
--- 
a/server/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
+++ 
b/server/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
@@ -19,17 +19,31 @@
 package org.apache.kylin.rest.controller;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.persistence.AclEntity;
+import org.apache.kylin.cube.CubeInstance;
 import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.rest.constant.Constant;
 import org.apache.kylin.rest.exception.InternalErrorException;
 import org.apache.kylin.rest.request.CreateProjectRequest;
 import org.apache.kylin.rest.request.UpdateProjectRequest;
+import org.apache.kylin.rest.service.AccessService;
+import org.apache.kylin.rest.service.CubeService;
 import org.apache.kylin.rest.service.ProjectService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.acls.domain.GrantedAuthoritySid;
+import org.springframework.security.acls.domain.PrincipalSid;
+import org.springframework.security.acls.model.AccessControlEntry;
+import org.springframework.security.acls.model.Acl;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -49,19 +63,135 @@ public class ProjectController extends BasicController {
     @Autowired
     private ProjectService projectService;
 
+    @Autowired
+    private AccessService accessService;
+    @Autowired
+    private CubeService cubeService;
+
     /**
      * Get available project list
-     * 
+     *
      * @return Table metadata array
      * @throws IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @RequestMapping(value = "", method = {RequestMethod.GET})
     @ResponseBody
     public List<ProjectInstance> getProjects(@RequestParam(value = "limit", 
required = false) Integer limit, @RequestParam(value = "offset", required = 
false) Integer offset) {
         return projectService.listAllProjects(limit, offset);
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.POST })
+    @RequestMapping(value = "/readable", method = {RequestMethod.GET})
+    @ResponseBody
+    public List<ProjectInstance> getReadableProjects(@RequestParam(value = 
"limit", required = false) Integer limit, @RequestParam(value = "offset", 
required = false) Integer offset) {
+        List<ProjectInstance> readableProjects = new 
ArrayList<ProjectInstance>();
+        //list all projects first
+        List<ProjectInstance> projectInstances = 
projectService.listAllProjects(limit, offset);
+
+        //get user infomation
+        Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
+        UserDetails userDetails = null;
+        if (authentication == null) {
+            logger.debug("authentication is null.");
+            throw new InternalErrorException("Can not find authentication 
infomation.");
+        }
+        if (authentication.getPrincipal() instanceof UserDetails) {
+            logger.debug("authentication.getPrincipal() is " + 
authentication.getPrincipal());
+            userDetails = (UserDetails) authentication.getPrincipal();
+        }
+        if (authentication.getDetails() instanceof UserDetails) {
+            logger.debug("authentication.getDetails() is " + 
authentication.getDetails());
+            userDetails = (UserDetails) authentication.getDetails();
+        }
+
+        //check if ROLE_ADMIN return all,also get user role list
+        List<String> userAuthority = new ArrayList<>();
+        for (GrantedAuthority auth : authentication.getAuthorities()) {
+            userAuthority.add(auth.getAuthority());
+            if (auth.getAuthority().equals(Constant.ROLE_ADMIN))
+                return projectInstances;
+        }
+        String userName = userDetails.getUsername();
+        for (ProjectInstance projectInstance : projectInstances) {
+
+            boolean hasProjectPermission = false;
+            AclEntity ae = accessService.getAclEntity("ProjectInstance", 
projectInstance.getId());
+            Acl projectAcl = accessService.getAcl(ae);
+            //project no Acl info will be skipped
+            if(projectAcl == null){
+                continue;
+            }
+
+            //project owner has permission
+            if 
(((PrincipalSid)projectAcl.getOwner()).getPrincipal().equals(userName)) {
+                readableProjects.add(projectInstance);
+                continue;
+            }
+
+            //check project permission and role
+            for (AccessControlEntry ace : projectAcl.getEntries()) {
+                if( ace.getSid() instanceof PrincipalSid && 
((PrincipalSid)ace.getSid()).getPrincipal().equals(userName)) {
+                        hasProjectPermission = true;
+                        readableProjects.add(projectInstance);
+                        break;
+
+                }else if(ace.getSid() instanceof GrantedAuthoritySid){
+                    String projectAuthority = ((GrantedAuthoritySid) 
ace.getSid()).getGrantedAuthority();
+                    if(userAuthority.contains(projectAuthority)){
+                        hasProjectPermission = true;
+                        readableProjects.add(projectInstance);
+                        break;
+                    }
+
+                }
+
+            }
+            if (!hasProjectPermission) {
+                List<CubeInstance> cubeInstances = 
cubeService.listAllCubes(projectInstance.getName());
+
+                for (CubeInstance cubeInstance : cubeInstances) {
+                    boolean hasCubePermission = false;
+                    AclEntity cubeAe = 
accessService.getAclEntity("CubeInstance", cubeInstance.getId());
+                    Acl cubeAcl = accessService.getAcl(cubeAe);
+                    //cube no Acl info will not be used to filter project
+                    if(cubeAcl == null){
+                        continue;
+                    }
+                    //cube owner will have permission to read project
+                    if 
(((PrincipalSid)cubeAcl.getOwner()).getPrincipal().equals(userName)) {
+                        hasProjectPermission = true;
+                        break;
+                    }
+                    for (AccessControlEntry cubeAce : cubeAcl.getEntries()) {
+
+                        if (cubeAce.getSid() instanceof PrincipalSid && 
((PrincipalSid)cubeAce.getSid()).getPrincipal().equals(userName)) {
+                            hasCubePermission = true;
+                            break;
+                        }
+                        else if(cubeAce.getSid() instanceof 
GrantedAuthoritySid) {
+                            String cubeAuthority = ((GrantedAuthoritySid) 
cubeAce.getSid()).getGrantedAuthority();
+                            if(userAuthority.contains(cubeAuthority)){
+                                hasCubePermission = true;
+                                break;
+                            }
+
+                        }
+                    }
+                    if (hasCubePermission) {
+                        hasProjectPermission = true;
+                        break;
+                    }
+                }
+                if (hasProjectPermission) {
+                    readableProjects.add(projectInstance);
+                }
+            }
+
+
+        }
+        return readableProjects;
+    }
+
+    @RequestMapping(value = "", method = {RequestMethod.POST})
     @ResponseBody
     public ProjectInstance saveProject(@RequestBody CreateProjectRequest 
projectRequest) {
         if (StringUtils.isEmpty(projectRequest.getName())) {
@@ -79,7 +209,7 @@ public class ProjectController extends BasicController {
         return createdProj;
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.PUT })
+    @RequestMapping(value = "", method = {RequestMethod.PUT})
     @ResponseBody
     public ProjectInstance updateProject(@RequestBody UpdateProjectRequest 
projectRequest) {
         if (StringUtils.isEmpty(projectRequest.getFormerProjectName())) {
@@ -98,7 +228,7 @@ public class ProjectController extends BasicController {
         return updatedProj;
     }
 
-    @RequestMapping(value = "/{projectName}", method = { RequestMethod.DELETE 
})
+    @RequestMapping(value = "/{projectName}", method = {RequestMethod.DELETE})
     @ResponseBody
     public void deleteProject(@PathVariable String projectName) {
         try {
@@ -111,8 +241,20 @@ public class ProjectController extends BasicController {
         }
     }
 
+
     public void setProjectService(ProjectService projectService) {
         this.projectService = projectService;
     }
 
+    /**
+     * @param accessService
+     */
+    public void setAccessService(AccessService accessService) {
+        this.accessService = accessService;
+    }
+
+    public void setCubeService(CubeService cubeService) {
+        this.cubeService = cubeService;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/server/src/main/java/org/apache/kylin/rest/controller/UserController.java
----------------------------------------------------------------------
diff --git 
a/server/src/main/java/org/apache/kylin/rest/controller/UserController.java 
b/server/src/main/java/org/apache/kylin/rest/controller/UserController.java
index a7bc782..f291841 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/UserController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/UserController.java
@@ -18,6 +18,7 @@
 
 package org.apache.kylin.rest.controller;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.kylin.rest.service.UserService;
@@ -76,7 +77,12 @@ public class UserController {
 
     @RequestMapping(value = "/authentication/authorities", method = 
RequestMethod.GET, produces = "application/json")
     public List<String> getAuthorities() {
-        return userService.getUserAuthorities();
+//        return userService.getUserAuthorities();
+        ArrayList<String> lists = new ArrayList<>();
+        lists.add("ROLE_ADMIN");
+        lists.add("ROLE_MODELER");
+        lists.add("ROLE_ANALYST");
+        return lists;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
----------------------------------------------------------------------
diff --git 
a/server/src/main/java/org/apache/kylin/rest/service/CubeService.java 
b/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
index ac4aa6b..fc64a58 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/CubeService.java
@@ -206,7 +206,7 @@ public class CubeService extends BasicService {
         return createdCube;
     }
 
-    private List<CubeInstance> listAllCubes(String projectName) {
+    public List<CubeInstance> listAllCubes(String projectName) {
         ProjectManager projectManager = getProjectManager();
         ProjectInstance project = projectManager.getProject(projectName);
         if (project == null) {

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/server/src/main/resources/kylinSecurity.xml
----------------------------------------------------------------------
diff --git a/server/src/main/resources/kylinSecurity.xml 
b/server/src/main/resources/kylinSecurity.xml
index 4a9b929..819d951 100644
--- a/server/src/main/resources/kylinSecurity.xml
+++ b/server/src/main/resources/kylinSecurity.xml
@@ -152,7 +152,7 @@
                        <scr:intercept-url pattern="/api/streaming*/**" 
access="isAuthenticated()" />
                        <scr:intercept-url pattern="/api/job*/**" 
access="isAuthenticated()" />
                        <scr:intercept-url pattern="/api/admin/config" 
access="permitAll" />
-                       <scr:intercept-url pattern="/api/projects" 
access="permitAll" />
+                       <scr:intercept-url pattern="/api/projects*/*" 
access="permitAll" />
                        <scr:intercept-url pattern="/api/admin*/**" 
access="hasRole('ROLE_ADMIN')" />
                        <scr:intercept-url pattern="/api/**" 
access="isAuthenticated()" />
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/controllers/auth.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/auth.js 
b/webapp/app/js/controllers/auth.js
index 2e5dc75..940ff4f 100644
--- a/webapp/app/js/controllers/auth.js
+++ b/webapp/app/js/controllers/auth.js
@@ -18,27 +18,25 @@
 
 'use strict';
 
-KylinApp.controller('LoginCtrl', function ($scope, $rootScope, $location, 
$base64, AuthenticationService, UserService) {
+KylinApp.controller('LoginCtrl', function ($scope, $rootScope, $location, 
$base64, AuthenticationService, UserService,ProjectService,ProjectModel) {
   $scope.username = null;
   $scope.password = null;
   $scope.loading = false;
 
   $scope.login = function () {
+
+    $rootScope.userAction.islogout = false;
+
     // set the basic authentication header that will be parsed in the next 
request and used to authenticate
     httpHeaders.common['Authorization'] = 'Basic ' + 
$base64.encode($scope.username + ':' + $scope.password);
     $scope.loading = true;
-    //verify project
-    if ($scope.projectModel.projects.length && 
!$scope.projectModel.selectedProject) {
-      $scope.loading = false;
-      $scope.error = "Unable to login, please select a project";
-      return;
-    }
 
     AuthenticationService.login({}, {}, function (data) {
       $scope.loading = false;
       $rootScope.$broadcast('event:loginConfirmed');
       UserService.setCurUser(data);
       $location.path(UserService.getHomePage());
+
     }, function (error) {
       $scope.loading = false;
       $scope.error = "Unable to login, please check your username/password.";

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/controllers/cubeSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeSchema.js 
b/webapp/app/js/controllers/cubeSchema.js
index d22acb9..60951b7 100755
--- a/webapp/app/js/controllers/cubeSchema.js
+++ b/webapp/app/js/controllers/cubeSchema.js
@@ -315,7 +315,7 @@ KylinApp.controller('CubeSchemaCtrl', function ($scope, 
QueryService, UserServic
 
     // ~ private methods
     function initProject() {
-        ProjectService.list({}, function (projects) {
+        ProjectService.listReadable({}, function (projects) {
             $scope.projects = projects;
 
             var cubeName = (!!$scope.routeParams.cubeName)? 
$scope.routeParams.cubeName:$scope.state.cubeName;

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/controllers/models.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/models.js 
b/webapp/app/js/controllers/models.js
index f1527d9..7fc2669 100644
--- a/webapp/app/js/controllers/models.js
+++ b/webapp/app/js/controllers/models.js
@@ -47,7 +47,13 @@ KylinApp.controller('ModelsCtrl', function ($scope, $q, 
$routeParams, $location,
     var defer = $q.defer();
     var queryParam = {};
     if (!$scope.projectModel.isSelectedProjectValid()) {
-      return;
+      defer.resolve([]);
+      return defer.promise;
+    }
+
+    if (!$scope.projectModel.projects.length) {
+      defer.resolve([]);
+      return defer.promise;
     }
 
     queryParam.projectName = $scope.projectModel.selectedProject;

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/controllers/page.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/page.js 
b/webapp/app/js/controllers/page.js
index 969279f..c1a5459 100644
--- a/webapp/app/js/controllers/page.js
+++ b/webapp/app/js/controllers/page.js
@@ -25,6 +25,9 @@ KylinApp.controller('PageCtrl', function ($scope, $q, 
AccessService, $modal, $lo
     $log.debug(data);
     kylinConfig.initWebConfigInfo();
   });
+  $rootScope.userAction={
+    'islogout':false
+  }
 
   $scope.kylinConfig = kylinConfig;
 
@@ -42,34 +45,13 @@ KylinApp.controller('PageCtrl', function ($scope, $q, 
AccessService, $modal, $lo
   $scope.activeTab = "";
   $scope.projectModel = ProjectModel;
   $scope.tableModel = TableModel;
-  //init
-  ProjectService.list({}, function (projects) {
-    var _projects = [];
-    angular.forEach(projects, function (project, index) {
-      $scope.listAccess(project, 'ProjectInstance');
-      _projects.push(project);
-    });
-    _projects = _.sortBy(_projects, function (i) {
-      return i.name.toLowerCase();
-    });
-
-    ProjectModel.setProjects(_projects);
-
-    var absUrl = $location.absUrl();
-
-    var projectInCookie = $cookieStore.get("project");
-    if (absUrl.indexOf("/login") == -1) {
-      var selectedProject = projectInCookie != null ? projectInCookie : null;
-      $scope.projectModel.setSelectedProject(selectedProject);
-    } else {
-      var selectedProject = $scope.projectModel.selectedProject != null ? 
$scope.projectModel.selectedProject : projectInCookie != null ? projectInCookie 
: $scope.projectModel.projects[0];
-      $scope.projectModel.setSelectedProject(selectedProject);
-    }
-  });
-
 
   // Set up common methods
   $scope.logout = function () {
+    //destroy projects info for user
+    ProjectModel.clear();
+
+    $rootScope.userAction.islogout = true;
     $scope.$emit('event:logoutRequest');
     $http.get(Config.service.base + 
'j_spring_security_logout').success(function () {
       UserService.setCurUser({});
@@ -110,7 +92,7 @@ KylinApp.controller('PageCtrl', function ($scope, $q, 
AccessService, $modal, $lo
   // common acl methods
   $scope.hasPermission = function (entity) {
     var curUser = UserService.getCurUser();
-    if (!curUser) {
+    if (!curUser.userDetails) {
       return curUser;
     }
 
@@ -182,8 +164,11 @@ KylinApp.controller('PageCtrl', function ($scope, $q, 
AccessService, $modal, $lo
 
   $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
     if (newValue != oldValue) {
-      //$log.log("project updated in page controller,from:"+oldValue+" 
To:"+newValue);
-      $cookieStore.put("project", $scope.projectModel.selectedProject);
+
+      //do not update cookie info when logout destroy project info
+      if(!$rootScope.userAction.islogout){
+        $cookieStore.put("project", $scope.projectModel.selectedProject);
+      }
     }
 
   });

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/controllers/projects.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/projects.js 
b/webapp/app/js/controllers/projects.js
index e0cc64d..b9dae73 100644
--- a/webapp/app/js/controllers/projects.js
+++ b/webapp/app/js/controllers/projects.js
@@ -1,96 +1,96 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-'use strict';
-
-KylinApp
-    .controller('ProjectCtrl', function ($scope, $modal, $q, ProjectService, 
MessageService,SweetAlert,$log,kylinConfig,projectConfig,ProjectModel) {
-
-        $scope.projects = [];
-        $scope.loading = false;
-        $scope.projectConfig = projectConfig;
-
-        $scope.state = { filterAttr: 'name', filterReverse: true, 
reverseColumn: 'name'};
-
-        $scope.list = function (offset, limit) {
-            offset = (!!offset) ? offset : 0;
-            limit = (!!limit) ? limit : 20;
-            var defer = $q.defer();
-            var queryParam = {offset: offset, limit: limit};
-
-            $scope.loading = true;
-            ProjectService.list(queryParam, function (projects) {
-                $scope.projects = $scope.projects.concat(projects);
-                angular.forEach(projects, function (project) {
-                    $scope.listAccess(project, 'ProjectInstance');
-                });
-                $scope.loading = false;
-                defer.resolve(projects.length);
-            });
-
-            return defer.promise;
-        }
-
-        $scope.toEdit = function(project) {
-            $modal.open({
-                templateUrl: 'project.html',
-                controller: projCtrl,
-                resolve: {
-                    projects: function () {
-                        return $scope.projects;
-                    },
-                    project: function(){
-                        return project;
-                    }
-                }
-            });
-        }
-
-        $scope.delete = function(project){
-            SweetAlert.swal({
-                title: '',
-                text: 'Are you sure to delete ?',
-                type: '',
-                showCancelButton: true,
-                confirmButtonColor: '#DD6B55',
-                confirmButtonText: "Yes",
-                closeOnConfirm: true
-            }, function(isConfirm) {
-                if(isConfirm){
-                ProjectService.delete({projecId: project.name}, function(){
-                    var pIndex = $scope.projects.indexOf(project);
-                    if (pIndex > -1) {
-                        $scope.projects.splice(pIndex, 1);
-                    }
-                ProjectModel.removeProject(project.name);
-                SweetAlert.swal('Success!',"Project [" + project.name + "] has 
been deleted successfully!", 'success');
-                },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');
-                    }
-                });
-                }
-            });
-        }
-    }
-);
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+'use strict';
+
+KylinApp
+    .controller('ProjectCtrl', function ($scope, $modal, $q, ProjectService, 
MessageService,SweetAlert,$log,kylinConfig,projectConfig,ProjectModel) {
+
+        $scope.projects = [];
+        $scope.loading = false;
+        $scope.projectConfig = projectConfig;
+
+        $scope.state = { filterAttr: 'name', filterReverse: true, 
reverseColumn: 'name'};
+
+        $scope.list = function (offset, limit) {
+            offset = (!!offset) ? offset : 0;
+            limit = (!!limit) ? limit : 20;
+            var defer = $q.defer();
+            var queryParam = {offset: offset, limit: limit};
+
+            $scope.loading = true;
+            ProjectService.listReadable(queryParam, function (projects) {
+                $scope.projects = $scope.projects.concat(projects);
+                angular.forEach(projects, function (project) {
+                    $scope.listAccess(project, 'ProjectInstance');
+                });
+                $scope.loading = false;
+                defer.resolve(projects.length);
+            });
+
+            return defer.promise;
+        }
+
+        $scope.toEdit = function(project) {
+            $modal.open({
+                templateUrl: 'project.html',
+                controller: projCtrl,
+                resolve: {
+                    projects: function () {
+                        return $scope.projects;
+                    },
+                    project: function(){
+                        return project;
+                    }
+                }
+            });
+        }
+
+        $scope.delete = function(project){
+            SweetAlert.swal({
+                title: '',
+                text: 'Are you sure to delete ?',
+                type: '',
+                showCancelButton: true,
+                confirmButtonColor: '#DD6B55',
+                confirmButtonText: "Yes",
+                closeOnConfirm: true
+            }, function(isConfirm) {
+                if(isConfirm){
+                ProjectService.delete({projecId: project.name}, function(){
+                    var pIndex = $scope.projects.indexOf(project);
+                    if (pIndex > -1) {
+                        $scope.projects.splice(pIndex, 1);
+                    }
+                ProjectModel.removeProject(project.name);
+                SweetAlert.swal('Success!',"Project [" + project.name + "] has 
been deleted successfully!", 'success');
+                },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');
+                    }
+                });
+                }
+            });
+        }
+    }
+);
+

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/listeners.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/listeners.js b/webapp/app/js/listeners.js
index 7998481..556acdf 100644
--- a/webapp/app/js/listeners.js
+++ b/webapp/app/js/listeners.js
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-KylinApp.run(function ($rootScope, $http, $location, UserService, 
AuthenticationService, MessageService, loadingRequest, SweetAlert) {
+KylinApp.run(function ($rootScope, $http, $location, UserService, 
AuthenticationService, MessageService, loadingRequest, 
$cookieStore,ProjectService,ProjectModel,AccessService,SweetAlert,loadingRequest)
 {
 
   $rootScope.permissions = {
     READ: {name: 'CUBE QUERY', value: 'READ', mask: 1},
@@ -26,18 +26,65 @@ KylinApp.run(function ($rootScope, $http, $location, 
UserService, Authentication
   };
 
   $rootScope.$on("$routeChangeStart", function () {
-    AuthenticationService.ping(function (data) {
-      if(!data.userDetails){
-        $location.path(UserService.getHomePage());
-      }
-      UserService.setCurUser(data);
-    });
+      AuthenticationService.ping(function (data) {
+        if(!data.userDetails){
+          $location.path(UserService.getHomePage());
+        }else{
+          UserService.setCurUser(data);
+          //get project info when login
+          if (!ProjectModel.projects.length&&!$rootScope.userAction.islogout) {
+
+            loadingRequest.show();
+            ProjectService.listReadable({}, function (projects) {
+              loadingRequest.hide();
+
+              if(!projects.length){
+                return;
+              }
+
+              var _projects = [];
+              _projects = _.sortBy(projects, function (i) {
+                return i.name.toLowerCase();
+              });
+              ProjectModel.setProjects(_projects);
+              var projectInCookie = $cookieStore.get("project");
+              if(projectInCookie&&ProjectModel.getIndex(projectInCookie)==-1){
+                projectInCookie = null;
+              }
+              var selectedProject = projectInCookie != null ? projectInCookie 
: null;
+              if(projectInCookie!=null){
+                selectedProject = projectInCookie;
+              }else if(UserService.hasRole('ROLE_ADMIN')){
+                selectedProject = null;
+              }else{
+                selectedProject = ProjectModel.projects[0].name
+              }
+
+              //var selectedProject = ProjectModel.selectedProject != null ? 
ProjectModel.selectedProject : projectInCookie != null ? projectInCookie : 
ProjectModel.projects[0].name;
+              ProjectModel.setSelectedProject(selectedProject);
+              angular.forEach(ProjectModel.projects, function (project, index) 
{
+                project.accessLoading = true;
+                AccessService.list({type: 'ProjectInstance', uuid: 
project.uuid}, function (accessEntities) {
+                  project.accessLoading = false;
+                  project.accessEntities = accessEntities;
+                });
+              });
+
+            },function(e){
+              loadingRequest.hide();
+              $location.path(UserService.getHomePage());
+            });
+          }
+        }
+      });
+
 
     if ($location.url() == '' || $location.url() == '/') {
       AuthenticationService.ping(function (data) {
         UserService.setCurUser(data);
         $location.path(UserService.getHomePage());
       });
+
       return;
     }
   });

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/model/modelsManager.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/modelsManager.js 
b/webapp/app/js/model/modelsManager.js
index 2c3c90a..fb67cd6 100644
--- a/webapp/app/js/model/modelsManager.js
+++ b/webapp/app/js/model/modelsManager.js
@@ -40,11 +40,13 @@ 
KylinApp.service('modelsManager',function(ModelService,CubeService,$q,AccessServ
 
             angular.forEach(_models, function (model, index) {
                 $log.info("Add model permission info");
+              if(model.uuid){
                 modelPermission.push(
                 AccessService.list({type: "DataModelDesc", uuid: model.uuid}, 
function (accessEntities) {
                     model.accessEntities = accessEntities;
                 }).$promise
                 )
+              }
                 $log.info("Add cube info to model ,not detail info");
                 cubeDetail.push(
                     CubeService.list({modelName:model.name}, function (_cubes) 
{

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/model/projectModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/projectModel.js 
b/webapp/app/js/model/projectModel.js
index eba8273..a264331 100644
--- a/webapp/app/js/model/projectModel.js
+++ b/webapp/app/js/model/projectModel.js
@@ -31,12 +31,6 @@ KylinApp.service('ProjectModel', function () {
       this.selectedProject = project;
     }
   };
-  this.getSelectedProject = function (project) {
-    if (this.selectedProject == "_null") {
-      return null;
-    }
-    return this.selectedProject;
-  };
 
   this.isSelectedProjectValid = function(){
     if(this.selectedProject == "_null"){
@@ -45,6 +39,13 @@ KylinApp.service('ProjectModel', function () {
     return true;
   }
 
+  this.getSelectedProject = function (project) {
+    if (this.selectedProject == "_null") {
+      return null;
+    }
+    return this.selectedProject;
+  };
+
   this.setProjects = function (projects) {
     if (projects.length) {
       this.projects = projects;
@@ -106,4 +107,25 @@ KylinApp.service('ProjectModel', function () {
     });
   }
 
+  this.clear = function(){
+    this.projects = [];
+    this.selectedProject = "_null";
+  }
+
+  this.clearProjects = function(){
+    this.projects = [];
+  }
+
+  this.getIndex = function(project){
+    var index = -1;
+    for (var i = 0; i < this.projects.length; i++) {
+      if (this.projects[i].name == project) {
+        index = i;
+        break;
+      }
+    }
+    return index;
+
+  }
+
 })

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/js/services/projects.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/projects.js 
b/webapp/app/js/services/projects.js
index 333e742..84a0a89 100644
--- a/webapp/app/js/services/projects.js
+++ b/webapp/app/js/services/projects.js
@@ -19,6 +19,7 @@
 KylinApp.factory('ProjectService', ['$resource', function ($resource, config) {
   return $resource(Config.service.url + 
'projects/:projecId/:propName/:propValue/:action', {}, {
     list: {method: 'GET', params: {}, isArray: true},
+    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}

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/partials/login.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/login.html b/webapp/app/partials/login.html
index 79128b1..452257b 100644
--- a/webapp/app/partials/login.html
+++ b/webapp/app/partials/login.html
@@ -32,28 +32,16 @@
                             <form name="login_form" ng-submit="login()">
                                 <div class="form-group">
                                     <span class="width-100 input-icon 
input-icon-right">
-                                        <input id="username" 
class="form-control" ng-model="username" type="text" autofocus="autofocus" 
required placeholder="Username" auto-fill-sync />
+                                        <input id="username" 
class="form-control" ng-model="username" type="text" autofocus="autofocus" 
ng-required placeholder="Username" auto-fill-sync />
                                         <i class="ace-icon fa fa-user"></i>
                                     </span>
                                 </div>
                                 <div class="form-group">
                                     <span class="width-100 input-icon 
input-icon-right">
-                                        <input id="password" 
class="form-control" ng-model="password" type="password" required 
placeholder="Password" auto-fill-sync />
+                                        <input id="password" 
class="form-control" ng-model="password" type="password" ng-required 
placeholder="Password" auto-fill-sync />
                                         <i class="ace-icon fa fa-lock"></i>
                                     </span>
                                 </div>
-                                <div class="form-group">
-                                    <span>
-
-                                        <select  
ng-required="projectModel.projects.length" chosen 
ng-model="projectModel.selectedProject" 
ng-init="newAccess.permission=permissions.READ.value;"
-                                                ng-options="project.name as 
project.name for project in projectModel.projects "
-                                                style="width: 100% !important;"
-                                                data-placeholder="select a 
project"
-                                                class="chosen-select">
-                                            <option value=""></option>
-                                        </select>
-                                    </span>
-                                </div>
                                 <div class="space"></div>
                                 <div class="form-group">
                                     <a 
href="http://kylin.apache.org/community/"; target="_blank" 
class="text-muted">Login Issue?</a>

http://git-wip-us.apache.org/repos/asf/kylin/blob/5d10249f/webapp/app/partials/models/models_tree.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/models_tree.html 
b/webapp/app/partials/models/models_tree.html
index 821d0fa..8f76113 100644
--- a/webapp/app/partials/models/models_tree.html
+++ b/webapp/app/partials/models/models_tree.html
@@ -50,9 +50,9 @@
 
             <div class="pull-right" showonhoverparent style="display:none;" 
class="cube_model_trees">
 
-              <a href="models/edit/{{model.name}}" title="Edit Model" 
ng-if="userService.hasRole('ROLE_MODELER') "><span class="fa fa-pencil fa-lg 
fa-fw"></span></a>
-              <a ng-click="cloneModel(model)" title="Clone Model"  
style="cursor:pointer;margin-right: 8px;" 
ng-if="userService.hasRole('ROLE_MODELER')"><span class="fa fa-copy fa-lg 
fa-fw"></span></a>
-              <a ng-click="dropModel(model)" title="Drop Model" 
style="cursor:pointer;margin-right: 8px;" 
ng-if="userService.hasRole('ROLE_MODELER')"><span class="fa fa-trash-o fa-lg 
fa-fw"></span></a>
+              <a href="models/edit/{{model.name}}" title="Edit Model" 
ng-if="(userService.hasRole('ROLE_ADMIN') || hasPermission(model, 
permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, 
permissions.OPERATION.mask))"><span class="fa fa-pencil fa-lg fa-fw"></span></a>
+              <a ng-click="cloneModel(model)" title="Clone Model"  
style="cursor:pointer;margin-right: 8px;" 
ng-if="(userService.hasRole('ROLE_ADMIN') || hasPermission(model, 
permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, 
permissions.OPERATION.mask))"><span class="fa fa-copy fa-lg fa-fw"></span></a>
+              <a ng-click="dropModel(model)" title="Drop Model" 
style="cursor:pointer;margin-right: 8px;" 
ng-if="(userService.hasRole('ROLE_ADMIN') || hasPermission(model, 
permissions.ADMINISTRATION.mask, permissions.MANAGEMENT.mask, 
permissions.OPERATION.mask))"><span class="fa fa-trash-o fa-lg 
fa-fw"></span></a>
 
             </div>
 

Reply via email to