From eac88e5d5095d5d83105539895fe5ec7bea15d90 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 10:50:34 +0200 Subject: [PATCH 1/7] v3: introduce permission objects --- lib/travis/api/v3.rb | 1 - lib/travis/api/v3/access_control/generic.rb | 24 ++++++-- lib/travis/api/v3/access_control/user.rb | 12 ++-- lib/travis/api/v3/permissions.rb | 5 ++ lib/travis/api/v3/permissions/generic.rb | 55 +++++++++++++++++++ lib/travis/api/v3/permissions/repository.rb | 7 +++ lib/travis/api/v3/services/requests/create.rb | 6 +- spec/v3/services/requests/create_spec.rb | 6 +- 8 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 lib/travis/api/v3/permissions.rb create mode 100644 lib/travis/api/v3/permissions/generic.rb create mode 100644 lib/travis/api/v3/permissions/repository.rb diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index 727d62ae..221df59b 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -30,7 +30,6 @@ module Travis WrongCredentials = ClientError .create('access denied', status: 403) LoginRequired = ClientError .create('login required', status: 403) InsufficientAccess = ClientError .create(status: 403) - PushAccessRequired = InsufficientAccess .create('push access required') WrongParams = ClientError .create('wrong parameters') ServerError = Error .create(status: 500) NotImplemented = ServerError .create('request not (yet) implemented', status: 501) diff --git a/lib/travis/api/v3/access_control/generic.rb b/lib/travis/api/v3/access_control/generic.rb index c4883ff3..4e5755cd 100644 --- a/lib/travis/api/v3/access_control/generic.rb +++ b/lib/travis/api/v3/access_control/generic.rb @@ -36,6 +36,11 @@ module Travis::API::V3 list.select { |r| visible?(r) } end + def permissions(object) + return unless factory = permission_class(object.class) + factory.new(self, object) + end + protected def build_visible?(build) @@ -78,13 +83,22 @@ module Travis::API::V3 send(method, object) if respond_to?(method, true) end - @@method_for_cache = Tool::ThreadLocal.new + + @@unknown_permission = Object.new + @@permission_class_cache = Tool::ThreadLocal.new + @@method_for_cache = Tool::ThreadLocal.new + + def permission_class(klass) + result = @@permission_class_cache[klass] ||= Permissions[normailze_type(klass), false] || @@unknown_permission + result unless result == @@unknown_permission + end def method_for(type, method) - @@method_for_cache[[type, method]] ||= begin - prefix = type.name.sub(/^Travis::API::V3::Models::/, ''.freeze).underscore - "#{prefix}_#{method}" - end + @@method_for_cache[[type, method]] ||= "#{normailze_type(type)}_#{method}" + end + + def normailze_type(type) + type.name.sub(/^Travis::API::V3::Models::/, ''.freeze).underscore.to_sym end end end diff --git a/lib/travis/api/v3/access_control/user.rb b/lib/travis/api/v3/access_control/user.rb index f1979dfa..c6a2dd25 100644 --- a/lib/travis/api/v3/access_control/user.rb +++ b/lib/travis/api/v3/access_control/user.rb @@ -2,12 +2,12 @@ require 'travis/api/v3/access_control/generic' module Travis::API::V3 class AccessControl::User < AccessControl::Generic - attr_reader :user, :permissions + attr_reader :user, :access_permissions def initialize(user) - user = Models::User.find(user.id) if user.is_a? ::User - @user = user - @permissions = user.permissions.where(user_id: user.id) + user = Models::User.find(user.id) if user.is_a? ::User + @user = user + @access_permissions = user.permissions.where(user_id: user.id) super() end @@ -20,7 +20,7 @@ module Travis::API::V3 end def visible_repositories(list) - list.where('repositories.private = false OR repositories.id IN (?)'.freeze, permissions.map(&:repository_id)) + list.where('repositories.private = false OR repositories.id IN (?)'.freeze, access_permissions.map(&:repository_id)) end protected @@ -35,7 +35,7 @@ module Travis::API::V3 def permission?(type, id) id = id.id if id.is_a? ::Repository - permissions.where(type => true, :repository_id => id).any? + access_permissions.where(type => true, :repository_id => id).any? end end end diff --git a/lib/travis/api/v3/permissions.rb b/lib/travis/api/v3/permissions.rb new file mode 100644 index 00000000..8b4c58b7 --- /dev/null +++ b/lib/travis/api/v3/permissions.rb @@ -0,0 +1,5 @@ +module Travis::API::V3 + module Permissions + extend ConstantResolver + end +end diff --git a/lib/travis/api/v3/permissions/generic.rb b/lib/travis/api/v3/permissions/generic.rb new file mode 100644 index 00000000..ac270bfe --- /dev/null +++ b/lib/travis/api/v3/permissions/generic.rb @@ -0,0 +1,55 @@ +module Travis::API::V3 + class Permissions::Generic + def self.access_rights + @access_rights ||= begin + rights = superclass.respond_to?(:access_rights) ? superclass.access_rights.dup : [] + public_instance_methods(false) do |method| + next unless method.to_s =~ /^([^_].+)\?$/ + rights << $1.to_sym + end + end + end + + # for any public method defined with a question mark in the end, it defines a method with an + # exclamation mark that will raise an InsufficientAccess error if the question mark version + # returns false + def self.method_added(method_name) + super + + return unless public_method_defined?(method_name) + return unless method_name.to_s =~ /^([^_].+)\?$/ + + permission = $1 + type = name[/[^:]+$/].underscore + + class_eval <<-RUBY + def #{permission}! + return self if #{permission}? + payload = { + resource_type: "#{type}".freeze, + permission: "#{permission}".freeze + } + payload[:#{type}] = object if read? + raise InsufficientAccess.new('operation requires #{permission} access to #{type}', payload) + end + RUBY + end + + attr_accessor :access_control, :object + + def initialize(access_control, object) + @access_control = access_control + @object = object + end + + def read? + access_control.visible? object + end + + private + + def write? + access_control.writable? object + end + end +end diff --git a/lib/travis/api/v3/permissions/repository.rb b/lib/travis/api/v3/permissions/repository.rb new file mode 100644 index 00000000..18b793e8 --- /dev/null +++ b/lib/travis/api/v3/permissions/repository.rb @@ -0,0 +1,7 @@ +module Travis::API::V3 + class Permissions::Repository < Permissions::Generic + def create_request? + write? + end + end +end diff --git a/lib/travis/api/v3/services/requests/create.rb b/lib/travis/api/v3/services/requests/create.rb index 2ff6f156..40a299c5 100644 --- a/lib/travis/api/v3/services/requests/create.rb +++ b/lib/travis/api/v3/services/requests/create.rb @@ -8,9 +8,9 @@ module Travis::API::V3 params "request", "user", :config, :message, :branch def run - raise LoginRequired unless access_control.logged_in? or access_control.full_access? - raise NotFound unless repository = find(:repository) - raise PushAccessRequired, repository: repository unless access_control.writable?(repository) + raise LoginRequired unless access_control.logged_in? or access_control.full_access? + raise NotFound unless repository = find(:repository) + access_control.permissions(repository).create_request! user = find(:user) if access_control.full_access? and params_for? 'user'.freeze user ||= access_control.user diff --git a/spec/v3/services/requests/create_spec.rb b/spec/v3/services/requests/create_spec.rb index 62b32089..b316ca82 100644 --- a/spec/v3/services/requests/create_spec.rb +++ b/spec/v3/services/requests/create_spec.rb @@ -49,8 +49,10 @@ describe Travis::API::V3::Services::Requests::Create do example { expect(last_response.status).to be == 403 } example { expect(JSON.load(body)).to be == { "@type" => "error", - "error_type" => "push_access_required", - "error_message" => "push access required", + "error_type" => "insufficient_access", + "error_message" => "operation requires create_request access to repository", + "resource_type" => "repository", + "permission" => "create_request", "repository" => { "@type" => "repository", "@href" => "/repo/#{repo.id}", From 77ad196a86094a7d6f1b17f2271c43662f8600f6 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 10:56:33 +0200 Subject: [PATCH 2/7] v3: use permissions check for enable/disable --- lib/travis/api/v3/permissions/repository.rb | 8 ++++++++ lib/travis/api/v3/services/repository/disable.rb | 5 +++++ lib/travis/api/v3/services/repository/enable.rb | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/lib/travis/api/v3/permissions/repository.rb b/lib/travis/api/v3/permissions/repository.rb index 18b793e8..b89d6ae4 100644 --- a/lib/travis/api/v3/permissions/repository.rb +++ b/lib/travis/api/v3/permissions/repository.rb @@ -1,5 +1,13 @@ module Travis::API::V3 class Permissions::Repository < Permissions::Generic + def enable? + write? + end + + def disable? + write? + end + def create_request? write? end diff --git a/lib/travis/api/v3/services/repository/disable.rb b/lib/travis/api/v3/services/repository/disable.rb index 08a191bb..c904351e 100644 --- a/lib/travis/api/v3/services/repository/disable.rb +++ b/lib/travis/api/v3/services/repository/disable.rb @@ -3,6 +3,7 @@ module Travis::API::V3 def run!(activate = false) raise LoginRequired unless access_control.logged_in? or access_control.full_access? raise NotFound unless repository = find(:repository) + check_access(repository) admin = access_control.admin_for(repository) @@ -11,5 +12,9 @@ module Travis::API::V3 repository end + + def check_access(repository) + access_control.permissions(repository).disable! + end end end diff --git a/lib/travis/api/v3/services/repository/enable.rb b/lib/travis/api/v3/services/repository/enable.rb index 5d85439b..5d43bbe7 100644 --- a/lib/travis/api/v3/services/repository/enable.rb +++ b/lib/travis/api/v3/services/repository/enable.rb @@ -3,5 +3,9 @@ module Travis::API::V3 def run! super(true) end + + def check_access(repository) + access_control.permissions(repository).enable! + end end end From 2b0ae177fa68454bf2079371e927f12734ead775 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 11:31:05 +0200 Subject: [PATCH 3/7] v3: expose repo access permissions in payload --- lib/travis/api/v3/access_control/scoped.rb | 13 ++++++++++-- lib/travis/api/v3/permissions/generic.rb | 11 +++++++--- lib/travis/api/v3/renderer/model_renderer.rb | 8 ++++++-- spec/v3/services/owner/find_spec.rb | 10 ++++++++++ spec/v3/services/owner/repositories_spec.rb | 5 +++++ .../repositories/for_current_user_spec.rb | 15 +++++++++----- spec/v3/services/repository/find_spec.rb | 20 +++++++++++++++++++ 7 files changed, 70 insertions(+), 12 deletions(-) diff --git a/lib/travis/api/v3/access_control/scoped.rb b/lib/travis/api/v3/access_control/scoped.rb index 5bf1df90..33b8017d 100644 --- a/lib/travis/api/v3/access_control/scoped.rb +++ b/lib/travis/api/v3/access_control/scoped.rb @@ -2,18 +2,27 @@ require 'travis/api/v3/access_control/generic' module Travis::API::V3 class AccessControl::Scoped < AccessControl::Generic - attr_accessor :unscoped, :owner_name, :name + attr_accessor :unscoped, :anonymous, :owner_name, :name def initialize(scope, unscoped) @owner_name, @name = scope.split(?/.freeze, 2) @unscoped = unscoped + @anonymous = AccessControl::Anonymous.new end protected def private_repository_visible?(repository) + scope_repository(repository).visible?(repository) + end + + def repository_writable?(repository) + scope_repository(repository).writable?(repository) + end + + def scope_repository(repository, method = caller_locations.first.base_label) return false if name and repository.name != name - unscoped.visible?(repository) if repository.owner_name == owner_name + repository.owner_name == owner_name ? unscoped : anonymous end end end diff --git a/lib/travis/api/v3/permissions/generic.rb b/lib/travis/api/v3/permissions/generic.rb index ac270bfe..5648adfd 100644 --- a/lib/travis/api/v3/permissions/generic.rb +++ b/lib/travis/api/v3/permissions/generic.rb @@ -2,11 +2,12 @@ module Travis::API::V3 class Permissions::Generic def self.access_rights @access_rights ||= begin - rights = superclass.respond_to?(:access_rights) ? superclass.access_rights.dup : [] - public_instance_methods(false) do |method| + rights = superclass.respond_to?(:access_rights) ? superclass.access_rights.dup : {} + public_instance_methods(false).each do |method| next unless method.to_s =~ /^([^_].+)\?$/ - rights << $1.to_sym + rights[$1.to_sym] = method end + rights end end @@ -46,6 +47,10 @@ module Travis::API::V3 access_control.visible? object end + def to_h + self.class.access_rights.map { |k,v| [k,!!public_send(v)] }.to_h + end + private def write? diff --git a/lib/travis/api/v3/renderer/model_renderer.rb b/lib/travis/api/v3/renderer/model_renderer.rb index 491aa627..81b4a864 100644 --- a/lib/travis/api/v3/renderer/model_renderer.rb +++ b/lib/travis/api/v3/renderer/model_renderer.rb @@ -43,7 +43,7 @@ module Travis::API::V3 @script_name = script_name @include = include @included = included - @access_control = access_control + @access_control = access_control || AccessControl::Anonymous.new end def href @@ -74,13 +74,17 @@ module Travis::API::V3 nested_included = included + [model] modes = {} + if permissions = access_control.permissions(model) and (representation != :minimal or include? :@permissions) + result[:@permissions] = permissions.to_h + end + if include.any? excepted_type = result[:@type].to_s fields = fields.dup end include.each do |qualified_field| - raise WrongParams, 'illegal format for include parameter'.freeze unless /\A(?\w+)\.(?\w+)\Z$/ =~ qualified_field + raise WrongParams, 'illegal format for include parameter'.freeze unless /\A(?\w+)\.(?@?\w+)\Z$/ =~ qualified_field next if prefix != excepted_type raise WrongParams, 'no field %p to include'.freeze % qualified_field unless self.class.available_attributes.include?(field) diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index 90152fd8..b5dd0c82 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -39,6 +39,11 @@ describe Travis::API::V3::Services::Owner::Find do "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => false, + "disable" => false, + "create_request"=> false}, "id" => repo.id, "name" => "example-repo", "slug" => "example-org/example-repo", @@ -76,6 +81,11 @@ describe Travis::API::V3::Services::Owner::Find do "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => false, + "disable" => false, + "create_request"=> false}, "id" => repo.id, "name" => "example-repo", "slug" => "example-org/example-repo", diff --git a/spec/v3/services/owner/repositories_spec.rb b/spec/v3/services/owner/repositories_spec.rb index 9f47fecb..77285bfc 100644 --- a/spec/v3/services/owner/repositories_spec.rb +++ b/spec/v3/services/owner/repositories_spec.rb @@ -18,6 +18,11 @@ describe Travis::API::V3::Services::Owner::Repositories do "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => false, + "disable" => false, + "create_request"=> false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb index 67068f69..26fe6151 100644 --- a/spec/v3/services/repositories/for_current_user_spec.rb +++ b/spec/v3/services/repositories/for_current_user_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe Travis::API::V3::Services::Repositories::ForCurrentUser do let(:repo) { Repository.by_slug('svenfuchs/minimal').first } - let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } - let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} - before { Permission.create(repository: repo, user: repo.owner, pull: true) } - before { repo.update_attribute(:private, true) } - after { repo.update_attribute(:private, false) } + let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) } + let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }} + before { Permission.create(repository: repo, user: repo.owner, pull: true, push: true) } + before { repo.update_attribute(:private, true) } + after { repo.update_attribute(:private, false) } describe "private repository, private API, authenticated as user with access" do before { get("/v3/repos", {}, headers) } @@ -18,6 +18,11 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do "repositories" => [{ "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => true, + "disable" => true, + "create_request"=> true}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb index b92df8d0..d0d6d431 100644 --- a/spec/v3/services/repository/find_spec.rb +++ b/spec/v3/services/repository/find_spec.rb @@ -10,6 +10,11 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(parsed_body).to be == { "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => false, + "disable" => false, + "create_request"=> false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -95,6 +100,11 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(parsed_body).to be == { "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => false, + "disable" => false, + "create_request"=> false}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -165,6 +175,11 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(parsed_body).to be == { "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => true, + "disable" => true, + "create_request"=> true}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -241,6 +256,11 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(parsed_body).to be == { "@type" => "repository", "@href" => "/v3/repo/#{repo.id}", + "@permissions" => { + "read" => true, + "enable" => true, + "disable" => true, + "create_request"=> true}, "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", From 429ad3fc6b79d95da8dfd269f70b6235803301fe Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 13:44:32 +0200 Subject: [PATCH 4/7] v3: don't error on including magic fields --- lib/travis/api/v3/renderer/model_renderer.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/travis/api/v3/renderer/model_renderer.rb b/lib/travis/api/v3/renderer/model_renderer.rb index 81b4a864..b62c8537 100644 --- a/lib/travis/api/v3/renderer/model_renderer.rb +++ b/lib/travis/api/v3/renderer/model_renderer.rb @@ -86,11 +86,14 @@ module Travis::API::V3 include.each do |qualified_field| raise WrongParams, 'illegal format for include parameter'.freeze unless /\A(?\w+)\.(?@?\w+)\Z$/ =~ qualified_field next if prefix != excepted_type - raise WrongParams, 'no field %p to include'.freeze % qualified_field unless self.class.available_attributes.include?(field) - field &&= field.to_sym - fields << field unless fields.include?(field) - modes[field] = :standard + if self.class.available_attributes.include?(field) + field &&= field.to_sym + fields << field unless fields.include?(field) + modes[field] = :standard + else + raise WrongParams, 'no field %p to include'.freeze % qualified_field unless result.keys.any? { |k| k.to_s == field.to_s } + end end fields.each do |field| From 21aa667b9c97ae79d4ca48423437129eb574c873 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 14:14:21 +0200 Subject: [PATCH 5/7] v3: add account permissions --- lib/travis/api/v3/access_control/generic.rb | 4 ++++ lib/travis/api/v3/models/account.rb | 14 ++++++++++++++ lib/travis/api/v3/models/organization.rb | 2 ++ lib/travis/api/v3/permissions/account.rb | 6 ++++++ lib/travis/api/v3/permissions/repository.rb | 2 ++ spec/v3/services/accounts/for_current_user_spec.rb | 2 ++ 6 files changed, 30 insertions(+) create mode 100644 lib/travis/api/v3/permissions/account.rb diff --git a/lib/travis/api/v3/access_control/generic.rb b/lib/travis/api/v3/access_control/generic.rb index 4e5755cd..0e09e409 100644 --- a/lib/travis/api/v3/access_control/generic.rb +++ b/lib/travis/api/v3/access_control/generic.rb @@ -43,6 +43,10 @@ module Travis::API::V3 protected + def account_visible?(account) + user and account.members.include?(user) + end + def build_visible?(build) visible? build.repository end diff --git a/lib/travis/api/v3/models/account.rb b/lib/travis/api/v3/models/account.rb index a78a4b13..53f45fd0 100644 --- a/lib/travis/api/v3/models/account.rb +++ b/lib/travis/api/v3/models/account.rb @@ -23,6 +23,20 @@ module Travis::API::V3 subscription.present? and subscription.active? end + def members + @members ||= if owner.respond_to? :members + owner.members + else + [owner] + end + end + + def reload + @members = nil + owner.reload + self + end + alias_method :educational, :educational? alias_method :subscribed, :subscribed? end diff --git a/lib/travis/api/v3/models/organization.rb b/lib/travis/api/v3/models/organization.rb index 973487ed..224f0b8e 100644 --- a/lib/travis/api/v3/models/organization.rb +++ b/lib/travis/api/v3/models/organization.rb @@ -8,5 +8,7 @@ module Travis::API::V3 def subscription super if Features.use_subscriptions? end + + alias members users end end diff --git a/lib/travis/api/v3/permissions/account.rb b/lib/travis/api/v3/permissions/account.rb new file mode 100644 index 00000000..a161b62d --- /dev/null +++ b/lib/travis/api/v3/permissions/account.rb @@ -0,0 +1,6 @@ +require 'travis/api/v3/permissions/generic' + +module Travis::API::V3 + class Permissions::Account < Permissions::Generic + end +end diff --git a/lib/travis/api/v3/permissions/repository.rb b/lib/travis/api/v3/permissions/repository.rb index b89d6ae4..75f47597 100644 --- a/lib/travis/api/v3/permissions/repository.rb +++ b/lib/travis/api/v3/permissions/repository.rb @@ -1,3 +1,5 @@ +require 'travis/api/v3/permissions/generic' + module Travis::API::V3 class Permissions::Repository < Permissions::Generic def enable? diff --git a/spec/v3/services/accounts/for_current_user_spec.rb b/spec/v3/services/accounts/for_current_user_spec.rb index 01d45c9a..e50b36e6 100644 --- a/spec/v3/services/accounts/for_current_user_spec.rb +++ b/spec/v3/services/accounts/for_current_user_spec.rb @@ -22,6 +22,7 @@ describe Travis::API::V3::Services::Accounts::ForCurrentUser do "@href" => "/v3/accounts", "accounts" => [{ "@type" => "account", + "@permissions" => { "read"=>true }, "id" => repo.owner.github_id, "subscribed" => false, "educational" => false, @@ -31,6 +32,7 @@ describe Travis::API::V3::Services::Accounts::ForCurrentUser do "id" => repo.owner_id, "login" => "svenfuchs" }}, {"@type" => "account", + "@permissions" => { "read"=>true }, "id" => 42, "subscribed" => false, "educational" => false, From 2094b505537e759e9d030d85ed52d8243a98e1f3 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 14:28:33 +0200 Subject: [PATCH 6/7] v3: add @permissions to organization payload --- lib/travis/api/v3/access_control/user.rb | 4 ++ lib/travis/api/v3/permissions/organization.rb | 9 ++++ spec/v3/services/organization/find_spec.rb | 15 +++--- .../organizations/for_current_user_spec.rb | 21 +++++---- spec/v3/services/owner/find_spec.rb | 47 ++++++++++--------- 5 files changed, 58 insertions(+), 38 deletions(-) create mode 100644 lib/travis/api/v3/permissions/organization.rb diff --git a/lib/travis/api/v3/access_control/user.rb b/lib/travis/api/v3/access_control/user.rb index c6a2dd25..3376ffb9 100644 --- a/lib/travis/api/v3/access_control/user.rb +++ b/lib/travis/api/v3/access_control/user.rb @@ -25,6 +25,10 @@ module Travis::API::V3 protected + def organization_writable?(organization) + organization.members.include? user + end + def repository_writable?(repository) permission?(:push, repository) end diff --git a/lib/travis/api/v3/permissions/organization.rb b/lib/travis/api/v3/permissions/organization.rb new file mode 100644 index 00000000..1693d975 --- /dev/null +++ b/lib/travis/api/v3/permissions/organization.rb @@ -0,0 +1,9 @@ +require 'travis/api/v3/permissions/generic' + +module Travis::API::V3 + class Permissions::Organization < Permissions::Generic + def sync? + write? + end + end +end diff --git a/spec/v3/services/organization/find_spec.rb b/spec/v3/services/organization/find_spec.rb index 030aa172..2245441a 100644 --- a/spec/v3/services/organization/find_spec.rb +++ b/spec/v3/services/organization/find_spec.rb @@ -9,13 +9,14 @@ describe Travis::API::V3::Services::Organization::Find do before { get("/v3/org/#{org.id}") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "organization", - "@href" => "/v3/org/#{org.id}", - "id" => org.id, - "login" => "example-org", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil + "@type" => "organization", + "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, + "id" => org.id, + "login" => "example-org", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil }} end end diff --git a/spec/v3/services/organizations/for_current_user_spec.rb b/spec/v3/services/organizations/for_current_user_spec.rb index f402e7cd..dfdf1517 100644 --- a/spec/v3/services/organizations/for_current_user_spec.rb +++ b/spec/v3/services/organizations/for_current_user_spec.rb @@ -18,16 +18,17 @@ describe Travis::API::V3::Services::Organizations::ForCurrentUser do before { get("/v3/orgs", {}, headers) } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "organizations", - "@href" => "/v3/orgs", - "organizations" => [{ - "@type" => "organization", - "@href" => "/v3/org/#{org.id}", - "id" => org.id, - "login" => "example-org", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil + "@type" => "organizations", + "@href" => "/v3/orgs", + "organizations" => [{ + "@type" => "organization", + "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>true }, + "id" => org.id, + "login" => "example-org", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil }] }} end diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index b5dd0c82..53336475 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -10,13 +10,14 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-org") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "organization", - "@href" => "/v3/org/#{org.id}", - "id" => org.id, - "login" => "example-org", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil + "@type" => "organization", + "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, + "id" => org.id, + "login" => "example-org", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil }} end @@ -31,6 +32,7 @@ describe Travis::API::V3::Services::Owner::Find do example { expect(JSON.load(body)).to be == { "@type" => "organization", "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, "id" => org.id, "login" => "example-org", "name" => nil, @@ -73,6 +75,7 @@ describe Travis::API::V3::Services::Owner::Find do example { expect(JSON.load(body)).to be == { "@type" => "organization", "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, "id" => org.id, "login" => "example-org", "name" => nil, @@ -108,13 +111,14 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-ORG") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "organization", - "@href" => "/v3/org/#{org.id}", - "id" => org.id, - "login" => "example-org", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil + "@type" => "organization", + "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, + "id" => org.id, + "login" => "example-org", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil }} end @@ -126,13 +130,14 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-org?organization.id=#{other.id}") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "organization", - "@href" => "/v3/org/#{org.id}", - "id" => org.id, - "login" => "example-org", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil + "@type" => "organization", + "@href" => "/v3/org/#{org.id}", + "@permissions" => { "read"=>true, "sync"=>false }, + "id" => org.id, + "login" => "example-org", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil }} end end From 857f13b26c51e4935b307d6b6984b7487c7dc74b Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 29 Apr 2015 14:39:52 +0200 Subject: [PATCH 7/7] v3: add @permissions to user payload --- lib/travis/api/v3/access_control/user.rb | 4 ++ lib/travis/api/v3/permissions/user.rb | 9 ++++ spec/v3/services/owner/find_spec.rb | 57 +++++++++++++----------- spec/v3/services/user/current_spec.rb | 19 ++++---- spec/v3/services/user/find_spec.rb | 19 ++++---- 5 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 lib/travis/api/v3/permissions/user.rb diff --git a/lib/travis/api/v3/access_control/user.rb b/lib/travis/api/v3/access_control/user.rb index 3376ffb9..b0b93f15 100644 --- a/lib/travis/api/v3/access_control/user.rb +++ b/lib/travis/api/v3/access_control/user.rb @@ -29,6 +29,10 @@ module Travis::API::V3 organization.members.include? user end + def user_writable?(user) + user == self.user + end + def repository_writable?(repository) permission?(:push, repository) end diff --git a/lib/travis/api/v3/permissions/user.rb b/lib/travis/api/v3/permissions/user.rb new file mode 100644 index 00000000..6aaf5af2 --- /dev/null +++ b/lib/travis/api/v3/permissions/user.rb @@ -0,0 +1,9 @@ +require 'travis/api/v3/permissions/generic' + +module Travis::API::V3 + class Permissions::User < Permissions::Generic + def sync? + write? + end + end +end diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index 53336475..66d3feca 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -151,15 +151,16 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-user") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "user", - "@href" => "/v3/user/#{user.id}", - "id" => user.id, - "login" => "example-user", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil, - "is_syncing" => nil, - "synced_at" => nil + "@type" => "user", + "@href" => "/v3/user/#{user.id}", + "@permissions" => {"read"=>true, "sync"=>false}, + "id" => user.id, + "login" => "example-user", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil, + "is_syncing" => nil, + "synced_at" => nil }} end @@ -167,15 +168,16 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-USER") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "user", - "@href" => "/v3/user/#{user.id}", - "id" => user.id, - "login" => "example-user", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil, - "is_syncing" => nil, - "synced_at" => nil + "@type" => "user", + "@href" => "/v3/user/#{user.id}", + "@permissions" => {"read"=>true, "sync"=>false}, + "id" => user.id, + "login" => "example-user", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil, + "is_syncing" => nil, + "synced_at" => nil }} end @@ -187,15 +189,16 @@ describe Travis::API::V3::Services::Owner::Find do before { get("/v3/owner/example-user?user.id=#{other.id}") } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "user", - "@href" => "/v3/user/#{user.id}", - "id" => user.id, - "login" => "example-user", - "name" => nil, - "github_id" => nil, - "avatar_url" => nil, - "is_syncing" => nil, - "synced_at" => nil + "@type" => "user", + "@href" => "/v3/user/#{user.id}", + "@permissions" => {"read"=>true, "sync"=>false}, + "id" => user.id, + "login" => "example-user", + "name" => nil, + "github_id" => nil, + "avatar_url" => nil, + "is_syncing" => nil, + "synced_at" => nil }} end end diff --git a/spec/v3/services/user/current_spec.rb b/spec/v3/services/user/current_spec.rb index 443671e6..88a1c920 100644 --- a/spec/v3/services/user/current_spec.rb +++ b/spec/v3/services/user/current_spec.rb @@ -10,15 +10,16 @@ describe Travis::API::V3::Services::User::Current do before { get("/v3/user", {}, headers) } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "user", - "@href" => "/v3/user/#{user.id}", - "id" => user.id, - "login" => "svenfuchs", - "name" =>"Sven Fuchs", - "github_id" => user.github_id, - "avatar_url" => "https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", - "is_syncing" => user.is_syncing, - "synced_at" => user.synced_at + "@type" => "user", + "@href" => "/v3/user/#{user.id}", + "@permissions" => {"read"=>true, "sync"=>true}, + "id" => user.id, + "login" => "svenfuchs", + "name" =>"Sven Fuchs", + "github_id" => user.github_id, + "avatar_url" => "https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", + "is_syncing" => user.is_syncing, + "synced_at" => user.synced_at }} end end \ No newline at end of file diff --git a/spec/v3/services/user/find_spec.rb b/spec/v3/services/user/find_spec.rb index 30ee4800..b493bc40 100644 --- a/spec/v3/services/user/find_spec.rb +++ b/spec/v3/services/user/find_spec.rb @@ -10,15 +10,16 @@ describe Travis::API::V3::Services::User::Find do before { get("/v3/user/#{user.id}", {}, headers) } example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { - "@type" => "user", - "@href" => "/v3/user/#{user.id}", - "id" => user.id, - "login" => "svenfuchs", - "name" =>"Sven Fuchs", - "github_id" => user.github_id, - "avatar_url" => "https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", - "is_syncing" => user.is_syncing, - "synced_at" => user.synced_at + "@type" => "user", + "@href" => "/v3/user/#{user.id}", + "@permissions" => {"read"=>true, "sync"=>true}, + "id" => user.id, + "login" => "svenfuchs", + "name" =>"Sven Fuchs", + "github_id" => user.github_id, + "avatar_url" => "https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", + "is_syncing" => user.is_syncing, + "synced_at" => user.synced_at }} end end \ No newline at end of file