hummingbird-me/kitsu-server

View on GitHub
app/graphql/types/profile.rb

Summary

Maintainability
A
2 hrs
Test Coverage
B
80%
class Types::Profile < Types::BaseObject
  implements Types::Interface::WithTimestamps

  description 'A user profile on Kitsu'

  field :id, ID, null: false

  field :slug, String,
    null: true,
    description: 'The URL-friendly identifier for this profile'

  field :url, String,
    null: true,
    description: 'A fully qualified URL to the profile'

  def url
    "https://kitsu.app/users/#{object.slug || object.id}"
  end

  field :name, String,
    null: false,
    description:
      <<~DESCRIPTION.squish
        A non-unique publicly visible name for the profile.
        Minimum of 3 characters and any valid Unicode character
      DESCRIPTION

  image_field :avatar_image,
    method: :avatar,
    description: 'An avatar image to easily identify this profile'

  image_field :banner_image,
    method: :cover_image,
    description: 'A banner to display at the top of the profile'

  field :about, String,
    null: true,
    description: 'A short biographical blurb about this profile'

  field :waifu, Types::Character,
    null: true,
    description: 'The character this profile has declared as their waifu or husbando'

  field :waifu_or_husbando, String,
    null: true,
    description: <<~DESCRIPTION.squish
      The properly-gendered term for the user's waifu.
      This should normally only be 'Waifu' or 'Husbando' but some
      people are jerks, including the person who wrote this...
    DESCRIPTION

  field :pro_tier, Types::Enum::ProTier,
    null: true,
    description: 'The PRO level the user currently has'

  field :pro_message, String,
    null: true,
    description: 'The message this user has submitted to the Hall of Fame'

  field :location, String,
    null: true,
    description: "The user's general location"

  field :gender, String,
    null: true,
    description: 'What the user identifies as'

  field :birthday, GraphQL::Types::ISO8601Date,
    null: true,
    description: 'When the user was born'

  field :pinned_post, Types::Post,
    null: true,
    description: 'Post pinned to the user profile'

  field :stats, Types::ProfileStats,
    null: false,
    description: 'The different stats we calculate for this user.'

  def stats
    object
  end

  field :followers, Types::Profile.connection_type, null: false do
    description 'People that follow the user'
    argument :sort, Loaders::FollowsLoader.sort_argument, required: false
  end

  def followers(sort: [{ on: :created_at, direction: :desc }])
    Loaders::FollowsLoader.connection_for({
      find_by: :followed_id,
      sort: sort
    }, object.id).then do |follows|
      Loaders::RecordLoader.for(User, token: context[:token]).load_many(follows.map(&:follower_id))
    end
  end

  field :following, Types::Profile.connection_type, null: false do
    description 'People the user is following'
    argument :sort, Loaders::FollowsLoader.sort_argument, required: false
  end

  def following(sort: [{ on: :created_at, direction: :desc }])
    Loaders::FollowsLoader.connection_for({
      find_by: :follower_id,
      sort: sort
    }, object.id).then do |follows|
      Loaders::RecordLoader.for(User, token: context[:token]).load_many(follows.map(&:followed_id))
    end
  end

  field :posts, Types::Post.connection_type, null: false do
    description 'All posts this profile has made.'
    argument :sort, Loaders::PostsLoader.sort_argument, required: false
  end

  def posts(sort: [{ on: :created_at, direction: :asc }])
    Loaders::PostsLoader.connection_for({
      find_by: :user_id,
      sort: sort
    }, object.id)
  end

  field :comments, Types::Comment.connection_type,
    null: false,
    description: 'All comments to any post this user has made.'

  def comments
    Loaders::AssociationLoader.for(object.class, :comments).scope(object)
  end

  field :library, Types::Library,
    null: false,
    description: 'The user library of their media'

  def library
    object
  end

  field :library_events, Types::LibraryEvent.connection_type, null: false do
    description 'A list of library events for this user'

    argument :sort, Loaders::LibraryEventsLoader.sort_argument, required: false
    argument :kind, [Types::Enum::LibraryEventKind],
      required: false,
      default_value: LibraryEvent.kinds.keys,
      description: 'Will return all if not supplied'
  end

  def library_events(kind: nil, sort: [{ on: :created_at, direction: :asc }])
    filters = { kind: kind }.compact

    Loaders::LibraryEventsLoader.connection_for({
      find_by: :user_id,
      sort: sort,
      where: filters
    }, object.id)
  end

  field :site_links, Types::SiteLink.connection_type,
    null: true,
    description: 'Links to the user on other (social media) sites.'

  def site_links
    Loaders::AssociationLoader.for(object.class, :profile_links).scope(object)
  end

  field :media_reactions, Types::MediaReaction.connection_type, null: false do
    description 'Media reactions written by this user.'
    argument :sort, Loaders::MediaReactionsLoader.sort_argument, required: false
  end

  def media_reactions(sort: [{ on: :created_at, direction: :asc }])
    Loaders::MediaReactionsLoader.connection_for({
      find_by: :user_id,
      sort: sort
    }, object.id)
  end

  field :favorites, Types::Favorite.connection_type,
    null: false,
    description: 'Favorite media, characters, and people'

  def favorites
    Loaders::AssociationLoader.for(object.class, :favorites).scope(object)
  end

  field :wiki_submissions, Types::WikiSubmission.connection_type, null: false do
    description 'Wiki submissions created by this user'
    argument :sort, Loaders::WikiSubmissionsLoader.sort_argument, required: false
    argument :statuses, [Types::Enum::WikiSubmissionStatus],
      required: false,
      default_value: WikiSubmission.statuses.keys,
      description: 'Will return all if not supplied'
  end

  def wiki_submissions(statuses: nil, sort: [{ on: :created_at, direction: :asc }])
    Loaders::WikiSubmissionsLoader.connection_for({
      find_by: :user_id,
      sort: sort,
      where: { status: statuses }
    }, object.id)
  end

  field :reviews, Types::Review.connection_type, null: true do
    description 'Reviews created by this user'
    argument :sort, Loaders::WikiSubmissionsLoader.sort_argument, required: false
  end

  def reviews(sort: [{ on: :created_at, direction: :asc }])
    Loaders::ReviewsLoader.connection_for({
      find_by: :user_id,
      sort: sort
    }, object.id)
  end
end