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

pulibrary / tigerdata-app / 2e85105d-f9c8-41e9-8b05-fe438b698516

26 Nov 2025 12:16PM UTC coverage: 71.597% (-8.0%) from 79.623%
2e85105d-f9c8-41e9-8b05-fe438b698516

push

circleci

web-flow
Display the data sponsor and data manager in the dashboard listing (#2247)

Closes #2236 

<img width="1036" height="675" alt="Screenshot 2025-11-25 at 3 07 41 PM"
src="https://github.com/user-attachments/assets/3b6a2189-7f71-4b17-97e5-e66c8fed3cb3"
/>

1 of 3 new or added lines in 1 file covered. (33.33%)

346 existing lines in 26 files now uncovered.

2367 of 3306 relevant lines covered (71.6%)

147.24 hits per line

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

56.48
/app/models/user.rb
1
# frozen_string_literal: true
2

3
require "csv"
2✔
4
class User < ApplicationRecord
2✔
5
  # Include default devise modules. Others available are:
6
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
7
  devise :rememberable, :omniauthable
2✔
8

9
  has_many :user_requests, dependent: :destroy
2✔
10

11
  paginates_per 100
2✔
12

13
  USER_REGISTRATION_LIST = Rails.root.join("data", "user_registration_list_#{Rails.env}.csv")
2✔
14

15
  attr_accessor :mediaflux_session
2✔
16

17
  def self.from_cas(access_token)
2✔
18
    user = User.find_by(provider: access_token.provider, uid: access_token.uid)
×
19
    if user.present? && user.given_name.nil? # fix any users that do not have the name information loaded
×
20
      user.initialize_name_values(access_token.extra)
×
21
      user.save
×
22
    end
23
    user
×
24
  end
25

26
  # Users that can be project sponsors
27
  def self.sponsor_users
2✔
28
    if Rails.env.development? || Rails.env.staging?
×
29
      User.where(eligible_sponsor: true).or(User.where(developer: true))
×
30
    else
31
      User.where(eligible_sponsor: true)
×
32
    end
33
  end
34

35
  # Users that can be data managers
36
  def self.manager_users
2✔
37
    if Rails.env.development? || Rails.env.staging?
×
38
      User.where(eligible_manager: true).or(User.where(developer: true))
×
39
    else
40
      User.where(eligible_manager: true)
×
41
    end
42
  end
43

44
  def clear_mediaflux_session(session)
2✔
45
    Rails.logger.debug("!!!!!!! Clearing Mediaflux session !!!!!!!!")
3✔
46
    @mediaflux_session = nil
3✔
47
    session[:mediaflux_session] = nil
3✔
48
  end
49

50
  def mediaflux_from_session(session)
2✔
51
    logger.debug "Session Get #{session[:mediaflux_session]} cas: #{session[:active_web_user]}  user: #{uid}"
121✔
52
    if session[:mediaflux_session].blank?
121✔
53
      logger.debug("!!!! Creating a new session !!! #{uid}")
109✔
54
      session[:mediaflux_session] = SystemUser.mediaflux_session
109✔
55
      session[:active_web_user] = false
108✔
56
    end
57
    @active_web_user = session[:active_web_user]
120✔
58
    @mediaflux_session = session[:mediaflux_session]
120✔
59
  end
60

61
  def mediaflux_login(token, session)
2✔
62
    logger.debug("mediaflux session created for #{uid}")
×
63
    logon_request = Mediaflux::LogonRequest.new(identity_token: token, token_type: "cas")
×
64
    if logon_request.error?
×
65
      raise "Invalid Logon #{logon_request.response_error}"
×
66
    end
67
    @mediaflux_session = logon_request.session_token
×
68
    @active_web_user = true
×
69
    session[:mediaflux_session] = @mediaflux_session
×
70
    session[:active_web_user] = @active_web_user
×
71
    logger.debug "Login Session #{session[:mediaflux_session]} cas: #{session[:active_web_user]}  user: #{uid}"
×
72

73
    User.update_user_roles(user: self)
×
74
  end
75

76
  def terminate_mediaflux_session
2✔
77
    return if @mediaflux_session.nil? # nothing to terminate
×
78
    logger.debug "!!!! Terminating mediaflux session"
×
79

80
    Mediaflux::LogoutRequest.new(session_token: @mediaflux_session).response_body
×
81
    @mediaflux_session = nil
×
82
  end
83

84
  # Initialize the name values from the CAS information.
85
  # Our name fields do not match their name fields, so we need to translate.
86
  def initialize_name_values(extra_cas_info)
2✔
87
    self.given_name = extra_cas_info.givenname
×
88
    self.family_name =  extra_cas_info.sn
×
89
    self.display_name = extra_cas_info.pudisplayname
×
90
  end
91

92
  # Return the display name if it exists, otherwise return the uid
93
  # @return [String]
94
  def display_name_safe
2✔
95
    return uid if given_name.blank? && family_name.blank?
90✔
96

97
    [given_name, family_name, "(#{uid})"].compact.join(" ")
90✔
98
  end
99

100
  # Return the display name if it exists, otherwise return the uid
101
  # @return [String]
102
  def display_name_only_safe
2✔
NEW
103
    return uid if given_name.blank? && family_name.blank?
×
NEW
104
    [given_name, family_name].compact.join(" ")
×
105
  end
106

107
  # Is this user eligible to be a data sponsor in this environment?
108
  # @return [Boolean]
109
  def eligible_sponsor?
2✔
110
    return true if developer
5✔
111
    super
5✔
112
  end
113

114
  # Is this user eligible to be a data manger in this environment?
115
  # @return [Boolean]
116
  def eligible_manager?
2✔
117
    return true if developer
2✔
118
    super
2✔
119
  end
120

121
  def developer?
2✔
122
    return true if developer
1✔
123
    super
1✔
124
  end
125

126
  # Is this user eligible to be a data user in this environment?
127
  # @return [Boolean]
128
  def eligible_data_user?
2✔
129
    return true if developer
3✔
130
    return true if !eligible_sponsor? && !eligible_manager
3✔
131
  end
132

133
  # Is this user eligible to be a sysadmin in this environment?
134
  # @return [Boolean]
135
  def eligible_sysadmin?
2✔
136
    (!Rails.env.production? && (developer || sysadmin)) || (Rails.env.production? && sysadmin)
49✔
137
  end
138

139
  def eligible_to_create_new?
2✔
140
    return true if eligible_sysadmin?
×
141

142
    !Rails.env.production? && (eligible_sponsor? && trainer?)
×
143
  end
144

145
  # Methods serialize_into_session() and serialize_from_session() are called by Warden/Devise
146
  # to calculate what information will be stored in the session and to serialize an object
147
  # back from the session.
148
  #
149
  # By default Warden/Devise store the database ID of the record (e.g. User.id) but this causes
150
  # problems if we repopulate our User table and the IDs change. The implementation provided below
151
  # uses the User.uid field (which is unique, does not change, and it's required) as the value to
152
  # store in the session to prevent this issue.
153
  #
154
  # References:
155
  #   https://stackoverflow.com/questions/23597718/what-is-the-warden-data-in-a-rails-devise-session-composed-of/23683925#23683925
156
  #   https://web.archive.org/web/20211028103224/https://tadas-s.github.io/ruby-on-rails/2020/08/02/devise-serialize-into-session-trick/
157
  #   https://github.com/wardencommunity/warden/wiki/Setup
158
  def self.serialize_into_session(record)
2✔
159
    # The return value _must_ have at least two elements since the serialize_from_session() requires
160
    # two arguments (see below)
161
    [record.uid, ""]
117✔
162
  end
163

164
  def self.serialize_from_session(key, _salt, _opts = {})
2✔
165
    User.where(uid: key)&.first
79✔
166
  end
167

168
  # Fetches the most recent download jobs for the user
169
  def latest_downloads(limit: 10)
2✔
170
    @latest_downloads ||= begin
6✔
171
                            downloads = UserRequest.where(user_id: id).where(["completion_time > ?", 7.days.ago]).order(created_at: "DESC").limit(limit)
6✔
172
                            downloads.map{|download| UserRequestPresenter.new(download)}
6✔
173
                          end
174
  end
175

176
  # Updates the user's roles (sys admin, developer) depending on the information on Mediaflux.
177
  # This method is meant to be used only for the current logged in user since the roles depend on the Mediaflux session.
178
  def self.update_user_roles(user:)
2✔
179
    raise "User.update_user_roles called with for a user without a Mediaflux session" if user.mediaflux_session.nil?
×
180

181
    mediaflux_roles = mediaflux_roles(user:)
×
182
    update_developer_status(user:, mediaflux_roles:)
×
183
    update_sysadmin_status(user:, mediaflux_roles:)
×
184
  rescue => ex
185
    Rails.logger.error("Error updating roles for user (id: #{user.id}) status, error: #{ex.message}")
×
186
  end
187

188
  # Returns the roles in Mediaflux for the user in the session.
189
  # This method is meant to be used only for the current logged in user since the roles depend on the Mediaflux session.
190
  def self.mediaflux_roles(user:)
2✔
191
    raise "User.mediaflux_roles called with for a user without a Mediaflux session" if user.mediaflux_session.nil?
1✔
192

193
    request = Mediaflux::ActorSelfDescribeRequest.new(session_token: user.mediaflux_session)
1✔
194
    request.resolve
1✔
195
    request.roles
1✔
196
  end
197

198
  private
2✔
199

200
  def self.update_developer_status(user:, mediaflux_roles:)
2✔
201
    # TODO: Figure out why the role name is different in staging from production:
202
    #   production:   "pu-smb-group:PU:tigerdata:librarydevelopers"
203
    #   staging:      "pu-oit-group:PU:tigerdata:librarydevelopers"
204
    #   development:  "pu-lib:developer"
205
    #   test:         "system-administrator"
206
    developer_now = mediaflux_roles.include?("pu-smb-group:PU:tigerdata:librarydevelopers") ||
×
207
      mediaflux_roles.include?("pu-oit-group:PU:tigerdata:librarydevelopers") ||
208
      mediaflux_roles.include?("pu-lib:developer") ||
209
      mediaflux_roles.include?("system-administrator")
210
    if user.developer != developer_now
×
211
      # Only update the record in the database if there is a change
212
      Rails.logger.info("Updating developer role for user #{user.id} to #{developer_now}")
×
213
      user.developer = developer_now
×
214
      user.save!
×
215
    end
216
  end
217

218
  def self.update_sysadmin_status(user:, mediaflux_roles:)
2✔
219
    sysadmin_now = mediaflux_roles.include?("system-administrator")
×
220
    if user.sysadmin != sysadmin_now
×
221
      # Only update the record in the database if there is a change
222
      Rails.logger.info("Updating sysadmin role for user #{user.id} to #{sysadmin_now}")
×
223
      user.sysadmin = sysadmin_now
×
224
      user.save!
×
225
    end
226
  end
227
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