discourse/discourse

View on GitHub
app/serializers/user_serializer.rb

Summary

Maintainability
B
6 hrs
Test Coverage
# 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

  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,
                     :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,
                     :mailing_list_posts_per_day,
                     :can_change_bio,
                     :user_api_keys,
                     :user_auth_tokens

  untrusted_attributes :bio_raw,
                       :bio_cooked,
                       :profile_background_upload_url,

  ###
  ### ATTRIBUTES
  ###

  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_associated_accounts?
    (object.id && object.id == scope.user.try(:id))
  end

  def include_second_factor_enabled?
    (object&.id == scope.user&.id) || scope.is_staff?
  end

  def second_factor_enabled
    object.totp_enabled? || object.security_keys_enabled?
  end

  def include_second_factor_backup_enabled?
    object&.id == scope.user&.id
  end

  def second_factor_backup_enabled
    object.backup_codes_enabled?
  end

  def include_second_factor_remaining_backup_codes?
    (object&.id == scope.user&.id) && object.backup_codes_enabled?
  end

  def second_factor_remaining_backup_codes
    object.remaining_backup_codes
  end

  def can_change_bio
    !(SiteSetting.enable_sso && SiteSetting.sso_overrides_bio)
  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}") },
        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

  ###
  ### 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
    TagUser.lookup(object, :muted).joins(:tag).pluck('tags.name')
  end

  def tracked_tags
    TagUser.lookup(object, :tracking).joins(:tag).pluck('tags.name')
  end

  def watching_first_post_tags
    TagUser.lookup(object, :watching_first_post).joins(:tag).pluck('tags.name')
  end

  def watched_tags
    TagUser.lookup(object, :watching).joins(:tag).pluck('tags.name')
  end

  def muted_category_ids
    CategoryUser.lookup(object, :muted).pluck(:category_id)
  end

  def tracked_category_ids
    CategoryUser.lookup(object, :tracking).pluck(:category_id)
  end

  def watched_category_ids
    CategoryUser.lookup(object, :watching).pluck(:category_id)
  end

  def watched_first_post_category_ids
    CategoryUser.lookup(object, :watching_first_post).pluck(:category_id)
  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 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

end