• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

curationexperts / laevigata / 30f93d48-e4b2-44ea-965a-de964df4c66f

14 May 2025 04:41PM UTC coverage: 97.411%. Remained the same
30f93d48-e4b2-44ea-965a-de964df4c66f

push

circleci

mark-dce
Corrects spelling mistake

"Afer" --> "After"

2822 of 2897 relevant lines covered (97.41%)

52.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/app/models/in_progress_etd.rb
1
# frozen_string_literal: true
2

3
# This class is used to represent an `Etd` record.
4
# It holds the data in a JSON data store for use by
5
# the Vue form.
6
#
7
# If the student fills in part of the form and saves,
8
# the partially-filled-in data will be saved in the
9
# `data` field.  If the student wants to continue
10
# editing their ETD later, this data will be used to
11
# populate the form with the data the student had
12
# previously saved.
13
#
14
# After the `Etd` record has been created in fedora
15
# (the student filled in the entire form and
16
# submitted it for approval), this class will still
17
# be used to represent the `Etd` in the Vue form, but
18
# its `data` field might need to be refreshed from
19
# the data on the `Etd` record that it represents.
20

21
class InProgressEtd < ApplicationRecord
4✔
22
  NO_EMBARGO = 'None - open access immediately'
4✔
23

24
  after_create :add_id_to_data_store
4✔
25

26
  # custom validators check for presence of tab-determined set of fields based on presence of tab-identifying data
27
  validates_with AboutMeValidator
4✔
28
  validates_with MyProgramValidator
4✔
29
  validates_with MyEtdValidator
4✔
30
  validates_with MyAdvisorValidator
4✔
31
  validates_with KeywordValidator
4✔
32
  validates_with EmbargoValidator
4✔
33
  validates_with MyFilesValidator
4✔
34

35
  # @param new_data [Hash, HashWithIndifferentAccess] New data to add to the existing data store.
36
  # @return [Hash] The resulting hash, with new data added to old data.
37
  # Note: new_data might only have a few fields in it.
38
  # We can't assume that new_data contains a full set
39
  # of metadata, so, for example, we can't assume that
40
  # the absence of a key means that a field should be
41
  # deleted.
42
  # This method has evolved and uses knowledge of
43
  # which metadata fields come from which tabs on
44
  # the edit form to delete or transform some of the
45
  # fields.  Time to refactor?  Instead of polluting
46
  # the back end code with knowledge about the form,
47
  # we could change the form to always submit all the
48
  # data from each tab, including blank fields.
49
  # Blank fields should be first-class data, just like
50
  # populated fields.
51
  def add_data(new_data)
4✔
52
    json_data = data || {}.to_json
62✔
53
    existing_data = JSON.parse(json_data)
62✔
54
    return existing_data unless new_data
62✔
55

56
    new_data = keep_last_completed_step(existing_data, new_data)
60✔
57
    new_data = keep_school_has_changed(existing_data, new_data)
60✔
58
    new_data = strip_blank_fields(new_data)
60✔
59
    remove_blank_members(new_data)
60✔
60
    remove_blank_supp_files(new_data)
60✔
61

62
    resulting_data = existing_data.merge(new_data)
60✔
63
    self.data = resulting_data.to_json
60✔
64
    resulting_data
60✔
65
  end
66

67
  # If we see the 'files' key in the new_data, then
68
  # we assume that we are submitting data from the
69
  # 'My Files' tab, so if the (optional) fields for
70
  # supplemental files aren't present, we can assume
71
  # the student deleted all the supplemental files
72
  # from the form, so we should also delete those
73
  # files from the cached data on the model.
74
  def remove_blank_supp_files(new_data)
4✔
75
    return unless new_data.key?('files')
60✔
76
    return unless new_data['supplemental_files'].blank?
4✔
77
    new_data['supplemental_files'] = nil
3✔
78
    new_data['supplemental_file_metadata'] = nil
3✔
79
  end
80

81
  # If we see the committee_chair_attributes key in
82
  # the new_data, then we assume that we are
83
  # submitting data from the 'My Advisor' tab, so
84
  # if (optional) committee members field is
85
  # missing from the keys, we can assume the student
86
  # deleted all the committee members off the form,
87
  # and then we should delete the members from the
88
  # cached data on the model.
89
  def remove_blank_members(new_data)
4✔
90
    return unless new_data.key?('committee_chair_attributes')
60✔
91
    return unless new_data['committee_members_attributes'].blank?
3✔
92
    new_data['committee_members_attributes'] = []
1✔
93
  end
94

95
  def strip_blank_fields(new_data)
4✔
96
    new_data.each do |key, value|
60✔
97
      next unless value.respond_to?(:reject)
145✔
98
      new_data[key] = value.reject { |v| v.blank? }
32✔
99
    end
100
    new_data
60✔
101
  end
102

103
  def keep_last_completed_step(existing_data, new_data)
4✔
104
    return new_data unless new_data[:currentStep]
60✔
105
    new_data[:currentStep] = existing_data['currentStep'] if existing_data.keys.include?('currentStep') && existing_data['currentStep'] >= new_data[:currentStep]
10✔
106
    new_data
10✔
107
  end
108

109
  def keep_school_has_changed(existing_data, new_data)
4✔
110
    return new_data unless etd_id.blank?
60✔
111
    if existing_data['school'].blank? || new_data[:school].blank?
51✔
112
      new_data[:schoolHasChanged] = false
50✔
113
      return new_data
50✔
114
    end
115

116
    new_data[:schoolHasChanged] = new_data[:school] != existing_data['school'] ? true : false
1✔
117
    new_data
1✔
118
  end
119

120
  # Store this record's ID for the javascript form to use.
121
  def add_id_to_data_store
4✔
122
    return unless id
28✔
123
    add_data('ipe_id' => id)
28✔
124
    save
28✔
125
  end
126

127
  # If this record is associated with an Etd record
128
  # that has already been persisted to fedora, we
129
  # need to refresh the JSON data store with the
130
  # latest data from the Etd.  (This record
131
  # may contain stale data if the Etd record was
132
  # updated outside the UI, e.g. a background job.)
133
  def refresh_from_etd!
4✔
134
    return if etd_id.blank?
11✔
135
    etd = Etd.find etd_id
8✔
136
    new_data = {}
8✔
137
    new_data['ipe_id'] = id unless id.blank?
8✔
138
    new_data['etd_id'] = etd_id
8✔
139

140
    all_simple_fields.each do |field|
8✔
141
      new_value = etd.send field
120✔
142
      # Fedora returns arrays for these -- we aren't using arrays in the form
143
      # so this needs to use an array accessor
144
      new_data[field] = new_value[0] unless new_value.blank?
120✔
145
    end
146

147
    # Single value fields or fields that need special handling
148
    new_data['degree_awarded'] = etd.degree_awarded # Needed by javascript
8✔
149
    new_data['embargo_length'] = etd.embargo_length
8✔
150
    new_data['keyword'] = etd.keyword
8✔
151
    new_data['department'] = etd.department
8✔
152
    new_data['research_field'] = etd.research_field
8✔
153
    new_data['other_copyrights'] = etd.other_copyrights
8✔
154
    new_data['patents'] = etd.patents
8✔
155
    new_data['requires_permissions'] = etd.requires_permissions
8✔
156
    new_data['partnering_agency'] = etd.partnering_agency
8✔
157
    new_data['graduation_date'] = etd.graduation_date
8✔
158
    new_data['embargo_type'] = etd.embargo_type
8✔
159
    new_data['committee_members_attributes'] = etd.committee_members
8✔
160
    new_data['committee_chair_attributes'] = etd.committee_chair
8✔
161

162
    primary_file = file_for_refresh(etd.primary_file_fs.first)
8✔
163
    new_data['files'] = primary_file.to_json unless primary_file.blank?
8✔
164

165
    unless etd.supplemental_files_fs.blank?
8✔
166
      new_data['supplemental_files'], new_data['supplemental_file_metadata'] = supplemental_files_for_refresh(etd)
1✔
167
    end
168

169
    self.data = new_data.to_json
8✔
170
    save!
8✔
171
  end
172

173
  # Information about the supplemental files that the JavaScript needs for the edit form.
174
  # @returns {Array} that contains 2 things: 'supplemental_files' (an array converted to JSON), and 'supplemental_file_metadata' (an array).
175
  # The 2 arrays are expected to keep the same order between them.
176
  # For example, the metadata in array index 0 of supplemental_files_metadata belongs to the file described in array index 0 of supplemental_files.
177
  def supplemental_files_for_refresh(etd)
4✔
178
    supp_files = []
1✔
179
    supp_files_metadata = []
1✔
180

181
    etd.supplemental_files_fs.each do |supp_file|
1✔
182
      supp_files << file_for_refresh(supp_file)
2✔
183
      supp_files_metadata << file_metadata_for_refresh(supp_file)
2✔
184
    end
185

186
    [supp_files.to_json, supp_files_metadata]
1✔
187
  end
188

189
  # Information about the file that the JavaScript needs for display and to render the 'Remove' button.
190
  def file_for_refresh(file_set)
4✔
191
    return if file_set.blank?
10✔
192
    {
193
      'id' => file_set.id,
5✔
194
      'name' => file_set.label,
195
      'size' => file_set.file_size.first,
196
      'deleteUrl' => Rails.application.class.routes.url_helpers.hyrax_file_set_path(file_set),
197
      'deleteType' => 'DELETE'
198
    }
199
  end
200

201
  # The metadata fields for the supplemental files on the ETD edit form.
202
  def file_metadata_for_refresh(file_set)
4✔
203
    return if file_set.blank?
2✔
204
    {
205
      'filename' => file_set.label,
2✔
206
      'title' => file_set.title,
207
      'description' => file_set.description,
208
      'file_type' => file_set.file_type
209
    }
210
  end
211

212
  # All the fields that this model needs to know,
213
  # except the fields for committee chairs and
214
  # members, which are nested fields.
215
  def all_simple_fields
4✔
216
    ::Hyrax::EtdForm.about_me_terms +
8✔
217
      ::Hyrax::EtdForm.my_program_terms +
218
      ::Hyrax::EtdForm.my_etd_terms +
219
      ::Hyrax::EtdForm.keyword_terms
220
  end
221
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc