Browse Source

Optimize the UI experience of open platform authorization management (#4436)

* add tech-support-qq-4.png

* Update README.md

* Enhance the user experience in the scenario of submitting duplicate keys

* Modify the key-value conflict exception prompt, adjust the code style

* Optimize the UI experience of open platform authorization management

* doc(CHANGES.md): update CHANGES.md

* Fixed use of document title sequence numbers

* Update apollo-portal/src/main/resources/static/i18n/en.json

Co-authored-by: Jason Song <nobodyiam@gmail.com>

* Update apollo-portal/src/main/resources/static/i18n/en.json

Co-authored-by: Jason Song <nobodyiam@gmail.com>

* Optimize the display of create consumer button

* Fix the problem of deleting consumer permissions

* Optimize the UI experience of open platform authorization management

* doc(CHANGES.md): update CHANGES.md

* Fixed use of document title sequence numbers

* Update apollo-portal/src/main/resources/static/i18n/en.json

Co-authored-by: Jason Song <nobodyiam@gmail.com>

* Update apollo-portal/src/main/resources/static/i18n/en.json

Co-authored-by: Jason Song <nobodyiam@gmail.com>

* Optimize the display of create consumer button

* Fix the problem of deleting consumer permissions

* Optimize ConsumerController related interface declaration

* Update apollo-portal/src/main/resources/static/i18n/en.json

Co-authored-by: Jason Song <nobodyiam@gmail.com>
kl 2 năm trước cách đây
mục cha
commit
5ab705de44

+ 2 - 0
CHANGES.md

@@ -13,6 +13,8 @@ Apollo 2.1.0
 * [Upgrade mysql-connector-java version to fix possible transaction rollback failure issue](https://github.com/apolloconfig/apollo/pull/4425)
 * [Remove database migration tool Flyway](https://github.com/apolloconfig/apollo/pull/4361)
 * [Optimize Spring-Security Firewall Deny Request Response 400](https://github.com/apolloconfig/apollo/pull/4428)
+* [Optimize the UI experience of open platform authorization management](https://github.com/apolloconfig/apollo/pull/4436)
 * [Allow users to associate multiple public namespaces at a time](https://github.com/apolloconfig/apollo/pull/4437)
+
 ------------------
 All issues and pull requests are [here](https://github.com/apolloconfig/apollo/milestone/11?closed=1)

+ 26 - 0
apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/service/ConsumerService.java

@@ -16,6 +16,7 @@
  */
 package com.ctrip.framework.apollo.openapi.service;
 
+import com.ctrip.framework.apollo.common.dto.PageDTO;
 import com.ctrip.framework.apollo.common.exception.BadRequestException;
 import com.ctrip.framework.apollo.openapi.entity.Consumer;
 import com.ctrip.framework.apollo.openapi.entity.ConsumerAudit;
@@ -38,7 +39,9 @@ import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.hash.Hashing;
+import java.util.Objects;
 import org.apache.commons.lang3.time.FastDateFormat;
+import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -291,4 +294,27 @@ public class ConsumerService {
 
     return appIds;
   }
+
+  public List<Consumer> findAllConsumer(Pageable page){
+    return this.consumerRepository.findAll(page).getContent();
+  }
+
+  @Transactional
+  public void deleteConsumer(String appId){
+    Consumer consumer = consumerRepository.findByAppId(appId);
+    if (consumer == null) {
+      throw new BadRequestException("ConsumerApp not exist");
+    }
+    long consumerId = consumer.getId();
+    List<ConsumerRole> consumerRoleList = consumerRoleRepository.findByConsumerId(consumerId);
+    ConsumerToken consumerToken = consumerTokenRepository.findByConsumerId(consumerId);
+
+    consumerRoleRepository.deleteAll(consumerRoleList);
+    consumerRepository.delete(consumer);
+
+    if (Objects.nonNull(consumerToken)) {
+      consumerTokenRepository.delete(consumerToken);
+    }
+  }
+
 }

+ 12 - 1
apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConsumerController.java

@@ -26,6 +26,7 @@ import com.ctrip.framework.apollo.openapi.service.ConsumerService;
 import com.ctrip.framework.apollo.portal.environment.Env;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
+import org.springframework.data.domain.Pageable;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
@@ -71,7 +72,7 @@ public class ConsumerController {
   }
 
   @PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
-  @GetMapping(value = "/consumers/by-appId")
+  @GetMapping(value = "/consumer-tokens/by-appId")
   public ConsumerToken getConsumerTokenByAppId(@RequestParam String appId) {
     return consumerService.getConsumerTokenByAppId(appId);
   }
@@ -119,6 +120,16 @@ public class ConsumerController {
     return consumerService.assignNamespaceRoleToConsumer(token, appId, namespaceName);
   }
 
+  @GetMapping("/consumers")
+  @PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
+  public List<Consumer> getConsumerList(Pageable page){
+    return consumerService.findAllConsumer(page);
+  }
 
+  @DeleteMapping(value = "/consumers/by-appId")
+  @PreAuthorize(value = "@permissionValidator.isSuperAdmin()")
+  public void deleteConsumers(@RequestParam String appId) {
+    consumerService.deleteConsumer(appId);
+  }
 
 }

+ 7 - 0
apollo-portal/src/main/resources/static/i18n/en.json

@@ -38,6 +38,8 @@
   "Common.PleaseChooseDepartment": "Please select department",
   "Common.PleaseChooseOwner": "Please select app owner",
   "Common.LoginExpiredTips": "Your login is expired. Please refresh the page and try again.",
+  "Common.Operation": "Operation",
+  "Common.Delete": "Delete",
   "Component.DeleteNamespace.Title": "Delete Namespace",
   "Component.DeleteNamespace.PublicContent": "Deleting namespace will cause the instances unable to get the configuration of this namespace. Are you sure to delete it?",
   "Component.DeleteNamespace.PrivateContent": "Deleting a private Namespace will cause the instances unable to get the configuration of this namespace, and the page will prompt 'missing namespace' (unless the AppNamespace is deleted by admin tool). Are you sure to delete it?",
@@ -591,6 +593,11 @@
   "Open.Manage.AppNotCreated": "App('{{appId}}') does not exist, please create it first",
   "Open.Manage.GrantSuccessfully": "Authorize Successfully",
   "Open.Manage.GrantFailed": "Failed to authorize",
+  "Open.Manage.ViewAndGrantPermission": "Grant Permission",
+  "Open.Manage.DeleteConsumer.Confirm": "You are deleting a third-party app with <b>AppId={{toOperationConsumer.appId}},AppName={{toOperationConsumer.name}}</b>,<br>Are you sure you want to delete?",
+  "Open.Manage.DeleteConsumer.Success": "Third-party app deleted successfully",
+  "Open.Manage.DeleteConsumer.Error": "Third-party app deletion failed",
+  "Open.Manage.CreateConsumer.Button": "Create Third-Party App",
   "Namespace.Role.Title": "Permission Management",
   "Namespace.Role.GrantModifyTo": "Permission to edit",
   "Namespace.Role.GrantModifyTo2": "(Can edit the configuration)",

+ 7 - 0
apollo-portal/src/main/resources/static/i18n/zh-CN.json

@@ -38,6 +38,8 @@
   "Common.PleaseChooseDepartment": "请选择部门",
   "Common.PleaseChooseOwner": "请选择应用负责人",
   "Common.LoginExpiredTips": "您的登录信息已过期,请刷新页面后重试",
+  "Common.Operation": "操作",
+  "Common.Delete": "删除",
   "Component.DeleteNamespace.Title": "删除 Namespace",
   "Component.DeleteNamespace.PublicContent": "删除 Namespace 将导致实例获取不到此 Namespace 的配置,确定要删除吗?",
   "Component.DeleteNamespace.PrivateContent": "删除私有 Namespace 将导致实例获取不到此 Namespace 的配置,且页面会提示缺失 Namespace(除非使用管理员工具删除 AppNamespace),确定要删除吗?",
@@ -591,6 +593,11 @@
   "Open.Manage.AppNotCreated": "App('{{appId}}')未创建,请先创建",
   "Open.Manage.GrantSuccessfully": "赋权成功",
   "Open.Manage.GrantFailed": "赋权失败",
+  "Open.Manage.ViewAndGrantPermission": "查看Token并赋权",
+  "Open.Manage.DeleteConsumer.Confirm": "您正在删除 <b>AppId='{{toOperationConsumer.appId}}',应用名称='{{toOperationConsumer.name}}'</b> 的第三方应用,<br>确定要删除吗?",
+  "Open.Manage.DeleteConsumer.Success": "第三方应用删除成功",
+  "Open.Manage.DeleteConsumer.Error": "第三方应用删除失败",
+  "Open.Manage.CreateConsumer.Button": "创建第三方应用",
   "Namespace.Role.Title": "权限管理",
   "Namespace.Role.GrantModifyTo": "修改权",
   "Namespace.Role.GrantModifyTo2": "(可以修改配置)",

+ 241 - 0
apollo-portal/src/main/resources/static/open/add-consumer.html

@@ -0,0 +1,241 @@
+<!--
+  ~ Copyright 2022 Apollo Authors
+  ~
+  ~ Licensed 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.
+  ~
+-->
+<!doctype html>
+<html ng-app="open_manage">
+
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <link rel="icon" href="../img/config.png">
+    <!-- styles -->
+    <link rel="stylesheet" type="text/css" href="../vendor/bootstrap/css/bootstrap.min.css">
+    <link rel="stylesheet" type="text/css" href="../vendor/angular/angular-toastr-1.4.1.min.css">
+    <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
+    <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
+    <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
+    <title>{{'Open.Manage.Title' | translate }}</title>
+</head>
+
+<body>
+
+    <apollonav></apollonav>
+
+
+    <div class="container-fluid" ng-controller="OpenManageController">
+        <div class="col-md-10 col-md-offset-1 panel">
+
+            <section class="panel-body" ng-show="isRootUser">
+                <!--project admin-->
+                <section class="row">
+                    <h5>{{'Open.Manage.CreateThirdApp' | translate }}
+                        <small>
+                            {{'Open.Manage.CreateThirdAppTips' | translate }}
+                        </small>
+                    </h5>
+                    <hr>
+                    <form class="form-horizontal">
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Open.Manage.ThirdAppId' | translate }}
+                            </label>
+                            <div class="col-sm-3">
+                                <input type="text" class="form-control" ng-model="consumer.appId">
+                                <small>{{'Open.Manage.ThirdAppIdTips' | translate }}</small>
+                            </div>
+                            <div class="col-sm-1">
+                                <button class="btn btn-info" ng-click="getTokenByAppId()">{{'Common.Search' | translate }}</button>
+                            </div>
+                            <div class="col-sm-6">
+                                <h4 style="color: red" ng-show="consumerToken"
+                                    ng-bind="'Token: ' + consumerToken.token"></h4>
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Common.Department' | translate }}
+                            </label>
+                            <div class="col-sm-3">
+                                <select id="organization">
+                                    <option></option>
+                                </select>
+                            </div>
+                        </div>
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Open.Manage.ThirdAppName' | translate }}
+                            </label>
+                            <div class="col-sm-3">
+                                <input type="text" class="form-control" ng-model="consumer.name">
+                                <small>{{'Open.Manage.ThirdAppNameTips' | translate }}</small>
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Open.Manage.ProjectOwner' | translate }}
+                            </label>
+                            <div class="col-sm-6 J_ownerSelectorPanel">
+                                <apollouserselector apollo-id="'ownerSelector'"></apollouserselector>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
+                            <div class="col-sm-offset-2 col-sm-9">
+                                <button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled"
+                                    ng-click="createConsumer()">
+                                    {{'Open.Manage.Create' | translate }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+                </section>
+
+                <section class="row">
+                    <h5>{{'Open.Manage.GrantPermission' | translate }}
+                        <small>
+                            {{'Open.Manage.GrantPermissionTips' | translate }}
+                        </small>
+                    </h5>
+                    <hr>
+                    <form class="form-horizontal" ng-submit="assignRoleToConsumer()">
+
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Open.Manage.Token' | translate }}
+                            </label>
+                            <div class="col-sm-5">
+                                <input type="text" class="form-control" ng-model="consumerRole.token" required>
+                            </div>
+                        </div>
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                <apollorequiredfield></apollorequiredfield>
+                                {{'Open.Manage.ManagedAppId' | translate }}
+                            </label>
+                            <div class="col-sm-3">
+                                <input type="text" class="form-control" ng-model="consumerRole.appId" required>
+                            </div>
+                        </div>
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.ManagedNamespace' | translate }}</label>
+                            <div class="col-sm-3">
+                                <input type="text" class="form-control" ng-model="consumerRole.namespaceName">
+                                <small>{{'Open.Manage.ManagedNamespaceTips' | translate }}</small>
+                            </div>
+                        </div>
+                        <div class="form-group" valdr-form-group>
+                            <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.GrantType' | translate }}
+                            </label>
+                            <div class="col-sm-3">
+                                <label class="radio-inline">
+                                    <input type="radio" name="inlineRadioOptions" ng-value="'NamespaceRole'"
+                                        ng-model="consumerRole.type">
+                                        {{'Open.Manage.GrantType.Namespace' | translate }}
+                                </label>
+                                <label class="radio-inline">
+                                    <input type="radio" name="inlineRadioOptions" ng-value="'AppRole'"
+                                        ng-model="consumerRole.type">
+                                        {{'Open.Manage.GrantType.App' | translate }}
+                                </label>
+                            </div>
+                        </div>
+                        <div class="form-group" valdr-form-group ng-show="consumerRole.type=='NamespaceRole'">
+                            <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.GrantEnv' | translate }}
+                            </label>
+                            <div class="col-sm-10">
+                                <div>
+                                    <label class="checkbox-inline" ng-repeat="env in envs">
+                                        <input type="checkbox" ng-checked="env.checked" ng-click="switchSelect(env)" />
+                                        {{env.env}}
+                                    </label>
+                                </div>
+                                <small>{{'Open.Manage.GrantEnvTips' | translate }}</small>
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <div class="col-sm-offset-2 col-sm-9">
+                                <button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled">
+                                        {{'Common.Submit' | translate }}
+                                </button>
+                            </div>
+                        </div>
+                    </form>
+
+                </section>
+
+            </section>
+
+            <section class="panel-body text-center" ng-if="!isRootUser">
+                <h4>{{'Common.IsRootUser' | translate }}</h4>
+            </section>
+
+        </div>
+    </div>
+
+    <div ng-include="'../views/common/footer.html'"></div>
+
+    <!-- jquery.js -->
+    <script src="../vendor/jquery.min.js" type="text/javascript"></script>
+
+    <!--angular-->
+    <script src="../vendor/angular/angular.min.js"></script>
+    <script src="../vendor/angular/angular-route.min.js"></script>
+    <script src="../vendor/angular/angular-resource.min.js"></script>
+    <script src="../vendor/angular/angular-toastr-1.4.1.tpls.min.js"></script>
+    <script src="../vendor/angular/loading-bar.min.js"></script>
+    <script src="../vendor/angular/angular-cookies.min.js"></script>
+
+    <script src="../vendor/angular/angular-translate.2.18.1/angular-translate.min.js"></script>
+    <script src="../vendor/angular/angular-translate.2.18.1/angular-translate-loader-static-files.min.js"></script>
+    <script src="../vendor/angular/angular-translate.2.18.1/angular-translate-storage-cookie.min.js"></script>
+    <!--valdr-->
+    <script src="../vendor/valdr/valdr.min.js" type="text/javascript"></script>
+    <script src="../vendor/valdr/valdr-message.min.js" type="text/javascript"></script>
+
+    <!-- bootstrap.js -->
+    <script src="../vendor/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
+
+    <script src="../vendor/lodash.min.js"></script>
+
+    <script src="../vendor/select2/select2.min.js" type="text/javascript"></script>
+    <!--biz-->
+    <!--must import-->
+    <script type="application/javascript" src="../scripts/app.js"></script>
+    <script type="application/javascript" src="../scripts/services/AppService.js"></script>
+    <script type="application/javascript" src="../scripts/services/EnvService.js"></script>
+    <script type="application/javascript" src="../scripts/services/UserService.js"></script>
+    <script type="application/javascript" src="../scripts/services/CommonService.js"></script>
+    <script type="application/javascript" src="../scripts/services/PermissionService.js"></script>
+    <script type="application/javascript" src="../scripts/services/OrganizationService.js"></script>
+    <script type="application/javascript" src="../scripts/services/ConsumerService.js"></script>
+
+    <script type="application/javascript" src="../scripts/AppUtils.js"></script>
+
+    <script type="application/javascript" src="../scripts/PageCommon.js"></script>
+    <script type="application/javascript" src="../scripts/directive/directive.js"></script>
+    <script type="application/javascript" src="../scripts/valdr.js"></script>
+
+    <script type="application/javascript" src="../scripts/controller/open/OpenManageController.js"></script>
+</body>
+
+</html>

+ 106 - 0
apollo-portal/src/main/resources/static/open/grant-permission-modal.html

@@ -0,0 +1,106 @@
+<div id="grantPermissionModal" class="modal fade">
+    <!--
+      ~ Copyright 2022 Apollo Authors
+      ~
+      ~ Licensed 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.
+      ~
+    -->
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header panel-primary">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
+                    aria-hidden="true">&times;</span></button>
+<!--                <h4 class="modal-title">{{title}}</h4>-->
+                <h4 class="modal-title">{{'Open.Manage.GrantPermission' | translate }}
+                    <small>
+                        {{'Open.Manage.GrantPermissionTips' | translate }}
+                    </small>
+                </h4>
+            </div>
+            <div class="modal-body form-horizontal">
+                <section class="panel-body">
+                    <section class="row">
+                        <form class="form-horizontal" ng-submit="doAssignRoleToConsumer()">
+
+                            <div class="form-group" valdr-form-group>
+                                <label class="col-sm-2 control-label">
+                                    <apollorequiredfield></apollorequiredfield>
+                                    {{'Open.Manage.Token' | translate }}
+                                </label>
+                                <div class="col-sm-5">
+                                    <input type="text" class="form-control" ng-model="consumerRole.token" disabled required>
+                                </div>
+                            </div>
+                            <div class="form-group" valdr-form-group>
+                                <label class="col-sm-2 control-label">
+                                    <apollorequiredfield></apollorequiredfield>
+                                    {{'Open.Manage.ManagedAppId' | translate }}
+                                </label>
+                                <div class="col-sm-3">
+                                    <input type="text" class="form-control" ng-model="consumerRole.appId" required>
+                                </div>
+                            </div>
+                            <div class="form-group" valdr-form-group>
+                                <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.ManagedNamespace' | translate }}</label>
+                                <div class="col-sm-3">
+                                    <input type="text" class="form-control" ng-model="consumerRole.namespaceName">
+                                    <small>{{'Open.Manage.ManagedNamespaceTips' | translate }}</small>
+                                </div>
+                            </div>
+                            <div class="form-group" valdr-form-group>
+                                <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.GrantType' | translate }}
+                                </label>
+                                <div class="col-sm-3">
+                                    <label class="radio-inline">
+                                        <input type="radio" name="inlineRadioOptions" ng-value="'NamespaceRole'"
+                                               ng-model="consumerRole.type">
+                                        {{'Open.Manage.GrantType.Namespace' | translate }}
+                                    </label>
+                                    <label class="radio-inline">
+                                        <input type="radio" name="inlineRadioOptions" ng-value="'AppRole'"
+                                               ng-model="consumerRole.type">
+                                        {{'Open.Manage.GrantType.App' | translate }}
+                                    </label>
+                                </div>
+                            </div>
+                            <div class="form-group" valdr-form-group ng-show="consumerRole.type=='NamespaceRole'">
+                                <label class="col-sm-2 control-label">
+                                    {{'Open.Manage.GrantEnv' | translate }}
+                                </label>
+                                <div class="col-sm-10">
+                                    <div>
+                                        <label class="checkbox-inline" ng-repeat="env in envs">
+                                            <input type="checkbox" ng-checked="env.checked" ng-click="switchSelect(env)" />
+                                            {{env.env}}
+                                        </label>
+                                    </div>
+                                    <small>{{'Open.Manage.GrantEnvTips' | translate }}</small>
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                <div class="col-sm-offset-2 col-sm-9">
+                                    <button type="submit" class="btn btn-primary">
+                                        {{'Common.Submit' | translate }}
+                                    </button>
+                                </div>
+                            </div>
+                        </form>
+
+                </section>
+                </section>
+            </div>
+        </div>
+    </div>
+</div>

+ 63 - 138
apollo-portal/src/main/resources/static/open/manage.html

@@ -26,6 +26,7 @@
     <link rel="stylesheet" type="text/css" media='all' href="../vendor/angular/loading-bar.min.css">
     <link rel="stylesheet" type="text/css" href="../styles/common-style.css">
     <link rel="stylesheet" type="text/css" href="../vendor/select2/select2.min.css">
+    <link rel="stylesheet" type="text/css" href="../vendor/iconfont/iconfont.css">
     <title>{{'Open.Manage.Title' | translate }}</title>
 </head>
 
@@ -33,153 +34,76 @@
 
     <apollonav></apollonav>
 
-
-    <div class="container-fluid" ng-controller="OpenManageController">
+    <div id="consumer-list" class="container-fluid" ng-controller="OpenManageController">
         <div class="col-md-10 col-md-offset-1 panel">
 
             <section class="panel-body" ng-show="isRootUser">
                 <!--project admin-->
                 <section class="row">
-                    <h5>{{'Open.Manage.CreateThirdApp' | translate }}
-                        <small>
-                            {{'Open.Manage.CreateThirdAppTips' | translate }}
-                        </small>
-                    </h5>
-                    <hr>
-                    <form class="form-horizontal">
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Open.Manage.ThirdAppId' | translate }}
-                            </label>
-                            <div class="col-sm-3">
-                                <input type="text" class="form-control" ng-model="consumer.appId">
-                                <small>{{'Open.Manage.ThirdAppIdTips' | translate }}</small>
-                            </div>
-                            <div class="col-sm-1">
-                                <button class="btn btn-info" ng-click="getTokenByAppId()">{{'Common.Search' | translate }}</button>
-                            </div>
-                            <div class="col-sm-6">
-                                <h4 style="color: red" ng-show="consumerToken"
-                                    ng-bind="'Token: ' + consumerToken.token"></h4>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Common.Department' | translate }}
-                            </label>
-                            <div class="col-sm-3">
-                                <select id="organization">
-                                    <option></option>
-                                </select>
-                            </div>
-                        </div>
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Open.Manage.ThirdAppName' | translate }}
-                            </label>
-                            <div class="col-sm-3">
-                                <input type="text" class="form-control" ng-model="consumer.name">
-                                <small>{{'Open.Manage.ThirdAppNameTips' | translate }}</small>
-                            </div>
+                    <div class="row">
+                        <div class="col-md-6">
+                            <h5>{{'Open.Manage.CreateThirdApp' | translate }}
+                                <small>
+                                    {{'Open.Manage.CreateThirdAppTips' | translate }}
+                                </small>
+                            </h5>
                         </div>
-                        <div class="form-group">
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Open.Manage.ProjectOwner' | translate }}
-                            </label>
-                            <div class="col-sm-6 J_ownerSelectorPanel">
-                                <apollouserselector apollo-id="'ownerSelector'"></apollouserselector>
-                            </div>
+                        <div class="col-md-6">
+                            <a class="btn btn-primary btn-md create-btn pull-right"
+                               href="{{ '/open/add-consumer.html' | prefixPath }}" target="_blank">
+                                <img src="../img/plus.png"/>
+                                {{'Open.Manage.CreateConsumer.Button' | translate }}
+                            </a>
                         </div>
-
-                        <div class="form-group">
-                            <div class="col-sm-offset-2 col-sm-9">
-                                <button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled"
-                                    ng-click="createConsumer()">
-                                    {{'Open.Manage.Create' | translate }}
-                                </button>
-                            </div>
+                    </div>
+                    <div class="row margin-top10" >
+                        <table class="table">
+                            <tr>
+                                <th style="width: 10%">{{'Common.AppId' | translate }}</th>
+                                <th style="width: 15%">{{'Common.AppName' | translate }}</th>
+                                <th style="width: 15%">{{'Common.AppOwner' | translate }}</th>
+                                <th style="width: 20%">{{'Common.Department' | translate }}</th>
+                                <th style="width: 20%">{{'Common.Email' | translate }}</th>
+                                <th style="width: 20%">{{'Common.Operation' | translate}}</th>
+                            </tr>
+                            <tr ng-repeat="app in consumerList" href="#">
+                                <td style="width: 10%">{{ app.appId }}</td>
+                                <td style="width: 15%">{{ app.name }}</td>
+                                <td style="width: 15%">{{ app.ownerName }}</td>
+                                <td style="width: 20%">{{ app.orgName + '(' + app.orgId + ')' }}</td>
+                                <td style="width: 20%">{{ app.ownerEmail }}</td>
+                                <td style="width: 20%;">
+                                    <button class="btn btn-default btn-md" ng-click="preGrantPermission(app)">
+                                        <img class="more-img" src="../img/edit.png" data-tooltip="tooltip"
+                                             data-placement="bottom">{{'Open.Manage.ViewAndGrantPermission' | translate}}
+                                    </button>
+
+                                    <button class="btn btn-default btn-md" ng-click="preDeleteConsumer(app)">
+                                        <img class="more-img" style="margin-left: 5px;" src="../img/cancel.png" data-tooltip="tooltip"
+                                             data-placement="bottom">{{'Common.Delete' | translate}}
+                                    </button>
+
+                                </td>
+                            </tr>
+
+                        </table>
+                    </div>
+                    <div ng-show="!hasMoreconsumerList" style="height: 15px"></div>
+                    <div class="homepage-loading-more-panel" ng-show="hasMoreconsumerList"
+                         ng-click="getConsumerList()">
+                        <div href="#" class="thumbnail hover cursor-pointer"
+                             style="display: flex;justify-content: center;align-items: center">
+                            <div><img class="more-img" src="../img/more.png" /></div>
+                            <div style="margin-left: 5px"><h5>{{'Index.LoadMore' | translate }}</h5></div>
                         </div>
-                    </form>
-                </section>
+                    </div>
+                    <apolloconfirmdialog apollo-dialog-id="'deleteConsumerDialog'"
+                                         apollo-title="'Delete.DeleteApp' | translate"
+                                         apollo-detail="'Open.Manage.DeleteConsumer.Confirm' | translate:this" apollo-show-cancel-btn="true"
+                                         apollo-confirm="deleteConsumer"></apolloconfirmdialog>
 
-                <section class="row">
-                    <h5>{{'Open.Manage.GrantPermission' | translate }}
-                        <small>
-                            {{'Open.Manage.GrantPermissionTips' | translate }}
-                        </small>
-                    </h5>
-                    <hr>
-                    <form class="form-horizontal" ng-submit="assignRoleToConsumer()">
-
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Open.Manage.Token' | translate }}
-                            </label>
-                            <div class="col-sm-5">
-                                <input type="text" class="form-control" ng-model="consumerRole.token" required>
-                            </div>
-                        </div>
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                <apollorequiredfield></apollorequiredfield>
-                                {{'Open.Manage.ManagedAppId' | translate }}
-                            </label>
-                            <div class="col-sm-3">
-                                <input type="text" class="form-control" ng-model="consumerRole.appId" required>
-                            </div>
-                        </div>
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                    {{'Open.Manage.ManagedNamespace' | translate }}</label>
-                            <div class="col-sm-3">
-                                <input type="text" class="form-control" ng-model="consumerRole.namespaceName">
-                                <small>{{'Open.Manage.ManagedNamespaceTips' | translate }}</small>
-                            </div>
-                        </div>
-                        <div class="form-group" valdr-form-group>
-                            <label class="col-sm-2 control-label">
-                                    {{'Open.Manage.GrantType' | translate }}
-                            </label>
-                            <div class="col-sm-3">
-                                <label class="radio-inline">
-                                    <input type="radio" name="inlineRadioOptions" ng-value="'NamespaceRole'"
-                                        ng-model="consumerRole.type">
-                                        {{'Open.Manage.GrantType.Namespace' | translate }}
-                                </label>
-                                <label class="radio-inline">
-                                    <input type="radio" name="inlineRadioOptions" ng-value="'AppRole'"
-                                        ng-model="consumerRole.type">
-                                        {{'Open.Manage.GrantType.App' | translate }}
-                                </label>
-                            </div>
-                        </div>
-                        <div class="form-group" valdr-form-group ng-show="consumerRole.type=='NamespaceRole'">
-                            <label class="col-sm-2 control-label">
-                                    {{'Open.Manage.GrantEnv' | translate }}
-                            </label>
-                            <div class="col-sm-10">
-                                <div>
-                                    <label class="checkbox-inline" ng-repeat="env in envs">
-                                        <input type="checkbox" ng-checked="env.checked" ng-click="switchSelect(env)" />
-                                        {{env.env}}
-                                    </label>
-                                </div>
-                                <small>{{'Open.Manage.GrantEnvTips' | translate }}</small>
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <div class="col-sm-offset-2 col-sm-9">
-                                <button type="submit" class="btn btn-primary" ng-disabled="submitBtnDisabled">
-                                        {{'Common.Submit' | translate }}
-                                </button>
-                            </div>
-                        </div>
-                    </form>
+                    <grantpermissionmodal consumer-role="consumerRole" assign-role-to-consumer="assignRoleToConsumer">
+                    </grantpermissionmodal>
 
                 </section>
 
@@ -233,6 +157,7 @@
 
     <script type="application/javascript" src="../scripts/PageCommon.js"></script>
     <script type="application/javascript" src="../scripts/directive/directive.js"></script>
+    <script type="application/javascript" src="../scripts/directive/open-manage-grant-permission-modal-directive.js"></script>
     <script type="application/javascript" src="../scripts/valdr.js"></script>
 
     <script type="application/javascript" src="../scripts/controller/open/OpenManageController.js"></script>

+ 50 - 0
apollo-portal/src/main/resources/static/scripts/controller/open/OpenManageController.js

@@ -29,15 +29,24 @@ function OpenManageController($scope, $translate, toastr, AppUtil, OrganizationS
 
     $scope.submitBtnDisabled = false;
     $scope.userSelectWidgetId = 'toAssignMasterRoleUser';
+    $scope.consumerListPage = 0;
+    $scope.consumerList = [];
+    $scope.hasMoreconsumerList = false;
+    $scope.toOperationConsumer={}
 
     $scope.getTokenByAppId = getTokenByAppId;
     $scope.createConsumer = createConsumer;
     $scope.assignRoleToConsumer = assignRoleToConsumer;
+    $scope.getConsumerList = getConsumerList;
+    $scope.preDeleteConsumer = preDeleteConsumer;
+    $scope.deleteConsumer = deleteConsumer;
+    $scope.preGrantPermission = preGrantPermission;
 
     function init() {
         initOrganization();
         initPermission();
         initEnv();
+        getConsumerList();
     }
 
     function initOrganization() {
@@ -60,6 +69,41 @@ function OpenManageController($scope, $translate, toastr, AppUtil, OrganizationS
         });
     }
 
+    function getConsumerList() {
+        var size = 10;
+        ConsumerService.getConsumerList($scope.consumerListPage, size)
+        .then(function (result) {
+            $scope.consumerListPage += 1;
+            $scope.hasMoreconsumerList = result.length === size;
+
+            if (!result || result.length === 0) {
+                return;
+            }
+            result.forEach(function (app) {
+                $scope.consumerList.push(app);
+            });
+
+        })
+    }
+
+    let toDeleteAppId = '';
+
+    function preDeleteConsumer(app) {
+        $scope.toOperationConsumer = app;
+        toDeleteAppId = app.appId;
+        $("#deleteConsumerDialog").modal("show");
+    }
+
+    function deleteConsumer(){
+        ConsumerService.deleteConsumer(toDeleteAppId)
+        .then(function () {
+            toastr.success($translate.instant('Open.Manage.DeleteConsumer.Success'));
+            $scope.consumerList = $scope.consumerList.filter(consumer => consumer.appId !== toDeleteAppId);
+        },function (error) {
+            toastr.error(AppUtil.errorMsg(error), $translate.instant('Open.Manage.DeleteConsumer.Error'));
+        })
+    }
+
     function initPermission() {
         PermissionService.has_root_permission()
             .then(function (result) {
@@ -150,6 +194,12 @@ function OpenManageController($scope, $translate, toastr, AppUtil, OrganizationS
 
     }
 
+    function preGrantPermission(app){
+        $scope.consumer.appId = app.appId;
+        getTokenByAppId();
+        AppUtil.showModal('#grantPermissionModal');
+    }
+
     function assignRoleToConsumer() {
         ConsumerService.assignRoleToConsumer($scope.consumerRole.token,
             $scope.consumerRole.type,

+ 78 - 0
apollo-portal/src/main/resources/static/scripts/directive/open-manage-grant-permission-modal-directive.js

@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 Apollo Authors
+ *
+ * Licensed 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.
+ *
+ */
+directive_module.directive('grantpermissionmodal', grantPermissionModalDirective);
+
+function grantPermissionModalDirective($translate, toastr, $sce, AppUtil, EnvService, ConsumerService) {
+    return {
+        restrict: 'E',
+        templateUrl: AppUtil.prefixPath() + '/open/grant-permission-modal.html',
+        transclude: true,
+        replace: true,
+        scope: {
+            consumerRole: '=',
+            assignRoleToConsumer: '=',
+        },
+        link: function (scope) {
+            scope.initialized = false;
+            scope.envs = [];
+            scope.envsChecked = [];
+
+            if(!scope.initialized){
+                initEnv();
+            }
+
+            scope.doAssignRoleToConsumer = function () {
+                ConsumerService.assignRoleToConsumer(scope.consumerRole.token,
+                    scope.consumerRole.type,
+                    scope.consumerRole.appId,
+                    scope.consumerRole.namespaceName,
+                    scope.envsChecked)
+                .then(function (consumerRoles) {
+                    toastr.success($translate.instant('Open.Manage.GrantSuccessfully'));
+                    AppUtil.hideModal('#grantPermissionModal');
+                    scope.consumerRole = {}
+                }, function (response) {
+                    AppUtil.showErrorMsg(response, $translate.instant('Open.Manage.GrantFailed'));
+                })
+            }
+
+            function initEnv() {
+                EnvService.find_all_envs()
+                .then(function (result) {
+                    for (let iLoop = 0; iLoop < result.length; iLoop++) {
+                        scope.envs.push({ checked: false, env: result[iLoop] });
+                        scope.envsChecked = [];
+                    }
+
+                    scope.envsChecked.switchSelect = function (item) {
+                        item.checked = !item.checked;
+                        scope.envsChecked = [];
+                        for (let iLoop = 0; iLoop < scope.envs.length; iLoop++) {
+                            const env = scope.envs[iLoop];
+                            if (env.checked) {
+                                scope.envsChecked.push(env.env);
+                            }
+                        }
+                    };
+                });
+            }
+
+        }
+    }
+}
+
+

+ 26 - 1
apollo-portal/src/main/resources/static/scripts/services/ConsumerService.js

@@ -25,12 +25,22 @@ appService.service('ConsumerService', ['$resource', '$q', 'AppUtil',
         get_consumer_token_by_appId: {
             method: 'GET',
             isArray: false,
-            url: AppUtil.prefixPath() + '/consumers/by-appId'
+            url: AppUtil.prefixPath() + '/consumer-tokens/by-appId'
         },
         assign_role_to_consumer: {
             method: 'POST',
             isArray: true,
             url: AppUtil.prefixPath() + '/consumers/:token/assign-role'
+        },
+        get_consumer_list: {
+            method: 'GET',
+            isArray: true,
+            url: AppUtil.prefixPath() + '/consumers'
+        },
+        delete_consumer: {
+            method: 'DELETE',
+            isArray: false,
+            url: AppUtil.prefixPath() + '/consumers/by-appId'
         }
 
     });
@@ -57,6 +67,21 @@ appService.service('ConsumerService', ['$resource', '$q', 'AppUtil',
                                     namespaceName: namespaceName
                                 }
             )
+        },
+        getConsumerList: function (page, size){
+            return AppUtil.ajax(resource.get_consumer_list,
+                {
+                    page: page,
+                    size: size
+                }
+            )
+        },
+        deleteConsumer: function (appId){
+            return AppUtil.ajax(resource.delete_consumer,
+                {
+                    appId: appId
+                }
+            )
         }
     }
 }]);

+ 32 - 0
apollo-portal/src/main/resources/static/styles/common-style.css

@@ -1141,3 +1141,35 @@ table th {
     height: 35px;
     margin-top: -4px
 }
+
+
+.margin-top10 { margin-top:10px; }
+
+#consumer-list th {
+    border-bottom: 1px solid #E4E7ED;
+    padding: 15px 8px 15px 8px;
+    font-size: 16px;
+    text-align: left;
+    word-break: break-all;
+}
+
+#consumer-list td {
+    border-bottom: 1px solid #E4E7ED;
+    padding: 15px 8px 15px 8px;
+    font-size: 14px;
+    word-break: break-all;
+}
+
+#consumer-list table {
+    margin-left: 20px;
+}
+
+#consumer-list .more-img {
+    width: 20px;
+    height: 20px;
+}
+
+#consumer-list .create-btn img {
+    width: 16px;
+    height: 16px;
+}

+ 36 - 0
apollo-portal/src/test/java/com/ctrip/framework/apollo/openapi/service/ConsumerServiceIntegrationTest.java

@@ -19,11 +19,19 @@ package com.ctrip.framework.apollo.openapi.service;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
+import com.ctrip.framework.apollo.common.exception.BadRequestException;
+import com.ctrip.framework.apollo.openapi.entity.Consumer;
 import com.ctrip.framework.apollo.portal.AbstractIntegrationTest;
 import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.List;
 import java.util.Set;
+import org.assertj.core.api.Assertions;
+import org.junit.Assert;
 import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
 import org.springframework.test.context.jdbc.Sql;
 
 /**
@@ -42,4 +50,32 @@ public class ConsumerServiceIntegrationTest extends AbstractIntegrationTest {
     assertEquals(Sets.newHashSet("consumer-test-app-id-0", "consumer-test-app-id-1"), appIds);
     assertFalse(appIds.contains("consumer-test-app-id-2"));
   }
+
+  @Test
+  @Sql(scripts = "/sql/openapi/ConsumerServiceIntegrationTest.commonData.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
+  @Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
+  public void testFindAllConsumer() {
+    List<Consumer> consumerList = consumerService.findAllConsumer(Pageable.ofSize(1));
+    assertEquals(1, consumerList.size());
+    consumerList = consumerService.findAllConsumer(Pageable.ofSize(4));
+    assertEquals(4, consumerList.size());
+  }
+
+  @Test
+  @Sql(scripts = "/sql/openapi/ConsumerServiceIntegrationTest.commonData.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
+  @Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
+  public void testDeleteConsumer() {
+    long consumerId = 1000;
+    String appId = "consumer-test-app-role";
+
+    Assertions.assertThatNoException()
+        .isThrownBy(()-> consumerService.deleteConsumer(appId));
+
+    Assertions.assertThatExceptionOfType(BadRequestException.class)
+        .isThrownBy(()-> consumerService.deleteConsumer(appId))
+        .withMessage("ConsumerApp not exist");
+
+    Assertions.assertThat(consumerService.getConsumerByConsumerId(consumerId))
+        .isNull();
+  }
 }

+ 265 - 0
apollo-portal/src/test/resources/sql/openapi/ConsumerServiceIntegrationTest.commonData.sql

@@ -0,0 +1,265 @@
+--
+-- Copyright 2022 Apollo Authors
+--
+-- Licensed 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.
+--
+
+/*
+	This sql is dumped from a apollo portal database.
+
+	The logic is as follows
+
+	create app:
+		consumer-test-app-id-0
+		consumer-test-app-id-1
+	    consumer-test-app-id-2
+
+	create consumer:
+		consumer-test-app-role
+
+	Authorization, let consumer-test-app-role manage:
+		consumer-test-app-id-0:
+			Authorization type: App
+		consumer-test-app-id-1:
+			Authorization type: Namespace
+			Managed Namespace: application
+*/
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET NAMES utf8 */;
+/*!50503 SET NAMES utf8mb4 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+/*!40000 ALTER TABLE `App` DISABLE KEYS */;
+INSERT INTO `App` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'consumer-test-app-id-0', 'consumer-test-app-id-0', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+INSERT INTO `App` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 'consumer-test-app-id-1', 'consumer-test-app-id-1', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+INSERT INTO `App` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 'consumer-test-app-id-2', 'consumer-test-app-id-2', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+/*!40000 ALTER TABLE `App` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `AppNamespace` DISABLE KEYS */;
+INSERT INTO `AppNamespace` (`Id`, `Name`, `AppId`, `Format`, `Comment`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'application', 'consumer-test-app-id-0', 'properties', 'default app namespace', 'apollo', 'apollo');
+INSERT INTO `AppNamespace` (`Id`, `Name`, `AppId`, `Format`, `Comment`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 'application', 'consumer-test-app-id-1', 'properties', 'default app namespace', 'apollo', 'apollo');
+INSERT INTO `AppNamespace` (`Id`, `Name`, `AppId`, `Format`, `Comment`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 'application', 'consumer-test-app-id-2', 'properties', 'default app namespace', 'apollo', 'apollo');
+/*!40000 ALTER TABLE `AppNamespace` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `Consumer` DISABLE KEYS */;
+INSERT INTO `Consumer` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'consumer-test-app-role', 'consumer-test-app-role', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+INSERT INTO `Consumer` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1001, 'consumer-test-app-role1', 'consumer-test-app-role1', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+INSERT INTO `Consumer` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1002, 'consumer-test-app-role2', 'consumer-test-app-role2', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+INSERT INTO `Consumer` (`Id`, `AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1003, 'consumer-test-app-role3', 'consumer-test-app-role3', 'TEST2', '样例部门2', 'apollo', 'apollo@acme.com', 'apollo', 'apollo');
+
+/*!40000 ALTER TABLE `Consumer` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `ConsumerAudit` DISABLE KEYS */;
+/*!40000 ALTER TABLE `ConsumerAudit` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `ConsumerRole` DISABLE KEYS */;
+INSERT INTO `ConsumerRole` (`Id`, `ConsumerId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 1000, 1000, 'apollo', 'apollo');
+INSERT INTO `ConsumerRole` (`Id`, `ConsumerId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 1000, 11000, 'apollo', 'apollo');
+INSERT INTO `ConsumerRole` (`Id`, `ConsumerId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 1000, 12000, 'apollo', 'apollo');
+/*!40000 ALTER TABLE `ConsumerRole` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `ConsumerToken` DISABLE KEYS */;
+INSERT INTO `ConsumerToken` (`Id`, `ConsumerId`, `Token`, `Expires`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 1000, '3c16bf5b1f44b465179253442460e8c0ad845289', '2098-12-31 10:00:00', 'apollo', 'apollo');
+/*!40000 ALTER TABLE `ConsumerToken` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `Favorite` DISABLE KEYS */;
+/*!40000 ALTER TABLE `Favorite` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `Permission` DISABLE KEYS */;
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'AssignRole', 'consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 'CreateNamespace', 'consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 'CreateCluster', 'consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(4000, 'ManageAppMaster', 'consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(5000, 'ModifyNamespace', 'consumer-test-app-id-0+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(6000, 'ReleaseNamespace', 'consumer-test-app-id-0+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(7000, 'ModifyNamespace', 'consumer-test-app-id-0+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(8000, 'ReleaseNamespace', 'consumer-test-app-id-0+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(9000, 'CreateNamespace', 'consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(10000, 'AssignRole', 'consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(11000, 'CreateCluster', 'consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(12000, 'ManageAppMaster', 'consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(13000, 'ModifyNamespace', 'consumer-test-app-id-1+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(14000, 'ReleaseNamespace', 'consumer-test-app-id-1+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(15000, 'ModifyNamespace', 'consumer-test-app-id-1+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(16000, 'ReleaseNamespace', 'consumer-test-app-id-1+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(17000, 'CreateCluster', 'consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(18000, 'AssignRole', 'consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(19000, 'CreateNamespace', 'consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(20000, 'ManageAppMaster', 'consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(21000, 'ModifyNamespace', 'consumer-test-app-id-2+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(22000, 'ReleaseNamespace', 'consumer-test-app-id-2+application', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(23000, 'ModifyNamespace', 'consumer-test-app-id-2+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(24000, 'ReleaseNamespace', 'consumer-test-app-id-2+application+DEV', 'apollo', 'apollo');
+/*!40000 ALTER TABLE `Permission` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `Role` DISABLE KEYS */;
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'Master+consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 'ManageAppMaster+consumer-test-app-id-0', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 'ModifyNamespace+consumer-test-app-id-0+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(4000, 'ReleaseNamespace+consumer-test-app-id-0+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(5000, 'ModifyNamespace+consumer-test-app-id-0+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(6000, 'ReleaseNamespace+consumer-test-app-id-0+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(7000, 'Master+consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(8000, 'ManageAppMaster+consumer-test-app-id-1', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(9000, 'ModifyNamespace+consumer-test-app-id-1+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(10000, 'ReleaseNamespace+consumer-test-app-id-1+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(11000, 'ModifyNamespace+consumer-test-app-id-1+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(12000, 'ReleaseNamespace+consumer-test-app-id-1+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(13000, 'Master+consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(14000, 'ManageAppMaster+consumer-test-app-id-2', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(15000, 'ModifyNamespace+consumer-test-app-id-2+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(16000, 'ReleaseNamespace+consumer-test-app-id-2+application', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(17000, 'ModifyNamespace+consumer-test-app-id-2+application+DEV', 'apollo', 'apollo');
+INSERT INTO `Role` (`Id`, `RoleName`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(18000, 'ReleaseNamespace+consumer-test-app-id-2+application+DEV', 'apollo', 'apollo');
+/*!40000 ALTER TABLE `Role` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `RolePermission` DISABLE KEYS */;
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 1000, 1000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 1000, 2000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 1000, 3000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(4000, 2000, 4000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(5000, 3000, 5000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(6000, 4000, 6000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(7000, 5000, 7000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(8000, 6000, 8000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(9000, 7000, 9000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(10000, 7000, 10000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(11000, 7000, 11000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(12000, 8000, 12000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(13000, 9000, 13000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(14000, 10000, 14000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(15000, 11000, 15000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(16000, 12000, 16000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(17000, 13000, 17000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(18000, 13000, 18000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(19000, 13000, 19000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(20000, 14000, 20000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(21000, 15000, 21000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(22000, 16000, 22000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(23000, 17000, 23000, 'apollo', 'apollo');
+INSERT INTO `RolePermission` (`Id`, `RoleId`, `PermissionId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(24000, 18000, 24000, 'apollo', 'apollo');
+/*!40000 ALTER TABLE `RolePermission` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `UserRole` DISABLE KEYS */;
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(1000, 'apollo', 1000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(2000, 'apollo', 3000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(3000, 'apollo', 4000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(4000, 'apollo', 7000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(5000, 'apollo', 9000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(6000, 'apollo', 10000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(7000, 'apollo', 13000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(8000, 'apollo', 15000, 'apollo', 'apollo');
+INSERT INTO `UserRole` (`Id`, `UserId`, `RoleId`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) VALUES
+(9000, 'apollo', 16000, 'apollo', 'apollo');
+/*!40000 ALTER TABLE `UserRole` ENABLE KEYS */;
+
+/*!40000 ALTER TABLE `Users` DISABLE KEYS */;
+INSERT INTO `Users` (`Id`, `Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) VALUES
+(1000, 'apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1);
+/*!40000 ALTER TABLE `Users` ENABLE KEYS */;
+
+/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
+/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;

BIN
doc/images/apollo-open-manage-list.png


BIN
doc/images/apollo-open-manage-token.png


+ 16 - 10
docs/en/usage/apollo-open-api-platform.md

@@ -13,24 +13,32 @@ The basic information is as follows.
 * AppId, app name, department of the third-party application
 * The person in charge of the third-party app
 
-Apollo administrator creates the third-party application at `http://{portal_address}/open/manage.html`. It is better to check whether this AppId has been created before creating it. After successful creation, a token will be generated as follows.
+Apollo administrator creates the third-party application at `http://{portal_address}/open/add-consumer.html`. It is better to check whether this AppId has been created before creating it. After successful creation, a token will be generated as follows.
 
 ![Open Platform Management](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage.png)
 
-#### 2.2 Authorization for registered third-party apps
+#### 2.2 View third-party apps
+Apollo administrator in `http://{portal_address}/open/manage.html` The HTML page allows you to view the list of third-party applications. It also provides management operations such as [View token and empower] and [delete], as shown in the following figure:
+![第三方应用列表](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage-list.png)
 
-Third-party applications should not be able to manipulate any Namespace configuration, so you need to bind the token to a Namespace that can be manipulated. Apollo administrators assign rights to the token in the `http://{portal_address}/open/manage.html` page. After the assignment, the third-party application can manage the configuration of the authorized Namespace through the Http REST interface provided by Apollo.
+The modal box page of [View token and empower] is shown in the following figure:
+![查看Token并赋权](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage-token.png)
 
-#### 2.3 Third-party application calls Apollo Open API
 
-##### 2.3.1 Calling the Http REST Interface
+#### 2.3 Authorization for registered third-party apps
+
+Third-party applications should not be able to manipulate any Namespace configuration, so you need to bind the token to a Namespace that can be manipulated. Apollo administrators assign rights to the token in the `http://{portal_address}/open/add-consumer.html` page. After the assignment, the third-party application can manage the configuration of the authorized Namespace through the Http REST interface provided by Apollo.
+
+#### 2.4 Third-party application calls Apollo Open API
+
+##### 2.4.1 Calling the Http REST Interface
 
 Third-party applications in any language can call Apollo's Open API. When calling the interface, you need to set attention to the following two points.
 
  * Add an Authorization field to the Http Header, with the field value of the applied token
  * Http Header Content-Type field needs to be set to application/json;charset=UTF-8
 
-##### 2.3.2 Java application calls Apollo Open API via apollo-openapi
+##### 2.4.2 Java application calls Apollo Open API via apollo-openapi
 
 Starting from version 1.1.0, Apollo provides the [apollo-openapi](https://github.com/apolloconfig/apollo/tree/master/apollo-openapi) client, so third-party applications in the Java language can more easily invoke the Apollo Open API.
 
@@ -57,11 +65,11 @@ ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
 
 You can then operate the Apollo Open API directly through the `ApolloOpenApiClient` interface, see the Rest interface documentation below for a description of the interface.
 
-##### 2.3.3 .Net core application calls Apollo Open API
+##### 2.4.3 .Net core application calls Apollo Open API
 
 Net core also provides a client for the open api, see https://github.com/ctripcorp/apollo.net/pull/77 for details
 
-##### 2.3.4 Shell Scripts calls Apollo Open API
+##### 2.4.4 Shell Scripts calls Apollo Open API
 
 Encapsulated bash functions, the underlying use of curl to send HTTP requests
 
@@ -159,8 +167,6 @@ Encapsulated bash functions, the underlying use of curl to send HTTP requests
 
 ##### 3.2.3 Getting the cluster interface 
 
-##### 3.2.3 Getting the cluster interface 
-
 * **URL** : `http://{portal_address}/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}`
 * **Method** : GET
 * **Request Params** : None

+ 17 - 8
docs/zh/usage/apollo-open-api-platform.md

@@ -13,21 +13,30 @@ Apollo提供了一套的Http REST接口,使第三方应用能够自己管理
 * 第三方应用的AppId、应用名、部门
 * 第三方应用负责人
 
-Apollo管理员在 `http://{portal_address}/open/manage.html` 创建第三方应用,创建之前最好先查询此AppId是否已经创建。创建成功之后会生成一个token,如下图所示:
+Apollo管理员在 `http://{portal_address}/open/add-consumer.html` 创建第三方应用,创建之前最好先查询此AppId是否已经创建。创建成功之后会生成一个token,如下图所示:
 
 ![开放平台管理](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage.png)
 
-#### 2.2 给已注册的第三方应用授权
-第三方应用不应该能操作任何Namespace的配置,所以需要给token绑定可以操作的Namespace。Apollo管理员在 `http://{portal_address}/open/manage.html` 页面给token赋权。赋权之后,第三方应用就可以通过Apollo提供的Http REST接口来管理已授权的Namespace的配置了。
+#### 2.2 查看第三方应用
+Apollo管理员在 `http://{portal_address}/open/manage.html` 页面可以查看第三方应用列表。并提供了【查看Token并赋权】、【删除】等管理操作,如下图所示:
 
-#### 2.3 第三方应用调用Apollo Open API
+![第三方应用列表](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage-list.png)
 
-##### 2.3.1 调用Http REST接口
+【查看Token并赋权】的模态框页面如下图所示:
+
+![查看Token并赋权](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-open-manage-token.png)
+
+#### 2.3 给已注册的第三方应用授权
+第三方应用不应该能操作任何Namespace的配置,所以需要给token绑定可以操作的Namespace。Apollo管理员在 `http://{portal_address}/open/add-consumer.html` 页面给token赋权。赋权之后,第三方应用就可以通过Apollo提供的Http REST接口来管理已授权的Namespace的配置了。
+
+#### 2.4 第三方应用调用Apollo Open API
+
+##### 2.4.1 调用Http REST接口
 任何语言的第三方应用都可以调用Apollo的Open API,在调用接口时,需要设置注意以下两点:
  * Http Header中增加一个Authorization字段,字段值为申请的token
  * Http Header的Content-Type字段需要设置成application/json;charset=UTF-8
 
-##### 2.3.2 Java应用通过apollo-openapi调用Apollo Open API
+##### 2.4.2 Java应用通过apollo-openapi调用Apollo Open API
 从1.1.0版本开始,Apollo提供了[apollo-openapi](https://github.com/apolloconfig/apollo/tree/master/apollo-openapi)客户端,所以Java语言的第三方应用可以更方便地调用Apollo Open API。
 
 首先引入`apollo-openapi`依赖:
@@ -51,11 +60,11 @@ ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
 
 后续就可以通过`ApolloOpenApiClient`的接口直接操作Apollo Open API了,接口说明参见下面的Rest接口文档。
 
-##### 2.3.3 .Net core应用调用Apollo Open API
+##### 2.4.3 .Net core应用调用Apollo Open API
 
 .Net core也提供了open api的客户端,详见https://github.com/ctripcorp/apollo.net/pull/77
 
-##### 2.3.4 Shell Scripts调用Apollo Open API
+##### 2.4.4 Shell Scripts调用Apollo Open API
 
 封装了bash的function,底层使用curl来发送HTTP请求