-
{{ 'calendar.restrict_this_slot_with_labels_(optional)' }}
+
{{ 'admin_calendar.restrict_this_slot_with_labels_(optional)' }}
diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb
index 1c99961e5..3d3d31e99 100644
--- a/app/controllers/api/availabilities_controller.rb
+++ b/app/controllers/api/availabilities_controller.rb
@@ -10,7 +10,7 @@ class API::AvailabilitiesController < API::ApiController
authorize Availability
start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start])
end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day
- @availabilities = Availability.includes(:machines,:tags,:trainings).where.not(available_type: 'event')
+ @availabilities = Availability.includes(:machines, :tags, :trainings, :spaces).where.not(available_type: 'event')
.where('start_at >= ? AND end_at <= ?', start_date, end_date)
end
@@ -161,7 +161,7 @@ class API::AvailabilitiesController < API::ApiController
end
def availability_params
- params.require(:availability).permit(:start_at, :end_at, :available_type, :machine_ids, :training_ids, :nb_total_places, machine_ids: [], training_ids: [], tag_ids: [],
+ params.require(:availability).permit(:start_at, :end_at, :available_type, :machine_ids, :training_ids, :nb_total_places, machine_ids: [], training_ids: [], space_ids: [], tag_ids: [],
:machines_attributes => [:id, :_destroy])
end
diff --git a/app/helpers/availability_helper.rb b/app/helpers/availability_helper.rb
index 69ed58e29..2e6d789f2 100644
--- a/app/helpers/availability_helper.rb
+++ b/app/helpers/availability_helper.rb
@@ -1,18 +1,22 @@
module AvailabilityHelper
MACHINE_COLOR = '#e4cd78'
TRAINING_COLOR = '#bd7ae9'
+ SPACE_COLOR = '#3fc7ff'
EVENT_COLOR = '#dd7e6b'
IS_RESERVED_BY_CURRENT_USER = '#b2e774'
MACHINE_IS_RESERVED_BY_USER = '#1d98ec'
IS_COMPLETED = '#eeeeee'
def availability_border_color(availability)
- if availability.available_type == 'machines'
- MACHINE_COLOR
- elsif availability.available_type == 'training'
- TRAINING_COLOR
- else
- EVENT_COLOR
+ case availability.available_type
+ when 'machines'
+ MACHINE_COLOR
+ when 'training'
+ TRAINING_COLOR
+ when 'space'
+ SPACE_COLOR
+ else
+ EVENT_COLOR
end
end
diff --git a/app/models/availability.rb b/app/models/availability.rb
index 2b8b29c90..737e6174e 100644
--- a/app/models/availability.rb
+++ b/app/models/availability.rb
@@ -12,6 +12,9 @@ class Availability < ActiveRecord::Base
has_many :trainings_availabilities, dependent: :destroy
has_many :trainings, through: :trainings_availabilities
+ has_many :spaces_availabilities, dependent: :destroy
+ has_many :spaces, through: :spaces_availabilities
+
has_many :slots
has_many :reservations, through: :slots
@@ -23,6 +26,7 @@ class Availability < ActiveRecord::Base
scope :machines, -> { where(available_type: 'machines') }
scope :trainings, -> { includes(:trainings).where(available_type: 'training') }
+ scope :spaces, -> { includes(:spaces).where(available_type: 'space') }
attr_accessor :is_reserved, :slot_id, :can_modify
@@ -43,10 +47,18 @@ class Availability < ActiveRecord::Base
end
def safe_destroy
- if available_type == 'machines'
- reservations = Reservation.where(reservable_type: 'Machine', reservable_id: machine_ids).joins(:slots).where('slots.availability_id = ?', id)
- else
- reservations = Reservation.where(reservable_type: 'Training', reservable_id: training_ids).joins(:slots).where('slots.availability_id = ?', id)
+ case available_type
+ when 'machines'
+ reservations = Reservation.where(reservable_type: 'Machine', reservable_id: machine_ids).joins(:slots).where('slots.availability_id = ?', id)
+ when 'training'
+ reservations = Reservation.where(reservable_type: 'Training', reservable_id: training_ids).joins(:slots).where('slots.availability_id = ?', id)
+ when 'space'
+ reservations = Reservation.where(reservable_type: 'Space', reservable_id: space_ids).joins(:slots).where('slots.availability_id = ?', id)
+ when 'event'
+ reservations = Reservation.where(reservable_type: 'Event', reservable_id: event&.id).joins(:slots).where('slots.availability_id = ?', id)
+ else
+ STDERR.puts "[safe_destroy] Availability with unknown type #{available_type}"
+ reservations = []
end
if reservations.size == 0
# this update may not call any rails callbacks, that's why we use direct SQL update
@@ -58,15 +70,21 @@ class Availability < ActiveRecord::Base
end
def title(filter = {})
- if available_type == 'machines'
- if filter[:machine_ids]
- return machines.to_ary.delete_if {|m| !filter[:machine_ids].include?(m.id)}.map(&:name).join(' - ')
- end
- return machines.map(&:name).join(' - ')
- elsif available_type == 'event'
- event.name
- else
- trainings.map(&:name).join(' - ')
+ case available_type
+ when 'machines'
+ if filter[:machine_ids]
+ return machines.to_ary.delete_if {|m| !filter[:machine_ids].include?(m.id)}.map(&:name).join(' - ')
+ end
+ return machines.map(&:name).join(' - ')
+ when 'event'
+ event.name
+ when 'training'
+ trainings.map(&:name).join(' - ')
+ when 'space'
+ spaces.map(&:name).join(' - ')
+ else
+ STDERR.puts "[title] Availability with unknown type #{available_type}"
+ '???'
end
end
@@ -74,23 +92,23 @@ class Availability < ActiveRecord::Base
# if haven't defined a nb_total_places, places are unlimited
def is_completed
return false if nb_total_places.blank?
- if available_type == 'training'
+ if available_type == 'training' || available_type == 'space'
nb_total_places <= slots.to_a.select {|s| s.canceled_at == nil }.size
elsif available_type == 'event'
event.nb_free_places == 0
end
end
- # TODO: refactoring this function for avoid N+1 query
def nb_total_places
- if available_type == 'training'
- if read_attribute(:nb_total_places).present?
- read_attribute(:nb_total_places)
+ case available_type
+ when 'training'
+ super.presence || trainings.map {|t| t.nb_total_places}.reduce(:+)
+ when 'event'
+ event.nb_total_places
+ when 'space'
+ super.presence || spaces.map {|s| s.default_places}.reduce(:+)
else
- trainings.first.nb_total_places unless trainings.empty?
- end
- elsif available_type == 'event'
- event.nb_total_places
+ nil
end
end
@@ -98,12 +116,17 @@ class Availability < ActiveRecord::Base
def as_indexed_json
json = JSON.parse(to_json)
json['hours_duration'] = (end_at - start_at) / (60 * 60)
- if available_type == 'machines'
- json['subType'] = machines_availabilities.map{|ma| ma.machine.friendly_id}
- elsif available_type == 'training'
- json['subType'] = trainings_availabilities.map{|ta| ta.training.friendly_id}
- elsif available_type == 'event'
- json['subType'] = [event.category.friendly_id]
+ case available_type
+ when 'machines'
+ json['subType'] = machines_availabilities.map{|ma| ma.machine.friendly_id}
+ when'training'
+ json['subType'] = trainings_availabilities.map{|ta| ta.training.friendly_id}
+ when 'event'
+ json['subType'] = [event.category.friendly_id]
+ when 'space'
+ json['subType'] = spaces_availabilities.map{|sa| sa.space.friendly_id}
+ else
+ json['subType'] = []
end
json['bookable_hours'] = json['hours_duration'] * json['subType'].length
json['date'] = start_at.to_date
diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml
index db3f4fbd5..b1a813a34 100644
--- a/config/locales/app.admin.en.yml
+++ b/config/locales/app.admin.en.yml
@@ -13,14 +13,16 @@ en:
calendar:
# manage the trainings & machines slots
- calendar:
+ admin_calendar:
calendar_management: "Calendar management"
trainings: "Trainings"
machines: "Machines"
spaces: "Spaces"
ongoing_reservations: "Ongoing reservations"
no_reservations: "No reservations"
+ confirmation_required: "Confirmation required"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Do you really want to cancel the {USER}'s reservation, the {DATE} at {TIME}, concerning {RESERVATION}?" # messageFormat interpolation
+ reservation_was_successfully_cancelled: "Reservation was successfully cancelled."
reservation_cancellation_failed: "Reservation cancellation failed."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Unable to remove the last machine of the slot. Delete the slot rather."
do_you_really_want_to_remove_MACHINE_from_this_slot: "Do you really want to remove \"{MACHINE}\" from this slot?" # messageFormat interpolation
@@ -42,7 +44,7 @@ en:
restrict_this_slot_with_labels_(optional): "Restrict this slot with labels (optional)"
the_slot_START-END_has_been_successfully_deleted: "The slot {{START}} - {{END}} has been successfully deleted" # angular interpolation
unable_to_delete_the_slot_START-END_because_it_s_already_reserved_by_a_member: "Unable to delete the slot {{START}} - {{END}} because it's already reserved by a member" # angular interpolation
- you_should_link_a_training_or_a_machine_to_this_slot: "You should link a training or a machine to this slot."
+ you_should_select_at_least_a_machine: "You should select at least one machine on this slot."
project_elements:
# management of the projects' components
diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml
index 7c2e258c5..edae9dd64 100644
--- a/config/locales/app.admin.fr.yml
+++ b/config/locales/app.admin.fr.yml
@@ -13,14 +13,16 @@ fr:
calendar:
# gestion des créneaux machines et formations
- calendar:
+ admin_calendar:
calendar_management: "Gestion du calendrier"
trainings: "Formations"
machines: "Machines"
spaces: "Espaces"
ongoing_reservations: "Réservations en cours"
no_reservations: "Aucune réservation"
+ confirmation_required: "Confirmation requise"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Êtes-vous {GENDER, select, female{sûre} other{sûr}} de vouloir annuler la réservation de {USER}, le {DATE} à {TIME}, concernant {RESERVATION} ?" # messageFormat interpolation
+ reservation_was_successfully_cancelled: "La réservation a bien été annulée."
reservation_cancellation_failed: "L'annulation de la réservation a échouée."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Impossible de supprimer la dernière machine du créneau. Supprimez plutôt le créneau."
do_you_really_want_to_remove_MACHINE_from_this_slot: "Êtes-vous {GENDER, select, female{sûre} other{sûr}} de vouloir retirer \"{MACHINE}\" de ce créneau ?" # messageFormat interpolation
@@ -42,7 +44,7 @@ fr:
restrict_this_slot_with_labels_(optional): "Restreindre ce créneau avec des étiquettes (optionnel)"
the_slot_START-END_has_been_successfully_deleted: "Le créneau {{START}} - {{END}} a bien été supprimé" # angular interpolation
unable_to_delete_the_slot_START-END_because_it_s_already_reserved_by_a_member: "Le créneau {{START}} - {{END}} n'a pu être supprimé car il est déjà réservé par un membre" # angular interpolation
- you_should_link_a_training_or_a_machine_to_this_slot: "Vous devriez associer une formation ou une machine à ce créneau."
+ you_should_select_at_least_a_machine: "Vous devriez sélectionne au moins une machine pour ce créneau."
project_elements:
# gestion des éléments constituant les projets