diff --git a/app/controllers/admin/versions_controller.rb b/app/controllers/admin/versions_controller.rb index 07108d38..69f57bb9 100644 --- a/app/controllers/admin/versions_controller.rb +++ b/app/controllers/admin/versions_controller.rb @@ -1,17 +1,17 @@ module Admin class VersionsController < Admin::BaseController - skip_authorization_check + load_resource :conference, find_by: :short_title + load_and_authorize_resource class: PaperTrail::Version def index - authorize! :index, PaperTrail::Version.new(item_type: 'User') - conf_ids_for_organizer = current_user.is_admin? ? Conference.pluck(:id) : Conference.with_role(:organizer, current_user).pluck(:id) - @versions = PaperTrail::Version.where(["conference_id IN (?) OR item_type = 'User'", conf_ids_for_organizer]) + @conf_ids_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title) + + return unless @conference.present? + authorize! :index, PaperTrail::Version.new(conference_id: @conference.id) + @versions = @versions.where(conference_id: @conference.id) end def revert_attribute - @version = PaperTrail::Version.find(params[:id]) - authorize! :revert_attribute, @version - if params[:attribute] && @version.changeset.reject{ |_, values| values[0].blank? && values[1].blank? }.keys.include?(params[:attribute]) if @version.item[params[:attribute]] == @version.changeset[params[:attribute]][0] flash[:error] = 'The item is already in the state that you are trying to revert it back to' @@ -33,9 +33,6 @@ module Admin end def revert_object - @version = PaperTrail::Version.find(params[:id]) - authorize! :revert_object, @version - if @version.event != 'create' if @version.reify.save flash[:notice] = 'The selected change was successfully reverted' diff --git a/app/models/ability.rb b/app/models/ability.rb index 760f43fe..773195f2 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -178,9 +178,8 @@ class Ability role.resource_type == 'Conference' && (conf_ids_for_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) - end + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'User' + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, conference_id: conf_ids_for_organizer end def signed_in_with_cfp_role(user) @@ -212,8 +211,10 @@ class Ability (Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id) end - can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Event', conference_id: conf_ids_for_cfp - can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, + item_type: %w(Event EventType Track DifficultyLevel EmailSettings Room Cfp Program Comment), conference_id: conf_ids_for_cfp + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, + ["item_type = 'Commercial' AND conference_id IN (?) AND (object LIKE '%Event%' OR object_changes LIKE '%Event%')", conf_ids_for_cfp] do |version| version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) && (version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event')) end @@ -238,6 +239,8 @@ class Ability role.resource_type == 'Conference' && role.name == 'info_desk' && (Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id) end + + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Registration', conference_id: conf_ids_for_info_desk end def signed_in_with_volunteers_coordinator_role(user) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 44eedf82..ef448dad 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -1,18 +1,24 @@ +- conference = Conference.find_by(id: version.conference_id) +- conference_short_title = conference.try(:short_title) || 'deleted_conference' +- conference_title = conference.try(:title) || 'Deleted Conference' + - case version.item_type - when 'UsersRole' - users_role = current_or_last_object_state(version.item_type, version.item_id) - user = current_or_last_object_state('User', users_role.user_id) = 'role' - = link_to users_role.role.name, admin_conference_role_path(conference_id: Conference.find(version.conference_id).short_title, id: users_role.role.name) + = link_to users_role.role.name, admin_conference_role_path(conference_id: conference_short_title, id: users_role.role.name) = version.event == 'create' ? 'to' : 'from' = 'user' - - = link_to (user.try(:name) || 'deleted user'), admin_user_path(id: users_role.user.id) + = link_to_user(users_role.user_id) - when 'Subscription', 'Registration' - = 'conference' - = link_to Conference.find(version.conference_id).title, - admin_conference_registrations_path(conference_id: Conference.find(version.conference_id).short_title) + - if conference + = 'conference' + = link_to conference_title, + admin_conference_registrations_path(conference_id: conference_short_title) + - else + = "deleted conference with ID #{version.conference_id}" - when 'Commercial' - commercial = current_or_last_object_state(version.item_type, version.item_id) @@ -25,7 +31,7 @@ - if commercialable_last_version.item event = link_to commercialable.title, - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: commercialable.id) + admin_conference_program_event_path(conference_id: conference_short_title, id: commercialable.id) - else = commercialable.title @@ -33,134 +39,134 @@ commercial in venue - if commercialable_last_version.item = link_to commercialable.name, - edit_admin_conference_venue_path(conference_id: Conference.find(version.conference_id).short_title, + edit_admin_conference_venue_path(conference_id: conference_short_title, id: commercialable.id, anchor: 'commercials-content') - else = commercialable.name - when 'Conference' = link_to 'commercial', - admin_conference_commercials_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_commercials_path(conference_id: conference_short_title) - when 'EventsRegistration', 'Comment', 'Vote', 'Event' = 'event' - object = current_or_last_object_state(version.item_type, version.item_id) - event_id = object.try(:event_id) || object.try(:commentable_id) || object.id = link_to (current_or_last_object_state('Event', event_id).try(:title) || 'deleted event'), - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: event_id) + admin_conference_program_event_path(conference_id: conference_short_title, id: event_id) - when 'Target' = 'target' - target = current_or_last_object_state(version.item_type, version.item_id) - = link_if_alive version, target.to_s, admin_conference_targets_path(conference_id: Conference.find(version.conference_id).short_title) + = link_if_alive version, target.to_s, admin_conference_targets_path(conference_id: conference_short_title) - when 'EventSchedule' - event_schedule = current_or_last_object_state(version.item_type, version.item_id) event = link_to (current_or_last_object_state('Event', event_schedule.event_id).try(:title) || 'deleted event'), - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: event_schedule.event_id) + admin_conference_program_event_path(conference_id: conference_short_title, id: event_schedule.event_id) in = link_to "Schedule #{event_schedule.schedule_id}", - admin_conference_schedule_path(conference_id: Conference.find(version.conference_id).short_title, id: event_schedule.schedule_id) + admin_conference_schedule_path(conference_id: conference_short_title, id: event_schedule.schedule_id) - when 'Schedule' = link_if_alive version, "Schedule #{version.item_id}", - admin_conference_schedule_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_schedule_path(conference_id: conference_short_title, id: version.item_id) - when 'Conference' = 'conference' - = link_to Conference.find(version.conference_id).title, - edit_admin_conference_path(id: Conference.find(version.conference_id).short_title) + = link_to Conference.find(version.item_id).title, + edit_admin_conference_path(id: Conference.find(version.item_id).short_title) - when 'RegistrationPeriod' = link_if_alive version, 'registration period', - admin_conference_registration_period_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_registration_period_path(conference_id: conference_short_title) - when 'Contact' = link_if_alive version, 'contact details', - edit_admin_conference_contact_path(conference_id: Conference.find(version.conference_id).short_title) + edit_admin_conference_contact_path(conference_id: conference_short_title) - when 'Program' = link_if_alive version, 'program', - admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_program_path(conference_id: conference_short_title) - when 'Cfp' = link_if_alive version, 'cfp', - admin_conference_program_cfp_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_program_cfp_path(conference_id: conference_short_title) - when 'Track' = 'track' - track = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, track.name, - admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_track_path(conference_id: conference_short_title, id: version.item_id) - when 'EventType' = 'event type' - event_type = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, event_type.title, - admin_conference_program_event_types_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_program_event_types_path(conference_id: conference_short_title) - when 'Role' = 'role' - role = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, role.name, - admin_conference_role_path(conference_id: Conference.find(version.conference_id).short_title, id: role.name) + admin_conference_role_path(conference_id: conference_short_title, id: role.name) - when 'Venue' = 'venue' - venue = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, venue.name, - admin_conference_venue_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_venue_path(conference_id: conference_short_title) - when 'Lodging' = 'lodging' - lodging = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, lodging.name, - admin_conference_lodgings_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_lodgings_path(conference_id: conference_short_title) - when 'Room' = 'room' - room = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, room.name, - admin_conference_venue_rooms_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_venue_rooms_path(conference_id: conference_short_title) - when 'Sponsor' = 'sponsor' - sponsor = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsor.name, - admin_conference_sponsors_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_sponsors_path(conference_id: conference_short_title) - when 'SponsorshipLevel' = 'sponsorship level' - sponsorship_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsorship_level.title, - admin_conference_sponsorship_levels_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_sponsorship_levels_path(conference_id: conference_short_title) - when 'Ticket' = 'ticket' - ticket = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, ticket.title, - admin_conference_ticket_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_ticket_path(conference_id: conference_short_title, id: version.item_id) - when 'Campaign' = 'campaign' - campaign = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, campaign.name, - admin_conference_campaigns_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_campaigns_path(conference_id: conference_short_title) - when 'DifficultyLevel' = 'difficulty level' - difficulty_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, difficulty_level.title, - admin_conference_program_difficulty_level_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_difficulty_level_path(conference_id: conference_short_title, id: version.item_id) - when 'Splashpage' = link_if_alive version, 'splashpage', - admin_conference_splashpage_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_splashpage_path(conference_id: conference_short_title) - when 'EmailSettings' = link_if_alive version, 'email settings', - admin_conference_emails_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_emails_path(conference_id: conference_short_title) - when 'User' - if version.event == 'update' @@ -168,6 +174,9 @@ = link_to (current_or_last_object_state('User', version.item_id).try(:name) || 'deleted user'), admin_user_path(id: version.item_id) - unless %w(Conference Subscription Registration User).include?(version.item_type) - = "in conference" - = link_to Conference.find(version.conference_id).short_title, - edit_admin_conference_path(id: Conference.find(version.conference_id).short_title) + - if conference + = "in conference" + = link_to conference_short_title, + edit_admin_conference_path(id: conference_short_title) + - else + = "in deleted conference with ID #{version.conference_id}" diff --git a/app/views/admin/versions/index.html.haml b/app/views/admin/versions/index.html.haml index 69af134b..860419af 100644 --- a/app/views/admin/versions/index.html.haml +++ b/app/views/admin/versions/index.html.haml @@ -1,6 +1,16 @@ .row .col-md-12 .page-header + + .dropdown.pull-right + %button.btn.btn-success.dropdown-toggle{'data-toggle' => 'dropdown', type: 'button'} + = @conference.nil? ? 'All Conferences & Users' : @conference.short_title + %span.caret + %ul.dropdown-menu + %li= link_to 'All Conferences & Users', admin_revision_history_path + - @conf_ids_with_role.each do |conference_short_title| + %li= link_to conference_short_title, admin_conference_revision_history_path(conference_id: conference_short_title) + %h1 Revision History %p.text-muted Log of changes made to conferences and associated resources diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index b1e4730c..cd90bbf1 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -139,3 +139,8 @@ = link_to(admin_conference_roles_path(@conference.short_title)) do %span.fa.fa-group Roles + - if can?(:index, PaperTrail::Version.new(conference_id: @conference.id, item_type: 'Event')) || can?(:index, PaperTrail::Version.new(conference_id: @conference.id, item_type: 'Registration')) + %li{:class=> active_nav_li(admin_conference_revision_history_path(@conference.short_title))} + = link_to(admin_conference_revision_history_path(@conference.short_title)) do + %span.fa.fa-history + Revision History diff --git a/app/views/layouts/_admin_sidebar_index.html.haml b/app/views/layouts/_admin_sidebar_index.html.haml index 4ae56dce..30ad5dcb 100644 --- a/app/views/layouts/_admin_sidebar_index.html.haml +++ b/app/views/layouts/_admin_sidebar_index.html.haml @@ -27,7 +27,7 @@ = link_to(admin_users_path) do %span.fa.fa-user Users - - if can? :index, PaperTrail::Version.new(item_type: 'User') + - if can? :index, PaperTrail::Version %li = link_to(admin_revision_history_path) do %span.fa.fa-history diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 95c7937e..50aa14d3 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -44,7 +44,7 @@ = link_to(admin_users_path) do %span.fa.fa-user Users -- if can? :index, PaperTrail::Version.new(item_type: 'User') +- if can? :index, PaperTrail::Version %li = link_to(admin_revision_history_path) do %span.fa.fa-history diff --git a/config/routes.rb b/config/routes.rb index 2a44f93a..b94a697d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -96,6 +96,8 @@ Osem::Application.routes.draw do patch :update_conference end end + + get '/revision_history' => 'versions#index' end get '/revision_history' => 'versions#index' diff --git a/spec/controllers/admin/versions_controller_spec.rb b/spec/controllers/admin/versions_controller_spec.rb index 4694837d..f1400e3b 100644 --- a/spec/controllers/admin/versions_controller_spec.rb +++ b/spec/controllers/admin/versions_controller_spec.rb @@ -97,5 +97,14 @@ describe Admin::VersionsController do expect(flash[:error]).to match('Revert failed. Attribute missing or invalid') end end + + describe 'GET #index' do + it 'raises error if user is not an organizer of specified conference' do + user = create(:user) + sign_in user + get :index, conference_id: conference.short_title + expect(flash[:alert]).to match('You are not authorized to access this area.') + end + end end end diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index 2bcd8331..d5462db6 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -56,6 +56,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference1.short_title}/program/difficulty_levels") expect(page).to have_link('Questions', href: "/admin/conferences/#{conference1.short_title}/questions") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference1.short_title}/roles") + expect(page).to have_link('Revision History', href: "/admin/conferences/#{conference1.short_title}/revision_history") visit edit_admin_conference_path(conference1.short_title) expect(current_path).to eq(edit_admin_conference_path(conference1.short_title)) @@ -137,6 +138,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference2.short_title}/program/difficulty_levels") expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference2.short_title}/questions") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference2.short_title}/roles") + expect(page).to have_link('Revision History', href: "/admin/conferences/#{conference2.short_title}/revision_history") visit edit_admin_conference_path(conference2.short_title) expect(current_path).to eq(root_path) @@ -181,7 +183,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(root_path) visit admin_revision_history_path - expect(current_path).to eq(root_path) + expect(current_path).to eq(admin_revision_history_path) end scenario 'when user is info desk' do @@ -214,6 +216,7 @@ feature 'Has correct abilities' do expect(page).to_not have_link('Difficulty levels', href: "/admin/conferences/#{conference3.short_title}/program/difficulty_levels") expect(page).to have_link('Questions', href: "/admin/conferences/#{conference3.short_title}/questions") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference3.short_title}/roles") + expect(page).to have_link('Revision History', href: "/admin/conferences/#{conference3.short_title}/revision_history") visit edit_admin_conference_path(conference3.short_title) expect(current_path).to eq(root_path) @@ -258,6 +261,6 @@ feature 'Has correct abilities' do expect(current_path).to eq(root_path) visit admin_revision_history_path - expect(current_path).to eq(root_path) + expect(current_path).to eq(admin_revision_history_path) end end