1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 class UsersController < ApplicationController
6 skip_around_action :require_thread_api_token, only: :welcome
7 skip_before_action :check_user_agreements, only: [:welcome, :inactive, :link_account, :merge]
8 skip_before_action :check_user_profile, only: [:welcome, :inactive, :profile, :link_account, :merge]
9 skip_before_action :find_object_by_uuid, only: [:welcome, :activity, :storage]
10 before_action :ensure_current_user_is_admin, only: [:sudo, :unsetup, :setup]
13 if params[:uuid] == current_user.uuid
16 if request.url.include?("/users/#{current_user.uuid}")
19 redirect_to(params[:return_to] || project_path(params[:uuid]))
30 redirect_to (params[:return_to] || '/')
35 if current_user.andand.is_invited
36 redirect_to (params[:return_to] || '/')
41 params[:offer_return_to] ||= params[:return_to]
43 # In a federation situation, when you get a user record using
44 # "current user of token" it can fetch a stale user record from
45 # the local cluster. So even if profile settings were just written
46 # to the user record on the login cluster (because the user just
47 # filled out the profile), those profile settings may not appear
48 # in the "current user" response because it is returning a cached
49 # record from the local cluster.
51 # In this case, explicitly fetching user record forces it to get a
52 # fresh record from the login cluster.
53 Thread.current[:user] = User.find(current_user.uuid)
57 @breadcrumb_page_name = nil
58 @users = User.limit(params[:limit]).with_count("none")
63 pipeline_instances: {}
66 @spans = [['This week', Time.now.beginning_of_week, Time.now],
68 Time.now.beginning_of_week.advance(weeks:-1),
69 Time.now.beginning_of_week],
70 ['This month', Time.now.beginning_of_month, Time.now],
72 1.month.ago.beginning_of_month,
73 Time.now.beginning_of_month]]
74 @spans.each do |span, threshold_start, threshold_end|
75 @activity[:logins][span] = Log.select(%w(uuid modified_by_user_uuid)).
76 filter([[:event_type, '=', 'login'],
77 [:object_kind, '=', 'arvados#user'],
78 [:created_at, '>=', threshold_start],
79 [:created_at, '<', threshold_end]]).with_count("none")
80 @activity[:jobs][span] = Job.select(%w(uuid modified_by_user_uuid)).
81 filter([[:created_at, '>=', threshold_start],
82 [:created_at, '<', threshold_end]]).with_count("none")
83 @activity[:pipeline_instances][span] = PipelineInstance.select(%w(uuid modified_by_user_uuid)).
84 filter([[:created_at, '>=', threshold_start],
85 [:created_at, '<', threshold_end]]).with_count("none")
86 @activity.each do |type, act|
89 @user_activity[u.uuid] ||= {}
90 @user_activity[u.uuid][span + ' ' + type.to_s] ||= 0
92 records.each do |record|
93 @user_activity[record.modified_by_user_uuid] ||= {}
94 @user_activity[record.modified_by_user_uuid][span + ' ' + type.to_s] ||= 0
95 @user_activity[record.modified_by_user_uuid][span + ' ' + type.to_s] += 1
96 @total_activity[span + ' ' + type.to_s] ||= 0
97 @total_activity[span + ' ' + type.to_s] += 1
101 @users = @users.sort_by do |a|
102 [-@user_activity[a.uuid].values.inject(:+), a.full_name]
104 # Prepend a "Total" pseudo-user to the sorted list
105 @user_activity[nil] = @total_activity
106 @users = [OpenStruct.new(uuid: nil)] + @users
110 @breadcrumb_page_name = nil
111 @users = User.limit(params[:limit]).with_count("none")
116 @user_storage[u.uuid] ||= {}
118 filter([[:object_uuid, '=', u.uuid],
119 [:event_type, '=', 'user-storage-report']]).
120 order(:created_at => :desc).
123 storage_log.each do |log_entry|
124 # We expect this block to only execute once since we specified limit(1)
125 @user_storage[u.uuid] = log_entry['properties']
126 @log_date[u.uuid] = log_entry['event_at']
128 total_storage.merge!(@user_storage[u.uuid]) { |k,v1,v2| v1 + v2 }
130 @users = @users.sort_by { |u|
131 [-@user_storage[u.uuid].values.push(0).inject(:+), u.full_name]}
132 # Prepend a "Total" pseudo-user to the sorted list
133 @users = [OpenStruct.new(uuid: nil)] + @users
134 @user_storage[nil] = total_storage
138 if current_user.andand.is_admin
146 if current_user.andand.is_admin
154 resp = arvados_api_client.api(ApiClientAuthorization, '', {
155 api_client_authorization: {
156 owner_uuid: @object.uuid
159 redirect_to root_url(api_token: "v2/#{resp[:uuid]}/#{resp[:api_token]}")
163 @my_ssh_keys = AuthorizedKey.where(authorized_user_uuid: current_user.uuid)
168 order('created_at desc').
170 where(created_by: current_user.uuid)
172 @my_collections = Collection.
174 order('created_at desc').
176 where(created_by: current_user.uuid)
177 collection_uuids = @my_collections.collect &:uuid
180 collection_uuids.each do |uuid|
181 @persist_state[uuid] = 'cache'
184 Link.filter([['head_uuid', 'in', collection_uuids],
185 ['link_class', 'in', ['tag', 'resources']]]).with_count("none")
189 (@my_tag_links[link.head_uuid] ||= []) << link
191 if link.name == 'wants'
192 @persist_state[link.head_uuid] = 'persistent'
197 @my_pipelines = PipelineInstance.
199 order('created_at desc').
201 where(created_by: current_user.uuid)
204 f.js { render template: 'users/home.js' }
205 f.html { render template: 'users/home' }
210 if current_user.andand.is_admin
217 respond_to do |format|
218 if current_user.andand.is_admin
220 setup_params[:send_notification_email] = "#{Rails.configuration.Mail.SendUserSetupNotificationEmail}"
221 if params['user_uuid'] && params['user_uuid'].size>0
222 setup_params[:uuid] = params['user_uuid']
224 if params['email'] && params['email'].size>0
225 user = {email: params['email']}
226 setup_params[:user] = user
228 if params['openid_prefix'] && params['openid_prefix'].size>0
229 setup_params[:openid_prefix] = params['openid_prefix']
231 if params['vm_uuid'] && params['vm_uuid'].size>0
232 setup_params[:vm_uuid] = params['vm_uuid']
235 setup_resp = User.setup setup_params
238 setup_resp[:items].each do |item|
239 if item[:head_kind] == "arvados#virtualMachine"
245 new_groups = params[:groups].split(',').map(&:strip).select{|i| !i.empty?}
246 if vm_link and new_groups != vm_link[:properties][:groups]
247 vm_login_link = Link.where(uuid: vm_link[:uuid])
248 if vm_login_link.items_available > 0
249 link = vm_login_link.results.first
250 props = link.properties
251 props[:groups] = new_groups
259 self.render_error status: 422
262 self.render_error status: 422
268 @vms = VirtualMachine.all.results
270 @current_selections = find_current_links @object
272 respond_to do |format|
280 Link.where(tail_uuid: @object.uuid,
281 link_class: 'permission',
282 name: 'can_login').with_count("none").
284 if perm_link.properties.andand[:username]
285 @my_vm_logins[perm_link.head_uuid] ||= []
286 @my_vm_logins[perm_link.head_uuid] << perm_link.properties[:username]
289 @my_virtual_machines = VirtualMachine.where(uuid: @my_vm_logins.keys).with_count("none")
293 @my_ssh_keys = AuthorizedKey.where(key_type: 'SSH', owner_uuid: @object.uuid)
296 def add_ssh_key_popup
297 respond_to do |format|
304 respond_to do |format|
305 key_params = {'key_type' => 'SSH'}
306 key_params['authorized_user_uuid'] = current_user.uuid
308 if params['name'] && params['name'].size>0
309 key_params['name'] = params['name'].strip
311 if params['public_key'] && params['public_key'].size>0
312 key_params['public_key'] = params['public_key'].strip
315 if !key_params['name'] && params['public_key'].andand.size>0
316 split_key = key_params['public_key'].split
317 key_params['name'] = split_key[-1] if (split_key.size == 3)
320 new_key = AuthorizedKey.create! key_params
324 self.render_error status: 422
329 def request_shell_access
330 logger.warn "request_access: #{params.inspect}"
331 params['request_url'] = request.url
332 RequestShellAccessReporter.send_request(current_user, params).deliver
336 User.merge params[:new_user_token], params[:direction]
342 def find_current_links user
343 current_selections = {}
346 return current_selections
350 oid_login_perms = Link.where(tail_uuid: user.email,
351 head_kind: 'arvados#user',
352 link_class: 'permission',
353 name: 'can_login').with_count("none")
355 if oid_login_perms.any?
356 prefix_properties = oid_login_perms.first.properties
357 current_selections[:identity_url_prefix] = prefix_properties[:identity_url_prefix]
361 repo_perms = Link.where(tail_uuid: user.uuid,
362 head_kind: 'arvados#repository',
363 link_class: 'permission',
364 name: 'can_write').with_count("none")
366 repo_uuid = repo_perms.first.head_uuid
367 repos = Repository.where(head_uuid: repo_uuid).with_count("none")
369 repo_name = repos.first.name
370 current_selections[:repo_name] = repo_name
375 vm_login_perms = Link.where(tail_uuid: user.uuid,
376 head_kind: 'arvados#virtualMachine',
377 link_class: 'permission',
378 name: 'can_login').with_count("none")
379 if vm_login_perms.any?
380 vm_perm = vm_login_perms.first
381 vm_uuid = vm_perm.head_uuid
382 current_selections[:vm_uuid] = vm_uuid
383 current_selections[:groups] = vm_perm.properties[:groups].andand.join(', ')
386 return current_selections