module Eco module API # Class to manage the current session. # Central helper of resources. class Session < Common::Session::BaseSession #@param init [Eco::API::Session::Config, Eco::API::Common::Session::Environment] object to ini the session def initialize(init = {}) e = init msg = "Expected object Eco::API::Session::Config or Eco::API::Common::Session::Environment. Given: #{init}" raise msg unless e.is_a?(Session::Config) || e.is_a?(Eco::API::Common::Session::Environment) e = Eco::API::Common::Session::Environment.new(init, session: self) if !e.is_a?(Eco::API::Common::Session::Environment) super(e) @entry_factories = {} @person_factories = {} logger.debug("LINE COMMAND: #{$0} #{ARGV.join(" ")}") end # Helper to perform multiple operations in one go. # @return [Eco::API::Session::Task] provides shortcuts to manage certain kind of operations. def do @task ||= Task.new(enviro) end # @return [Eco::API::Session::Batch] provides helper to launch batch operations. def batch @batch ||= Batch.new(enviro) end # @see Eco::API::Session::Config#policy_groups def policy_groups config.policy_groups end # @see Eco::API::Session::Config#login_providers def login_providers config.login_providers end # @see Eco::API::Session::Config#tagtree def tagtree config.tagtree(enviro: enviro) end # @see Eco::API::Session::Config#schemas def schemas config.schemas end # @return [String, Ecoportal::API::V1::PersonSchema] current active session's schema def schema self.schema = config.people.default_schema || schemas.first unless @schema @schema end # Sets the current target `PersonSchema` of this session. # @note observe that it is essential for the parsers/serialisers to identify target/present attributes. # @param schema [String, Ecoportal::API::V1::PersonSchema] where `String` can be the _name_ or the _id_ of the schema. def schema=(value) @schema = to_schema(value) self end # Builds the presets using the usergroup ids of the input. # @note for each flag/ability it will take the highest among those mapped for the present usergroups. # @param [Ecoportal::API::Internal::Person, Array] the array should be of usegroup names or ids. # @return [Hash] with custom presets. def new_preset(input) case input when Ecoportal::API::Internal::Person presets_factory.new(*input&.account&.policy_group_ids) when Array presets_factory.new(*input) else presets_factory.new(input) end end # Helper to obtain a EntryFactory # @param schema [String, Ecoportal::API::V1::PersonSchema] `schema` to which associate the EntryFactory, # where `String` can be the _name_ or the _id_ of the schema. # @return [Eco::API::Common::People::EntryFactory] associated to `schema`. # If `schema` is `nil` or not provided it uses the currently associated to the `session` def entry_factory(schema: nil) schema = to_schema(schema) || self.schema return @entry_factories[schema&.id] if @entry_factories.key?(schema&.id) # TODO: check PersonEntry#to_internal and #to_external in init_attr_trackers # => when attr_map is avoided, it doesn't work as it should mappings = [] if map_file = config.people.fields_mapper mappings = map_file ? file_manager.load_json(map_file) : [] end @entry_factories[schema&.id] = Eco::API::Common::People::EntryFactory.new({ schema: schema, person_parser: config.people.parser, attr_map: Eco::Data::Mapper.new(mappings), logger: logger }) end # Helper to obtain a PersonFactory # @param schema [String, Ecoportal::API::V1::PersonSchema] `schema` to which associate the PersonFactory, # where `String` can be the _name_ or the _id_ of the schema. # @return [Eco::API::Common::People::PersonFactory] associated to `schema`. # If `schema` is `nil` or not provided it uses the currently associated to the `session` def person_factory(schema: nil) schema = to_schema(schema) || self.schema @person_factories[schema&.id] ||= Eco::API::Common::People::PersonFactory.new(schema: schema) end # Allows to use the defined parsers # @note the use of these method requires to know which is the expected format of `source` # @param attr [String] type (`Symbol`) or attribute (`String`) to target a specific parser. # @param source [Any] source value to be parsed. def parse_attribute(attr, source) unless parsers = entry_factory.person_parser raise "There are no parsers defined" end parsers.parse(attr, source) end def export(*args) entry_factory.export(*args) end # @see Eco::API::Common::People::EntryFactory#new # @return [Ecoportal::API::Internal::Person] def new_person(**keyed_args) person_factory.new(**keyed_args) end # Builds the entry for the given data. # @see Eco::API::Common::People::EntryFactory#new # @return [Eco::API::Common::People::PersonEntry] parsed entry. def new_entry(data, dependencies: {}) entry_factory.new(data, dependencies: dependencies) end # @see Eco::API::Common::People::EntryFactory#entries # @return [Eco::API::Common::People::Entries] collection of entries. def entries(*args) entry_factory.entries(*args).tap do |collection| logger.info("Loaded #{collection.length} input entries.") end end # Generates an entries collection from a csv input file. # @see Eco::API::Common::People::EntryFactory#entries # @param file [String] file to generate the entries from. # @return [Eco::API::Common::People::Entries] collection of entries. def csv_entries(file) return entries(file: file, format: :csv) end # Generates the collection of entries that should be discarded from an update. # @note requires `session.config.people.discarded_file` to be defined. # @return [Eco::API::Common::People::Entries] collection of entries. def discarded_entries return @discarded_entries if instance_variable_defined?(:@discarded_entries) file = config.people.discarded_file file = file_manager.dir.file(file) @discarded_entries = csv_entries(file) end def workflow(io:) config.workflow.tap do |wf| yield(wf, io) if block_given? end end def usecases @usecases ||= Eco::API::UseCases::DefaultCases.new.merge(config.usecases) end def post_launch @post_launch ||= config.post_launch.select(usecases) end def process_case(name, io: nil, type: nil, **params) args = { session: self }.merge(params) usecases.case(name, type: type).launch(io: io, **args) end def job_groups @job_groups ||= Batch::JobsGroups.new(enviro) end def job_group(name, order: :last) case when job_groups.exists?(name) job_groups[name] else job_groups.new(name, order: order) end end def jobs_launch(simulate: false) job_groups.launch(simulate: simulate) end def summary job_groups.summary end # Sends an email # @see Eco::API::Common::Session::Mailer#mail def mail(**kargs) mailer.mail(**kargs) end # Uploads content into a file, a file or a directory to S3 # @see Eco::API::Common::Session::S3Uploader#upload # @see Eco::API::Common::Session::S3Uploader#upload_file # @see Eco::API::Common::Session::S3Uploader#upload_directory # @param content [String] content to be uploaded (requires `file`) # @param file [String] name of the file to be uploaded # @param directory [String] name of source directory to be uploaded # @param recurse [Boolean] used with `directory`: deepen in the folder structure? (`false`: default) # @param link [Boolean] **return** _link(s)_ (`true`) or _path(s)_ (`false`: default) # @return [String, Array] either paths to S3 objects if `link` is `false`, or _link_ otherwise def s3upload(content: nil, file: nil, directory: nil, recurse: false, link: false) if content == :target path = self.do.s3upload_targets elsif content && file path = s3uploader.upload(file, content) elsif file path = s3uploader.upload_file(file) elsif directory path = s3uploader.upload_directory(directory, recurse: recurse) else logger.error("To use Session.s3upload, you must specify either directory, file or content and file name") end return path unless link s3uploader.link(path) end private # Helper to state the abilities that a person should have with given their usergroups def presets_factory @presets_factory ||= Eco::API::Organization::PresetsFactory.new({ presets_custom: file_manager.dir.file(config.people.presets_custom, should_exist: true), presets_map: file_manager.dir.file(config.people.presets_map, should_exist: true), enviro: enviro }) end # Comparer to state if 2 schemas are different def same_schema? (schema1, schema2) eq = schema1&.id == schema2&.id eq ||= schema1&.name&.downcase == schema2&.name&.downcase schema1 && schema2 && eq end # from schema `id` or `name` to a PersonSchema object def to_schema(value) return nil unless value sch = nil case value when String unless sch = schemas.schema(value) fatal "The schema with id or name '#{value}' does not exist." end when Ecoportal::API::V1::PersonSchema sch = value else fatal "Required String or Ecoportal::API::V1::PersonSchema. Given: #{value}" end sch end end end end require_relative 'session/config' require_relative 'session/batch' require_relative 'session/task'