diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e42d54886..bcd8aa87e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -419,7 +419,7 @@ def role_toggle # Set/update ability if new_value - @user.community_user.grant_privilege 'mod' + @user.community_user.grant_privilege! 'mod' else @user.community_user.privilege('mod').destroy end @@ -448,7 +448,7 @@ def mod_privilege_action case params[:do] when 'grant' if ua.nil? - @user.community_user.grant_privilege(ability.internal_id) + @user.community_user.grant_privilege!(ability.internal_id) AuditLog.admin_audit(event_type: 'ability_grant', related: @user, user: current_user, comment: ability.internal_id.to_s) elsif ua.is_suspended diff --git a/app/models/community_user.rb b/app/models/community_user.rb index b1390fcf8..e81d1f579 100644 --- a/app/models/community_user.rb +++ b/app/models/community_user.rb @@ -14,6 +14,8 @@ class CommunityUser < ApplicationRecord after_create :prevent_ulysses_case + delegate :url_helpers, to: 'Rails.application.routes' + def system? user_id == -1 end @@ -58,8 +60,6 @@ def flag_score end end - ## Privilege functions - def privilege?(internal_id, ignore_suspension: false, ignore_mod: false) if internal_id != 'mod' && !ignore_mod && user.is_moderator return true # includes: privilege? 'mod' @@ -77,11 +77,26 @@ def privilege(internal_id) UserAbility.joins(:ability).where(community_user_id: id, abilities: { internal_id: internal_id }).first end - def grant_privilege(internal_id) + ## + # Grant a specified ability to this CommunityUser. + # @param internal_id [String] The +internal_id+ of the ability to grant. + # @param notify [Boolean] Whether to send a notification to the user. + def grant_privilege!(internal_id, notify: true) priv = Ability.where(internal_id: internal_id).first UserAbility.create community_user_id: id, ability: priv + if notify + community_host = priv.community.host + user.create_notification("You've earned the #{priv.name} ability! Learn more.", + url_helpers.ability_url(priv.internal_id, host: community_host)) + end end + ## + # Recalculate a specified ability for this CommunityUser. Will not revoke abilities that have already been granted. + # @param internal_id [String] The +internal_id+ of the ability to be recalculated. + # @param sandbox [Boolean] Whether to run in sandbox mode - if sandboxed, the ability will not be granted but the + # return value indicates whether it would have been. + # @return [Boolean] Whether or not the ability was granted. def recalc_privilege(internal_id, sandbox: false) # Do not recalculate privileges already granted return true if privilege?(internal_id, ignore_suspension: true, ignore_mod: false) @@ -100,17 +115,27 @@ def recalc_privilege(internal_id, sandbox: false) end # If not sandbox mode, create new privilege entry - grant_privilege(internal_id) unless sandbox + grant_privilege!(internal_id) unless sandbox recalc_trust_level unless sandbox true end + ## + # Recalculate a list of standard abilities for this CommunityUser. + # @param sandbox [Boolean] Whether to run in sandbox mode - see {#recalc_privilege}. + # @return [Array] def recalc_privileges(sandbox: false) [:everyone, :unrestricted, :edit_posts, :edit_tags, :flag_close, :flag_curate].map do |ability| recalc_privilege(ability, sandbox: sandbox) end end + alias ability? privilege? + alias ability privilege + alias grant_ability! grant_privilege! + alias recalc_ability recalc_privilege + alias recalc_abilities recalc_privileges + # This check makes sure that every user gets the # 'everyone' permission upon creation. We do not want # to create a no permissions user by accident. diff --git a/db/migrate/20200813132829_enforce_concurrence_of_is_moderator_and_mod_ability.rb b/db/migrate/20200813132829_enforce_concurrence_of_is_moderator_and_mod_ability.rb index d84fdcc33..606f724a9 100644 --- a/db/migrate/20200813132829_enforce_concurrence_of_is_moderator_and_mod_ability.rb +++ b/db/migrate/20200813132829_enforce_concurrence_of_is_moderator_and_mod_ability.rb @@ -2,7 +2,7 @@ class EnforceConcurrenceOfIsModeratorAndModAbility < ActiveRecord::Migration[5.2 def up CommunityUser.unscoped.where(is_moderator: true).all.map do |cu| RequestContext.community = cu.community - cu.grant_privilege 'mod' + cu.grant_privilege! 'mod' end end diff --git a/scripts/recalc_abilities.rb b/scripts/recalc_abilities.rb index eeda78688..17c99d4fd 100644 --- a/scripts/recalc_abilities.rb +++ b/scripts/recalc_abilities.rb @@ -36,11 +36,11 @@ puts "Scope: CommunityUser : #{cu.id}" end - cu.recalc_privileges + cu.recalc_abilities # Grant mod ability if mod status is given - if (cu.is_moderator || cu.is_admin || u.is_global_moderator || u.is_global_admin) && !cu.privilege?('mod') - cu.grant_privilege('mod') + if (cu.is_moderator || cu.is_admin || u.is_global_moderator || u.is_global_admin) && !cu.ability?('mod') + cu.grant_ability!('mod') end resolved << q.id diff --git a/scripts/recalc_abilities_upon_first_migration.rb b/scripts/recalc_abilities_upon_first_migration.rb index 520144e65..32b3c48e4 100644 --- a/scripts/recalc_abilities_upon_first_migration.rb +++ b/scripts/recalc_abilities_upon_first_migration.rb @@ -9,7 +9,7 @@ cu.recalc_privileges if (cu.is_moderator || cu.is_admin || u.is_global_moderator || u.is_global_admin) && !cu.privilege?('mod') - cu.grant_privilege('mod') + cu.grant_privilege!('mod') end rescue puts " !!! Error recalcing for CommunityUser.Id=#{cu.id}" diff --git a/test/models/user_test.rb b/test/models/user_test.rb index e7ffe7800..9d8cfd64b 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -46,7 +46,7 @@ class UserTest < ActiveSupport::TestCase assert_equal true, users(:moderator).can_update(post, post_type) assert_equal true, users(:editor).can_update(post, post_type) - basic_user.community_user.grant_privilege('unrestricted') + basic_user.community_user.grant_privilege!('unrestricted') assert_equal false, basic_user.can_update(post, post_type) assert_equal true, basic_user.can_update(post, post_types(:free_edit)) end