This patch only enables the UI to modify permissions on Pools. The vast majority of the code is non-type-specific though, so once this part is finalized it will be easy to expand it to other object types. --- src/app/controllers/application_controller.rb | 10 + src/app/controllers/permissions_controller.rb | 184 ++++++++++++++++----- src/app/controllers/pools_controller.rb | 14 ++- src/app/helpers/application_helper.rb | 1 + src/app/stylesheets/custom.scss | 4 + src/app/views/layouts/_filter_table.haml | 4 + src/app/views/permissions/_form.haml | 16 ++ src/app/views/permissions/_new.haml | 14 ++ src/app/views/permissions/_permissions.haml | 24 +++ src/app/views/permissions/index.haml | 1 + src/app/views/permissions/new.haml | 20 +-- src/app/views/pools/_permissions.haml | 8 +- src/config/locales/en.yml | 4 + src/config/routes.rb | 2 + src/features/permission.feature | 58 ++++--- src/features/step_definitions/permission_steps.rb | 13 ++- 16 files changed, 285 insertions(+), 92 deletions(-) create mode 100644 src/app/views/permissions/_form.haml create mode 100644 src/app/views/permissions/_new.haml create mode 100644 src/app/views/permissions/_permissions.haml create mode 100644 src/app/views/permissions/index.haml
diff --git a/src/app/controllers/application_controller.rb b/src/app/controllers/application_controller.rb index b2d7453..2b7f9c5 100644 --- a/src/app/controllers/application_controller.rb +++ b/src/app/controllers/application_controller.rb @@ -241,4 +241,14 @@ class ApplicationController < ActionController::Base raise "Tab '#{tab}' doesn't exist" end end + + def set_permissions_header + @permission_list_header = [ + { :name => '', :sortable => false }, + { :name => t("user"), :sort_attr => :last_name }, + { :name => t("role"), :sort_attr => :role}, + { :name => t("privileges")}, + ] + end + end diff --git a/src/app/controllers/permissions_controller.rb b/src/app/controllers/permissions_controller.rb index 280fbe9..b2eaa7f 100644 --- a/src/app/controllers/permissions_controller.rb +++ b/src/app/controllers/permissions_controller.rb @@ -18,40 +18,150 @@
class PermissionsController < ApplicationController before_filter :require_user + before_filter :set_permissions_header
- def show - @permission = Permission.find(params[:id]) - require_privilege(Privilege::PERM_VIEW, @permission.permission_object) - end - - def list - set_permission_object Privilege::PERM_VIEW + def index + obj_type = params[:permission_object_type] + id = params[:permission_object_id] + @permission_object = obj_type.constantize.find(id) if obj_type and id + raise RuntimeError, "invalid permission object" if @permission_object.nil? + respond_to do |format| + format.html + format.json { render :json => @permission_object.as_json } + format.js { render :partial => 'index' } + end end
def new - set_permission_object Privilege::PERM_SET - @permission = Permission.new(:permission_object_type => @permission_object.class, - :permission_object_id => @permission_object.id) + obj_type = params[:permission_object_type] + id = params[:permission_object_id] + @permission_object = obj_type.constantize.find(id) if obj_type and id + require_privilege(Privilege::PERM_SET, @permission_object) @users = User.all @roles = Role.find_all_by_scope(@permission_object.class.name) + load_headers + load_users + respond_to do |format| + format.html + format.js { render :partial => 'new' } + end end
def create - @permission = Permission.new(params[:permission]) - require_privilege(Privilege::PERM_SET, @permission.permission_object) - if request.post? && @permission.save - flash[:notice] = "Permission record added." - redirect_to :action => "list", - :permission_object_type => @permission.permission_object_type, - :permission_object_id => @permission.permission_object_id - else - @permission_object = @permission.permission_object - @users = User.all - @roles = Role.find_all_by_scope(@permission_object.class.name) - render :action => 'new' + obj_type = params[:permission_object_type] + id = params[:permission_object_id] + @permission_object = obj_type.constantize.find(id) if obj_type and id + require_privilege(Privilege::PERM_SET, @permission_object) + added=[] + not_added=[] + params[:user_role_selected].each do |user_role| + user_id,role_id = user_role.split(",") + unless role_id.nil? + permission = Permission.new(:user_id => user_id, + :role_id => role_id, + :permission_object => @permission_object) + if permission.save + added << permission.user.login + " " + permission.role.name + else + not_added << permission.user.login + " " + permission.role.name + end + end + end + unless added.empty? + flash[:notice] = "These User Roles were added: #{added.join(', ')}" + end + unless not_added.empty? + flash[:error] = "Could not add these User Roles: #{not_added.join(', ')}" + end + if added.empty? and not_added.empty? + flash[:error] = "No users selected" + end + respond_to do |format| + format.html { redirect_to polymorphic_path(@permission_object, + :details_tab => :permissions, + :only_tab => true) } + format.js { render :partial => 'index', + :permission_object_type => @permission_object.class.name, + :permission_object_id => @permission_object.id } + end + end + + def multi_update + obj_type = params[:permission_object_type] + id = params[:permission_object_id] + @permission_object = obj_type.constantize.find(id) if obj_type and id + require_privilege(Privilege::PERM_SET, @permission_object) + modified=[] + not_modified=[] + params[:permission_role_selected].each do |permission_role| + permission_id,role_id = permission_role.split(",") + unless role_id.nil? + permission = Permission.find(permission_id) + role = Role.find(role_id) + old_role = permission.role + unless permission.role == role + permission.role = role + if permission.save + modified << permission.user.login + " " + permission.role.name + " from " + old_role.name + else + not_modified << permission.user.login + " " + permission.role.name + end + end + end + end + unless modified.empty? + flash[:notice] = "These User Roles were modified: #{modified.join(', ')}" + end + unless not_modified.empty? + flash[:error] = "Could not add these User Roles: #{not_modified.join(', ')}" + end + if modified.empty? and not_modified.empty? + flash[:error] = "No users selected" + end + respond_to do |format| + format.html { redirect_to polymorphic_path(@permission_object, + :details_tab => :permissions, + :only_tab => true) } + format.js { render :partial => 'index', + :permission_object_type => @permission_object.class.name, + :permission_object_id => @permission_object.id } end end
+ def multi_destroy + obj_type = params[:permission_object_type] + id = params[:permission_object_id] + @permission_object = obj_type.constantize.find(id) if obj_type and id + raise RuntimeError, "invalid permission object" if @permission_object.nil? + require_privilege(Privilege::PERM_SET, @permission_object) + deleted=[] + not_deleted=[] + + Permission.find(params[:permission_selected]).each do |p| + if check_privilege(Privilege::PERM_SET, p.permission_object) && p.destroy + deleted << p.user.login + " " + p.role.name + else + not_deleted << p.user.login + " " + p.role.name + end + end + + unless deleted.empty? + flash[:notice] = "These Permission Grants were deleted: #{deleted.join(', ')}" + end + unless not_deleted.empty? + flash[:error] = "Could not delete these Permission Grants: #{not_deleted.join(', ')}" + end + respond_to do |format| + format.html { redirect_to polymorphic_path(@permission_object, + :details_tab => :permissions, + :only_tab => true) } + format.js { render :partial => 'index', + :permission_object_type => @permission_object.class.name, + :permission_object_id => @permission_object.id } + format.json { render :json => @permission, :status => :created } + end + + end def destroy if request.post? p =Permission.find(params[:permission][:id]) @@ -65,25 +175,19 @@ class PermissionsController < ApplicationController
private
- def set_permission_object(action) - if !params[:permission_object_type].nil? - @permission_object = - params[:permission_object_type].constantize.find(params[:permission_object_id]) - elsif !params[:pool_id].nil? - @permission_object = Pool.find params[:pool_id] - elsif !params[:provider_id].nil? - @permission_object = Provider.find params[:provider_id] - elsif !params[:cloud_account_id].nil? - @permission_object = ProviderAccount.find params[:cloud_account_id] - elsif !params[:base_permission_object_id].nil? - @permission_object = BasePermissionObject.find params[:base_permission_object_id] - else - @permission_object = BasePermissionObject.general_permission_scope - end - - raise ActiveRecord::RecordNotFound if @permission_object.nil? + def load_users + sort_order = params[:sort_by].nil? ? "login" : params[:sort_by] + @users = User.all(:order => sort_order) + end
- require_privilege(action, @permission_object) + def load_headers + @header = [ + { :name => '', :sortable => false }, + { :name => t('users.index.username'), :sortable => false }, + { :name => t('users.index.last_name'), :sortable => false }, + { :name => t('users.index.first_name'), :sortable => false }, + { :name => t('role'), :sortable => false } + ] end
end diff --git a/src/app/controllers/pools_controller.rb b/src/app/controllers/pools_controller.rb index 043af1d..1ab7c1b 100644 --- a/src/app/controllers/pools_controller.rb +++ b/src/app/controllers/pools_controller.rb @@ -20,6 +20,7 @@ class PoolsController < ApplicationController before_filter :require_user before_filter :set_params_and_header, :only => [:index, :show] before_filter :load_pools, :only => [:show] + before_filter :set_permissions_header, :only => [:show]
viewstate :index do |default| default.merge!({ @@ -91,11 +92,22 @@ class PoolsController < ApplicationController #{:name => 'History', :view => @view, :id => 'history'}, {:name => 'Properties', :view => 'properties', :id => 'properties'}, {:name => 'Catalog Images', :view => 'images', :id => 'images'} - #{:name => 'Permissions', :view => 'permissions', :id => 'permissions'} ] if "images" == params[:details_tab] @map = @pool.provider_image_map end + + if "permissions" == params[:details_tab] + require_privilege(Privilege::PERM_VIEW, @pool) + @permission_object = @pool + end + if @pool.has_privilege(current_user, Privilege::PERM_VIEW) + @roles = Role.find_all_by_scope(@permission_object.class.name) + @tabs << {:name => 'Users', + :view => 'permissions', + :id => 'permissions', + :count => @pool.permissions.count} + end details_tab_name = params[:details_tab].blank? ? 'deployments' : params[:details_tab] @details_tab = @tabs.find {|t| t[:id] == details_tab_name} || @tabs.first[:name].downcase @deployments = @pool.deployments if @details_tab[:id] == 'deployments' diff --git a/src/app/helpers/application_helper.rb b/src/app/helpers/application_helper.rb index 0135722..dc979c6 100644 --- a/src/app/helpers/application_helper.rb +++ b/src/app/helpers/application_helper.rb @@ -72,6 +72,7 @@ module ApplicationHelper select_togle_opts = options[:show_select_toggle] render :partial => 'layouts/filter_table', :locals => { :form_header => options[:form_header] || :form_header, + :form_footer => options[:form_footer] || :form_footer, # TODO - Right now saved_searches are not functional; this will need to be expanded :saved_searches => ["<option>All #{_class.name.pluralize}</option>"], :object_count => rows.count, diff --git a/src/app/stylesheets/custom.scss b/src/app/stylesheets/custom.scss index d019798..7b8d2cd 100644 --- a/src/app/stylesheets/custom.scss +++ b/src/app/stylesheets/custom.scss @@ -47,3 +47,7 @@ ul.deployment-array.small li.deployment { height: 90px; } + +.hidden { + display: none; +} diff --git a/src/app/views/layouts/_filter_table.haml b/src/app/views/layouts/_filter_table.haml index 0f98d0d..8a36b92 100644 --- a/src/app/views/layouts/_filter_table.haml +++ b/src/app/views/layouts/_filter_table.haml @@ -27,3 +27,7 @@ %th = column[:name] = rows.collect {|row| capture_haml(row, &block)}.to_s.html_safe + + - if content_for? form_footer + %ul.obj_actions + = yield form_footer diff --git a/src/app/views/permissions/_form.haml b/src/app/views/permissions/_form.haml new file mode 100644 index 0000000..8c2debd --- /dev/null +++ b/src/app/views/permissions/_form.haml @@ -0,0 +1,16 @@ +- content_for :form_footer do + = hidden_field_tag :permission_object_type, @permission_object.class.name + = hidden_field_tag :permission_object_id, @permission_object.id + = link_to 'Cancel', polymorphic_path(@permission_object, + :details_tab => :permissions, + :only_tab => true), :class => 'button danger' + = restful_submit_tag "Grant Access", "create", permissions_path, 'POST', :id => 'save_button' += filter_table(@header, @users) do |user| + %tr{:class => cycle('nostripe','stripe')} + %td + -# - selected = params[:select] == 'all' + -# = check_box_tag "user_selected[]", user.id, selected, :id => "user_checkbox_#{user.id}" + %td= link_to user.login, user_path(user) + %td= user.last_name + %td= user.first_name + %td= select_tag "user_role_selected[]", options_for_select([['', "#{user.id},"]] + @roles.map {|r| [ r.name, "#{user.id},#{r.id}" ] }, :disabled => @permission_object.permissions.where(:user_id=>user.id).collect {|p| "#{user.id},#{p.role.id}"}), :id => "user_role_selected_#{user.id}" diff --git a/src/app/views/permissions/_new.haml b/src/app/views/permissions/_new.haml new file mode 100644 index 0000000..63d8125 --- /dev/null +++ b/src/app/views/permissions/_new.haml @@ -0,0 +1,14 @@ +%header.page-header + %h1{:class => controller.controller_name} Grant Access + #obj_actions.button-group + Return to + = link_to "#{@permission_object.name} #{@permission_object.class}", polymorphic_path(@permission_object, :details_tab => :permissions, :only_tab => true), :class => 'button primary', :id => 'new_pool_button' + .corner + +%section.content-section.pools + Choose roles for users you would like to grant access to this #{@permission_object.class} + %header + %h2 Users + + .content + = render :partial => 'form' diff --git a/src/app/views/permissions/_permissions.haml b/src/app/views/permissions/_permissions.haml new file mode 100644 index 0000000..cf0cf4f --- /dev/null +++ b/src/app/views/permissions/_permissions.haml @@ -0,0 +1,24 @@ +- content_for :form_header do + - if check_privilege(Privilege::PERM_SET) + %li + = link_to "Grant Access", new_permission_path(:permission_object_type => @permission_object.class.name, :permission_object_id => @permission_object.id), { :class => 'button primary', :id => 'new_permission_button'} + = restful_submit_tag "Revoke Access", "destroy", multi_destroy_permissions_path, 'DELETE', :id => 'delete_button', :class => 'button danger' + = restful_submit_tag "Edit", "multi_update", multi_update_permissions_path, 'POST', :id => 'edit_button', :class => 'hidden' + .corner + = hidden_field_tag :permission_object_type, @permission_object.class.name + = hidden_field_tag :permission_object_id, @permission_object.id + += filter_table(@permission_list_header, @permission_object.permissions) do |permission| + %tr{:class => cycle('nostripe','stripe')} + %td + - if check_privilege(Privilege::PERM_SET) + - selected = params[:select] == 'all' + = check_box_tag "permission_selected[]", permission.id, selected, :id => "permission_checkbox_#{permission.id}" + %td= link_to "#{permission.user.first_name} #{permission.user.last_name}", user_path(permission.user) + - if check_privilege(Privilege::PERM_SET) + %td= select_tag "permission_role_selected[]", options_for_select(@roles.map {|r| [ r.name, "#{permission.id},#{r.id}" ] }, :selected => "#{permission.id},#{permission.role.id}", :disabled => @permission_object.permissions.where(["user_id = ? and role_id != ?", permission.user_id, permission.role_id]).collect {|p| "#{permission.id},#{p.role.id}"}), :id => "permission_role_selected_#{permission.id}" + :javascript + $("#permission_role_selected_#{permission.id}").change(function () { $("#edit_button").click(); } ); + + -else + %td= permission.role.name diff --git a/src/app/views/permissions/index.haml b/src/app/views/permissions/index.haml new file mode 100644 index 0000000..229236b --- /dev/null +++ b/src/app/views/permissions/index.haml @@ -0,0 +1 @@ += render :partial => 'permissions' diff --git a/src/app/views/permissions/new.haml b/src/app/views/permissions/new.haml index 25bae8e..b40557d 100644 --- a/src/app/views/permissions/new.haml +++ b/src/app/views/permissions/new.haml @@ -1,19 +1 @@ -.conductor_form - - if @permission.errors.any? - = render 'layouts/error_messages', :object => @permission - %h2 - Add new Permission for #{@permission_object.name} - %br/ - = form_tag :action => 'create' do - %ul - %li - %label - User - %span User to receive permission grant - = select("permission", "user_id", @users.collect {|u| [ u.login, u.id ] }, { :include_blank => true }) - %li - %label Role - = select("permission", "role_id", @roles.collect {|r| [ r.name, r.id ] }, { :include_blank => true }) - = hidden_field :permission, :permission_object_type - = hidden_field :permission, :permission_object_id - = submit_tag "Save", :class => "submit" += render :partial => 'new' diff --git a/src/app/views/pools/_permissions.haml b/src/app/views/pools/_permissions.haml index e44abc9..e73ced3 100644 --- a/src/app/views/pools/_permissions.haml +++ b/src/app/views/pools/_permissions.haml @@ -1,7 +1 @@ -%h3 - Permissions have not been implemented yet. - -:javascript - Conductor.setupPrettyFilterURL( - '#{url_for(:action => :show, :details_tab => 'permissions', :view => 'filter' )}', - '#{url_for(:action => :show, :details_tab => 'permissions', :view => 'pretty' )}'); \ No newline at end of file += render :partial => 'permissions/permissions' diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml index 6c87532..c475943 100644 --- a/src/config/locales/en.yml +++ b/src/config/locales/en.yml @@ -5,6 +5,7 @@ en: confirm_delete: "Are you sure you want to delete this user?" index: user_id: User ID + username: Username last_name: Last Name first_name: First Name quota_used: Quota Used @@ -34,6 +35,9 @@ en: define_profiles: Define Profiles define_locales: Define Locales permissions: Permissions + role: Role + user: User + privileges: Privileges general_settings: General Settings new_user: New User edit_user: Edit User diff --git a/src/config/routes.rb b/src/config/routes.rb index 78340bd..0482bc6 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -83,6 +83,8 @@ Conductor::Application.routes.draw do resources :permissions do collection do get :list + delete :multi_destroy + post :multi_update end end
diff --git a/src/features/permission.feature b/src/features/permission.feature index ee2d736..ae9a642 100644 --- a/src/features/permission.feature +++ b/src/features/permission.feature @@ -7,40 +7,50 @@ Feature: Manage Permissions Given I am an authorised user And I am logged in And a user "testuser" exists + And a pool "PermissionPool" exists
Scenario: Create a new Permission - Given I am on the permissions page + Given I am viewing the pool "PermissionPool" + When I follow link with ID "details_permissions" And there is not a permission for the user "testuser" - When I follow "Add a new permission record" + When I follow "Grant Access" Then I should be on the new permission page - And I should see "new Permission" - When I select "testuser" from "permission[user_id]" - And I select "Provider Creator" from "permission[role_id]" - And I press "Save" - Then I should be on the permissions page - And I should see "Permission record added" + And I should see "Choose roles for users" + When I select "Pool User" role for the user "testuser" + And I press "Grant Access" + Then I should be on the page for the pool "PermissionPool" + And I should see "These User Roles were added" And I should see "testuser"
Scenario: Create a second permission on a resource - Given there is a permission for the user "testuser" - And I am on the new permission page - When I select "testuser" from "permission[user_id]" - And I select "Provider Creator" from "permission[role_id]" - And I press "Save" - Then I should be on the permissions page - And I should see "Permission record added" + Given there is a permission for the user "testuser" on the pool "PermissionPool" + And I am viewing the pool "PermissionPool" + When I follow link with ID "details_permissions" + When I follow "Grant Access" + Then I should be on the new permission page + And I should see "Choose roles for users" + When I select "Pool Owner" role for the user "testuser" + And I press "Grant Access" + Then I should be on the page for the pool "PermissionPool" + And I should see "These User Roles were added" And I should see "testuser"
Scenario: Attempt to duplicate a permission - Given there is a permission for the user "testuser" - And I am on the new permission page - When I select "testuser" from "permission[user_id]" - And I select "Administrator" from "permission[role_id]" - And I press "Save" - Then I should see "new Permission" + Given there is a permission for the user "testuser" on the pool "PermissionPool" + And I am viewing the pool "PermissionPool" + When I follow link with ID "details_permissions" + When I follow "Grant Access" + Then I should be on the new permission page + And I should see "Choose roles for users" + When I select "Pool User" role for the user "testuser" + And I press "Grant Access" + Then I should be on the page for the pool "PermissionPool" + And I should see "Could not add these User Roles" + And I should see "testuser"
Scenario: Delete a permission - Given there is a permission for the user "testuser" - And I am on the permissions page + Given there is a permission for the user "testuser" on the pool "PermissionPool" + And I am viewing the pool "PermissionPool" + When I follow link with ID "details_permissions" When I delete the permission - Then I should be on the permissions page + Then I should be on the page for the pool "PermissionPool" diff --git a/src/features/step_definitions/permission_steps.rb b/src/features/step_definitions/permission_steps.rb index d2007f5..1f8ae6b 100644 --- a/src/features/step_definitions/permission_steps.rb +++ b/src/features/step_definitions/permission_steps.rb @@ -10,6 +10,17 @@ Given /^there is a permission for the user "([^"]*)"$/ do |login| @admin_permission = FactoryGirl.create(:admin_permission, :user_id => @user.id) end
+Given /^there is a permission for the user "([^"]*)" on the pool "([^"]*)"$/ do |login, pool_name| + @pool_user_permission = FactoryGirl.create(:pool_user_permission, :user_id => @user.id, + :permission_object => Pool.find_by_name(pool_name)) +end + Given /^I delete the permission$/ do - click_button "delete_#{@admin_permission.id}" + check "permission_checkbox_#{@pool_user_permission.id}" + click_button "delete_button" +end + +When /^(?:|I )select "([^"]*)" role for the user "([^"]*)"$/ do |role_name, user_name| + user = User.find_by_login(user_name) + select(role_name, :from => "user_role_selected_#{user.id}") end
On Mon, Oct 03, 2011 at 07:04:06PM -0400, Scott Seago wrote:
This patch only enables the UI to modify permissions on Pools. The vast majority of the code is non-type-specific though, so once this part is finalized it will be easy to expand it to other object types.
src/app/controllers/application_controller.rb | 10 + src/app/controllers/permissions_controller.rb | 184 ++++++++++++++++----- src/app/controllers/pools_controller.rb | 14 ++- src/app/helpers/application_helper.rb | 1 + src/app/stylesheets/custom.scss | 4 + src/app/views/layouts/_filter_table.haml | 4 + src/app/views/permissions/_form.haml | 16 ++ src/app/views/permissions/_new.haml | 14 ++ src/app/views/permissions/_permissions.haml | 24 +++ src/app/views/permissions/index.haml | 1 + src/app/views/permissions/new.haml | 20 +-- src/app/views/pools/_permissions.haml | 8 +- src/config/locales/en.yml | 4 + src/config/routes.rb | 2 + src/features/permission.feature | 58 ++++--- src/features/step_definitions/permission_steps.rb | 13 ++- 16 files changed, 285 insertions(+), 92 deletions(-) create mode 100644 src/app/views/permissions/_form.haml create mode 100644 src/app/views/permissions/_new.haml create mode 100644 src/app/views/permissions/_permissions.haml create mode 100644 src/app/views/permissions/index.haml
ACK.
-- Matt
aeolus-devel@lists.fedorahosted.org