소스 검색

HUE-8530 [useradmin] Adding basic organization page

Romain 5 년 전
부모
커밋
c6bb73d922

+ 32 - 9
apps/useradmin/src/useradmin/templates/layout.mako

@@ -17,8 +17,8 @@
 <%!
 from django.utils.translation import ugettext as _
 
-from desktop import conf
 from desktop.auth.backend import is_admin
+from desktop.conf import USE_DEFAULT_CONFIGURATION, ENABLE_ORGANIZATIONS
 
 def is_selected(section, matcher):
   if section == matcher:
@@ -62,14 +62,37 @@ def is_selected(section, matcher):
                   ${ _('User Admin') }
                 </a>
               </li>
-              %if is_admin(user):
-                <li class="${is_selected(section, 'users')}"><a href="${ url('useradmin.views.list_users') }">${_('Users')}</a></li>
-                <li class="${is_selected(section, 'groups')}"><a href="${ url('useradmin.views.list_groups') }">${_('Groups')}</a></li>
-                <li class="${is_selected(section, 'permissions')}"><a href="${ url('useradmin.views.list_permissions') }">${_('Permissions')}</a></li>
-                %if conf.USE_DEFAULT_CONFIGURATION.get():
-                <li class="${is_selected(section, 'configurations')}"><a href="${ url('useradmin.views.list_configurations') }">${_('Configurations')}</a></li>
-                %endif
-              %endif
+              % if is_admin(user):
+                <li class="${is_selected(section, 'users')}">
+                  <a href="${ url('useradmin.views.list_users') }">
+                    ${ _('Users') }
+                  </a>
+                </li>
+                <li class="${is_selected(section, 'groups')}">
+                  <a href="${ url('useradmin.views.list_groups') }">
+                    ${ _('Groups') }
+                  </a>
+                </li>
+                <li class="${is_selected(section, 'permissions')}">
+                  <a href="${ url('useradmin.views.list_permissions') }">
+                    ${ _('Permissions') }
+                  </a>
+                </li>
+                % if ENABLE_ORGANIZATIONS.get():
+                <li class="${is_selected(section, 'organizations')}">
+                  <a href="${ url('useradmin.views.list_organizations') }">
+                    ${ _('Organizations') }
+                  </a>
+                </li>
+                % endif
+                % if USE_DEFAULT_CONFIGURATION.get():
+                <li class="${is_selected(section, 'configurations')}">
+                  <a href="${ url('useradmin.views.list_configurations') }">
+                    ${ _('Configurations') }
+                  </a>
+                </li>
+                % endif
+              % endif
             </ul>
           </div>
         </div>

+ 255 - 0
apps/useradmin/src/useradmin/templates/list_organizations.mako

@@ -0,0 +1,255 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License.  You may obtain a copy of the License at
+##
+##     http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+<%!
+from django.utils.translation import ugettext as _
+
+from desktop.auth.backend import is_admin
+from desktop.conf import ENABLE_ORGANIZATIONS
+from desktop.views import commonheader, commonfooter, antixss
+
+from useradmin.models import group_permissions
+%>
+
+
+<%namespace name="actionbar" file="actionbar.mako" />
+<%namespace name="layout" file="layout.mako" />
+
+%if not is_embeddable:
+${ commonheader(_('Groups'), "useradmin", user, request) | n,unicode }
+%endif
+
+${layout.menubar(section='groups')}
+
+<div id="groupsComponents" class="useradmin container-fluid">
+  <div class="card card-small">
+    <h1 class="card-heading simple">
+      ${_('Groups')}
+      % if ENABLE_ORGANIZATIONS.get():
+        @ ${ user.organization }
+      % endif
+    </h1>
+
+    <%actionbar:render>
+      <%def name="search()">
+          <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, members, etc...')}">
+      </%def>
+      <%def name="actions()">
+        %if is_admin(user):
+            <button class="btn delete-group-btn confirmationModal" title="${_('Delete')}" disabled="disabled"><i class="fa fa-trash-o"></i> ${_('Delete')}</button>
+        %endif
+      </%def>
+      <%def name="creation()">
+        %if is_admin(user):
+          <a id="addGroupBtn" href="${url('useradmin.views.edit_group')}" class="btn"><i
+              class="fa fa-plus-circle"></i> ${_('Add group')}</a>
+          % if is_ldap_setup:
+            <a id="addLdapGroupBtn" href="${url('useradmin.views.add_ldap_groups')}" class="btn"><i
+                class="fa fa-refresh"></i> ${_('Add/Sync LDAP group')}</a>
+          % endif
+          <a href="http://gethue.com/making-hadoop-accessible-to-your-employees-with-ldap/"
+            title="${ _('Learn how to integrate Hue with your company LDAP') }" target="_blank">
+            <i class="fa fa-question-circle"></i>
+          </a>
+        %endif
+      </%def>
+    </%actionbar:render>
+
+    <table class="table table-condensed datatables">
+      <thead>
+      <tr>
+        %if is_admin(user):
+          <th width="1%">
+            <div class="select-all hue-checkbox fa"></div>
+          </th>
+        %endif
+        <th>${_('Group Name')}</th>
+        <th>${_('Members')}</th>
+        <th>${_('Permissions')}</th>
+      </tr>
+      </thead>
+      <tbody>
+        % for group in groups:
+          <tr class="tableRow"
+              data-search="${group.name}${', '.join([group_user.username for group_user in group.organizationuser_set.all()])}">
+          % if is_admin(user):
+            <td data-row-selector-exclude="true">
+              <div class="hue-checkbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
+            </td>
+          % endif
+          <td>
+            % if is_admin(user):
+              <strong>
+                <a title="${ _('Edit %(groupname)s') % dict(groupname=group.name) }"
+                  href="${ url('useradmin.views.edit_group', name=group.name) }"
+                  data-row-selector="true">
+                    ${group.name}
+                </a>
+              </strong>
+            % else:
+              <strong>${group.name}</strong>
+            % endif
+          </td>
+          <td>${ ', '.join([group_user.username for group_user in group.organizationuser_set.all()]) }</td>
+          <td>{ group.organizationgroup_set.count() } { group.huepermission_set.count() }</td>
+        </tr>
+        % endfor
+      </tbody>
+      <tfoot class="hide">
+      <tr>
+        <td colspan="8">
+          <div class="alert">
+            ${_('There are no groups matching the search criteria.')}
+          </div>
+        </td>
+      </tr>
+      </tfoot>
+    </table>
+  </div>
+  <div class="modal hide fade delete-group">
+    <form action="${ url('useradmin.views.delete_group') }" method="POST">
+      ${ csrf_token(request) | n,unicode }
+      % if is_embeddable:
+        <input type="hidden" value="true" name="is_embeddable" />
+      % endif
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
+        <h2 class="modal-title">${_("Are you sure you want to delete the selected group(s)?")}</h2>
+      </div>
+      <div class="modal-footer">
+        <a href="javascript:void(0);" class="btn" data-dismiss="modal">${_('No')}</a>
+        <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
+      </div>
+      <div class="hide">
+        <select name="group_names" data-bind="options: chosenGroups, selectedOptions: chosenGroups" multiple="true"></select>
+      </div>
+    </form>
+  </div>
+</div>
+
+
+<script src="${ static('desktop/ext/js/datatables-paging-0.1.js') }" type="text/javascript" charset="utf-8"></script>
+
+<script type="text/javascript">
+
+  $(document).ready(function () {
+    var $groupsComponents = $('#groupsComponents');
+    $(document).off('click', '#groupsComponents .groupCheck');
+
+    var viewModel = {
+      availableGroups: ko.observableArray(${ groups_json | n,antixss }),
+      chosenGroups: ko.observableArray([])
+    };
+
+    ko.applyBindings(viewModel, $groupsComponents[0]);
+
+    var dt = $groupsComponents.find('.datatables').dataTable({
+      "sPaginationType":"bootstrap",
+      "iDisplayLength":100,
+      "bLengthChange":false,
+      "sDom": "<'row'r>t<'row-fluid'<'dt-pages'p><'dt-records'i>>",
+      "bInfo": false,
+      "bFilter": true,
+      "bAutoWidth": false,
+      "aoColumns": [
+        %if is_admin(user):
+            { "bSortable": false },
+        %endif
+        { "sWidth": "20%" },
+        { "sWidth": "20%" },
+        null
+      ],
+      "oLanguage": {
+        "sEmptyTable": "${_('No data available')}",
+        "sZeroRecords": "${_('No matching records')}",
+      }
+    });
+
+    % if is_embeddable:
+    $groupsComponents.find('.delete-group form').ajaxForm({
+      dataType:  'json',
+      success: function(data) {
+        $groupsComponents.find(".delete-group").modal("hide");
+        $.jHueNotify.info("${ _('The groups were deleted.') }");
+        if (data && data.url){
+          huePubSub.publish('open.link', data.url);
+        }
+      }
+    });
+    % endif
+
+    $groupsComponents.find(".filter-input").jHueDelayedInput(function () {
+      if (dt) {
+        dt.fnFilter($groupsComponents.find(".filter-input").val().toLowerCase());
+      }
+    });
+
+    $groupsComponents.find('[data-rel="tooltip"]').tooltip({
+      placement: 'right'
+    });
+
+    $groupsComponents.find(".dataTables_wrapper").css("min-height", "0");
+    $groupsComponents.find(".dataTables_filter").hide();
+
+    $groupsComponents.find(".select-all").click(function () {
+      if ($(this).attr("checked")) {
+        $(this).removeAttr("checked").removeClass("fa-check");
+        $groupsComponents.find(".groupCheck").removeClass("fa-check").removeAttr("checked");
+      }
+      else {
+        $(this).attr("checked", "checked").addClass("fa-check");
+        $groupsComponents.find(".groupCheck").addClass("fa-check").attr("checked", "checked");
+      }
+      toggleActions();
+    });
+
+    $(document).on('click', '#groupsComponents .groupCheck', function () {
+      if ($(this).attr("checked")) {
+        $(this).removeClass("fa-check").removeAttr("checked");
+      }
+      else {
+        $(this).addClass("fa-check").attr("checked", "checked");
+      }
+      toggleActions();
+    });
+
+    function toggleActions() {
+      if ($groupsComponents.find(".groupCheck[checked='checked']").length > 0) {
+        $groupsComponents.find(".delete-group-btn").removeAttr("disabled");
+      }
+      else {
+        $groupsComponents.find(".delete-group-btn").attr("disabled", "disabled");
+      }
+    }
+
+    $groupsComponents.find(".delete-group-btn").click(function () {
+      viewModel.chosenGroups.removeAll();
+
+      $groupsComponents.find(".hue-checkbox[checked='checked']").each(function (index) {
+        viewModel.chosenGroups.push($(this).data("name").toString()); // needed for numeric group names
+      });
+
+      $groupsComponents.find(".delete-group").modal("show");
+    });
+
+    $groupsComponents.find("a[data-row-selector='true']").jHueRowSelector();
+  });
+</script>
+
+${layout.commons()}
+
+%if not is_embeddable:
+${ commonfooter(request, messages) | n,unicode }
+%endif

+ 1 - 0
apps/useradmin/src/useradmin/urls.py

@@ -33,6 +33,7 @@ urlpatterns = [
   url(r'^groups/?$', useradmin_views.list_groups, name="useradmin.views.list_groups"),
   url(r'^permissions/?$', useradmin_views.list_permissions, name="useradmin.views.list_permissions"),
   url(r'^configurations/?$', useradmin_views.list_configurations, name="useradmin.views.list_configurations"),
+  url(r'^organizations/?$', useradmin_views.list_organizations, name="useradmin.views.list_organizations"),
   url(r'^users/edit/(?P<username>%s)$' % (username_re,), useradmin_views.edit_user, name="useradmin.views.edit_user"),
   url(r'^users/add_ldap_users$', useradmin_views.add_ldap_users, name="useradmin.views.add_ldap_users"),
   url(r'^users/add_ldap_groups$', useradmin_views.add_ldap_groups, name="useradmin.views.add_ldap_groups"),

+ 10 - 0
apps/useradmin/src/useradmin/views.py

@@ -52,6 +52,7 @@ from useradmin.forms import SyncLdapUsersGroupsForm, AddLdapGroupsForm, AddLdapU
   validate_last_name, PasswordChangeForm
 from useradmin.ldap_access import LdapBindException, LdapSearchException
 from useradmin.models import HuePermission, UserProfile, LdapGroup, get_profile, get_default_user_group, User, Group
+from useradmin.models2 import Organization
 
 if sys.version_info[0] > 2:
   unicode = str
@@ -107,6 +108,15 @@ def list_configurations(request):
   })
 
 
+def list_organizations(request):
+  return render("list_organizations.mako", request, {
+      'groups': Organization.objects.all(),
+      'groups_json': json.dumps(list(Organization.objects.values_list('name', flat=True))),
+      'is_embeddable': request.GET.get('is_embeddable', False),
+      'is_ldap_setup': is_ldap_setup()
+  })
+
+
 def list_for_autocomplete(request):
   extended_user_object = request.GET.get('extend_user') == 'true'
   autocomplete_filter = request.GET.get('filter', "")

+ 1 - 0
desktop/core/src/desktop/js/onePageViewModel.js

@@ -774,6 +774,7 @@ class OnePageViewModel {
       { url: '/sqoop', app: 'sqoop' },
       { url: '/jobsub', app: 'jobsub' },
       { url: '/useradmin/configurations/', app: 'useradmin_configurations' },
+      { url: '/useradmin/organizations/', app: 'useradmin_organizations' },
       { url: '/useradmin/groups/', app: 'useradmin_groups' },
       { url: '/useradmin/groups/new', app: 'useradmin_newgroup' },
       { url: '/useradmin/groups/edit/:group', app: 'useradmin_editgroup' },

+ 1 - 0
desktop/core/src/desktop/templates/hue.mako

@@ -359,6 +359,7 @@ ${ smart_unicode(login_modal(request).content) | n,unicode }
     useradmin_permissions: { url: '/useradmin/permissions', title: '${_('User Admin - Permissions')}' },
     useradmin_editpermission: { url: '/useradmin/permissions/edit/*', title: '${_('User Admin - Edit Permission')}' },
     useradmin_configurations: { url: '/useradmin/configurations', title: '${_('User Admin - Configurations')}' },
+    useradmin_organizations: { url: '/useradmin/organizations', title: '${_('User Admin - Organization')}' },
     useradmin_newuser: { url: '/useradmin/users/new', title: '${_('User Admin - New User')}' },
     useradmin_addldapusers: { url: '/useradmin/users/add_ldap_users', title: '${_('User Admin - Add LDAP User')}' },
     useradmin_edituser: { url: '/useradmin/users/edit/:user', title: '${_('User Admin - Edit User')}' },