FEATURE: Multisite support for S3 image stores (#6689)

* FEATURE: Multisite support for S3 image stores

* Use File.join to concatenate all paths & fix linting on multisite/s3_store_spec.rb
This commit is contained in:
Rishabh 2018-11-29 09:41:48 +05:30 committed by Guo Xiang Tan
parent 5db50d6cdc
commit 05a4f3fb51
4 changed files with 55 additions and 12 deletions

View File

@ -28,6 +28,10 @@ module FileStore
not_implemented not_implemented
end end
def upload_path
File.join("uploads", RailsMultisite::ConnectionManagement.current_db)
end
def has_been_uploaded?(url) def has_been_uploaded?(url)
not_implemented not_implemented
end end

View File

@ -32,10 +32,6 @@ module FileStore
"#{Discourse.asset_host}#{relative_base_url}" "#{Discourse.asset_host}#{relative_base_url}"
end end
def upload_path
"/uploads/#{RailsMultisite::ConnectionManagement.current_db}"
end
def relative_base_url def relative_base_url
"#{Discourse.base_uri}#{upload_path}" "#{Discourse.base_uri}#{upload_path}"
end end
@ -46,7 +42,7 @@ module FileStore
def download_url(upload) def download_url(upload)
return unless upload return unless upload
"#{relative_base_url}/#{upload.sha1}" File.join(relative_base_url, upload.sha1)
end end
def cdn_url(url) def cdn_url(url)
@ -68,7 +64,7 @@ module FileStore
end end
def get_path_for(type, upload_id, sha, extension) def get_path_for(type, upload_id, sha, extension)
"#{upload_path}/#{super(type, upload_id, sha, extension)}" File.join("/", upload_path, super(type, upload_id, sha, extension))
end end
def copy_file(file, path) def copy_file(file, path)
@ -90,7 +86,7 @@ module FileStore
end end
def public_dir def public_dir
"#{Rails.root}/public" File.join(Rails.root, "public")
end end
def tombstone_dir def tombstone_dir
@ -105,15 +101,13 @@ module FileStore
private private
def list_missing(model) def list_missing(model)
public_directory = "#{Rails.root}/public"
count = 0 count = 0
model.find_each do |upload| model.find_each do |upload|
# could be a remote image # could be a remote image
next unless upload.url =~ /^\/[^\/]/ next unless upload.url =~ /^\/[^\/]/
path = "#{public_directory}#{upload.url}" path = "#{public_dir}#{upload.url}"
bad = true bad = true
begin begin
bad = false if File.size(path) != 0 bad = false if File.size(path) != 0

View File

@ -41,9 +41,12 @@ module FileStore
# add a "content disposition" header for "attachments" # add a "content disposition" header for "attachments"
options[:content_disposition] = "attachment; filename=\"#{filename}\"" unless FileHelper.is_supported_image?(filename) options[:content_disposition] = "attachment; filename=\"#{filename}\"" unless FileHelper.is_supported_image?(filename)
# if this fails, it will throw an exception # if this fails, it will throw an exception
path.prepend(File.join(upload_path, "/")) if RailsMultisite::ConnectionManagement.current_db != "default"
path = @s3_helper.upload(file, path, options) path = @s3_helper.upload(file, path, options)
# return the upload url # return the upload url
"#{absolute_base_url}/#{path}" File.join(absolute_base_url, path)
end end
def remove_file(url, path) def remove_file(url, path)
@ -93,7 +96,7 @@ module FileStore
return url if SiteSetting.Upload.s3_cdn_url.blank? return url if SiteSetting.Upload.s3_cdn_url.blank?
schema = url[/^(https?:)?\/\//, 1] schema = url[/^(https?:)?\/\//, 1]
folder = @s3_helper.s3_bucket_folder_path.nil? ? "" : "#{@s3_helper.s3_bucket_folder_path}/" folder = @s3_helper.s3_bucket_folder_path.nil? ? "" : "#{@s3_helper.s3_bucket_folder_path}/"
url.sub("#{schema}#{absolute_base_url}/#{folder}", "#{SiteSetting.Upload.s3_cdn_url}/") url.sub(File.join("#{schema}#{absolute_base_url}", folder), File.join(SiteSetting.Upload.s3_cdn_url, "/"))
end end
def cache_avatar(avatar, user_id) def cache_avatar(avatar, user_id)

View File

@ -0,0 +1,42 @@
require 'rails_helper'
require 'file_store/s3_store'
RSpec.describe 'Multisite s3 uploads', type: :multisite do
let(:conn) { RailsMultisite::ConnectionManagement }
let(:uploaded_file) { file_from_fixtures("smallest.png") }
let(:upload) do
Fabricate(:upload, sha1: Digest::SHA1.hexdigest(File.read(uploaded_file)))
end
let(:s3_client) { Aws::S3::Client.new(stub_responses: true) }
let(:s3_helper) do
S3Helper.new(SiteSetting.s3_upload_bucket, '', client: s3_client)
end
let(:store) { FileStore::S3Store.new(s3_helper) }
context 'uploading to s3' do
before(:each) do
SiteSetting.s3_upload_bucket = "some-really-cool-bucket"
SiteSetting.s3_access_key_id = "s3-access-key-id"
SiteSetting.s3_secret_access_key = "s3-secret-access-key"
SiteSetting.enable_s3_uploads = true
end
describe "#store_upload" do
it "returns the correct url for default and second multisite db" do
expect(store.store_upload(uploaded_file, upload)).to eq(
"//#{SiteSetting.s3_upload_bucket}.s3.dualstack.us-east-1.amazonaws.com/original/1X/c530c06cf89c410c0355d7852644a73fc3ec8c04.png"
)
conn.with_connection('second') do
expect(store.store_upload(uploaded_file, upload)).to eq(
"//#{SiteSetting.s3_upload_bucket}.s3.dualstack.us-east-1.amazonaws.com/uploads/second/original/1X/c530c06cf89c410c0355d7852644a73fc3ec8c04.png"
)
end
end
end
end
end