0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 01:10:43 +08:00
discourse/app/models/concerns/has_post_upload_references.rb
Jarek Radosz 8baf4d5d4c
DEV: Enable Style/RedundantSelf rubocop rule (#40098)
(to be enabled in the shared config)
2026-05-19 19:27:45 +02:00

148 lines
4.1 KiB
Ruby
Vendored

# frozen_string_literal: true
module HasPostUploadReferences
extend ActiveSupport::Concern
def link_post_uploads(fragments: nil)
upload_ids = []
each_upload_url(fragments: fragments) do |url, _, sha1|
upload = Upload.fetch_from(sha1:, url:)
# Link any video thumbnails
if SiteSetting.video_thumbnails_enabled && upload.present? &&
FileHelper.supported_video.include?(upload.extension&.downcase)
# Video thumbnails have the filename of the video file sha1 with a .png or .jpg extension.
# This is because at time of upload in the composer we don't know the topic/post id yet
# and there is no thumbnail info added to the markdown to tie the thumbnail to the topic/post after
# creation.
thumbnail =
Upload
.where("original_filename like ?", "#{upload.sha1}.%")
.order(id: :desc)
.first if upload.sha1.present?
if thumbnail.present?
upload_ids << thumbnail.id
handle_video_thumbnail(thumbnail) if respond_to?(:handle_video_thumbnail, true)
end
end
upload_ids << upload.id if upload.present?
end
upload_references =
upload_ids.map do |upload_id|
{
target_id: id,
target_type: self.class.name,
upload_id: upload_id,
created_at: Time.zone.now,
updated_at: Time.zone.now,
}
end
UploadReference.transaction do
UploadReference.where(target: self).delete_all
UploadReference.insert_all(upload_references) if upload_references.size > 0
if SiteSetting.secure_uploads?
Upload
.where(id: upload_ids, access_control_post_id: nil)
.where("id NOT IN (SELECT upload_id FROM custom_emojis)")
.update_all(access_control_post_id: access_control_post_id_for_upload)
end
end
end
def each_upload_url(fragments: nil, include_local_upload: true)
current_db = RailsMultisite::ConnectionManagement.current_db
upload_patterns = [
%r{/uploads/#{current_db}/},
%r{/original/},
%r{/optimized/},
%r{/uploads/short-url/[a-zA-Z0-9]+(\.[a-z0-9]+)?},
]
fragments ||= Nokogiri::HTML5.fragment(cooked)
selectors =
fragments.css(
"a/@href",
"img/@src",
"source/@src",
"track/@src",
"video/@poster",
"div/@data-video-src",
"div/@data-original-video-src",
)
links =
selectors
.map do |media|
src = media.value
next if src.blank?
if src.end_with?("/images/transparent.png") &&
(parent = media.parent)["data-orig-src"].present?
parent["data-orig-src"]
else
src
end
end
.compact
.uniq
links.each do |src|
src = src.split("?")[0]
if src.start_with?("upload://")
sha1 = Upload.sha1_from_short_url(src)
yield(src, nil, sha1)
next
end
if src.include?("/uploads/short-url/")
host =
begin
URI(src).host
rescue URI::Error
end
next if host.present? && host != Discourse.current_hostname
sha1 = Upload.sha1_from_short_path(src)
yield(src, nil, sha1)
next
end
next if upload_patterns.none? { |pattern| src =~ pattern }
next if Rails.configuration.multisite && src.exclude?(current_db)
src = "#{SiteSetting.force_https ? "https" : "http"}:#{src}" if src.start_with?("//")
if !Discourse.store.has_been_uploaded?(src) && !Upload.secure_uploads_url?(src) &&
!(include_local_upload && src =~ %r{\A/[^/]}i)
next
end
path =
begin
URI(
UrlHelper.unencode(GlobalSetting.cdn_url ? src.sub(GlobalSetting.cdn_url, "") : src),
)&.path
rescue URI::Error
end
next if path.blank?
sha1 =
if path.include? "optimized"
OptimizedImage.extract_sha1(path)
else
Upload.extract_sha1(path) || Upload.sha1_from_short_path(path)
end
yield(src, path, sha1)
end
end
end