Commit 451f9c6c authored by Igor Drozdov's avatar Igor Drozdov

Allow uploading up to 10 files

Currently, we can't upload multiple designs at once
It fixes the bug

Changelog: fixed
parent 7c76abc7
...@@ -27,10 +27,10 @@ RSpec.describe 'User uploads new design', :js do ...@@ -27,10 +27,10 @@ RSpec.describe 'User uploads new design', :js do
expect(page).to have_content('dk.png') expect(page).to have_content('dk.png')
end end
upload_design(gif_fixture, count: 2) upload_design([gif_fixture, logo_svg_fixture, big_image_fixture], count: 4)
expect(page).to have_selector('.js-design-list-item', count: 2) expect(page).to have_selector('.js-design-list-item', count: 4)
expect(page.all('.js-design-list-item').map(&:text)).to eq(['dk.png', 'banana_sample.gif']) expect(page.all('.js-design-list-item').map(&:text)).to eq(['dk.png', 'banana_sample.gif', 'logo_sample.svg', 'big-image.png'])
end end
end end
...@@ -50,8 +50,16 @@ RSpec.describe 'User uploads new design', :js do ...@@ -50,8 +50,16 @@ RSpec.describe 'User uploads new design', :js do
Rails.root.join('spec', 'fixtures', 'banana_sample.gif') Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
end end
def upload_design(fixture, count:) def logo_svg_fixture
attach_file(:upload_file, fixture, match: :first, make_visible: true) Rails.root.join('spec', 'fixtures', 'logo_sample.svg')
end
def big_image_fixture
Rails.root.join('spec', 'fixtures', 'big-image.png')
end
def upload_design(fixtures, count:)
attach_file(:upload_file, fixtures, multiple: true, match: :first, make_visible: true)
wait_for('designs uploaded') do wait_for('designs uploaded') do
issue.reload.designs.count == count issue.reload.designs.count == count
......
...@@ -270,7 +270,7 @@ func TestUploadHandlerForMultipleFiles(t *testing.T) { ...@@ -270,7 +270,7 @@ func TestUploadHandlerForMultipleFiles(t *testing.T) {
require.NoError(t, s.writer.Close()) require.NoError(t, s.writer.Close())
response := testUploadArtifacts(t, s.writer.FormDataContentType(), s.url, s.buffer) response := testUploadArtifacts(t, s.writer.FormDataContentType(), s.url, s.buffer)
require.Equal(t, http.StatusBadRequest, response.Code) require.Equal(t, http.StatusInternalServerError, response.Code)
} }
func TestUploadFormProcessing(t *testing.T) { func TestUploadFormProcessing(t *testing.T) {
......
...@@ -24,10 +24,12 @@ import ( ...@@ -24,10 +24,12 @@ import (
"gitlab.com/gitlab-org/gitlab/workhorse/internal/upload/exif" "gitlab.com/gitlab-org/gitlab/workhorse/internal/upload/exif"
) )
const maxFilesAllowed = 10
// ErrInjectedClientParam means that the client sent a parameter that overrides one of our own fields // ErrInjectedClientParam means that the client sent a parameter that overrides one of our own fields
var ( var (
ErrInjectedClientParam = errors.New("injected client parameter") ErrInjectedClientParam = errors.New("injected client parameter")
ErrMultipleFilesUploaded = errors.New("upload request contains more than one file") ErrTooManyFilesUploaded = fmt.Errorf("upload request contains more than %v files", maxFilesAllowed)
) )
var ( var (
...@@ -117,8 +119,8 @@ func rewriteFormFilesFromMultipart(r *http.Request, writer *multipart.Writer, pr ...@@ -117,8 +119,8 @@ func rewriteFormFilesFromMultipart(r *http.Request, writer *multipart.Writer, pr
} }
func (rew *rewriter) handleFilePart(ctx context.Context, name string, p *multipart.Part, opts *filestore.SaveFileOpts) error { func (rew *rewriter) handleFilePart(ctx context.Context, name string, p *multipart.Part, opts *filestore.SaveFileOpts) error {
if rew.filter.Count() > 0 { if rew.filter.Count() >= maxFilesAllowed {
return ErrMultipleFilesUploaded return ErrTooManyFilesUploaded
} }
multipartFiles.WithLabelValues(rew.filter.Name()).Inc() multipartFiles.WithLabelValues(rew.filter.Name()).Inc()
......
...@@ -27,6 +27,10 @@ func (s *SavedFileTracker) Count() int { ...@@ -27,6 +27,10 @@ func (s *SavedFileTracker) Count() int {
} }
func (s *SavedFileTracker) ProcessFile(_ context.Context, fieldName string, file *filestore.FileHandler, _ *multipart.Writer) error { func (s *SavedFileTracker) ProcessFile(_ context.Context, fieldName string, file *filestore.FileHandler, _ *multipart.Writer) error {
if _, ok := s.rewrittenFields[fieldName]; ok {
return fmt.Errorf("the %v field has already been processed", fieldName)
}
s.Track(fieldName, file.LocalPath) s.Track(fieldName, file.LocalPath)
return nil return nil
} }
......
...@@ -37,3 +37,14 @@ func TestSavedFileTracking(t *testing.T) { ...@@ -37,3 +37,14 @@ func TestSavedFileTracking(t *testing.T) {
require.Contains(t, rewrittenFields, "test") require.Contains(t, rewrittenFields, "test")
} }
func TestDuplicatedFileProcessing(t *testing.T) {
tracker := SavedFileTracker{}
file := &filestore.FileHandler{}
require.NoError(t, tracker.ProcessFile(context.Background(), "file", file, nil))
err := tracker.ProcessFile(context.Background(), "file", file, nil)
require.Error(t, err)
require.Equal(t, "the file field has already been processed", err.Error())
}
...@@ -35,8 +35,8 @@ func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, p ...@@ -35,8 +35,8 @@ func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, p
switch err { switch err {
case ErrInjectedClientParam: case ErrInjectedClientParam:
helper.CaptureAndFail(w, r, err, "Bad Request", http.StatusBadRequest) helper.CaptureAndFail(w, r, err, "Bad Request", http.StatusBadRequest)
case ErrMultipleFilesUploaded: case ErrTooManyFilesUploaded:
helper.CaptureAndFail(w, r, err, "Uploading multiple files is not allowed", http.StatusBadRequest) helper.CaptureAndFail(w, r, err, err.Error(), http.StatusBadRequest)
case http.ErrNotMultipart: case http.ErrNotMultipart:
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
case filestore.ErrEntityTooLarge: case filestore.ErrEntityTooLarge:
......
...@@ -260,10 +260,10 @@ func TestUploadingMultipleFiles(t *testing.T) { ...@@ -260,10 +260,10 @@ func TestUploadingMultipleFiles(t *testing.T) {
var buffer bytes.Buffer var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer) writer := multipart.NewWriter(&buffer)
_, err = writer.CreateFormFile("file", "my.file") for i := 0; i < 11; i++ {
require.NoError(t, err) _, err = writer.CreateFormFile(fmt.Sprintf("file %v", i), "my.file")
_, err = writer.CreateFormFile("file", "my.file") require.NoError(t, err)
require.NoError(t, err) }
require.NoError(t, writer.Close()) require.NoError(t, writer.Close())
httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer) httpRequest, err := http.NewRequest("PUT", "/url/path", &buffer)
...@@ -279,7 +279,7 @@ func TestUploadingMultipleFiles(t *testing.T) { ...@@ -279,7 +279,7 @@ func TestUploadingMultipleFiles(t *testing.T) {
HandleFileUploads(response, httpRequest, nilHandler, apiResponse, &testFormProcessor{}, opts) HandleFileUploads(response, httpRequest, nilHandler, apiResponse, &testFormProcessor{}, opts)
require.Equal(t, 400, response.Code) require.Equal(t, 400, response.Code)
require.Equal(t, "Uploading multiple files is not allowed\n", response.Body.String()) require.Equal(t, "upload request contains more than 10 files\n", response.Body.String())
} }
func TestUploadProcessingFile(t *testing.T) { func TestUploadProcessingFile(t *testing.T) {
......
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