From bff7f76c33688f192c8519047604b1d007271f03 Mon Sep 17 00:00:00 2001
From: Piotr Sarnacki <drogus@gmail.com>
Date: Thu, 21 May 2015 12:15:50 +0200
Subject: [PATCH] v3: Implement fetching repository by slug

---
 lib/travis/api/app.rb                         |  1 -
 lib/travis/api/v3/queries/repository.rb       | 10 +++++++++-
 lib/travis/api/v3/routes.rb                   |  3 ++-
 lib/travis/api/v3/routes/dsl.rb               |  4 ++--
 spec/v3/service_index_spec.rb                 |  4 ++--
 .../repositories/for_current_user_spec.rb     |  2 +-
 spec/v3/services/repository/find_spec.rb      | 19 ++++++++++++++++++-
 7 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/lib/travis/api/app.rb b/lib/travis/api/app.rb
index fb841547..b6f37690 100644
--- a/lib/travis/api/app.rb
+++ b/lib/travis/api/app.rb
@@ -108,7 +108,6 @@ module Travis::Api
 
         use Travis::Api::App::Cors # if Travis.env == 'development' ???
         use Raven::Rack if Travis.env == 'production' || Travis.env == 'staging'
-        use Rack::Protection::PathTraversal
         use Rack::SSL if Endpoint.production?
         use ActiveRecord::ConnectionAdapters::ConnectionManagement
         use ActiveRecord::QueryCache
diff --git a/lib/travis/api/v3/queries/repository.rb b/lib/travis/api/v3/queries/repository.rb
index d8ceaff9..dfc9ed99 100644
--- a/lib/travis/api/v3/queries/repository.rb
+++ b/lib/travis/api/v3/queries/repository.rb
@@ -1,10 +1,18 @@
 module Travis::API::V3
   class Queries::Repository < Query
-    params :id
+    params :id, :slug
 
     def find
+      return by_slug if slug
       return Models::Repository.find_by_id(id) if id
       raise WrongParams, 'missing repository.id'.freeze
     end
+
+    private
+
+    def by_slug
+      owner_name, name = slug.split('/')
+      Models::Repository.where(owner_name: owner_name, name: name).first
+    end
   end
 end
diff --git a/lib/travis/api/v3/routes.rb b/lib/travis/api/v3/routes.rb
index 66c13dde..81305aab 100644
--- a/lib/travis/api/v3/routes.rb
+++ b/lib/travis/api/v3/routes.rb
@@ -15,7 +15,8 @@ module Travis::API::V3
     end
 
     resource :repository do
-      route '/repo/{repository.id}'
+      route '/repo/({repository.id}|{repository.slug})',
+            capture: { :"repository.id" => :digit }
       get :find
 
       post :enable,  '/enable'
diff --git a/lib/travis/api/v3/routes/dsl.rb b/lib/travis/api/v3/routes/dsl.rb
index fbd71c8f..e32a97ff 100644
--- a/lib/travis/api/v3/routes/dsl.rb
+++ b/lib/travis/api/v3/routes/dsl.rb
@@ -33,8 +33,8 @@ module Travis::API::V3
       @current_resource = resource_was
     end
 
-    def route(value)
-      current_resource.route = Mustermann.new(prefix) + Mustermann.new(value)
+    def route(value, options = {})
+      current_resource.route = Mustermann.new(prefix) + Mustermann.new(value, options)
     end
 
     def get(*args)
diff --git a/spec/v3/service_index_spec.rb b/spec/v3/service_index_spec.rb
index bf49e614..855c0861 100644
--- a/spec/v3/service_index_spec.rb
+++ b/spec/v3/service_index_spec.rb
@@ -151,12 +151,12 @@ describe Travis::API::V3::ServiceIndex do
     describe 'with /v3 prefix' do
       let(:headers) { { 'HTTP_ACCEPT' => 'application/json-home' } }
       let(:path) { '/v3/' }
-      specify(:resources) { expect(json['resources']).to include("http://schema.travis-ci.com/rel/repository/find") }
+      specify(:resources) { expect(json['resources']).to include("http://schema.travis-ci.com/rel/repository/find/by_repository.id") }
     end
 
     describe 'with Travis-API-Version header' do
       let(:headers) { { 'HTTP_ACCEPT' => 'application/json-home', 'HTTP_TRAVIS_API_VERSION' => '3' } }
-      specify(:resources) { expect(json['resources']).to include("http://schema.travis-ci.com/rel/repository/find") }
+      specify(:resources) { expect(json['resources']).to include("http://schema.travis-ci.com/rel/repository/find/by_repository.id") }
     end
   end
 end
diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb
index 785c3c7c..5049de5f 100644
--- a/spec/v3/services/repositories/for_current_user_spec.rb
+++ b/spec/v3/services/repositories/for_current_user_spec.rb
@@ -74,4 +74,4 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do
     example { expect(last_response)                   .to be_ok            }
     example { expect(JSON.load(body)['repositories']) .to be == []         }
   end
-end
\ No newline at end of file
+end
diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb
index a6e64c9f..994c10c9 100644
--- a/spec/v3/services/repository/find_spec.rb
+++ b/spec/v3/services/repository/find_spec.rb
@@ -4,6 +4,23 @@ describe Travis::API::V3::Services::Repository::Find do
   let(:repo) { Repository.by_slug('svenfuchs/minimal').first }
   let(:parsed_body) { JSON.load(body) }
 
+  describe "fetching a public repository by slug" do
+    before     { get("/v3/repo/svenfuchs%2Fminimal")     }
+    example    { expect(last_response).to be_ok }
+    example    { expect(parsed_body['slug']).to be == 'svenfuchs/minimal' }
+  end
+
+  describe "fetching a non-existing repository by slug" do
+    before     { get("/v3/repo/svenfuchs%2Fminimal1")     }
+    example { expect(last_response).to be_not_found }
+    example { expect(parsed_body).to be == {
+      "@type"         => "error",
+      "error_type"    => "not_found",
+      "error_message" => "repository not found (or insufficient access)",
+      "resource_type" => "repository"
+    }}
+  end
+
   describe "public repository" do
     before     { get("/v3/repo/#{repo.id}")     }
     example    { expect(last_response).to be_ok }
@@ -349,4 +366,4 @@ describe Travis::API::V3::Services::Repository::Find do
     example { expect(last_response).to be_ok }
     example { expect(parsed_body).to include("last_build") }
   end
-end
\ No newline at end of file
+end