2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-02-03 11:44:40 +08:00
|
|
|
require "guardian/bookmark_guardian"
|
2019-10-02 12:01:53 +08:00
|
|
|
require "guardian/category_guardian"
|
|
|
|
require "guardian/ensure_magic"
|
2023-02-03 11:44:40 +08:00
|
|
|
require "guardian/group_guardian"
|
2019-10-02 12:01:53 +08:00
|
|
|
require "guardian/post_guardian"
|
|
|
|
require "guardian/post_revision_guardian"
|
2023-02-03 11:44:40 +08:00
|
|
|
require "guardian/sidebar_guardian"
|
2019-10-02 12:01:53 +08:00
|
|
|
require "guardian/tag_guardian"
|
2023-02-03 11:44:40 +08:00
|
|
|
require "guardian/topic_guardian"
|
|
|
|
require "guardian/user_guardian"
|
2014-02-14 00:42:35 +08:00
|
|
|
|
2013-02-07 03:46:45 +08:00
|
|
|
# The guardian is responsible for confirming access to various site resources and operations
|
2013-02-06 03:16:51 +08:00
|
|
|
class Guardian
|
2023-02-03 11:44:40 +08:00
|
|
|
include BookmarkGuardian
|
2014-01-10 07:25:14 +08:00
|
|
|
include CategoryGuardian
|
2023-02-03 11:44:40 +08:00
|
|
|
include EnsureMagic
|
|
|
|
include GroupGuardian
|
2014-05-12 22:30:10 +08:00
|
|
|
include PostGuardian
|
2014-10-28 05:06:43 +08:00
|
|
|
include PostRevisionGuardian
|
2023-02-03 11:44:40 +08:00
|
|
|
include SidebarGuardian
|
2016-06-07 02:18:15 +08:00
|
|
|
include TagGuardian
|
2023-02-03 11:44:40 +08:00
|
|
|
include TopicGuardian
|
|
|
|
include UserGuardian
|
2014-02-05 03:05:50 +08:00
|
|
|
|
2013-05-20 14:04:53 +08:00
|
|
|
class AnonymousUser
|
2018-12-04 11:48:13 +08:00
|
|
|
def blank?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
def admin?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
def staff?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
def moderator?
|
|
|
|
false
|
|
|
|
end
|
2019-04-17 16:05:02 +08:00
|
|
|
def anonymous?
|
|
|
|
true
|
|
|
|
end
|
2018-12-04 11:48:13 +08:00
|
|
|
def approved?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
def staged?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
def silenced?
|
|
|
|
false
|
|
|
|
end
|
2022-03-22 08:23:14 +08:00
|
|
|
def is_system_user?
|
|
|
|
false
|
|
|
|
end
|
2022-10-05 08:50:20 +08:00
|
|
|
def bot?
|
|
|
|
false
|
|
|
|
end
|
2018-12-04 11:48:13 +08:00
|
|
|
def secure_category_ids
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
def topic_create_allowed_category_ids
|
|
|
|
[]
|
|
|
|
end
|
2022-06-30 08:18:12 +08:00
|
|
|
def groups
|
|
|
|
[]
|
|
|
|
end
|
2018-12-04 11:48:13 +08:00
|
|
|
def has_trust_level?(level)
|
|
|
|
false
|
|
|
|
end
|
2021-11-23 02:18:53 +08:00
|
|
|
def has_trust_level_or_staff?(level)
|
|
|
|
false
|
|
|
|
end
|
2018-12-04 11:48:13 +08:00
|
|
|
def email
|
|
|
|
nil
|
|
|
|
end
|
2022-06-30 08:18:12 +08:00
|
|
|
def whisperer?
|
|
|
|
false
|
|
|
|
end
|
2022-09-26 11:58:40 +08:00
|
|
|
def in_any_groups?(group_ids)
|
|
|
|
false
|
|
|
|
end
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
2014-05-12 22:30:10 +08:00
|
|
|
|
2018-10-09 22:21:41 +08:00
|
|
|
attr_reader :request
|
2014-11-03 19:46:08 +08:00
|
|
|
|
2018-10-09 22:21:41 +08:00
|
|
|
def initialize(user = nil, request = nil)
|
2013-05-20 14:04:53 +08:00
|
|
|
@user = user.presence || AnonymousUser.new
|
2018-10-09 22:21:41 +08:00
|
|
|
@request = request
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def user
|
|
|
|
@user.presence
|
|
|
|
end
|
|
|
|
alias current_user user
|
|
|
|
|
|
|
|
def anonymous?
|
|
|
|
!authenticated?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-05-20 14:04:53 +08:00
|
|
|
def authenticated?
|
|
|
|
@user.present?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def is_admin?
|
2013-05-20 14:04:53 +08:00
|
|
|
@user.admin?
|
2013-04-29 14:33:24 +08:00
|
|
|
end
|
|
|
|
|
2013-05-02 15:22:27 +08:00
|
|
|
def is_staff?
|
2013-05-20 14:04:53 +08:00
|
|
|
@user.staff?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-02-07 11:24:19 +08:00
|
|
|
def is_moderator?
|
|
|
|
@user.moderator?
|
|
|
|
end
|
|
|
|
|
2022-06-30 08:18:12 +08:00
|
|
|
def is_whisperer?
|
|
|
|
@user.whisperer?
|
|
|
|
end
|
|
|
|
|
2020-07-29 05:15:04 +08:00
|
|
|
def is_category_group_moderator?(category)
|
2022-08-04 08:07:12 +08:00
|
|
|
return false if !category
|
2022-10-27 06:13:21 +08:00
|
|
|
return false if !category_group_moderation_allowed?
|
2022-08-04 08:07:12 +08:00
|
|
|
|
|
|
|
reviewable_by_group_id = category.reviewable_by_group_id
|
|
|
|
return false if reviewable_by_group_id.blank?
|
|
|
|
|
2022-10-27 06:13:21 +08:00
|
|
|
@category_group_moderator_groups ||= {}
|
2022-08-04 08:07:12 +08:00
|
|
|
|
2022-10-27 06:13:21 +08:00
|
|
|
if @category_group_moderator_groups.key?(reviewable_by_group_id)
|
|
|
|
@category_group_moderator_groups[reviewable_by_group_id]
|
2022-08-04 08:07:12 +08:00
|
|
|
else
|
2022-10-27 06:13:21 +08:00
|
|
|
@category_group_moderator_groups[
|
|
|
|
reviewable_by_group_id
|
|
|
|
] = category_group_moderator_scope.exists?("categories.id": category.id)
|
2020-07-29 05:15:04 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-11-11 01:18:08 +08:00
|
|
|
def is_silenced?
|
|
|
|
@user.silenced?
|
2016-06-20 15:41:17 +08:00
|
|
|
end
|
|
|
|
|
2013-09-05 08:27:34 +08:00
|
|
|
def is_developer?
|
|
|
|
@user && is_admin? &&
|
2013-09-06 12:07:23 +08:00
|
|
|
(
|
2018-01-17 12:50:18 +08:00
|
|
|
Rails.env.development? || Developer.user_ids.include?(@user.id) ||
|
2023-01-09 20:10:19 +08:00
|
|
|
(
|
2013-09-06 12:07:23 +08:00
|
|
|
Rails.configuration.respond_to?(:developer_emails) &&
|
|
|
|
Rails.configuration.developer_emails.include?(@user.email)
|
2023-01-09 20:10:19 +08:00
|
|
|
)
|
2018-01-17 12:50:18 +08:00
|
|
|
)
|
2013-09-05 08:27:34 +08:00
|
|
|
end
|
|
|
|
|
2016-06-27 01:25:45 +08:00
|
|
|
def is_staged?
|
|
|
|
@user.staged?
|
|
|
|
end
|
|
|
|
|
2019-04-17 16:05:02 +08:00
|
|
|
def is_anonymous?
|
|
|
|
@user.anonymous?
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Can the user see the object?
|
|
|
|
def can_see?(obj)
|
2013-05-20 14:04:53 +08:00
|
|
|
if obj
|
|
|
|
see_method = method_name_for :see, obj
|
2023-02-24 15:57:01 +08:00
|
|
|
see_method && public_send(see_method, obj)
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-03-18 02:50:28 +08:00
|
|
|
def can_create?(klass, parent = nil)
|
|
|
|
return false unless authenticated? && klass
|
|
|
|
|
|
|
|
# If no parent is provided, we look for a can_create_klass?
|
|
|
|
# custom method.
|
|
|
|
#
|
|
|
|
# If a parent is provided, we look for a method called
|
|
|
|
# can_create_klass_on_parent?
|
|
|
|
target = klass.name.underscore
|
|
|
|
if parent.present?
|
|
|
|
return false unless can_see?(parent)
|
|
|
|
target << "_on_#{parent.class.name.underscore}"
|
|
|
|
end
|
|
|
|
create_method = :"can_create_#{target}?"
|
|
|
|
|
2019-05-07 10:22:37 +08:00
|
|
|
return public_send(create_method, parent) if respond_to?(create_method)
|
2014-03-18 02:50:28 +08:00
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2018-04-25 23:46:54 +08:00
|
|
|
def can_enable_safe_mode?
|
|
|
|
SiteSetting.enable_safe_mode? || is_staff?
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Can the user edit the obj
|
|
|
|
def can_edit?(obj)
|
2013-08-16 20:24:29 +08:00
|
|
|
can_do?(:edit, obj)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# Can we delete the object
|
|
|
|
def can_delete?(obj)
|
2013-08-16 20:24:29 +08:00
|
|
|
can_do?(:delete, obj)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2021-10-13 17:53:23 +08:00
|
|
|
def can_permanently_delete?(obj)
|
|
|
|
can_do?(:permanently_delete, obj)
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def can_moderate?(obj)
|
2020-10-14 00:03:14 +08:00
|
|
|
obj && authenticated? && !is_silenced? &&
|
|
|
|
(
|
|
|
|
is_staff? ||
|
|
|
|
(obj.is_a?(Topic) && @user.has_trust_level?(TrustLevel[4]) && can_see_topic?(obj))
|
|
|
|
)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
alias can_see_flags? can_moderate?
|
2014-09-03 04:12:27 +08:00
|
|
|
|
2018-02-22 22:57:02 +08:00
|
|
|
def can_tag?(topic)
|
|
|
|
return false if topic.blank?
|
2018-02-14 04:46:25 +08:00
|
|
|
|
2018-02-22 22:57:02 +08:00
|
|
|
topic.private_message? ? can_tag_pms? : can_tag_topics?
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_see_tags?(topic)
|
|
|
|
SiteSetting.tagging_enabled && topic.present? && (!topic.private_message? || can_tag_pms?)
|
2018-02-14 04:46:25 +08:00
|
|
|
end
|
|
|
|
|
2017-07-04 16:29:05 +08:00
|
|
|
def can_send_activation_email?(user)
|
|
|
|
user && is_staff? && !SiteSetting.must_approve_users?
|
|
|
|
end
|
|
|
|
|
2014-09-03 04:12:27 +08:00
|
|
|
def can_grant_badges?(_user)
|
|
|
|
SiteSetting.enable_badges && is_staff?
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2019-04-12 21:55:27 +08:00
|
|
|
def can_delete_reviewable_queued_post?(reviewable)
|
2023-04-21 00:07:35 +08:00
|
|
|
return false if reviewable.blank?
|
|
|
|
return false if !authenticated?
|
2023-04-25 09:22:37 +08:00
|
|
|
return true if is_api? && is_admin?
|
2023-04-21 00:07:35 +08:00
|
|
|
|
|
|
|
reviewable.created_by_id == @user.id
|
2019-04-12 21:55:27 +08:00
|
|
|
end
|
|
|
|
|
2014-04-23 04:43:46 +08:00
|
|
|
def can_see_group?(group)
|
2020-01-15 18:21:58 +08:00
|
|
|
group.present? && can_see_groups?([group])
|
2014-04-23 04:43:46 +08:00
|
|
|
end
|
|
|
|
|
2019-08-14 21:30:04 +08:00
|
|
|
def can_see_group_members?(group)
|
|
|
|
return false if group.blank?
|
2020-01-15 18:21:58 +08:00
|
|
|
return true if is_admin? || group.members_visibility_level == Group.visibility_levels[:public]
|
2019-08-14 21:30:04 +08:00
|
|
|
return true if is_staff? && group.members_visibility_level == Group.visibility_levels[:staff]
|
2020-09-22 00:32:43 +08:00
|
|
|
return true if is_staff? && group.members_visibility_level == Group.visibility_levels[:members]
|
2019-08-14 21:30:04 +08:00
|
|
|
if authenticated? && group.members_visibility_level == Group.visibility_levels[:logged_on_users]
|
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2019-08-14 21:30:04 +08:00
|
|
|
return false if user.blank?
|
|
|
|
|
2020-01-15 18:21:58 +08:00
|
|
|
return false unless membership = GroupUser.find_by(group_id: group.id, user_id: user.id)
|
|
|
|
return true if membership.owner
|
2019-08-14 21:30:04 +08:00
|
|
|
|
2020-01-15 18:21:58 +08:00
|
|
|
return false if group.members_visibility_level == Group.visibility_levels[:owners]
|
|
|
|
return false if group.members_visibility_level == Group.visibility_levels[:staff]
|
2019-08-14 21:30:04 +08:00
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2019-05-30 06:40:43 +08:00
|
|
|
def can_see_groups?(groups)
|
|
|
|
return false if groups.blank?
|
2020-01-15 18:21:58 +08:00
|
|
|
if is_admin? || groups.all? { |g| g.visibility_level == Group.visibility_levels[:public] }
|
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2019-05-30 06:40:43 +08:00
|
|
|
if is_staff? && groups.all? { |g| g.visibility_level == Group.visibility_levels[:staff] }
|
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2020-09-22 00:32:43 +08:00
|
|
|
if is_staff? && groups.all? { |g| g.visibility_level == Group.visibility_levels[:members] }
|
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2019-07-09 03:09:50 +08:00
|
|
|
if authenticated? &&
|
|
|
|
groups.all? { |g| g.visibility_level == Group.visibility_levels[:logged_on_users] }
|
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2019-05-30 06:40:43 +08:00
|
|
|
return false if user.blank?
|
|
|
|
|
|
|
|
memberships = GroupUser.where(group: groups, user_id: user.id).pluck(:owner)
|
2020-01-15 18:21:58 +08:00
|
|
|
return false if memberships.size < groups.size
|
|
|
|
return true if memberships.all? # owner of all groups
|
2019-05-30 06:40:43 +08:00
|
|
|
|
2020-01-15 18:21:58 +08:00
|
|
|
return false if groups.all? { |g| g.visibility_level == Group.visibility_levels[:owners] }
|
|
|
|
return false if groups.all? { |g| g.visibility_level == Group.visibility_levels[:staff] }
|
2019-05-30 06:40:43 +08:00
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2019-10-24 20:23:19 +08:00
|
|
|
def can_see_groups_members?(groups)
|
|
|
|
return false if groups.blank?
|
|
|
|
|
|
|
|
requested_group_ids = groups.map(&:id) # Can't use pluck, groups could be a regular array
|
2020-01-15 18:21:58 +08:00
|
|
|
matching_group_ids =
|
|
|
|
Group.where(id: requested_group_ids).members_visible_groups(user).pluck(:id)
|
2019-10-24 20:23:19 +08:00
|
|
|
|
2020-01-15 18:21:58 +08:00
|
|
|
matching_group_ids.sort == requested_group_ids.sort
|
2019-10-24 20:23:19 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Can we impersonate this user?
|
|
|
|
def can_impersonate?(target)
|
2023-03-23 12:16:05 +08:00
|
|
|
GlobalSetting.allow_impersonation && target &&
|
2013-02-06 03:16:51 +08:00
|
|
|
# You must be an admin to impersonate
|
2013-05-20 14:04:53 +08:00
|
|
|
is_admin? &&
|
2013-09-05 08:27:34 +08:00
|
|
|
# You may not impersonate other admins unless you are a dev
|
|
|
|
(!target.admin? || is_developer?)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-05-20 14:04:53 +08:00
|
|
|
# Additionally, you may not impersonate yourself;
|
|
|
|
# but the two tests for different admin statuses
|
|
|
|
# make it impossible to be the same user.
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2017-02-21 20:45:30 +08:00
|
|
|
def can_view_action_logs?(target)
|
2017-04-21 00:15:52 +08:00
|
|
|
target.present? && is_staff?
|
2017-02-21 20:45:30 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Can we approve it?
|
|
|
|
def can_approve?(target)
|
2019-04-17 02:42:47 +08:00
|
|
|
is_staff? && target && target.active? && !target.approved?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2014-04-29 01:46:28 +08:00
|
|
|
|
|
|
|
def can_activate?(target)
|
|
|
|
is_staff? && target && not(target.active?)
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-11-08 02:53:32 +08:00
|
|
|
def can_suspend?(user)
|
2013-05-25 00:13:31 +08:00
|
|
|
user && is_staff? && user.regular?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2013-11-08 02:53:32 +08:00
|
|
|
alias can_deactivate? can_suspend?
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
def can_revoke_admin?(admin)
|
2013-05-20 14:04:53 +08:00
|
|
|
can_administer_user?(admin) && admin.admin?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def can_grant_admin?(user)
|
2016-12-29 11:11:33 +08:00
|
|
|
can_administer_user?(user) && !user.admin?
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-02-13 06:58:08 +08:00
|
|
|
def can_revoke_moderation?(moderator)
|
2013-05-20 14:04:53 +08:00
|
|
|
can_administer?(moderator) && moderator.moderator?
|
2013-02-13 06:58:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def can_grant_moderation?(user)
|
2016-12-29 11:11:33 +08:00
|
|
|
can_administer?(user) && !user.moderator?
|
2013-02-13 06:58:08 +08:00
|
|
|
end
|
|
|
|
|
2018-04-07 02:29:27 +08:00
|
|
|
def can_grant_title?(user, title = nil)
|
|
|
|
return true if user && is_staff?
|
2018-04-27 04:50:50 +08:00
|
|
|
return false if title.nil?
|
2018-06-01 07:10:52 +08:00
|
|
|
return true if title.empty? # A title set to '(none)' in the UI is an empty string
|
2018-04-07 02:29:27 +08:00
|
|
|
return false if user != @user
|
2020-01-09 01:01:46 +08:00
|
|
|
|
|
|
|
if user
|
|
|
|
.badges
|
|
|
|
.where(allow_title: true)
|
|
|
|
.pluck(:name)
|
2020-01-09 01:37:28 +08:00
|
|
|
.any? { |name| Badge.display_name(name) == title }
|
2020-01-09 01:01:46 +08:00
|
|
|
return true
|
2023-01-09 20:10:19 +08:00
|
|
|
end
|
2020-01-09 01:01:46 +08:00
|
|
|
|
2018-04-07 02:29:27 +08:00
|
|
|
user.groups.where(title: title).exists?
|
2013-06-26 06:39:20 +08:00
|
|
|
end
|
|
|
|
|
2019-10-29 01:46:27 +08:00
|
|
|
def can_use_primary_group?(user, group_id = nil)
|
|
|
|
return false if !user || !group_id
|
|
|
|
group = Group.find_by(id: group_id.to_i)
|
|
|
|
|
|
|
|
user.group_ids.include?(group_id.to_i) && (group ? !group.automatic : false)
|
|
|
|
end
|
|
|
|
|
2021-07-21 19:41:04 +08:00
|
|
|
def can_use_flair_group?(user, group_id = nil)
|
|
|
|
return false if !user || !group_id || !user.group_ids.include?(group_id.to_i)
|
2023-02-13 12:39:45 +08:00
|
|
|
flair_icon, flair_upload_id = Group.where(id: group_id.to_i).pick(:flair_icon, :flair_upload_id)
|
2021-07-21 19:41:04 +08:00
|
|
|
flair_icon.present? || flair_upload_id.present?
|
|
|
|
end
|
|
|
|
|
2022-11-11 19:06:05 +08:00
|
|
|
def can_change_primary_group?(user, group)
|
|
|
|
user && can_edit_group?(group)
|
2014-02-11 05:59:36 +08:00
|
|
|
end
|
|
|
|
|
2013-07-03 16:27:40 +08:00
|
|
|
def can_change_trust_level?(user)
|
2013-07-23 07:13:48 +08:00
|
|
|
user && is_staff?
|
2013-07-03 16:27:40 +08:00
|
|
|
end
|
|
|
|
|
2013-04-04 00:23:28 +08:00
|
|
|
# Support sites that have to approve users
|
|
|
|
def can_access_forum?
|
|
|
|
return true unless SiteSetting.must_approve_users?
|
2020-04-06 07:56:47 +08:00
|
|
|
return false if anonymous?
|
2013-04-04 00:23:28 +08:00
|
|
|
|
2013-05-02 15:22:27 +08:00
|
|
|
# Staff can't lock themselves out of a site
|
|
|
|
return true if is_staff?
|
2013-04-04 00:23:28 +08:00
|
|
|
|
2013-05-02 15:22:27 +08:00
|
|
|
@user.approved?
|
2013-04-04 00:23:28 +08:00
|
|
|
end
|
|
|
|
|
2014-03-22 02:13:04 +08:00
|
|
|
def can_see_invite_details?(user)
|
2021-10-14 22:57:01 +08:00
|
|
|
is_staff? || is_me?(user)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2020-03-05 00:47:09 +08:00
|
|
|
def can_see_invite_emails?(user)
|
|
|
|
is_staff? || is_me?(user)
|
|
|
|
end
|
|
|
|
|
2014-05-09 16:22:15 +08:00
|
|
|
def can_invite_to_forum?(groups = nil)
|
2021-09-29 22:40:16 +08:00
|
|
|
authenticated? && (is_staff? || SiteSetting.max_invites_per_day.to_i.positive?) &&
|
|
|
|
(is_staff? || @user.has_trust_level?(SiteSetting.min_trust_level_to_allow_invite.to_i)) &&
|
|
|
|
(is_admin? || groups.blank? || groups.all? { |g| can_edit_group?(g) })
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2017-07-21 14:12:24 +08:00
|
|
|
def can_invite_to?(object, groups = nil)
|
2021-10-11 17:19:31 +08:00
|
|
|
return false if !authenticated?
|
2021-09-29 22:40:16 +08:00
|
|
|
return false if !object.is_a?(Topic) || !can_see?(object)
|
2017-07-21 14:12:24 +08:00
|
|
|
return false if groups.present?
|
2015-03-03 03:25:25 +08:00
|
|
|
|
2021-09-29 22:40:16 +08:00
|
|
|
if object.is_a?(Topic)
|
2018-12-05 23:43:07 +08:00
|
|
|
if object.private_message?
|
|
|
|
return true if is_admin?
|
2022-09-26 11:58:40 +08:00
|
|
|
|
2022-10-05 08:50:20 +08:00
|
|
|
return false if !@user.in_any_groups?(SiteSetting.personal_message_enabled_groups_map)
|
2018-12-05 23:43:07 +08:00
|
|
|
return false if object.reached_recipients_limit? && !is_staff?
|
|
|
|
end
|
2018-03-08 04:04:17 +08:00
|
|
|
|
2018-12-05 23:43:07 +08:00
|
|
|
if (category = object.category) && category.read_restricted
|
2021-09-29 22:40:16 +08:00
|
|
|
return category.groups&.where(automatic: false).any? { |g| can_edit_group?(g) }
|
2015-03-03 03:25:25 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-29 22:40:16 +08:00
|
|
|
true
|
2013-11-07 01:56:26 +08:00
|
|
|
end
|
|
|
|
|
2017-02-03 01:38:25 +08:00
|
|
|
def can_invite_via_email?(object)
|
2021-10-11 17:19:31 +08:00
|
|
|
return false if !can_invite_to_forum?
|
2021-09-29 22:40:16 +08:00
|
|
|
return false if !can_invite_to?(object)
|
|
|
|
|
2021-03-19 08:20:10 +08:00
|
|
|
(SiteSetting.enable_local_logins || SiteSetting.enable_discourse_connect) &&
|
|
|
|
(!SiteSetting.must_approve_users? || is_staff?)
|
2017-02-03 01:38:25 +08:00
|
|
|
end
|
|
|
|
|
2014-05-28 04:14:37 +08:00
|
|
|
def can_bulk_invite_to_forum?(user)
|
2021-11-10 01:43:23 +08:00
|
|
|
user.admin?
|
2014-05-28 04:14:37 +08:00
|
|
|
end
|
|
|
|
|
2016-06-07 13:27:08 +08:00
|
|
|
def can_resend_all_invites?(user)
|
|
|
|
user.staff?
|
2014-07-30 01:57:08 +08:00
|
|
|
end
|
|
|
|
|
2021-03-03 17:45:29 +08:00
|
|
|
def can_destroy_all_invites?(user)
|
2017-06-29 22:32:07 +08:00
|
|
|
user.staff?
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def can_see_private_messages?(user_id)
|
2014-02-07 11:24:19 +08:00
|
|
|
is_admin? || (authenticated? && @user.id == user_id)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2017-12-14 10:53:21 +08:00
|
|
|
def can_invite_group_to_private_message?(group, topic)
|
|
|
|
can_see_topic?(topic) && can_send_private_message?(group)
|
|
|
|
end
|
|
|
|
|
2022-11-07 07:11:18 +08:00
|
|
|
##
|
|
|
|
# This should be used as a general, but not definitive, check for whether
|
|
|
|
# the user can send private messages _generally_, which is mostly useful
|
|
|
|
# for changing the UI.
|
|
|
|
#
|
|
|
|
# Please otherwise use can_send_private_message?(target, notify_moderators)
|
|
|
|
# to check if a single target can be messaged.
|
|
|
|
def can_send_private_messages?(notify_moderators: false)
|
2022-03-22 08:23:14 +08:00
|
|
|
from_system = @user.is_system_user?
|
2022-10-05 08:50:20 +08:00
|
|
|
from_bot = @user.bot?
|
2017-10-06 15:56:58 +08:00
|
|
|
|
2014-02-13 12:08:46 +08:00
|
|
|
# User is authenticated
|
2013-05-20 14:04:53 +08:00
|
|
|
authenticated? &&
|
2022-11-07 07:11:18 +08:00
|
|
|
# User can send PMs, this can be covered by trust levels as well via AUTO_GROUPS
|
|
|
|
(
|
|
|
|
is_staff? || from_bot || from_system ||
|
|
|
|
(@user.in_any_groups?(SiteSetting.personal_message_enabled_groups_map)) ||
|
|
|
|
notify_moderators
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
# This should be used as a final check for when a user is sending a message
|
|
|
|
# to a target user or group.
|
|
|
|
def can_send_private_message?(target, notify_moderators: false)
|
|
|
|
target_is_user = target.is_a?(User)
|
|
|
|
target_is_group = target.is_a?(Group)
|
|
|
|
from_system = @user.is_system_user?
|
|
|
|
|
|
|
|
# Must be a valid target
|
2022-12-20 11:11:14 +08:00
|
|
|
return false if !(target_is_group || target_is_user)
|
|
|
|
|
|
|
|
# Users can send messages to certain groups with the `everyone` messageable_level
|
|
|
|
# even if they are not in personal_message_enabled_groups
|
|
|
|
group_is_messageable = target_is_group && Group.messageable(@user).where(id: target.id).exists?
|
|
|
|
|
2022-11-07 07:11:18 +08:00
|
|
|
# User is authenticated and can send PMs, this can be covered by trust levels as well via AUTO_GROUPS
|
2022-12-20 11:11:14 +08:00
|
|
|
(can_send_private_messages?(notify_moderators: notify_moderators) || group_is_messageable) &&
|
2017-10-06 15:56:58 +08:00
|
|
|
# User disabled private message
|
2022-11-07 07:11:18 +08:00
|
|
|
(is_staff? || target_is_group || target.user_option.allow_private_messages) &&
|
2014-05-07 03:01:19 +08:00
|
|
|
# Can't send PMs to suspended users
|
2022-11-07 07:11:18 +08:00
|
|
|
(is_staff? || target_is_group || !target.suspended?) &&
|
2017-12-14 10:53:21 +08:00
|
|
|
# Check group messageable level
|
2022-12-20 11:11:14 +08:00
|
|
|
(from_system || target_is_user || group_is_messageable || notify_moderators) &&
|
2017-11-11 01:18:08 +08:00
|
|
|
# Silenced users can only send PM to staff
|
|
|
|
(!is_silenced? || target.staff?)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2018-08-27 09:38:11 +08:00
|
|
|
def can_send_private_messages_to_email?
|
2017-08-29 00:07:30 +08:00
|
|
|
# Staged users must be enabled to create a temporary user.
|
2021-04-06 20:39:27 +08:00
|
|
|
return false if !SiteSetting.enable_staged_users
|
2017-08-29 00:07:30 +08:00
|
|
|
# User is authenticated
|
2021-04-06 20:39:27 +08:00
|
|
|
return false if !authenticated?
|
2017-08-29 00:07:30 +08:00
|
|
|
# User is trusted enough
|
2022-10-05 08:50:20 +08:00
|
|
|
@user.in_any_groups?(SiteSetting.personal_message_enabled_groups_map) &&
|
2022-09-26 11:58:40 +08:00
|
|
|
@user.has_trust_level_or_staff?(SiteSetting.min_trust_to_send_email_messages)
|
2017-08-29 00:07:30 +08:00
|
|
|
end
|
|
|
|
|
2017-05-20 03:59:37 +08:00
|
|
|
def can_export_entity?(entity)
|
2020-04-06 07:56:47 +08:00
|
|
|
return false if anonymous?
|
2018-09-21 09:07:13 +08:00
|
|
|
return true if is_admin?
|
|
|
|
return entity != "user_list" if is_moderator?
|
2017-05-20 03:59:37 +08:00
|
|
|
|
|
|
|
# Regular users can only export their archives
|
|
|
|
return false unless entity == "user_archive"
|
2014-12-30 20:37:05 +08:00
|
|
|
UserExport.where(
|
|
|
|
user_id: @user.id,
|
|
|
|
created_at: (Time.zone.now.beginning_of_day..Time.zone.now.end_of_day),
|
|
|
|
).count == 0
|
2014-12-23 00:17:04 +08:00
|
|
|
end
|
|
|
|
|
2020-01-02 21:04:08 +08:00
|
|
|
def can_mute_user?(target_user)
|
|
|
|
can_mute_users? && @user.id != target_user.id && !target_user.staff?
|
2019-03-27 17:41:50 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def can_mute_users?
|
|
|
|
return false if anonymous?
|
|
|
|
@user.staff? || @user.trust_level >= TrustLevel.levels[:basic]
|
|
|
|
end
|
|
|
|
|
2020-01-02 21:04:08 +08:00
|
|
|
def can_ignore_user?(target_user)
|
|
|
|
can_ignore_users? && @user.id != target_user.id && !target_user.staff?
|
2019-03-21 03:55:46 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def can_ignore_users?
|
|
|
|
return false if anonymous?
|
2020-11-21 02:05:20 +08:00
|
|
|
@user.staff? || @user.has_trust_level?(SiteSetting.min_trust_level_to_allow_ignore.to_i)
|
2019-03-20 18:18:46 +08:00
|
|
|
end
|
|
|
|
|
2020-06-03 11:19:42 +08:00
|
|
|
def allowed_theme_repo_import?(repo)
|
|
|
|
return false if !@user.admin?
|
|
|
|
|
2020-07-27 08:23:54 +08:00
|
|
|
allowed_repos = GlobalSetting.allowed_theme_repos
|
|
|
|
if !allowed_repos.blank?
|
|
|
|
urls = allowed_repos.split(",").map(&:strip)
|
2020-06-03 11:19:42 +08:00
|
|
|
return urls.include?(repo)
|
|
|
|
end
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2018-09-07 08:44:57 +08:00
|
|
|
def allow_themes?(theme_ids, include_preview: false)
|
2018-08-10 19:12:02 +08:00
|
|
|
return true if theme_ids.blank?
|
|
|
|
|
2021-10-29 23:46:52 +08:00
|
|
|
if allowed_theme_ids = Theme.allowed_remote_theme_ids
|
2020-07-27 08:23:54 +08:00
|
|
|
return false if (theme_ids - allowed_theme_ids).present?
|
2020-06-03 11:19:42 +08:00
|
|
|
end
|
|
|
|
|
2018-09-07 08:44:57 +08:00
|
|
|
return true if include_preview && is_staff? && (theme_ids - Theme.theme_ids).blank?
|
2018-08-08 12:46:34 +08:00
|
|
|
|
|
|
|
parent = theme_ids.first
|
|
|
|
components = theme_ids[1..-1] || []
|
|
|
|
|
|
|
|
Theme.user_theme_ids.include?(parent) && (components - Theme.components_for(parent)).empty?
|
2017-04-15 01:35:12 +08:00
|
|
|
end
|
|
|
|
|
2020-04-09 00:52:36 +08:00
|
|
|
def can_publish_page?(topic)
|
2020-11-06 08:33:19 +08:00
|
|
|
return false if !SiteSetting.enable_page_publishing?
|
2022-09-29 07:24:33 +08:00
|
|
|
return false if SiteSetting.secure_uploads?
|
2020-04-09 00:52:36 +08:00
|
|
|
return false if topic.blank?
|
|
|
|
return false if topic.private_message?
|
|
|
|
return false unless can_see_topic?(topic)
|
|
|
|
is_staff?
|
|
|
|
end
|
|
|
|
|
2020-05-23 12:56:13 +08:00
|
|
|
def can_see_about_stats?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2021-05-19 14:15:24 +08:00
|
|
|
def can_see_site_contact_details?
|
|
|
|
!SiteSetting.login_required? || authenticated?
|
|
|
|
end
|
|
|
|
|
2018-10-12 07:40:48 +08:00
|
|
|
def auth_token
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
return if !request
|
|
|
|
|
|
|
|
token = Auth::DefaultCurrentUserProvider.find_v0_auth_cookie(request).presence
|
|
|
|
|
|
|
|
if !token
|
|
|
|
cookie = Auth::DefaultCurrentUserProvider.find_v1_auth_cookie(request.env)
|
|
|
|
token = cookie[:token] if cookie
|
2018-10-12 07:51:41 +08:00
|
|
|
end
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
|
|
|
|
UserAuthToken.hash_token(token) if token
|
2018-10-12 07:40:48 +08:00
|
|
|
end
|
|
|
|
|
2021-11-24 04:25:54 +08:00
|
|
|
def can_mention_here?
|
|
|
|
return false if SiteSetting.here_mention.blank?
|
|
|
|
return false if SiteSetting.max_here_mentioned < 1
|
|
|
|
return false if !authenticated?
|
|
|
|
return false if User.where(username_lower: SiteSetting.here_mention).exists?
|
|
|
|
|
|
|
|
@user.has_trust_level_or_staff?(SiteSetting.min_trust_level_for_here_mention)
|
|
|
|
end
|
|
|
|
|
2021-08-27 00:16:00 +08:00
|
|
|
def is_me?(other)
|
|
|
|
other && authenticated? && other.is_a?(User) && @user == other
|
|
|
|
end
|
|
|
|
|
2013-05-20 14:04:53 +08:00
|
|
|
private
|
|
|
|
|
|
|
|
def is_my_own?(obj)
|
2023-07-21 21:21:07 +08:00
|
|
|
if anonymous?
|
|
|
|
return(
|
|
|
|
SiteSetting.allow_anonymous_likes? && obj.class == PostAction && obj.is_like? &&
|
|
|
|
obj.user_id == @user.id
|
|
|
|
)
|
2013-10-04 11:28:49 +08:00
|
|
|
end
|
2023-07-21 21:21:07 +08:00
|
|
|
return obj.user_id == @user.id if obj.respond_to?(:user_id) && obj.user_id && @user.id
|
|
|
|
return obj.user == @user if obj.respond_to?(:user)
|
2013-10-04 11:28:49 +08:00
|
|
|
|
|
|
|
false
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def is_not_me?(other)
|
|
|
|
@user.blank? || !is_me?(other)
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_administer?(obj)
|
2016-12-29 11:11:33 +08:00
|
|
|
is_admin? && obj.present? && obj.id&.positive?
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def can_administer_user?(other_user)
|
|
|
|
can_administer?(other_user) && is_not_me?(other_user)
|
|
|
|
end
|
|
|
|
|
|
|
|
def method_name_for(action, obj)
|
|
|
|
method_name = :"can_#{action}_#{obj.class.name.underscore}?"
|
2023-08-10 08:03:38 +08:00
|
|
|
method_name if respond_to?(method_name)
|
2013-05-20 14:04:53 +08:00
|
|
|
end
|
|
|
|
|
2013-08-16 20:24:29 +08:00
|
|
|
def can_do?(action, obj)
|
|
|
|
if obj && authenticated?
|
|
|
|
action_method = method_name_for action, obj
|
2019-11-15 04:10:51 +08:00
|
|
|
(action_method ? public_send(action_method, obj) : true)
|
2014-01-17 00:59:26 +08:00
|
|
|
else
|
|
|
|
false
|
2013-08-16 20:24:29 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-04-25 09:22:37 +08:00
|
|
|
def is_api?
|
|
|
|
@user && request&.env&.dig(Auth::DefaultCurrentUserProvider::API_KEY_ENV)
|
|
|
|
end
|
|
|
|
|
2022-10-27 06:13:21 +08:00
|
|
|
protected
|
|
|
|
|
|
|
|
def category_group_moderation_allowed?
|
|
|
|
authenticated? && SiteSetting.enable_category_group_moderation
|
|
|
|
end
|
|
|
|
|
|
|
|
def category_group_moderator_scope
|
|
|
|
Category.joins(
|
|
|
|
"INNER JOIN group_users ON group_users.group_id = categories.reviewable_by_group_id",
|
|
|
|
).where("group_users.user_id = ?", user.id)
|
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|