Files
redux-scraper/app/models/domain/user/bluesky_user.rb
2025-08-13 08:20:32 +00:00

108 lines
2.4 KiB
Ruby

# typed: strict
class Domain::User::BlueskyUser < Domain::User
aux_table :bluesky
due_timestamp :scanned_profile_at, 3.years
due_timestamp :scanned_posts_at, 3.years
has_created_posts! Domain::Post::BlueskyPost
# TODO - when we scrape liked posts, add this back in
# has_faved_posts! Domain::Post::BlueskyPost
belongs_to :last_scan_log_entry, class_name: "HttpLogEntry", optional: true
belongs_to :last_posts_scan_log_entry,
class_name: "HttpLogEntry",
optional: true
enum :state,
{ ok: "ok", account_disabled: "account_disabled", error: "error" },
prefix: :state
validates :handle, presence: true
validates :did, presence: true
validates :state, presence: true
after_initialize { self.state ||= "ok" if new_record? }
after_commit :enqueue_initial_scan, on: :create
sig { override.returns([String, Symbol]) }
def self.param_prefix_and_attribute
["bsky", :handle]
end
sig { override.returns(String) }
def self.view_prefix
"bsky"
end
sig { override.returns(Domain::DomainType) }
def self.domain_type
Domain::DomainType::Bluesky
end
sig { override.returns(String) }
def description_html_base_domain
"bsky.app"
end
sig { override.returns(String) }
def site_name_for_view
"Bluesky"
end
sig { returns(String) }
def did!
T.must(did)
end
sig { override.returns(T.nilable(String)) }
def description_html_for_view
description
end
sig { override.returns(T::Array[String]) }
def names_for_search
[display_name, handle].compact
end
sig { override.returns(T.nilable(String)) }
def external_url_for_view
"https://bsky.app/profile/#{did}" if did.present?
end
sig { override.returns(T.nilable(String)) }
def name_for_view
display_name.present? ? display_name : "@#{handle}"
end
sig { override.returns(String) }
def account_status_for_view
"Active" # TODO: Implement proper status checking
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
private
sig { void }
def enqueue_initial_scan
# Only enqueue for valid users with proper DIDs and handles
return unless state_ok? && did.present? && handle.present?
# Enqueue the scan job to run immediately
Domain::Bluesky::Job::ScanUserJob.perform_later({ user: self })
end
end