150 lines
3.4 KiB
Ruby
150 lines
3.4 KiB
Ruby
# typed: strict
|
|
class Domain::Post::BlueskyPost < Domain::Post
|
|
aux_table :bluesky, allow_redefining: :title
|
|
|
|
belongs_to :first_seen_entry, class_name: "::HttpLogEntry", optional: true
|
|
|
|
has_multiple_files! Domain::PostFile::BlueskyPostFile
|
|
has_single_creator! Domain::User::BlueskyUser
|
|
has_faving_users! Domain::User::BlueskyUser
|
|
|
|
after_initialize { self.state ||= "ok" if new_record? }
|
|
|
|
enum :state,
|
|
{
|
|
ok: "ok",
|
|
removed: "removed",
|
|
scan_error: "scan_error",
|
|
file_error: "file_error",
|
|
},
|
|
prefix: "state"
|
|
|
|
validates :state, presence: true
|
|
validates :bluesky_id, presence: true
|
|
|
|
sig { override.returns([String, Symbol]) }
|
|
def self.param_prefix_and_attribute
|
|
["bsky", :bluesky_id]
|
|
end
|
|
|
|
sig { override.returns(String) }
|
|
def self.view_prefix
|
|
"bsky"
|
|
end
|
|
|
|
sig { override.returns(Symbol) }
|
|
def self.post_order_attribute
|
|
:bluesky_id
|
|
end
|
|
|
|
sig { override.returns(Domain::DomainType) }
|
|
def self.domain_type
|
|
Domain::DomainType::Bluesky
|
|
end
|
|
|
|
sig { override.returns(T.nilable(Domain::User)) }
|
|
def primary_creator_for_view
|
|
self.creator
|
|
end
|
|
|
|
sig { override.returns(T.nilable(T.any(String, Integer))) }
|
|
def domain_id_for_view
|
|
self.bluesky_id
|
|
end
|
|
|
|
sig { override.returns(T.nilable(Addressable::URI)) }
|
|
def external_url_for_view
|
|
handle = self.creator&.handle
|
|
if bluesky_id.present? && handle.present?
|
|
Addressable::URI.parse(
|
|
"https://bsky.app/profile/#{handle}/post/#{bluesky_id}",
|
|
)
|
|
end
|
|
end
|
|
|
|
sig { override.returns(T.nilable(Domain::PostFile)) }
|
|
def primary_file_for_view
|
|
self.files.first
|
|
end
|
|
|
|
sig { override.returns(T::Boolean) }
|
|
def pending_scan?
|
|
scanned_at.nil?
|
|
end
|
|
|
|
sig { override.returns(T.nilable(String)) }
|
|
def description_html_for_view
|
|
text
|
|
end
|
|
|
|
sig { override.returns(String) }
|
|
def description_html_base_domain
|
|
"bsky.app"
|
|
end
|
|
|
|
sig { override.returns(T.nilable(String)) }
|
|
def description_for_view
|
|
self.text
|
|
end
|
|
|
|
sig { override.returns(T.nilable(Integer)) }
|
|
def num_favorites_for_view
|
|
like_count
|
|
end
|
|
|
|
sig { override.returns(T.nilable(String)) }
|
|
def title
|
|
# Use first 50 characters of text as title, or a fallback
|
|
current_text = text
|
|
current_text.present? ? current_text.truncate(50) : "Bluesky Post"
|
|
end
|
|
|
|
sig { returns(T.nilable(String)) }
|
|
def status_for_view
|
|
case self.state
|
|
when "ok"
|
|
"OK"
|
|
when "removed"
|
|
"Removed"
|
|
when "scan_error"
|
|
"Scan error"
|
|
when "file_error"
|
|
"File error"
|
|
end
|
|
end
|
|
|
|
sig do
|
|
params(
|
|
at_uri: String,
|
|
creator: Domain::User::BlueskyUser,
|
|
first_seen_log_entry: T.nilable(HttpLogEntry),
|
|
).returns(Domain::Post::BlueskyPost)
|
|
end
|
|
def self.find_or_initialize_by_at_uri(
|
|
at_uri,
|
|
creator:,
|
|
first_seen_log_entry: nil
|
|
)
|
|
# Extract the record key (post ID) from AT URI
|
|
# e.g., "at://did:plc:abc123/app.bsky.feed.post/xyz789" -> "xyz789"
|
|
bluesky_id = at_uri.split("/").last
|
|
|
|
post =
|
|
Domain::Post::BlueskyPost.find_or_initialize_by(
|
|
bluesky_id: bluesky_id,
|
|
) do |post|
|
|
post.first_seen_entry = first_seen_log_entry
|
|
post.at_uri = at_uri
|
|
end
|
|
|
|
post.creator ||= creator
|
|
post
|
|
end
|
|
|
|
sig { override.returns(T.nilable(T::Array[TagForView])) }
|
|
def tags_for_view
|
|
return nil unless hashtags.present?
|
|
hashtags.map { |tag| TagForView.new(category: :general, value: tag) }
|
|
end
|
|
end
|