Merge commit 'bddd9952a74d1eddad5d5a255419e07c836b286d' into addCron
Conflicts: spec/v3/services/owner/find_spec.rb spec/v3/services/repositories/for_current_user_spec.rb spec/v3/services/repositories/for_owner_spec.rb spec/v3/services/repository/find_spec.rb
This commit is contained in:
commit
e4aec173ee
1
Gemfile
1
Gemfile
|
@ -33,6 +33,7 @@ gem 'skylight', '~> 0.6.0.beta.1'
|
||||||
gem 'stackprof'
|
gem 'stackprof'
|
||||||
|
|
||||||
gem 'jemalloc'
|
gem 'jemalloc'
|
||||||
|
gem 'customerio'
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'rspec', '~> 2.13'
|
gem 'rspec', '~> 2.13'
|
||||||
|
|
32
Gemfile.lock
32
Gemfile.lock
|
@ -36,9 +36,9 @@ GIT
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/rtomayko/rack-cache.git
|
remote: git://github.com/rtomayko/rack-cache.git
|
||||||
revision: d00e6e491fcc7bdca9c27d735abde5c4fdb48cd9
|
revision: f96febebed7700337e8c362403b081e45b8e4f13
|
||||||
specs:
|
specs:
|
||||||
rack-cache (1.2)
|
rack-cache (1.5.1)
|
||||||
rack (>= 0.4)
|
rack (>= 0.4)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
|
@ -50,7 +50,7 @@ GIT
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: git://github.com/travis-ci/travis-core.git
|
remote: git://github.com/travis-ci/travis-core.git
|
||||||
revision: 21793fc8b01f965b93cf98b7ab1458ee359a5a62
|
revision: 3a9f6e4c14bb1eacb93609e1864c9c547a13c1a4
|
||||||
specs:
|
specs:
|
||||||
travis-core (0.0.1)
|
travis-core (0.0.1)
|
||||||
actionmailer (~> 3.2.19)
|
actionmailer (~> 3.2.19)
|
||||||
|
@ -137,7 +137,7 @@ GEM
|
||||||
activesupport (3.2.22)
|
activesupport (3.2.22)
|
||||||
i18n (~> 0.6, >= 0.6.4)
|
i18n (~> 0.6, >= 0.6.4)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
addressable (2.3.8)
|
addressable (2.4.0)
|
||||||
arel (3.0.3)
|
arel (3.0.3)
|
||||||
atomic (1.1.99)
|
atomic (1.1.99)
|
||||||
avl_tree (1.1.3)
|
avl_tree (1.1.3)
|
||||||
|
@ -145,7 +145,7 @@ GEM
|
||||||
descendants_tracker (~> 0.0.4)
|
descendants_tracker (~> 0.0.4)
|
||||||
ice_nine (~> 0.11.0)
|
ice_nine (~> 0.11.0)
|
||||||
thread_safe (~> 0.3, >= 0.3.1)
|
thread_safe (~> 0.3, >= 0.3.1)
|
||||||
backports (3.6.6)
|
backports (3.6.7)
|
||||||
builder (3.0.4)
|
builder (3.0.4)
|
||||||
bunny (0.8.0)
|
bunny (0.8.0)
|
||||||
celluloid (0.16.0)
|
celluloid (0.16.0)
|
||||||
|
@ -157,6 +157,9 @@ GEM
|
||||||
composite_primary_keys (5.0.14)
|
composite_primary_keys (5.0.14)
|
||||||
activerecord (~> 3.2.0, >= 3.2.9)
|
activerecord (~> 3.2.0, >= 3.2.9)
|
||||||
connection_pool (2.1.1)
|
connection_pool (2.1.1)
|
||||||
|
customerio (0.6.1)
|
||||||
|
httparty (>= 0.5, < 0.12)
|
||||||
|
multi_json (~> 1.0)
|
||||||
dalli (2.7.2)
|
dalli (2.7.2)
|
||||||
data_migrations (0.0.1)
|
data_migrations (0.0.1)
|
||||||
activerecord
|
activerecord
|
||||||
|
@ -171,7 +174,7 @@ GEM
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
factory_girl (2.4.2)
|
factory_girl (2.4.2)
|
||||||
activesupport
|
activesupport
|
||||||
faraday (0.9.1)
|
faraday (0.9.2)
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
ffi (1.9.6)
|
ffi (1.9.6)
|
||||||
foreman (0.64.0)
|
foreman (0.64.0)
|
||||||
|
@ -187,7 +190,10 @@ GEM
|
||||||
hashr (0.0.22)
|
hashr (0.0.22)
|
||||||
hike (1.2.3)
|
hike (1.2.3)
|
||||||
hitimes (1.2.3)
|
hitimes (1.2.3)
|
||||||
httpclient (2.6.0.1)
|
httparty (0.11.0)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
multi_xml (>= 0.5.2)
|
||||||
|
httpclient (2.7.0.1)
|
||||||
i18n (0.7.0)
|
i18n (0.7.0)
|
||||||
ice_nine (0.11.1)
|
ice_nine (0.11.1)
|
||||||
jemalloc (1.0.1)
|
jemalloc (1.0.1)
|
||||||
|
@ -215,6 +221,7 @@ GEM
|
||||||
mocha (0.14.0)
|
mocha (0.14.0)
|
||||||
metaclass (~> 0.0.1)
|
metaclass (~> 0.0.1)
|
||||||
multi_json (1.11.2)
|
multi_json (1.11.2)
|
||||||
|
multi_xml (0.5.5)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
net-http-persistent (2.9.4)
|
net-http-persistent (2.9.4)
|
||||||
net-http-pipeline (1.0.1)
|
net-http-pipeline (1.0.1)
|
||||||
|
@ -225,10 +232,11 @@ GEM
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
pusher (0.14.5)
|
pusher (0.14.6)
|
||||||
httpclient (~> 2.5)
|
httpclient (~> 2.5)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
signature (~> 0.1.8)
|
pusher-signature (~> 0.1.8)
|
||||||
|
pusher-signature (0.1.8)
|
||||||
rack (1.4.7)
|
rack (1.4.7)
|
||||||
rack-attack (4.2.0)
|
rack-attack (4.2.0)
|
||||||
rack
|
rack
|
||||||
|
@ -255,7 +263,7 @@ GEM
|
||||||
rdoc (3.12.2)
|
rdoc (3.12.2)
|
||||||
json (~> 1.4)
|
json (~> 1.4)
|
||||||
redcarpet (2.3.0)
|
redcarpet (2.3.0)
|
||||||
redis (3.2.1)
|
redis (3.2.2)
|
||||||
redis-namespace (1.5.1)
|
redis-namespace (1.5.1)
|
||||||
redis (~> 3.0, >= 3.0.4)
|
redis (~> 3.0, >= 3.0.4)
|
||||||
rerun (0.8.2)
|
rerun (0.8.2)
|
||||||
|
@ -275,7 +283,6 @@ GEM
|
||||||
json
|
json
|
||||||
redis (>= 3.0.6)
|
redis (>= 3.0.6)
|
||||||
redis-namespace (>= 1.3.1)
|
redis-namespace (>= 1.3.1)
|
||||||
signature (0.1.8)
|
|
||||||
simple_states (1.0.1)
|
simple_states (1.0.1)
|
||||||
activesupport
|
activesupport
|
||||||
hashr (~> 0.0.10)
|
hashr (~> 0.0.10)
|
||||||
|
@ -315,7 +322,7 @@ GEM
|
||||||
treetop (1.4.15)
|
treetop (1.4.15)
|
||||||
polyglot
|
polyglot
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
tzinfo (0.3.44)
|
tzinfo (0.3.46)
|
||||||
unicorn (4.8.3)
|
unicorn (4.8.3)
|
||||||
kgio (~> 2.6)
|
kgio (~> 2.6)
|
||||||
rack
|
rack
|
||||||
|
@ -335,6 +342,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_model_serializers
|
active_model_serializers
|
||||||
bunny (~> 0.8.0)
|
bunny (~> 0.8.0)
|
||||||
|
customerio
|
||||||
dalli
|
dalli
|
||||||
database_cleaner (~> 0.8.0)
|
database_cleaner (~> 0.8.0)
|
||||||
factory_girl (~> 2.4.0)
|
factory_girl (~> 2.4.0)
|
||||||
|
|
|
@ -17,7 +17,8 @@ This is the app running on https://api.travis-ci.org/
|
||||||
|
|
||||||
### Database setup
|
### Database setup
|
||||||
|
|
||||||
1. `rake db:create db:structure:load`
|
1. `rake db:create db:migrate`
|
||||||
|
2. for testing 'RAILS_ENV=test bundle exec rake db:create db:migrate --trace'
|
||||||
1. Clone `travis-logs` and copy the `logs` database (assume the PostgreSQL user is `postgres`):
|
1. Clone `travis-logs` and copy the `logs` database (assume the PostgreSQL user is `postgres`):
|
||||||
```sh-session
|
```sh-session
|
||||||
cd ..
|
cd ..
|
||||||
|
|
|
@ -2,6 +2,7 @@ require 'travis/api/app'
|
||||||
require 'addressable/uri'
|
require 'addressable/uri'
|
||||||
require 'faraday'
|
require 'faraday'
|
||||||
require 'securerandom'
|
require 'securerandom'
|
||||||
|
require 'customerio'
|
||||||
|
|
||||||
class Travis::Api::App
|
class Travis::Api::App
|
||||||
class Endpoint
|
class Endpoint
|
||||||
|
@ -78,6 +79,7 @@ class Travis::Api::App
|
||||||
#
|
#
|
||||||
# * **github_token**: GitHub token for checking authorization (required)
|
# * **github_token**: GitHub token for checking authorization (required)
|
||||||
post '/github' do
|
post '/github' do
|
||||||
|
check_agent
|
||||||
unless params[:github_token]
|
unless params[:github_token]
|
||||||
halt 422, { "error" => "Must pass 'github_token' parameter" }
|
halt 422, { "error" => "Must pass 'github_token' parameter" }
|
||||||
end
|
end
|
||||||
|
@ -94,6 +96,7 @@ class Travis::Api::App
|
||||||
# * **redirect_uri**: URI to redirect to after handshake.
|
# * **redirect_uri**: URI to redirect to after handshake.
|
||||||
get '/handshake' do
|
get '/handshake' do
|
||||||
handshake do |user, token, redirect_uri|
|
handshake do |user, token, redirect_uri|
|
||||||
|
|
||||||
if target_ok? redirect_uri
|
if target_ok? redirect_uri
|
||||||
content_type :html
|
content_type :html
|
||||||
data = { user: user, token: token, uri: redirect_uri }
|
data = { user: user, token: token, uri: redirect_uri }
|
||||||
|
@ -145,6 +148,43 @@ class Travis::Api::App
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def allowed_agents
|
||||||
|
@allowed_agents ||= redis.smembers('auth_agents')
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_agent
|
||||||
|
return if settings.test? or allowed_agents.empty?
|
||||||
|
return if allowed_agents.any? { |a| request.user_agent.to_s.start_with? a }
|
||||||
|
halt 403, "you are currently not allowed to perform this request. please contact support@travis-ci.com."
|
||||||
|
end
|
||||||
|
|
||||||
|
# update first login date if not set
|
||||||
|
def update_first_login(user)
|
||||||
|
unless user.first_logged_in_at
|
||||||
|
user.update_attributes(first_logged_in_at: Time.now)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_customerio(user)
|
||||||
|
return unless Travis.config.customerio.site_id
|
||||||
|
|
||||||
|
# send event to customer.io
|
||||||
|
payload = {
|
||||||
|
:id => user.id,
|
||||||
|
:name => user.name,
|
||||||
|
:login => user.login,
|
||||||
|
:email => primary_email_for_user(user.github_oauth_token),
|
||||||
|
:created_at => user.created_at.to_i,
|
||||||
|
:github_id => user.github_id,
|
||||||
|
:education => user.education,
|
||||||
|
:first_logged_in_at => user.first_logged_in_at.to_i
|
||||||
|
}
|
||||||
|
|
||||||
|
customerio.identify(payload)
|
||||||
|
rescue StandardError => e
|
||||||
|
Travis.logger.error "Could not update Customer.io for User: #{user.id}:#{user.login} with message:#{e.message}"
|
||||||
|
end
|
||||||
|
|
||||||
def serialize_user(user)
|
def serialize_user(user)
|
||||||
rendered = Travis::Api.data(user, version: :v2)
|
rendered = Travis::Api.data(user, version: :v2)
|
||||||
rendered['user'].merge('token' => user.tokens.first.try(:token).to_s)
|
rendered['user'].merge('token' => user.tokens.first.try(:token).to_s)
|
||||||
|
@ -174,6 +214,8 @@ class Travis::Api::App
|
||||||
user = user_for_github_token(github_token)
|
user = user_for_github_token(github_token)
|
||||||
token = generate_token(user: user, app_id: 0)
|
token = generate_token(user: user, app_id: 0)
|
||||||
payload = params[:state].split(":::", 2)[1]
|
payload = params[:state].split(":::", 2)[1]
|
||||||
|
update_first_login(user)
|
||||||
|
update_customerio(user)
|
||||||
yield serialize_user(user), token, payload
|
yield serialize_user(user), token, payload
|
||||||
else
|
else
|
||||||
values[:state] = create_state
|
values[:state] = create_state
|
||||||
|
@ -183,6 +225,7 @@ class Travis::Api::App
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def create_state
|
def create_state
|
||||||
state = SecureRandom.urlsafe_base64(16)
|
state = SecureRandom.urlsafe_base64(16)
|
||||||
redis.sadd('github:states', state)
|
redis.sadd('github:states', state)
|
||||||
|
@ -212,6 +255,7 @@ class Travis::Api::App
|
||||||
super
|
super
|
||||||
|
|
||||||
@user = ::User.find_by_github_id(data['id'])
|
@user = ::User.find_by_github_id(data['id'])
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def info(attributes = {})
|
def info(attributes = {})
|
||||||
|
@ -342,6 +386,15 @@ class Travis::Api::App
|
||||||
def allowed_https_targets
|
def allowed_https_targets
|
||||||
@allowed_https_targets ||= Travis.config.auth.target_origin.to_s.split(',')
|
@allowed_https_targets ||= Travis.config.auth.target_origin.to_s.split(',')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def primary_email_for_user(oauth_token)
|
||||||
|
# check for the users primary email address (we don't store this info)
|
||||||
|
GH.with(token: oauth_token, client_id: nil) { GH['user/emails'] }.select { |e| e['primary'] }.first['email']
|
||||||
|
end
|
||||||
|
|
||||||
|
def customerio
|
||||||
|
Customerio::Client.new(Travis.config.customerio.site_id, Travis.config.customerio.api_key, :json => true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,6 +53,8 @@ class Travis::Api::App
|
||||||
if params
|
if params
|
||||||
params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten]
|
params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten]
|
||||||
quality = params.delete('q').to_f if params['q']
|
quality = params.delete('q').to_f if params['q']
|
||||||
|
else
|
||||||
|
params = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
if subtype =~ HEADER_FORMAT
|
if subtype =~ HEADER_FORMAT
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Travis::Api::App
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_travis(agent)
|
def mark_travis(agent)
|
||||||
command = agent.application.comment.detect { |c| c.start_with? "command " }
|
command = agent.application.comment.detect { |c| c.start_with? "command " } if agent.application.comment
|
||||||
|
|
||||||
if command
|
if command
|
||||||
mark(:cli, :version, agent.version)
|
mark(:cli, :version, agent.version)
|
||||||
|
|
|
@ -31,6 +31,12 @@ class Rack::Attack
|
||||||
"/auth/post_message/iframe"
|
"/auth/post_message/iframe"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
####
|
||||||
|
# Whitelisted IP addresses
|
||||||
|
whitelist('whitelist client requesting from redis') do |request|
|
||||||
|
Travis.redis.sismember(:api_whitelisted_ips, request.ip)
|
||||||
|
end
|
||||||
|
|
||||||
####
|
####
|
||||||
# Ban based on: IP address
|
# Ban based on: IP address
|
||||||
# Ban time: indefinite
|
# Ban time: indefinite
|
||||||
|
@ -44,7 +50,7 @@ class Rack::Attack
|
||||||
# Ban time: 5 hours
|
# Ban time: 5 hours
|
||||||
# Ban after: 10 POST requests within five minutes to /auth/github
|
# Ban after: 10 POST requests within five minutes to /auth/github
|
||||||
blacklist('hammering /auth/github') do |request|
|
blacklist('hammering /auth/github') do |request|
|
||||||
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 10, findtime: 5.minutes, bantime: bantime(5.hours)) do
|
Rack::Attack::Allow2Ban.filter(request.identifier, maxretry: 2, findtime: 5.minutes, bantime: bantime(5.hours)) do
|
||||||
request.post? and request.path == '/auth/github'
|
request.post? and request.path == '/auth/github'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -59,6 +65,14 @@ class Rack::Attack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# Throttle: unauthenticated requests to /auth/github - 1 per minute
|
||||||
|
# Scoped by: IP address
|
||||||
|
throttle('req/ip/1min', limit: 1, period: 1.minute) do |request|
|
||||||
|
request.ip unless request.authenticated? and request.path == '/auth/github'
|
||||||
|
end
|
||||||
|
|
||||||
###
|
###
|
||||||
# Throttle: unauthenticated requests - 500 per minute
|
# Throttle: unauthenticated requests - 500 per minute
|
||||||
# Scoped by: IP address
|
# Scoped by: IP address
|
||||||
|
|
|
@ -6,6 +6,7 @@ module Travis::API::V3
|
||||||
has_many :builds, dependent: :delete_all, order: 'builds.id DESC'.freeze
|
has_many :builds, dependent: :delete_all, order: 'builds.id DESC'.freeze
|
||||||
has_many :permissions, dependent: :delete_all
|
has_many :permissions, dependent: :delete_all
|
||||||
has_many :users, through: :permissions
|
has_many :users, through: :permissions
|
||||||
|
has_many :stars
|
||||||
|
|
||||||
belongs_to :owner, polymorphic: true
|
belongs_to :owner, polymorphic: true
|
||||||
belongs_to :last_build, class_name: 'Travis::API::V3::Models::Build'.freeze
|
belongs_to :last_build, class_name: 'Travis::API::V3::Models::Build'.freeze
|
||||||
|
@ -49,5 +50,17 @@ module Travis::API::V3
|
||||||
rescue ActiveRecord::RecordNotUnique
|
rescue ActiveRecord::RecordNotUnique
|
||||||
branches.where(name: name).first
|
branches.where(name: name).first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def id_default_branch
|
||||||
|
[id, default_branch_name]
|
||||||
|
end
|
||||||
|
|
||||||
|
def send(name, *args, &block)
|
||||||
|
if name == [:id, :default_branch]
|
||||||
|
name = :id_default_branch
|
||||||
|
end
|
||||||
|
|
||||||
|
__send__(name, *args, &block)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
6
lib/travis/api/v3/models/star.rb
Normal file
6
lib/travis/api/v3/models/star.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Models::Star < Model
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :repository
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ module Travis::API::V3
|
||||||
has_many :tokens, dependent: :destroy
|
has_many :tokens, dependent: :destroy
|
||||||
has_many :organizations, through: :memberships
|
has_many :organizations, through: :memberships
|
||||||
has_many :repositories, as: :owner
|
has_many :repositories, as: :owner
|
||||||
|
has_many :stars
|
||||||
has_one :subscription, as: :owner
|
has_one :subscription, as: :owner
|
||||||
|
|
||||||
serialize :github_oauth_token, Extensions::EncryptedColumn.new(disable: true)
|
serialize :github_oauth_token, Extensions::EncryptedColumn.new(disable: true)
|
||||||
|
@ -17,5 +18,9 @@ module Travis::API::V3
|
||||||
def subscription
|
def subscription
|
||||||
super if Features.use_subscriptions?
|
super if Features.use_subscriptions?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def starred_repository_ids
|
||||||
|
@starred_repository_ids ||= stars.map(&:repository_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,14 @@ module Travis::API::V3
|
||||||
write?
|
write?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def star?
|
||||||
|
write?
|
||||||
|
end
|
||||||
|
|
||||||
|
def unstar?
|
||||||
|
write?
|
||||||
|
end
|
||||||
|
|
||||||
def create_request?
|
def create_request?
|
||||||
write?
|
write?
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Queries::Repositories < Query
|
class Queries::Repositories < Query
|
||||||
params :active, :private, prefix: :repository
|
params :active, :private, :starred, prefix: :repository
|
||||||
sortable_by :id, :github_id, :owner_name, :name, active: sort_condition(:active)
|
sortable_by :id, :github_id, :owner_name, :name, active: sort_condition(:active)
|
||||||
|
|
||||||
def for_member(user)
|
def for_member(user, **options)
|
||||||
all.joins(:users).where(users: user_condition(user), invalidated_at: nil)
|
all(user: user, **options).joins(:users).where(users: user_condition(user), invalidated_at: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def for_owner(owner)
|
def for_owner(owner, **options)
|
||||||
filter(owner.repositories)
|
filter(owner.repositories, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def all
|
def all(**options)
|
||||||
@all ||= filter(Models::Repository)
|
filter(Models::Repository, **options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(list)
|
def filter(list, user: nil)
|
||||||
list = list.where(invalidated_at: nil)
|
list = list.where(invalidated_at: nil)
|
||||||
list = list.where(active: bool(active)) unless active.nil?
|
list = list.where(active: bool(active)) unless active.nil?
|
||||||
list = list.where(private: bool(private)) unless private.nil?
|
list = list.where(private: bool(private)) unless private.nil?
|
||||||
list = list.includes(:owner) if includes? 'repository.owner'.freeze
|
list = list.includes(:owner) if includes? 'repository.owner'.freeze
|
||||||
|
|
||||||
|
if user and not starred.nil?
|
||||||
|
if bool(starred)
|
||||||
|
list = list.joins(:stars).where(stars: { user_id: user.id })
|
||||||
|
elsif user.starred_repository_ids.any?
|
||||||
|
list = list.where("repositories.id NOT IN (?)", user.starred_repository_ids)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if includes? 'repository.last_build'.freeze or includes? 'build'.freeze
|
if includes? 'repository.last_build'.freeze or includes? 'build'.freeze
|
||||||
list = list.includes(:last_build)
|
list = list.includes(:last_build)
|
||||||
list = list.includes(last_build: :commit) if includes? 'build.commit'.freeze
|
list = list.includes(last_build: :commit) if includes? 'build.commit'.freeze
|
||||||
|
|
|
@ -3,13 +3,31 @@ module Travis::API::V3
|
||||||
params :id, :slug
|
params :id, :slug
|
||||||
|
|
||||||
def find
|
def find
|
||||||
|
@find ||= find!
|
||||||
|
end
|
||||||
|
|
||||||
|
def star(current_user)
|
||||||
|
repository = find
|
||||||
|
starred = Models::Star.where(repository_id: repository.id, user_id: current_user.id).first
|
||||||
|
Models::Star.create(repository_id: repository.id, user_id: current_user.id) unless starred
|
||||||
|
repository
|
||||||
|
end
|
||||||
|
|
||||||
|
def unstar(current_user)
|
||||||
|
repository = find
|
||||||
|
starred = Models::Star.where(repository_id: repository.id, user_id: current_user.id).first
|
||||||
|
starred.delete if starred
|
||||||
|
repository
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find!
|
||||||
return by_slug if slug
|
return by_slug if slug
|
||||||
return Models::Repository.find_by_id(id) if id
|
return Models::Repository.find_by_id(id) if id
|
||||||
raise WrongParams, 'missing repository.id'.freeze
|
raise WrongParams, 'missing repository.id'.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def by_slug
|
def by_slug
|
||||||
owner_name, name = slug.split('/')
|
owner_name, name = slug.split('/')
|
||||||
Models::Repository.where(owner_name: owner_name, name: name, invalidated_at: nil).first
|
Models::Repository.where(owner_name: owner_name, name: name, invalidated_at: nil).first
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'travis/api/v3/renderer/model_renderer'
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Renderer::Repository < Renderer::ModelRenderer
|
class Renderer::Repository < Renderer::ModelRenderer
|
||||||
representation(:minimal, :id, :name, :slug)
|
representation(:minimal, :id, :name, :slug)
|
||||||
representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :owner, :default_branch)
|
representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :owner, :default_branch, :starred)
|
||||||
|
|
||||||
def active
|
def active
|
||||||
!!model.active
|
!!model.active
|
||||||
|
@ -19,6 +19,11 @@ module Travis::API::V3
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def starred
|
||||||
|
return false unless user = access_control.user
|
||||||
|
user.starred_repository_ids.include? id
|
||||||
|
end
|
||||||
|
|
||||||
def include_default_branch?
|
def include_default_branch?
|
||||||
return true if include? 'repository.default_branch'.freeze
|
return true if include? 'repository.default_branch'.freeze
|
||||||
return true if include.any? { |i| i.start_with? 'branch'.freeze }
|
return true if include.any? { |i| i.start_with? 'branch'.freeze }
|
||||||
|
|
|
@ -78,6 +78,8 @@ module Travis::API::V3
|
||||||
|
|
||||||
post :enable, '/enable'
|
post :enable, '/enable'
|
||||||
post :disable, '/disable'
|
post :disable, '/disable'
|
||||||
|
post :star, '/star'
|
||||||
|
post :unstar, '/unstar'
|
||||||
|
|
||||||
resource :branch do
|
resource :branch do
|
||||||
route '/branch/{branch.name}'
|
route '/branch/{branch.name}'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Services::Repositories::ForCurrentUser < Service
|
class Services::Repositories::ForCurrentUser < Service
|
||||||
params :active, :private, prefix: :repository
|
params :active, :private, :starred, prefix: :repository
|
||||||
paginate(default_limit: 100)
|
paginate(default_limit: 100)
|
||||||
|
|
||||||
def run!
|
def run!
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Services::Repositories::ForOwner < Service
|
class Services::Repositories::ForOwner < Service
|
||||||
params :active, :private, prefix: :repository
|
params :active, :private, :starred, prefix: :repository
|
||||||
paginate(default_limit: 100)
|
paginate(default_limit: 100)
|
||||||
|
|
||||||
def run!
|
def run!
|
||||||
unfiltered = query.for_owner(find(:owner))
|
unfiltered = query.for_owner(find(:owner), user: access_control.user)
|
||||||
access_control.visible_repositories(unfiltered)
|
access_control.visible_repositories(unfiltered)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
15
lib/travis/api/v3/services/repository/star.rb
Normal file
15
lib/travis/api/v3/services/repository/star.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Services::Repository::Star < Service
|
||||||
|
def run!
|
||||||
|
raise LoginRequired unless access_control.logged_in? or access_control.full_access?
|
||||||
|
raise NotFound unless repository = find(:repository)
|
||||||
|
check_access(repository)
|
||||||
|
current_user = access_control.user
|
||||||
|
query.star(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_access(repository)
|
||||||
|
access_control.permissions(repository).star!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
lib/travis/api/v3/services/repository/unstar.rb
Normal file
15
lib/travis/api/v3/services/repository/unstar.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Services::Repository::Unstar < Service
|
||||||
|
def run!
|
||||||
|
raise LoginRequired unless access_control.logged_in? or access_control.full_access?
|
||||||
|
raise NotFound unless repository = find(:repository)
|
||||||
|
check_access(repository)
|
||||||
|
current_user = access_control.user
|
||||||
|
query.unstar(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_access(repository)
|
||||||
|
access_control.permissions(repository).unstar!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -64,7 +64,7 @@ describe Travis::API::V3::ServiceIndex do
|
||||||
|
|
||||||
describe "for_current_user action" do
|
describe "for_current_user action" do
|
||||||
let(:action) { resource.fetch("actions").fetch("for_current_user") }
|
let(:action) { resource.fetch("actions").fetch("for_current_user") }
|
||||||
specify { expect(action).to include("@type"=>"template", "request_method"=>"GET", "uri_template"=>"#{path}repos{?active,include,limit,offset,private,repository.active,repository.private,sort_by}") }
|
specify { expect(action).to include("@type"=>"template", "request_method"=>"GET", "uri_template"=>"#{path}repos{?active,include,limit,offset,private,repository.active,repository.private,repository.starred,sort_by,starred}") }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,10 @@ describe Travis::API::V3::Services::Owner::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => false,
|
"enable" => false,
|
||||||
"disable" => false,
|
"disable" => false,
|
||||||
|
"star" => false,
|
||||||
|
"unstar" => false,
|
||||||
"create_request" => false,
|
"create_request" => false,
|
||||||
"create_cron" => false },
|
"create_cron" => false},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "example-repo",
|
"name" => "example-repo",
|
||||||
"slug" => "example-org/example-repo",
|
"slug" => "example-org/example-repo",
|
||||||
|
@ -78,7 +80,8 @@ describe Travis::API::V3::Services::Owner::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}]
|
}]
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
@ -109,8 +112,10 @@ describe Travis::API::V3::Services::Owner::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => false,
|
"enable" => false,
|
||||||
"disable" => false,
|
"disable" => false,
|
||||||
|
"star" => false,
|
||||||
|
"unstar" => false,
|
||||||
"create_request"=> false,
|
"create_request"=> false,
|
||||||
"create_cron" => false },
|
"create_cron" => false},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "example-repo",
|
"name" => "example-repo",
|
||||||
"slug" => "example-org/example-repo",
|
"slug" => "example-org/example-repo",
|
||||||
|
@ -123,7 +128,8 @@ describe Travis::API::V3::Services::Owner::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation"=> "minimal",
|
"@representation"=> "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}]
|
}]
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Travis::API::V3::Services::Repositories::ForCurrentUser do
|
describe Travis::API::V3::Services::Repositories::ForCurrentUser do
|
||||||
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
||||||
let(:build) { repo.builds.first }
|
let(:build) { repo.builds.first }
|
||||||
let(:jobs) { Travis::API::V3::Models::Build.find(build.id).jobs }
|
let(:jobs) { Travis::API::V3::Models::Build.find(build.id).jobs }
|
||||||
|
|
||||||
|
@ -42,8 +42,10 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => true,
|
"enable" => true,
|
||||||
"disable" => true,
|
"disable" => true,
|
||||||
|
"star" => true,
|
||||||
|
"unstar" => true,
|
||||||
"create_request" => true,
|
"create_request" => true,
|
||||||
"create_cron" => true },
|
"create_cron" => true},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -60,7 +62,9 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}}]
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
|
}]
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,4 +86,29 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
|
||||||
example { expect(last_response) .to be_ok }
|
example { expect(last_response) .to be_ok }
|
||||||
example { expect(JSON.load(body)['repositories']) .to be == [] }
|
example { expect(JSON.load(body)['repositories']) .to be == [] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=true" do
|
||||||
|
before { Travis::API::V3::Models::Star.create(user: repo.owner, repository: repo) }
|
||||||
|
before { get("/v3/repos", {"starred" => "true"}, headers) }
|
||||||
|
after { repo.owner.stars.each(&:destroy) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=true" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .not_to be_empty }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=false" do
|
||||||
|
before { get("/v3/repos", {"starred" => "false"}, headers) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=false" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .not_to be_empty }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=false but no unstarred repos" do
|
||||||
|
before { Travis::API::V3::Models::Star.create(user: repo.owner, repository: repo) }
|
||||||
|
after { repo.owner.stars.each(&:destroy) }
|
||||||
|
before { get("/v3/repos", {"starred" => "false"}, headers) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=false" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .to be_empty }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,8 +42,10 @@ describe Travis::API::V3::Services::Repositories::ForOwner do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => false,
|
"enable" => false,
|
||||||
"disable" => false,
|
"disable" => false,
|
||||||
|
"star" => false,
|
||||||
|
"unstar" => false,
|
||||||
"create_request" => false,
|
"create_request" => false,
|
||||||
"create_cron" => false },
|
"create_cron" => false},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -60,7 +62,9 @@ describe Travis::API::V3::Services::Repositories::ForOwner do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}}]}}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
|
}]}}
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "filter: private=false" do
|
describe "filter: private=false" do
|
||||||
|
@ -75,4 +79,29 @@ describe Travis::API::V3::Services::Repositories::ForOwner do
|
||||||
example { expect(last_response) .to be_ok }
|
example { expect(last_response) .to be_ok }
|
||||||
example { expect(JSON.load(body)['repositories']) .to be == [] }
|
example { expect(JSON.load(body)['repositories']) .to be == [] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=true" do
|
||||||
|
before { Travis::API::V3::Models::Star.create(user: repo.owner, repository: repo) }
|
||||||
|
before { get("/v3/repos", {"starred" => "true"}, headers) }
|
||||||
|
after { repo.owner.stars.each(&:destroy) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=true" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .not_to be_empty }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=false" do
|
||||||
|
before { get("/v3/repos", {"starred" => "false"}, headers) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=false" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .not_to be_empty }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "filter: starred=false but no unstarred repos" do
|
||||||
|
before { Travis::API::V3::Models::Star.create(user: repo.owner, repository: repo) }
|
||||||
|
after { repo.owner.stars.each(&:destroy) }
|
||||||
|
before { get("/v3/repos", {"starred" => "false"}, headers) }
|
||||||
|
example { expect(last_response) .to be_ok }
|
||||||
|
example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?starred=false" }
|
||||||
|
example { expect(JSON.load(body)['repositories']) .to be_empty }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
72
spec/v3/services/repository/disable_spec.rb
Normal file
72
spec/v3/services/repository/disable_spec.rb
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Travis::API::V3::Services::Repository::Disable do
|
||||||
|
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
||||||
|
|
||||||
|
before do
|
||||||
|
repo.update_attributes!(active: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "not authenticated" do
|
||||||
|
before { post("/v3/repo/#{repo.id}/disable") }
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "login_required",
|
||||||
|
"error_message" => "login required"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "missing repo, authenticated" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/9999999999/disable", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, no push access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/#{repo.id}/disable", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body).to_s).to include(
|
||||||
|
"@type",
|
||||||
|
"error_type",
|
||||||
|
"insufficient_access",
|
||||||
|
"error_message",
|
||||||
|
"operation requires disable access to repository",
|
||||||
|
"resource_type",
|
||||||
|
"repository",
|
||||||
|
"permission",
|
||||||
|
"disable")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "private repository, no access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { repo.update_attribute(:private, true) }
|
||||||
|
before { post("/v3/repo/#{repo.id}/disable", {}, headers) }
|
||||||
|
after { repo.update_attribute(:private, false) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, push access"
|
||||||
|
# as this reqires a call to github, and stubbing this request has proven difficult,
|
||||||
|
# this test has been omitted for now
|
||||||
|
end
|
72
spec/v3/services/repository/enable_spec.rb
Normal file
72
spec/v3/services/repository/enable_spec.rb
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Travis::API::V3::Services::Repository::Enable do
|
||||||
|
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
||||||
|
|
||||||
|
before do
|
||||||
|
repo.update_attributes!(active: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "not authenticated" do
|
||||||
|
before { post("/v3/repo/#{repo.id}/enable") }
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "login_required",
|
||||||
|
"error_message" => "login required"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "missing repo, authenticated" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/9999999999/enable", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, no push access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/#{repo.id}/enable", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body).to_s).to include(
|
||||||
|
"@type",
|
||||||
|
"error_type",
|
||||||
|
"insufficient_access",
|
||||||
|
"error_message",
|
||||||
|
"operation requires enable access to repository",
|
||||||
|
"resource_type",
|
||||||
|
"repository",
|
||||||
|
"permission",
|
||||||
|
"enable")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "private repository, no access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { repo.update_attribute(:private, true) }
|
||||||
|
before { post("/v3/repo/#{repo.id}/enable", {}, headers) }
|
||||||
|
after { repo.update_attribute(:private, false) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, push access"
|
||||||
|
# as this reqires a call to github, and stubbing this request has proven difficult,
|
||||||
|
# this test has been omitted for now
|
||||||
|
end
|
|
@ -34,8 +34,10 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => false,
|
"enable" => false,
|
||||||
"disable" => false,
|
"disable" => false,
|
||||||
|
"star" => false,
|
||||||
|
"unstar" => false,
|
||||||
"create_request" => false,
|
"create_request" => false,
|
||||||
"create_cron" => false },
|
"create_cron" => false},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -52,7 +54,8 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -109,8 +112,10 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => false,
|
"enable" => false,
|
||||||
"disable" => false,
|
"disable" => false,
|
||||||
|
"star" => false,
|
||||||
|
"unstar" => false,
|
||||||
"create_request" => false,
|
"create_request" => false,
|
||||||
"create_cron" => false },
|
"create_cron" => false},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -127,7 +132,8 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -169,8 +175,10 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => true,
|
"enable" => true,
|
||||||
"disable" => true,
|
"disable" => true,
|
||||||
|
"star" => true,
|
||||||
|
"unstar" => true,
|
||||||
"create_request" => true,
|
"create_request" => true,
|
||||||
"create_cron" => true },
|
"create_cron" => true},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -187,7 +195,8 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -235,8 +244,10 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"read" => true,
|
"read" => true,
|
||||||
"enable" => true,
|
"enable" => true,
|
||||||
"disable" => true,
|
"disable" => true,
|
||||||
|
"star" => true,
|
||||||
|
"unstar" => true,
|
||||||
"create_request" => true,
|
"create_request" => true,
|
||||||
"create_cron" => true },
|
"create_cron" => true},
|
||||||
"id" => repo.id,
|
"id" => repo.id,
|
||||||
"name" => "minimal",
|
"name" => "minimal",
|
||||||
"slug" => "svenfuchs/minimal",
|
"slug" => "svenfuchs/minimal",
|
||||||
|
@ -253,7 +264,8 @@ describe Travis::API::V3::Services::Repository::Find do
|
||||||
"@type" => "branch",
|
"@type" => "branch",
|
||||||
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
"@href" => "/v3/repo/#{repo.id}/branch/master",
|
||||||
"@representation" => "minimal",
|
"@representation" => "minimal",
|
||||||
"name" => "master"}
|
"name" => "master"},
|
||||||
|
"starred" => false
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
68
spec/v3/services/repository/star_spec.rb
Normal file
68
spec/v3/services/repository/star_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Travis::API::V3::Services::Repository::Star do
|
||||||
|
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
||||||
|
|
||||||
|
describe "not authenticated" do
|
||||||
|
before { post("/v3/repo/#{repo.id}/star") }
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "login_required",
|
||||||
|
"error_message" => "login required"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "missing repo, authenticated" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/9999999999/star", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, no push access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/#{repo.id}/star", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body).to_s).to include(
|
||||||
|
"@type",
|
||||||
|
"error_type",
|
||||||
|
"insufficient_access",
|
||||||
|
"error_message",
|
||||||
|
"operation requires star access to repository",
|
||||||
|
"resource_type",
|
||||||
|
"repository",
|
||||||
|
"permission",
|
||||||
|
"star")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "private repository, no access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { repo.update_attribute(:private, true) }
|
||||||
|
before { post("/v3/repo/#{repo.id}/star", {}, headers) }
|
||||||
|
after { repo.update_attribute(:private, false) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, push access"
|
||||||
|
# this requires stubing a github request, which is difficult, so has been omitted for now
|
||||||
|
|
||||||
|
end
|
68
spec/v3/services/repository/unstar_spec.rb
Normal file
68
spec/v3/services/repository/unstar_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Travis::API::V3::Services::Repository::Unstar do
|
||||||
|
let(:repo) { Travis::API::V3::Models::Repository.where(owner_name: 'svenfuchs', name: 'minimal').first }
|
||||||
|
|
||||||
|
describe "not authenticated" do
|
||||||
|
before { post("/v3/repo/#{repo.id}/unstar") }
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "login_required",
|
||||||
|
"error_message" => "login required"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "missing repo, authenticated" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/9999999999/unstar", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, no push access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { post("/v3/repo/#{repo.id}/unstar", {}, headers) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 403 }
|
||||||
|
example { expect(JSON.load(body).to_s).to include(
|
||||||
|
"@type",
|
||||||
|
"error_type",
|
||||||
|
"insufficient_access",
|
||||||
|
"error_message",
|
||||||
|
"operation requires unstar access to repository",
|
||||||
|
"resource_type",
|
||||||
|
"repository",
|
||||||
|
"permission",
|
||||||
|
"unstar")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "private repository, no access" do
|
||||||
|
let(:token) { Travis::Api::App::AccessToken.create(user: repo.owner, app_id: 1) }
|
||||||
|
let(:headers) {{ 'HTTP_AUTHORIZATION' => "token #{token}" }}
|
||||||
|
before { repo.update_attribute(:private, true) }
|
||||||
|
before { post("/v3/repo/#{repo.id}/unstar", {}, headers) }
|
||||||
|
after { repo.update_attribute(:private, false) }
|
||||||
|
|
||||||
|
example { expect(last_response.status).to be == 404 }
|
||||||
|
example { expect(JSON.load(body)).to be == {
|
||||||
|
"@type" => "error",
|
||||||
|
"error_type" => "not_found",
|
||||||
|
"error_message" => "repository not found (or insufficient access)",
|
||||||
|
"resource_type" => "repository"
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "existing repository, push access"
|
||||||
|
# this requires stubing a github request, which is difficult, so has been omitted for now
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user