Merge branch 'master' into origin-2608-websocket-event-bus-alt2
[arvados.git] / services / api / app / controllers / arvados / v1 / users_controller.rb
1 class Arvados::V1::UsersController < ApplicationController
2   skip_before_filter :find_object_by_uuid, only:
3     [:activate, :event_stream, :current, :system, :setup]
4   skip_before_filter :render_404_if_no_object, only:
5     [:activate, :event_stream, :current, :system, :setup]
6   before_filter :admin_required, only: [:setup, :unsetup]
7
8   def current
9     @object = current_user
10     show
11   end
12   def system
13     @object = system_user
14     show
15   end
16
17   class ChannelStreamer
18     Q_UPDATE_INTERVAL = 12
19     def initialize(opts={})
20       @opts = opts
21     end
22     def each
23       return unless @opts[:channel]
24       @redis = Redis.new(:timeout => 0)
25       @redis.subscribe(@opts[:channel]) do |event|
26         event.message do |channel, msg|
27           yield msg + "\n"
28         end
29       end
30     end
31   end
32
33   def event_stream
34     channel = current_user.andand.uuid
35     if current_user.andand.is_admin
36       channel = params[:uuid] || channel
37     end
38     if client_accepts_plain_text_stream
39       self.response.headers['Last-Modified'] = Time.now.ctime.to_s
40       self.response_body = ChannelStreamer.new(channel: channel)
41     else
42       render json: {
43         href: url_for(uuid: channel),
44         comment: ('To retrieve the event stream as plain text, ' +
45                   'use a request header like "Accept: text/plain"')
46       }
47     end
48   end
49
50   def activate
51     if current_user.andand.is_admin && params[:uuid]
52       @object = User.find params[:uuid]
53     else
54       @object = current_user
55     end
56     if not @object.is_active
57       if not (current_user.is_admin or @object.is_invited)
58         logger.warn "User #{@object.uuid} called users.activate " +
59           "but is not invited"
60         raise ArgumentError.new "Cannot activate without being invited."
61       end
62       act_as_system_user do
63         required_uuids = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
64                                     system_user_uuid,
65                                     'signature',
66                                     'require',
67                                     system_user_uuid,
68                                     Collection.uuid_like_pattern).
69           collect(&:head_uuid)
70         signed_uuids = Link.where(owner_uuid: system_user_uuid,
71                                   link_class: 'signature',
72                                   name: 'click',
73                                   tail_uuid: @object.uuid,
74                                   head_uuid: required_uuids).
75           collect(&:head_uuid)
76         todo_uuids = required_uuids - signed_uuids
77         if todo_uuids.empty?
78           @object.update_attributes is_active: true
79           logger.info "User #{@object.uuid} activated"
80         else
81           logger.warn "User #{@object.uuid} called users.activate " +
82             "before signing agreements #{todo_uuids.inspect}"
83           raise ArvadosModel::PermissionDeniedError.new \
84           "Cannot activate without user agreements #{todo_uuids.inspect}."
85         end
86       end
87     end
88     show
89   end
90
91   # create user object and all the needed links
92   def setup
93     @object = nil
94     if params[:uuid]
95       @object = User.find_by_uuid params[:uuid]
96       if !@object
97         return render_404_if_no_object
98       end
99       object_found = true
100     else
101       if !params[:user]
102         raise ArgumentError.new "Required uuid or user"
103       else
104         if params[:user]['uuid']
105           @object = User.find_by_uuid params[:user]['uuid']
106           if @object
107             object_found = true
108           end
109         end
110
111         if !@object
112           if !params[:user]['email']
113             raise ArgumentError.new "Require user email"
114           end
115
116           if !params[:openid_prefix]
117             raise ArgumentError.new "Required openid_prefix parameter is missing."
118           end
119
120           @object = model_class.create! resource_attrs
121         end
122       end
123     end
124
125     if object_found
126       @response = @object.setup_repo_vm_links params[:repo_name],
127                     params[:vm_uuid], params[:openid_prefix]
128     else
129       @response = User.setup @object, params[:openid_prefix],
130                     params[:repo_name], params[:vm_uuid]
131     end
132
133     # setup succeeded. send email to user
134     if params[:send_notification_email] == true || params[:send_notification_email] == 'true'
135       UserNotifier.account_is_setup(@object).deliver
136     end
137
138     render json: { kind: "arvados#HashList", items: @response.as_api_response(nil) }
139   end
140
141   # delete user agreements, vm, repository, login links; set state to inactive
142   def unsetup
143     reload_object_before_update
144     @object.unsetup
145     show
146   end
147
148   protected
149
150   def self._setup_requires_parameters
151     {
152       send_notification_email: { type: 'boolean', required: true },
153     }
154   end
155
156 end