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

pulibrary / tigerdata-app / 700664ce-9925-405e-8380-cada5d7c2e48

07 Nov 2025 06:12PM UTC coverage: 91.229% (-0.1%) from 91.357%
700664ce-9925-405e-8380-cada5d7c2e48

Pull #2168

circleci

bess
Refactoring to allow easier integration of the new LUX widget
The lux widget takes the name of the routine to call when the input changes.  Making the url integrated with the page will allow us to more easily call the lookup routine

refs #2083
Pull Request #2168: Refactoring to allow easier integration of the new LUX widget

2850 of 3124 relevant lines covered (91.23%)

538.43 hits per line

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

100.0
/app/models/request.rb
1
# frozen_string_literal: true
2
# rubocop:disable Metrics/ClassLength
3
class Request < ApplicationRecord
5✔
4
  DRAFT = "draft" # default state set by database
5✔
5
  SUBMITTED = "submitted" # Ready to be approved
5✔
6

7
  def valid_to_submit?
5✔
8
    errors.clear
61✔
9
    # run all validations and then check for errors otherwise ruby stops at the first error
10
    valid_title?
61✔
11
    valid_data_sponsor?
61✔
12
    valid_data_manager?
61✔
13
    valid_departments?
61✔
14
    valid_quota?
61✔
15
    valid_project_purpose?
61✔
16
    valid_description?
61✔
17
    # Is parent folder really required?  For Skeletor let's skip it.
18
    # valid_parent_folder?
19
    valid_project_folder?
61✔
20
    # For Skeletor we are setting the requestor to the data sponsor
21
    # valid_requested_by?
22
    errors.count == 0
61✔
23
  end
24

25
  def valid_title?
5✔
26
    check_errors? do
70✔
27
      field_present?(project_title, :project_title)
70✔
28
      valid_length(project_title, 200, :project_title)
70✔
29
      no_quotes(project_title, :project_title)
70✔
30
    end
31
  end
32

33
  def valid_data_sponsor?
5✔
34
    check_errors? { validate_uid(data_sponsor, :data_sponsor) }
128✔
35
  end
36

37
  def valid_data_manager?
5✔
38
    check_errors? { validate_uid(data_manager, :data_manager) }
128✔
39
  end
40

41
  def valid_departments?
5✔
42
    check_errors? { field_present?(departments, :departments) }
126✔
43
  end
44

45
  def valid_project_purpose?
5✔
46
    check_errors? { project_purpose_present?(project_purpose, :project_purpose) }
122✔
47
  end
48

49
  def valid_description?
5✔
50
    check_errors? do
66✔
51
      field_present?(description, :description)
66✔
52
      valid_length(description, 1000, :description)
66✔
53
      no_quotes(description, :description)
66✔
54
    end
55
  end
56

57
  def valid_parent_folder?
5✔
58
    check_errors? do
2✔
59
      field_present?(parent_folder, :parent_folder)
2✔
60
      no_quotes(project_title, :parent_folder)
2✔
61
    end
62
  end
63

64
  def valid_project_folder?
5✔
65
    check_errors? do
64✔
66
      field_present?(project_folder, :project_folder)
64✔
67
      no_quotes(project_folder, :project_folder)
64✔
68
    end
69
  end
70

71
  def valid_quota?
5✔
72
    if ((quota == "500 GB") || (quota == "2 TB") || (quota == "10 TB") || (quota == "25 TB")) ||
69✔
73
       (custom_quota? && (storage_size.present? && (storage_size > 0)) && ((storage_unit == "GB") || (storage_unit == "TB")))
6✔
74
      true
65✔
75
    else
76
      errors.add(:quota, :invalid, message: "must be one of '500 GB', '2 TB', '10 TB', '25 TB', or 'custom'")
4✔
77
      false
4✔
78
    end
79
  end
80

81
  def custom_quota?
5✔
82
    quota == "custom"
666✔
83
  end
84

85
  def valid_requested_by?
5✔
86
    check_errors? { field_present?(requested_by, :requested_by) }
4✔
87
  end
88

89
  def approve(approver)
5✔
90
    create_project_operation = ProjectCreate.new
284✔
91
    result = create_project_operation.call(request: self, approver: approver)
284✔
92
    if result.success?
284✔
93
      result.value!
281✔
94
    else
95
      self.error_message = { message: result.failure }
3✔
96
      save!
3✔
97
      cleanup_incomplete_project
3✔
98
      raise ProjectCreate::ProjectCreateError, result.failure
3✔
99
    end
100
  end
101

102
  def approved_quota_size
5✔
103
    if approved_quota.present?
309✔
104
      if approved_quota == "custom"
275✔
105
        approved_storage_size.to_f
273✔
106
      else
107
        approved_quota.split.first.to_f
2✔
108
      end
109
    else
110
      requested_quota_size
34✔
111
    end
112
  end
113

114
  def requested_quota_size
5✔
115
    if custom_quota?
330✔
116
      storage_size.to_f
278✔
117
    else
118
      quota.split.first.to_f
52✔
119
    end
120
  end
121

122
  def approved_quota_unit
5✔
123
    if approved_quota.present?
312✔
124
      if approved_quota == "custom"
277✔
125
        approved_storage_unit
275✔
126
      else
127
        approved_quota.split.last
2✔
128
      end
129
    else
130
      requested_quota_unit
35✔
131
    end
132
  end
133

134
  def requested_quota_unit
5✔
135
    if custom_quota?
330✔
136
      storage_unit
278✔
137
    else
138
      quota.split.last
52✔
139
    end
140
  end
141

142
  def submitted?
5✔
143
    state == Request::SUBMITTED
177✔
144
  end
145

146
  def project_path
5✔
147
    return project_folder if parent_folder.blank?
3✔
148

149
    [parent_folder, project_folder].join("/")
1✔
150
  end
151

152
  def requestor
5✔
153
    return "missing" if requested_by.blank?
2✔
154
    User.find_by(uid: requested_by).display_name_safe
2✔
155
  end
156

157
  def data_manager_name
5✔
158
    user_name(data_manager)
27✔
159
  end
160

161
  def data_sponsor_name
5✔
162
    user_name(data_sponsor)
27✔
163
  end
164

165
  private
5✔
166

167
    def user_name(uid)
5✔
168
      return "" if uid.blank?
54✔
169
      user = User.find_by(uid: uid)
14✔
170
      if user.present?
14✔
171
        user.display_name_safe
13✔
172
      else
173
        uid
1✔
174
      end
175
    end
176

177
    def check_errors?
5✔
178
      original_error_count = errors.count
456✔
179
      yield
456✔
180
      original_error_count == errors.count
456✔
181
    end
182

183
    def field_present?(value, name)
5✔
184
      if value.blank?
267✔
185
        errors.add(name, :invalid, message: "cannot be empty")
86✔
186
      end
187
    end
188

189
    def validate_uid(uid, field)
5✔
190
      if uid.blank?
128✔
191
        errors.add(field, :blank, message: "cannot be empty")
37✔
192
      elsif User.where(uid: uid).count == 0
91✔
193
        errors.add(field, :invalid, message: "must be a valid user")
2✔
194
      end
195
    end
196

197
    def project_purpose_present?(project_purpose, field)
5✔
198
      if project_purpose.blank?
61✔
199
        errors.add(field, :blank, message: "select a project purpose")
25✔
200
      end
201
    end
202

203
    def valid_length(value, length, field)
5✔
204
      return if value.blank?
136✔
205
      if value.length > length
96✔
206
        errors.add(field, :invalid, message: "cannot exceed #{length} characters")
8✔
207
      end
208
    end
209

210
    def no_quotes(value, field)
5✔
211
      return if value.blank?
202✔
212
      if value.include?('"')
137✔
213
        errors.add(field, :invalid, message: "cannot include quotes")
5✔
214
      end
215
    end
216

217
    # If a request fails to be a approved we make sure there were not orphan
218
    # project records left in our Rails database that do not have a matching
219
    # project in Mediaflux (i.e. collection asset).
220
    def cleanup_incomplete_project
5✔
221
      project = Project.find_by_id(project_id)
3✔
222
      if project && project.mediaflux_id.nil?
3✔
223
        Rails.logger.warn("Deleting project #{project.id} because the approval for request #{id} failed and it was not created in Mediaflux.")
2✔
224
        project.destroy!
2✔
225
      end
226
    end
227
end
228
# rubocop:enable Metrics/ClassLength
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

© 2025 Coveralls, Inc