From 1812950e91daaf7a1b02e3777c4e1d483b42d018 Mon Sep 17 00:00:00 2001
From: Brett Smith <brett@curoverse.com>
Date: Tue, 29 Apr 2014 17:41:48 -0400
Subject: [PATCH] api: Accept JSON-formatted reader token array.

---
 .../app/controllers/application_controller.rb | 30 ++++++++-----
 .../test/integration/reader_tokens_test.rb    | 42 ++++++++++++-------
 2 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/services/api/app/controllers/application_controller.rb b/services/api/app/controllers/application_controller.rb
index 3a757618e2..f83cd3428f 100644
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@ -540,28 +540,38 @@ class ApplicationController < ActionController::Base
     end
   end
 
-  def self.accept_attribute_as_json(attr, force_class=nil)
-    before_filter lambda { accept_attribute_as_json attr, force_class }
+  def load_json_value(hash, key, must_be_class=nil)
+    if hash[key].is_a? String
+      hash[key] = Oj.load(hash[key], symbol_keys: false)
+      if must_be_class and !hash[key].is_a? must_be_class
+        raise TypeError.new("parameter #{key.to_s} must be a #{must_be_class.to_s}")
+      end
+    end
+  end
+
+  def self.accept_attribute_as_json(attr, must_be_class=nil)
+    before_filter lambda { accept_attribute_as_json attr, must_be_class }
   end
   accept_attribute_as_json :properties, Hash
   accept_attribute_as_json :info, Hash
-  def accept_attribute_as_json(attr, force_class)
+  def accept_attribute_as_json(attr, must_be_class)
     if params[resource_name] and resource_attrs.is_a? Hash
-      if resource_attrs[attr].is_a? String
-        resource_attrs[attr] = Oj.load(resource_attrs[attr],
-                                       symbol_keys: false)
-        if force_class and !resource_attrs[attr].is_a? force_class
-          raise TypeError.new("#{resource_name}[#{attr.to_s}] must be a #{force_class.to_s}")
-        end
-      elsif resource_attrs[attr].is_a? Hash
+      if resource_attrs[attr].is_a? Hash
         # Convert symbol keys to strings (in hashes provided by
         # resource_attrs)
         resource_attrs[attr] = resource_attrs[attr].
           with_indifferent_access.to_hash
+      else
+        load_json_value(resource_attrs, attr, must_be_class)
       end
     end
   end
 
+  def self.accept_param_as_json(key, must_be_class=nil)
+    prepend_before_filter lambda { load_json_value(params, key, must_be_class) }
+  end
+  accept_param_as_json :reader_tokens, Array
+
   def render_list
     @object_list = {
       :kind  => "arvados##{(@response_resource_name || resource_name).camelize(:lower)}List",
diff --git a/services/api/test/integration/reader_tokens_test.rb b/services/api/test/integration/reader_tokens_test.rb
index c0b8cfeec6..6ed8461c62 100644
--- a/services/api/test/integration/reader_tokens_test.rb
+++ b/services/api/test/integration/reader_tokens_test.rb
@@ -7,20 +7,34 @@ class Arvados::V1::ReaderTokensTest < ActionController::IntegrationTest
     specimens(:owned_by_spectator).uuid
   end
 
-  def get_specimens(main_auth, read_auth)
+  def get_specimens(main_auth, read_auth, formatter=:to_a)
     params = {}
-    params[:reader_tokens] = [api_token(read_auth)] if read_auth
+    params[:reader_tokens] = [api_token(read_auth)].send(formatter) if read_auth
     headers = {}
     headers.merge!(auth(main_auth)) if main_auth
     get('/arvados/v1/specimens', params, headers)
   end
 
-  def get_specimen_uuids(main_auth, read_auth)
-    get_specimens(main_auth, read_auth)
+  def get_specimen_uuids(main_auth, read_auth, formatter=:to_a)
+    get_specimens(main_auth, read_auth, formatter)
     assert_response :success
     json_response['items'].map { |spec| spec['uuid'] }
   end
 
+  def assert_post_denied(main_auth, read_auth, formatter=:to_a)
+    if main_auth
+      headers = auth(main_auth)
+      expected = 403
+    else
+      headers = {}
+      expected = 401
+    end
+    post('/arvados/v1/specimens.json',
+         {specimen: {}, reader_tokens: [api_token(read_auth)].send(formatter)},
+         headers)
+    assert_response expected
+  end
+
   test "active user can't see spectator specimen" do
     # Other tests in this suite assume that the active user doesn't
     # have read permission to the owned_by_spectator specimen.
@@ -37,17 +51,17 @@ class Arvados::V1::ReaderTokensTest < ActionController::IntegrationTest
                         spectator_specimen, "did not find spectator specimen")
       end
 
+      test "#{main_auth} auth with JSON read token #{read_auth} can read" do
+        assert_includes(get_specimen_uuids(main_auth, read_auth, :to_json),
+                        spectator_specimen, "did not find spectator specimen")
+      end
+
       test "#{main_auth} auth with reader token #{read_auth} can't write" do
-        if main_auth
-          headers = auth(main_auth)
-          expected = 403
-        else
-          headers = {}
-          expected = 401
-        end
-        post('/arvados/v1/specimens.json',
-             {specimen: {}, reader_tokens: [api_token(read_auth)]}, headers)
-        assert_response expected
+        assert_post_denied(main_auth, read_auth)
+      end
+
+      test "#{main_auth} auth with JSON read token #{read_auth} can't write" do
+        assert_post_denied(main_auth, read_auth, :to_json)
       end
     end
   end
-- 
2.30.2