From e3d56ecadb666afdcf230b5ed4f6cc8768a0629a Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 25 Aug 2015 19:41:04 +0200 Subject: [PATCH] v3: more info in the service index --- lib/travis/api/v3/github.rb | 12 ++- .../api/v3/renderer/collection_renderer.rb | 4 + lib/travis/api/v3/renderer/error.rb | 5 ++ lib/travis/api/v3/routes/resource.rb | 5 +- lib/travis/api/v3/service_index.rb | 81 +++++++++++++++++-- 5 files changed, 99 insertions(+), 8 deletions(-) diff --git a/lib/travis/api/v3/github.rb b/lib/travis/api/v3/github.rb index e9064a58..9ec3f6fc 100644 --- a/lib/travis/api/v3/github.rb +++ b/lib/travis/api/v3/github.rb @@ -5,13 +5,23 @@ module Travis::API::V3 DEFAULT_OPTIONS = { client_id: Travis.config.oauth2.try(:client_id), client_secret: Travis.config.oauth2.try(:client_secret), + scopes: Travis.config.oauth2.try(:scope).to_s.split(?,), user_agent: "Travis-API/3 Travis-CI/0.0.1 GH/#{GH::VERSION}", origin: Travis.config.host, api_url: Travis.config.github.api_url, + web_url: Travis.config.github.api_url.gsub(%r{\A(https?://)(?:api\.)?([^/]+)(?:/.*)?\Z}, '\1\2'), ssl: Travis.config.ssl.merge(Travis.config.github.ssl || {}).to_hash.compact } private_constant :DEFAULT_OPTIONS + def self.client_config + { + api_url: DEFAULT_OPTIONS[:api_url], + web_url: DEFAULT_OPTIONS[:web_url], + scopes: DEFAULT_OPTIONS[:scopes] + } + end + attr_reader :gh, :user def initialize(user = nil, token = nil) @@ -40,4 +50,4 @@ module Travis::API::V3 end end end -end \ No newline at end of file +end diff --git a/lib/travis/api/v3/renderer/collection_renderer.rb b/lib/travis/api/v3/renderer/collection_renderer.rb index cd415343..db5021be 100644 --- a/lib/travis/api/v3/renderer/collection_renderer.rb +++ b/lib/travis/api/v3/renderer/collection_renderer.rb @@ -8,6 +8,10 @@ module Travis::API::V3 @available_attributes ||= Set.new end + def self.representations + { standard: available_attributes } + end + def self.type(value) define_method(:type) { value } end diff --git a/lib/travis/api/v3/renderer/error.rb b/lib/travis/api/v3/renderer/error.rb index 1d85d15e..7d5fd4a2 100644 --- a/lib/travis/api/v3/renderer/error.rb +++ b/lib/travis/api/v3/renderer/error.rb @@ -1,7 +1,12 @@ module Travis::API::V3 module Renderer::Error + AVAILABLE_ATTRIBUTES = [ :error_type, :error_message, :resource_type, :permission ] extend self + def available_attributes + AVAILABLE_ATTRIBUTES + end + def render(error, **) { :@type => 'error'.freeze, diff --git a/lib/travis/api/v3/routes/resource.rb b/lib/travis/api/v3/routes/resource.rb index 2805f9a9..90730063 100644 --- a/lib/travis/api/v3/routes/resource.rb +++ b/lib/travis/api/v3/routes/resource.rb @@ -2,11 +2,12 @@ require 'mustermann' module Travis::API::V3 class Routes::Resource - attr_accessor :identifier, :route, :services + attr_accessor :identifier, :route, :services, :meta_data - def initialize(identifier) + def initialize(identifier, **meta_data) @identifier = identifier @services = {} + @meta_data = meta_data end def add_service(request_method, service, sub_route = nil) diff --git a/lib/travis/api/v3/service_index.rb b/lib/travis/api/v3/service_index.rb index 79e3f3e3..4ee23a1e 100644 --- a/lib/travis/api/v3/service_index.rb +++ b/lib/travis/api/v3/service_index.rb @@ -18,36 +18,107 @@ module Travis::API::V3 @json_home_response = V3.response(render_json_home, content_type: 'application/json-home'.freeze) end + def config + # TODO: move this somewhere else? + pusher_config = (Travis.config.pusher_ws || Travis.config.pusher || {}).to_hash.slice(:scheme, :host, :port, :path, :key, :secure, :private) + { + host: Travis.config.client_domain || Travis.config.host, + github: V3::GitHub.client_config, + pusher: pusher_config + } + end + + def all_resources + @all_resources ||= begin + home_actions = { + find: { + :@type => :template, + :request_method => :GET, + :uri_template => prefix + ?/ + } + } + + all = routes.resources + [ + Routes::Resource.new(:account), # dummy as there are only accounts routes right now + Routes::Resource.new(:error), + Routes::Resource.new(:home, attributes: [:config, :errors, :resources], actions: home_actions), + Routes::Resource.new(:resource, attributes: [:actions, :attributes, :representations, :access_rights]), + Routes::Resource.new(:template, attributes: [:request_method, :uri_template]) + ] + + all.sort_by(&:identifier) + end + end + + def error_payload(error) + attributes = [] + default_message = error.default_message + + if default_message.is_a? Symbol + default_message = error.template % default_message + attributes << :resource_type + end + + if error == InsufficientAccess + attributes << :resource_type + attributes << :permission + end + + { status: error.status, default_message: default_message, additional_attributes: attributes.uniq.sort } + end + + def errors + errors = V3.constants.map { |c| V3.const_get(c) }.select { |c| c < V3::Error } + errors.map { |e| [e.type, error_payload(e)] }.sort_by(&:first).to_h + end + def render(env) json_home?(env) ? json_home_response : json_response end def render_json resources = { } - routes.resources.sort_by(&:identifier).each do |resource| + all_resources.each do |resource| data = resources[resource.identifier] ||= { :@type => :resource, :actions => {} } - if renderer = Renderer[resource.identifier, false] and renderer.respond_to? :representations - data[:representations] = renderer.representations + data.merge! resource.meta_data + + if renderer = Renderer[resource.identifier, false] + data[:attributes] = renderer.available_attributes if renderer.respond_to? :available_attributes + data[:representations] = renderer.representations if renderer.respond_to? :representations end + + if permissions = Permissions[resource.identifier, false] + data[:permissions] = permissions.access_rights.keys + end + resource.services.each do |(request_method, sub_route), service| list = resources[resource.identifier][:actions][service] ||= [] pattern = sub_route ? resource.route + sub_route : resource.route factory = Services[resource.identifier][service] + pattern.to_templates.each do |template| params = factory.params if request_method == 'GET'.freeze params &&= params.reject { |p| p.start_with? ?@.freeze } template += "{?#{params.sort.join(?,)}}" if params and params.any? list << { :@type => :template, :request_method => request_method, :uri_template => prefix + template } end + end end - { :@type => :home, :@href => "#{prefix}/", :resources => resources } + + { + :@type => :home, + :@href => "#{prefix}/", + :config => config, + :errors => errors, + :resources => resources + } end def render_json_home relations = {} - routes.resources.each do |resource| + all_resources.each do |resource| resource.services.each do |(request_method, sub_route), service| pattern = sub_route ? resource.route + sub_route : resource.route relation = "http://schema.travis-ci.com/rel/#{resource.identifier}/#{service}"