From 10d3a30b255cd85b2cf7af39814fd7418eecd838 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Date: Fri, 21 Sep 2012 13:22:30 +0300
Subject: [PATCH] APi for commits. Better api docs

---
 Guardfile                         |   1 +
 app/views/help/api.html.haml      | 147 ++++++++++++++++--------------
 doc/api/commits.md                |  38 ++++++++
 lib/api.rb                        |   1 +
 lib/api/commits.rb                |  29 ++++++
 lib/api/entities.rb               |   5 +
 lib/api/helpers.rb                |   2 +-
 lib/api/milestones.rb             |   6 ++
 lib/api/projects.rb               |  20 ++--
 spec/requests/api/commits_spec.rb |  29 ++++++
 10 files changed, 199 insertions(+), 79 deletions(-)
 create mode 100644 doc/api/commits.md
 create mode 100644 lib/api/commits.rb
 create mode 100644 spec/requests/api/commits_spec.rb

diff --git a/Guardfile b/Guardfile
index 50a10af9a31a0..e682f0b6cf1fb 100644
--- a/Guardfile
+++ b/Guardfile
@@ -4,6 +4,7 @@
 guard 'rspec', :version => 2, :all_on_start => false, :all_after_pass => false do
   watch(%r{^spec/.+_spec\.rb$})
   watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
+  watch(%r{^lib/api/(.+)\.rb$})     { |m| "spec/requests/api/#{m[1]}_spec.rb" }
   watch('spec/spec_helper.rb')  { "spec" }
 
   # Rails example
diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml
index b1916110ca553..1f0ce87938184 100644
--- a/app/views/help/api.html.haml
+++ b/app/views/help/api.html.haml
@@ -1,89 +1,96 @@
-%h3 API
+%h3.page_title API
 .back_link
   = link_to help_path do
     &larr; to index
-%hr
+%br
 
-%ol
+%ul.nav.nav-tabs.log-tabs
+  %li.active
+    = link_to "README", "#README", 'data-toggle' => 'tab'
   %li
-    %a{href: "#README"} README
+    = link_to "Projects", "#projects", 'data-toggle' => 'tab'
   %li
-    %a{href: "#projects"} Projects
+    = link_to "Snippets", "#snippets", 'data-toggle' => 'tab'
   %li
-    %a{href: "#snippets"} Snippets
+    = link_to "Users", "#users", 'data-toggle' => 'tab'
   %li
-    %a{href: "#users"} Users
+    = link_to "Session", "#session", 'data-toggle' => 'tab'
   %li
-    %a{href: "#session"} Session
+    = link_to "Issues", "#issues", 'data-toggle' => 'tab'
   %li
-    %a{href: "#issues"} Issues
+    = link_to "Milestones", "#milestones", 'data-toggle' => 'tab'
   %li
-    %a{href: "#milestones"} Milestones
-
-.file_holder#README
-  .file_title
-    %i.icon-file
-    README
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "README.md"))
-
-%br
-
-.file_holder#projects
-  .file_title
-    %i.icon-file
-    Projects
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "projects.md"))
-
-%br
-
-.file_holder#snippets
-  .file_title
-    %i.icon-file
-    Projects Snippets
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "snippets.md"))
+    = link_to "Commits", "#commits", 'data-toggle' => 'tab'
 
-%br
+.tab-content
+  .tab-pane.active#README
+    .file_holder
+      .file_title
+        %i.icon-file
+        README
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "README.md"))
 
-.file_holder#users
-  .file_title
-    %i.icon-file
-    Users
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "users.md"))
+  .tab-pane#projects
+    .file_holder
+      .file_title
+        %i.icon-file
+        Projects
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "projects.md"))
 
-%br
+  .tab-pane#snippets
+    .file_holder
+      .file_title
+        %i.icon-file
+        Projects Snippets
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "snippets.md"))
 
-.file_holder#session
-  .file_title
-    %i.icon-file
-    Session
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "session.md"))
+  .tab-pane#users
+    .file_holder
+      .file_title
+        %i.icon-file
+        Users
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "users.md"))
 
-%br
+  .tab-pane#session
+    .file_holder
+      .file_title
+        %i.icon-file
+        Session
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "session.md"))
 
-.file_holder#issues
-  .file_title
-    %i.icon-file
-    Issues
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
+  .tab-pane#issues
+    .file_holder
+      .file_title
+        %i.icon-file
+        Issues
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
 
-%br
+  .tab-pane#milestones
+    .file_holder
+      .file_title
+        %i.icon-file
+        Milestones
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "milestones.md"))
 
-.file_holder#milestones
-  .file_title
-    %i.icon-file
-    Milestones
-  .file_content.wiki
-    = preserve do
-      = markdown File.read(Rails.root.join("doc", "api", "milestones.md"))
+  .tab-pane#commits
+    .file_holder
+      .file_title
+        %i.icon-file
+        Commits
+      .file_content.wiki
+        = preserve do
+          = markdown File.read(Rails.root.join("doc", "api", "commits.md"))
diff --git a/doc/api/commits.md b/doc/api/commits.md
new file mode 100644
index 0000000000000..fccb35c33000a
--- /dev/null
+++ b/doc/api/commits.md
@@ -0,0 +1,38 @@
+## List Commits
+
+Get a list of project commits.
+
+```
+GET /projects/:id/commits
+```
+
+Parameters:
+
++ `id` (required) - The ID or code name of a project
++ `ref_name` (optional) - branch/tag name
++ `page` (optional)
++ `per_page` (optional)
+
+
+```json
+
+[
+  {
+      "id": "ed899a2f4b50b4370feeea94676502b42383c746",
+      "short_id": "ed899a2f4b5",
+      "title": "Replace sanitize with escape once",
+      "author_name": "Dmitriy Zaporozhets",
+      "author_email": "dzaporozhets@sphereconsultinginc.com",
+      "created_at": "2012-09-20T11:50:22+03:00"
+  },
+  {
+      "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
+      "short_id": "6104942438c",
+      "title": "Sanitize for network graph",
+      "author_name": "randx",
+      "author_email": "dmitriy.zaporozhets@gmail.com",
+      "created_at": "2012-09-20T09:06:12+03:00"
+  }
+]
+
+```
diff --git a/lib/api.rb b/lib/api.rb
index 3b62f31bf3227..f4e9e5fcc13a6 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -19,5 +19,6 @@ class API < Grape::API
     mount Milestones
     mount Keys
     mount Session
+    mount Commits
   end
 end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
new file mode 100644
index 0000000000000..47d96fc4906d9
--- /dev/null
+++ b/lib/api/commits.rb
@@ -0,0 +1,29 @@
+module Gitlab
+  # Commits API
+  class Commits < Grape::API
+    before { authenticate! }
+
+    resource :projects do
+      # Get a list of project commits
+      #
+      # Parameters:
+      #   id (required) - The ID or code name of a project
+      #   ref_name (optional) - Name of branch or tag
+      #   page (optional) - default is 0
+      #   per_page (optional) - default is 20
+      # Example Request:
+      #   GET /projects/:id/commits
+      get ":id/commits" do
+        authorize! :download_code, user_project
+
+        page = params[:page] || 0
+        per_page = params[:per_page] || 20
+        ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
+
+        commits = user_project.commits(ref, nil, per_page, page * per_page)
+
+        present CommitDecorator.decorate(commits), with: Entities::Commit
+      end
+    end
+  end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index a8b786aebb0e0..1909a016208b4 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -17,6 +17,11 @@ class Hook < Grape::Entity
       expose :id, :url
     end
 
+    class Commit < Grape::Entity
+      expose :id, :short_id, :title,
+        :author_name, :author_email, :created_at
+    end
+
     class Project < Grape::Entity
       expose :id, :code, :name, :description, :path, :default_branch
       expose :owner, using: Entities::UserBasic
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 9a08b99580043..14390545bd5eb 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -61,7 +61,7 @@ def render_api_error!(message, status)
       error!({'message' => message}, status)
     end
 
-    private 
+    private
 
     def abilities
       @abilities ||= begin
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index daaff9403256f..f55dfd04cc5b5 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -11,6 +11,8 @@ class Milestones < Grape::API
       # Example Request:
       #   GET /projects/:id/milestones
       get ":id/milestones" do
+        authorize! :read_milestone, user_project
+
         present paginate(user_project.milestones), with: Entities::Milestone
       end
 
@@ -22,6 +24,8 @@ class Milestones < Grape::API
       # Example Request:
       #   GET /projects/:id/milestones/:milestone_id
       get ":id/milestones/:milestone_id" do
+        authorize! :read_milestone, user_project
+
         @milestone = user_project.milestones.find(params[:milestone_id])
         present @milestone, with: Entities::Milestone
       end
@@ -36,6 +40,8 @@ class Milestones < Grape::API
       # Example Request:
       #   POST /projects/:id/milestones
       post ":id/milestones" do
+        authorize! :admin_milestone, user_project
+
         attrs = attributes_for_keys [:title, :description, :due_date]
         @milestone = user_project.milestones.new attrs
         if @milestone.save
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 1d9004f8eedcd..d6ff02c3cd24f 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -40,14 +40,14 @@ class Projects < Grape::API
       post do
         params[:code] ||= params[:name]
         params[:path] ||= params[:name]
-        attrs = attributes_for_keys [:code, 
-                                    :path, 
-                                    :name, 
-                                    :description, 
-                                    :default_branch, 
-                                    :issues_enabled, 
-                                    :wall_enabled, 
-                                    :merge_requests_enabled, 
+        attrs = attributes_for_keys [:code,
+                                    :path,
+                                    :name,
+                                    :description,
+                                    :default_branch,
+                                    :issues_enabled,
+                                    :wall_enabled,
+                                    :merge_requests_enabled,
                                     :wiki_enabled]
         @project = Project.create_by_user(attrs, current_user)
         if @project.saved?
@@ -207,6 +207,8 @@ class Projects < Grape::API
       # Example Request:
       #   POST /projects/:id/snippets
       post ":id/snippets" do
+        authorize! :write_snippet, user_project
+
         attrs = attributes_for_keys [:title, :file_name]
         attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
         attrs[:content] = params[:code] if params[:code].present?
@@ -282,6 +284,8 @@ class Projects < Grape::API
       # Example Request:
       #   GET /projects/:id/repository/commits/:sha/blob
       get ":id/repository/commits/:sha/blob" do
+        authorize! :download_code, user_project
+
         ref = params[:sha]
 
         commit = user_project.commit ref
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
new file mode 100644
index 0000000000000..3af5ec21c432e
--- /dev/null
+++ b/spec/requests/api/commits_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Gitlab::API do
+  include ApiHelpers
+
+  let(:user) { Factory :user }
+  let!(:project) { Factory :project, owner: user }
+
+  describe "GET /projects/:id/commits" do
+    context "authorized user" do
+      before { project.add_access(user, :read) }
+
+      it "should return project commits" do
+        get api("/projects/#{project.code}/commits", user)
+        response.status.should == 200
+
+        json_response.should be_an Array
+        json_response.first['id'].should == project.commit.id
+      end
+    end
+
+    context "unauthorized user" do
+      it "should return project commits" do
+        get api("/projects/#{project.code}/commits")
+        response.status.should == 401
+      end
+    end
+  end
+end
-- 
GitLab