From 34e110430c80af56c5bef05c0b5d63728af34d52 Mon Sep 17 00:00:00 2001 From: Philipe Leandro Date: Sun, 5 Nov 2023 18:26:37 -0300 Subject: [PATCH 1/3] Add endpoint to upload file --- .../api/v1/handle_file_controller.rb | 12 ++++++++++ app/helpers/handle_file_helper.rb | 24 +++++++++++++++++++ config/application.rb | 1 + config/routes.rb | 1 + 4 files changed, 38 insertions(+) create mode 100644 app/controllers/api/v1/handle_file_controller.rb create mode 100644 app/helpers/handle_file_helper.rb diff --git a/app/controllers/api/v1/handle_file_controller.rb b/app/controllers/api/v1/handle_file_controller.rb new file mode 100644 index 0000000..9ce50e5 --- /dev/null +++ b/app/controllers/api/v1/handle_file_controller.rb @@ -0,0 +1,12 @@ +module Api + module V1 + class HandleFileController < Api::ApplicationController + include HandleFileHelper + + def import + rows = set_rows_to_json(params[:file].tempfile) + render json: {file_rows: rows}, status: :ok + end + end + end +end \ No newline at end of file diff --git a/app/helpers/handle_file_helper.rb b/app/helpers/handle_file_helper.rb new file mode 100644 index 0000000..df74648 --- /dev/null +++ b/app/helpers/handle_file_helper.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +require 'csv' + +module HandleFileHelper + def set_rows_to_json(file) + file_parsed = parse_file_csv(file) + set_response(file_parsed) + end + + def parse_file_csv(file) + CSV.parse(file.read) + end + + def encode_string(string) + string.force_encoding("ISO-8859-1").encode("UTF-8") + end + + def set_response(parsed_file) + json_response = {} + parsed_file.each_with_index { |row,index| json_response.merge!("row_#{index + 1}": encode_string(row.join(','))) } + + json_response + end +end diff --git a/config/application.rb b/config/application.rb index 287432d..2c1bbbd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -3,6 +3,7 @@ require_relative "boot" require "rails/all" +require "csv" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. diff --git a/config/routes.rb b/config/routes.rb index c365fed..52b6b14 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,7 @@ namespace :v1 do get "/public_method", to: "hello_world#public_method" get "/private_method", to: "hello_world#private_method" + post "/import", to: "handle_file#import" resources :users, only: [:index] end From cc92f7801368053f8ce3f1bcda001e968034635c Mon Sep 17 00:00:00 2001 From: Lucas Leandro Date: Tue, 17 Dec 2024 21:11:08 -0300 Subject: [PATCH 2/3] initial tests csv --- Gemfile | 2 + spec/fixtures/files/empty_file.csv | 0 spec/fixtures/files/non_csv_file.txt | 0 spec/fixtures/files/valid_file.csv | 3 ++ spec/requests/api/v1/handle_file_spec.rb | 57 ++++++++++++++++++++++++ spec/requests/api/v1/hello_word_spec.rb | 2 +- 6 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/files/empty_file.csv create mode 100644 spec/fixtures/files/non_csv_file.txt create mode 100644 spec/fixtures/files/valid_file.csv create mode 100644 spec/requests/api/v1/handle_file_spec.rb diff --git a/Gemfile b/Gemfile index e5b5eb6..291de7c 100644 --- a/Gemfile +++ b/Gemfile @@ -96,6 +96,8 @@ group :development do # Speed up commands on slow machines / big apps [https://github.com/rails/spring] gem "spring" + + gem 'graphiql-rails' end group :test do diff --git a/spec/fixtures/files/empty_file.csv b/spec/fixtures/files/empty_file.csv new file mode 100644 index 0000000..e69de29 diff --git a/spec/fixtures/files/non_csv_file.txt b/spec/fixtures/files/non_csv_file.txt new file mode 100644 index 0000000..e69de29 diff --git a/spec/fixtures/files/valid_file.csv b/spec/fixtures/files/valid_file.csv new file mode 100644 index 0000000..cfa01ee --- /dev/null +++ b/spec/fixtures/files/valid_file.csv @@ -0,0 +1,3 @@ +name,age +Alice,30 +Bob,25 \ No newline at end of file diff --git a/spec/requests/api/v1/handle_file_spec.rb b/spec/requests/api/v1/handle_file_spec.rb new file mode 100644 index 0000000..67078d6 --- /dev/null +++ b/spec/requests/api/v1/handle_file_spec.rb @@ -0,0 +1,57 @@ +require "rails_helper" + +RSpec.describe "HandleFiles" do + describe 'POST api/v1/import' do + context 'when CSV file is valid' do + let(:csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'valid_file.csv'), 'text/csv') } + + it 'returns status ok' do + post '/api/v1/import', params: { file: csv_file } + + + expect(response).to have_http_status(:ok) + end + + it 'returns the correct JSON response with file rows' do + post '/api/v1/import', params: { file: csv_file } + + + expect(JSON.parse(response.body)['file_rows']).to be_a(Hash) + end + end + + + context 'when CSV file is empty' do + let(:empty_csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'empty_file.csv'), 'text/csv') } + + it 'returns status ok' do + post '/api/v1/import', params: { file: empty_csv_file } + + expect(response).to have_http_status(:ok) + end + + it 'returns empty file rows in JSON' do + post '/api/v1/import', params: { file: empty_csv_file } + + expect(JSON.parse(response.body)['file_rows']).to be_empty + end + end + + context 'when file is not a CSV' do + let(:non_csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'non_csv_file.txt'), 'text/csv') } + + it 'returns an error status' do + post '/api/v1/import', params: { file: non_csv_file } + + expect(response).to have_http_status(:unprocessable_entity) + end + + it 'returns an error message' do + post '/api/v1/import', params: { file: non_csv_file } + + expect(response.body).to include('Invalid file type') + end + end + end +end + diff --git a/spec/requests/api/v1/hello_word_spec.rb b/spec/requests/api/v1/hello_word_spec.rb index 93df43b..d0022a1 100644 --- a/spec/requests/api/v1/hello_word_spec.rb +++ b/spec/requests/api/v1/hello_word_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "rails_helper" +require 'rails_helper' RSpec.describe "HelloWorlds" do describe "GET /api/v1/public_method" do From fa2b75e4dbb8f8035fa2b3c6f1662b16ac86f527 Mon Sep 17 00:00:00 2001 From: Lucas Leandro Date: Wed, 18 Dec 2024 21:44:02 -0300 Subject: [PATCH 3/3] tests csv --- .ruby-version | 1 + backend/config/routes.rb | 3 ++ .../spec/requests/api/v1/handle_file_spec.rb | 30 +++++++------------ 3 files changed, 15 insertions(+), 19 deletions(-) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..bea438e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.3.1 diff --git a/backend/config/routes.rb b/backend/config/routes.rb index aa9596d..51497c9 100644 --- a/backend/config/routes.rb +++ b/backend/config/routes.rb @@ -18,6 +18,9 @@ namespace :api, defaults: { format: :json } do namespace :v1 do + get "/public_method", to: "hello_world#public_method" + get "/private_method", to: "hello_world#private_method" + post "/import", to: "handle_file#import" resources :users, only: %i[index create] resources :schools, only: %i[index] end diff --git a/backend/spec/requests/api/v1/handle_file_spec.rb b/backend/spec/requests/api/v1/handle_file_spec.rb index 67078d6..06dd747 100644 --- a/backend/spec/requests/api/v1/handle_file_spec.rb +++ b/backend/spec/requests/api/v1/handle_file_spec.rb @@ -7,15 +7,11 @@ it 'returns status ok' do post '/api/v1/import', params: { file: csv_file } - - expect(response).to have_http_status(:ok) end it 'returns the correct JSON response with file rows' do post '/api/v1/import', params: { file: csv_file } - - expect(JSON.parse(response.body)['file_rows']).to be_a(Hash) end end @@ -23,33 +19,29 @@ context 'when CSV file is empty' do let(:empty_csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'empty_file.csv'), 'text/csv') } - + it 'returns status ok' do post '/api/v1/import', params: { file: empty_csv_file } - expect(response).to have_http_status(:ok) end it 'returns empty file rows in JSON' do post '/api/v1/import', params: { file: empty_csv_file } - expect(JSON.parse(response.body)['file_rows']).to be_empty end end - context 'when file is not a CSV' do - let(:non_csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'non_csv_file.txt'), 'text/csv') } - - it 'returns an error status' do - post '/api/v1/import', params: { file: non_csv_file } - - expect(response).to have_http_status(:unprocessable_entity) + context "when CSV file is valid" do + let(:csv_file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'valid_file.csv'), 'text/csv') } + + it "returns status ok" do + post '/api/v1/import', params: { file: csv_file } + expect(response).to have_http_status(:ok) end - - it 'returns an error message' do - post '/api/v1/import', params: { file: non_csv_file } - - expect(response.body).to include('Invalid file type') + + it "returns the correct JSON response with file rows" do + post '/api/v1/import', params: { file: csv_file } + expect(response.body).to include('file_rows') end end end