diff --git a/app/controllers/api/v1/upload_controller.rb b/app/controllers/api/v1/accounts/upload_controller.rb similarity index 82% rename from app/controllers/api/v1/upload_controller.rb rename to app/controllers/api/v1/accounts/upload_controller.rb index ad6b0b96c..4c54938b7 100644 --- a/app/controllers/api/v1/upload_controller.rb +++ b/app/controllers/api/v1/accounts/upload_controller.rb @@ -1,4 +1,4 @@ -class Api::V1::UploadController < Api::BaseController +class Api::V1::Accounts::UploadController < Api::V1::Accounts::BaseController def create file_blob = ActiveStorage::Blob.create_and_upload!( key: nil, diff --git a/app/javascript/dashboard/helper/specs/uploadHelper.spec.js b/app/javascript/dashboard/helper/specs/uploadHelper.spec.js index 11bb535f0..a31ff16bb 100644 --- a/app/javascript/dashboard/helper/specs/uploadHelper.spec.js +++ b/app/javascript/dashboard/helper/specs/uploadHelper.spec.js @@ -25,10 +25,10 @@ describe('#Upload Helpers', () => { axios.post.mockResolvedValueOnce(mockResponse); - const result = await uploadFile(mockFile); + const result = await uploadFile(mockFile, '1602'); expect(axios.post).toHaveBeenCalledWith( - '/api/v1/upload', + '/api/v1/accounts/1602/upload', expect.any(FormData), { headers: { 'Content-Type': 'multipart/form-data' } } ); diff --git a/app/javascript/dashboard/helper/uploadHelper.js b/app/javascript/dashboard/helper/uploadHelper.js index d2baa9e08..2a1b9d9cd 100644 --- a/app/javascript/dashboard/helper/uploadHelper.js +++ b/app/javascript/dashboard/helper/uploadHelper.js @@ -21,17 +21,25 @@ const HEADERS = { * @param {File} file - The file to be uploaded. It should be a File object (typically coming from a file input element). * @returns {Promise} A promise that resolves with the server's response when the upload is successful, or rejects if there's an error. */ -export async function uploadFile(file) { +export async function uploadFile(file, accountId) { // Create a new FormData instance. let formData = new FormData(); + if (!accountId) { + accountId = window.location.pathname.split('/')[3]; + } + // Append the file to the FormData instance under the key 'attachment'. formData.append('attachment', file); // Use axios to send a POST request to the upload endpoint. - const { data } = await axios.post(`/api/${API_VERSION}/upload`, formData, { - headers: HEADERS, - }); + const { data } = await axios.post( + `/api/${API_VERSION}/accounts/${accountId}/upload`, + formData, + { + headers: HEADERS, + } + ); return { fileUrl: data.file_url, diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 4993f304b..d67c7facd 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -138,8 +138,9 @@ class Rack::Attack end ## Prevent Abuse of attachment upload APIs ## - throttle('/api/v1/upload', limit: 60, period: 1.hour) do |req| - req.ip if req.path_without_extentions == '/api/v1/upload' && req.post? + throttle('/api/v1/accounts/:account_id/upload', limit: 60, period: 1.hour) do |req| + match_data = %r{/api/v1/accounts/(?\d+)/upload}.match(req.path) + match_data[:account_id] if match_data.present? end ## ----------------------------------------------- ## diff --git a/config/routes.rb b/config/routes.rb index 4748d18ca..424bfa630 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -217,13 +217,13 @@ Rails.application.routes.draw do post :reorder, on: :collection end end + + resources :upload, only: [:create] end end # end of account scoped api routes # ---------------------------------- - resources :upload, only: [:create] - namespace :integrations do resources :webhooks, only: [:create] end diff --git a/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb b/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb index 0cf41c6a2..e9858844a 100644 --- a/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb @@ -128,7 +128,7 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do expect(account.automation_rules.count).to eq(0) - post '/api/v1/upload', + post "/api/v1/accounts/#{account.id}/upload/", headers: administrator.create_new_auth_token, params: { attachment: file } @@ -163,13 +163,13 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do file_1 = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png') file_2 = fixture_file_upload(Rails.root.join('spec/assets/sample.png'), 'image/png') - post '/api/v1/upload', + post "/api/v1/accounts/#{account.id}/upload/", headers: administrator.create_new_auth_token, params: { attachment: file_1 } blob_1 = response.parsed_body - post '/api/v1/upload', + post "/api/v1/accounts/#{account.id}/upload/", headers: administrator.create_new_auth_token, params: { attachment: file_2 } diff --git a/spec/controllers/api/v1/accounts/macros_controller_spec.rb b/spec/controllers/api/v1/accounts/macros_controller_spec.rb index 20667b3e7..5fb8fb2b4 100644 --- a/spec/controllers/api/v1/accounts/macros_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/macros_controller_spec.rb @@ -129,7 +129,7 @@ RSpec.describe 'Api::V1::Accounts::MacrosController', type: :request do it 'Saves file in the macros actions to send an attachments' do file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png') - post '/api/v1/upload', + post "/api/v1/accounts/#{account.id}/upload/", headers: administrator.create_new_auth_token, params: { attachment: file } diff --git a/spec/controllers/api/v1/upload_controller_spec.rb b/spec/controllers/api/v1/upload_controller_spec.rb index 279257dc3..0a5e758a3 100644 --- a/spec/controllers/api/v1/upload_controller_spec.rb +++ b/spec/controllers/api/v1/upload_controller_spec.rb @@ -1,14 +1,14 @@ require 'rails_helper' -RSpec.describe 'Api::V1::UploadController', type: :request do - describe 'POST /api/v1/upload/' do +RSpec.describe 'Api::V1::Accounts::UploadController', type: :request do + describe 'POST /api/v1/account/1/upload/' do let(:account) { create(:account) } let(:user) { create(:user, account: account) } it 'uploads the image when authorized' do file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png') - post '/api/v1/upload/', + post "/api/v1/accounts/#{account.id}/upload/", headers: user.create_new_auth_token, params: { attachment: file } @@ -25,7 +25,7 @@ RSpec.describe 'Api::V1::UploadController', type: :request do it 'does not upload when un-authorized' do file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png') - post '/api/v1/upload/', + post "/api/v1/accounts/#{account.id}/upload/", headers: {}, params: { attachment: file }