class Eco::API::MicroCases
Public Instance Methods
@param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options. @return [Array<String>] the account parameters that should not be included.
# File lib/eco/api/microcases/account_excluded.rb, line 7 def account_excluded(person, options) [].tap do |account_excluded| unless person.new? if options.dig(:exclude, :policy_groups) account_excluded.push("policy_group_ids") end if options.dig(:exclude, :default_tag) account_excluded.push("default_tag") end if options.dig(:exclude, :login_providers) account_excluded.push("login_provider_ids") end end end end
It preserves the usergroups of `person` and appends those defined in `policy_group_ids` of the `entry` @param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options.
# File lib/eco/api/microcases/append_usergroups.rb, line 8 def append_usergroups(entry, person, options) unless options.dig(:exclude, :account) if person.account person.account.policy_group_ids |= entry.policy_group_ids end end end
@note by default `supervisor_id` is always excluded. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options. @return [Array<String>] the core parameters that should not be included.
# File lib/eco/api/microcases/core_excluded.rb, line 8 def core_excluded(person, options) ["supervisor_id"].tap do |core_excluded| unless person.new? exclusions = ["name", "external_id", "email", "filter_tags"].select do |attr| options.dig(:exclude, attr.to_sym) end core_excluded.concat(exclusions) end end end
If defined, it sets the default usergroup, only when the `policy_group_ids` was not part of the input data. @param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options.
# File lib/eco/api/microcases/fix_default_group.rb, line 8 def fix_default_group(entry, person, options) unless options.dig(:exclude, :account) unless options.dig(:exclude, :policy_groups) && !person.new? end_pg_ids = person.account.policy_group_ids if person.account_added? && __def_usergroup_id && !entry.policy_group_ids? # on account creation, if missing policy_group_ids column in the input # use default_usergroup, if it's defined end_pg_ids = [__def_usergroup_id] end person.account.policy_group_ids = end_pg_ids end end end
# File lib/eco/api/microcases.rb, line 5 def micro self end
Helper to locally cache the people manager. @param filename [String] the name of the file where the data should be cached. @return [Eco::API::Organization::People] the `People` object with the data.
# File lib/eco/api/microcases/people_cache.rb, line 7 def people_cache(filename = enviro.config.people.cache) logger.info("Going to get all the people via API") start = Time.now people = session.batch.get_people secs = (Time.now - start).round(3) cnt = people.count per_sec = (cnt.to_f / secs).round(2) logger.info("Loaded #{cnt} people in #{secs} seconds (#{per_sec} people/sec)") file = file_manager.save_json(people, filename, :timestamp) logger.info("#{people.length} people loaded and saved locally to #{file}.") Eco::API::Organization::People.new(people) end
Helper to load `People` that works in different phases:
1. first tries to get the newest cached file that follows `filename` pattern - if not the newest, it tries to find the specific filename 2. if it succeeds to identif a cached file, it loads it - if it fails, it tries to get people from the server
@note
- `filename` will be relative to the working directory (the one of the session `enviro` set by the user).
@param filename [String] the name of the file where the cached data is to be found. @param modifier [Array<Symbol>] modifiers to specify how this function should proceed:
- `:newest` if it should try to find the newest file (pattern alike). - `:api` if it should try to get people from the server in case there's no cache. - `:file` if it is supposed to load people from a file. - `:save` if it is supposed to cache/save the data locally once obtained people from the server (`:api`)
@return [Eco::API::Organization::People] the `People` object with the data.
# File lib/eco/api/microcases/people_load.rb, line 18 def people_load(filename = enviro.config.people.cache, modifier: [:newest, :api]) modifier = [modifier].flatten load_file = [:file, :newest].any? {|flag| modifier.include?(flag)} case when filename && load_file if file = people_load_filename(filename, newest: modifier.include?(:newest)) file_manager.load_json(file).tap do |people| logger.info("#{people&.length} people loaded from file #{file}") if people.is_a?(Array) end else logger.error("could not find the file #{file_manager.dir.file(filename)}") exit unless modifier.include?(:api) people_load(modifier: modifier - [:newest, :file]) end when modifier.include?(:api) logger.info("Going to get all the people via API") start = Time.now session.batch.get_people.tap do |people| secs = (Time.now - start).round(3) cnt = people.count per_sec = (cnt.to_f / secs).round(2) logger.info("Loaded #{cnt} people in #{secs} seconds (#{per_sec} people/sec)") if modifier.include?(:save) && people && people.length > 0 file = file_manager.save_json(people, filename, :timestamp) logger.info("#{people.length } people saved to file #{file}.") end end end.yield_self do |people| Eco::API::Organization::People.new(people) end end
Helper to obtain all the elements of `people` anew from the _People Manager_. @note this helper is normally used to run consecutive usecases, where data needs refresh. @param people [Eco::API::Organization::People] the people that needs refresh. @param include_created [Boolean] include people created during this session? (will check `:create` batch jobs). @return [Eco::API::Organization::People] the `People` object with the data.
# File lib/eco/api/microcases/people_refresh.rb, line 9 def people_refresh(people:, include_created: true) ini = people.length if include_created session.job_groups.find_jobs(type: :create).map do |job| people = people.merge(job.people) end end created = people.length - ini msg = "Going to refresh #{people.length} people with server data" msg += " (including #{created} that were created)" if created > 0 logger.info(msg) start = Time.now entries = session.batch.get_people(people, silent: true) secs = (Time.now - start).round(3) cnt = entries.count per_sec = (cnt.to_f / secs).round(2) logger.info("Re-loaded #{cnt} people (out of #{people.length}) in #{secs} seconds (#{per_sec} people/sec)") missing = people.length - entries.length logger.error("Missed to obtain #{missing} people during the refresh") if missing > 0 Eco::API::Organization::People.new(entries) end
Helper to search/obtain people from `data` against the server (_People Manager_). @note
- this helper is normally used to **get partial** part of the people manager. - therefore, normally used with _**delta** input files_ (files with only the differences).
@param data [Eco::API::Organization::People, Enumerable<Person>, Enumerable<Hash>] `People` to search against the server. @param options [Hash] the options. @param silent [Boolean] `false` if low level search messages should be shown. @return [Eco::API::Organization::People] the `People` object with the found persons.
# File lib/eco/api/microcases/people_search.rb, line 12 def people_search(data, options: {}, silent: true) session.logger.info("Going to api get #{data.length} entries...") start = Time.now people = session.batch.search(data, silent: silent).yield_self do |status| secs = (Time.now - start).round(3) Eco::API::Organization::People.new(status.people).tap do |people| cnt = people.count per_sec = (cnt.to_f / secs).round(2) msg = "... could get #{cnt} people (out of #{data.length} entries) in #{secs} seconds (#{per_sec} people/sec)" session.logger.info(msg) end end # get the supervisors of found people (current supervisors) supers = people_search_prepare_supers_request(people) if supers.length > 0 session.logger.info(" Going to api get #{supers.length} current supervisors...") start = Time.now people = session.batch.search(supers, silent: silent).yield_self do |status| secs = (Time.now - start).round(3) found = status.people cnt = found.count per_sec = (cnt.to_f / secs).round(2) msg = "... could find #{cnt} current supers (out of #{supers.length}) in #{secs} seconds (#{per_sec} people/sec)" session.logger.info(msg) people.merge(found, strict: micro.strict_search?(options)) end end # get the supervisors referred in the input data (future supervisors) supers = people_search_prepare_supers_request(data, people) if supers.length > 0 session.logger.info(" Going to api get #{supers.length} supervisors as per input entries...") start = Time.now people = session.batch.search(supers, silent: silent).yield_self do |status| secs = (Time.now - start).round(3) found = status.people cnt = found.count per_sec = (cnt.to_f / secs).round(2) msg = "... could find #{cnt} input supers (out of #{supers.length}) in #{secs} seconds (#{per_sec} people/sec)" session.logger.info(msg) people.merge(found, strict: micro.strict_search?(options)) end end session.logger.info("Finally got #{people.length} people (out of #{data.length} entries)") people end
Helper to preserve the original `default_tag`. @note
1. It only works if the original value of `default_tag` was **not** empty
@param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options. @return [String] the final value of `default_tag`.
# File lib/eco/api/microcases/preserve_default_tag.rb, line 10 def preserve_default_tag(person, options) if account = person.account if account.as_update.key?("default_tag") if original = person.original_doc.dig("account", "default_tag") person.account.default_tag = original end end end person.account&.default_tag end
Helper to preserve the original `policy_group_ids`. @note
1. It only works if the original value of `policy_group_ids` was **not** empty
@param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options. @param keep_new [Boolean] tells if it should keep the new policy groups or get rid of them. @return [String] the final value of `policy_group_ids`.
# File lib/eco/api/microcases/preserve_policy_groups.rb, line 11 def preserve_policy_groups(person, options, keep_new: false) if account = person.account if account.as_update.key?("policy_group_ids") if original = person.original_doc.dig("account", "policy_group_ids") unless original.empty? if keep_new person.account.policy_group_ids += original else person.account.policy_group_ids = original end end end end end person.account&.policy_group_ids end
When the input data, or `entry`, does not provide the `default_tag`, it sets the `default_tag` of the user following some criteria @note it assumes `default_tag` has been already set to `person.account` @param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options
# File lib/eco/api/microcases/refresh_default_tag.rb, line 10 def refresh_default_tag(entry, person, options) if person.account unless options.dig(:exclude, :account) unless options.dig(:exclude, :filter_tags) || options.dig(:exclude, :default_tag) || entry&.default_tag? if session.tagtree person.account.default_tag = session.tagtree.default_tag(*person.filter_tags) else tags = person.filter_tags || [] person.account.default_tag = tags.first unless tags.length > 1 end end end end end
Helper to upload target files to `S3`. @return [Array<String>] the paths in `S3` of the uploaded files.
# File lib/eco/api/microcases/s3upload_targets.rb, line 6 def s3upload_targets [].tap do |paths| session.config.s3storage.target_files.each_with_object(paths) do |file, arr| arr.push(session.s3upload(file: file)) end session.config.s3storage.target_directories.each_with_object(paths) do |folder, arr| arr.concat(session.s3upload(directory: folder)) end session.config.s3storage.target_file_patterns.each_with_object(paths) do |pattern, arr| filenames = [] case pattern when Regexp Dir.entries(".").sort.each do |file| next unless File.file?(file) # Skip directories filenames.push(file) if file =~ pattern end when String Dir.glob(pattern).sort.each do |file| next unless File.file?(file) # Skip directories filenames.push(file) end else # missconfiguration end filenames.each do |file| arr.push(session.s3upload(file: file)) end end end end
@param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options.
# File lib/eco/api/microcases/set_account.rb, line 7 def set_account(entry, person, options) unless options.dig(:exclude, :account) entry.set_account(person, exclude: micro.account_excluded(person, options)) person.account.send_invites = options[:send_invites] if options.key?(:send_invites) micro.refresh_default_tag(entry, person, options) micro.fix_default_group(entry, person, options) end end
Sets all the core details, but the supervisor. @note `supervisor_id` requires a special treatment, and therefore is always excluded. @param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param options [Hash] the options
# File lib/eco/api/microcases/set_core.rb, line 9 def set_core(entry, person, options) unless options.dig(:exclude, :core) && !person.new? entry.set_core(person, exclude: micro.core_excluded(person, options)) micro.fix_filter_tags(person, options) end end
Sets all the core details, but the supervisor. @note `supervisor_id` requires a special treatment, and therefore is always excluded. @param entry [PersonEntry] the input entry with the data we should set on person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param people [Eco::API::Organization::People] target existing People of the current update. @param supers_job [Eco::API::Session::Batch::Job] the job that will run the supers . @param options [Hash] the options.
# File lib/eco/api/microcases/set_core_with_supervisor.rb, line 11 def set_core_with_supervisor(entry, person, people, supers_job, options) unless options.dig(:exclude, :core) && !person.new? micro.set_core(entry, person, options) if entry.supervisor_id? micro.set_supervisor(person, entry.supervisor_id, people, options) do |unknown_id| # delay setting supervisor if does not exit supers_job.add(person) do |person| micro.set_supervisor(person, unknown_id, people, options) end end end end end
Unique access point to set the `supervisor_id` value on a person. @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done. @param sup_id [nil, String] the **supervisor id** we should set on the `person`. @param people [Eco::API::Organization::People] People involved in the current update. @param options [Hash] the options. @yield [supervisor_id] callback when the supervisor_id is unknown (not `nil` nor any one's in `people`). @yieldparam supervisor_id [String] the unknown `supervisor_id`.
# File lib/eco/api/microcases/set_supervisor.rb, line 11 def set_supervisor(person, sup_id, people, options) unless options.dig(:exclude, :core) || options.dig(:exclude, :supervisor) cur_id = person.supervisor_id cur_super = cur_id && with_supervisor(cur_id, people) micro.with_supervisor(sup_id, people) do |new_super| if !sup_id person.supervisor_id = nil descrease_subordinates(cur_super) elsif new_super && id = new_super.id person.supervisor_id = id descrease_subordinates(cur_super) increase_subordinates(new_super) elsif !block_given? descrease_subordinates(cur_super) person.supervisor_id = sup_id else yield(sup_id) if block_given? end end end end
When trying to find an `person` with given a source `entry`, it states if such a search should be `strict` or `soft`. @note
- `strict` searches ignore the email when the source `entry` has an `external_id` specified. - see related command line options `-search-strict` and `-search-soft`
@param options [Hash] the options. @return [Boolean] `true` if the search should be `strict` only, and `false` otherwise.
# File lib/eco/api/microcases/strict_search.rb, line 10 def strict_search?(options) strict_config = session.config.people.strict_search? strict_option = options.dig(:search, :strict) soft_option = options.dig(:search, :soft) && !strict_option (strict_config || strict_option) && !soft_option end
Finds each entry of `entries` in `people` and runs a block. @note
- it also links to `person.entry` the input data entry.
@param entries [Eco::API::Common::People::Entries] the input entries with the data. @param people [Eco::API::Organization::People] target existing People of the current update. @param options [Hash] the options. @param append_created [Boolean] whether or not a new person will be added to the `people` object. @yield [entry, person] gives each entry, and the paired person thereof (new or existing). @yieldparam entry [PersonEntry] the input entry with the data we should set on person. @yieldparam person [Ecoportal::API::V1::Person] the found person that matches `entry`, or a new person otherwise. @return [Eco::API::Organization::People] all the people, including new and existing ones.
# File lib/eco/api/microcases/with_each.rb, line 15 def with_each(entries, people, options, append_created: true) @_skip_all_multiple_results = false people_copy = people.newFrom(people.to_a) entries.each_with_object([]) do |entry, scoped| begin unless person = people_copy.find(entry, strict: micro.strict_search?(options)) person = session.new_person.tap do |person| people << person if append_created end end rescue Eco::API::Organization::People::MultipleSearchResults => e unless @_skip_all_multiple_results msg = "\n * When searching this Entry: #{entry.to_s(:identify)}" person = _with_each_prompt_to_select_user(e.append_message(msg), entry: entry) end end if person person.entry = entry yield(entry, person) if block_given? scoped << person end end.yield_self {|all_people| people.newFrom all_people.uniq} end
Detects who has left the organization and `yield` s them one by one to the given block @note to be used only when the input file is the full DB @param entries [Eco::API::Common::People::Entries] the input entries with the data. @param people [Eco::API::Organization::People] target existing People of the current update. @param options [Hash] the options. @yield [person] gives each person of `people` that is not present in `entries`. @yieldparam person [Ecoportal::API::V1::Person] the person that leaves the org. @return [Eco::API::Organization::People] the leavers.
# File lib/eco/api/microcases/with_each_leaver.rb, line 12 def with_each_leaver(entries, people, options) leavers = people.map do |person| unless entries.find(person, strict: micro.strict_search?(options)) yield(person) if block_given? person end end.compact people.newFrom leavers end
Finds those in `entries` that already exist in the organization (`people`) and `yield` s them one by one to the given block. @note
- it also links to `person.entry` the input data `entry`.
@param entries [Eco::API::Common::People::Entries] the input entries with the data. @param people [Eco::API::Organization::People] target existing People of the current update. @param options [Hash] the options. @param log_starter [Boolean] log error message if an `entry` does not have match in `people`. @yield [entry, person] gives each found `person` of `entries` that is not present in `people`. @yieldparam entry [PersonEntry] the input entry with the data we should set on person. @yieldparam person [Ecoportal::API::V1::Person] the found person. @return [Eco::API::Organization::People] the found people.
# File lib/eco/api/microcases/with_each_present.rb, line 15 def with_each_present(entries, people, options, log_starter: false) found = [] micro.with_each(entries, people, options) do |entry, person| if person.new? if log_starter session.logger.error("This person does not exist: #{entry.to_s(:identify)}") end next end found << person yield(entry, person) if block_given? end people.newFrom found end
Detects who in the `entries` is new in the organization and `yield` s them one by one to the given block. @note
- it also links to `person.entry` the input data `entry`.
@param entries [Eco::API::Common::People::Entries] the input entries with the data. @param people [Eco::API::Organization::People] target existing People of the current update. @param options [Hash] the options. @param log_present [Boolean] log error message if an `entry` has match in `people`. @param append_created [Boolean] whether or not a new person will be added to the `people` object. @yield [entry, person] gives each new `person` of `entries` that is not present in `people`. @yieldparam entry [PersonEntry] the input entry with the data we should set on person. @yieldparam person [Ecoportal::API::V1::Person] the new person. @return [Eco::API::Organization::People] the starters.
# File lib/eco/api/microcases/with_each_starter.rb, line 16 def with_each_starter(entries, people, options, log_present: false, append_created: true) starters = [] micro.with_each(entries, people, options, append_created: append_created) do |entry, person| if !person.new? if log_present session.logger.error("This person (id: '#{person.id}') already exists: #{entry.to_s(:identify)}") end next end starters << person yield(entry, person) if block_given? end people.newFrom starters end
Finds all the subordinates of `supervisor`. @note if `supervisor` is `nil`, it will return all people with no supervisor. @param supervisor [String, Ecoportal::API::V1::Person
, Hash] the `supervisor` or the `id` / `external_id` thereof. @param people [Eco::API::Organization::People] target existing People of the current update. @yield [subordinate] block that does some stuff with `subordinate`. @yieldparam subordinate [Ecoportal::API::V1::Person] each one of the suborinates of `supervisor`. @return [Eco::API::Organization::People] the subordinates of `supervisor`.
# File lib/eco/api/microcases/with_each_subordinate.rb, line 11 def with_each_subordinate(supervisor, people) people.supervisor_id(_person_id(supervisor, people)).tap do |subordinates| subordinates.each do |subordinate| yield(subordinate) if block_given? end end end
Finds the supervisor among `people` by using the `supervisor_id` of `value`. @param value [String, Ecoportal::API::V1::Person
, Hash] the subordinate person,
or the unique identifier of the supervisor to be found (preferably the `external_id`).
@param people [Eco::API::Organization::People] target existing People of the current update. @param strict [Boolean] specifies if the search should be `strict` (see {Eco::API::Organization::People#person}). @yield [supervisor] block that does some stuff with supevisor. @yieldparam supervisor [Ecoportal::API::V1::Person] the person object of the supervisor, or `nil` if not found. @return [nil, Ecoportal::API::V1::Person] found `supervisor` of `value`.
# File lib/eco/api/microcases/with_supervisor.rb, line 12 def with_supervisor(value, people, strict: false) if sup_id = with_supervisor_supervisor_id(value) people.person(id: sup_id, external_id: sup_id, email: sup_id, strict: strict) end.tap do |supervisor| yield(supervisor) if block_given? end end
Private Instance Methods
# File lib/eco/api/microcases/fix_default_group.rb, line 26 def __def_usergroup_id @def_usergroup_id ||= if session.config.people.default_usergroup? session.policy_groups.to_id(session.config.people.default_usergroup) end end
# File lib/eco/api/microcases/with_each_subordinate.rb, line 21 def _person_id(value, people) case value when Hash _person_id(value["id"] || value["external_id"], people) when Ecoportal::API::V1::Person _person_id(value.id || value.external_id, people) when String micro.with_supervisor(value, people)&.id end end
# File lib/eco/api/microcases/with_each.rb, line 42 def _with_each_prompt_to_select_user(error, entry: nil, increase_count: true) unless error.is_a?(Eco::API::Organization::People::MultipleSearchResults) raise "Expecting Eco::API::Organization::People::MultipleSearchResults. Given: #{error.class}" end @_with_each_prompts = 0 unless instance_variable_defined?(:@_with_each_prompts) @_with_each_prompts += 1 if increase_count lines = [] lines << "\n(#{@_with_each_prompts}) " + error.to_s + "\n" lines << " #index - Select the correct person by its number index among the list above." lines << " (I) - Just Skip/Ignore this one. I will deal with that input entry in another launch." lines << " (A) - Ignore all the rest of input entries with this problem." lines << " (C) - Create a new person." lines << " (B) - Just break this script. I need to change the input file :/" prompt_user("Type one option (#number/I/A/C/B):", explanation: lines.join("\n"), default: "I") do |res| res = res.upcase case when res.start_with?("I") logger.info "Ignoring entry... #{entry.to_s(:identify) if entry}" nil when res.start_with?("A") logger.info "All input entries with this same issue will be ignored for this launch" @_skip_all_multiple_results = true nil when res.start_with?("C") logger.info "Creating new person...#{"for entry #{entry.to_s(:identify)}" if entry}" session.new_person when res.start_with?("B") raise error when res && !res.empty? && (pos = res.to_i rescue nil) && (pos < error.candidates.length) error.candidate(pos).tap do |person| logger.info "Thanks!! You selected #{person.identify}" sleep(1.5) end else if pos.is_a?(Numeric) && (pos >= error.candidates.length) print "#{pos} is not a number in the range. " else print "#{res} is not an option. " end puts "Please select one of the offered options..." sleep(1) _with_each_prompt_to_select_user(error, increase_count: false, entry: entry) end end end
# File lib/eco/api/microcases/set_supervisor.rb, line 35 def descrease_subordinates(person, by = 1) if person.is_a?(Ecoportal::API::V1::Person) person.subordinates -= by #person.subordinates = 0 if person.subordinates < 0 end end
# File lib/eco/api/microcases/set_supervisor.rb, line 42 def increase_subordinates(person, by = 1) if person.is_a?(Ecoportal::API::V1::Person) #person.subordinates = 0 if person.subordinates < 0 person.subordinates += by end end
# File lib/eco/api/microcases/people_load.rb, line 54 def people_load_filename(filename, newest: false) if newest # search input file based on pattern (in case the name has a timestamp) file_manager.dir.newest_file(file: filename).tap do |file| logger.info("previous file found: #{file}") if file end else file_manager.dir.file(filename, should_exist: true) end end
Prepares a unique request with only the supervisor ids missing in `people`
# File lib/eco/api/microcases/people_search.rb, line 66 def people_search_prepare_supers_request(data, people = data) data.each_with_object([]) do |entry, request| spr = {"id" => (sup_id = people_search_super_id(entry))} unless !sup_id || request.include?(spr) micro.with_supervisor(sup_id, people) do |supervisor| request.push(spr) unless supervisor end end end end
Gets the `supervisor_id` from `value`
# File lib/eco/api/microcases/people_search.rb, line 78 def people_search_super_id(value) sup_id = if value.respond_to?(:supervisor_id) value.supervisor_id elsif value.is_a?(Hash) && value.key("supervisor_id") value["supervisor_id"] end sup_id = nil if sup_id.to_s.strip.empty? sup_id end
# File lib/eco/api/microcases/with_supervisor.rb, line 22 def with_supervisor_supervisor_id(value) return nil if value.to_s.strip.empty? case when value.respond_to?(:supervisor_id) value.supervisor_id when value.is_a?(Hash) value["supervisor_id"] else value end end