module Eco module API module Organization class People < Eco::Language::Models::Collection # build the shortcuts of Collection attr_presence :account, :details attr_collection :id, :external_id, :email, :name, :supervisor_id alias_method :people, :to_a def initialize(people = [], klass: Ecoportal::API::Internal::Person) @klass = Ecoportal::API::Internal::Person unless klass == Ecoportal::API::V1::Person super(people, klass: @klass) @caches_init = false end # @!group Main identifier helpers def id(*args) attr('id', *args).first end def external_id(*args) attr('external_id', *args).first end def [](id_or_ext) id(id_or_ext) || external_id(id_or_ext) end # @!endgroup # @!group Special filters def users account_present(true) end def contacts details_present(true) end def non_users account_present(false) end def supervisors sup_ids = self.ids & self.supervisor_ids sup_ids.map do |id| person(id: id, strict: true) end.yield_self do |supervisors| newFrom supervisors end end def missing_supervisors_ids sup_ids = self.supervisor_ids sup_ids - (sup_ids & self.ids) end def filter_tags_any(tags) attr("filter_tags", tags, default_modifier.any.insensitive) end def filter_tags_all(tags) attr("filter_tags", tags, default_modifier.all.insensitive) end def policy_group_ids_any(ids) attr("policy_group_ids", tags, default_modifier.any.insensitive) end def policy_group_ids_all(ids) attr("policy_group_ids", tags, default_modifier.all.insensitive) end # @!endgroup # @!group Searchers # It searches a person using the parameters given. # @param id [String] the `internal id` of the person # @param external_id [String] the `exernal_id` of the person # @param email [String] the `email` of the person # @param strict [Boolean] if should perform a `soft` or a `strict` search. `strict` will avoid repeated email addresses. # @return [Person, nil] the person we were searching, or `nil` if not found. def person(id: nil, external_id: nil, email: nil, strict: false) init_caches pers = @by_id[id]&.first if id pers = @by_external_id[external_id&.strip]&.first if !pers && !external_id.to_s.strip.empty? # strict prevents taking existing user for searched person with same email # specially useful if the organisation ensures all have external id (no need for email search) if !pers && (!strict || external_id.to_s.strip.empty?) # person still not found and either not strict or no external_id provided pers = @by_users_email[email&.downcase.strip]&.first if !email.to_s.strip.empty? if !pers && !strict && !email.to_s.strip.empty? candidates = @by_non_users_email[email&.downcase.strip] || [] raise "Too many non-user candidates (#{candidates.length}) with email '#{email}'" if candidates.length > 1 pers = candidates.first end pers = @by_external_id[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty? end pers end def find(object, strict: false) id = attr_value(object, "id") external_id = attr_value(object, "external_id") email = attr_value(object, "email") person(id: id, external_id: external_id, email: email, strict: strict) end # @!endgroup # @!group Basic Collection Methods def to_json to_a.to_json end def newFrom(data) self.class.new(data, klass: @klass) end def uniq(strict: false, include_unsearchable: false) unsearchable = [] to_a.each_with_object([]) do |person, people| if found = find(person, strict: strict) people << found else unsearchable << person end end.yield_self do |found| found += unsearchable if include_unsearchable newFrom found end end def merge(data, strict: false, uniq: true) list = uniq ? exclude_people(data, strict: strict).to_a : to_a data = data.to_a unless data.is_a?(Array) newFrom list + data end def exclude(object, strict: false) exclude_people(into_a(object), strict: strict) end def exclude!(object, strict: false) self < exclude(object, strict: strict) end def exclude_people(list, strict: false) list.map do |person| find(person, strict: strict) end.compact.yield_self do |discarded| newFrom to_a - discarded end end # @!endgroup # @!group Groupping methods def email_id_maps users.group_by(:email).transform_values { |person| person.id } end def group_by_supervisor to_h(:supervisor_id) end def to_h(attr = "id") super(attr || "id") end # @!endgroup protected def on_change @caches_init = false end private def init_caches return if @caches_init @by_id = to_h @by_external_id = to_h('external_id') @by_users_email = users.to_h('email') @by_non_users_email = non_users.to_h('email') @caches_init = true end end end end end