On Tuesday 19 June 2012 17:42:40 Scott Seago wrote:
> 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 | 12 +-
> src/app/controllers/user_groups_controller.rb | 202
> ++++++++++++++++++++ .../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 | 62 ++++++-
> src/config/routes.rb | 15 ++
> .../step_definitions/user_group_steps.rb} | 26 ++-
> src/features/support/paths.rb | 6 +
> src/features/user_group.feature | 54 ++++++
> .../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 ++++
> 29 files changed, 851 insertions(+), 44 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
> copy src/{app/models/entity.rb =
>
features/step_definitions/user_group_steps.rb} (52%) 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 d2c4efd..1ed8159 100644
> --- a/aeolus-conductor.spec.in
> +++ b/aeolus-conductor.spec.in
> @@ -199,6 +199,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 eb5931b..b30326b
> 100644
> --- a/src/app/controllers/application_controller.rb
> +++ b/src/app/controllers/application_controller.rb
> @@ -281,7 +281,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}
> @@ -350,7 +350,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 acdbb2c..6d8ae54
> 100644
> --- a/src/app/controllers/permissions_controller.rb
> +++ b/src/app/controllers/permissions_controller.rb
> @@ -165,11 +165,21 @@ 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_order),
> params[:page]) + @entities =
> paginate_collection(Entity.order(sort_order).
> + apply_filters(:preset_filter_id => params[:entities_preset_filter],
> + :search_filter => params[:entities_search]),
> params[:page]) end
> def load_headers
> diff --git a/src/app/controllers/user_groups_controller.rb
> b/src/app/controllers/user_groups_controller.rb new file mode 100644
> index 0000000..189ec09
> --- /dev/null
> +++ b/src/app/controllers/user_groups_controller.rb
> @@ -0,0 +1,202 @@
> +#
> +# 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((a)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 !(a)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 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_typ
> :e]
> + # :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.#{(a)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..19b825a 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:
> @@ -1353,7 +1413,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/routes.rb b/src/config/routes.rb
> index da762a7..38fbb53 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'
> + post 'remove_members'
> + post 'filter_members'
> + end
> + end
> +
> resources :logs do
> collection do
> post 'filter'
> diff --git a/src/app/models/entity.rb
> b/src/features/step_definitions/user_group_steps.rb similarity index 52%
> copy from src/app/models/entity.rb
> copy to src/features/step_definitions/user_group_steps.rb
> index bbc56fe..b5426f2 100644
> --- a/src/app/models/entity.rb
> +++ b/src/features/step_definitions/user_group_steps.rb
> @@ -13,17 +13,23 @@
> # 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
> -class Entity< ActiveRecord::Base
> - belongs_to :entity_target, :polymorphic => true
> - validates_presence_of :entity_target_id
> - has_many :session_entities, :dependent => :destroy
> - has_many :permissions, :dependent => :destroy
> - has_many :derived_permissions, :dependent => :destroy
> +Given /^there is a user group "([^"]*)"$/ do |name|
> + unless UserGroup.find_by_name(name)
> + FactoryGirl.create :user_group, :name => name
> + end
> +end
> - # type-specific associations
> - belongs_to :user, :class_name => "User", :foreign_key =
> "entity_target_id" - belongs_to :user_group,
:class_name => "UserGroup",
> - :foreign_key => "entity_target_id"
> +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
> 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..d858035
> --- /dev/null
> +++ b/src/features/user_group.feature
> @@ -0,0 +1,54 @@
> +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
> +
> + 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
> + 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"
> +
> +
> +
> +
remove this ^, because git said "src/features/user_group.feature:51: new blank
line at EOF" when I applied this patch
> 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
NACK with one inline nit.
I'd like to advise you for next time to split patch to smaller parts(patches),
then the reviewing will be more comfortable. Also whole new funcionality could
be more readable.
It's good approach to have only 1-3 changed files per patch, in this patch is
29 files changed, 851 insertions(+), 44 deletions(-)
Issues to fix:
- navigation.rb - need to be added user_groups to "second_level.item :users
... , :highlights_on => .."
- method remove_members is missing in user_groups_controller.rb (what caused
that member cannot be removed from group)
- missing test for removing members
I've fixed the mentioned issues above (including the whitespace one),
and I'm about to send an updated patch.
Scott