Browse Source

[security] Frontend for editing groups of a role

Romain Rigaux 11 years ago
parent
commit
ebdfa06

+ 23 - 10
apps/security/src/security/templates/hive.mako

@@ -124,7 +124,7 @@ ${ layout.menubar(section='hive') }
                       </ul>
                       </ul>
                     </div>
                     </div>
                     <select class="user-list" data-bind="options: $root.selectableHadoopUsers, select2: { placeholder: '${ _("Select a user") }', update: $root.doAs, type: 'user'}" style="width: 120px"></select>
                     <select class="user-list" data-bind="options: $root.selectableHadoopUsers, select2: { placeholder: '${ _("Select a user") }', update: $root.doAs, type: 'user'}" style="width: 120px"></select>
-                    <i class="fa fa-group" title="List of groups in popover for this user?"></i>
+                    <i class="fa fa-group" title="${ _('List of groups in popover for this user?') }"></i>
                   </div>
                   </div>
                   <a href="javascript: void(0)" data-bind="click: $root.assist.collapseOthers">
                   <a href="javascript: void(0)" data-bind="click: $root.assist.collapseOthers">
                     <i class="fa fa-compress"></i> ${_('Close others')}
                     <i class="fa fa-compress"></i> ${_('Close others')}
@@ -182,7 +182,7 @@ ${ layout.menubar(section='hive') }
 
 
           <table class="card-marginbottom" data-bind="visible: $root.roles().length > 0">
           <table class="card-marginbottom" data-bind="visible: $root.roles().length > 0">
             <thead>
             <thead>
-              <th width="1%"><div data-bind="click: $root.selectAllRoles, css: {hueCheckbox: true, 'fa': true, 'fa-check': allRolesSelected}"></div></th>
+              <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { hueCheckbox: true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
               <th width="2%"></th>
               <th width="2%"></th>
               <th width="20%">${ _('Name') }</th>
               <th width="20%">${ _('Name') }</th>
               <th width="54%">${ _('Groups') }</th>
               <th width="54%">${ _('Groups') }</th>
@@ -192,7 +192,7 @@ ${ layout.menubar(section='hive') }
             <tbody data-bind="foreach: $root.roles">
             <tbody data-bind="foreach: $root.roles">
               <tr>
               <tr>
                 <td class="center" data-bind="click: handleSelect" style="cursor: default">
                 <td class="center" data-bind="click: handleSelect" style="cursor: default">
-                  <div data-bind="css: {hueCheckbox: true, 'fa': true, 'fa-check': selected}"></div>
+                  <div data-bind="css: { hueCheckbox: true, 'fa': true, 'fa-check': selected }"></div>
                 </td>
                 </td>
                 <td class="center">
                 <td class="center">
                   <a href="javascript:void(0);" title="${ _('Show privileges') }">
                   <a href="javascript:void(0);" title="${ _('Show privileges') }">
@@ -201,9 +201,22 @@ ${ layout.menubar(section='hive') }
                 </td>
                 </td>
                 <td data-bind="text: name, click: function() { if (showPrivileges()) { showPrivileges(false); } else { $root.list_sentry_privileges_by_role($data);} }" class="pointer"></td>
                 <td data-bind="text: name, click: function() { if (showPrivileges()) { showPrivileges(false); } else { $root.list_sentry_privileges_by_role($data);} }" class="pointer"></td>
                 <td>
                 <td>
-                  <span data-bind="foreach: groups">
-                    <a href="/useradmin/groups"><span data-bind="text: $data"></span></a>
-                  </span>
+                  <a href="javascript: void(0)" data-bind="click: function() { showEditGroups(true); }">
+                    <span data-bind="foreach: groups, visible: ! showEditGroups()">
+                      <span data-bind="text: $data"></span>
+                    </span>
+                  </a>
+                  <div data-bind="visible: showEditGroups() || groups().length == 0">
+                    <select data-bind="options: $root.selectableHadoopGroups, selectedOptions: groups, select2: { update: groups, type: 'group'}" size="5" multiple="true" style="width: 400px"></select>
+                    <div data-bind="visible: groupsChanged().length > 0">
+                      <a href="javascript: void(0)">
+                        <i class="fa fa-undo"></i>
+                      </a>
+                      <a href="javascript: void(0)">
+                        <i class="fa fa-save"></i>
+                      </a>
+                    </div>
+                  </div>
                 </td>
                 </td>
                 <td>
                 <td>
                   <a href=""><span data-bind="text: grantorPrincipal"></span></a>
                   <a href=""><span data-bind="text: grantorPrincipal"></span></a>
@@ -254,20 +267,20 @@ ${ layout.menubar(section='hive') }
   </div>
   </div>
   <div class="modal-body" data-bind="with: $root.role, visible: showCreateRole">
   <div class="modal-body" data-bind="with: $root.role, visible: showCreateRole">
     <p>
     <p>
-      Name <input type="text" class="input-small" data-bind="value: $data.name" />
+      ${ _('Name') } <input type="text" class="input-small" data-bind="value: $data.name" />
       <br/>
       <br/>
-      Privileges
+      ${ _('Privileges') }
       <div data-bind="template: { name: 'privilege', foreach: privileges }"></div>
       <div data-bind="template: { name: 'privilege', foreach: privileges }"></div>
       <a href="javascript: void(0)" data-bind="click: addPrivilege">
       <a href="javascript: void(0)" data-bind="click: addPrivilege">
         <i class="fa fa-plus"></i>
         <i class="fa fa-plus"></i>
       </a>
       </a>
       <br/>
       <br/>
-      Groups
+      ${ _('Groups') }
       <select data-bind="options: $root.selectableHadoopGroups, selectedOptions: groups, select2: { update: groups, type: 'group'}" size="5" multiple="true" style="width: 120px"></select>
       <select data-bind="options: $root.selectableHadoopGroups, selectedOptions: groups, select2: { update: groups, type: 'group'}" size="5" multiple="true" style="width: 120px"></select>
     </p>
     </p>
   </div>
   </div>
   <div class="modal-footer">
   <div class="modal-footer">
-    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
+    <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
     <button rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Add role') }" class="btn btn-primary" data-bind="click: $root.role.create">${ _('Add role') }</button>
     <button rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Add role') }" class="btn btn-primary" data-bind="click: $root.role.create">${ _('Add role') }</button>
   </div>
   </div>
 </div>
 </div>

+ 1 - 5
apps/security/src/security/views.py

@@ -21,16 +21,12 @@ from beeswax.api import autocomplete
 from desktop.lib.django_util import render
 from desktop.lib.django_util import render
 
 
 
 
-def _get_hadoop_groups(): # Mock for now, maybe pull from LDAP
-  return ['romain', 'sambashare', 'cdrom', 'lpadmin', 'admin', 'adm', 'lp', 'dialout', 'plugdev']
-
-
 def hive(request):
 def hive(request):
   assist = autocomplete(request, database=None, table=None)
   assist = autocomplete(request, database=None, table=None)
 
 
   return render("hive.mako", request, {
   return render("hive.mako", request, {
       'assist': assist,
       'assist': assist,
-      'initial': json.dumps({'user': request.user.username, 'hadoop_groups': _get_hadoop_groups()}),
+      'initial': json.dumps({'user': request.user.username}),
   })
   })
 
 
 
 

+ 15 - 7
apps/security/static/js/hive.ko.js

@@ -104,12 +104,15 @@ var Role = function (vm, role) {
   }
   }
   self.grantorPrincipal = ko.observable(typeof role.grantorPrincipal != "undefined" && role.grantorPrincipal != null ? role.grantorPrincipal : "");
   self.grantorPrincipal = ko.observable(typeof role.grantorPrincipal != "undefined" && role.grantorPrincipal != null ? role.grantorPrincipal : "");
   self.groups = ko.observableArray();
   self.groups = ko.observableArray();
+  self.originalGroups = ko.observableArray();
   $.each(typeof role.groups != "undefined" && role.groups != null ? role.groups : [], function (index, group) {
   $.each(typeof role.groups != "undefined" && role.groups != null ? role.groups : [], function (index, group) {
     self.groups.push(group);
     self.groups.push(group);
+    self.originalGroups.push(group);
   });
   });
   self.privileges = ko.observableArray(); // Not included in the API
   self.privileges = ko.observableArray(); // Not included in the API
   self.originalPrivileges = ko.observableArray();
   self.originalPrivileges = ko.observableArray();
   self.showPrivileges = ko.observable(false);
   self.showPrivileges = ko.observable(false);
+  self.showEditGroups = ko.observable(false);
 
 
   self.privilegesChanged = ko.computed(function () {
   self.privilegesChanged = ko.computed(function () {
     return $.grep(self.privileges(), function (privilege) {
     return $.grep(self.privileges(), function (privilege) {
@@ -117,6 +120,12 @@ var Role = function (vm, role) {
     });
     });
   });
   });
 
 
+  self.groupsChanged = ko.computed(function () {
+    var a = ko.utils.compareArrays(self.groups(), self.originalGroups());
+    //alert(ko.mapping.toJSON(a));
+    return a;
+  });
+  
   self.reset = function () {
   self.reset = function () {
     self.name('');
     self.name('');
     self.groups.removeAll();
     self.groups.removeAll();
@@ -369,7 +378,7 @@ var Assist = function (vm) {
     // load root first
     // load root first
     self.fetchHivePath("", function(){
     self.fetchHivePath("", function(){
       Object.keys(self.treeAdditionalData).forEach(function (path) {
       Object.keys(self.treeAdditionalData).forEach(function (path) {
-        if (path.indexOf(".") == -1 && path != ""){
+        if (path.indexOf(".") == -1 && path != "") {
           if (typeof force == "boolean" && force) {
           if (typeof force == "boolean" && force) {
             self.fetchHivePath(path);
             self.fetchHivePath(path);
           }
           }
@@ -378,7 +387,7 @@ var Assist = function (vm) {
               self.fetchHivePath(path, function(){
               self.fetchHivePath(path, function(){
                 Object.keys(self.treeAdditionalData).forEach(function (ipath) {
                 Object.keys(self.treeAdditionalData).forEach(function (ipath) {
                   if (ipath.split(".").length == 2 && ipath.split(".")[0] == path){
                   if (ipath.split(".").length == 2 && ipath.split(".")[0] == path){
-                    self.fetchHivePath(ipath, function(){
+                    self.fetchHivePath(ipath, function() {
                       self.updateTreeProperty(self.growingTree(), "isExpanded", true);
                       self.updateTreeProperty(self.growingTree(), "isExpanded", true);
                     });
                     });
                   }
                   }
@@ -448,13 +457,13 @@ var Assist = function (vm) {
     self.fetchHivePath("", function(){
     self.fetchHivePath("", function(){
       self.updatePathProperty(self.growingTree(), "", "isExpanded", true);
       self.updatePathProperty(self.growingTree(), "", "isExpanded", true);
       var _crumbs = self.path().split(".");
       var _crumbs = self.path().split(".");
-      self.fetchHivePath(_crumbs[0], function(){
+      self.fetchHivePath(_crumbs[0], function() {
         self.updatePathProperty(self.growingTree(), _crumbs[0], "isExpanded", true);
         self.updatePathProperty(self.growingTree(), _crumbs[0], "isExpanded", true);
         if (_crumbs.length > 1){
         if (_crumbs.length > 1){
           self.fetchHivePath(_crumbs[0] + "." + _crumbs[1], function(){
           self.fetchHivePath(_crumbs[0] + "." + _crumbs[1], function(){
             self.updatePathProperty(self.growingTree(), _crumbs[0] + "." + _crumbs[1], "isExpanded", true);
             self.updatePathProperty(self.growingTree(), _crumbs[0] + "." + _crumbs[1], "isExpanded", true);
             self.loadData(self.growingTree());
             self.loadData(self.growingTree());
-            if (typeof callback != "undefined"){
+            if (typeof callback != "undefined") {
               callback();
               callback();
             }
             }
             else {
             else {
@@ -465,7 +474,7 @@ var Assist = function (vm) {
         }
         }
         else {
         else {
           self.loadData(self.growingTree());
           self.loadData(self.growingTree());
-          if (typeof callback != "undefined"){
+          if (typeof callback != "undefined") {
             callback();
             callback();
           }
           }
           else {
           else {
@@ -499,7 +508,6 @@ var Assist = function (vm) {
             self.addColumns(_originalPath, data.columns, _hasCallback);
             self.addColumns(_originalPath, data.columns, _hasCallback);
           }
           }
 
 
-
           if (_hasCallback) {
           if (_hasCallback) {
             loadCallback(data);
             loadCallback(data);
           } else {
           } else {
@@ -531,7 +539,7 @@ var HiveViewModel = function (initial) {
 
 
   // Models
   // Models
   self.roles = ko.observableArray();
   self.roles = ko.observableArray();
-  self.availableHadoopGroups = ko.mapping.fromJS(initial.hadoop_groups);
+  self.availableHadoopGroups = ko.observableArray();
   self.assist = new Assist(self);
   self.assist = new Assist(self);
 
 
   // Editing
   // Editing