discourse/app/serializers/user_serializer.rb
Neil Lalonde b0f06b8ed0
FIX: don't allow category and tag tracking settings on staged users (#13688)
Configuring staged users to watch categories and tags is a way to sign
them up to get many emails. These emails may be unwanted and get marked
as spam, hurting the site's email deliverability.
Users can opt-in to email notifications by logging on to their
account and configuring their own preferences.

If staff need to be able to configure these preferences on behalf of
staged users, the "allow changing staged user tracking" site setting
can be enabled. Default is to not allow it.

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2021-07-16 14:50:40 -04:00

335 lines
7.9 KiB
Ruby

# frozen_string_literal: true
class UserSerializer < UserCardSerializer
attributes :bio_raw,
:bio_cooked,
:can_edit,
:can_edit_username,
:can_edit_email,
:can_edit_name,
:uploaded_avatar_id,
:has_title_badges,
:pending_count,
:profile_view_count,
:second_factor_enabled,
:second_factor_backup_enabled,
:second_factor_remaining_backup_codes,
:associated_accounts,
:profile_background_upload_url,
:can_upload_profile_header,
:can_upload_user_card_background
has_one :invited_by, embed: :object, serializer: BasicUserSerializer
has_many :groups, embed: :object, serializer: BasicGroupSerializer
has_many :group_users, embed: :object, serializer: BasicGroupUserSerializer
has_one :user_option, embed: :object, serializer: UserOptionSerializer
def include_user_option?
can_edit
end
staff_attributes :post_count,
:can_be_deleted,
:can_delete_all_posts
private_attributes :locale,
:muted_category_ids,
:regular_category_ids,
:watched_tags,
:watching_first_post_tags,
:tracked_tags,
:muted_tags,
:tracked_category_ids,
:watched_category_ids,
:watched_first_post_category_ids,
:system_avatar_upload_id,
:system_avatar_template,
:gravatar_avatar_upload_id,
:gravatar_avatar_template,
:custom_avatar_upload_id,
:custom_avatar_template,
:has_title_badges,
:muted_usernames,
:ignored_usernames,
:allowed_pm_usernames,
:mailing_list_posts_per_day,
:can_change_bio,
:can_change_location,
:can_change_website,
:can_change_tracking_preferences,
:user_api_keys,
:user_auth_tokens,
:user_notification_schedule,
:use_logo_small_as_avatar
untrusted_attributes :bio_raw,
:bio_cooked,
:profile_background_upload_url,
###
### ATTRIBUTES
###
#
def user_notification_schedule
object.user_notification_schedule || UserNotificationSchedule::DEFAULT
end
def mailing_list_posts_per_day
val = Post.estimate_posts_per_day
[val, SiteSetting.max_emails_per_day_per_user].min
end
def groups
object.groups.order(:id)
.visible_groups(scope.user).members_visible_groups(scope.user)
end
def group_users
object.group_users.order(:group_id)
end
def include_group_users?
user_is_current_user || scope.is_admin?
end
def include_associated_accounts?
user_is_current_user
end
def include_second_factor_enabled?
user_is_current_user || scope.is_admin?
end
def second_factor_enabled
object.totp_enabled? || object.security_keys_enabled?
end
def include_second_factor_backup_enabled?
user_is_current_user
end
def second_factor_backup_enabled
object.backup_codes_enabled?
end
def include_second_factor_remaining_backup_codes?
user_is_current_user && object.backup_codes_enabled?
end
def second_factor_remaining_backup_codes
object.remaining_backup_codes
end
def can_change_bio
!(SiteSetting.enable_discourse_connect && SiteSetting.discourse_connect_overrides_bio)
end
def can_change_location
!(SiteSetting.enable_discourse_connect && SiteSetting.discourse_connect_overrides_location)
end
def can_change_website
!(SiteSetting.enable_discourse_connect && SiteSetting.discourse_connect_overrides_website)
end
def can_change_tracking_preferences
scope.can_change_tracking_preferences?(object)
end
def user_api_keys
keys = object.user_api_keys.where(revoked_at: nil).map do |k|
{
id: k.id,
application_name: k.application_name,
scopes: k.scopes.map { |s| I18n.t("user_api_key.scopes.#{s.name}") },
created_at: k.created_at,
last_used_at: k.last_used_at,
}
end
keys.sort! { |a, b| a[:last_used_at].to_time <=> b[:last_used_at].to_time }
keys.length > 0 ? keys : nil
end
def user_auth_tokens
ActiveModel::ArraySerializer.new(
object.user_auth_tokens,
each_serializer: UserAuthTokenSerializer,
scope: scope
)
end
def bio_raw
object.user_profile.bio_raw
end
def bio_cooked
object.user_profile.bio_processed
end
def can_edit
scope.can_edit?(object)
end
def can_edit_username
scope.can_edit_username?(object)
end
def can_edit_email
scope.can_edit_email?(object)
end
def can_edit_name
scope.can_edit_name?(object)
end
def can_upload_profile_header
scope.can_upload_profile_header?(object)
end
def can_upload_user_card_background
scope.can_upload_user_card_background?(object)
end
###
### STAFF ATTRIBUTES
###
def post_count
object.user_stat.try(:post_count)
end
def can_be_deleted
scope.can_delete_user?(object)
end
def can_delete_all_posts
scope.can_delete_all_posts?(object)
end
###
### PRIVATE ATTRIBUTES
###
def muted_tags
tags_with_notification_level(:muted)
end
def tracked_tags
tags_with_notification_level(:tracking)
end
def watching_first_post_tags
tags_with_notification_level(:watching_first_post)
end
def watched_tags
tags_with_notification_level(:watching)
end
def muted_category_ids
categories_with_notification_level(:muted)
end
def regular_category_ids
categories_with_notification_level(:regular)
end
def tracked_category_ids
categories_with_notification_level(:tracking)
end
def watched_category_ids
categories_with_notification_level(:watching)
end
def watched_first_post_category_ids
categories_with_notification_level(:watching_first_post)
end
def muted_usernames
MutedUser.where(user_id: object.id).joins(:muted_user).pluck(:username)
end
def ignored_usernames
IgnoredUser.where(user_id: object.id).joins(:ignored_user).pluck(:username)
end
def allowed_pm_usernames
AllowedPmUser.where(user_id: object.id).joins(:allowed_pm_user).pluck(:username)
end
def system_avatar_upload_id
# should be left blank
end
def system_avatar_template
User.system_avatar_template(object.username)
end
def include_gravatar_avatar_upload_id?
object.user_avatar&.gravatar_upload_id
end
def gravatar_avatar_upload_id
object.user_avatar.gravatar_upload_id
end
def include_gravatar_avatar_template?
include_gravatar_avatar_upload_id?
end
def gravatar_avatar_template
User.avatar_template(object.username, object.user_avatar.gravatar_upload_id)
end
def include_custom_avatar_upload_id?
object.user_avatar&.custom_upload_id
end
def custom_avatar_upload_id
object.user_avatar.custom_upload_id
end
def include_custom_avatar_template?
include_custom_avatar_upload_id?
end
def custom_avatar_template
User.avatar_template(object.username, object.user_avatar.custom_upload_id)
end
def has_title_badges
object.badges.where(allow_title: true).exists?
end
def pending_count
0
end
def profile_view_count
object.user_profile.views
end
def profile_background_upload_url
object.profile_background_upload&.url
end
def use_logo_small_as_avatar
object.is_system_user? && SiteSetting.logo_small && SiteSetting.use_site_small_logo_as_system_avatar
end
private
def custom_field_keys
fields = super
if scope.can_edit?(object)
fields += DiscoursePluginRegistry.serialized_current_user_fields.to_a
end
fields
end
end