demarches-normaliennes/app/models/export.rb

131 lines
3.3 KiB
Ruby
Raw Normal View History

2020-08-06 16:35:45 +02:00
# == Schema Information
#
# Table name: exports
#
2021-06-16 11:46:25 +02:00
# id :bigint not null, primary key
# format :string not null
# key :text not null
# time_span_type :string default("everything"), not null
# created_at :datetime not null
# updated_at :datetime not null
2020-08-06 16:35:45 +02:00
#
2019-12-03 18:36:50 +01:00
class Export < ApplicationRecord
2021-04-08 12:47:29 +02:00
MAX_DUREE_CONSERVATION_EXPORT = 3.hours
2019-12-03 18:36:50 +01:00
enum format: {
csv: 'csv',
ods: 'ods',
xlsx: 'xlsx'
}
2021-06-16 11:46:25 +02:00
enum time_span_type: {
everything: 'everything',
monthly: 'monthly'
}
2019-12-03 18:36:50 +01:00
has_and_belongs_to_many :groupe_instructeurs
has_one_attached :file
validates :format, :groupe_instructeurs, :key, presence: true
2019-12-03 18:36:50 +01:00
scope :stale, -> { where('exports.updated_at < ?', (Time.zone.now - MAX_DUREE_CONSERVATION_EXPORT)) }
2019-12-03 18:36:50 +01:00
2020-09-29 14:00:31 +02:00
after_create_commit :compute_async
2019-12-03 18:36:50 +01:00
2021-06-16 11:46:25 +02:00
FORMATS = [:xlsx, :ods, :csv].flat_map do |format|
Export.time_span_types.values.map do |time_span_type|
[format, time_span_type]
end
end
2019-12-03 18:36:50 +01:00
def compute_async
ExportJob.perform_later(self)
end
def compute
file.attach(
2021-06-16 11:46:25 +02:00
io: io(since: since),
2019-12-03 18:36:50 +01:00
filename: filename,
2020-02-24 10:33:31 +01:00
content_type: content_type,
# We generate the exports ourselves, so they are safe
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
2019-12-03 18:36:50 +01:00
)
end
2021-06-16 11:46:25 +02:00
def since
time_span_type == Export.time_span_types.fetch(:monthly) ? 30.days.ago : nil
end
2019-12-03 18:36:50 +01:00
def ready?
file.attached?
end
2021-04-08 12:47:29 +02:00
def old?
updated_at < 20.minutes.ago
end
2021-06-16 11:46:25 +02:00
def self.find_or_create_export(format, time_span_type, groupe_instructeurs)
create_with(groupe_instructeurs: groupe_instructeurs)
2021-06-16 11:46:25 +02:00
.create_or_find_by(format: format,
time_span_type: time_span_type,
key: generate_cache_key(groupe_instructeurs.map(&:id)))
2019-12-03 18:36:50 +01:00
end
def self.find_for_groupe_instructeurs(groupe_instructeurs_ids)
exports = where(key: generate_cache_key(groupe_instructeurs_ids))
2021-06-16 11:46:25 +02:00
[:xlsx, :csv, :ods].map do |format|
[
format,
Export.time_span_types.values.map do |time_span_type|
[time_span_type, exports.find { |export| export.format == format.to_s && export.time_span_type == time_span_type }]
end.filter { |(_, export)| export.present? }.to_h
]
end.filter { |(_, exports)| exports.present? }.to_h
end
def self.generate_cache_key(groupe_instructeurs_ids)
groupe_instructeurs_ids.sort.join('-')
2019-12-03 18:36:50 +01:00
end
private
def filename
procedure_identifier = procedure.path || "procedure-#{procedure.id}"
2019-12-03 18:36:50 +01:00
"dossiers_#{procedure_identifier}_#{Time.zone.now.strftime('%Y-%m-%d_%H-%M')}.#{format}"
end
2021-06-16 11:46:25 +02:00
def io(since: nil)
2019-12-03 18:36:50 +01:00
dossiers = Dossier.where(groupe_instructeur: groupe_instructeurs)
2021-06-16 11:46:25 +02:00
if since.present?
dossiers = dossiers.where('dossiers.depose_at > ?', since)
2021-06-16 11:46:25 +02:00
end
2019-12-03 18:36:50 +01:00
service = ProcedureExportService.new(procedure, dossiers)
case format.to_sym
when :csv
StringIO.new(service.to_csv)
when :xlsx
StringIO.new(service.to_xlsx)
when :ods
StringIO.new(service.to_ods)
end
end
def content_type
case format.to_sym
when :csv
'text/csv'
when :xlsx
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
when :ods
'application/vnd.oasis.opendocument.spreadsheet'
end
end
def procedure
groupe_instructeurs.first.procedure
end
end