14873: Removes activerecord-deprecated_finders gem dependency.
[arvados.git] / services / api / app / controllers / application_controller.rb
index a627bf4a46da64896482e5026f1e62c0aa567806..7a9b7a67e5d7a8411763141fe7dd1a1a302e9116 100644 (file)
@@ -3,6 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0
 
 require 'safe_json'
+require 'request_error'
 
 module ApiTemplateOverride
   def allowed_to_render?(fieldset, field, model, options)
@@ -77,14 +78,21 @@ class ApplicationController < ActionController::Base
     @distinct = nil
     @response_resource_name = nil
     @attrs = nil
+    @extra_included = nil
   end
 
   def default_url_options
+    options = {}
     if Rails.configuration.host
-      {:host => Rails.configuration.host}
-    else
-      {}
+      options[:host] = Rails.configuration.host
+    end
+    if Rails.configuration.port
+      options[:port] = Rails.configuration.port
+    end
+    if Rails.configuration.protocol
+      options[:protocol] = Rails.configuration.protocol
     end
+    options
   end
 
   def index
@@ -137,7 +145,7 @@ class ApplicationController < ActionController::Base
 
   def render_error(e)
     logger.error e.inspect
-    if e.respond_to? :backtrace and e.backtrace
+    if !e.is_a? RequestError and (e.respond_to? :backtrace and e.backtrace)
       logger.error e.backtrace.collect { |x| x + "\n" }.join('')
     end
     if (@object.respond_to? :errors and
@@ -156,6 +164,10 @@ class ApplicationController < ActionController::Base
     send_error("Path not found", status: 404)
   end
 
+  def render_accepted
+    send_json ({accepted: true}), status: 202
+  end
+
   protected
 
   def send_error(*args)
@@ -181,7 +193,10 @@ class ApplicationController < ActionController::Base
   end
 
   def find_objects_for_index
-    @objects ||= model_class.readable_by(*@read_users, {:include_trash => (params[:include_trash] || 'untrash' == action_name)})
+    @objects ||= model_class.readable_by(*@read_users, {
+      :include_trash => (params[:include_trash] || 'untrash' == action_name),
+      :include_old_versions => params[:include_old_versions]
+    })
     apply_where_limit_order_params
   end
 
@@ -336,29 +351,22 @@ class ApplicationController < ActionController::Base
     # If there are too many reader tokens, assume the request is malicious
     # and ignore it.
     if request.get? and params[:reader_tokens] and
-        params[:reader_tokens].size < 100
+      params[:reader_tokens].size < 100
+      secrets = params[:reader_tokens].map { |t|
+        if t.is_a? String and t.starts_with? "v2/"
+          t.split("/")[2]
+        else
+          t
+        end
+      }
       @read_auths += ApiClientAuthorization
         .includes(:user)
         .where('api_token IN (?) AND
                 (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)',
-               params[:reader_tokens])
-        .all
+               secrets)
+        .to_a
     end
     @read_auths.select! { |auth| auth.scopes_allow_request? request }
-
-    # Use a salted token as a reader token for /groups/ and /users/current
-    if params[:remote] && (
-         request.path.start_with?('/arvados/v1/groups') ||
-         request.path.start_with?('/arvados/v1/users/current'))
-      auth = ApiClientAuthorization.
-             validate(token: Thread.current[:supplied_token],
-                      remote: params[:remote])
-      if auth && auth.user
-        Thread.current[:user] = auth.user
-        @read_auths << auth
-      end
-    end
-
     @read_users = @read_auths.map(&:user).uniq
   end
 
@@ -379,7 +387,7 @@ class ApplicationController < ActionController::Base
   end
 
   def require_auth_scope
-    if @read_auths.empty?
+    unless current_user && @read_auths.any? { |auth| auth.user.andand.uuid == current_user.uuid }
       if require_login != false
         send_error("Forbidden", status: 403)
       end
@@ -395,7 +403,9 @@ class ApplicationController < ActionController::Base
       req_id = "req-" + Random::DEFAULT.rand(2**128).to_s(36)[0..19]
     end
     response.headers['X-Request-Id'] = Thread.current[:request_id] = req_id
-    yield
+    Rails.logger.tagged(req_id) do
+      yield
+    end
     Thread.current[:request_id] = nil
   end
 
@@ -416,7 +426,7 @@ class ApplicationController < ActionController::Base
   def set_cors_headers
     response.headers['Access-Control-Allow-Origin'] = '*'
     response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, PUT, POST, DELETE'
-    response.headers['Access-Control-Allow-Headers'] = 'Authorization'
+    response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
     response.headers['Access-Control-Max-Age'] = '86486400'
   end
 
@@ -505,12 +515,15 @@ class ApplicationController < ActionController::Base
       :limit => @limit,
       :items => @objects.as_api_response(nil, {select: @select})
     }
+    if @extra_included
+      list[:included] = @extra_included.as_api_response(nil, {select: @select})
+    end
     case params[:count]
     when nil, '', 'exact'
       if @objects.respond_to? :except
         list[:items_available] = @objects.
           except(:limit).except(:offset).
-          count(:id, distinct: true)
+          distinct.count(:id)
       end
     when 'none'
     else
@@ -564,10 +577,20 @@ class ApplicationController < ActionController::Base
         location: "query",
         required: false,
         default: false
-      }
+      },
+      cluster_id: {
+        type: 'string',
+        description: "Create object on a remote federated cluster instead of the current one.",
+        location: "query",
+        required: false,
+      },
     }
   end
 
+  def self._update_requires_parameters
+    {}
+  end
+
   def self._index_requires_parameters
     {
       filters: { type: 'array', required: false },
@@ -578,6 +601,12 @@ class ApplicationController < ActionController::Base
       limit: { type: 'integer', required: false, default: DEFAULT_LIMIT },
       offset: { type: 'integer', required: false, default: 0 },
       count: { type: 'string', required: false, default: 'exact' },
+      cluster_id: {
+        type: 'string',
+        description: "List objects on a remote federated cluster instead of the current one.",
+        location: "query",
+        required: false,
+      },
     }
   end