Class: Project

Inherits:
ApplicationRecord show all
Includes:
Housekeeping::AssociationHelpers, Housekeeping::Timestamps, Housekeeping::Users, Preferences
Defined in:
app/models/project.rb,
app/models/project/preferences.rb

Overview

A project is a team’s wrapper for a group of data. Most data is project specific, with a few exceptions. A project has many users, and one or more project administrators. With the exception of “Workers” who can only see and therefore use certain elements of the workbench all members of a project share the same privileges. A projects members are therefor well trained and trusted contributors to the project.

Defined Under Namespace

Modules: Preferences

Constant Summary collapse

MANIFEST =

ORDER MATTERS Used in ‘nuke` order (not available in production UI), but ultimately also for dumping records.

The intent is to use ‘delete_all` for speed. This means that callbacks are not fired (associated destroys).

%w{
   Observation
   CitationTopic
   Citation
   Note
   CharacterState
   Protocol
   AlternateValue
   DataAttribute
   TaggedSectionKeyword
   Tag
   Confidence
   Role
   SledImage
   Label
   Attribution
   DwcOccurrence
   ProtocolRelationship
   SqedDepiction
   Depiction
   Documentation
   Document
   CollectionObjectObservation
   DerivedCollectionObject
   PinboardItem
   AssertedDistribution
   BiocurationClassification
   BiologicalRelationshipType
   BiologicalAssociationsBiologicalAssociationsGraph
   BiologicalAssociation
   BiologicalRelationship
   BiologicalAssociationsGraph
   CollectionProfile
   ContainerItem
   Container
   PublicContent
   Content
   Georeference
   Identifier
   Lead
   LoanItem
   Loan
   OtuPageLayoutSection
   OtuPageLayout
   ProjectSource
   TaxonDetermination
   TypeMaterial
   RangedLotCategory
   Image
   CommonName
   TaxonNameClassification
   TaxonNameRelationship
   ControlledVocabularyTerm
   OriginRelationship
   Sequence
   SequenceRelationship
   Extract
   GeneAttribute
   ObservationMatrixColumn
   ObservationMatrixColumnItem
   ObservationMatrixRow
   ObservationMatrixRowItem
   ObservationMatrix
   FieldOccurrence
   CollectionObject
   CollectingEvent
   Otu
   OtuRelationship
   TaxonName
   Descriptor
   ProjectMember
   Download
   DatasetRecordField
   DatasetRecord
   ImportDataset
   CachedMapItem
   CachedMapRegister
   CachedMap
}.freeze

Constants included from Preferences

Preferences::BASE_PREFERENCES

Instance Attribute Summary collapse

Attributes included from Housekeeping::Users

#by

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Preferences

#fill_preferences, #layout=, #reset_preferences

Methods included from Housekeeping::AssociationHelpers

#has_many_relationship_classes, #has_many_relationships

Methods included from Housekeeping::Timestamps

#data_breakdown_for_chartkick_recent

Methods included from Housekeeping::Users

#set_created_by_id, #set_updated_by_id

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Attribute Details

#api_access_tokenString?

Returns The token is not intended to be private. Generating one is akin to indicating that your project’s data are public, and they will be exposed in the general API to all. The token is primarily for tracking “anonymous” use.

Returns:

  • (String, nil)

    The token is not intended to be private. Generating one is akin to indicating that your project’s data are public, and they will be exposed in the general API to all. The token is primarily for tracking “anonymous” use.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'app/models/project.rb', line 21

class Project < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Housekeeping::AssociationHelpers
  include Project::Preferences

  attr_accessor :without_root_taxon_name
  attr_accessor :clear_api_access_token
  attr_accessor :set_new_api_access_token

  # ORDER MATTERS
  # Used in `nuke` order (not available in production UI), but
  # ultimately also for dumping records.
  #
  # The intent is to use  `delete_all` for speed. This means
  # that callbacks are *not* fired (associated destroys).
  MANIFEST = %w{
     Observation
     CitationTopic
     Citation
     Note
     CharacterState
     Protocol
     AlternateValue
     DataAttribute
     TaggedSectionKeyword
     Tag
     Confidence
     Role
     SledImage
     Label
     Attribution
     DwcOccurrence
     ProtocolRelationship
     SqedDepiction
     Depiction
     Documentation
     Document
     CollectionObjectObservation
     DerivedCollectionObject
     PinboardItem
     AssertedDistribution
     BiocurationClassification
     BiologicalRelationshipType
     BiologicalAssociationsBiologicalAssociationsGraph
     BiologicalAssociation
     BiologicalRelationship
     BiologicalAssociationsGraph
     CollectionProfile
     ContainerItem
     Container
     PublicContent
     Content
     Georeference
     Identifier
     Lead
     LoanItem
     Loan
     OtuPageLayoutSection
     OtuPageLayout
     ProjectSource
     TaxonDetermination
     TypeMaterial
     RangedLotCategory
     Image
     CommonName
     TaxonNameClassification
     TaxonNameRelationship
     ControlledVocabularyTerm
     OriginRelationship
     Sequence
     SequenceRelationship
     Extract
     GeneAttribute
     ObservationMatrixColumn
     ObservationMatrixColumnItem
     ObservationMatrixRow
     ObservationMatrixRowItem
     ObservationMatrix
     FieldOccurrence
     CollectionObject
     CollectingEvent
     Otu
     OtuRelationship
     TaxonName
     Descriptor
     ProjectMember
     Download
     DatasetRecordField
     DatasetRecord
     ImportDataset
     CachedMapItem
     CachedMapRegister
     CachedMap
  }.freeze

  has_many :project_members, dependent: :restrict_with_error

  has_many :users, through: :project_members

  has_many :project_sources, inverse_of: :projects, dependent: :restrict_with_error
  has_many :sources, inverse_of: :projects, through: :project_sources

  before_save :generate_api_access_token, if: :set_new_api_access_token
  before_save :destroy_api_access_token, if: -> { self.clear_api_access_token}
  after_create :create_root_taxon_name, unless: -> {self.without_root_taxon_name == true}

  validates_presence_of :name
  validates_uniqueness_of :name

  def project_administrators
    users.joins(:project_members).where(project_members: {is_project_administrator: true})
  end

  def is_editable?(user)
    user = User.find(user) if !user.kind_of?(User)
    return true if user.is_administrator? || project_administrators.include?(user)
    false
  end

  # @return [Hash]
  #   for each model in manifest list its annotators
  def annotators
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.safe_constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      if !MANIFEST.include?(k)
        raise "#{k} has not been added to annotators method ."
      end
    end

    h = {}

    begin
      MANIFEST.each do |o|
        klass = o.safe_constantize

      end



      true
    rescue => e
      raise e
    end
  end

  # !! This is not production ready.
  # @return [Boolean]
  #   based on whether the project has successfully been deleted.  Can also raise on detected problems with configuration.
  def nuke
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      unless MANIFEST.include?(k)
        raise "#{k} has not been added to #nuke order."
      end
    end

    begin
      MANIFEST.each do |o|
        klass = o.constantize
        # `unscoped` disables default_scope, which would restrict which records in a project are deleted
        klass.unscoped.where(project_id: id).delete_all
      end

      self.destroy

      true
    rescue => e
      raise e
    end
  end

  # TODO: boot load checks
  def root_taxon_name
    # Calling TaxonName is a hack to load the required has_many into Project,
    # "has_many :taxon_names" is invoked through TaxonName within Housekeeping::Project
    # Within TaxonName closure_tree (appears to?) require a database connection.

    # Since we shouldn't (can't?) initiate a connection prior to a require_dependency
    # we simply load TaxonName for the first time here.
    TaxonName.tap {} # TODO: move to require_dependency?
    TaxonNameRelationship.tap {}
    taxon_names.root
  end

  def self.find_for_autocomplete(params)
    where('name LIKE ?', "#{params[:term]}%")
  end

  protected

  def create_root_taxon_name
    p = Protonym.stub_root(project_id: id, by: creator)
    p.save!
    p
  end

  # @return [String]
  def generate_api_access_token
    self.api_access_token = Utilities::RandomToken.generate
  end

  def destroy_api_access_token
    self.api_access_token = nil
  end

end

#clear_api_access_tokenObject

Returns the value of attribute clear_api_access_token.



28
29
30
# File 'app/models/project.rb', line 28

def clear_api_access_token
  @clear_api_access_token
end

#nameString

Returns The name of the project.

Returns:

  • (String)

    The name of the project



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'app/models/project.rb', line 21

class Project < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Housekeeping::AssociationHelpers
  include Project::Preferences

  attr_accessor :without_root_taxon_name
  attr_accessor :clear_api_access_token
  attr_accessor :set_new_api_access_token

  # ORDER MATTERS
  # Used in `nuke` order (not available in production UI), but
  # ultimately also for dumping records.
  #
  # The intent is to use  `delete_all` for speed. This means
  # that callbacks are *not* fired (associated destroys).
  MANIFEST = %w{
     Observation
     CitationTopic
     Citation
     Note
     CharacterState
     Protocol
     AlternateValue
     DataAttribute
     TaggedSectionKeyword
     Tag
     Confidence
     Role
     SledImage
     Label
     Attribution
     DwcOccurrence
     ProtocolRelationship
     SqedDepiction
     Depiction
     Documentation
     Document
     CollectionObjectObservation
     DerivedCollectionObject
     PinboardItem
     AssertedDistribution
     BiocurationClassification
     BiologicalRelationshipType
     BiologicalAssociationsBiologicalAssociationsGraph
     BiologicalAssociation
     BiologicalRelationship
     BiologicalAssociationsGraph
     CollectionProfile
     ContainerItem
     Container
     PublicContent
     Content
     Georeference
     Identifier
     Lead
     LoanItem
     Loan
     OtuPageLayoutSection
     OtuPageLayout
     ProjectSource
     TaxonDetermination
     TypeMaterial
     RangedLotCategory
     Image
     CommonName
     TaxonNameClassification
     TaxonNameRelationship
     ControlledVocabularyTerm
     OriginRelationship
     Sequence
     SequenceRelationship
     Extract
     GeneAttribute
     ObservationMatrixColumn
     ObservationMatrixColumnItem
     ObservationMatrixRow
     ObservationMatrixRowItem
     ObservationMatrix
     FieldOccurrence
     CollectionObject
     CollectingEvent
     Otu
     OtuRelationship
     TaxonName
     Descriptor
     ProjectMember
     Download
     DatasetRecordField
     DatasetRecord
     ImportDataset
     CachedMapItem
     CachedMapRegister
     CachedMap
  }.freeze

  has_many :project_members, dependent: :restrict_with_error

  has_many :users, through: :project_members

  has_many :project_sources, inverse_of: :projects, dependent: :restrict_with_error
  has_many :sources, inverse_of: :projects, through: :project_sources

  before_save :generate_api_access_token, if: :set_new_api_access_token
  before_save :destroy_api_access_token, if: -> { self.clear_api_access_token}
  after_create :create_root_taxon_name, unless: -> {self.without_root_taxon_name == true}

  validates_presence_of :name
  validates_uniqueness_of :name

  def project_administrators
    users.joins(:project_members).where(project_members: {is_project_administrator: true})
  end

  def is_editable?(user)
    user = User.find(user) if !user.kind_of?(User)
    return true if user.is_administrator? || project_administrators.include?(user)
    false
  end

  # @return [Hash]
  #   for each model in manifest list its annotators
  def annotators
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.safe_constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      if !MANIFEST.include?(k)
        raise "#{k} has not been added to annotators method ."
      end
    end

    h = {}

    begin
      MANIFEST.each do |o|
        klass = o.safe_constantize

      end



      true
    rescue => e
      raise e
    end
  end

  # !! This is not production ready.
  # @return [Boolean]
  #   based on whether the project has successfully been deleted.  Can also raise on detected problems with configuration.
  def nuke
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      unless MANIFEST.include?(k)
        raise "#{k} has not been added to #nuke order."
      end
    end

    begin
      MANIFEST.each do |o|
        klass = o.constantize
        # `unscoped` disables default_scope, which would restrict which records in a project are deleted
        klass.unscoped.where(project_id: id).delete_all
      end

      self.destroy

      true
    rescue => e
      raise e
    end
  end

  # TODO: boot load checks
  def root_taxon_name
    # Calling TaxonName is a hack to load the required has_many into Project,
    # "has_many :taxon_names" is invoked through TaxonName within Housekeeping::Project
    # Within TaxonName closure_tree (appears to?) require a database connection.

    # Since we shouldn't (can't?) initiate a connection prior to a require_dependency
    # we simply load TaxonName for the first time here.
    TaxonName.tap {} # TODO: move to require_dependency?
    TaxonNameRelationship.tap {}
    taxon_names.root
  end

  def self.find_for_autocomplete(params)
    where('name LIKE ?', "#{params[:term]}%")
  end

  protected

  def create_root_taxon_name
    p = Protonym.stub_root(project_id: id, by: creator)
    p.save!
    p
  end

  # @return [String]
  def generate_api_access_token
    self.api_access_token = Utilities::RandomToken.generate
  end

  def destroy_api_access_token
    self.api_access_token = nil
  end

end

#preferencesHash

Returns Settings for the project (for all users).

Returns:

  • (Hash)

    Settings for the project (for all users)



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'app/models/project.rb', line 21

class Project < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Housekeeping::AssociationHelpers
  include Project::Preferences

  attr_accessor :without_root_taxon_name
  attr_accessor :clear_api_access_token
  attr_accessor :set_new_api_access_token

  # ORDER MATTERS
  # Used in `nuke` order (not available in production UI), but
  # ultimately also for dumping records.
  #
  # The intent is to use  `delete_all` for speed. This means
  # that callbacks are *not* fired (associated destroys).
  MANIFEST = %w{
     Observation
     CitationTopic
     Citation
     Note
     CharacterState
     Protocol
     AlternateValue
     DataAttribute
     TaggedSectionKeyword
     Tag
     Confidence
     Role
     SledImage
     Label
     Attribution
     DwcOccurrence
     ProtocolRelationship
     SqedDepiction
     Depiction
     Documentation
     Document
     CollectionObjectObservation
     DerivedCollectionObject
     PinboardItem
     AssertedDistribution
     BiocurationClassification
     BiologicalRelationshipType
     BiologicalAssociationsBiologicalAssociationsGraph
     BiologicalAssociation
     BiologicalRelationship
     BiologicalAssociationsGraph
     CollectionProfile
     ContainerItem
     Container
     PublicContent
     Content
     Georeference
     Identifier
     Lead
     LoanItem
     Loan
     OtuPageLayoutSection
     OtuPageLayout
     ProjectSource
     TaxonDetermination
     TypeMaterial
     RangedLotCategory
     Image
     CommonName
     TaxonNameClassification
     TaxonNameRelationship
     ControlledVocabularyTerm
     OriginRelationship
     Sequence
     SequenceRelationship
     Extract
     GeneAttribute
     ObservationMatrixColumn
     ObservationMatrixColumnItem
     ObservationMatrixRow
     ObservationMatrixRowItem
     ObservationMatrix
     FieldOccurrence
     CollectionObject
     CollectingEvent
     Otu
     OtuRelationship
     TaxonName
     Descriptor
     ProjectMember
     Download
     DatasetRecordField
     DatasetRecord
     ImportDataset
     CachedMapItem
     CachedMapRegister
     CachedMap
  }.freeze

  has_many :project_members, dependent: :restrict_with_error

  has_many :users, through: :project_members

  has_many :project_sources, inverse_of: :projects, dependent: :restrict_with_error
  has_many :sources, inverse_of: :projects, through: :project_sources

  before_save :generate_api_access_token, if: :set_new_api_access_token
  before_save :destroy_api_access_token, if: -> { self.clear_api_access_token}
  after_create :create_root_taxon_name, unless: -> {self.without_root_taxon_name == true}

  validates_presence_of :name
  validates_uniqueness_of :name

  def project_administrators
    users.joins(:project_members).where(project_members: {is_project_administrator: true})
  end

  def is_editable?(user)
    user = User.find(user) if !user.kind_of?(User)
    return true if user.is_administrator? || project_administrators.include?(user)
    false
  end

  # @return [Hash]
  #   for each model in manifest list its annotators
  def annotators
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.safe_constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      if !MANIFEST.include?(k)
        raise "#{k} has not been added to annotators method ."
      end
    end

    h = {}

    begin
      MANIFEST.each do |o|
        klass = o.safe_constantize

      end



      true
    rescue => e
      raise e
    end
  end

  # !! This is not production ready.
  # @return [Boolean]
  #   based on whether the project has successfully been deleted.  Can also raise on detected problems with configuration.
  def nuke
    known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

    known.each do |k|
      next if k.constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
      unless MANIFEST.include?(k)
        raise "#{k} has not been added to #nuke order."
      end
    end

    begin
      MANIFEST.each do |o|
        klass = o.constantize
        # `unscoped` disables default_scope, which would restrict which records in a project are deleted
        klass.unscoped.where(project_id: id).delete_all
      end

      self.destroy

      true
    rescue => e
      raise e
    end
  end

  # TODO: boot load checks
  def root_taxon_name
    # Calling TaxonName is a hack to load the required has_many into Project,
    # "has_many :taxon_names" is invoked through TaxonName within Housekeeping::Project
    # Within TaxonName closure_tree (appears to?) require a database connection.

    # Since we shouldn't (can't?) initiate a connection prior to a require_dependency
    # we simply load TaxonName for the first time here.
    TaxonName.tap {} # TODO: move to require_dependency?
    TaxonNameRelationship.tap {}
    taxon_names.root
  end

  def self.find_for_autocomplete(params)
    where('name LIKE ?', "#{params[:term]}%")
  end

  protected

  def create_root_taxon_name
    p = Protonym.stub_root(project_id: id, by: creator)
    p.save!
    p
  end

  # @return [String]
  def generate_api_access_token
    self.api_access_token = Utilities::RandomToken.generate
  end

  def destroy_api_access_token
    self.api_access_token = nil
  end

end

#set_new_api_access_tokenObject

Returns the value of attribute set_new_api_access_token.



29
30
31
# File 'app/models/project.rb', line 29

def set_new_api_access_token
  @set_new_api_access_token
end

#without_root_taxon_nameObject

Returns the value of attribute without_root_taxon_name.



27
28
29
# File 'app/models/project.rb', line 27

def without_root_taxon_name
  @without_root_taxon_name
end

Class Method Details

.find_for_autocomplete(params) ⇒ Object



210
211
212
# File 'app/models/project.rb', line 210

def self.find_for_autocomplete(params)
  where('name LIKE ?', "#{params[:term]}%")
end

Instance Method Details

#annotatorsHash

Returns for each model in manifest list its annotators.

Returns:

  • (Hash)

    for each model in manifest list its annotators



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'app/models/project.rb', line 143

def annotators
  known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

  known.each do |k|
    next if k.safe_constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
    if !MANIFEST.include?(k)
      raise "#{k} has not been added to annotators method ."
    end
  end

  h = {}

  begin
    MANIFEST.each do |o|
      klass = o.safe_constantize

    end



    true
  rescue => e
    raise e
  end
end

#create_root_taxon_nameObject (protected)



216
217
218
219
220
# File 'app/models/project.rb', line 216

def create_root_taxon_name
  p = Protonym.stub_root(project_id: id, by: creator)
  p.save!
  p
end

#destroy_api_access_tokenObject (protected)



227
228
229
# File 'app/models/project.rb', line 227

def destroy_api_access_token
  self.api_access_token = nil
end

#generate_api_access_tokenString (protected)

Returns:

  • (String)


223
224
225
# File 'app/models/project.rb', line 223

def generate_api_access_token
  self.api_access_token = Utilities::RandomToken.generate
end

#is_editable?(user) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
138
139
# File 'app/models/project.rb', line 135

def is_editable?(user)
  user = User.find(user) if !user.kind_of?(User)
  return true if user.is_administrator? || project_administrators.include?(user)
  false
end

#nukeBoolean

!! This is not production ready.

Returns:

  • (Boolean)

    based on whether the project has successfully been deleted. Can also raise on detected problems with configuration.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'app/models/project.rb', line 172

def nuke
  known = ApplicationRecord.subclasses.select {|a| a.column_names.include?('project_id')}.map(&:name)

  known.each do |k|
    next if k.constantize.table_name == 'test_classes' # TODO: a kludge to ignore stubbed classes in testing
    unless MANIFEST.include?(k)
      raise "#{k} has not been added to #nuke order."
    end
  end

  begin
    MANIFEST.each do |o|
      klass = o.constantize
      # `unscoped` disables default_scope, which would restrict which records in a project are deleted
      klass.unscoped.where(project_id: id).delete_all
    end

    self.destroy

    true
  rescue => e
    raise e
  end
end

#project_administratorsObject



131
132
133
# File 'app/models/project.rb', line 131

def project_administrators
  users.joins(:project_members).where(project_members: {is_project_administrator: true})
end

#root_taxon_nameObject

TODO: boot load checks



198
199
200
201
202
203
204
205
206
207
208
# File 'app/models/project.rb', line 198

def root_taxon_name
  # Calling TaxonName is a hack to load the required has_many into Project,
  # "has_many :taxon_names" is invoked through TaxonName within Housekeeping::Project
  # Within TaxonName closure_tree (appears to?) require a database connection.

  # Since we shouldn't (can't?) initiate a connection prior to a require_dependency
  # we simply load TaxonName for the first time here.
  TaxonName.tap {} # TODO: move to require_dependency?
  TaxonNameRelationship.tap {}
  taxon_names.root
end