11917: Do not clear rails cache at boot time.
[arvados.git] / apps / workbench / app / controllers / users_controller.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class UsersController < ApplicationController
6   skip_around_filter :require_thread_api_token, only: :welcome
7   skip_before_filter :check_user_agreements, only: [:welcome, :inactive]
8   skip_before_filter :check_user_profile, only: [:welcome, :inactive, :profile]
9   skip_before_filter :find_object_by_uuid, only: [:welcome, :activity, :storage]
10   before_filter :ensure_current_user_is_admin, only: [:sudo, :unsetup, :setup]
11
12   def show
13     if params[:uuid] == current_user.uuid
14       respond_to do |f|
15         f.html do
16           if request.url.include?("/users/#{current_user.uuid}")
17             super
18           else
19             redirect_to(params[:return_to] || project_path(params[:uuid]))
20           end
21         end
22       end
23     else
24       super
25     end
26   end
27
28   def welcome
29     if current_user
30       redirect_to (params[:return_to] || '/')
31     end
32   end
33
34   def inactive
35     if current_user.andand.is_invited
36       redirect_to (params[:return_to] || '/')
37     end
38   end
39
40   def profile
41     params[:offer_return_to] ||= params[:return_to]
42   end
43
44   def activity
45     @breadcrumb_page_name = nil
46     @users = User.limit(params[:limit])
47     @user_activity = {}
48     @activity = {
49       logins: {},
50       jobs: {},
51       pipeline_instances: {}
52     }
53     @total_activity = {}
54     @spans = [['This week', Time.now.beginning_of_week, Time.now],
55               ['Last week',
56                Time.now.beginning_of_week.advance(weeks:-1),
57                Time.now.beginning_of_week],
58               ['This month', Time.now.beginning_of_month, Time.now],
59               ['Last month',
60                1.month.ago.beginning_of_month,
61                Time.now.beginning_of_month]]
62     @spans.each do |span, threshold_start, threshold_end|
63       @activity[:logins][span] = Log.select(%w(uuid modified_by_user_uuid)).
64         filter([[:event_type, '=', 'login'],
65                 [:object_kind, '=', 'arvados#user'],
66                 [:created_at, '>=', threshold_start],
67                 [:created_at, '<', threshold_end]])
68       @activity[:jobs][span] = Job.select(%w(uuid modified_by_user_uuid)).
69         filter([[:created_at, '>=', threshold_start],
70                 [:created_at, '<', threshold_end]])
71       @activity[:pipeline_instances][span] = PipelineInstance.select(%w(uuid modified_by_user_uuid)).
72         filter([[:created_at, '>=', threshold_start],
73                 [:created_at, '<', threshold_end]])
74       @activity.each do |type, act|
75         records = act[span]
76         @users.each do |u|
77           @user_activity[u.uuid] ||= {}
78           @user_activity[u.uuid][span + ' ' + type.to_s] ||= 0
79         end
80         records.each do |record|
81           @user_activity[record.modified_by_user_uuid] ||= {}
82           @user_activity[record.modified_by_user_uuid][span + ' ' + type.to_s] ||= 0
83           @user_activity[record.modified_by_user_uuid][span + ' ' + type.to_s] += 1
84           @total_activity[span + ' ' + type.to_s] ||= 0
85           @total_activity[span + ' ' + type.to_s] += 1
86         end
87       end
88     end
89     @users = @users.sort_by do |a|
90       [-@user_activity[a.uuid].values.inject(:+), a.full_name]
91     end
92     # Prepend a "Total" pseudo-user to the sorted list
93     @user_activity[nil] = @total_activity
94     @users = [OpenStruct.new(uuid: nil)] + @users
95   end
96
97   def storage
98     @breadcrumb_page_name = nil
99     @users = User.limit(params[:limit])
100     @user_storage = {}
101     total_storage = {}
102     @log_date = {}
103     @users.each do |u|
104       @user_storage[u.uuid] ||= {}
105       storage_log = Log.
106         filter([[:object_uuid, '=', u.uuid],
107                 [:event_type, '=', 'user-storage-report']]).
108         order(:created_at => :desc).
109         with_count('none').
110         limit(1)
111       storage_log.each do |log_entry|
112         # We expect this block to only execute once since we specified limit(1)
113         @user_storage[u.uuid] = log_entry['properties']
114         @log_date[u.uuid] = log_entry['event_at']
115       end
116       total_storage.merge!(@user_storage[u.uuid]) { |k,v1,v2| v1 + v2 }
117     end
118     @users = @users.sort_by { |u|
119       [-@user_storage[u.uuid].values.push(0).inject(:+), u.full_name]}
120     # Prepend a "Total" pseudo-user to the sorted list
121     @users = [OpenStruct.new(uuid: nil)] + @users
122     @user_storage[nil] = total_storage
123   end
124
125   def show_pane_list
126     if current_user.andand.is_admin
127       super | %w(Admin)
128     else
129       super
130     end
131   end
132
133   def index_pane_list
134     if current_user.andand.is_admin
135       super | %w(Activity)
136     else
137       super
138     end
139   end
140
141   def sudo
142     resp = arvados_api_client.api(ApiClientAuthorization, '', {
143                                     api_client_authorization: {
144                                       owner_uuid: @object.uuid
145                                     }
146                                   })
147     redirect_to root_url(api_token: resp[:api_token])
148   end
149
150   def home
151     @my_ssh_keys = AuthorizedKey.where(authorized_user_uuid: current_user.uuid)
152     @my_tag_links = {}
153
154     @my_jobs = Job.
155       limit(10).
156       order('created_at desc').
157       where(created_by: current_user.uuid)
158
159     @my_collections = Collection.
160       limit(10).
161       order('created_at desc').
162       where(created_by: current_user.uuid)
163     collection_uuids = @my_collections.collect &:uuid
164
165     @persist_state = {}
166     collection_uuids.each do |uuid|
167       @persist_state[uuid] = 'cache'
168     end
169
170     Link.filter([['head_uuid', 'in', collection_uuids],
171                              ['link_class', 'in', ['tag', 'resources']]]).
172       each do |link|
173       case link.link_class
174       when 'tag'
175         (@my_tag_links[link.head_uuid] ||= []) << link
176       when 'resources'
177         if link.name == 'wants'
178           @persist_state[link.head_uuid] = 'persistent'
179         end
180       end
181     end
182
183     @my_pipelines = PipelineInstance.
184       limit(10).
185       order('created_at desc').
186       where(created_by: current_user.uuid)
187
188     respond_to do |f|
189       f.js { render template: 'users/home.js' }
190       f.html { render template: 'users/home' }
191     end
192   end
193
194   def unsetup
195     if current_user.andand.is_admin
196       @object.unsetup
197     end
198     show
199   end
200
201   def setup
202     respond_to do |format|
203       if current_user.andand.is_admin
204         setup_params = {}
205         setup_params[:send_notification_email] = "#{Rails.configuration.send_user_setup_notification_email}"
206         if params['user_uuid'] && params['user_uuid'].size>0
207           setup_params[:uuid] = params['user_uuid']
208         end
209         if params['email'] && params['email'].size>0
210           user = {email: params['email']}
211           setup_params[:user] = user
212         end
213         if params['openid_prefix'] && params['openid_prefix'].size>0
214           setup_params[:openid_prefix] = params['openid_prefix']
215         end
216         if params['vm_uuid'] && params['vm_uuid'].size>0
217           setup_params[:vm_uuid] = params['vm_uuid']
218         end
219
220         setup_resp = User.setup setup_params
221         if setup_resp
222           vm_link = nil
223           setup_resp[:items].each do |item|
224             if item[:head_kind] == "arvados#virtualMachine"
225               vm_link = item
226               break
227             end
228           end
229           if params[:groups]
230             new_groups = params[:groups].split(',').map(&:strip).select{|i| !i.empty?}
231             if vm_link and new_groups != vm_link[:properties][:groups]
232               vm_login_link = Link.where(uuid: vm_link[:uuid])
233               if vm_login_link.items_available > 0
234                 link = vm_login_link.results.first
235                 props = link.properties
236                 props[:groups] = new_groups
237                 link.save!
238               end
239             end
240           end
241
242           format.js
243         else
244           self.render_error status: 422
245         end
246       else
247         self.render_error status: 422
248       end
249     end
250   end
251
252   def setup_popup
253     @vms = VirtualMachine.all.results
254
255     @current_selections = find_current_links @object
256
257     respond_to do |format|
258       format.html
259       format.js
260     end
261   end
262
263   def repositories
264     # all repositories accessible by current user
265     all_repositories = Hash[Repository.all.order('name asc').collect {|repo| [repo.uuid, repo]}]
266
267     @my_repositories = [] # we want them ordered as owned and the rest
268     @repo_writable = {}
269
270     # owned repos
271     all_repositories.each do |_, repo|
272       if repo.owner_uuid == current_user.uuid
273         @repo_writable[repo.uuid] = 'can_write'
274         @my_repositories << repo
275       end
276     end
277
278     # rest of the repos
279     handled = @my_repositories.map(&:uuid)
280     all_repositories.each do |_, repo|
281       @my_repositories << repo if !repo.uuid.in?(handled)
282     end
283   end
284
285   def virtual_machines
286     @my_vm_logins = {}
287     Link.where(tail_uuid: @object.uuid,
288                link_class: 'permission',
289                name: 'can_login').
290           each do |perm_link|
291             if perm_link.properties.andand[:username]
292               @my_vm_logins[perm_link.head_uuid] ||= []
293               @my_vm_logins[perm_link.head_uuid] << perm_link.properties[:username]
294             end
295           end
296     @my_virtual_machines = VirtualMachine.where(uuid: @my_vm_logins.keys)
297   end
298
299   def ssh_keys
300     @my_ssh_keys = AuthorizedKey.where(key_type: 'SSH', owner_uuid: @object.uuid)
301   end
302
303   def add_ssh_key_popup
304     respond_to do |format|
305       format.html
306       format.js
307     end
308   end
309
310   def add_ssh_key
311     respond_to do |format|
312       key_params = {'key_type' => 'SSH'}
313       key_params['authorized_user_uuid'] = current_user.uuid
314
315       if params['name'] && params['name'].size>0
316         key_params['name'] = params['name'].strip
317       end
318       if params['public_key'] && params['public_key'].size>0
319         key_params['public_key'] = params['public_key'].strip
320       end
321
322       if !key_params['name'] && params['public_key'].andand.size>0
323         split_key = key_params['public_key'].split
324         key_params['name'] = split_key[-1] if (split_key.size == 3)
325       end
326
327       new_key = AuthorizedKey.create! key_params
328       if new_key
329         format.js
330       else
331         self.render_error status: 422
332       end
333     end
334   end
335
336   def request_shell_access
337     logger.warn "request_access: #{params.inspect}"
338     params['request_url'] = request.url
339     RequestShellAccessReporter.send_request(current_user, params).deliver
340   end
341
342   protected
343
344   def find_current_links user
345     current_selections = {}
346
347     if !user
348       return current_selections
349     end
350
351     # oid login perm
352     oid_login_perms = Link.where(tail_uuid: user.email,
353                                    head_kind: 'arvados#user',
354                                    link_class: 'permission',
355                                    name: 'can_login')
356
357     if oid_login_perms.any?
358       prefix_properties = oid_login_perms.first.properties
359       current_selections[:identity_url_prefix] = prefix_properties[:identity_url_prefix]
360     end
361
362     # repo perm
363     repo_perms = Link.where(tail_uuid: user.uuid,
364                             head_kind: 'arvados#repository',
365                             link_class: 'permission',
366                             name: 'can_write')
367     if repo_perms.any?
368       repo_uuid = repo_perms.first.head_uuid
369       repos = Repository.where(head_uuid: repo_uuid)
370       if repos.any?
371         repo_name = repos.first.name
372         current_selections[:repo_name] = repo_name
373       end
374     end
375
376     # vm login perm
377     vm_login_perms = Link.where(tail_uuid: user.uuid,
378                               head_kind: 'arvados#virtualMachine',
379                               link_class: 'permission',
380                               name: 'can_login')
381     if vm_login_perms.any?
382       vm_perm = vm_login_perms.first
383       vm_uuid = vm_perm.head_uuid
384       current_selections[:vm_uuid] = vm_uuid
385       current_selections[:groups] = vm_perm.properties[:groups].andand.join(', ')
386     end
387
388     return current_selections
389   end
390
391 end