[PATCH conductor] Tasks 3387/3388 UI for user groups implementation (revised)
Tzu-Mainn Chen
tzumainn at redhat.com
Mon Jul 2 16:15:11 UTC 2012
ACK; fixes the issues pointed out by previous review.
Mainn
----- Original Message -----
> From: "Scott Seago" <sseago at redhat.com>
> To: aeolus-devel at lists.fedorahosted.org
> Cc: "Scott Seago" <sseago at redhat.com>
> Sent: Monday, July 2, 2012 11:05:57 AM
> Subject: [PATCH conductor] Tasks 3387/3388 UI for user groups implementation (revised)
>
> UI for managing local user groups and for assigning group
> permissions.
> When testing, note that after adding/removing a user from a group
> the user must log out and in again to see the effects.
> ---
> aeolus-conductor.spec.in | 1 +
> src/app/controllers/application_controller.rb | 7 +-
> src/app/controllers/permissions_controller.rb | 13 +-
> src/app/controllers/user_groups_controller.rb | 238
> ++++++++++++++++++++
> .../user_groups_helper.rb} | 23 +--
> src/app/models/common_filter_methods.rb | 8 +-
> src/app/models/derived_permission.rb | 23 ++
> src/app/models/entity.rb | 19 ++
> src/app/models/permission.rb | 23 ++
> src/app/models/user_group.rb | 12 +
> src/app/views/permissions/_form.html.haml | 23 ++-
> src/app/views/permissions/_permissions.html.haml | 20 ++
> src/app/views/user_groups/_form.html.haml | 26 +++
> src/app/views/user_groups/_list.html.haml | 41 ++++
> src/app/views/user_groups/add_members.html.haml | 25 ++
> src/app/views/user_groups/edit.html.haml | 14 ++
> src/app/views/user_groups/index.html.haml | 2 +
> src/app/views/user_groups/new.html.haml | 13 +
> src/app/views/user_groups/show.html.haml | 71 ++++++
> src/config/locales/en.yml | 63 +++++-
> src/config/navigation.rb | 2 +-
> src/config/routes.rb | 15 ++
> src/features/step_definitions/user_group_steps.rb | 56 +++++
> src/features/support/paths.rb | 6 +
> src/features/user_group.feature | 72 ++++++
> .../controllers/user_groups_controller_spec.rb | 75 ++++++
> src/spec/factories/permission.rb | 7 +
> .../factories/user_group.rb} | 23 +-
> src/spec/models/permission_spec.rb | 19 ++
> src/spec/models/user_group_spec.rb | 43 ++++
> 30 files changed, 948 insertions(+), 35 deletions(-)
> create mode 100644 src/app/controllers/user_groups_controller.rb
> copy src/app/{models/common_filter_methods.rb =>
> helpers/user_groups_helper.rb} (55%)
> create mode 100644 src/app/views/user_groups/_form.html.haml
> create mode 100644 src/app/views/user_groups/_list.html.haml
> create mode 100644 src/app/views/user_groups/add_members.html.haml
> create mode 100644 src/app/views/user_groups/edit.html.haml
> create mode 100644 src/app/views/user_groups/index.html.haml
> create mode 100644 src/app/views/user_groups/new.html.haml
> create mode 100644 src/app/views/user_groups/show.html.haml
> create mode 100644 src/features/step_definitions/user_group_steps.rb
> create mode 100644 src/features/user_group.feature
> create mode 100644
> src/spec/controllers/user_groups_controller_spec.rb
> copy src/{app/models/common_filter_methods.rb =>
> spec/factories/user_group.rb} (56%)
> create mode 100644 src/spec/models/user_group_spec.rb
>
> diff --git a/aeolus-conductor.spec.in b/aeolus-conductor.spec.in
> index 6186651..30e6f43 100644
> --- a/aeolus-conductor.spec.in
> +++ b/aeolus-conductor.spec.in
> @@ -209,6 +209,7 @@ haml="app/views/hardware_profiles
> app/views/realm_mappings \
> app/views/api/hooks \
> app/views/api \
> app/views/images \
> + app/views/user_groups \
> app/views/api/builds app/views/api/provider_images \
> app/views/api/target_images app/views/api/entrypoint \
> app/views/api/environments \
> diff --git a/src/app/controllers/application_controller.rb
> b/src/app/controllers/application_controller.rb
> index 1907d23..d5da863 100644
> --- a/src/app/controllers/application_controller.rb
> +++ b/src/app/controllers/application_controller.rb
> @@ -282,7 +282,7 @@ class ApplicationController <
> ActionController::Base
>
> def set_admin_users_tabs(tab)
> @tabs = [{:name => t('application_controller.admin_tabs.users'),
> :url => users_url, :id => 'users'},
> - #{:name =>
> t('application_controller.admin_tabs.groups'), :url => groups_url,
> :id => 'groups'},
> + {:name =>
> t('application_controller.admin_tabs.user_groups'), :url =>
> user_groups_url, :id => 'user_groups'},
> {:name =>
> t('application_controller.admin_tabs.permissions'),
> :url => permissions_url, :id => 'permissions'},
> ]
> unless @details_tab = @tabs.find {|t| t[:id] == tab}
> @@ -352,7 +352,10 @@ class ApplicationController <
> ActionController::Base
> else
> local_perms = @permission_object.permissions
> end
> - @permissions = paginate_collection(local_perms, params[:page])
> + @permissions = paginate_collection(local_perms.
> + apply_filters(:preset_filter_id =>
> params[:permissions_preset_filter],
> + :search_filter => params[:permissions_search]),
> + params[:page])
>
> @permission_list_header = []
> unless (@show_inherited or @show_global)
> diff --git a/src/app/controllers/permissions_controller.rb
> b/src/app/controllers/permissions_controller.rb
> index c4d1371..41cad43 100644
> --- a/src/app/controllers/permissions_controller.rb
> +++ b/src/app/controllers/permissions_controller.rb
> @@ -165,11 +165,22 @@ class PermissionsController <
> ApplicationController
> :permission_object_id => p.permission_object_id
> end
>
> + def filter
> + redirect_to_original({"permissions_preset_filter" =>
> params[:permissions_preset_filter], "permissions_search" =>
> params[:permissions_search]})
> + end
> +
> + def filter_entities
> + redirect_to_original({"entities_preset_filter" =>
> params[:entities_preset_filter], "entities_search" =>
> params[:entities_search]})
> + end
> +
> private
>
> def load_entities
> sort_order = params[:sort_by].nil? ? "name" : params[:sort_by]
> - @entities = paginate_collection(Entity.all(:order =>
> sort_column(Entity, sort_order)),
> + @entities = paginate_collection(Entity.
> + all(:order => sort_column(Entity, sort_order)).
> + apply_filters(:preset_filter_id =>
> params[:entities_preset_filter],
> + :search_filter => params[:entities_search]),
> params[:page])
> end
>
> diff --git a/src/app/controllers/user_groups_controller.rb
> b/src/app/controllers/user_groups_controller.rb
> new file mode 100644
> index 0000000..59b8665
> --- /dev/null
> +++ b/src/app/controllers/user_groups_controller.rb
> @@ -0,0 +1,238 @@
> +#
> +# Copyright 2011 Red Hat, Inc.
> +#
> +# 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.
> +#
> +
> +class UserGroupsController < ApplicationController
> + before_filter :require_user, :except => [:new, :create]
> +
> + def index
> + require_privilege(Privilege::VIEW, User)
> + @title = t'user_groups.groups'
> + clear_breadcrumbs
> + save_breadcrumb(user_groups_path)
> + set_admin_users_tabs 'user_groups'
> + @params = params
> + load_headers
> + load_user_groups
> + respond_to do |format|
> + format.html
> + format.js { render :partial => 'list' }
> + end
> + end
> +
> + def show
> + @user_group = UserGroup.find(params[:id])
> + require_privilege(Privilege::VIEW, User)
> + @title = @user_group.name
> + save_breadcrumb(user_group_path(@user_group), @user_group.name)
> + @tab_captions = ['Properties']
> + @details_tab = params[:details_tab].blank? ? 'properties' :
> params[:details_tab]
> + @members = paginate_collection(@user_group.members,
> params[:page])
> + respond_to do |format|
> + format.html
> + format.js do
> + if params.delete :details_pane
> + render :partial => 'layouts/details_pane' and return
> + end
> + render :partial => @details_tab
> + end
> + end
> + end
> +
> + def new
> + require_privilege(Privilege::CREATE, User)
> + @title = t'user_groups.new.new_user_group'
> + @user_group = UserGroup.new
> + # remove when we enable ldap
> + @user_group.membership_source =
> UserGroup::MEMBERSHIP_SOURCE_LOCAL
> + end
> +
> + def create
> + if params[:commit] == "Reset"
> + redirect_to :action => 'new' and return
> + end
> +
> + require_privilege(Privilege::MODIFY, User)
> + @user_group = UserGroup.new(params[:user_group])
> + unless @user_group.save
> + render :action => 'new' and return
> + end
> +
> + respond_to do |format|
> + if @user_group.save
> + flash[:notice] = t "user_groups.flash.notice.added"
> + format.html { redirect_to user_groups_path }
> + format.json { render :json => @user_group, :status =>
> :created }
> + else
> + flash.now[:warning] = t
> "user_groups.flash.warning.creation_failed"
> + format.html { render :new }
> + format.js { render :partial => 'new' }
> + format.json { render :json => @user_group.errors, :status =>
> :unprocessable_entity }
> + end
> + end
> + end
> +
> + def edit
> + @user_group = UserGroup.find(params[:id])
> + require_privilege(Privilege::MODIFY, User)
> + @title = t'user_groups.edit.edit_user_group'
> + end
> +
> + def update
> + @user_group = UserGroup.find(params[:id])
> + require_privilege(Privilege::MODIFY, User)
> +
> + if params[:commit] == "Reset"
> + redirect_to edit_user_group_url(@user_group) and return
> + end
> +
> + redirect_to root_url and return unless @user_group
> +
> + unless @user_group.update_attributes(params[:user_group])
> + render :action => 'edit' and return
> + else
> + flash[:notice] = t"user_groups.flash.notice.updated"
> + redirect_to user_group_path(@user_group)
> + end
> + end
> +
> + def multi_destroy
> + require_privilege(Privilege::MODIFY, User)
> + deleted_user_groups = []
> +
> + begin
> + UserGroup.transaction do
> + UserGroup.find(params[:user_group_selected]).each do
> |user_group|
> + if user_group.destroy
> + deleted_user_groups << user_group.name
> + end
> + end
> + end
> +
> + unless deleted_user_groups.empty?
> + flash[:notice] =
> "#{t('user_groups.flash.notice.more_deleted', :count =>
> deleted_user_groups.length)} #{deleted_user_groups.join(', ')}"
> + end
> +
> + rescue => ex
> + flash[:warning] = t('user_groups.flash.warning.not_delete',
> :reason => ex.message)
> + end
> +
> + redirect_to user_groups_url
> + end
> +
> + def destroy
> + require_privilege(Privilege::MODIFY, User)
> + user_group = UserGroup.find(params[:id])
> + if user_group.destroy
> + flash[:notice] = t"user_groups.flash.notice.deleted"
> + else
> + flash[:notice] = t"user_groups.flash.warning.delete_failed"
> + end
> +
> + respond_to do |format|
> + format.html { redirect_to user_groups_path }
> + end
> + end
> +
> + def add_members
> + @user_group = UserGroup.find(params[:id])
> + require_privilege(Privilege::MODIFY, User)
> +
> + unless @user_group.membership_source ==
> UserGroup::MEMBERSHIP_SOURCE_LOCAL
> + flash[:error] = t('user_groups.flash.error.not_a_local_group')
> + redirect_to user_group_path(@user_group) and return
> + end
> +
> + @users = paginate_collection(User.where('users.id not in (?)',
> +
> @user_group.members.empty?
> ?
> + 0 :
> @user_group.members.map(&:id)),
> + params[:page])
> +
> + added = []
> + not_added = []
> +
> + if params[:members_selected].blank?
> + flash[:error] =
> t"user_groups.flash.error.select_to_add_members" if request.post?
> + else
> + User.find(params[:members_selected]).each do |member|
> + if !@user_group.members.include?(member) and
> + @user_group.members << member
> + added << member.name
> + else
> + not_added << member.name
> + end
> + end
> + unless added.empty?
> + flash[:notice] =
> "#{t('user_groups.flash.notice.members_added')}: #{added.join(',
> ')}"
> + end
> + unless not_added.empty?
> + flash[:error] =
> "#{t('user_groups.flash.error.members_not_added')}:
> #{not_added.join(', ')}"
> + end
> + respond_to do |format|
> + format.html { redirect_to user_group_path(@user_group) }
> + end
> + end
> + end
> +
> + def remove_members
> + @user_group = UserGroup.find(params[:id])
> + require_privilege(Privilege::MODIFY, User)
> +
> + unless @user_group.membership_source ==
> UserGroup::MEMBERSHIP_SOURCE_LOCAL
> + flash[:error] = t('user_groups.flash.error.not_a_local_group')
> + redirect_to user_group_path(@user_group) and return
> + end
> +
> + removed=[]
> + not_removed=[]
> +
> + if params[:members_selected].blank?
> + if request.post?
> + flash[:error] =
> t"user_groups.flash.error.select_to_remove_members"
> + end
> + else
> + User.find(params[:members_selected]).each do |member|
> + if @user_group.members.delete member
> + removed << member.name
> + else
> + not_removed << member.name
> + end
> + end
> + unless removed.empty?
> + flash[:notice] =
> "#{t('user_groups.flash.notice.members_removed')}: #{removed.join(',
> ')}"
> + end
> + unless not_removed.empty?
> + flash[:error] =
> "#{t('user_groups.flash.error.members_not_removed')}:
> #{not_removed.join(', ')}"
> + end
> + end
> + respond_to do |format|
> + format.html { redirect_to user_group_path(@user_group) }
> + end
> + end
> +
> + def load_user_groups
> + sort_order = params[:sort_by].nil? ? "name" : params[:sort_by]
> + @user_groups = UserGroup.apply_filters(:preset_filter_id =>
> params[:users_preset_filter], :search_filter =>
> params[:user_groups_search]).order(sort_order)
> + end
> +
> + def load_headers
> + @header = [
> + { :name => 'checkbox', :class => 'checkbox', :sortable =>
> false },
> + { :name => t('user_groups.index.name'), :sortable => false },
> + { :name => t('user_groups.index.type'), :sortable => false },
> + ]
> + end
> +
> +end
> diff --git a/src/app/models/common_filter_methods.rb
> b/src/app/helpers/user_groups_helper.rb
> similarity index 55%
> copy from src/app/models/common_filter_methods.rb
> copy to src/app/helpers/user_groups_helper.rb
> index 7bb2be2..85ad81f 100644
> --- a/src/app/models/common_filter_methods.rb
> +++ b/src/app/helpers/user_groups_helper.rb
> @@ -1,5 +1,5 @@
> #
> -# Copyright 2011 Red Hat, Inc.
> +# Copyright 2012 Red Hat, Inc.
> #
> # Licensed under the Apache License, Version 2.0 (the "License");
> # you may not use this file except in compliance with the License.
> @@ -13,19 +13,12 @@
> # See the License for the specific language governing permissions
> and
> # limitations under the License.
> #
> -#this module contains functions for filtering table data
> -module CommonFilterMethods
> - def apply_filters(options = {})
> -
> apply_preset_filter(options[:preset_filter_id]).apply_search_filter(options[:search_filter])
> - end
> -
> - private
> -
> - def apply_preset_filter(preset_filter_id)
> - if preset_filter_id.present?
> - self::PRESET_FILTERS_OPTIONS.select{|item| item[:id] ==
> preset_filter_id}.first[:query]
> - else
> - scoped
> - end
> +module UserGroupsHelper
> + def members_header
> + [
> + { :name => 'checkbox', :class => 'checkbox', :sortable =>
> false },
> + { :name => t('users.index.username'), :sortable => false },
> + { :name => t('user_groups.index.name'), :sortable => false },
> + ]
> end
> end
> diff --git a/src/app/models/common_filter_methods.rb
> b/src/app/models/common_filter_methods.rb
> index 7bb2be2..9491ecb 100644
> --- a/src/app/models/common_filter_methods.rb
> +++ b/src/app/models/common_filter_methods.rb
> @@ -23,7 +23,13 @@ module CommonFilterMethods
>
> def apply_preset_filter(preset_filter_id)
> if preset_filter_id.present?
> - self::PRESET_FILTERS_OPTIONS.select{|item| item[:id] ==
> preset_filter_id}.first[:query]
> + option = self::PRESET_FILTERS_OPTIONS.select { |item|
> + item[:id] == preset_filter_id}.first
> + if option[:query]
> + option[:query]
> + else
> + includes(option[:includes]).where(option[:where])
> + end
> else
> scoped
> end
> diff --git a/src/app/models/derived_permission.rb
> b/src/app/models/derived_permission.rb
> index b7a2530..80d055d 100644
> --- a/src/app/models/derived_permission.rb
> +++ b/src/app/models/derived_permission.rb
> @@ -15,6 +15,9 @@
> #
>
> class DerivedPermission < ActiveRecord::Base
> + class << self
> + include CommonFilterMethods
> + end
> # the source permission for the denormalized object
> belongs_to :permission
> validates_presence_of :permission_id
> @@ -54,4 +57,24 @@ class DerivedPermission < ActiveRecord::Base
> validates_uniqueness_of :permission_id, :scope =>
> [:permission_object_id,
> :permission_object_type]
>
> + # :query is handled differently for permission
> + PRESET_FILTERS_OPTIONS = [
> + {:title => "permissions.preset_filters.user_permissions",
> + :id => "user_permissions",
> + :includes => :entity,
> + :where => {"entities.entity_target_type" => "User"}},
> + {:title => "permissions.preset_filters.group_permissions",
> + :id => "group_permissions",
> + :includes => :entity,
> + :where => {"entities.entity_target_type" => "UserGroup"}}
> + ]
> +
> + def self.apply_search_filter(search)
> + if search
> + includes("entity").where("lower(entities.name) LIKE :search",
> :search => "%#{search.downcase}%")
> + else
> + scoped
> + end
> + end
> +
> end
> diff --git a/src/app/models/entity.rb b/src/app/models/entity.rb
> index bbc56fe..db88a5e 100644
> --- a/src/app/models/entity.rb
> +++ b/src/app/models/entity.rb
> @@ -15,6 +15,9 @@
> #
>
> class Entity < ActiveRecord::Base
> + class << self
> + include CommonFilterMethods
> + end
> belongs_to :entity_target, :polymorphic => true
> validates_presence_of :entity_target_id
> has_many :session_entities, :dependent => :destroy
> @@ -26,4 +29,20 @@ class Entity < ActiveRecord::Base
> belongs_to :user_group, :class_name => "UserGroup",
> :foreign_key => "entity_target_id"
>
> + PRESET_FILTERS_OPTIONS = [
> + {:title => "user",
> + :id => "users",
> + :where => {"entities.entity_target_type" => "User"}},
> + {:title => "user_group",
> + :id => "user_groups",
> + :where => {"entities.entity_target_type" => "UserGroup"}}
> + ]
> +
> + def self.apply_search_filter(search)
> + if search
> + where("lower(entities.name) LIKE :search", :search =>
> "%#{search.downcase}%")
> + else
> + scoped
> + end
> + end
> end
> diff --git a/src/app/models/permission.rb
> b/src/app/models/permission.rb
> index 048f7a5..9b4c0ac 100644
> --- a/src/app/models/permission.rb
> +++ b/src/app/models/permission.rb
> @@ -30,6 +30,9 @@
> #
>
> class Permission < ActiveRecord::Base
> + class << self
> + include CommonFilterMethods
> + end
> belongs_to :role
> belongs_to :entity
>
> @@ -67,6 +70,17 @@ class Permission < ActiveRecord::Base
>
> after_save :update_derived_permissions
>
> + # :query is handled differently for permission
> + PRESET_FILTERS_OPTIONS = [
> + {:title => "permissions.preset_filters.user_permissions",
> + :id => "user_permissions",
> + :includes => :entity,
> + :where => {"entities.entity_target_type" => "User"}},
> + {:title => "permissions.preset_filters.group_permissions",
> + :id => "group_permissions",
> + :includes => :entity,
> + :where => {"entities.entity_target_type" => "UserGroup"}}
> + ]
> def user
> entity.user
> end
> @@ -100,4 +114,13 @@ class Permission < ActiveRecord::Base
> end
> end
> end
> +
> + def self.apply_search_filter(search)
> + if search
> + includes("entity").where("lower(entities.name) LIKE :search",
> :search => "%#{search.downcase}%")
> + else
> + scoped
> + end
> + end
> +
> end
> diff --git a/src/app/models/user_group.rb
> b/src/app/models/user_group.rb
> index 293d0db..dcb2f63 100644
> --- a/src/app/models/user_group.rb
> +++ b/src/app/models/user_group.rb
> @@ -15,6 +15,9 @@
> #
>
> class UserGroup < ActiveRecord::Base
> + class << self
> + include CommonFilterMethods
> + end
> # name will correspond to the group name if we're using LDAP,
> otherwise it's
> # entered by the admin creating the group
>
> @@ -42,4 +45,13 @@ class UserGroup < ActiveRecord::Base
> self.entity.name = "#{self.name} (#{self.membership_source})"
> self.entity.save!
> end
> +
> + def self.apply_search_filter(search)
> + if search
> + where("lower(name) LIKE :search", :search =>
> "%#{search.downcase}%")
> + else
> + scoped
> + end
> + end
> +
> end
> diff --git a/src/app/views/permissions/_form.html.haml
> b/src/app/views/permissions/_form.html.haml
> index 95aa05d..39b1865 100644
> --- a/src/app/views/permissions/_form.html.haml
> +++ b/src/app/views/permissions/_form.html.haml
> @@ -1,3 +1,23 @@
> +- content_for :entities_filter_controls do
> + %li
> + = label_tag :entities_preset_filter, t('filter_table.viewing')
> + = select_tag(:entities_preset_filter,
> preset_filters_options_for_select(Entity::PRESET_FILTERS_OPTIONS,
> params[:entities_preset_filter]), :include_blank =>
> t("permissions.preset_filters.all_entities"), :disabled => false)
> + = hidden_field_tag :current_path, request.fullpath
> + = restful_submit_tag t("filter_table.apply_filters"), "filter",
> filter_entities_permissions_path, 'POST', :class => 'button', :id =>
> 'apply_entities_preset_filter'
> + %span.label.badge.dark= @entities.count
> + %li.table-search-filter
> + = text_field_tag :entities_search, params[:entities_search],
> :placeholder => t("filter_table.search")
> + = restful_submit_tag "", "search",
> filter_entities_permissions_path, 'POST', :class => 'button', :id =>
> 'apply_entities_search'
> +
> + :javascript
> + $(document).ready(function(){
> + $("#apply_entities_preset_filter").hide();
> + $("#entities_preset_filter").change(function() {
> + $("#apply_entities_preset_filter").click();
> + });
> + Conductor.clickOnEnterKeypress($('#entities_search'),
> $('#apply_entities_search'));
> + });
> +
> - content_for :form_footer do
> = hidden_field_tag :permission_object_type,
> @permission_object.class.name
> = hidden_field_tag :permission_object_id, @permission_object.id
> @@ -5,7 +25,8 @@
> = hidden_field_tag :use_tabs, @use_tabs
> = link_to t('cancel'), @return_path, :class => 'button danger'
> = restful_submit_tag t('permissions.form.grant_access'), "create",
> permissions_path, 'POST', :id => 'save_button', :class =>
> 'button'
> -= filter_table(@header, @entities) do |entity|
> += filter_table(@header, @entities,
> + :filter_controls => :entities_filter_controls) do
> |entity|
> %tr{:class => cycle('nostripe','stripe')}
> %td
> -# - selected = params[:select] == 'all'
> diff --git a/src/app/views/permissions/_permissions.html.haml
> b/src/app/views/permissions/_permissions.html.haml
> index b1e18f7..56a0c8e 100644
> --- a/src/app/views/permissions/_permissions.html.haml
> +++ b/src/app/views/permissions/_permissions.html.haml
> @@ -24,6 +24,26 @@
> %li= link_to t('permissions.inherited_access'),
> params.merge(:show_inherited => true, :show_global =>
> false, :page => 1), { :class => 'button primary', :id =>
> 'inherited_permission_button'}
> %li= link_to t('permissions.global_access'),
> params.merge(:show_inherited => false, :show_global =>
> true, :page => 1), { :class => 'button primary', :id =>
> 'global_permission_button'}
>
> +- content_for :permissions_filter_controls do
> + %li
> + = label_tag :permissions_preset_filter,
> t('filter_table.viewing')
> + = select_tag(:permissions_preset_filter,
> preset_filters_options_for_select(Permission::PRESET_FILTERS_OPTIONS,
> params[:permissions_preset_filter]), :include_blank =>
> t("permissions.preset_filters.all_permissions"), :disabled => false)
> + = hidden_field_tag :current_path, request.fullpath
> + = restful_submit_tag t("filter_table.apply_filters"), "filter",
> filter_permissions_path, 'POST', :class => 'button', :id =>
> 'apply_permissions_preset_filter'
> + %span.label.badge.dark= @permissions.count
> + %li.table-search-filter
> + = text_field_tag :permissions_search,
> params[:permissions_search], :placeholder =>
> t("filter_table.search")
> + = restful_submit_tag "", "search", filter_permissions_path,
> 'POST', :class => 'button', :id => 'apply_permissions_search'
> +
> + :javascript
> + $(document).ready(function(){
> + $("#apply_permissions_preset_filter").hide();
> + $("#permissions_preset_filter").change(function() {
> + $("#apply_permissions_preset_filter").click();
> + });
> + Conductor.clickOnEnterKeypress($('#permissions_search'),
> $('#apply_permissions_search'));
> + });
> +
> = filter_table(@permission_list_header,
> @permissions,
> :form_header => :permissions_form_header,
> diff --git a/src/app/views/user_groups/_form.html.haml
> b/src/app/views/user_groups/_form.html.haml
> new file mode 100644
> index 0000000..1db6a7a
> --- /dev/null
> +++ b/src/app/views/user_groups/_form.html.haml
> @@ -0,0 +1,26 @@
> +- if @user_group.errors.any?
> + = render 'layouts/error_messages', :object => @user_group
> +
> +%fieldset
> + .field
> + = form.label :type
> + .input
> + - if @user_group.new_record?
> + = form.select(:membership_source,
> UserGroup::MEMBERSHIP_SOURCES.collect {|x|
> [t("user_groups.#{x.downcase}"), x]}, {}, {:disabled => true})
> + = form.hidden_field :membership_source
> + - else
> + = t("user_groups.#{@user_group.membership_source.downcase}")
> + .field
> + = form.label :name
> + .input
> + - if @user_group.new_record? or @user_group.membership_source
> == UserGroup::MEMBERSHIP_SOURCE_LOCAL
> + = form.text_field :name
> + - else
> + = @user_group.name
> + .field
> + = form.label :description
> + .input
> + = form.text_area :description, :class => 'long'
> +
> +%fieldset.options
> + = form.submit "#{t'user_groups.form.save_user_group'}", :class =>
> "submit button pill"
> diff --git a/src/app/views/user_groups/_list.html.haml
> b/src/app/views/user_groups/_list.html.haml
> new file mode 100644
> index 0000000..5c99b39
> --- /dev/null
> +++ b/src/app/views/user_groups/_list.html.haml
> @@ -0,0 +1,41 @@
> +%header
> + %h2#user_groups.groups= @title
> +
> +- content_for :form_header do
> + %li= restful_submit_tag "#{t'user_groups.list.delete_selected'}",
> "destroy", multi_destroy_user_groups_path, 'DELETE', :id =>
> 'delete_button', :class => 'button danger'
> + %li= link_to t("user_groups.list.add_user_group"),
> new_user_group_path, :class => 'button', :id =>
> 'add_user_group_button'
> +
> +- content_for :filter_controls do
> + %li
> + = label_tag :user_groups_preset_filter,
> t('filter_table.viewing')
> + = hidden_field_tag :current_path, request.fullpath
> + = select_tag(:user_groups_preset_filter,
> preset_filters_options_for_select(User::PRESET_FILTERS_OPTIONS,
> params[:user_groups_preset_filter]), :include_blank =>
> t("user_groups.preset_filters.all_user_groups"), :disabled => true)
> + = restful_submit_tag t("filter_table.apply_filters"), "index",
> filter_user_groups_path, 'POST', :class => 'button', :id =>
> 'apply_user_groups_preset_filter'
> + %span.label.badge.dark= @user_groups.count
> + / = link_to "Filter", "#", :class => 'button pill'
> + /%li
> + /%li.more_actions
> + / %span= image_tag "button-userdrop.png"
> + / %ul
> + / %li= link_to "Add/Remove Columns", "#"
> + / %li= link_to "Freeze Column", "#"
> + %li.table-search-filter
> + = text_field_tag :user_groups_search,
> params[:user_groups_search], :placeholder =>
> t("filter_table.search")
> + = restful_submit_tag "", "index", filter_user_groups_path,
> 'POST', :class => 'button', :id => 'apply_user_groups_search'
> +
> + :javascript
> + $(document).ready(function(){
> + $("#apply_user_groups_preset_filter").hide();
> + $("#user_groups_preset_filter").change(function() {
> + $("#apply_user_groups_preset_filter").click();
> + });
> + Conductor.clickOnEnterKeypress($('#user_groups_search'),
> $('#apply_user_groups_search'));
> + });
> +
> += filter_table(@header, @user_groups) do |user_group|
> + %tr{:class => cycle('nostripe','stripe')}
> + %td{:class => 'checkbox'}
> + - selected = params[:select] == 'all'
> + = check_box_tag "user_group_selected[]", user_group.id,
> selected, :id => "user_group_checkbox_#{user_group.id}"
> + %td= link_to user_group.name, user_group_path(user_group)
> + %td= t("user_groups.#{user_group.membership_source.downcase}")
> diff --git a/src/app/views/user_groups/add_members.html.haml
> b/src/app/views/user_groups/add_members.html.haml
> new file mode 100644
> index 0000000..4b3a30c
> --- /dev/null
> +++ b/src/app/views/user_groups/add_members.html.haml
> @@ -0,0 +1,25 @@
> += render :partial => 'layouts/admin_nav'
> +%header.page-header
> + .obj_actions
> + .return_to
> + = t'return_to'
> + = link_to @user_group.name, user_group_path(@user_group), :id
> => 'user_group_button'
> + %h1.user_groups= @user_group.name
> +
> +%section.content-section.user_groups
> + %header
> + .align-center
> + %strong= t("user_groups.choose_members")
> + .content
> + - content_for :form_footer do
> + = link_to t('cancel'), user_group_path(@user_group), :class =>
> 'button danger'
> + = restful_submit_tag t('user_groups.show.add_members'), "add",
> add_members_user_group_path(@user_group), 'POST', :id =>
> 'save_button', :class => 'button'
> + = filter_table(members_header, @users) do |user|
> + %tr{:class => cycle('nostripe','stripe')}
> + %td{:class => 'checkbox'}
> + - selected = params[:select] == 'all'
> + = check_box_tag "members_selected[]", user.id, selected,
> :id => "member_checkbox_#{user.id}"
> + %td
> + = link_to user.login, users_path(user)
> + %td
> + = user.name
> diff --git a/src/app/views/user_groups/edit.html.haml
> b/src/app/views/user_groups/edit.html.haml
> new file mode 100644
> index 0000000..7350a43
> --- /dev/null
> +++ b/src/app/views/user_groups/edit.html.haml
> @@ -0,0 +1,14 @@
> += render :partial => 'layouts/admin_nav'
> +%header.page-header
> + .obj_actions
> + .return_to
> + =t'return_to'
> + = link_to "#{t'user_groups.groups'}", user_groups_path
> + %h1.users= @title
> +
> +%section.content-section.user_groups
> + .content
> + .align-center
> + = @user_group.name
> + = form_for @user_group, :url => user_group_path(@user_group),
> :html => {:class => 'generic horizontal'} do |f|
> + = render :partial => "form", :locals => { :form => f }
> diff --git a/src/app/views/user_groups/index.html.haml
> b/src/app/views/user_groups/index.html.haml
> new file mode 100644
> index 0000000..7cc23db
> --- /dev/null
> +++ b/src/app/views/user_groups/index.html.haml
> @@ -0,0 +1,2 @@
> += render :partial => 'layouts/admin_nav'
> += render :partial => 'layouts/admin_users_tabs'
> diff --git a/src/app/views/user_groups/new.html.haml
> b/src/app/views/user_groups/new.html.haml
> new file mode 100644
> index 0000000..eaaf3a7
> --- /dev/null
> +++ b/src/app/views/user_groups/new.html.haml
> @@ -0,0 +1,13 @@
> += render :partial => 'layouts/admin_nav'
> +%header.page-header
> + .obj_actions
> + .return_to
> + =t'return_to'
> + = link_to "#{t'user_groups.groups'}", user_groups_path
> + %h1.users= @title
> +
> +%section.content-section.user_groups
> + .content
> + .align-center
> + = form_for @user_group, :url => user_groups_path, :html =>
> {:class => 'generic horizontal'} do |f|
> + = render :partial => "form", :locals => { :form => f }
> diff --git a/src/app/views/user_groups/show.html.haml
> b/src/app/views/user_groups/show.html.haml
> new file mode 100644
> index 0000000..426137f
> --- /dev/null
> +++ b/src/app/views/user_groups/show.html.haml
> @@ -0,0 +1,71 @@
> += render :partial => 'layouts/admin_nav'
> +%header.page-header
> + .obj_actions
> + .return_to
> + = t'return_to'
> + = link_to t("user_groups.groups"), user_groups_path
> + - if check_privilege(Privilege::CREATE, User)
> + = link_to t('user_groups.new.new_user_group'),
> new_user_group_url, :class => 'button primary', :id =>
> 'new_user_group_button'
> + .button-group
> + - if check_privilege(Privilege::MODIFY, User)
> + = link_to t('edit'), edit_user_group_path(@user_group),
> :class => 'button pill', :id => 'edit_button'
> + = button_to t("delete"), user_group_path(@user_group),
> :method => 'delete', :confirm => "Are you sure you want to delete?",
> :class => 'button pill danger', :id => 'delete'
> + %h1.no-icon= @title
> +
> +%section.content-section.user
> + %header
> + %h2=t'properties'
> +
> + .content
> + %table.properties_table
> + %tbody
> + %tr
> + %td= t('user_groups.show.type')
> + %td= @user_group.membership_source
> + %tr
> + %td= t('user_groups.show.name')
> + %td= @user_group.name
> + %tr
> + %td= t('user_groups.show.description')
> + %td= @user_group.description
> +
> +- if @user_group.membership_source ==
> UserGroup::MEMBERSHIP_SOURCE_LOCAL
> + %section.content-section
> + %header
> + %h2=t('user_groups.show.members')
> +
> + .content
> + - content_for :form_header do
> + - if check_privilege(Privilege::CREATE, Deployable)
> + %li= restful_submit_tag t("remove"), "destroy",
> remove_members_user_group_path(@user_group), 'DELETE', :id =>
> 'delete_button', :class => 'button danger'
> + %li= link_to t("user_groups.show.add_members"),
> add_members_user_group_path(@user_group), :class => 'button', :id =>
> 'add_members_button'
> +
> + - content_for :filter_controls do
> + %li
> + = label_tag :members_preset_filter,
> t('filter_table.viewing')
> + = hidden_field_tag :current_path, request.fullpath
> + = select_tag(:members_preset_filter,
> preset_filters_options_for_select(Deployable::PRESET_FILTERS_OPTIONS,
> params[:members_preset_filter]), :include_blank =>
> t("users.preset_filters.all_users"), :disabled => true)
> + = restful_submit_tag t("filter_table.apply_filters"),
> "filter", filter_members_user_group_path(@user_group), 'POST',
> :class => 'button', :id => 'apply_members_preset_filter'
> + %span.label.badge.dark= @user_group.members.count
> + %li.table-search-filter
> + = text_field_tag :members_search, params[:members_search],
> :placeholder => t("filter_table.search")
> + = restful_submit_tag "", "search",
> filter_members_user_group_path(@user_group), 'POST', :class =>
> 'button', :id => 'apply_members_search'
> +
> + :javascript
> + $(document).ready(function(){
> + $("#apply_members_preset_filter").hide();
> + $("#members_preset_filter").change(function() {
> + $("#apply_members_preset_filter").click();
> + });
> + Conductor.clickOnEnterKeypress($('#members_search'),
> $('#apply_members_search'));
> + });
> +
> + = filter_table(members_header, @members) do |member|
> + %tr{:class => cycle('nostripe','stripe')}
> + %td{:class => 'checkbox'}
> + - selected = params[:select] == 'all'
> + = check_box_tag "members_selected[]", member.id,
> selected, :id => "member_checkbox_#{member.id}"
> + %td
> + = link_to member.login, users_path(member)
> + %td
> + = member.name
> diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
> index 8c2e010..9295373 100644
> --- a/src/config/locales/en.yml
> +++ b/src/config/locales/en.yml
> @@ -102,6 +102,62 @@ en:
> name_starts_with_B: "Name starts with B"
> errors:
> has_running_instances: '%{login} has running instances'
> + user_groups:
> + groups: "User Groups"
> + local: Local
> + ldap: LDAP
> + return_to: "Return to:"
> + confirm_delete: "Are you sure you want to delete this user
> group?"
> + quick_jump: "Quick Jump:"
> + choose_members: "Choose Users to add to this Group."
> + index:
> + name: Name
> + type: Type
> + show:
> + name: Name
> + type: Type
> + description: Description
> + members: Members
> + add_members: Add Members
> + edit: Edit
> + delete: Delete
> + created: CREATED
> + last_updated: LAST UPDATED
> + form:
> + name: Name
> + type: Type
> + save_user_group: Save User Group
> + new:
> + new_user_group: New User Group
> + neccessary_information: "Enter necessary information about
> your new user group and click 'Save User Group' when you are
> finished."
> + list:
> + delete_selected: Delete Selected
> + add_user_group: Add User Group
> + edit:
> + edit_user_group: Edit User Group
> + flash:
> + notice:
> + added: "User Group added"
> + updated: "User Group updated!"
> + deleted: "User Group has been successfully deleted."
> + more_deleted:
> + one: Deleted user group
> + other: Deleted user groups
> + members_added: "These users have been added"
> + members_removed: "These users have been removed"
> + warning:
> + creation_failed: 'Could not create user group'
> + delete_failed: 'Could not delete user group'
> + not_delete: 'Cannot delete: %{reason}'
> + error:
> + members_not_added: "Could not add these users"
> + members_not_removed: "Could not remove these users"
> + not_a_local_group: 'Only locally-managed groups can be
> managed here.'
> + select_to_add_members: 'You must select at least one user to
> add.'
> + preset_filters:
> + all_user_groups: "All User Groups"
> + local: "Locally-managed User Groups"
> + ldap: "LDAP-managed User Groups"
> user_sessions:
> new:
> username: "Username:"
> @@ -151,6 +207,7 @@ en:
> role: Role
> role_assignments: Role Assignments
> user: User
> + user_group: User Group
> privileges: Privileges
> general_settings: General Settings
> new_user: New User
> @@ -1285,7 +1342,10 @@ en:
> user_and_role: "%{user} (%{role})"
> user_and_role_change: "%{user} (from %{old_role} to
> %{role})"
> preset_filters:
> + all_entities: All Entities
> all_permissions: All Permissions
> + user_permissions: User Permissions
> + group_permissions: Group Permissions
> quotas:
> quota: Quota
> edit:
> @@ -1333,6 +1393,7 @@ en:
> administer: Administer
> second_level:
> users: Users
> + user_groups: User Groups
> environments: Environments
> content: Content
> cloud_providers: Cloud Providers
> @@ -1353,7 +1414,7 @@ en:
> realms: Realms
> hardware: Hardware
> users: Users
> - groups: Groups
> + user_groups: User Groups
> permissions: Global Role Grants
> pool_families: Pool Families
> images: Images
> diff --git a/src/config/navigation.rb b/src/config/navigation.rb
> index c8a48a2..4c37e23 100644
> --- a/src/config/navigation.rb
> +++ b/src/config/navigation.rb
> @@ -20,7 +20,7 @@ SimpleNavigation::Configuration.run do |navigation|
> first_level.dom_class = 'container'
> first_level.item :monitor, t('navigation.first_level.monitor'),
> pools_path, :class => 'monitor', :link => { :id => 'monitor' },
> :highlights_on =>
> /\/deployments|\/pools|\/instances|\/logs|\/\z/
> first_level.item :administer,
> t('navigation.first_level.administer'), users_path, :class =>
> 'administer' do |second_level|
> - second_level.item :users, t('navigation.second_level.users'),
> users_path, :link => { :class => 'users' }, :highlights_on =>
> /\/users|\/roles|\/permissions|\/account/
> + second_level.item :users, t('navigation.second_level.users'),
> users_path, :link => { :class => 'users' }, :highlights_on =>
> /\/users|\/user_groups|\/roles|\/permissions|\/account/
> second_level.item :environments,
> t('navigation.second_level.environments'),
> pool_families_path, :link => { :class => 'environments' },
> :highlights_on => /\/pool_families|\/images/
> second_level.item :content,
> t('navigation.second_level.content'), catalogs_path, :link =>
> { :class => 'content' }, :highlights_on =>
> /\/catalogs|\/catalog_entries|\/realms|\/hardware_profiles|\/realm_mappings|\/deployables/
> second_level.item :cloud_providers,
> t('navigation.second_level.cloud_providers'), providers_path,
> :link => { :class => 'providers' }, :highlights_on =>
> /\/providers|\/provider_realms|\/config_servers/
> diff --git a/src/config/routes.rb b/src/config/routes.rb
> index da762a7..68ed728 100644
> --- a/src/config/routes.rb
> +++ b/src/config/routes.rb
> @@ -83,6 +83,8 @@ Conductor::Application.routes.draw do
> get :list
> delete :multi_destroy
> post :multi_update
> + post :filter
> + post :filter_entities
> end
> end
>
> @@ -156,6 +158,19 @@ Conductor::Application.routes.draw do
> post :filter, :on => :collection
> end
>
> + resources :user_groups do
> + collection do
> + delete 'multi_destroy'
> + post :filter
> + end
> + member do
> + get 'add_members'
> + post 'add_members'
> + delete 'remove_members'
> + post 'filter_members'
> + end
> + end
> +
> resources :logs do
> collection do
> post 'filter'
> diff --git a/src/features/step_definitions/user_group_steps.rb
> b/src/features/step_definitions/user_group_steps.rb
> new file mode 100644
> index 0000000..2959a21
> --- /dev/null
> +++ b/src/features/step_definitions/user_group_steps.rb
> @@ -0,0 +1,56 @@
> +#
> +# Copyright 2012 Red Hat, Inc.
> +#
> +# 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.
> +#
> +Given /^a user group "([^"]*)" exists$/ do |name|
> + unless UserGroup.find_by_name(name)
> + FactoryGirl.create :user_group, :name => name
> + end
> +end
> +
> +Given /^there is a user group "([^"]*)"$/ do |name|
> + unless UserGroup.find_by_name(name)
> + FactoryGirl.create :user_group, :name => name
> + end
> +end
> +
> +Then /^there should be (\d+) user groups?$/ do |number|
> + UserGroup.count.should == number.to_i
> +end
> +
> +When /^I check "([^"]*)" user group$/ do |user_group_name|
> + user_group = UserGroup.find_by_name(user_group_name)
> + check("user_group_checkbox_#{user_group.id}")
> +end
> +
> +When /^I check the "([^"]*)" member$/ do |login|
> + member = User.find_by_login(login)
> + check("member_checkbox_#{member.id}")
> +end
> +
> +Then /^there should be (\d+) user belonging to "([^"]*)"$/ do
> |count, name|
> + user_group = UserGroup.find_by_name(name)
> + user_group.members.count == count
> +end
> +
> +Given /^there is a user "([^"]*)" belonging to user group
> "([^"]*)"$/ do |login, group_name|
> + member = User.find_by_login(login)
> + user_group = UserGroup.find_by_name(group_name)
> + user_group.members << member
> +end
> +
> +Then /^there should not exist a member belonging to "([^"]*)"$/ do
> |group_name|
> + user_group = UserGroup.find_by_name(group_name)
> + user_group.members.count == 0
> +end
> diff --git a/src/features/support/paths.rb
> b/src/features/support/paths.rb
> index 38f926d..f809a8c 100644
> --- a/src/features/support/paths.rb
> +++ b/src/features/support/paths.rb
> @@ -35,6 +35,9 @@ module NavigationHelpers
> when /^(.*)'s user page$/i
> user_path(User.find_by_login($1))
>
> + when /^(.*)'s user group page$/i
> + user_group_path(UserGroup.find_by_name($1))
> +
> when /^(.*)'s role page$/i
> role_path(Role.find_by_name($1))
>
> @@ -179,6 +182,9 @@ module NavigationHelpers
> when /^the (.*)'s edit user page$/
> edit_user_path(User.find_by_login($1))
>
> + when /^the (.*)'s edit user group page$/
> + edit_user_group_path(UserGroup.find_by_name($1))
> +
> when /^the "(.*)" catalog page/
> url_for catalog_path(Catalog.find_by_name($1))
>
> diff --git a/src/features/user_group.feature
> b/src/features/user_group.feature
> new file mode 100644
> index 0000000..08f4db7
> --- /dev/null
> +++ b/src/features/user_group.feature
> @@ -0,0 +1,72 @@
> +Feature: Manage User Groups
> + In order to manage user groups
> + As an admin
> + I want to add/edit/remove user groupss
> +
> + Background:
> + Given I am an authorised user
> + And I am logged in
> + And a user group "testgroup" exists
> + And a user "testuser" exists
> +
> + Scenario: Show user group detials
> + Given I am on the user groups page
> + And there is a user group "testgroup"
> + When I follow "testgroup"
> + Then I should be on testgroup's user group page
> +
> + Scenario: Delete user groups
> + Given there is a user group "testgroup"
> + Given there is a user group "testgroup2"
> + And I am on the user groups page
> + Then there should be 2 user groups
> + And I should be on the user groups page
> + When I check "testgroup" user group
> + And I press "Delete"
> + Then I should see "Deleted user group"
> + And there should be 1 user group
> +
> + Scenario: Create new user group
> + Given I am on the user groups page
> + When I follow "add_user_group_button"
> + Then I should be on the new user group page
> + And I should see "New User Group"
> + When I fill in the following:
> + | Name | testgroup3 |
> + And I press "Save"
> + Then I should be on the user groups page
> + And I should see "User Group added"
> +
> + Scenario: Edit existing user group
> + Given I am on the user groups page
> + And I follow "testgroup"
> + Then I should be on testgroup's user group page
> + And I should see "testgroup"
> + When I follow "Edit"
> + Then I should be on the testgroup's edit user group page
> + And I fill in "user_group_name" with "newname"
> + When I press "Save"
> + Then I should be on newname's user group page
> + And I should see "User Group updated"
> + And I should see "newname"
> +
> + Scenario: Add member to user group
> + Given I am on the user groups page
> + And I follow "testgroup"
> + Then I should be on testgroup's user group page
> + And I should see "testgroup"
> + When I follow "Add Member"
> + And I check the "testuser" member
> + And I press "Add Member"
> + Then there should be 1 user belonging to "testgroup"
> + And I should see "testuser"
> +
> + Scenario: Remove member from user group
> + And there is a user "testuser" belonging to user group
> "testgroup"
> + Given I am on the user groups page
> + And I follow "testgroup"
> + Then I should be on testgroup's user group page
> + Then I should see "testuser"
> + When I check the "testuser" member
> + And I press "Remove"
> + Then there should not exist a member belonging to "testgroup"
> diff --git a/src/spec/controllers/user_groups_controller_spec.rb
> b/src/spec/controllers/user_groups_controller_spec.rb
> new file mode 100644
> index 0000000..d5e68bb
> --- /dev/null
> +++ b/src/spec/controllers/user_groups_controller_spec.rb
> @@ -0,0 +1,75 @@
> +#
> +# Copyright 2011 Red Hat, Inc.
> +#
> +# 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.
> +#
> +
> +require 'spec_helper'
> +
> +describe UserGroupsController do
> +
> + fixtures :all
> + before(:each) do
> + @user_group = Factory.create(:user_group)
> + @tuser = FactoryGirl.create :tuser
> + @admin_permission = FactoryGirl.create :admin_permission
> + @admin = @admin_permission.user
> + end
> +
> + describe "#create" do
> + context "user enters valid input" do
> + it "creates user group" do
> + mock_warden(@admin)
> + lambda do
> + post :create, :user_group => {
> + :name => "user_group2", :membership_source => "local" }
> + end.should change(UserGroup, :count).by(1)
> +
> + response.should redirect_to(user_groups_path)
> + end
> +
> + it "fails to create user" do
> + mock_warden(@admin)
> + lambda do
> + post :create, :user_group => {}
> + end.should_not change(UserGroup, :count)
> +
> + returned_user_group = assigns[:user_group]
> + returned_user_group.errors.empty?.should be_false
> + returned_user_group.should have(1).errors_on(:name)
> + returned_user_group.should
> have(2).errors_on(:membership_source)
> +
> + response.should render_template('new')
> + end
> + end
> + end
> +
> + it "allows an admin to create user group" do
> + mock_warden(@admin)
> + lambda do
> + post :create, :user_group => {
> + :name => "user_group3", :membership_source => "local" }
> + end.should change(UserGroup, :count)
> +
> + response.should redirect_to(user_groups_url)
> + end
> +
> + it "should not allow a regular user to create user group" do
> + mock_warden(@tuser)
> + lambda do
> + post :create, :user_group => {
> + :name => "user_group4", :membership_source => "local" }
> + end.should_not change(UserGroup, :count)
> + end
> +
> +end
> diff --git a/src/spec/factories/permission.rb
> b/src/spec/factories/permission.rb
> index e401fe8..4b2d2b4 100644
> --- a/src/spec/factories/permission.rb
> +++ b/src/spec/factories/permission.rb
> @@ -62,4 +62,11 @@ FactoryGirl.define do
> entity { |r| FactoryGirl.create(:pool_family_user).entity }
> end
>
> + factory :group_admin_permission, :parent => :permission do
> + role { |r| Role.first(:conditions => ['name = ?', 'base.admin'])
> || FactoryGirl.create(:role, :name => 'base.admin') }
> + permission_object { |r|
> BasePermissionObject.general_permission_scope }
> + entity { |r| FactoryGirl.create(:user_group).entity }
> + end
> +
> +
> end
> diff --git a/src/app/models/common_filter_methods.rb
> b/src/spec/factories/user_group.rb
> similarity index 56%
> copy from src/app/models/common_filter_methods.rb
> copy to src/spec/factories/user_group.rb
> index 7bb2be2..bf1f6fc 100644
> --- a/src/app/models/common_filter_methods.rb
> +++ b/src/spec/factories/user_group.rb
> @@ -1,5 +1,5 @@
> #
> -# Copyright 2011 Red Hat, Inc.
> +# Copyright 2012 Red Hat, Inc.
> #
> # Licensed under the Apache License, Version 2.0 (the "License");
> # you may not use this file except in compliance with the License.
> @@ -13,19 +13,16 @@
> # See the License for the specific language governing permissions
> and
> # limitations under the License.
> #
> -#this module contains functions for filtering table data
> -module CommonFilterMethods
> - def apply_filters(options = {})
> -
> apply_preset_filter(options[:preset_filter_id]).apply_search_filter(options[:search_filter])
> - end
>
> - private
> +FactoryGirl.define do
> +
> + factory :user_group do |u|
> + sequence(:name) { |n| "group#{n}" }
> + membership_source 'local'
> + end
>
> - def apply_preset_filter(preset_filter_id)
> - if preset_filter_id.present?
> - self::PRESET_FILTERS_OPTIONS.select{|item| item[:id] ==
> preset_filter_id}.first[:query]
> - else
> - scoped
> - end
> + factory :ldap_group , :parent => :user_group do
> + membership_source = 'LDAP'
> end
> +
> end
> diff --git a/src/spec/models/permission_spec.rb
> b/src/spec/models/permission_spec.rb
> index 7f05587..ea9a20d 100644
> --- a/src/spec/models/permission_spec.rb
> +++ b/src/spec/models/permission_spec.rb
> @@ -84,4 +84,23 @@ describe Permission do
> should be_false
> end
>
> + it "User added to Admin group should be able to create users" do
> + newuser = FactoryGirl.create(:user)
> + group_admin_permission =
> FactoryGirl.create(:group_admin_permission)
> + user_group = group_admin_permission.user_group
> + SessionEntity.update_session(@session_id, newuser)
> +
> BasePermissionObject.general_permission_scope.has_privilege(@session_id,
> +
> newuser,
> +
> Privilege::CREATE,
> +
> User).should
> be_false
> + user_group.members << newuser
> + newuser.reload
> + SessionEntity.update_session(@session_id, newuser)
> +
> BasePermissionObject.general_permission_scope.has_privilege(@session_id,
> +
> newuser,
> +
> Privilege::CREATE,
> +
> User).should
> be_true
> +
> + end
> +
> end
> diff --git a/src/spec/models/user_group_spec.rb
> b/src/spec/models/user_group_spec.rb
> new file mode 100644
> index 0000000..915df0a
> --- /dev/null
> +++ b/src/spec/models/user_group_spec.rb
> @@ -0,0 +1,43 @@
> +#
> +# Copyright 2012 Red Hat, Inc.
> +#
> +# 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.
> +#
> +
> +require 'spec_helper'
> +
> +describe UserGroup do
> + before(:each) do
> + end
> +
> + it "should create a new local group" do
> + user_group = Factory.create(:user_group)
> + user_group.should be_valid
> + user_group.members.size.should == 0
> + end
> +
> + it "should create a new ldap group" do
> + user_group = Factory.create(:ldap_group)
> + user_group.should be_valid
> + end
> +
> + it "should add members to a new local group" do
> + user_group = Factory.create(:user_group)
> + user = Factory.create(:tuser)
> + user_group.members.size.should == 0
> + user_group.members << user
> + user_group.reload
> + user_group.members.size.should == 1
> + end
> +
> +end
> --
> 1.7.6.5
>
>
More information about the aeolus-devel
mailing list