166 lines
4.7 KiB
Ruby
166 lines
4.7 KiB
Ruby
# typed: strict
|
|
module Domain::Fa::PostsHelper
|
|
extend T::Sig
|
|
|
|
include ActionView::Helpers::DateHelper
|
|
include ActionView::Helpers::SanitizeHelper
|
|
include ActionView::Helpers::RenderingHelper
|
|
include ActionView::Helpers::TagHelper
|
|
|
|
sig { params(post: Domain::Fa::Post).returns(String) }
|
|
def post_state_string(post)
|
|
if post.have_file?
|
|
"file"
|
|
elsif post.scanned?
|
|
"scanned"
|
|
else
|
|
post.state || "unknown"
|
|
end
|
|
end
|
|
|
|
sig do
|
|
params(
|
|
params:
|
|
T.any(ActionController::Parameters, T::Hash[T.untyped, T.untyped]),
|
|
).returns(T.nilable(String))
|
|
end
|
|
def page_str(params)
|
|
if (params[:page] || 1).to_i > 1
|
|
"(page #{params[:page]})"
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
sig { params(post: Domain::Fa::Post).returns(T.nilable(HttpLogEntry)) }
|
|
def guess_scanned_http_log_entry(post)
|
|
HttpLogEntry.find_all_by_uri(
|
|
"https://www.furaffinity.net/view/#{post.fa_id}",
|
|
).first
|
|
end
|
|
|
|
sig { params(post: Domain::Fa::Post).returns(T.nilable(HttpLogEntry)) }
|
|
def guess_file_downloaded_http_log_entry(post)
|
|
if (uri = post.file_uri)
|
|
HttpLogEntry.find_all_by_uri(uri).first
|
|
end
|
|
end
|
|
|
|
sig { params(html: String).returns(String) }
|
|
def fa_post_description_sanitized(html)
|
|
fa_post_id_to_node = {}
|
|
fa_user_url_name_to_node = {}
|
|
|
|
sanitizer =
|
|
Sanitize.new(
|
|
elements: %w[br img b i span strong],
|
|
attributes: {
|
|
"span" => %w[style],
|
|
},
|
|
css: {
|
|
properties: %w[font-size color],
|
|
},
|
|
transformers: [
|
|
Kernel.lambda do |env|
|
|
# Only allow and transform FA links
|
|
if env[:node_name] == "a"
|
|
node = env[:node]
|
|
|
|
# by default, assume the host is www.furaffinity.net
|
|
href = node["href"]&.downcase || ""
|
|
href = "//" + href if href.match?(/^(www\.)?furaffinity\.net/)
|
|
uri =
|
|
begin
|
|
URI.parse(href)
|
|
rescue URI::InvalidURIError
|
|
nil
|
|
end
|
|
|
|
valid_type = !uri.is_a?(URI::MailTo)
|
|
next { node_whitelist: [node] } if uri.nil? || !valid_type
|
|
|
|
uri.host ||= "www.furaffinity.net"
|
|
uri.scheme ||= "https"
|
|
path = uri.path
|
|
|
|
fa_host_matcher = /^(www\.)?furaffinity\.net$/
|
|
fa_post_matcher = %r{^/view/(\d+)/?$}
|
|
fa_user_matcher = %r{^/user/(\w+)/?$}
|
|
|
|
if fa_host_matcher.match?(uri.host) && path
|
|
if match = path.match(fa_post_matcher)
|
|
fa_id = match[1].to_i
|
|
fa_post_id_to_node[fa_id] = node
|
|
next { node_whitelist: [node] }
|
|
elsif match = path.match(fa_user_matcher)
|
|
fa_url_name = match[1]
|
|
fa_user_url_name_to_node[fa_url_name] = node
|
|
next { node_whitelist: [node] }
|
|
end
|
|
end
|
|
|
|
# Don't allow any other links
|
|
node.replace(node.children)
|
|
end
|
|
end,
|
|
],
|
|
)
|
|
|
|
fragment = Nokogiri::HTML5.fragment(sanitizer.send(:preprocess, html))
|
|
sanitizer.node!(fragment)
|
|
|
|
if fa_post_id_to_node.any?
|
|
# Batch load posts and their titles, ensuring fa_post_ids are strings
|
|
posts_by_id =
|
|
Domain::Fa::Post.where(fa_id: fa_post_id_to_node.keys).index_by(&:fa_id)
|
|
|
|
# Replace the link text with post titles if available
|
|
fa_post_id_to_node.each do |fa_id, node|
|
|
if (post = posts_by_id[fa_id])
|
|
node.replace(
|
|
Nokogiri::HTML5.fragment(
|
|
render(
|
|
partial: "domain/fa/posts/description_inline_link_fa_post",
|
|
locals: {
|
|
post: post,
|
|
},
|
|
),
|
|
),
|
|
)
|
|
else
|
|
node.replace(node.children)
|
|
end
|
|
end
|
|
end
|
|
|
|
if fa_user_url_name_to_node.any?
|
|
# Batch load users and their names, ensuring fa_user_url_names are strings
|
|
users_by_url_name =
|
|
Domain::Fa::User
|
|
.where(url_name: fa_user_url_name_to_node.keys)
|
|
.includes(:avatar)
|
|
.index_by(&:url_name)
|
|
|
|
# Replace the link text with user names if available
|
|
fa_user_url_name_to_node.each do |fa_url_name, node|
|
|
if (user = users_by_url_name[fa_url_name])
|
|
node.replace(
|
|
Nokogiri::HTML5.fragment(
|
|
render(
|
|
partial: "domain/fa/posts/description_inline_link_fa_user",
|
|
locals: {
|
|
user: user,
|
|
},
|
|
),
|
|
),
|
|
)
|
|
else
|
|
node.replace(node.children)
|
|
end
|
|
end
|
|
end
|
|
|
|
raw fragment.to_html(preserve_newline: true)
|
|
end
|
|
end
|