1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-13 23:48:55 +01:00
fab-manager/app/services/availabilities/availabilities_service.rb

153 lines
7.0 KiB
Ruby
Raw Normal View History

2019-01-17 16:26:03 +01:00
# frozen_string_literal: true
# List all Availability's slots for the given resources
2019-01-17 16:26:03 +01:00
class Availabilities::AvailabilitiesService
# @param current_user [User]
2023-01-18 17:44:58 +01:00
# @param level [String] 'slot' | 'availability'
def initialize(current_user, level = 'slot')
2019-01-17 16:26:03 +01:00
@current_user = current_user
@maximum_visibility = {
year: Setting.get('visibility_yearly').to_i.months.since,
other: Setting.get('visibility_others').to_i.months.since
}
2022-11-29 21:02:01 +01:00
@minimum_visibility = Setting.get('reservation_deadline').to_i.minutes.since
@level = level
2019-01-17 16:26:03 +01:00
end
# @param window [Hash] the time window the look through: {start: xxx, end: xxx}
# @option window [ActiveSupport::TimeWithZone] :start
# @option window [ActiveSupport::TimeWithZone] :end
# @param ids [Array<Integer>]
# @param events [Boolean] should events be included in the results?
def index(window, ids, events: false)
2022-12-16 18:43:38 +01:00
machines_availabilities = Setting.get('machines_module') ? machines(Machine.where(id: ids[:machines]), @current_user, window) : []
spaces_availabilities = Setting.get('spaces_module') ? spaces(Space.where(id: ids[:spaces]), @current_user, window) : []
trainings_availabilities = Setting.get('trainings_module') ? trainings(Training.where(id: ids[:trainings]), @current_user, window) : []
events_availabilities = if events && Setting.get('events_in_calendar')
events(Event.all, @current_user, window)
else
[]
end
[].concat(trainings_availabilities).concat(events_availabilities).concat(machines_availabilities).concat(spaces_availabilities)
end
# list all slots for the given machines, with visibility relative to the given user
# @param machines [ActiveRecord::Relation<Machine>]
# @param user [User]
# @param window [Hash] the time window the look through: {start: xxx, end: xxx}
# @option window [ActiveSupport::TimeWithZone] :start the beginning of the time window
# @option window [ActiveSupport::TimeWithZone] :end the end of the time window
def machines(machines, user, window)
2023-01-18 17:44:58 +01:00
ma_availabilities = Availability.includes(:machines_availabilities)
.where('machines_availabilities.machine_id': machines.map(&:id))
availabilities = availabilities(ma_availabilities, 'machines', user, window[:start], window[:end])
2019-01-17 16:26:03 +01:00
if @level == 'slot'
availabilities.map(&:slots).flatten
else
availabilities
end
2019-01-17 16:26:03 +01:00
end
# list all slots for the given space, with visibility relative to the given user
# @param spaces [ActiveRecord::Relation<Space>]
# @param user [User]
# @param window [Hash] the time window the look through: {start: xxx, end: xxx}
# @option window [ActiveSupport::TimeWithZone] :start
# @option window [ActiveSupport::TimeWithZone] :end
def spaces(spaces, user, window)
sp_availabilities = Availability.includes('spaces_availabilities')
.where('spaces_availabilities.space_id': spaces.map(&:id))
availabilities = availabilities(sp_availabilities, 'space', user, window[:start], window[:end])
2019-01-17 16:26:03 +01:00
if @level == 'slot'
availabilities.map(&:slots).flatten
else
availabilities
end
2019-01-17 16:26:03 +01:00
end
2022-07-12 17:46:01 +02:00
# list all slots for the given training(s), with visibility relative to the given user
# @param trainings [ActiveRecord::Relation<Training>]
# @param user [User]
# @param window [Hash] the time window the look through: {start: xxx, end: xxx}
# @option window [ActiveSupport::TimeWithZone] :start
# @option window [ActiveSupport::TimeWithZone] :end
def trainings(trainings, user, window)
tr_availabilities = Availability.includes('trainings_availabilities')
.where('trainings_availabilities.training_id': trainings.map(&:id))
availabilities = availabilities(tr_availabilities, 'training', user, window[:start], window[:end])
2019-01-17 16:26:03 +01:00
if @level == 'slot'
availabilities.map(&:slots).flatten
else
availabilities
end
end
# list all slots for the given event(s), with visibility relative to the given user
# @param events [ActiveRecord::Relation<Event>]
# @param user [User]
# @param window [Hash] the time window the look through: {start: xxx, end: xxx}
# @option window [ActiveSupport::TimeWithZone] :start
# @option window [ActiveSupport::TimeWithZone] :end
def events(events, user, window)
ev_availabilities = Availability.includes('event').where('events.id': events.map(&:id))
availabilities = availabilities(ev_availabilities, 'event', user, window[:start], window[:end])
if @level == 'slot'
availabilities.map(&:slots).flatten
else
availabilities
end
2019-01-17 16:26:03 +01:00
end
2023-01-18 17:44:58 +01:00
protected
2019-01-17 16:26:03 +01:00
# @param user [User]
2019-01-17 16:26:03 +01:00
def subscription_year?(user)
user&.subscription && user.subscription.plan.interval == 'year' && user.subscription.expired_at >= Time.current
2019-01-17 16:26:03 +01:00
end
# members must have validated at least 1 training and must have a valid yearly subscription to view
# the trainings further in the futur. This is used to prevent users with a rolling subscription to take
# their first training in a very long delay.
# @param user [User]
def show_more_trainings?(user)
user&.trainings&.size&.positive? && subscription_year?(user)
2019-01-17 16:26:03 +01:00
end
# @param availabilities [ActiveRecord::Relation<Availability>]
# @param type [String]
# @param user [User]
# @param range_start [ActiveSupport::TimeWithZone]
# @param range_end [ActiveSupport::TimeWithZone]
# @return ActiveRecord::Relation<Availability>
def availabilities(availabilities, type, user, range_start, range_end)
2019-01-17 16:26:03 +01:00
# who made the request?
# 1) an admin (he can see all availabilities from 1 month ago to anytime in the future)
if @current_user&.admin? || @current_user&.manager?
window_start = [range_start, 1.month.ago].max
2023-01-18 17:44:58 +01:00
availabilities.includes(:tags, :slots)
.joins(:slots)
.where('availabilities.start_at <= ? AND availabilities.end_at >= ? AND available_type = ?', range_end, window_start, type)
.where('slots.start_at > ? AND slots.end_at < ?', window_start, range_end)
2019-01-17 16:26:03 +01:00
.where(lock: false)
# 2) an user (he cannot see past availabilities neither those further than 1 (or 3) months in the future)
2019-01-17 16:26:03 +01:00
else
end_at = @maximum_visibility[:other]
end_at = @maximum_visibility[:year] if subscription_year?(user) && type != 'training'
end_at = @maximum_visibility[:year] if show_more_trainings?(user) && type == 'training'
window_end = [end_at, range_end].min
2022-11-29 21:02:01 +01:00
window_start = [range_start, @minimum_visibility].max
2023-01-18 17:44:58 +01:00
availabilities.includes(:tags, :slots)
.joins(:slots)
.where('availabilities.start_at <= ? AND availabilities.end_at >= ? AND available_type = ?', window_end, window_start, type)
.where('slots.start_at > ? AND slots.end_at < ?', window_start, window_end)
.where('availability_tags.tag_id' => user&.tag_ids&.concat([nil]))
2019-01-17 16:26:03 +01:00
.where(lock: false)
end
end
end