Files
redux-scraper/app/models/domain/user.rb
2025-06-17 05:56:11 +00:00

206 lines
5.2 KiB
Ruby

# typed: strict
class Domain::User < ReduxApplicationRecord
extend T::Helpers
include AttrJsonRecordAliases
include HasCompositeToParam
include HasViewPrefix
include HasDescriptionHtmlForView
include HasTimestampsWithDueAt
include HasDomainType
self.table_name = "domain_users"
abstract!
class_attribute :class_has_created_posts,
:class_has_faved_posts,
:class_has_followed_users,
:class_has_followed_by_users,
:due_at_timestamp_fields
# Counter cache methods with fallbacks
sig { returns(Integer) }
def user_post_creations_count
super || user_post_creations.count
end
sig { returns(Integer) }
def user_post_favs_count
super || user_post_favs.count
end
sig { returns(Integer) }
def user_user_follows_from_count
super || user_user_follows_from.count
end
sig { returns(Integer) }
def user_user_follows_to_count
super || user_user_follows_to.count
end
sig(:final) { returns(T::Boolean) }
def has_created_posts?
class_has_created_posts.present?
end
sig(:final) { returns(T::Boolean) }
def has_faved_posts?
class_has_faved_posts.present?
end
sig(:final) { returns(T::Boolean) }
def has_followed_users?
class_has_followed_users.present?
end
sig(:final) { returns(T::Boolean) }
def has_followed_by_users?
class_has_followed_by_users.present?
end
sig { returns(String) }
def type
super
end
sig { params(value: String).returns(String) }
def type=(value)
super
end
after_save :set_names_for_search
sig { void }
def set_names_for_search
values = names_for_search_values
models = user_search_names.pluck(:name)
missing_values = values - models
extra_values = models - values
if missing_values.any?
::Domain::UserSearchName.upsert_all(
missing_values.map { |name| { user_id: id, name: name } },
unique_by: %i[user_id name],
)
end
if extra_values.any?
::Domain::UserSearchName.where(user_id: id, name: extra_values).delete_all
end
end
sig(:final) { returns(T::Array[String]) }
def names_for_search_values
names_for_search
.map { |name| name.downcase.strip }
.reject(&:blank?)
.uniq
.sort
end
attr_json :migrated_user_favs_at, :datetime
has_many :user_search_names,
class_name: "::Domain::UserSearchName",
inverse_of: :user,
dependent: :destroy
has_many :user_post_creations,
class_name: "::Domain::UserPostCreation",
inverse_of: :user,
dependent: :destroy
has_many :user_post_favs,
class_name: "::Domain::UserPostFav",
inverse_of: :user,
dependent: :destroy
has_many :user_user_follows_from,
class_name: "::Domain::UserUserFollow",
foreign_key: :from_id,
inverse_of: :from,
dependent: :destroy
has_many :user_user_follows_to,
class_name: "::Domain::UserUserFollow",
foreign_key: :to_id,
inverse_of: :to,
dependent: :destroy
has_many :posts, through: :user_post_creations, source: :post
has_many :faved_posts, through: :user_post_favs, source: :post
has_many :followed_users, through: :user_user_follows_from, source: :to
has_many :followed_by_users, through: :user_user_follows_to, source: :from
sig { params(klass: T.class_of(Domain::Post)).void }
def self.has_created_posts!(klass)
self.class_has_created_posts = klass
has_many :posts,
-> { order(klass.param_order_attribute => :desc) },
through: :user_post_creations,
source: :post,
class_name: klass.name
end
sig { params(klass: T.class_of(Domain::Post)).void }
def self.has_faved_posts!(klass)
self.class_has_faved_posts = klass
has_many :faved_posts,
-> { order(klass.param_order_attribute => :desc) },
through: :user_post_favs,
source: :post,
class_name: klass.name
end
sig { params(klass: T.class_of(Domain::User)).void }
def self.has_followed_users!(klass)
self.class_has_followed_users = klass
has_many :followed_users,
through: :user_user_follows_from,
source: :to,
class_name: klass.name
end
sig { params(klass: T.class_of(Domain::User)).void }
def self.has_followed_by_users!(klass)
self.class_has_followed_by_users = klass
has_many :followed_by_users,
through: :user_user_follows_to,
source: :from,
class_name: klass.name
end
has_one :avatar,
-> { order(created_at: :desc) },
class_name: "::Domain::UserAvatar",
inverse_of: :user
has_many :avatars,
class_name: "::Domain::UserAvatar",
inverse_of: :user,
dependent: :destroy
sig { abstract.returns(String) }
def account_status_for_view
end
sig { abstract.returns(T.nilable(String)) }
def external_url_for_view
end
sig { abstract.returns(T.nilable(String)) }
def name_for_view
end
sig { overridable.returns(T::Array[String]) }
def names_for_search
[]
end
end
# eager load all subclasses
Dir[Rails.root.join("app/models/domain/user/**/*.rb")].each do |file|
require_dependency file
end