From 523291442766e7cd4adbad6d2bc7c6803cdd3811 Mon Sep 17 00:00:00 2001 From: Chris Flipse Date: Sat, 9 Jun 2018 16:35:17 -0400 Subject: [PATCH] Implement the cancan filters for diary entries Access logic is not _entirely_ exported from the controller, unfortunately. For interface reasons, some actions which require admin have to be listed within the controller's deny_access method. This is required because, being a default-deny system, cancancan _cannot_ tell you the reason you were denied access; and so the "nice" feedback presenting next steps can't be gleaned from the exception --- app/controllers/diary_entry_controller.rb | 31 ++++++++++++------- app/models/ability.rb | 8 +++++ test/models/abilities_test.rb | 36 +++++++++++++++++++++++ 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/app/controllers/diary_entry_controller.rb b/app/controllers/diary_entry_controller.rb index f2c11fc74..ff8758990 100644 --- a/app/controllers/diary_entry_controller.rb +++ b/app/controllers/diary_entry_controller.rb @@ -3,13 +3,15 @@ class DiaryEntryController < ApplicationController before_action :authorize_web before_action :set_locale - before_action :require_user, :only => [:new, :edit, :comment, :hide, :hidecomment, :subscribe, :unsubscribe] + + authorize_resource + before_action :lookup_user, :only => [:view, :comments] before_action :check_database_readable before_action :check_database_writable, :only => [:new, :edit, :comment, :hide, :hidecomment, :subscribe, :unsubscribe] - before_action :require_administrator, :only => [:hide, :hidecomment] before_action :allow_thirdparty_images, :only => [:new, :edit, :list, :view, :comments] + def new @title = t "diary_entry.new.title" @@ -215,6 +217,22 @@ class DiaryEntryController < ApplicationController private + # This is required because, being a default-deny system, cancancan + # _cannot_ tell you the reason you were denied access; and so + # the "nice" feedback presenting next steps can't be gleaned from + # the exception + ## + # for the hide actions, require that the user is a administrator, or fill out + # a helpful error message and return them to the user page. + def deny_access(exception) + if current_user && exception.action.in?([:hide, :hidecomment]) + flash[:error] = t("user.filter.not_an_administrator") + redirect_to :action => "view" + else + super + end + end + ## # return permitted diary entry parameters def entry_params @@ -229,15 +247,6 @@ class DiaryEntryController < ApplicationController params.require(:diary_comment).permit(:body) end - ## - # require that the user is a administrator, or fill out a helpful error message - # and return them to the user page. - def require_administrator - unless current_user.administrator? - flash[:error] = t("user.filter.not_an_administrator") - redirect_to :action => "view" - end - end ## # decide on a location for the diary entry map diff --git a/app/models/ability.rb b/app/models/ability.rb index 897316691..59b1c5ec3 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -7,8 +7,16 @@ class Ability can :index, :site can [:permalink, :edit, :help, :fixthemap, :offline, :export, :about, :preview, :copyright, :key, :id, :welcome], :site + can [:list, :rss, :view, :comments], DiaryEntry + if user can :weclome, :site + + can [:create, :edit, :comment, :subscribe, :unsubscribe], DiaryEntry + + if user.administrator? + can [:hide, :hidecomment], [DiaryEntry, DiaryComment] + end end # Define abilities for the passed in user here. For example: # diff --git a/test/models/abilities_test.rb b/test/models/abilities_test.rb index ab8458531..6472ad2e3 100644 --- a/test/models/abilities_test.rb +++ b/test/models/abilities_test.rb @@ -4,4 +4,40 @@ require "test_helper" class AbilityTest < ActiveSupport::TestCase + test "diary permissions for a guest" do + ability = Ability.new(nil, []) + [:list, :rss, :view, :comments].each do |action| + assert ability.can?(action, DiaryEntry), "should be able to #{action} DiaryEntries" + end + + [:create, :edit, :comment, :subscribe, :unsubscribe, :hide, :hidecomment].each do |action| + assert ability.cannot?(action, DiaryEntry), "should be able to #{action} DiaryEntries" + assert ability.cannot?(action, DiaryComment), "should be able to #{action} DiaryEntries" + end + end + + + test "Diary permissions for a normal user" do + ability = Ability.new(create(:user), []) + + [:list, :rss, :view, :comments, :create, :edit, :comment, :subscribe, :unsubscribe].each do |action| + assert ability.can?(action, DiaryEntry), "should be able to #{action} DiaryEntries" + end + + [:hide, :hidecomment].each do |action| + assert ability.cannot?(action, DiaryEntry), "should be able to #{action} DiaryEntries" + assert ability.cannot?(action, DiaryComment), "should be able to #{action} DiaryEntries" + end + end + + test "Diary for an administrator" do + ability = Ability.new(create(:administrator_user), []) + [:list, :rss, :view, :comments, :create, :edit, :comment, :subscribe, :unsubscribe, :hide, :hidecomment].each do |action| + assert ability.can?(action, DiaryEntry), "should be able to #{action} DiaryEntries" + end + + [:hide, :hidecomment].each do |action| + assert ability.can?(action, DiaryComment), "should be able to #{action} DiaryComment" + end + end end -- 2.43.2