Project

General

Profile

Feature #3818 ยป 3818-try1.patch

Brett Smith, 03/29/2015 05:25 PM

View differences:

apps/workbench/app/models/arvados_base.rb
62 62
    schema = arvados_api_client.discovery[:schemas][self.to_s.to_sym]
63 63
    return @columns if schema.nil?
64 64
    schema[:properties].each do |k, coldef|
65
      case k
66
      when :etag, :kind
65
      if coldef[:readonly] or (k == :etag) or (k == :kind)
67 66
        attr_reader k
68 67
      else
69 68
        if coldef[:type] == coldef[:type].downcase
......
329 328
     (current_user.is_admin or
330 329
      current_user.uuid == self.owner_uuid or
331 330
      new_record? or
332
      (respond_to?(:writable_by) ?
331
      ((respond_to?(:writable_by) and !writable_by.nil?) ?
333 332
       writable_by.include?(current_user.uuid) :
334 333
       (ArvadosBase.find(owner_uuid).writable_by.include? current_user.uuid rescue false)))) or false
335 334
  end
services/api/app/controllers/arvados/v1/schema_controller.rb
95 95
          next
96 96
        end
97 97
        object_properties = {}
98
        k.columns.
99
          select { |col| col.name != 'id' }.
100
          collect do |col|
101
          if k.serialized_attributes.has_key? col.name
102
            object_properties[col.name] = {
103
              type: k.serialized_attributes[col.name].object_class.to_s
104
            }
98
        attr_types = k.attributes_types
99
        k.all_api_accessible_attributes.each_key.map(&:to_s).each do |attr_name|
100
          attr_schema = {}
101
          if attr_types.include?(attr_name)
102
            attr_schema[:type] = attr_types[attr_name]
103
          elsif k.serialized_attributes.include?(attr_name)
104
            attr_schema[:type] = k.serialized_attributes[attr_name].object_class.to_s
105 105
          else
106
            object_properties[col.name] = {
107
              type: col.type
108
            }
106
            attr_schema[:type] = k.columns_hash[attr_name].type
107
          end
108
          unless k.columns_hash.include?(attr_name)
109
            attr_schema[:readonly] = true
109 110
          end
111
          object_properties[attr_name] = attr_schema
110 112
        end
111 113
        discovery[:schemas][k.to_s + 'List'] = {
112 114
          id: k.to_s + 'List',
services/api/app/models/api_client_authorization.rb
22 22

  
23 23
  UNLOGGED_CHANGES = ['last_used_at', 'last_used_by_ip_address', 'updated_at']
24 24

  
25
  def self.attributes_types
26
    super.merge({ "uuid" => columns_hash["api_token"].type,
27
                  "owner_uuid" => "string",
28
                  "modified_by_client_uuid" => "string",
29
                  "modified_by_user_uuid" => "string",
30
                  "modified_at" => "timestamp",
31
                })
32
  end
33

  
25 34
  def assign_random_api_token
26 35
    self.api_token ||= rand(2**256).to_s(36)
27 36
  end
services/api/app/models/arvados_model.rb
81 81
    self.columns.select { |col| col.name == attr.to_s }.first
82 82
  end
83 83

  
84
  def self.all_api_accessible_attributes
85
    # Return a hash that maps attributes accessible through the API to the
86
    # methods that generate them (all symbols).
87
    # The result includes attributes accessible through any API template.
88
    # If the same attribute is generated by different methods in different
89
    # templates, the value for that attribute key is undefined.
90
    result = {}
91
    methods.grep(/^api_accessible_\w+$/).each do |method_name|
92
      next if method_name == :api_accessible_attributes
93
      result.merge!(send(method_name))
94
    end
95
    result
96
  end
97

  
98
  def self.attributes_types
99
    # Return a hash that maps attribute name strings to type strings.
100
    # Subclasses should override this to provide type information for the
101
    # discovery document for any attributes that aren't database-backed.
102
    { "etag" => "string",
103
      "href" => "string",
104
      "kind" => "string",
105
    }
106
  end
107

  
84 108
  def self.attributes_required_columns
85 109
    # This method returns a hash.  Each key is the name of an API attribute,
86 110
    # and it's mapped to a list of database columns that must be fetched
......
91 115
    # specific columns from the database.
92 116
    all_columns = columns.map(&:name)
93 117
    api_column_map = Hash.new { |hash, key| hash[key] = [] }
94
    methods.grep(/^api_accessible_\w+$/).each do |method_name|
95
      next if method_name == :api_accessible_attributes
96
      send(method_name).each_pair do |api_attr_name, col_name|
97
        col_name = col_name.to_s
98
        if all_columns.include?(col_name)
99
          api_column_map[api_attr_name.to_s] |= [col_name]
100
        end
118
    all_api_accessible_attributes.each_pair do |api_attr_name, source_name|
119
      source_name = source_name.to_s
120
      if all_columns.include?(source_name)
121
        api_column_map[api_attr_name.to_s] |= [source_name]
101 122
      end
102 123
    end
103 124
    api_column_map
services/api/app/models/group.rb
16 16
    t.add :writable_by
17 17
  end
18 18

  
19
  def self.attributes_types
20
    super.merge({"writable_by" => "Array"})
21
  end
22

  
19 23
  def maybe_invalidate_permissions_cache
20 24
    if uuid_changed? or owner_uuid_changed?
21 25
      # This can change users' permissions on other groups as well as
services/api/app/models/job.rb
62 62
            (Complete = 'Complete'),
63 63
           ]
64 64

  
65
  def self.attributes_types
66
    super.merge({ "queue_position" => "integer",
67
                  "node_uuids" => "Array",
68
                })
69
  end
70

  
65 71
  def assert_finished
66 72
    update_attributes(finished_at: finished_at || db_current_time,
67 73
                      success: success.nil? ? false : success,
services/api/app/models/keep_disk.rb
23 23
    t.add :ping_secret
24 24
  end
25 25

  
26
  def self.attributes_types
27
    proxy_attrs = {}
28
    %w(service_host service_port service_ssl_flag).each do |attr_name|
29
      proxy_attrs[attr_name] = KeepService.columns_hash[attr_name].type
30
    end
31
    super.merge(proxy_attrs)
32
  end
33

  
26 34
  def foreign_key_attributes
27 35
    super.reject { |a| a == "filesystem_uuid" }
28 36
  end
services/api/app/models/link.rb
21 21
    t.add :properties
22 22
  end
23 23

  
24
  def self.attributes_types
25
    result = super
26
    kind_type = result["kind"]
27
    result.merge({"head_kind" => kind_type, "tail_kind" => kind_type})
28
  end
29

  
24 30
  def properties
25 31
    @properties ||= Hash.new
26 32
    super
services/api/app/models/log.rb
18 18
    t.add :properties
19 19
  end
20 20

  
21
  def self.attributes_types
22
    super.merge({"object_kind" => "string"})
23
  end
24

  
21 25
  def object_kind
22 26
    if k = ArvadosModel::resource_class_for_uuid(object_uuid)
23 27
      k.kind
services/api/app/models/node.rb
39 39
    t.add lambda { |x| @@nameservers }, :as => :nameservers
40 40
  end
41 41

  
42
  def self.attributes_types
43
    super.merge({ "crunch_worker_state" => "string",
44
                  "nameservers" => "Array",
45
                  "status" => "string",
46
                })
47
  end
48

  
42 49
  def domain
43 50
    super || @@domain
44 51
  end
services/api/app/models/repository.rb
19 19
    super.merge({"push_url" => ["name"], "fetch_url" => ["name"]})
20 20
  end
21 21

  
22
  def self.attributes_types
23
    super.merge({"fetch_url" => "string", "push_url" => "string"})
24
  end
25

  
22 26
  def push_url
23 27
    "git@git.%s.arvadosapi.com:%s.git" % [Rails.configuration.uuid_prefix, name]
24 28
  end
services/api/app/models/user.rb
57 57

  
58 58
  ALL_PERMISSIONS = {read: true, write: true, manage: true}
59 59

  
60
  def self.attributes_types
61
    super.merge({ "full_name" => "string",
62
                  "is_invited" => "boolean",
63
                  "writable_by" => "Array",
64
                })
65
  end
66

  
60 67
  def full_name
61 68
    "#{first_name} #{last_name}".strip
62 69
  end
services/api/test/functional/arvados/v1/schema_controller_test.rb
20 20
    assert_includes discovery_doc, 'defaultTrashLifetime'
21 21
    assert_equal discovery_doc['defaultTrashLifetime'], Rails.application.config.default_trash_lifetime
22 22
  end
23

  
24
  test "discovery document includes types for all API-accessible attributes" do
25
    get :index
26
    assert_response :success
27
    schemas = json_response["schemas"]
28
    ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |klass|
29
      klass_name = klass.to_s
30
      next if klass_name.start_with?("Commit")
31
      klass_schema = schemas[klass_name].andand["properties"]
32
      refute_nil(klass_schema, "no schema for #{klass}")
33
      attr_names = klass.methods.
34
          grep(/^api_accessible_\w+$/).
35
          flat_map do |method_name|
36
        if method_name == :api_accessible_attributes
37
          []
38
        else
39
          klass.send(method_name).keys
40
        end
41
      end.uniq.map(&:to_s).sort
42
      schema_keys = klass_schema.keys.sort
43
      assert_equal(attr_names, schema_keys,
44
                   "#{klass_name} has wrong attributes list")
45
      assert_empty(klass_schema.keys.
46
                     select { |key| klass_schema[key]["type"].nil? },
47
                   "#{klass_name} attributes missing type information")
48
      writable_attrs = attr_names.reject { |n| klass.columns_hash[n].nil? }
49
      assert_empty(writable_attrs.select { |k| klass_schema[k]["readonly"] },
50
                   "writable attribute(s) marked readonly")
51
      readonly_attrs = attr_names - writable_attrs
52
      assert_empty(readonly_attrs.reject { |k| klass_schema[k]["readonly"] },
53
                   "readonly attribute(s) not marked readonly")
54
    end
55
  end
23 56
end
    (1-1/1)