Commit e8b9d427 authored by Robert Speicher's avatar Robert Speicher

Merge branch '208403-attachment-file-not-found' into 'master'

Ensure valid path is used by AttachmentUploader

See merge request gitlab-org/gitlab!26849
parents 5948981b 95abfc32
...@@ -11,4 +11,15 @@ class AttachmentUploader < GitlabUploader ...@@ -11,4 +11,15 @@ class AttachmentUploader < GitlabUploader
def dynamic_segment def dynamic_segment
File.join(model.class.underscore, mounted_as.to_s, model.id.to_s) File.join(model.class.underscore, mounted_as.to_s, model.id.to_s)
end end
def mounted_as
# Geo fails to sync attachments on Note, and LegacyDiffNotes with missing mount_point.
#
# See https://gitlab.com/gitlab-org/gitlab/-/issues/209752 for more details.
if model.class.underscore.include?('note')
super || 'attachment'
else
super
end
end
end end
---
title: Ensure valid mount point is used by attachments on notes
merge_request: 26849
author:
type: fixed
...@@ -63,7 +63,7 @@ describe API::Geo do ...@@ -63,7 +63,7 @@ describe API::Geo do
end end
end end
describe 'GET /geo/transfers/attachment/1' do describe 'GET /geo/transfers/attachment/:id' do
let(:note) { create(:note, :with_attachment) } let(:note) { create(:note, :with_attachment) }
let(:upload) { Upload.find_by(model: note, uploader: 'AttachmentUploader') } let(:upload) { Upload.find_by(model: note, uploader: 'AttachmentUploader') }
let(:transfer) { Gitlab::Geo::Replication::FileTransfer.new(:attachment, upload) } let(:transfer) { Gitlab::Geo::Replication::FileTransfer.new(:attachment, upload) }
...@@ -81,7 +81,7 @@ describe API::Geo do ...@@ -81,7 +81,7 @@ describe API::Geo do
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
end end
context 'attachment file exists' do context 'when attachment file exists' do
subject(:request) { get api("/geo/transfers/attachment/#{upload.id}"), headers: req_header } subject(:request) { get api("/geo/transfers/attachment/#{upload.id}"), headers: req_header }
it 'responds with 200 with X-Sendfile' do it 'responds with 200 with X-Sendfile' do
...@@ -95,13 +95,25 @@ describe API::Geo do ...@@ -95,13 +95,25 @@ describe API::Geo do
it_behaves_like 'with terms enforced' it_behaves_like 'with terms enforced'
end end
context 'attachment does not exist' do context 'when attachment does not exist' do
it 'responds with 404' do it 'responds with 404' do
get api("/geo/transfers/attachment/100000"), headers: not_found_req_header get api("/geo/transfers/attachment/100000"), headers: not_found_req_header
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
end end
context 'when attachment has mount_point nil' do
it 'responds with 200 with X-Sendfile' do
upload.update(mount_point: nil)
get api("/geo/transfers/attachment/#{upload.id}"), headers: req_header
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('application/octet-stream')
expect(response.headers['X-Sendfile']).to eq(note.attachment.path)
end
end
end end
describe 'GET /geo/transfers/avatar/1' do describe 'GET /geo/transfers/avatar/1' do
......
...@@ -149,10 +149,12 @@ describe Gitlab::BackgroundMigration::LegacyUploadMover, schema: :latest do ...@@ -149,10 +149,12 @@ describe Gitlab::BackgroundMigration::LegacyUploadMover, schema: :latest do
context 'when an upload belongs to a legacy_diff_note' do context 'when an upload belongs to a legacy_diff_note' do
let!(:merge_request) { create(:merge_request, source_project: project) } let!(:merge_request) { create(:merge_request, source_project: project) }
let!(:note) do let!(:note) do
create(:legacy_diff_note_on_merge_request, create(:legacy_diff_note_on_merge_request,
note: 'some note', project: project, noteable: merge_request) note: 'some note', project: project, noteable: merge_request)
end end
let(:legacy_upload) do let(:legacy_upload) do
create(:upload, :with_file, :attachment_upload, create(:upload, :with_file, :attachment_upload,
path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note) path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note)
...@@ -193,6 +195,17 @@ describe Gitlab::BackgroundMigration::LegacyUploadMover, schema: :latest do ...@@ -193,6 +195,17 @@ describe Gitlab::BackgroundMigration::LegacyUploadMover, schema: :latest do
it_behaves_like 'move error' it_behaves_like 'move error'
end end
context 'when upload has mount_point nil' do
let(:legacy_upload) do
create(:upload, :with_file, :attachment_upload,
path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note, mount_point: nil)
end
it_behaves_like 'migrates the file correctly'
it_behaves_like 'legacy local file'
it_behaves_like 'legacy upload deletion'
end
context 'when the file can be handled correctly' do context 'when the file can be handled correctly' do
it_behaves_like 'migrates the file correctly' it_behaves_like 'migrates the file correctly'
it_behaves_like 'legacy local file' it_behaves_like 'legacy local file'
......
...@@ -127,6 +127,36 @@ describe Upload do ...@@ -127,6 +127,36 @@ describe Upload do
expect(uploader.mounted_as).to eq(subject.send(:mount_point)) expect(uploader.mounted_as).to eq(subject.send(:mount_point))
expect(uploader.file).not_to be_nil expect(uploader.file).not_to be_nil
end end
context 'when upload has mount_point nil' do
context 'when an upload belongs to a note' do
it 'mounts it as attachment' do
project = create(:project, :legacy_storage)
merge_request = create(:merge_request, source_project: project)
note = create(:legacy_diff_note_on_merge_request, note: 'some note', project: project, noteable: merge_request)
subject = build(:upload, :with_file, :attachment_upload, model: note, mount_point: nil)
uploader = subject.retrieve_uploader
expect(uploader.upload).to eq(subject)
expect(uploader.path).to include('attachment')
expect(uploader.file).not_to be_nil
end
end
context 'when an upload does not belong to a note' do
it 'does not mount it as attachment' do
appearance = create(:appearance)
subject = build(:upload, :with_file, :attachment_upload, model: appearance, mount_point: nil)
uploader = subject.retrieve_uploader
expect(uploader.upload).to eq(subject)
expect(uploader.path).not_to include('attachment')
expect(uploader.file).not_to be_nil
end
end
end
end end
describe '#needs_checksum?' do describe '#needs_checksum?' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment