diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ca497bdd..732dcac75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog Fab-manager +## v5.6.2 2023 January 9 + +- Improved fix_invoice_item task +- Improved test coverage +- Fix a bug: unable to set some dates for the events if user is in negative timezone +- Fix a bug: events are shown as over and unbookable, starting from midnight at the event end's day +- Fix a bug: updating a space/machine/event/training removes the image +- Fix a bug: cryptic error message when failed to create a manager +- Fix a bug: unable to restore accounting periods closed by a deleted admin +- Fix a bug: unable to build an accounting archive if the operator was deleted +- Fix a bug: unable to udpate an event category + ## v5.6.1 2023 January 6 - Fix a bug: allow decimal values for VAT rates diff --git a/app/controllers/api/events_controller.rb b/app/controllers/api/events_controller.rb index 12ccbf2c8..9937d63bc 100644 --- a/app/controllers/api/events_controller.rb +++ b/app/controllers/api/events_controller.rb @@ -95,7 +95,7 @@ class API::EventsController < API::ApiController :amount, :nb_total_places, :availability_id, :all_day, :recurrence, :recurrence_end_at, :category_id, :event_theme_ids, :age_range_id, event_theme_ids: [], - event_image_attributes: [:attachment], + event_image_attributes: %i[id attachment], event_files_attributes: %i[id attachment _destroy], event_price_categories_attributes: %i[id price_category_id amount _destroy], advanced_accounting_attributes: %i[code analytical_section]) diff --git a/app/controllers/api/machines_controller.rb b/app/controllers/api/machines_controller.rb index aabe63c92..4084bfab7 100644 --- a/app/controllers/api/machines_controller.rb +++ b/app/controllers/api/machines_controller.rb @@ -50,7 +50,7 @@ class API::MachinesController < API::ApiController def machine_params params.require(:machine).permit(:name, :description, :spec, :disabled, :machine_category_id, :plan_ids, :reservable, - plan_ids: [], machine_image_attributes: [:attachment], + plan_ids: [], machine_image_attributes: %i[id attachment], machine_files_attributes: %i[id attachment _destroy], advanced_accounting_attributes: %i[code analytical_section]) end diff --git a/app/controllers/api/spaces_controller.rb b/app/controllers/api/spaces_controller.rb index 4945ddb44..f155e1d81 100644 --- a/app/controllers/api/spaces_controller.rb +++ b/app/controllers/api/spaces_controller.rb @@ -50,7 +50,7 @@ class API::SpacesController < API::ApiController def space_params params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled, - space_image_attributes: [:attachment], + space_image_attributes: %i[id attachment], space_files_attributes: %i[id attachment _destroy], advanced_accounting_attributes: %i[code analytical_section]) end diff --git a/app/controllers/api/trainings_controller.rb b/app/controllers/api/trainings_controller.rb index ba7e78325..81b711ab3 100644 --- a/app/controllers/api/trainings_controller.rb +++ b/app/controllers/api/trainings_controller.rb @@ -76,7 +76,7 @@ class API::TrainingsController < API::ApiController def training_params params.require(:training) .permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, :disabled, - training_image_attributes: [:attachment], machine_ids: [], plan_ids: [], + training_image_attributes: %i[id attachment], machine_ids: [], plan_ids: [], advanced_accounting_attributes: %i[code analytical_section]) end end diff --git a/app/frontend/src/javascript/controllers/admin/members.js b/app/frontend/src/javascript/controllers/admin/members.js index 3123f74e5..6d6408f59 100644 --- a/app/frontend/src/javascript/controllers/admin/members.js +++ b/app/frontend/src/javascript/controllers/admin/members.js @@ -1262,7 +1262,7 @@ Application.Controllers.controller('NewManagerController', ['$state', '$scope', return $state.go('app.admin.members'); } , function (error) { - growl.error(_t('app.admin.admins_new.failed_to_create_manager') + JSON.stringify(error.data ? error.data : error)); + growl.error(_t('app.admin.manager_new.failed_to_create_manager') + JSON.stringify(error.data ? error.data : error)); console.error(error); } ); diff --git a/app/frontend/src/javascript/controllers/events.js.erb b/app/frontend/src/javascript/controllers/events.js.erb index 6969cb45a..48546ce18 100644 --- a/app/frontend/src/javascript/controllers/events.js.erb +++ b/app/frontend/src/javascript/controllers/events.js.erb @@ -162,6 +162,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' // Get the details for the current event (event's id is recovered from the current URL) $scope.event = eventPromise; + $scope.eventEndDateTime = moment(`${eventPromise.end_date}T${eventPromise.end_time}:00`); // the application global settings $scope.settings = settingsPromise; @@ -259,7 +260,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' $scope.isShowReserveEventButton = () => { return $scope.event.nb_free_places > 0 && !$scope.reserve.toReserve && - $scope.now.isBefore($scope.event.end_date) && + $scope.now.isBefore($scope.eventEndDateTime) && helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'event'); }; diff --git a/app/frontend/src/javascript/lib/api.ts b/app/frontend/src/javascript/lib/api.ts index 29c5374d6..b90cb27ce 100644 --- a/app/frontend/src/javascript/lib/api.ts +++ b/app/frontend/src/javascript/lib/api.ts @@ -18,7 +18,7 @@ export default class ApiLib { ...object, ...attachmentAttributes.reduce((a, name) => { return { ...a, [name]: null }; }, {}) } - }); + }, { dateWithTimezone: true }); attachmentAttributes.forEach((attr) => { data.delete(`${name}[${attr}]`); if (Array.isArray(object[attr])) { diff --git a/app/frontend/templates/events/show.html b/app/frontend/templates/events/show.html index dbfee4a87..ec362a3d5 100644 --- a/app/frontend/templates/events/show.html +++ b/app/frontend/templates/events/show.html @@ -173,7 +173,7 @@ -
+
{{ 'app.public.events_show.event_is_over' }} {{ 'app.public.events_show.thanks_for_coming' }} {{ 'app.public.events_show.view_event_list' }} diff --git a/app/models/accounting_period.rb b/app/models/accounting_period.rb index 39746142f..2d62d2703 100644 --- a/app/models/accounting_period.rb +++ b/app/models/accounting_period.rb @@ -12,7 +12,7 @@ class AccountingPeriod < ApplicationRecord before_create :compute_totals after_commit :archive_closed_data, on: [:create] - validates :start_at, :end_at, :closed_at, :closed_by, presence: true + validates :start_at, :end_at, :closed_at, presence: true validates_with DateRangeValidator validates_with DurationValidator validates_with PastPeriodValidator diff --git a/app/models/category.rb b/app/models/category.rb index 57e132569..687642d1e 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -12,17 +12,15 @@ class Category < ApplicationRecord after_update :update_statistic_subtype, if: :saved_change_to_name? after_destroy :remove_statistic_subtype - def create_statistic_subtype - index = StatisticIndex.where(es_type_key: 'event') - StatisticSubType.create!(statistic_types: index.first.statistic_types, key: slug, label: name) + index = StatisticIndex.find_by(es_type_key: 'event') + StatisticSubType.create!(statistic_types: index.statistic_types, key: slug, label: name) end def update_statistic_subtype - index = StatisticIndex.where(es_type_key: 'event') + index = StatisticIndex.find_by(es_type_key: 'event') subtype = StatisticSubType.joins(statistic_type_sub_types: :statistic_type) - .where(key: slug, statistic_types: { statistic_index_id: index.first.id }) - .first + .find_by(key: previous_changes[:name][0], statistic_types: { statistic_index_id: index.id }) subtype.label = name subtype.save! end diff --git a/app/views/api/age_ranges/index.json.jbuilder b/app/views/api/age_ranges/index.json.jbuilder index 234ca45fe..11c1ef223 100644 --- a/app/views/api/age_ranges/index.json.jbuilder +++ b/app/views/api/age_ranges/index.json.jbuilder @@ -1,6 +1,6 @@ -user_is_admin = (current_user and current_user.admin?) +# frozen_string_literal: true json.array!(@age_ranges) do |ar| json.extract! ar, :id, :name - json.related_to ar.events.count if user_is_admin + json.related_to ar.events.count if current_user&.admin? end diff --git a/app/workers/archive_worker.rb b/app/workers/archive_worker.rb index c7fb99124..d36857296 100644 --- a/app/workers/archive_worker.rb +++ b/app/workers/archive_worker.rb @@ -28,7 +28,7 @@ class ArchiveWorker end NotificationCenter.call type: :notify_admin_archive_complete, - receiver: User.find(period.closed_by), + receiver: User.where(id: period.closed_by)&.first, attached_object: period end diff --git a/lib/tasks/fablab/fix_invoice_items.rake b/lib/tasks/fablab/fix_invoice_items.rake index 5d4c1b91c..f1ed9abce 100644 --- a/lib/tasks/fablab/fix_invoice_items.rake +++ b/lib/tasks/fablab/fix_invoice_items.rake @@ -25,6 +25,8 @@ namespace :fablab do .or(InvoiceItem.where(object_id: nil)) .find_each do |ii| invoice = ii.invoice + next if ii.object_type == 'Error' + other_items = invoice.invoice_items.where.not(id: ii.id) puts "\e[4;33mFound an invalid InvoiceItem\e[0m" puts '==============================================' @@ -43,7 +45,10 @@ namespace :fablab do puts "Other item slots: #{oii.object.try(:slots)&.map { |s| "#{s.start_at} - #{s.end_at}" }}" print "\e[1;34m[ ? ]\e[0m Associate the item with #{oii.object_type} #{oii.object_id} ? (y/N) > " confirm = $stdin.gets.chomp - ii.update(object_id: oii.object_id, object_type: oii.object_type) if confirm == 'y' + if confirm == 'y' + ii.update(object_id: oii.object_id, object_type: oii.object_type) + break + end end ii.reload if ii.object_id.nil? || ii.object_type.nil? diff --git a/package.json b/package.json index 45aa16646..1a9f005a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.6.1", + "version": "5.6.2", "description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.", "keywords": [ "fablab", @@ -151,7 +151,7 @@ "ngUpload": "0.5", "ngtemplate-loader": "^2.1.0", "nvd3": "1.8", - "object-to-formdata": "^4.4.2", + "object-to-formdata": "https://github.com/sylvainbx/object-to-formdata.git#master", "phosphor-react": "^1.4.0", "process": "^0.11.10", "prop-types": "^15.7.2", diff --git a/test/fixtures/abuses.yml b/test/fixtures/abuses.yml index e69de29bb..0650fbce5 100644 --- a/test/fixtures/abuses.yml +++ b/test/fixtures/abuses.yml @@ -0,0 +1,10 @@ +abuse_1: + id: 1 + signaled_id: 1 + signaled_type: 'Project' + first_name: 'Jean' + last_name: 'Dupont' + email: 'jean.dupont@gmail.com' + message: 'Ce projet est offensant pour ma religion' + created_at: '2023-01-06 16:39:40.584472' + updated_at: '2023-01-06 16:39:40.584472' diff --git a/test/integration/abuses_test.rb b/test/integration/abuses_test.rb index ed417032f..8e5a6e0b4 100644 --- a/test/integration/abuses_test.rb +++ b/test/integration/abuses_test.rb @@ -3,19 +3,6 @@ require 'test_helper' class AbusesTest < ActionDispatch::IntegrationTest - # Called before every test method runs. Can be used - # to set up fixture information. - def setup - # Do nothing - end - - # Called after every test method runs. Can be used to tear - # down fixture information. - - def teardown - # Do nothing - end - # Abuse report test 'visitor report an abuse' do project = Project.take @@ -43,7 +30,9 @@ class AbusesTest < ActionDispatch::IntegrationTest assert_equal 'Project', abuse[:reporting][:signaled_type], 'signaled object type mismatch' # Check notifications were sent for every admins - notifications = Notification.where(notification_type_id: NotificationType.find_by_name('notify_admin_abuse_reported'), attached_object_type: 'Abuse', attached_object_id: abuse[:reporting][:id]) + notifications = Notification.where(notification_type_id: NotificationType.find_by_name('notify_admin_abuse_reported'), # rubocop:disable Rails/DynamicFindBy + attached_object_type: 'Abuse', + attached_object_id: abuse[:reporting][:id]) assert_not_empty notifications, 'no notifications were created' notified_users_ids = notifications.map(&:receiver_id) User.admins.each do |adm| @@ -69,6 +58,40 @@ class AbusesTest < ActionDispatch::IntegrationTest headers: default_headers assert_equal 422, response.status, response.body - assert_match /can't be blank/, response.body + assert_match(/can't be blank/, response.body) + end + + test 'admin list all abuses' do + login_as(User.admins.first, scope: :user) + + get '/api/abuses' + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the abuses + abuses = json_response(response.body) + assert_equal Abuse.count, abuses[:abuses].length + assert_not_nil abuses[:abuses].first[:id] + assert_not_nil abuses[:abuses].first[:signaled_type] + assert_not_nil abuses[:abuses].first[:signaled_id] + assert_not_nil abuses[:abuses].first[:first_name] + assert_not_nil abuses[:abuses].first[:last_name] + assert_not_nil abuses[:abuses].first[:email] + assert_not_nil abuses[:abuses].first[:message] + assert_not_nil abuses[:abuses].first[:created_at] + assert_not_nil abuses[:abuses].first[:signaled] + assert_not_nil abuses[:abuses].first[:signaled][:name] + assert_not_nil abuses[:abuses].first[:signaled][:slug] + assert_not_nil abuses[:abuses].first[:signaled][:published_at] + assert_not_nil abuses[:abuses].first[:signaled][:author] + end + + test 'admin delete an abuse' do + login_as(User.admins.first, scope: :user) + + delete '/api/abuses/1' + assert_response :success + assert_empty response.body end end diff --git a/test/integration/accounting_period_test.rb b/test/integration/accounting_period_test.rb index 3452ab6fb..8f68c0ea2 100644 --- a/test/integration/accounting_period_test.rb +++ b/test/integration/accounting_period_test.rb @@ -76,8 +76,8 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest end test 'admin tries to close today' do - start_at = Date.today.beginning_of_day.iso8601 - end_at = Date.today.end_of_day.iso8601 + start_at = DateTime.current.beginning_of_day.iso8601 + end_at = DateTime.current.end_of_day.iso8601 post '/api/accounting_periods', params: { @@ -110,6 +110,17 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest period_id = AccountingPeriod.first.id get "/api/accounting_periods/#{period_id}/archive" - assert_match /^attachment; filename=/, response.headers['Content-Disposition'] + assert_match(/^attachment; filename=/, response.headers['Content-Disposition']) + end + + test 'list all periods' do + get '/api/accounting_periods' + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the periods + periods = json_response(response.body) + assert_equal AccountingPeriod.count, periods.length end end diff --git a/test/integration/admins_test.rb b/test/integration/admins_test.rb index bd4e314ca..ccc505bf6 100644 --- a/test/integration/admins_test.rb +++ b/test/integration/admins_test.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'test_helper' + class AdminsTest < ActionDispatch::IntegrationTest # Called before every test method runs. Can be used # to set up fixture information. @@ -8,13 +10,6 @@ class AdminsTest < ActionDispatch::IntegrationTest login_as(@admin, scope: :user) end - # Called after every test method runs. Can be used to tear - # down fixture information. - - def teardown - # Do nothing - end - test 'create an admin' do post '/api/admins', params: { @@ -67,4 +62,10 @@ class AdminsTest < ActionDispatch::IntegrationTest admins[:admins][0][:profile_attributes][:user_avatar][:id], 'admin avatar does not match' end + + test 'admin cannot delete himself' do + delete "/api/admins/#{@admin.id}" + + assert_response :unauthorized + end end diff --git a/test/integration/age_ranges_test.rb b/test/integration/age_ranges_test.rb new file mode 100644 index 000000000..d79adf7bb --- /dev/null +++ b/test/integration/age_ranges_test.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'test_helper' + +class AgeRangesTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create an age range' do + post '/api/age_ranges', + params: { + name: '8 - 10 ans' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct age range was created + res = json_response(response.body) + range = AgeRange.where(id: res[:id]).first + assert_not_nil range, 'range was not created in database' + + assert_equal '8 - 10 ans', res[:name] + end + + test 'update an age range' do + patch '/api/age_ranges/1', + params: { + name: "Jusqu'à 17 ans" + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the age range was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal "Jusqu'à 17 ans", res[:name] + end + + test 'list all age ranges' do + get '/api/age_ranges' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + ranges = json_response(response.body) + assert_equal AgeRange.count, ranges.count + end + + test 'delete an age range' do + delete '/api/age_ranges/1' + assert_response :success + assert_empty response.body + end +end diff --git a/test/integration/categories_test.rb b/test/integration/categories_test.rb new file mode 100644 index 000000000..c27e4c2c7 --- /dev/null +++ b/test/integration/categories_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class CategoriesTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a category' do + post '/api/categories', + params: { + name: 'Workshop' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct category was created + res = json_response(response.body) + cat = Category.where(id: res[:id]).first + assert_not_nil cat, 'category was not created in database' + + assert_equal 'Workshop', res[:name] + end + + test 'update a category' do + patch '/api/categories/1', + params: { + name: 'Stage pratique' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the category was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'Stage pratique', res[:name] + end + + test 'list all categories' do + get '/api/categories' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + cats = json_response(response.body) + assert_equal Category.count, cats.count + end + + test 'delete a category' do + cat = Category.create!(name: 'delete me') + delete "/api/categories/#{cat.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + cat.reload + end + end +end diff --git a/test/integration/components_test.rb b/test/integration/components_test.rb new file mode 100644 index 000000000..edeec1d08 --- /dev/null +++ b/test/integration/components_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ComponentsTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a component' do + post '/api/components', + params: { + name: 'Wood' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct component was created + res = json_response(response.body) + comp = Component.where(id: res[:id]).first + assert_not_nil comp, 'component was not created in database' + + assert_equal 'Wood', res[:name] + end + + test 'update a component' do + patch '/api/components/1', + params: { + name: 'Silicon' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the component was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'Silicon', res[:name] + end + + test 'list all components' do + get '/api/components' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + comps = json_response(response.body) + assert_equal Component.count, comps.count + end + + test 'delete a component' do + comp = Component.create!(name: 'delete me') + delete "/api/components/#{comp.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + comp.reload + end + end +end diff --git a/test/integration/event_themes_test.rb b/test/integration/event_themes_test.rb new file mode 100644 index 000000000..1422be021 --- /dev/null +++ b/test/integration/event_themes_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class EventThemesTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create an event theme' do + post '/api/event_themes', + params: { + name: 'Cuisine' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct event theme was created + res = json_response(response.body) + theme = EventTheme.where(id: res[:id]).first + assert_not_nil theme, 'event theme was not created in database' + + assert_equal 'Cuisine', res[:name] + end + + test 'update an event theme' do + patch '/api/event_themes/1', + params: { + name: 'DIY' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the event theme was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'DIY', res[:name] + end + + test 'list all event themes' do + get '/api/event_themes' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + themes = json_response(response.body) + assert_equal EventTheme.count, themes.count + end + + test 'delete an event theme' do + theme = EventTheme.create!(name: 'delete me') + delete "/api/event_themes/#{theme.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + theme.reload + end + end +end diff --git a/test/integration/groups_test.rb b/test/integration/groups_test.rb new file mode 100644 index 000000000..77e85777c --- /dev/null +++ b/test/integration/groups_test.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'test_helper' + +class GroupsTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a group' do + post '/api/groups', + params: { + name: 'Strange people', + disabled: true + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct group was created + res = json_response(response.body) + group = Group.where(id: res[:id]).first + assert_not_nil group, 'group was not created in database' + + assert_equal 'Strange people', res[:name] + assert_equal true, res[:disabled] + end + + test 'update a group' do + patch '/api/groups/1', + params: { + name: 'Normal people' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the group was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'Normal people', res[:name] + end + + test 'list all groups' do + get '/api/groups' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + groups = json_response(response.body) + assert_equal Group.count, groups.count + end + + test 'delete a group' do + group = Group.create!(name: 'delete me') + delete "/api/groups/#{group.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + group.reload + end + end + + test 'unable to delete a used group' do + delete '/api/groups/1' + assert_response :forbidden + assert_not_nil Group.find(1) + end +end diff --git a/test/integration/prepaid_packs_test.rb b/test/integration/prepaid_packs_test.rb new file mode 100644 index 000000000..b161ab915 --- /dev/null +++ b/test/integration/prepaid_packs_test.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'test_helper' + +class PrepaidPacksTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a prepaid pack' do + post '/api/prepaid_packs', + params: { + pack: { + priceable_id: 1, + priceable_type: 'Machine', + group_id: 1, + amount: 10, + minutes: 120, + validity_count: 1, + validity_interval: 'month' + } + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct prepaid pack was created + res = json_response(response.body) + pack = PrepaidPack.where(id: res[:id]).first + assert_not_nil pack, 'prepaid pack was not created in database' + + assert_equal 1, res[:priceable_id] + assert_equal 'Machine', res[:priceable_type] + assert_equal 1, res[:group_id] + assert_equal 10, res[:amount] + assert_equal 120, res[:minutes] + assert_equal 1, res[:validity_count] + assert_equal 'month', res[:validity_interval] + end + + test 'update a prepaid pack' do + patch '/api/prepaid_packs/1', + params: { + pack: { + amount: 20 + } + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the prepaid pack was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 20, res[:amount] + end + + test 'list all prepaid packs' do + get '/api/prepaid_packs' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + pack = json_response(response.body) + assert_equal PrepaidPack.count, pack.count + end + + test 'delete prepaid pack' do + pack = PrepaidPack.create!(priceable_type: 'Machine', priceable_id: 2, group_id: 2, amount: 100, minutes: 240) + delete "/api/prepaid_packs/#{pack.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + pack.reload + end + end + + test 'cannot delete an used prepaid pack' do + delete '/api/prepaid_packs/1' + assert_response :forbidden + assert_not_nil PrepaidPack.find(1) + end +end diff --git a/test/integration/tags_test.rb b/test/integration/tags_test.rb new file mode 100644 index 000000000..39abed9f6 --- /dev/null +++ b/test/integration/tags_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class TagsTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a tag' do + post '/api/tags', + params: { + name: 'Atelier coco' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct tag was created + res = json_response(response.body) + tag = Tag.where(id: res[:id]).first + assert_not_nil tag, 'tag was not created in database' + + assert_equal 'Atelier coco', res[:name] + end + + test 'update a tag' do + patch '/api/tags/1', + params: { + name: 'Hardcore bidouilleurs' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the tag was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'Hardcore bidouilleurs', res[:name] + end + + test 'list all tags' do + get '/api/tags' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + tags = json_response(response.body) + assert_equal Tag.count, tags.count + end + + test 'delete a tag' do + tag = Tag.create!(name: 'delete me') + delete "/api/tags/#{tag.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + tag.reload + end + end +end diff --git a/test/integration/themes_test.rb b/test/integration/themes_test.rb new file mode 100644 index 000000000..94226b6e4 --- /dev/null +++ b/test/integration/themes_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ThemesTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'create a theme' do + post '/api/themes', + params: { + name: 'Cuisine' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 201, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the correct tag was created + res = json_response(response.body) + theme = Theme.where(id: res[:id]).first + assert_not_nil theme, 'theme was not created in database' + + assert_equal 'Cuisine', res[:name] + end + + test 'update a theme' do + patch '/api/themes/1', + params: { + name: 'Objets de la maison' + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the tag was updated + res = json_response(response.body) + assert_equal 1, res[:id] + assert_equal 'Objets de la maison', res[:name] + end + + test 'list all themes' do + get '/api/themes' + + # Check response format & status + assert_equal 200, response.status, response.body + assert_equal Mime[:json], response.content_type + + # Check the list items are ok + themes = json_response(response.body) + assert_equal Theme.count, themes.count + end + + test 'delete a theme' do + theme = Theme.create!(name: 'delete me') + delete "/api/themes/#{theme.id}" + assert_response :success + assert_empty response.body + assert_raise ActiveRecord::RecordNotFound do + theme.reload + end + end +end diff --git a/yarn.lock b/yarn.lock index b63e8d438..43654e7c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8311,10 +8311,9 @@ object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-to-formdata@^4.4.2: +"object-to-formdata@https://github.com/sylvainbx/object-to-formdata.git#master": version "4.4.2" - resolved "https://registry.yarnpkg.com/object-to-formdata/-/object-to-formdata-4.4.2.tgz#f89013f90493c58cb5f6ab9f50b7aeec30745ea6" - integrity sha512-fu6UDjsqIfFUu/B3GXJ2IFnNAL/YbsC1PPzqDIFXcfkhdYjTD3K4zqhyD/lZ6+KdP9O/64YIPckIOiS5ouXwLA== + resolved "https://github.com/sylvainbx/object-to-formdata.git#4c00be9626e64653e0e2fdfbefca99b3fb3de511" object.assign@^4.1.0, object.assign@^4.1.2: version "4.1.2"