mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-26 20:54:21 +01:00
Merge branch 'dev' for release 5.7.2
This commit is contained in:
commit
2d83e7a7f5
@ -1,5 +1,11 @@
|
|||||||
# Changelog Fab-manager
|
# Changelog Fab-manager
|
||||||
|
|
||||||
|
## v5.7.2 2023 February 24
|
||||||
|
|
||||||
|
- Fix a bug: unable to update recurrent events
|
||||||
|
- Fix a bug: invalid border color for slots
|
||||||
|
- Fix a bug: members can change/cancel their reservations
|
||||||
|
|
||||||
## v5.7.1 2023 February 20
|
## v5.7.1 2023 February 20
|
||||||
|
|
||||||
- Fix a bug: timezone is ignored while configuring calendar opening/closing time
|
- Fix a bug: timezone is ignored while configuring calendar opening/closing time
|
||||||
|
@ -23,10 +23,11 @@ module AvailabilityHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
# @param slot [Slot]
|
# @param slot [Slot]
|
||||||
|
# @param reservable [Machine]
|
||||||
# @param customer [User]
|
# @param customer [User]
|
||||||
def machines_slot_border_color(slot, customer = nil)
|
def machines_slot_border_color(slot, reservable = nil, customer = nil)
|
||||||
if slot.reserved?
|
if slot.reserved?(reservable)
|
||||||
slot.reserved_by?(customer&.id) ? IS_RESERVED_BY_CURRENT_USER : IS_FULL
|
slot.reserved_by?(customer&.id, [reservable]) ? IS_RESERVED_BY_CURRENT_USER : IS_FULL
|
||||||
else
|
else
|
||||||
MACHINE_COLOR
|
MACHINE_COLOR
|
||||||
end
|
end
|
||||||
|
@ -89,9 +89,9 @@ class Event::UpdateEventService
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
ef_attributes = file_attributes(base_event, occurrence, event_params)
|
|
||||||
e_params.merge(
|
e_params.merge(
|
||||||
event_files_attributes: ef_attributes
|
event_files_attributes: file_attributes(base_event, occurrence, event_params),
|
||||||
|
event_image_attributes: image_attributes(occurrence, event_params)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -137,5 +137,15 @@ class Event::UpdateEventService
|
|||||||
end
|
end
|
||||||
ef_attributes
|
ef_attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @param occurrence [Event]
|
||||||
|
# @param event_params [ActionController::Parameters]
|
||||||
|
def image_attributes(occurrence, event_params)
|
||||||
|
if event_params['event_image_attributes'].nil? || event_params['event_image_attributes']['id'].present?
|
||||||
|
{ id: occurrence.event_image&.id }
|
||||||
|
else
|
||||||
|
event_params['event_image_attributes']
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,7 +11,7 @@ class Slots::TitleService
|
|||||||
# @param reservables [Array<Machine, Space, Training, Event>]
|
# @param reservables [Array<Machine, Space, Training, Event>]
|
||||||
def call(slot, reservables = nil)
|
def call(slot, reservables = nil)
|
||||||
reservables = all_reservables(slot) if reservables.nil?
|
reservables = all_reservables(slot) if reservables.nil?
|
||||||
is_reserved = slot.reserved?
|
is_reserved = reservables.map { |r| slot.reserved?(r) }.reduce(:|)
|
||||||
is_reserved_by_user = slot.reserved_by?(@user&.id, reservables)
|
is_reserved_by_user = slot.reserved_by?(@user&.id, reservables)
|
||||||
|
|
||||||
name = reservables.map(&:name).join(', ')
|
name = reservables.map(&:name).join(', ')
|
||||||
@ -37,6 +37,7 @@ class Slots::TitleService
|
|||||||
end
|
end
|
||||||
|
|
||||||
# @param slot [Slot]
|
# @param slot [Slot]
|
||||||
|
# @return [Array<Machine, Space, Training, Event>]
|
||||||
def all_reservables(slot)
|
def all_reservables(slot)
|
||||||
slot.places.pluck('reservable_type', 'reservable_id').map { |r| r[0].classify.constantize.find(r[1]) }
|
slot.places.pluck('reservable_type', 'reservable_id').map { |r| r[0].classify.constantize.find(r[1]) }
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.slot_id slot.id
|
json.slot_id slot.id
|
||||||
json.can_modify slot.modifiable?(operator_role, @user&.id, reservable)
|
json.can_modify slot.modifiable?(operator_role, user&.id, reservable)
|
||||||
json.title Slots::TitleService.new(operator_role, @user).call(slot, [reservable])
|
json.title Slots::TitleService.new(operator_role, user).call(slot, [reservable])
|
||||||
json.start slot.start_at.iso8601
|
json.start slot.start_at.iso8601
|
||||||
json.end slot.end_at.iso8601
|
json.end slot.end_at.iso8601
|
||||||
json.is_reserved slot.reserved?(reservable)
|
json.is_reserved slot.reserved?(reservable)
|
||||||
@ -10,7 +10,7 @@ json.is_completed slot.full?(reservable)
|
|||||||
json.backgroundColor 'white'
|
json.backgroundColor 'white'
|
||||||
|
|
||||||
json.availability_id slot.availability_id
|
json.availability_id slot.availability_id
|
||||||
json.slots_reservations_ids Slots::ReservationsService.user_reservations(slot, @user, reservable)[:reservations]
|
json.slots_reservations_ids Slots::ReservationsService.user_reservations(slot, user, reservable)[:reservations]
|
||||||
|
|
||||||
json.tag_ids slot.availability.tag_ids
|
json.tag_ids slot.availability.tag_ids
|
||||||
json.tags slot.availability.tags do |t|
|
json.tags slot.availability.tags do |t|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.array!(@slots) do |slot|
|
json.array!(@slots) do |slot|
|
||||||
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: @machine
|
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: @machine, user: @customer
|
||||||
json.borderColor machines_slot_border_color(slot, @customer)
|
json.borderColor machines_slot_border_color(slot, @machine, @customer)
|
||||||
|
|
||||||
json.machine do
|
json.machine do
|
||||||
json.id @machine.id
|
json.id @machine.id
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.array!(@slots) do |slot|
|
json.array!(@slots) do |slot|
|
||||||
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: @space
|
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: @space, user: @customer
|
||||||
json.is_completed slot.full?
|
json.is_completed slot.full?
|
||||||
json.borderColor space_slot_border_color(slot)
|
json.borderColor space_slot_border_color(slot)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.array!(@slots) do |slot|
|
json.array!(@slots) do |slot|
|
||||||
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: slot.availability.trainings.first
|
json.partial! 'api/availabilities/slot', slot: slot, operator_role: @operator_role, reservable: slot.availability.trainings.first, user: @customer
|
||||||
json.borderColor trainings_events_border_color(slot.availability)
|
json.borderColor trainings_events_border_color(slot.availability)
|
||||||
|
|
||||||
json.is_completed slot.full?
|
json.is_completed slot.full?
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fab-manager",
|
"name": "fab-manager",
|
||||||
"version": "5.7.1",
|
"version": "5.7.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.",
|
"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": [
|
"keywords": [
|
||||||
"fablab",
|
"fablab",
|
||||||
|
134
test/integration/events/recurrence_update_test.rb
Normal file
134
test/integration/events/recurrence_update_test.rb
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Events; end
|
||||||
|
|
||||||
|
class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@admin = User.find_by(username: 'admin')
|
||||||
|
login_as(@admin, scope: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'update a recurrent event' do
|
||||||
|
# first create a recurrent event
|
||||||
|
name = 'Fablab party'
|
||||||
|
post '/api/events',
|
||||||
|
params: {
|
||||||
|
event: {
|
||||||
|
title: name,
|
||||||
|
event_image_attributes: {
|
||||||
|
attachment: fixture_file_upload('/files/event/Party.jpg')
|
||||||
|
},
|
||||||
|
description: 'Come party tonight at the fablab...',
|
||||||
|
start_date: 2.weeks.from_now,
|
||||||
|
end_date: 2.weeks.from_now,
|
||||||
|
all_day: false,
|
||||||
|
start_time: '18:00',
|
||||||
|
end_time: '23:29',
|
||||||
|
amount: 20,
|
||||||
|
category_id: 2,
|
||||||
|
recurrence: 'month',
|
||||||
|
recurrence_end_at: 2.weeks.from_now + 3.months
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headers: upload_headers
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_equal 201, response.status, response.body
|
||||||
|
assert_equal Mime[:json], response.content_type
|
||||||
|
|
||||||
|
# Check the events were correctly created
|
||||||
|
db_events = Event.where(title: name)
|
||||||
|
assert_equal 4, db_events.count
|
||||||
|
|
||||||
|
# Update all the events
|
||||||
|
event = db_events.first
|
||||||
|
new_title = 'Skateboard party'
|
||||||
|
new_descr = 'Come make a skateboard tonight at the Fablab'
|
||||||
|
new_image = '/files/event/Skateboard.jpg'
|
||||||
|
put "/api/events/#{event&.id}", params: {
|
||||||
|
event: {
|
||||||
|
title: new_title,
|
||||||
|
event_image_attributes: {
|
||||||
|
attachment: fixture_file_upload(new_image)
|
||||||
|
},
|
||||||
|
description: new_descr,
|
||||||
|
category_id: 1,
|
||||||
|
event_theme_ids: [1],
|
||||||
|
age_range_id: 1,
|
||||||
|
start_date: event&.availability&.start_at,
|
||||||
|
end_date: event&.availability&.end_at,
|
||||||
|
all_day: false,
|
||||||
|
start_time: '18:00',
|
||||||
|
end_time: '23:29',
|
||||||
|
amount: 20
|
||||||
|
},
|
||||||
|
edit_mode: 'all'
|
||||||
|
}, headers: upload_headers
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_response :success, response.body
|
||||||
|
assert_equal Mime[:json], response.content_type
|
||||||
|
|
||||||
|
# Check the events were correctly updated
|
||||||
|
res = json_response(response.body)
|
||||||
|
assert_equal 'update', res[:action]
|
||||||
|
assert_equal 4, res[:total]
|
||||||
|
assert_equal 4, res[:updated]
|
||||||
|
res[:details][:events].each do |res_event|
|
||||||
|
assert res_event[:status]
|
||||||
|
db_event = Event.find(res_event[:event][:id])
|
||||||
|
assert_equal new_title, db_event.title
|
||||||
|
assert_equal new_descr, db_event.description
|
||||||
|
assert_equal 1, db_event.category_id
|
||||||
|
assert_includes db_event.event_theme_ids, 1
|
||||||
|
assert_equal 1, db_event.age_range_id
|
||||||
|
assert FileUtils.compare_file(
|
||||||
|
File.join(ActionDispatch::IntegrationTest.fixture_path, new_image),
|
||||||
|
db_event.event_image.attachment.file.path
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update again but only the next events
|
||||||
|
event = Event.includes(:availability).where(title: new_title).order('availabilities.start_at').limit(2)[1]
|
||||||
|
put "/api/events/#{event&.id}", params: {
|
||||||
|
event: {
|
||||||
|
title: event.title,
|
||||||
|
description: event.description,
|
||||||
|
event_image_attributes: {
|
||||||
|
id: event.event_image.id
|
||||||
|
},
|
||||||
|
category_id: 2,
|
||||||
|
event_theme_ids: [1],
|
||||||
|
age_range_id: 1,
|
||||||
|
start_date: event.availability.start_at,
|
||||||
|
end_date: event.availability.end_at,
|
||||||
|
all_day: false,
|
||||||
|
start_time: '18:00',
|
||||||
|
end_time: '23:29',
|
||||||
|
amount: 20
|
||||||
|
},
|
||||||
|
edit_mode: 'next'
|
||||||
|
}.to_json, headers: default_headers
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_response :success, response.body
|
||||||
|
assert_equal Mime[:json], response.content_type
|
||||||
|
|
||||||
|
# Check the events were correctly updated
|
||||||
|
res = json_response(response.body)
|
||||||
|
assert_equal 'update', res[:action]
|
||||||
|
assert_equal 3, res[:total]
|
||||||
|
assert_equal 3, res[:updated]
|
||||||
|
res[:details][:events].each do |res_event|
|
||||||
|
assert res_event[:status]
|
||||||
|
db_event = Event.find(res_event[:event][:id])
|
||||||
|
assert_equal 2, db_event.category_id
|
||||||
|
assert FileUtils.compare_file(
|
||||||
|
File.join(ActionDispatch::IntegrationTest.fixture_path, new_image),
|
||||||
|
db_event.event_image.attachment.file.path
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -12,6 +12,7 @@ require 'sidekiq/testing'
|
|||||||
require 'minitest/reporters'
|
require 'minitest/reporters'
|
||||||
require 'helpers/invoice_helper'
|
require 'helpers/invoice_helper'
|
||||||
require 'helpers/archive_helper'
|
require 'helpers/archive_helper'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
VCR.configure do |config|
|
VCR.configure do |config|
|
||||||
config.cassette_library_dir = 'test/vcr_cassettes'
|
config.cassette_library_dir = 'test/vcr_cassettes'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user