Files
redux-scraper/app/models/domain/user/fa_user.rb
2025-09-10 16:30:51 +00:00

197 lines
4.7 KiB
Ruby

# typed: strict
class Domain::User::FaUser < Domain::User
aux_table :fa
due_timestamp :scanned_gallery_at, 3.years
due_timestamp :scanned_page_at, 3.months
due_timestamp :scanned_follows_at, 3.months
due_timestamp :scanned_followed_by_at, 3.months
due_timestamp :scanned_incremental_at, 1.month
belongs_to :last_user_page_log_entry,
foreign_key: :last_user_page_id,
class_name: "::HttpLogEntry",
optional: true
belongs_to :last_gallery_page_log_entry,
foreign_key: :last_gallery_page_id,
class_name: "::HttpLogEntry",
optional: true
has_followed_users! Domain::User::FaUser
has_followed_by_users! Domain::User::FaUser
has_created_posts! Domain::Post::FaPost
has_faved_posts! Domain::Post::FaPost,
Domain::UserPostFav::FaUserPostFav,
fav_model_order: {
fa_fav_id: :desc,
}
enum :state,
{ ok: "ok", account_disabled: "account_disabled", error: "error" },
prefix: :state
validates :name, presence: true
validates :url_name, presence: true, uniqueness: true
validates :state, presence: true
# validates :account_status,
# inclusion: {
# in: %w[active suspended banned deceased],
# allow_nil: true,
# }
after_initialize { self.state ||= "ok" if new_record? }
sig { override.returns(T.class_of(Domain::UserPostFav)) }
def self.fav_model_type
Domain::UserPostFav::FaUserPostFav
end
sig { override.returns([String, Symbol]) }
def self.param_prefix_and_attribute
["fa", :url_name]
end
sig { returns(String) }
def sigil_for_view
case account_status
when "active"
"~"
when "suspended"
"!"
when "banned"
"-"
when "deceased"
""
when "admin"
"@"
else
"~"
end
end
sig { void }
def thing
Domain::User::FaUser.where(url_name: "test")
end
sig { override.returns(String) }
def self.view_prefix
"fa"
end
sig { override.returns(Domain::DomainType) }
def self.domain_type
Domain::DomainType::Fa
end
sig { override.returns(String) }
def description_html_base_domain
"furaffinity.net"
end
sig { override.returns(String) }
def site_name_for_view
"Furaffinity"
end
sig { override.returns(T.nilable(String)) }
def description_html_for_view
profile_html
end
sig { override.returns(T::Array[String]) }
def names_for_search
[name, url_name, full_name].compact
end
sig do
params(
submission_parser:
T.any(
Domain::Fa::Parser::ListedSubmissionParserHelper,
Domain::Fa::Parser::SubmissionParserHelper,
),
).returns(Domain::User::FaUser)
end
def self.find_or_build_from_submission_parser(submission_parser)
find_or_initialize_by(url_name: submission_parser.artist_url_name) do |user|
user.name = submission_parser.artist
end
end
sig do
params(
post_id: Integer,
fav_id: T.nilable(Integer),
explicit_time: T.nilable(Time),
).void
end
def update_fav_model(post_id:, fav_id: nil, explicit_time: nil)
attrs = { user_id: self.id, post_id: }
attrs[:fa_fav_id] = fav_id if fav_id.present?
attrs[:explicit_time] = explicit_time.in_time_zone if explicit_time.present?
Domain::UserPostFav::FaUserPostFav.upsert(
attrs,
unique_by: %i[user_id post_id],
)
self.user_post_favs.reset
end
# TODO - write a test for this
sig { override.returns(String) }
def account_status_for_view
as =
account_status ||
begin
if (hle = guess_last_user_page_log_entry)
parser =
Domain::Fa::Parser::Page.from_log_entry(
hle,
require_logged_in: false,
)
parser.user_page.account_status.to_s if parser.probably_user_page?
end
end || "unknown"
as.titlecase
end
sig { returns(String) }
def account_state_for_view
case state
when "ok"
"Ok"
when "account_disabled"
"Disabled"
when "error"
"Error"
else
"Unknown"
end
end
sig { returns(T.nilable(HttpLogEntry)) }
def guess_last_user_page_log_entry
last_user_page_log_entry ||
HttpLogEntry.find_by_uri_host_path(
"https://www.furaffinity.net/user/#{url_name}/",
) ||
HttpLogEntry.find_by_uri_host_path(
"https://www.furaffinity.net/user/#{url_name}",
)
end
sig { override.returns(T.nilable(String)) }
def external_url_for_view
"https://www.furaffinity.net/user/#{url_name}" if url_name.present?
end
sig { override.returns(T.nilable(String)) }
def name_for_view
name || url_name
end
end