summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock17
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/models/user.rb3
-rw-r--r--config/gitlab.yml.example8
-rw-r--r--config/initializers/00_before_all.rb1
-rw-r--r--config/initializers/grack_auth.rb46
-rw-r--r--config/routes.rb56
-rw-r--r--lib/api.rb61
-rw-r--r--lib/api/entities.rb23
-rw-r--r--lib/api/helpers.rb11
-rw-r--r--spec/api/projects_spec.rb55
-rw-r--r--spec/api/users_spec.rb38
-rw-r--r--spec/spec_helper.rb4
14 files changed, 303 insertions, 24 deletions
diff --git a/Gemfile b/Gemfile
index 4c977dde0a9..530f06b159d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,8 +15,10 @@ gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git",
gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188"
gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44"
gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"
+gem 'grack', :git => "https://github.com/gitlabhq/grack.git"
gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git"
+gem "grape"
gem "stamp"
gem "kaminari"
gem "haml-rails"
diff --git a/Gemfile.lock b/Gemfile.lock
index d50a8d1e5d7..c3a45b59b6e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -14,6 +14,13 @@ GIT
hashery (~> 1.4.0)
GIT
+ remote: https://github.com/gitlabhq/grack.git
+ revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
+ specs:
+ grack (1.0.0)
+ rack (~> 1.4.1)
+
+GIT
remote: https://github.com/gitlabhq/grit.git
revision: 7f35cb98ff17d534a07e3ce6ec3d580f67402837
ref: 7f35cb98ff17d534a07e3ce6ec3d580f67402837
@@ -162,6 +169,12 @@ GEM
gherkin (2.11.0)
json (>= 1.4.6)
git (1.2.5)
+ grape (0.2.0)
+ hashie (~> 1.2)
+ multi_json
+ multi_xml
+ rack
+ rack-mount
haml (3.1.6)
haml-rails (0.3.4)
actionpack (~> 3.0)
@@ -223,6 +236,8 @@ GEM
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
+ rack-mount (0.8.3)
+ rack (>= 1.0.0)
rack-protection (1.2.0)
rack
rack-ssl (1.3.2)
@@ -373,6 +388,8 @@ DEPENDENCIES
foreman
git
gitolite!
+ grack!
+ grape
grit!
haml-rails
httparty
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 79838665336..4619cb01acf 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -34,7 +34,7 @@ class Admin::UsersController < ApplicationController
def new
- @admin_user = User.new(:projects_limit => 10)
+ @admin_user = User.new(:projects_limit => GITLAB_OPTS["default_projects_limit"])
end
def edit
diff --git a/app/models/user.rb b/app/models/user.rb
index 60b5662788f..ccb1dddfef6 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -90,7 +90,8 @@ class User < ActiveRecord::Base
:name => name,
:email => email,
:password => password,
- :password_confirmation => password
+ :password_confirmation => password,
+ :projects_limit => GITLAB_OPTS["default_projects_limit"]
)
end
end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index f29bafa1f21..74e841d20f8 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -17,13 +17,21 @@ git_host:
base_path: /home/git/repositories/
host: localhost
git_user: git
+ upload_pack: true
+ receive_pack: true
# port: 22
+
# Git settings
# Use default values unless you understand it
git:
+ path: /usr/bin/git
# Max size of git object like commit, in bytes
# This value can be increased if you have a very large commits
git_max_size: 5242880 # 5.megabytes
# Git timeout to read commit, in seconds
git_timeout: 10
+
+# Gitlab settings
+gitlab:
+ default_projects_limit: 10
diff --git a/config/initializers/00_before_all.rb b/config/initializers/00_before_all.rb
index 96919595815..01498804ceb 100644
--- a/config/initializers/00_before_all.rb
+++ b/config/initializers/00_before_all.rb
@@ -1,3 +1,4 @@
GIT_HOST = YAML.load_file("#{Rails.root}/config/gitlab.yml")["git_host"]
EMAIL_OPTS = YAML.load_file("#{Rails.root}/config/gitlab.yml")["email"]
GIT_OPTS = YAML.load_file("#{Rails.root}/config/gitlab.yml")["git"]
+GITLAB_OPTS = YAML.load_file("#{Rails.root}/config/gitlab.yml")["gitlab"]
diff --git a/config/initializers/grack_auth.rb b/config/initializers/grack_auth.rb
new file mode 100644
index 00000000000..bb34ce6dc54
--- /dev/null
+++ b/config/initializers/grack_auth.rb
@@ -0,0 +1,46 @@
+module Grack
+ class Auth < Rack::Auth::Basic
+
+ def valid?
+ # Authentication with username and password
+ email, password = @auth.credentials
+ user = User.find_by_email(email)
+ return false unless user.valid_password?(password)
+
+ # Find project by PATH_INFO from env
+ if m = /^\/([\w-]+).git/.match(@env['PATH_INFO']).to_a
+ return false unless project = Project.find_by_path(m.last)
+ end
+
+ # Git upload and receive
+ if @env['REQUEST_METHOD'] == 'GET'
+ true
+ elsif @env['REQUEST_METHOD'] == 'POST'
+ if @env['REQUEST_URI'].end_with?('git-upload-pack')
+ return project.dev_access_for?(user)
+ elsif @env['REQUEST_URI'].end_with?('git-receive-pack')
+ if project.protected_branches.map(&:name).include?(current_ref)
+ project.master_access_for?(user)
+ else
+ project.dev_access_for?(user)
+ end
+ else
+ false
+ end
+ else
+ false
+ end
+ end# valid?
+
+ def current_ref
+ if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
+ input = Zlib::GzipReader.new(@request.body).string
+ else
+ input = @request.body.string
+ end
+
+ oldrev, newrev, ref = input.split(' ')
+ /refs\/heads\/([\w-]+)/.match(ref).to_a.last
+ end
+ end# Auth
+end# Grack
diff --git a/config/routes.rb b/config/routes.rb
index ed4cec4f496..f657b1d2ed8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -4,10 +4,22 @@ Gitlab::Application.routes.draw do
#
get 'search' => "search#show"
+ # API
+ require 'api'
+ mount Gitlab::API => '/api'
+
# Optionally, enable Resque here
require 'resque/server'
mount Resque::Server.new, at: '/info/resque'
+ # Enable Grack support
+ mount Grack::Bundle.new({
+ git_path: GIT_OPTS['path'],
+ project_root: GIT_HOST['base_path'],
+ upload_pack: GIT_HOST['upload_pack'],
+ receive_pack: GIT_HOST['receive_pack']
+ }), at: '/git'
+
#
# Help
#
@@ -20,15 +32,15 @@ Gitlab::Application.routes.draw do
# Admin Area
#
namespace :admin do
- resources :users do
- member do
+ resources :users do
+ member do
put :team_update
put :block
put :unblock
end
end
- resources :projects, :constraints => { :id => /[^\/]+/ } do
- member do
+ resources :projects, :constraints => { :id => /[^\/]+/ } do
+ member do
get :team
put :team_update
end
@@ -80,12 +92,12 @@ Gitlab::Application.routes.draw do
resources :wikis, :only => [:show, :edit, :destroy, :create] do
member do
- get "history"
+ get "history"
end
end
- resource :repository do
- member do
+ resource :repository do
+ member do
get "branches"
get "tags"
get "archive"
@@ -95,14 +107,14 @@ Gitlab::Application.routes.draw do
resources :deploy_keys
resources :protected_branches, :only => [:index, :create, :destroy]
- resources :refs, :only => [], :path => "/" do
- collection do
+ resources :refs, :only => [], :path => "/" do
+ collection do
get "switch"
end
- member do
+ member do
get "tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
- get "blob",
+ get "blob",
:constraints => {
:id => /[a-zA-Z.0-9\/_\-]+/,
:path => /.*/
@@ -127,36 +139,36 @@ Gitlab::Application.routes.draw do
end
end
- resources :merge_requests do
- member do
+ resources :merge_requests do
+ member do
get :diffs
get :automerge
get :automerge_check
end
- collection do
+ collection do
get :branch_from
get :branch_to
end
end
-
- resources :snippets do
- member do
+
+ resources :snippets do
+ member do
get "raw"
end
end
- resources :hooks, :only => [:index, :create, :destroy] do
- member do
+ resources :hooks, :only => [:index, :create, :destroy] do
+ member do
get :test
end
end
- resources :commits do
- collection do
+ resources :commits do
+ collection do
get :compare
end
- member do
+ member do
get :patch
end
end
diff --git a/lib/api.rb b/lib/api.rb
new file mode 100644
index 00000000000..4fdc3273a0e
--- /dev/null
+++ b/lib/api.rb
@@ -0,0 +1,61 @@
+require 'api/entities'
+require 'api/helpers'
+
+module Gitlab
+ class API < Grape::API
+ format :json
+ helpers APIHelpers
+
+ # Users API
+ resource :users do
+ before { authenticate! }
+
+ # GET /users
+ get do
+ @users = User.all
+ present @users, :with => Entities::User
+ end
+
+ # GET /users/:id
+ get ":id" do
+ @user = User.find(params[:id])
+ present @user, :with => Entities::User
+ end
+ end
+
+ # GET /user
+ get "/user" do
+ authenticate!
+ present @current_user, :with => Entities::User
+ end
+
+ # Projects API
+ resource :projects do
+ before { authenticate! }
+
+ # GET /projects
+ get do
+ @projects = current_user.projects
+ present @projects, :with => Entities::Project
+ end
+
+ # GET /projects/:id
+ get ":id" do
+ @project = current_user.projects.find_by_code(params[:id])
+ present @project, :with => Entities::Project
+ end
+
+ # GET /projects/:id/repository/branches
+ get ":id/repository/branches" do
+ @project = current_user.projects.find_by_code(params[:id])
+ present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches
+ end
+
+ # GET /projects/:id/repository/tags
+ get ":id/repository/tags" do
+ @project = current_user.projects.find_by_code(params[:id])
+ present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
new file mode 100644
index 00000000000..44a43985602
--- /dev/null
+++ b/lib/api/entities.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module Entities
+ class User < Grape::Entity
+ expose :id, :email, :name, :bio, :skype, :linkedin, :twitter,
+ :dark_scheme, :theme_id, :blocked, :created_at
+ end
+
+ class Project < Grape::Entity
+ expose :id, :code, :name, :description, :path, :default_branch
+ expose :owner, :using => Entities::User
+ expose :private_flag, :as => :private
+ expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
+ end
+
+ class ProjectRepositoryBranches < Grape::Entity
+ expose :name, :commit
+ end
+
+ class ProjectRepositoryTags < Grape::Entity
+ expose :name, :commit
+ end
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
new file mode 100644
index 00000000000..cd2e39bf3a7
--- /dev/null
+++ b/lib/api/helpers.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ module APIHelpers
+ def current_user
+ @current_user ||= User.find_by_authentication_token(params[:private_token])
+ end
+
+ def authenticate!
+ error!('401 Unauthorized', 401) unless current_user
+ end
+ end
+end
diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb
new file mode 100644
index 00000000000..e4835736b8c
--- /dev/null
+++ b/spec/api/projects_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+ let(:user) { Factory :user }
+ let!(:project) { Factory :project, :owner => user }
+ before { project.add_access(user, :read) }
+
+ describe "GET /projects" do
+ it "should return authentication error" do
+ get "/api/projects"
+ response.status.should == 401
+ end
+
+ describe "authenticated GET /projects" do
+ it "should return an array of projects" do
+ get "/api/projects?private_token=#{user.private_token}"
+ response.status.should == 200
+ json = JSON.parse(response.body)
+ json.should be_an Array
+ json.first['name'].should == project.name
+ json.first['owner']['email'].should == user.email
+ end
+ end
+ end
+
+ describe "GET /projects/:id" do
+ it "should return a project by id" do
+ get "/api/projects/#{project.code}?private_token=#{user.private_token}"
+ response.status.should == 200
+ json = JSON.parse(response.body)
+ json['name'].should == project.name
+ json['owner']['email'].should == user.email
+ end
+ end
+
+ describe "GET /projects/:id/repository/branches" do
+ it "should return an array of project branches" do
+ get "/api/projects/#{project.code}/repository/branches?private_token=#{user.private_token}"
+ response.status.should == 200
+ json = JSON.parse(response.body)
+ json.should be_an Array
+ json.first['name'].should == project.repo.heads.sort_by(&:name).first.name
+ end
+ end
+
+ describe "GET /projects/:id/repository/tags" do
+ it "should return an array of project tags" do
+ get "/api/projects/#{project.code}/repository/tags?private_token=#{user.private_token}"
+ response.status.should == 200
+ json = JSON.parse(response.body)
+ json.should be_an Array
+ json.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
+ end
+ end
+end
diff --git a/spec/api/users_spec.rb b/spec/api/users_spec.rb
new file mode 100644
index 00000000000..f142ac637ec
--- /dev/null
+++ b/spec/api/users_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+ let(:user) { Factory :user }
+
+ describe "GET /users" do
+ it "should return authentication error" do
+ get "/api/users"
+ response.status.should == 401
+ end
+
+ describe "authenticated GET /users" do
+ it "should return an array of users" do
+ get "/api/users?private_token=#{user.private_token}"
+ response.status.should == 200
+ json = JSON.parse(response.body)
+ json.should be_an Array
+ json.first['email'].should == user.email
+ end
+ end
+ end
+
+ describe "GET /users/:id" do
+ it "should return a user by id" do
+ get "/api/users/#{user.id}?private_token=#{user.private_token}"
+ response.status.should == 200
+ JSON.parse(response.body)['email'].should == user.email
+ end
+ end
+
+ describe "GET /user" do
+ it "should return current user" do
+ get "/api/user?private_token=#{user.private_token}"
+ response.status.should == 200
+ JSON.parse(response.body)['email'].should == user.email
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 5556798f511..65e7e529a5b 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -58,4 +58,8 @@ RSpec.configure do |config|
config.after do
DatabaseCleaner.clean
end
+
+ config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
+ :file_path => /spec\/api/
+ }
end