limit creation of file_links to 20 at once

pull/10331/head
Christophe Bliard 3 years ago
parent 4722323d12
commit 0e99279bd5
No known key found for this signature in database
GPG Key ID: 2BC07603210C3FA4
  1. 4
      docs/api/apiv3/paths/work_package_file_links.yml
  2. 2
      lib/api/utilities/endpoints/bodied.rb
  3. 4
      modules/storages/config/locales/en.yml
  4. 50
      modules/storages/lib/api/v3/file_links/parse_create_params_service.rb
  5. 36
      modules/storages/spec/requests/api/v3/file_links/file_links_spec.rb

@ -12,8 +12,8 @@ post:
The request body must contain the generated storage token, and not the storage id. In addition, the request must The request body must contain the generated storage token, and not the storage id. In addition, the request must
send the origin file id and the stored meta data. send the origin file id and the stored meta data.
If there is already a link on the given work package with the same file id from the same storage, the previous Up to 20 file links can be submitted at once. If there is already a link on the given work package with the same
data is not overwritten. file id from the same storage, the previous data is not overwritten.
As it is possible to link folders from a storage to a work package, the _mimeType_ of this entity can be empty. As it is possible to link folders from a storage to a work package, the _mimeType_ of this entity can be empty.
parameters: parameters:

@ -84,7 +84,7 @@ module API
endpoint = self endpoint = self
-> do -> do
request = self # proc is executed in the context of the request request = self # proc is executed in the context of the grape request
endpoint.before_hook&.(request: request) endpoint.before_hook&.(request: request)
params = endpoint.parse(request) params = endpoint.parse(request)
call = endpoint.process(request, params) call = endpoint.process(request, params)

@ -25,6 +25,10 @@ en:
minimal_nextcloud_version_unmet: "does not meet minimal version requirements (must be Nextcloud 23 or higher)" minimal_nextcloud_version_unmet: "does not meet minimal version requirements (must be Nextcloud 23 or higher)"
not_nextcloud_server: "is not a Nextcloud server" not_nextcloud_server: "is not a Nextcloud server"
api_v3:
errors:
too_many_elements_created_at_once: "Too many elements created at once. Expected %{max} at most, got %{actual}."
storages: storages:
page_titles: page_titles:
project_settings: project_settings:

@ -28,28 +28,58 @@
module API::V3::FileLinks module API::V3::FileLinks
class ParseCreateParamsService < ::API::ParseResourceParamsService class ParseCreateParamsService < ::API::ParseResourceParamsService
MAX_ELEMENTS = 20
attr_reader :request_body
def call(request_body) def call(request_body)
@request_body = request_body
ServiceResult.new( ServiceResult.new(
success: true, success: true,
result: parse_elements(request_body) result: parse_elements
) )
end end
def parse_elements(request_body) private
request_body.dig("_embedded", "elements")
.tap { ensure_valid_elements(_1) } def parse_elements
.map do |params| assert_valid_elements
elements.map do |element|
API::V3::FileLinks::FileLinkRepresenter API::V3::FileLinks::FileLinkRepresenter
.new(Hashie::Mash.new, current_user: current_user) .new(Hashie::Mash.new, current_user: current_user)
.from_hash(params) .from_hash(element)
end end
end end
private def elements
@elements ||= request_body.dig("_embedded", "elements")
end
def assert_valid_elements
assert_elements_is_present
assert_elements_is_an_array
assert_elements_does_not_exceed_maximum
end
def assert_elements_is_present
return if elements.present?
raise API::Errors::PropertyMissingError.new('_embedded/elements')
end
def assert_elements_is_an_array
return if elements.is_a?(Array)
raise API::Errors::PropertyFormatError.new('_embedded/elements', 'Array', elements.class.name)
end
def assert_elements_does_not_exceed_maximum
return if elements.size <= MAX_ELEMENTS
def ensure_valid_elements(elements) raise API::Errors::Validation.new('_embedded/elements',
raise API::Errors::PropertyMissingError.new('_embedded/elements') if elements.blank? I18n.t('api_v3.errors.too_many_elements_created_at_once',
raise API::Errors::PropertyFormatError.new('_embedded/elements', 'Array', elements.class.name) unless elements.is_a?(Array) max: MAX_ELEMENTS, actual: elements.size))
end end
end end
end end

@ -183,6 +183,42 @@ describe 'API v3 file links resource', type: :request do
expected_format: 'Array', expected_format: 'Array',
actual: 'Integer') actual: 'Integer')
end end
# rubocop:disable RSpec/MultipleMemoizedHelpers
context "when more than #{API::V3::FileLinks::ParseCreateParamsService::MAX_ELEMENTS} embedded elements" do
let(:max) { API::V3::FileLinks::ParseCreateParamsService::MAX_ELEMENTS }
let(:too_many) { max + 1 }
let(:params) do
{
_type: "Collection",
_embedded: {
elements: 1.upto(too_many).map do |id|
{
originData: {
id: id,
name: "logo#{id}.png",
mimeType: "image/png",
createdAt: "2021-12-19T09:42:10.170Z",
lastModifiedAt: "2021-12-20T14:00:13.987Z",
createdByName: "Luke Skywalker",
lastModifiedByName: "Anakin Skywalker"
},
_links: {
storageUrl: {
href: storage_url1
}
}
}
end
}
}
end
it_behaves_like 'constraint violation' do
let(:message) { "Too many elements created at once. Expected #{max} at most, got #{too_many}." }
end
end
# rubocop:enable RSpec/MultipleMemoizedHelpers
end end
describe 'GET /api/v3/file_links/:file_link_id' do describe 'GET /api/v3/file_links/:file_link_id' do

Loading…
Cancel
Save