132 lines
4.0 KiB
Ruby
132 lines
4.0 KiB
Ruby
# typed: false
|
|
module Domain::Fa::UsersHelper
|
|
extend T::Sig
|
|
|
|
def avatar_url(sha256, thumb: "32-avatar")
|
|
blob_path(HexUtil.bin2hex(sha256), format: "jpg", thumb: thumb)
|
|
end
|
|
|
|
def fa_user_avatar_path(user, thumb: nil)
|
|
if (sha256 = user.avatar&.file_sha256)
|
|
blob_path(HexUtil.bin2hex(sha256), format: "jpg", thumb: thumb)
|
|
else
|
|
# default / 'not found' avatar image
|
|
# "/blobs/9080fd4e7e23920eb2dccfe2d86903fc3e748eebb2e5aa8c657bbf6f3d941cdc/contents.jpg"
|
|
asset_path("user-circle.svg")
|
|
end
|
|
end
|
|
|
|
def sanitized_fa_user_profile_html(html)
|
|
# try to preload all the FA usernames in the profile
|
|
maybe_url_names =
|
|
Nokogiri
|
|
.HTML(html)
|
|
.css("a")
|
|
.flat_map do |node|
|
|
href = URI.parse(node["href"])
|
|
right_host = href.host.nil? || href.host == "www.furaffinity.net"
|
|
right_path = href.path =~ %r{/user/.+}
|
|
if right_host && right_path
|
|
[href]
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
.map { |href| href.path.split("/")[2]&.downcase }
|
|
|
|
preloaded_users =
|
|
Domain::Fa::User
|
|
.where(url_name: maybe_url_names)
|
|
.select(:id, :state, :state_detail, :log_entry_detail, :url_name)
|
|
.joins(:avatar)
|
|
.includes(:avatar)
|
|
.index_by(&:url_name)
|
|
|
|
raw Sanitize.fragment(
|
|
html,
|
|
elements: %w[br img b i span strong],
|
|
attributes: {
|
|
"span" => %w[style],
|
|
"a" => [],
|
|
},
|
|
css: {
|
|
properties: %w[font-size color],
|
|
},
|
|
transformers:
|
|
lambda do |env|
|
|
return unless env[:node_name] == "a"
|
|
node = env[:node]
|
|
href = URI.parse(node["href"])
|
|
unless href.host == nil || href.host == "www.furaffinity.net"
|
|
return
|
|
end
|
|
return unless href.path =~ %r{/user/.+}
|
|
url_name = href.path.split("/")[2]&.downcase
|
|
Sanitize.node!(
|
|
node,
|
|
{ elements: %w[a], attributes: { "a" => %w[href] } },
|
|
)
|
|
node["href"] = domain_fa_user_path(url_name)
|
|
node["class"] = "text-slate-200 underline decoration-slate-200 " +
|
|
"decoration-dashed decoration-dashed decoration-1"
|
|
|
|
whitelist = [node]
|
|
|
|
user =
|
|
preloaded_users[url_name] ||
|
|
Domain::Fa::User.find_by(url_name: url_name)
|
|
if user
|
|
img = Nokogiri::XML::Node.new("img", node.document)
|
|
img["class"] = "inline w-5"
|
|
img["src"] = fa_user_avatar_path(user, thumb: "32-avatar")
|
|
node.prepend_child(img)
|
|
whitelist << img
|
|
end
|
|
|
|
{ node_allowlist: whitelist }
|
|
end,
|
|
)
|
|
end
|
|
|
|
# TODO - remove this once we've migrated similarity scores to new user model
|
|
sig do
|
|
params(
|
|
user: Domain::User::FaUser,
|
|
limit: Integer,
|
|
exclude_followed_by: T.nilable(Domain::User::FaUser),
|
|
).returns(T::Array[Domain::User::FaUser])
|
|
end
|
|
def similar_users_by_followed(user, limit: 10, exclude_followed_by: nil)
|
|
factors = Domain::Factors::UserUserFollowToFactors.find_by(user: user)
|
|
return [] if factors.nil?
|
|
|
|
relation =
|
|
Domain::NeighborFinder
|
|
.find_neighbors(factors)
|
|
.limit(limit)
|
|
.includes(:user)
|
|
if exclude_followed_by
|
|
relation =
|
|
relation.where.not(
|
|
user_id: exclude_followed_by.followed_users.select(:to_id),
|
|
)
|
|
end
|
|
|
|
relation.map { |factor| factor.user }
|
|
end
|
|
|
|
def fa_user_account_status(user)
|
|
log_entry_id = user.log_entry_detail["last_user_page_id"]
|
|
return "unknown" if log_entry_id.nil?
|
|
log_entry = HttpLogEntry.find_by(id: log_entry_id)
|
|
return "unknown" if log_entry.nil?
|
|
parser =
|
|
Domain::Fa::Parser::Page.new(
|
|
log_entry.response.contents,
|
|
require_logged_in: false,
|
|
)
|
|
return "unknown" unless parser.probably_user_page?
|
|
parser.user_page.account_status
|
|
end
|
|
end
|