Class: Organization

Overview

Organization attributes follow https://schema.org/Organization, with only housekeeping exceptions.

@!attribute alternate_name

@!attribute description

@!attribute disambiguating_description

@!attribute same_as_id @return [Organization, nil]

@!attribute address

@!attribute email

@!attribute telephone

@!attribute duns

@!attribute global_location_number

@!attribute legal_name

@!attribute area_served_id @return [GeographicArea, nil]

@!attribute department_id @return [Organization, nil]

@!attribute parent_organization_id @return [Organization, nil]

@!attribute geographic_area_id @return [GeographicArea, nil] Where the Organization is. Must resolve to a country, i.e. it is a country or any level below one.

Instance Attribute Summary collapse

Attributes included from Housekeeping::Users

#by

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Shared::IsData

#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_in_use?, #similar

Methods included from Shared::Identifiers

#dwc_occurrence_id, #identified?, #next_by_identifier, #previous_by_identifier, #reject_identifiers, #uri, #uuid, #visible_identifiers_for

Methods included from Shared::Notes

#concatenated_notes_string, #reject_notes

Methods included from Shared::Depictions

#has_depictions?, #image_array=, #reject_depictions, #reject_images

Methods included from Housekeeping::Users

#set_created_by_id, #set_updated_by_id

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Attribute Details

#nameString

Returns:

  • (String)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/models/organization.rb', line 41

class Organization < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::Depictions
  include Shared::Notes
  include Shared::Identifiers
  include Shared::SharedAcrossProjects
  include Shared::IsData

  belongs_to :parent_organization, class_name: 'Organization'
  belongs_to :department, class_name: 'Organization'
  belongs_to :same_as, class_name: 'Organization'

  belongs_to :area_served, class_name: 'GeographicArea'
  belongs_to :geographic_area, inverse_of: :organizations

  has_many :project_organizations, inverse_of: :organization, dependent: :destroy
  has_many :projects, inverse_of: :organizations, through: :project_organizations

  has_many :roles, dependent: :restrict_with_error, inverse_of: :organization #, before_remove: :set_cached_for_related

  has_many :author_roles, class_name: 'SourceAuthor', dependent: :restrict_with_error, inverse_of: :organization #, before_remove: :set_cached_for_related
  has_many :editor_roles, class_name: 'SourceEditor', dependent: :restrict_with_error, inverse_of: :organization
  has_many :source_roles, class_name: 'SourceSource', dependent: :restrict_with_error, inverse_of: :organization

  has_many :collector_roles, class_name: 'Collector', dependent: :restrict_with_error, inverse_of: :organization
  has_many :determiner_roles, class_name: 'Determiner', dependent: :restrict_with_error, inverse_of: :organization
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor', dependent: :restrict_with_error, inverse_of: :organization
  has_many :georeferencer_roles, class_name: 'Georeferencer', dependent: :restrict_with_error, inverse_of: :organization

  has_many :authored_sources, class_name: 'Source::Bibtex', through: :author_roles, source: :role_object, source_type: 'Source', inverse_of: :authors
  has_many :edited_sources, class_name: 'Source::Bibtex', through: :editor_roles, source: :role_object, source_type: 'Source', inverse_of: :editors
  has_many :human_sources, class_name: 'Source::Bibtex', through: :source_roles, source: :role_object, source_type: 'Source', inverse_of: :people
  has_many :authored_taxon_names, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName', class_name: 'Protonym', inverse_of: :taxon_name_authors
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent', inverse_of: :collectors
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference', inverse_of: :georeference_authors
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination', inverse_of: :determiners

  validates_presence_of :name
  validates_uniqueness_of :legal_name, allow_nil: true
  validates :email, format:  {with: User::VALID_EMAIL_REGEX}, allow_nil: true # TODO: unify

  validate :related_not_self
  validate :names_not_same
  validate :geographic_area_resolves_to_country

  # @return [GeographicArea, nil]
  #   the country the Organization is in
  def country
    geographic_area&.level0
  end

  # @param role_type [String] one of the Role types
  # @return [Scope]
  #    the max 10 most recently used (1 week, could parameterize) organizations
  def self.used_recently(user_id, role_type = 'AttributionOwner')
    t = Role.arel_table
    p = Organization.arel_table

    # i is a select manager
    i = t.project(t['organization_id'], t['type'], t['updated_at']).from(t)
      .where(t['updated_at'].gt(1.week.ago))
      .where(t['updated_by_id'].eq(user_id))
      .where(t['type'].eq(role_type))
      .order(t['updated_at'].desc)

    # z is a table alias
    z = i.as('recent_t')

    Organization.joins(
      Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['organization_id'].eq(p['id'])))
    ).pluck(:organization_id).uniq
  end

  # @params Role [String] one the available roles
  # @return [Hash] Organizations optimized for user selection
  def self.select_optimized(user_id, project_id, role_type = 'AttributionOwner')
    r = used_recently(user_id, role_type)
    h = {
      quick: [],
      pinboard: Organization.pinned_by(user_id).where(pinboard_items: {project_id:}).to_a,
      recent: []
    }

    if r.empty?
      h[:quick] = Organization.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).to_a
    else
      h[:recent] = Organization.where('"organizations"."id" IN (?)', r.first(10) ).to_a
      h[:quick] = (
        Organization.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).to_a +
        Organization.where('"organizations"."id" IN (?)', r.first(4) ).to_a
      ).uniq
    end
    h
  end

  protected

  def names_not_same
    errors.add(:name, 'is same as alternate name') if name == alternate_name
  end


  def related_not_self
    [:same_as_id, :department_id, :parent_organization_id].each do |a|
      b = send(a)
      errors.add(a, 'can not be self') if b && id == b
    end
  end

  def geographic_area_resolves_to_country
    return true if geographic_area.nil?
    errors.add(:geographic_area, 'does not resolve to a country') if geographic_area.level0_id.nil?
  end

end

Class Method Details

.select_optimized(user_id, project_id, role_type = 'AttributionOwner') ⇒ Hash

Returns Organizations optimized for user selection.

Returns:

  • (Hash)

    Organizations optimized for user selection



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'app/models/organization.rb', line 117

def self.select_optimized(user_id, project_id, role_type = 'AttributionOwner')
  r = used_recently(user_id, role_type)
  h = {
    quick: [],
    pinboard: Organization.pinned_by(user_id).where(pinboard_items: {project_id:}).to_a,
    recent: []
  }

  if r.empty?
    h[:quick] = Organization.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).to_a
  else
    h[:recent] = Organization.where('"organizations"."id" IN (?)', r.first(10) ).to_a
    h[:quick] = (
      Organization.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).to_a +
      Organization.where('"organizations"."id" IN (?)', r.first(4) ).to_a
    ).uniq
  end
  h
end

.used_recently(user_id, role_type = 'AttributionOwner') ⇒ Scope

Returns the max 10 most recently used (1 week, could parameterize) organizations.

Parameters:

  • role_type (String) (defaults to: 'AttributionOwner')

    one of the Role types

Returns:

  • (Scope)

    the max 10 most recently used (1 week, could parameterize) organizations



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/organization.rb', line 96

def self.used_recently(user_id, role_type = 'AttributionOwner')
  t = Role.arel_table
  p = Organization.arel_table

  # i is a select manager
  i = t.project(t['organization_id'], t['type'], t['updated_at']).from(t)
    .where(t['updated_at'].gt(1.week.ago))
    .where(t['updated_by_id'].eq(user_id))
    .where(t['type'].eq(role_type))
    .order(t['updated_at'].desc)

  # z is a table alias
  z = i.as('recent_t')

  Organization.joins(
    Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['organization_id'].eq(p['id'])))
  ).pluck(:organization_id).uniq
end

Instance Method Details

#countryGeographicArea?

Returns the country the Organization is in.

Returns:



89
90
91
# File 'app/models/organization.rb', line 89

def country
  geographic_area&.level0
end

#geographic_area_resolves_to_countryObject (protected)



151
152
153
154
# File 'app/models/organization.rb', line 151

def geographic_area_resolves_to_country
  return true if geographic_area.nil?
  errors.add(:geographic_area, 'does not resolve to a country') if geographic_area.level0_id.nil?
end

#names_not_sameObject (protected)



139
140
141
# File 'app/models/organization.rb', line 139

def names_not_same
  errors.add(:name, 'is same as alternate name') if name == alternate_name
end


144
145
146
147
148
149
# File 'app/models/organization.rb', line 144

def related_not_self
  [:same_as_id, :department_id, :parent_organization_id].each do |a|
    b = send(a)
    errors.add(a, 'can not be self') if b && id == b
  end
end