Class: Project
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Project
- Defined in:
- app/models/project.rb
Constant Summary collapse
- PENDING_STATUS =
Valid project status described in ADR 7 See ‘architecture-decisions/0007-valid-project-statuses.md`
"pending"
- APPROVED_STATUS =
"approved"
- ACTIVE_STATUS =
"active"
Class Method Summary collapse
- .approved_projects ⇒ Object
- .data_user_projects(user) ⇒ Object
- .default_storage_capacity ⇒ Object
- .default_storage_usage ⇒ Object
- .managed_projects(manager) ⇒ Object
- .pending_projects ⇒ Object
-
.safe_name(name) ⇒ Object
Ensure that the project directory is a valid path.
- .sponsored_projects(sponsor) ⇒ Object
- .users_projects(user) ⇒ Object
Instance Method Summary collapse
- #activate!(collection_id:, current_user:) ⇒ Object
- #approve!(mediaflux_id:, current_user:) ⇒ Object
- #asset_count(session_id:) ⇒ Object
- #create!(initial_metadata:, user:) ⇒ Object
- #created_by_user ⇒ Object
- #departments ⇒ Object
- #draft_doi(user:) ⇒ Object
-
#file_list(session_id:, size: 10) ⇒ Object
Fetches the first n files.
-
#file_list_to_file(session_id:, filename:) ⇒ Object
Fetches the entire file list to a file.
- #in_mediaflux? ⇒ Boolean
- #mediaflux_document ⇒ Object
- #mediaflux_metadata(session_id:) ⇒ Object
-
#metadata ⇒ Object
Ideally this method should return a ProjectMetadata object (like ‘metadata_model` does) but we’ll keep them both while we are refactoring the code so that we don’t break everything at once since ‘metadata` is used everywhere.
- #metadata=(metadata_model) ⇒ Object
- #metadata_model ⇒ Object
- #metadata_model=(new_metadata_model) ⇒ Object
- #pending? ⇒ Boolean
- #project_directory ⇒ Object
- #project_directory_parent_path ⇒ Object
- #project_directory_short ⇒ Object
- #reload ⇒ Object
- #save_in_mediaflux(user:) ⇒ Object
- #status ⇒ Object
- #storage_capacity(session_id:) ⇒ Object
- #storage_capacity_raw(session_id:) ⇒ Object
- #storage_usage(session_id:) ⇒ Object
- #storage_usage_raw(session_id:) ⇒ Object
- #title ⇒ Object
- #to_xml ⇒ Object
Class Method Details
.approved_projects ⇒ Object
174 175 176 |
# File 'app/models/project.rb', line 174 def self.approved_projects Project.where("mediaflux_id IS NOT NULL") end |
.data_user_projects(user) ⇒ Object
178 179 180 181 182 183 184 |
# File 'app/models/project.rb', line 178 def self.data_user_projects(user) # See https://scalegrid.io/blog/using-jsonb-in-postgresql-how-to-effectively-store-index-json-data-in-postgresql/ # for information on the @> operator query_ro = '{"data_user_read_only":["' + user + '"]}' query_rw = '{"data_user_read_write":["' + user + '"]}' Project.where("(metadata_json @> ? :: jsonb) OR (metadata_json @> ? :: jsonb)", query_ro, query_rw) end |
.default_storage_capacity ⇒ Object
236 237 238 |
# File 'app/models/project.rb', line 236 def self.default_storage_capacity "0 GB" end |
.default_storage_usage ⇒ Object
215 216 217 |
# File 'app/models/project.rb', line 215 def self.default_storage_usage "0 KB" end |
.managed_projects(manager) ⇒ Object
166 167 168 |
# File 'app/models/project.rb', line 166 def self.managed_projects(manager) Project.where("metadata_json->>'data_manager' = ?", manager) end |
.pending_projects ⇒ Object
170 171 172 |
# File 'app/models/project.rb', line 170 def self.pending_projects Project.where("mediaflux_id IS NULL") end |
.safe_name(name) ⇒ Object
Ensure that the project directory is a valid path
303 304 305 306 |
# File 'app/models/project.rb', line 303 def self.safe_name(name) # only alphanumeric characters name.strip.gsub(/[^A-Za-z\d]/, "-") end |
.sponsored_projects(sponsor) ⇒ Object
162 163 164 |
# File 'app/models/project.rb', line 162 def self.sponsored_projects(sponsor) Project.where("metadata_json->>'data_sponsor' = ?", sponsor) end |
.users_projects(user) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'app/models/project.rb', line 143 def self.users_projects(user) # See https://scalegrid.io/blog/using-jsonb-in-postgresql-how-to-effectively-store-index-json-data-in-postgresql/ # for information on the @> operator uid = user.uid query_ro = '{"data_user_read_only":["' + uid + '"]}' query_rw = '{"data_user_read_write":["' + uid + '"]}' query = "(metadata_json @> ? :: jsonb) OR (metadata_json @> ? :: jsonb)" args = [query_ro, query_rw] if user.eligible_sponsor? query += "OR (metadata_json->>'data_sponsor' = ?)" args << uid end if user.eligible_manager? query += "OR (metadata_json->>'data_manager' = ?)" args << uid end Project.where( query, *args) end |
Instance Method Details
#activate!(collection_id:, current_user:) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'app/models/project.rb', line 52 def activate!(collection_id:, current_user:) response = Mediaflux::AssetMetadataRequest.new(session_token: current_user.mediaflux_session, id: collection_id) = response. # get the metadata of the collection from mediaflux return unless [:collection] == true # If the collection id exists # check if the project doi in rails matches the project doi in mediaflux return unless [:project_id] == self..project_id # activate a project by setting the status to 'active' self..status = Project::ACTIVE_STATUS # also read in the actual project directory self..project_directory = [:project_directory] self.save! ProvenanceEvent.generate_active_events(project: self, user: current_user) end |
#approve!(mediaflux_id:, current_user:) ⇒ Object
35 36 37 38 39 40 41 42 43 44 |
# File 'app/models/project.rb', line 35 def approve!(mediaflux_id:, current_user:) self.mediaflux_id = mediaflux_id self..status = Project::APPROVED_STATUS self.save! # create two provenance events, one for approving the project and # another for changing the status of the project ProvenanceEvent.generate_approval_events(project: self, user: current_user) end |
#asset_count(session_id:) ⇒ Object
210 211 212 213 |
# File 'app/models/project.rb', line 210 def asset_count(session_id:) values = (session_id:) values.fetch(:total_file_count, 0) end |
#create!(initial_metadata:, user:) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'app/models/project.rb', line 18 def create!(initial_metadata:, user:) self. = if self.valid? if .project_id == ProjectMetadata::DOI_NOT_MINTED self.draft_doi(user: user) self.save! ProvenanceEvent.generate_submission_events(project: self, user: user) else self.save! end # return doi self..project_id else nil end end |
#created_by_user ⇒ Object
190 191 192 |
# File 'app/models/project.rb', line 190 def created_by_user User.find_by(uid: .created_by) end |
#departments ⇒ Object
101 102 103 104 |
# File 'app/models/project.rb', line 101 def departments unsorted = .departments || [] unsorted.sort end |
#draft_doi(user:) ⇒ Object
71 72 73 74 |
# File 'app/models/project.rb', line 71 def draft_doi(user:) puldatacite = PULDatacite.new self..project_id = puldatacite.draft_doi end |
#file_list(session_id:, size: 10) ⇒ Object
Fetches the first n files
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'app/models/project.rb', line 257 def file_list(session_id:, size: 10) return { files: [] } if mediaflux_id.nil? query_req = Mediaflux::QueryRequest.new(session_token: session_id, collection: mediaflux_id, deep_search: true, aql_query: "type!='application/arc-asset-collection'") iterator_id = query_req.result iterator_req = Mediaflux::IteratorRequest.new(session_token: session_id, iterator: iterator_id, size: size) results = iterator_req.result # Destroy _after_ fetching the first set of results from iterator_req. # This call is required since it possible that we have read less assets than # what the collection has but we are done with the iterator. Mediaflux::IteratorDestroyRequest.new(session_token: session_id, iterator: iterator_id).resolve results end |
#file_list_to_file(session_id:, filename:) ⇒ Object
Fetches the entire file list to a file
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'app/models/project.rb', line 275 def file_list_to_file(session_id:, filename:) return { files: [] } if mediaflux_id.nil? query_req = Mediaflux::QueryRequest.new(session_token: session_id, collection: mediaflux_id, deep_search: true, aql_query: "type!='application/arc-asset-collection'") iterator_id = query_req.result File.open(filename, "w") do |file| # file header file.write("ID, PATH, NAME, COLLECTION?, LAST_MODIFIED, SIZE\r\n") loop do iterator_req = Mediaflux::IteratorRequest.new(session_token: session_id, iterator: iterator_id, size: 1000) iterator_resp = iterator_req.result lines = files_from_iterator(iterator_resp) file.write(lines.join("\r\n") + "\r\n") break if iterator_resp[:complete] || iterator_req.error? end end # Destroy _after_ fetching the results from iterator_req # This call is technically not necessary since Mediaflux automatically deletes the iterator # once we have ran through it and by now we have. But it does not hurt either. Mediaflux::IteratorDestroyRequest.new(session_token: session_id, iterator: iterator_id).resolve end |
#in_mediaflux? ⇒ Boolean
139 140 141 |
# File 'app/models/project.rb', line 139 def in_mediaflux? mediaflux_id.present? end |
#mediaflux_document ⇒ Object
198 199 200 |
# File 'app/models/project.rb', line 198 def mediaflux_document ProjectMediaflux.document(project: self) end |
#mediaflux_metadata(session_id:) ⇒ Object
202 203 204 205 206 207 208 |
# File 'app/models/project.rb', line 202 def (session_id:) @mediaflux_metadata ||= begin accum_req = Mediaflux::AssetMetadataRequest.new(session_token: session_id, id: mediaflux_id) accum_req. end @mediaflux_metadata end |
#metadata ⇒ Object
Ideally this method should return a ProjectMetadata object (like ‘metadata_model` does) but we’ll keep them both while we are refactoring the code so that we don’t break everything at once since ‘metadata` is used everywhere.
79 80 81 |
# File 'app/models/project.rb', line 79 def @metadata_hash = ( || {}).with_indifferent_access end |
#metadata=(metadata_model) ⇒ Object
91 92 93 94 95 |
# File 'app/models/project.rb', line 91 def () # Convert our metadata to a hash so it can be saved on our JSONB field = JSON.parse(.to_json) self. = end |
#metadata_model ⇒ Object
83 84 85 |
# File 'app/models/project.rb', line 83 def @metadata_model ||= ProjectMetadata.new_from_hash(self.) end |
#metadata_model=(new_metadata_model) ⇒ Object
87 88 89 |
# File 'app/models/project.rb', line 87 def () @metadata_model = end |
#pending? ⇒ Boolean
135 136 137 |
# File 'app/models/project.rb', line 135 def pending? status == PENDING_STATUS end |
#project_directory ⇒ Object
106 107 108 109 110 111 112 113 114 |
# File 'app/models/project.rb', line 106 def project_directory return nil if .project_directory.nil? dirname, basename = project_directory_pathname.split if (dirname.relative?) "#{Mediaflux::Connection.root_namespace}/#{safe_name(.project_directory)}" else project_directory_pathname.to_s end end |
#project_directory_parent_path ⇒ Object
116 117 118 119 120 121 122 123 124 |
# File 'app/models/project.rb', line 116 def project_directory_parent_path return Mediaflux::Connection.root_namespace if .project_directory.nil? dirname = project_directory_pathname.dirname if (dirname.relative?) Mediaflux::Connection.root_namespace else dirname.to_s end end |
#project_directory_short ⇒ Object
126 127 128 129 |
# File 'app/models/project.rb', line 126 def project_directory_short return nil if .project_directory.nil? project_directory_pathname.basename.to_s end |
#reload ⇒ Object
46 47 48 49 50 |
# File 'app/models/project.rb', line 46 def reload super @metadata_model = ProjectMetadata.new_from_hash(self.) self end |
#save_in_mediaflux(user:) ⇒ Object
186 187 188 |
# File 'app/models/project.rb', line 186 def save_in_mediaflux(user:) ProjectMediaflux.save(project: self, user: user) end |
#status ⇒ Object
131 132 133 |
# File 'app/models/project.rb', line 131 def status .status end |
#storage_capacity(session_id:) ⇒ Object
240 241 242 243 244 245 246 247 248 |
# File 'app/models/project.rb', line 240 def storage_capacity(session_id:) values = (session_id:) quota_value = values.fetch(:quota_allocation, '') #if quota does not exist, set value to an empty string if quota_value.blank? return self.class.default_storage_capacity else return quota_value end end |
#storage_capacity_raw(session_id:) ⇒ Object
250 251 252 253 254 |
# File 'app/models/project.rb', line 250 def storage_capacity_raw(session_id:) values = (session_id:) quota_value = values.fetch(:quota_allocation_raw, 0) #if quota does not exist, set value to 0 quota_value end |
#storage_usage(session_id:) ⇒ Object
219 220 221 222 223 224 225 226 227 228 |
# File 'app/models/project.rb', line 219 def storage_usage(session_id:) values = (session_id:) quota_value = values.fetch(:quota_used, '') if quota_value.blank? return self.class.default_storage_usage else return quota_value end end |
#storage_usage_raw(session_id:) ⇒ Object
230 231 232 233 234 |
# File 'app/models/project.rb', line 230 def storage_usage_raw(session_id:) values = (session_id:) quota_value = values.fetch(:quota_used_raw, 0) quota_value end |
#title ⇒ Object
97 98 99 |
# File 'app/models/project.rb', line 97 def title self..title end |
#to_xml ⇒ Object
194 195 196 |
# File 'app/models/project.rb', line 194 def to_xml ProjectMediaflux.xml_payload(project: self) end |