diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 638d2ab6..5c71ffdc 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -8,7 +8,7 @@ module Admin return false end unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) || - (current_user.has_role? :info_desk, :any) || + (current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) || (current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin raise CanCan::AccessDenied.new('You are not authorized to access this area!') end diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb index 087bf7f8..9d0dc78b 100644 --- a/app/controllers/admin/organizations_controller.rb +++ b/app/controllers/admin/organizations_controller.rb @@ -1,6 +1,7 @@ module Admin class OrganizationsController < Admin::BaseController load_and_authorize_resource :organization + after_action :assign_role, only: :create def index @organizations = Organization.all @@ -45,6 +46,10 @@ module Admin private + def assign_role + current_user.add_role :organization_admin, @organization + end + def organization_params params.require(:organization).permit(:name, :description, :picture) end diff --git a/app/models/ability.rb b/app/models/ability.rb index 6fa8c12f..7d1cf868 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -110,6 +110,7 @@ class Ability # Abilities from not_signed_in and signed_in are also inherited signed_in(user) + signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any signed_in_with_organizer_role(user) if user.has_role? :organizer, :any signed_in_with_cfp_role(user) if user.has_role? :cfp, :any signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any @@ -146,57 +147,73 @@ class Ability end end - def signed_in_with_organizer_role(user) - # ids of all the conferences for which the user has the 'organizer' role - conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id) + def signed_in_with_organization_admin_role(user) + org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) - can :manage, Resource, conference_id: conf_ids_for_organizer - can [:new, :create], Conference if user.has_role?(:organizer, :any) - can :manage, Conference, id: conf_ids_for_organizer - can :manage, Splashpage, conference_id: conf_ids_for_organizer - can :manage, Contact, conference_id: conf_ids_for_organizer - can :manage, EmailSettings, conference_id: conf_ids_for_organizer - can :manage, Campaign, conference_id: conf_ids_for_organizer - can :manage, Target, conference_id: conf_ids_for_organizer - can :manage, Commercial, commercialable_type: 'Conference', - commercialable_id: conf_ids_for_organizer - can :manage, Registration, conference_id: conf_ids_for_organizer - can :manage, RegistrationPeriod, conference_id: conf_ids_for_organizer - can :manage, Question, conference_id: conf_ids_for_organizer - can :manage, Question do |question| - !(question.conferences.pluck(:id) & conf_ids_for_organizer).empty? + can :manage, Organization, id: org_ids_for_organization_admin + can :manage, Conference, organization_id: org_ids_for_organization_admin + conf_ids_for_organization_admin = [] + org_ids_for_organization_admin.each do |org_id| + conf_ids_for_organization_admin += Organization.find(org_id).conferences.pluck(:id) end - can :manage, Vposition, conference_id: conf_ids_for_organizer - can :manage, Vday, conference_id: conf_ids_for_organizer - can :manage, Program, conference_id: conf_ids_for_organizer - can :manage, Schedule, program: { conference_id: conf_ids_for_organizer } - can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organizer } } - can :manage, Cfp, program: { conference_id: conf_ids_for_organizer } - can :manage, Event, program: { conference_id: conf_ids_for_organizer} - can :manage, EventType, program: { conference_id: conf_ids_for_organizer} - can :manage, Track, program: { conference_id: conf_ids_for_organizer} - can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organizer} + can [:index, :show], Role + can [:edit, :update], Role do |role| + role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) + end + signed_in_with_organizer_role(user, conf_ids_for_organization_admin) + end + + def signed_in_with_organizer_role(user, conf_ids_for_organization_admin = []) + # ids of all the conferences for which the user has the 'organizer' role and + # conferences that belong to organizations for which user is 'organization_admin' + conf_ids_for_organization_admin_and_organizer = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq + can :manage, Resource, conference_id: conf_ids_for_organization_admin_and_organizer + can [:new, :create], Conference if user.has_role?(:organizer, :any) + can :manage, Conference, id: conf_ids_for_organization_admin_and_organizer + can :manage, Splashpage, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Contact, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, EmailSettings, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Campaign, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Target, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Commercial, commercialable_type: 'Conference', + commercialable_id: conf_ids_for_organization_admin_and_organizer + can :manage, Registration, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, RegistrationPeriod, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Question, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Question do |question| + !(question.conferences.pluck(:id) & conf_ids_for_organization_admin_and_organizer).empty? + end + can :manage, Vposition, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Vday, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Program, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Schedule, program: { conference_id: conf_ids_for_organization_admin_and_organizer } + can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organization_admin_and_organizer } } + can :manage, Cfp, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Event, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, EventType, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Track, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organization_admin_and_organizer} can :manage, Commercial, commercialable_type: 'Event', - commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) - can :manage, Venue, conference_id: conf_ids_for_organizer + commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) + can :manage, Venue, conference_id: conf_ids_for_organization_admin_and_organizer can :manage, Commercial, commercialable_type: 'Venue', - commercialable_id: Venue.where(conference_id: conf_ids_for_organizer).pluck(:id) - can :manage, Lodging, conference_id: conf_ids_for_organizer - can :manage, Room, venue: { conference_id: conf_ids_for_organizer} - can :manage, Sponsor, conference_id: conf_ids_for_organizer - can :manage, SponsorshipLevel, conference_id: conf_ids_for_organizer - can :manage, Ticket, conference_id: conf_ids_for_organizer + commercialable_id: Venue.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id) + can :manage, Lodging, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Room, venue: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Sponsor, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, SponsorshipLevel, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Ticket, conference_id: conf_ids_for_organization_admin_and_organizer can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) # Abilities for Role (Conference resource) can [:index, :show], Role can [:edit, :update, :toggle_user], Role do |role| - role.resource_type == 'Conference' && (conf_ids_for_organizer.include? role.resource_id) + role.resource_type == 'Conference' && (conf_ids_for_organization_admin_and_organizer.include? role.resource_id) end can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'User' || (conf_ids_for_organizer.include? version.conference_id) + version.item_type == 'User' || (conf_ids_for_organization_admin_and_organizer.include? version.conference_id) end end diff --git a/app/models/organization.rb b/app/models/organization.rb index 60a83fef..0fdbe5f9 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -1,7 +1,17 @@ class Organization < ActiveRecord::Base + resourcify :roles, dependent: :delete_all + has_many :conferences, dependent: :destroy + after_create :create_roles + validates :name, presence: true mount_uploader :picture, PictureUploader, mount_on: :picture + + private + + def create_roles + Role.where(name: 'organization_admin', resource: self).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + end end diff --git a/lib/tasks/roles.rake b/lib/tasks/roles.rake index 8c817db0..227f9642 100644 --- a/lib/tasks/roles.rake +++ b/lib/tasks/roles.rake @@ -2,6 +2,10 @@ namespace :roles do desc 'Adds back deleted roles to all conferences' task add: :environment do + Organization.all.each do |org| + Role.where(name: 'organization_admin', resource: org).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + end + Conference.all.each do |c| Role.where(name: 'organizer', resource: c).first_or_create(description: 'For the organizers of the conference (who shall have full access)') Role.where(name: 'cfp', resource: c).first_or_create(description: 'For the members of the CfP team') diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 001c7365..980cc194 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -9,7 +9,8 @@ describe 'User' do subject(:ability){ Ability.new(user) } let(:user){ nil } - let!(:my_conference) { create(:full_conference) } + let!(:organization) { create(:organization) } + let!(:my_conference) { create(:full_conference, organization: organization) } let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } let(:my_registration) { create(:registration, conference: my_conference, user: admin) } @@ -44,6 +45,7 @@ describe 'User' do let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } # Test abilities for not signed in users context 'when user is not signed in' do + it{ should be_able_to(:index, Organization)} it{ should be_able_to(:index, Conference)} it{ should be_able_to(:show, conference_public)} @@ -138,9 +140,14 @@ describe 'User' do shared_examples 'user with any role' do before do + @other_organization = create(:organization) @other_conference = create(:conference) end + it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + %w(organizer cfp info_desk volunteers_coordinator).each do |role| it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: @other_conference)) } it{ should_not be_able_to(:update, Role.find_by(name: role, resource: @other_conference)) } @@ -164,6 +171,18 @@ describe 'User' do end end + context 'when user has the role organization_admin' do + let(:role) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:user) { create(:user, role_ids: [role.id]) } + let(:other_conference) { create(:conference) } + + it{ should_not be_able_to(:manage, other_conference) } + it{ should be_able_to(:manage, my_conference) } + it{ should be_able_to(:manage, organization) } + + it_behaves_like 'user with any role' + end + context 'when user has the role organizer' do let(:role) { Role.find_by(name: 'organizer', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) }