app/models/setup/file_data_type.rb
module Setup
class FileDataType < DataType
origins Setup::CrossOriginShared::DEFAULT_ORIGINS, :cenit
validates_presence_of :namespace
build_in_data_type.referenced_by(:namespace, :name).with(
:namespace,
:name,
:id_type,
:title,
:slug,
:_type,
:validators,
:schema_data_type,
:before_save_callbacks,
:after_save_callbacks,
:records_methods,
:data_type_methods
)
build_in_data_type.and(
properties: {
id_type: {
enum: %w(default integer string),
enumNames: %w(Default Integer String),
default: 'default'
},
schema: {
edi: {
discard: true
}
}
}
)
# TODO shared_deny :simple_delete_data_type, :bulk_delete_data_type
field :id_type, type: String, default: -> { self.class.id_type_enum.values.first }
has_and_belongs_to_many :validators, class_name: Setup::Validator.to_s, inverse_of: nil
belongs_to :schema_data_type, class_name: Setup::JsonDataType.to_s, inverse_of: nil
validates_inclusion_of :id_type, in: ->(file_data_type) { file_data_type.class.id_type_enum.values + [nil] }
before_save :validate_configuration!, :check_id_type!
after_save { file_store_config.save }
after_destroy { file_store_config.destroy }
def check_id_type!
if !new_record? && self.changes['id_type'] && records_model.all.count > 0
errors.add(:id_type, 'can not be changed when file records exist.')
throw :abort
end
end
def validate_configuration!
throw :abort unless validate_configuration
end
def validate_configuration
self.title = self.name if title.blank?
validators_classes = Hash.new { |h, k| h[k] = [] }
if validators.present?
validators.each { |validator| validators_classes[validator.class] << validator }
validators_classes.delete(Setup::AlgorithmValidator)
if validators_classes.size == 1 &&
(validators = validators_classes.values.first).size == 1 &&
validators[0].is_a?(Setup::EdiValidator)
self.schema_data_type = validators[0].first.schema_data_type
else
if schema_data_type.present?
errors.add(:schema_data_type, 'is not allowed if no format validator is defined')
self.schema_data_type = nil
end
if validators_classes.count > 1
errors.add(:validators, "include validators of exclusive types: #{validators_classes.keys.to_a.collect(&:to_s).to_sentence}")
end
validators_classes.each do |validator_class, validators|
errors.add(:validators, "include multiple validators of the same exclusive type #{validator_class}: #{validators.collect(&:name).to_sentence}") if validators.count > 1
end
end
else
errors.add(:schema_data_type, 'is not allowed if no format validator is defined') if schema_data_type.present?
self.schema_data_type = nil
end
remove_attribute(:id_type) if default_id_type?
errors.blank?
end
def default_id_type?
return true if id_type.blank?
id_options = self.class.id_type_enum.values
id_type == id_options.first || id_options.exclude?(id_type)
end
def format_validator
@format_validator ||= validators.detect { |validator| validator.is_a?(Setup::FormatValidator) }
end
def data_type_storage_collection_name
"#{super}.files"
end
def chunks_storage_collection_name
data_type_storage_collection_name.gsub(/files\Z/, 'chunks')
end
def all_data_type_storage_collections_names
[data_type_storage_collection_name, chunks_storage_collection_name]
end
def mongoff_model_class
Mongoff::GridFs::FileModel
end
def schema
@schema ||=
begin
sch = Mongoff::GridFs::FileModel::SCHEMA
unless default_id_type?
sch = sch.deep_dup
sch['properties']['_id'] = { 'type' => id_type }
end
sch
end
end
def validate_file(file)
errors = []
validators.each do |v|
next if errors.present?
errors += v.validate_file_record(file)
end
errors
end
def validate_file!(file)
if (errors = validate_file(file)).present?
raise Exception.new('Invalid file data: ' + errors.to_sentence)
end
end
alias_method :mogoff_model, :records_model
def records_model
build_in_model =
begin
[namespace, name].reject(&:empty?).join('::').constantize
rescue
nil
end
if build_in_model && build_in_model < BuildInFileType
build_in_model
else
super
end
end
def new_from(string_or_readable, options = {})
if options[:data_type_parser]
super
else
options.reverse_merge!(default_attributes)
attrs = options.select { |key, _| %w(filename contentType metadata).include?(key.to_s) }
if (id = (options['_id'] || options['id']))
attrs['id'] = id
end
file = (id && !options['add_new'] && records_model.where(_id: id).first) || records_model.new
file.assign_attributes(attrs)
file.data = string_or_readable
file
end
end
def create_from(string_or_readable, options = {})
if data_type_methods.any? { |alg| alg.name == 'create_from' }
return method_missing(:create_from, string_or_readable, options)
end
if options[:data_type_parser]
super
else
options = default_attributes.merge(options)
file = new_from(string_or_readable, options)
file.save(options)
file
end
end
def new_from_json(json_or_readable, options = {})
if data_type_methods.any? { |alg| alg.name == 'new_from_json' }
return method_missing(:new_from_json, json_or_readable, options)
end
if options[:data_type_parser]
super
else
data = json_or_readable
unless format_validator.nil? || format_validator.data_format == :json
data = ((data.is_a?(String) || data.is_a?(Hash)) && data) || data.read
data = format_validator.format_from_json(data, schema_data_type: schema_data_type)
options[:valid_data] = true
end
new_from(data, options)
end
end
def new_from_xml(string_or_readable, options = {})
if data_type_methods.any? { |alg| alg.name == 'new_from_xml' }
return method_missing(:new_from_xml, string_or_readable, options)
end
if options[:data_type_parser]
super
else
data = string_or_readable
unless format_validator.nil? || format_validator.data_format == :xml
data = (data.is_a?(String) && data) || data.read
data = format_validator.format_from_xml(data, schema_data_type: schema_data_type)
options[:valid_data] = true
end
new_from(data, options)
end
end
def new_from_edi(string_or_readable, options = {})
if data_type_methods.any? { |alg| alg.name == 'new_from_edi' }
return method_missing(:new_from_edi, string_or_readable, options)
end
if options[:data_type_parser]
super
else
data = string_or_readable
unless format_validator.nil? || format_validator.data_format == :edi
data = (data.is_a?(String) && data) || data.read
data = format_validator.format_from_edi(data, schema_data_type: schema_data_type)
options[:valid_data] = true
end
new_from(data, options)
end
end
def default_attributes
{
default_filename: "file_#{DateTime.now.strftime('%Y-%m-%d_%Hh%Mm%S')}" + ((extension = format_validator.try(:file_extension)) ? ".#{extension}" : ''),
default_contentType: format_validator.try(:content_type) || 'application/octet-stream'
}
end
def file_store_config
if new_record?
@_file_store_config ||= Setup::FileStoreConfig.new(data_type: self)
else
if @file_store_cache_disabled || !@_file_store_config
@_file_store_config = Setup::FileStoreConfig.find_or_create_by(data_type: self)
end
end
@_file_store_config
end
delegate :file_store, :public_read, to: :file_store_config
def can_cross?(origin)
origin.to_sym != :cenit && self.origin != :cenit
end
class << self
def id_type_enum
{
Default: 'default',
Integer: 'integer',
String: 'string'
}
end
end
end
end