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

pulibrary / tigerdata-app / 7291b10e-eaa3-4284-9371-5a980ceebf59

24 Nov 2025 07:18PM UTC coverage: 87.613% (-3.7%) from 91.333%
7291b10e-eaa3-4284-9371-5a980ceebf59

push

circleci

web-flow
Adds breadcrumb to Wizard (#2231)

Adds the breadcrumb to the Wizard and the functionality to allow the
user to save their changes before leaving the Wizard when clicking on
the "Dashboard" link in the breadcrumbs.

Closes #2102

5 of 12 new or added lines in 11 files covered. (41.67%)

904 existing lines in 36 files now uncovered.

2801 of 3197 relevant lines covered (87.61%)

360.23 hits per line

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

95.24
/app/presenters/project_show_presenter.rb
1
# frozen_string_literal: true
2
class ProjectShowPresenter
4✔
3
  delegate "id", "in_mediaflux?", "mediaflux_id", "status", to: :project
4✔
4
  delegate "project_id", "storage_performance_expectations", to: :project_metadata
4✔
5

6
  attr_reader :project, :project_metadata
4✔
7

8
  # @return [Class] The presenter class for building XML Documents from Projects
9
  def self.xml_presenter_class
4✔
UNCOV
10
    ProjectXmlPresenter
5✔
11
  end
12

13
  # While we are transitioning to fetching the data straight from Mediaflux `project` can be
14
  # an ActiveRecord Project model (when used from the Project show page) or a Hash with the
15
  # data from Mediaflux (when used from the Dashboard).
16
  # This branching can be refactored (elimitated?) once we implement ticket
17
  # https://github.com/pulibrary/tigerdata-app/issues/2039 and the project data will always
18
  # come from Mediaflux.
19
  def initialize(project, current_user)
4✔
20
    if project.is_a?(Hash)
177✔
21
      @project_mf = project
121✔
22
      @project = rails_project(@project_mf)
121✔
23
    else
24
      @project = project
56✔
25
      @project_mf = project.mediaflux_metadata(session_id: current_user.mediaflux_session)
56✔
26
    end
27
    @project_metadata = @project&.metadata_model
173✔
28
  end
29

30
  def title
4✔
31
    @project_mf[:title]
12✔
32
  end
33

34
  def description
4✔
35
    @project_mf[:description]
4✔
36
  end
37

38
  # @return [String] the XML for the project Document
39
  def to_xml
4✔
UNCOV
40
    xml_document.to_xml
4✔
41
  end
42

43
  # @return [Nokogiri::XML::Document] the XML Document for the Project
44
  def xml_document
4✔
UNCOV
45
    @xml_document ||= xml_presenter.document
5✔
46
  end
47

48
  def created
4✔
UNCOV
49
    @project.created_at.strftime("%b %e, %Y %l:%M %p")
1✔
50
  end
51

52
  def updated
4✔
UNCOV
53
    @project.updated_at.strftime("%b %e, %Y %l:%M %p")
1✔
54
  end
55

56
  def data_sponsor
4✔
UNCOV
57
    User.find_by(uid: @project_mf[:data_sponsor])
27✔
58
  end
59

60
  def data_manager
4✔
UNCOV
61
    User.find_by(uid: @project_mf[:data_manager])
17✔
62
  end
63

64
  def data_read_only_users
4✔
UNCOV
65
    (@project_mf[:ro_users] || []).map { |uid| ReadOnlyUser.find_by(uid:) }.compact
16✔
66
  end
67

68
  def data_read_write_users
4✔
UNCOV
69
    (@project_mf[:rw_users] || []).map { |uid| User.find_by(uid:) }.compact
16✔
70
  end
71

72
  def data_users
4✔
UNCOV
73
    unsorted_data_users = data_read_only_users + data_read_write_users
13✔
UNCOV
74
    sorted_data_users = unsorted_data_users.sort_by { |u| u.family_name || u.uid }
19✔
UNCOV
75
    sorted_data_users.uniq { |u| u.uid }
19✔
76
  end
77

78
  def data_user_names
4✔
UNCOV
79
    user_model_names = data_users.map(&:display_name_safe)
2✔
UNCOV
80
    user_model_names.join(", ")
2✔
81
  end
82

83
  def project_purpose
4✔
84
    ProjectPurpose.label_for(@project_mf[:project_purpose])
4✔
85
  end
86

87
  # used to hide the project root that is not visible to the end user
88
  def project_directory
4✔
89
    # This value comes from Mediaflux without the extra hidden root
90
    directory = @project_mf[:project_directory] || ""
3✔
91
    directory.start_with?("/") ? directory : "/" + directory
3✔
92
  end
93

94
  def hpc
4✔
UNCOV
95
    @project_mf[:hpc] == true ? "Yes" : "No"
1✔
96
  end
97

98
  def globus
4✔
UNCOV
99
    @project_mf[:globus] == true ? "Yes" : "No"
1✔
100
  end
101

102
  def smb
4✔
UNCOV
103
    @project_mf[:smb] == true ? "Yes" : "No"
1✔
104
  end
105

106
  def number_of_files
4✔
UNCOV
107
    @project_mf[:number_of_files]
1✔
108
  end
109

110
  def departments
4✔
UNCOV
111
    @project_mf[:departments] || []
5✔
112
  end
113

114
  def department_codes
4✔
UNCOV
115
    @dep_with_codes = {}
2✔
UNCOV
116
    departments_list = departments.nil? ? [] : departments.first.split(", ")
2✔
UNCOV
117
    departments_list.map do |dept|
2✔
UNCOV
118
      tmp_code = Affiliation.find_fuzzy_by_name(dept)
2✔
UNCOV
119
      @dep_with_codes[dept] = tmp_code.code unless tmp_code.nil?
2✔
120
    end
UNCOV
121
    @dep_with_codes
2✔
122
  end
123

124
  def project_id
4✔
125
    @project_mf[:project_id]
3✔
126
  end
127

128
  def storage_capacity(session_id: nil)
4✔
129
    return project_metadata.storage_capacity if session_id.nil?
3✔
130

UNCOV
131
    persisted = project.storage_capacity_raw(session_id: session_id)
1✔
UNCOV
132
    value = persisted.to_f
1✔
133

UNCOV
134
    value*default_capacity_divisor
1✔
135
  end
136

137
  def formatted_storage_capacity(session_id:)
4✔
UNCOV
138
    value = storage_capacity(session_id: session_id)
1✔
UNCOV
139
    format("%.3f", value)
1✔
140
  end
141

142
  def formatted_quota_percentage(session_id:)
4✔
UNCOV
143
    value = quota_percentage(session_id:)
1✔
UNCOV
144
    format("%.3f", value)
1✔
145
  end
146

147
  def quota_usage(session_id:)
4✔
UNCOV
148
    "#{project.storage_usage(session_id:)} out of #{project.storage_capacity(session_id:)} used"
1✔
149
  end
150

151
  def quota_percentage(session_id:, dashboard: false)
4✔
UNCOV
152
    storage_capacity = project.storage_capacity_raw(session_id:)
2✔
UNCOV
153
    return 0 if storage_capacity.zero?
2✔
UNCOV
154
    storage_usage = project.storage_usage_raw(session_id:)
2✔
UNCOV
155
    return 0 if storage_usage == 0
2✔
156
    storage_value = (storage_usage.to_f / storage_capacity.to_f) * 100
×
157
    minimum_storage_used = true if storage_value > 0 && storage_value < 1
×
158
    storage_value = 1 if minimum_storage_used
×
159
    storage_value += 1 if minimum_storage_used && dashboard
×
160
    storage_value
×
161
  end
162

163
  def user_has_access?(user:)
4✔
UNCOV
164
    return true if user.eligible_sysadmin?
22✔
UNCOV
165
    data_sponsor&.uid == user.uid || data_manager&.uid == user.uid || data_users.map(&:uid).include?(user.uid)
22✔
166
  end
167

168
  def project_in_rails?
4✔
169
    project != nil
121✔
170
  end
171

172
  private
4✔
173

174
    # Capacity is in bytes
175
    def default_capacity_divisor
4✔
UNCOV
176
      1.0/(1000.0**3)
1✔
177
    end
178

179
    def xml_presenter_args
4✔
UNCOV
180
      project
5✔
181
    end
182

183
    def xml_presenter
4✔
UNCOV
184
      @xml_presenter ||= self.class.xml_presenter_class.new(xml_presenter_args)
5✔
185
    end
186

187
    def rails_project(project_mf)
4✔
188
      database_record = Project.where(mediaflux_id:project_mf[:mediaflux_id]).first
121✔
189
      if database_record.nil?
121✔
190
        Rails.logger.warn("Mediaflux project with ID #{project_mf[:mediaflux_id]} is not in the Rails database (title: #{project_mf[:title]})")
111✔
191
        Honeybadger.notify("Mediaflux project with ID #{project_mf[:mediaflux_id]} is not in the Rails database (title: #{project_mf[:title]})")
111✔
192
      end
193
      database_record
121✔
194
    end
195
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

© 2025 Coveralls, Inc