From e3b149fae611d9c66d3e41048970bd78f322cc9c Mon Sep 17 00:00:00 2001 From: Caley Woods Date: Wed, 19 Sep 2012 10:27:27 -0500 Subject: [PATCH 01/34] Update comment in example unicorn config The timeout was changed to 30 and the comment wasn't updated. Also I've seen several reports of this timeout not being long enough for quite a few people. It resulted in me getting a 502 bad gateway from nginx until I upped it. Perhaps could back to the default 60 would be better? I changed mine to 300, running on an AWS micro instance. --- config/unicorn.rb.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 23746d255b48..425dbf33f869 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -6,7 +6,7 @@ working_directory app_dir # worker spawn times preload_app true -# nuke workers after 60 seconds (the default) +# nuke workers after 30 seconds (60 is the default) timeout 30 # listen on a Unix domain socket and/or a TCP port, From ed899a2f4b50b4370feeea94676502b42383c746 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 20 Sep 2012 11:50:22 +0300 Subject: [PATCH 02/34] Replace sanitize with escape once --- lib/gitlab/graph_commit.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/graph_commit.rb b/lib/gitlab/graph_commit.rb index e14d670e5c77..d3668a991073 100644 --- a/lib/gitlab/graph_commit.rb +++ b/lib/gitlab/graph_commit.rb @@ -5,7 +5,7 @@ class GraphCommit attr_accessor :time, :space attr_accessor :refs - include ActionView::Helpers::SanitizeHelper + include ActionView::Helpers::TagHelper def self.to_graph(project) @repo = project.repo @@ -166,7 +166,7 @@ def to_graph_hash h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:id] = sha h[:date] = date - h[:message] = sanitize(Gitlab::Encode.utf8(message)) + h[:message] = escape_once(Gitlab::Encode.utf8(message)) h[:login] = author.email h end From 0e524aaea1a98e5f1dff7f7370838116da5ba6f0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 20 Sep 2012 13:00:18 +0300 Subject: [PATCH 03/34] Added workaround for github-markup issue with rendering markdown --- app/helpers/tree_helper.rb | 8 ++++++-- app/views/refs/_tree.html.haml | 6 +++++- app/views/refs/_tree_file.html.haml | 6 +++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index a5d5c7422302..2b7265ca19e4 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -32,7 +32,11 @@ def tree_full_path(content) # # Returns boolean def markup?(filename) - filename.end_with?(*%w(.mdown .md .markdown .textile .rdoc .org .creole - .mediawiki .rst .asciidoc .pod)) + filename.end_with?(*%w(.textile .rdoc .org .creole + .mediawiki .rst .asciidoc .pod)) + end + + def gitlab_markdown?(filename) + filename.end_with?(*%w(.mdown .md .markdown)) end end diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml index ec6dba4ee07a..55078718b79f 100644 --- a/app/views/refs/_tree.html.haml +++ b/app/views/refs/_tree.html.haml @@ -43,7 +43,11 @@ %i.icon-file = content.name .file_content.wiki - = raw GitHub::Markup.render(content.name, content.data) + - if gitlab_markdown?(content.name) + = preserve do + = markdown(content.data) + - else + = raw GitHub::Markup.render(content.name, content.data) :javascript $(function(){ diff --git a/app/views/refs/_tree_file.html.haml b/app/views/refs/_tree_file.html.haml index f6566ccf5d52..76173e24246a 100644 --- a/app/views/refs/_tree_file.html.haml +++ b/app/views/refs/_tree_file.html.haml @@ -9,7 +9,11 @@ = link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" = link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small" - if file.text? - - if markup?(name) + - if gitlab_markdown?(name) + .file_content.wiki + = preserve do + = markdown(file.data) + - elsif markup?(name) .file_content.wiki = raw GitHub::Markup.render(name, file.data) - else From f33e1e480e9009f8cd3930eef1830877623588c5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 20 Sep 2012 13:05:07 +0300 Subject: [PATCH 04/34] Let it be v2.9 --- CHANGELOG | 4 +++- VERSION | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7322efbf2285..99641ad3a95b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,8 +9,10 @@ v 2.9.0 - scss refactoring. gitlab_bootstrap/ dir - fix git push http body bigger than 112k problem - list of labels page under issues tab - - API for milestones + - API for milestones, keys - restyled buttons + - OAuth + - Comment order changed v 2.8.1 - ability to disable gravatars diff --git a/VERSION b/VERSION index a564e65383b6..c8e38b614057 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.9.0pre +2.9.0 From 4e1f1e142299209ff50d595528b1e6410c9b7308 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 18:34:07 +0600 Subject: [PATCH 05/34] API docs minor formatting fix [ci-skip] --- doc/api/projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 73d6adc9bc3e..53ee5d412abb 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -102,7 +102,7 @@ Parameters: + `name` (required) - new project name + `code` (optional) - new project code, uses project name if not set + `path` (optional) - new project path, uses project name if not set -+ `description (optional) - short project description ++ `description` (optional) - short project description + `default_branch` (optional) - 'master' by default + `issues_enabled` (optional) - enabled by default + `wall_enabled` (optional) - enabled by default From 37817cc31d890f1e79b31ae3d625fbace672451e Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 18:38:34 +0600 Subject: [PATCH 06/34] API: expose project id for milestones --- lib/api/entities.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 13a48e120197..6241fc8f1877 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -36,7 +36,9 @@ class ProjectSnippet < Grape::Entity end class Milestone < Grape::Entity - expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at + expose :id + expose (:project_id) {|milestone| milestone.project.id} + expose :title, :description, :due_date, :closed, :updated_at, :created_at end class Issue < Grape::Entity From 9aafe77e708174aac697a8dcafc99b90e96be36e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 20 Sep 2012 17:44:44 +0300 Subject: [PATCH 07/34] I want be able to get token via api. Used for mobile applications --- doc/api/README.md | 1 + doc/api/session.md | 22 +++++++++++++++++ lib/api.rb | 1 + lib/api/entities.rb | 8 +++++-- lib/api/session.rb | 21 +++++++++++++++++ spec/requests/api/session_spec.rb | 39 +++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 doc/api/session.md create mode 100644 lib/api/session.rb create mode 100644 spec/requests/api/session_spec.rb diff --git a/doc/api/README.md b/doc/api/README.md index 9741072c095c..443ec7bf1ca0 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -30,6 +30,7 @@ When listing resources you can pass the following parameters: ## Contents + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) ++ [Session](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/session.md) + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) + [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.md) + [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) diff --git a/doc/api/session.md b/doc/api/session.md new file mode 100644 index 000000000000..9fdbeb439a40 --- /dev/null +++ b/doc/api/session.md @@ -0,0 +1,22 @@ +Login to get private token + +``` +POST /session +``` + +Parameters: + ++ `email` (required) - The email of user ++ `password` (required) - Valid password + + +```json +{ + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "private_token": "dd34asd13as", + "created_at": "2012-05-23T08:00:58Z", + "blocked": true +} +``` diff --git a/lib/api.rb b/lib/api.rb index 37e03849b96e..3b62f31bf322 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -18,5 +18,6 @@ class API < Grape::API mount Issues mount Milestones mount Keys + mount Session end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 6241fc8f1877..5d8cc2765b1a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -9,6 +9,10 @@ class UserBasic < Grape::Entity expose :id, :email, :name, :blocked, :created_at end + class UserLogin < Grape::Entity + expose :id, :email, :name, :private_token, :blocked, :created_at + end + class Hook < Grape::Entity expose :id, :url end @@ -52,8 +56,8 @@ class Issue < Grape::Entity end class Key < Grape::Entity - expose :id, - :title, + expose :id, + :title, :key end end diff --git a/lib/api/session.rb b/lib/api/session.rb new file mode 100644 index 000000000000..5bcdf93abe92 --- /dev/null +++ b/lib/api/session.rb @@ -0,0 +1,21 @@ +module Gitlab + # Users API + class Session < Grape::API + # Login to get token + # + # Example Request: + # POST /session + post "/session" do + resource = User.find_for_database_authentication(email: params[:email]) + + return forbidden! unless resource + + if resource.valid_password?(params[:password]) + present resource, with: Entities::UserLogin + else + forbidden! + end + end + end +end + diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb new file mode 100644 index 000000000000..0809475be81b --- /dev/null +++ b/spec/requests/api/session_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { Factory :user } + + describe "POST /session" do + context "when valid password" do + it "should return private token" do + post api("/session"), email: user.email, password: '123456' + response.status.should == 201 + + json_response['email'].should == user.email + json_response['private_token'].should == user.private_token + end + end + + context "when invalid password" do + it "should return authentication error" do + post api("/session"), email: user.email, password: '123' + response.status.should == 403 + + json_response['email'].should be_nil + json_response['private_token'].should be_nil + end + end + + context "when empty password" do + it "should return authentication error" do + post api("/session"), email: user.email + response.status.should == 403 + + json_response['email'].should be_nil + json_response['private_token'].should be_nil + end + end + end +end From 3dd940d4cbd72afed38eba49b557823a6a55eac2 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 08:36:43 -0700 Subject: [PATCH 08/34] API: extend UserLogin entity from UserBasic --- lib/api/entities.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5d8cc2765b1a..a8b786aebb0e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -9,8 +9,8 @@ class UserBasic < Grape::Entity expose :id, :email, :name, :blocked, :created_at end - class UserLogin < Grape::Entity - expose :id, :email, :name, :private_token, :blocked, :created_at + class UserLogin < UserBasic + expose :private_token end class Hook < Grape::Entity @@ -56,9 +56,7 @@ class Issue < Grape::Entity end class Key < Grape::Entity - expose :id, - :title, - :key + expose :id, :title, :key end end end From b08d33f6a9a82e04f288fc0a4de6d4a7489795e1 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 08:38:08 -0700 Subject: [PATCH 09/34] API: return 401 for invalid session --- lib/api/session.rb | 5 ++--- spec/requests/api/session_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/api/session.rb b/lib/api/session.rb index 5bcdf93abe92..b4050160ae42 100644 --- a/lib/api/session.rb +++ b/lib/api/session.rb @@ -8,14 +8,13 @@ class Session < Grape::API post "/session" do resource = User.find_for_database_authentication(email: params[:email]) - return forbidden! unless resource + return unauthorized! unless resource if resource.valid_password?(params[:password]) present resource, with: Entities::UserLogin else - forbidden! + unauthorized! end end end end - diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index 0809475be81b..f251f3921aca 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -19,7 +19,7 @@ context "when invalid password" do it "should return authentication error" do post api("/session"), email: user.email, password: '123' - response.status.should == 403 + response.status.should == 401 json_response['email'].should be_nil json_response['private_token'].should be_nil @@ -29,7 +29,7 @@ context "when empty password" do it "should return authentication error" do post api("/session"), email: user.email - response.status.should == 403 + response.status.should == 401 json_response['email'].should be_nil json_response['private_token'].should be_nil From 81aeac46d63cd315b6545494cfa41ae163cadc5c Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 08:51:26 -0700 Subject: [PATCH 10/34] update help section with session API docs --- app/views/help/api.html.haml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index 35176f8e214d..b1916110ca55 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -13,6 +13,8 @@ %a{href: "#snippets"} Snippets %li %a{href: "#users"} Users + %li + %a{href: "#session"} Session %li %a{href: "#issues"} Issues %li @@ -58,6 +60,16 @@ %br +.file_holder#session + .file_title + %i.icon-file + Session + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "session.md")) + +%br + .file_holder#issues .file_title %i.icon-file From a605943d76216f2c5e78178c2b87ed92ff79741f Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Thu, 20 Sep 2012 22:11:15 +0600 Subject: [PATCH 11/34] fix broken spec --- spec/helpers/tree_helper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb index bb124d8b303d..d450b687cafe 100644 --- a/spec/helpers/tree_helper_spec.rb +++ b/spec/helpers/tree_helper_spec.rb @@ -2,7 +2,7 @@ describe TreeHelper do describe '#markup?' do - %w(mdown md markdown textile rdoc org creole mediawiki rst asciidoc pod).each do |type| + %w(textile rdoc org creole mediawiki rst asciidoc pod).each do |type| it "returns true for #{type} files" do markup?("README.#{type}").should be_true end From 4cc169d3cacea7e4325bb5632cc8878a7c3f41fe Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 21 Sep 2012 11:22:53 +0300 Subject: [PATCH 12/34] Improve commits compare. Added tags to autocomplete. Dont look for commits if from & to are empty --- app/controllers/commits_controller.rb | 1 + app/models/commit.rb | 12 ++++++++---- app/roles/repository.rb | 8 ++++++++ app/views/commits/compare.html.haml | 28 +++++++++++++++------------ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 6d3f1aea6c9f..1e7aec005f15 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -52,6 +52,7 @@ def compare @commits = result[:commits] @commit = result[:commit] @diffs = result[:diffs] + @refs_are_same = result[:same] @line_notes = [] @commits = CommitDecorator.decorate(@commits) diff --git a/app/models/commit.rb b/app/models/commit.rb index 15afedcb1017..73583e9e7b79 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -82,20 +82,24 @@ def commits_between(repo, from, to) end def compare(project, from, to) - first = project.commit(to.try(:strip)) - last = project.commit(from.try(:strip)) - result = { commits: [], diffs: [], - commit: nil + commit: nil, + same: false } + return result unless from && to + + first = project.commit(to.try(:strip)) + last = project.commit(from.try(:strip)) + if first && last commits = [first, last].sort_by(&:created_at) younger = commits.first older = commits.last + result[:same] = (younger.id == older.id) result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] result[:commit] = Commit.new(older) diff --git a/app/roles/repository.rb b/app/roles/repository.rb index a77de4ad5f01..01156ac18b70 100644 --- a/app/roles/repository.rb +++ b/app/roles/repository.rb @@ -79,6 +79,14 @@ def heads @heads ||= repo.heads end + def branches_names + heads.map(&:name) + end + + def ref_names + [branches_names + tags].flatten + end + def tree(fcommit, path = nil) fcommit = commit if fcommit == :head tree = fcommit.tree diff --git a/app/views/commits/compare.html.haml b/app/views/commits/compare.html.haml index 7dab1f5c0fa6..db15ba53823a 100644 --- a/app/views/commits/compare.html.haml +++ b/app/views/commits/compare.html.haml @@ -1,16 +1,16 @@ = render "head" -%h3 +%h3.page_title Compare View %hr %div - %p + %p.slead Fill input field with commit id like - %code '4eedf23' + %code.label_branch 4eedf23 or branch/tag name like - %code master - & press compare button for commits list, code diff. + %code.label_branch master + and press compare button for commits list, code diff. %br @@ -19,22 +19,24 @@ = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge" = "..." = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" + - if @refs_are_same + .alert + %span Refs are the same .actions - = submit_tag "Compare", class: "btn primary" + = submit_tag "Compare", class: "btn primary wide commits-compare-btn" - -- unless @commits.empty? +- if @commits.present? %div.ui-box %h5.small Commits (#{@commits.count}) %ul.unstyled= render @commits -- unless @diffs.empty? - %h4 Diff - = render "commits/diffs", diffs: @diffs + - unless @diffs.empty? + %h4 Diff + = render "commits/diffs", diffs: @diffs :javascript $(function() { - var availableTags = #{@project.heads.map(&:name).to_json}; + var availableTags = #{@project.ref_names.to_json}; $("#from").autocomplete({ source: availableTags, @@ -45,5 +47,7 @@ source: availableTags, minLength: 1 }); + + disableButtonIfEmptyField('#to', '.commits-compare-btn'); }); From 10d3a30b255cd85b2cf7af39814fd7418eecd838 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 21 Sep 2012 13:22:30 +0300 Subject: [PATCH 13/34] 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 50a10af9a31a..e682f0b6cf1f 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 b1916110ca55..1f0ce8793818 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 ← 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 000000000000..fccb35c33000 --- /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 3b62f31bf322..f4e9e5fcc13a 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 000000000000..47d96fc4906d --- /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 a8b786aebb0e..1909a016208b 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 9a08b9958004..14390545bd5e 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 daaff9403256..f55dfd04cc5b 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 1d9004f8eedc..d6ff02c3cd24 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 000000000000..3af5ec21c432 --- /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 From 25b745271a1db25fc709ae13737b04c1f94cdb95 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 03:23:17 -0700 Subject: [PATCH 14/34] add API for project team members --- doc/api/projects.md | 63 +++++++++++++------- lib/api/entities.rb | 7 ++- lib/api/projects.rb | 93 +++++++++++++++++++----------- spec/requests/api/projects_spec.rb | 54 ++++++++++------- 4 files changed, 139 insertions(+), 78 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 53ee5d412abb..1e23df3ac899 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -112,66 +112,89 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. -## Get project users +## List project team members -Get users and access roles for existing project +Get a list of project team members. ``` -GET /projects/:id/users +GET /projects/:id/members ``` Parameters: + `id` (required) - The ID or code name of a project -Will return users and their access roles with status `200 OK` on success, or `404 Not found` on fail. +## Get project team member -## Add project users +Get a project team member. -Add users to exiting project +``` +GET /projects/:id/members/:user_id +``` + +Parameters: ++ `id` (required) - The ID or code name of a project ++ `user_id` (required) - The ID of a user + +```json +{ + + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z", + "access_level": 40 +} ``` -POST /projects/:id/users + +## Add project team member + +Add a user to a project team. + +``` +POST /projects/:id/members ``` Parameters: + `id` (required) - The ID or code name of a project -+ `user_ids` (required) - The ID list of users to add -+ `project_access` (required) - Project access level ++ `user_id` (required) - The ID of a user to add ++ `access_level` (required) - Project access level Will return status `201 Created` on success, or `404 Not found` on fail. -## Update project users access level +## Edit project team member -Update existing users to specified access level +Update project team member to specified access level. ``` -PUT /projects/:id/users +PUT /projects/:id/members/:user_id ``` Parameters: + `id` (required) - The ID or code name of a project -+ `user_ids` (required) - The ID list of users to add -+ `project_access` (required) - Project access level ++ `user_id` (required) - The ID of a team member ++ `access_level` (required) - Project access level Will return status `200 OK` on success, or `404 Not found` on fail. -## Delete project users +## Remove project team member -Delete users from exiting project +Removes user from project team. ``` -DELETE /projects/:id/users +DELETE /projects/:id/members/:user_id ``` Parameters: + `id` (required) - The ID or code name of a project -+ `user_ids` (required) - The ID list of users to add ++ `user_id` (required) - The ID of a team member -Will return status `200 OK` on success, or `404 Not found` on fail. +Status code `200` will be returned on success. ## Get project hooks @@ -344,7 +367,7 @@ Parameters: + `id` (required) - The ID or code name of a project + `sha` (required) - The commit or branch name -+ `filepath` (required) - The path the file ++ `filepath` (required) - The path the file Will return the raw file contents. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index a8b786aebb0e..9e5723245dc1 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -24,9 +24,10 @@ class Project < Grape::Entity expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at end - class UsersProject < Grape::Entity - expose :user, using: Entities::UserBasic - expose :project_access + class ProjectMember < UserBasic + expose :project_access, :as => :access_level do |user, options| + options[:project].users_projects.find_by_user_id(user.id).project_access + end end class RepoObject < Grape::Entity diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 1d9004f8eedc..456b8a7714de 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? @@ -57,56 +57,83 @@ class Projects < Grape::API end end - # Get project users + # Get a project team members # # Parameters: # id (required) - The ID or code name of a project # Example Request: - # GET /projects/:id/users - get ":id/users" do - @users_projects = paginate user_project.users_projects - present @users_projects, with: Entities::UsersProject + # GET /projects/:id/members + get ":id/members" do + @members = paginate user_project.users + present @members, with: Entities::ProjectMember, project: user_project end - # Add users to project with specified access level + # Get a project team members # # Parameters: # id (required) - The ID or code name of a project - # user_ids (required) - The ID list of users to add - # project_access (required) - Project access level + # user_id (required) - The ID of a user # Example Request: - # POST /projects/:id/users - post ":id/users" do + # GET /projects/:id/members/:user_id + get ":id/members/:user_id" do + @member = user_project.users.find params[:user_id] + present @member, with: Entities::ProjectMember, project: user_project + end + + # Add a new project team member + # + # Parameters: + # id (required) - The ID or code name of a project + # user_id (required) - The ID of a user + # access_level (required) - Project access level + # Example Request: + # POST /projects/:id/members + post ":id/members" do authorize! :admin_project, user_project - user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) - nil + users_project = user_project.users_projects.new( + user_id: params[:user_id], + project_access: params[:access_level] + ) + + if users_project.save + @member = users_project.user + present @member, with: Entities::ProjectMember, project: user_project + else + not_found! + end end - # Update users to specified access level + # Update project team member # # Parameters: # id (required) - The ID or code name of a project - # user_ids (required) - The ID list of users to add - # project_access (required) - New project access level to + # user_id (required) - The ID of a team member + # access_level (required) - Project access level # Example Request: - # PUT /projects/:id/add_users - put ":id/users" do + # PUT /projects/:id/members/:user_id + put ":id/members/:user_id" do authorize! :admin_project, user_project - user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) - nil + users_project = user_project.users_projects.find_by_user_id params[:user_id] + + if users_project.update_attributes(project_access: params[:access_level]) + @member = users_project.user + present @member, with: Entities::ProjectMember, project: user_project + else + not_found! + end end - # Delete project users + # Remove a team member from project # # Parameters: # id (required) - The ID or code name of a project - # user_ids (required) - The ID list of users to delete + # user_id (required) - The ID of a team member # Example Request: - # DELETE /projects/:id/users - delete ":id/users" do + # DELETE /projects/:id/members/:user_id + delete ":id/members/:user_id" do authorize! :admin_project, user_project - user_project.delete_users_ids_from_team(params[:user_ids].values) - nil + users_project = user_project.users_projects.find_by_user_id params[:user_id] + users_project.destroy end # Get project hooks diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index b46380b21d92..40a9147d726b 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -111,42 +111,52 @@ end end - describe "GET /projects/:id/users" do - it "should return project users" do - get api("/projects/#{project.code}/users", user) - + describe "GET /projects/:id/members" do + it "should return project team members" do + get api("/projects/#{project.code}/members", user) response.status.should == 200 - json_response.should be_an Array json_response.count.should == 2 - json_response.first['user']['id'].should == user.id + json_response.first['email'].should == user.email end end - describe "POST /projects/:id/users" do - it "should add users to project" do - expect { - post api("/projects/#{project.code}/users", user), - user_ids: {"0" => user2.id}, project_access: UsersProject::DEVELOPER - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) + describe "GET /projects/:id/members/:user_id" do + it "should return project team member" do + get api("/projects/#{project.code}/members/#{user.id}", user) + response.status.should == 200 + json_response['email'].should == user.email + json_response['access_level'].should == UsersProject::MASTER end end - describe "PUT /projects/:id/users" do - it "should update users to new access role" do + describe "POST /projects/:id/members" do + it "should add user to project team" do expect { - put api("/projects/#{project.code}/users", user), - user_ids: {"0" => user3.id}, project_access: UsersProject::MASTER - }.to change {project.users_projects.where(:project_access => UsersProject::MASTER).count}.by(1) + post api("/projects/#{project.code}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + end + + describe "PUT /projects/:id/members/:user_id" do + it "should update project team member" do + put api("/projects/#{project.code}/members/#{user3.id}", user), access_level: UsersProject::MASTER + response.status.should == 200 + json_response['email'].should == user3.email + json_response['access_level'].should == UsersProject::MASTER end end - describe "DELETE /projects/:id/users" do - it "should delete users from project" do + describe "DELETE /projects/:id/members/:user_id" do + it "should remove user from project team" do expect { - delete api("/projects/#{project.code}/users", user), - user_ids: {"0" => user3.id} - }.to change {project.users_projects.count}.by(-1) + delete api("/projects/#{project.code}/members/#{user3.id}", user) + }.to change { UsersProject.count }.by(-1) end end From 4a072be2d775d5ce59573cfb447ddab940854d54 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 04:34:07 -0700 Subject: [PATCH 15/34] API: commits belong to project repository --- doc/api/commits.md | 38 ------------------------------ doc/api/projects.md | 34 ++++++++++++++++++++++++++ lib/api.rb | 1 - lib/api/commits.rb | 29 ----------------------- lib/api/entities.rb | 9 ++++--- lib/api/projects.rb | 18 ++++++++++++++ spec/requests/api/commits_spec.rb | 29 ----------------------- spec/requests/api/projects_spec.rb | 21 +++++++++++++++++ 8 files changed, 77 insertions(+), 102 deletions(-) delete mode 100644 doc/api/commits.md delete mode 100644 lib/api/commits.rb delete mode 100644 spec/requests/api/commits_spec.rb diff --git a/doc/api/commits.md b/doc/api/commits.md deleted file mode 100644 index fccb35c33000..000000000000 --- a/doc/api/commits.md +++ /dev/null @@ -1,38 +0,0 @@ -## 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/doc/api/projects.md b/doc/api/projects.md index 1e23df3ac899..2d67bfa96743 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -355,6 +355,40 @@ Parameters: ] ``` +## Project repository commits + +Get a list of repository commits in a project. + +``` +GET /projects/:id/repository/commits +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `ref_name` (optional) - The name of a repository branch or tag + +```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" + } +] +``` + ## Raw blob content Get the raw file contents for a file. diff --git a/lib/api.rb b/lib/api.rb index f4e9e5fcc13a..3b62f31bf322 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -19,6 +19,5 @@ 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 deleted file mode 100644 index 47d96fc4906d..000000000000 --- a/lib/api/commits.rb +++ /dev/null @@ -1,29 +0,0 @@ -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 fd19fa0e87fd..ee6f15f12186 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -17,11 +17,6 @@ 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 @@ -39,6 +34,10 @@ class RepoObject < Grape::Entity expose :name, :commit end + class RepoCommit < Grape::Entity + expose :id, :short_id, :title, :author_name, :author_email, :created_at + end + class ProjectSnippet < Grape::Entity expose :id, :title, :file_name expose :author, using: Entities::UserBasic diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 0554d97c86bd..c3dc3da6facd 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -211,6 +211,24 @@ class Projects < Grape::API present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject end + # Get a project repository commits + # + # Parameters: + # id (required) - The ID or code name of a project + # ref_name (optional) - The name of a repository branch or tag + # Example Request: + # GET /projects/:id/repository/commits + get ":id/repository/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::RepoCommit + end + # Get a project snippet # # Parameters: diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb deleted file mode 100644 index 3af5ec21c432..000000000000 --- a/spec/requests/api/commits_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -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 diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 40a9147d726b..498bbad6179f 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -199,6 +199,27 @@ end end + describe "GET /projects/:id/repository/commits" do + context "authorized user" do + before { project.add_access(user2, :read) } + + it "should return project commits" do + get api("/projects/#{project.code}/repository/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 not return project commits" do + get api("/projects/#{project.code}/repository/commits") + response.status.should == 401 + end + end + end + describe "GET /projects/:id/snippets/:snippet_id" do it "should return a project snippet" do get api("/projects/#{project.code}/snippets/#{snippet.id}", user) From b62445813dffec92e85540ed081e4d6e12d58dc0 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 04:49:28 -0700 Subject: [PATCH 16/34] API: SSH keys belong to user entity --- doc/api/keys.md | 79 ------------------------------ doc/api/users.md | 78 +++++++++++++++++++++++++++++ lib/api.rb | 1 - lib/api/entities.rb | 4 +- lib/api/keys.rb | 50 ------------------- lib/api/users.rb | 59 +++++++++++++++++++--- spec/requests/api/ssh_keys_spec.rb | 73 --------------------------- spec/requests/api/users_spec.rb | 63 +++++++++++++++++++++++- 8 files changed, 195 insertions(+), 212 deletions(-) delete mode 100644 doc/api/keys.md delete mode 100644 lib/api/keys.rb delete mode 100644 spec/requests/api/ssh_keys_spec.rb diff --git a/doc/api/keys.md b/doc/api/keys.md deleted file mode 100644 index d22b22e20b89..000000000000 --- a/doc/api/keys.md +++ /dev/null @@ -1,79 +0,0 @@ -## List keys - -Get a list of currently authenticated user's keys. - -``` -GET /keys -``` - -```json -[ - { - "id": 1, - "title" : "Public key" - "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 - 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 - soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", - }, - { - "id": 3, - "title" : "Another Public key" - "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 - 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 - soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" - } -] -``` - -## Single key - -Get a single key. - -``` -GET /keys/:id -``` - -Parameters: - -+ `id` (required) - The ID of a key - -```json -{ - "id": 1, - "title" : "Public key" - "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 - 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 - soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" -} -``` -## Add key - -Create new key owned by currently authenticated user - -``` -POST /keys -``` - -Parameters: - -+ `title` (required) - new SSH Key's title -+ `key` (required) - new SSH key - -Will return created key with status `201 Created` on success, or `404 Not -found` on fail. - -## Delete key - -Delete key owned by currently authenticated user - -``` -DELETE /keys/:id -``` - -Parameters: - -+ `id` (required) - key ID - -Will return `200 OK` on success, or `404 Not Found` on fail. - - diff --git a/doc/api/users.md b/doc/api/users.md index b9b04dc5399a..4f806b145d15 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -88,3 +88,81 @@ GET /user "theme_id": 1 } ``` + +## List SSH keys + +Get a list of currently authenticated user's SSH keys. + +``` +GET /user/keys +``` + +```json +[ + { + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", + }, + { + "id": 3, + "title" : "Another Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" + } +] +``` + +## Single SSH key + +Get a single key. + +``` +GET /user/keys/:id +``` + +Parameters: + ++ `id` (required) - The ID of an SSH key + +```json +{ + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" +} +``` +## Add SSH key + +Create new key owned by currently authenticated user + +``` +POST /user/keys +``` + +Parameters: + ++ `title` (required) - new SSH Key's title ++ `key` (required) - new SSH key + +Will return created key with status `201 Created` on success, or `404 Not +found` on fail. + +## Delete SSH key + +Delete key owned by currently authenticated user + +``` +DELETE /user/keys/:id +``` + +Parameters: + ++ `id` (required) - SSH key ID + +Will return `200 OK` on success, or `404 Not Found` on fail. diff --git a/lib/api.rb b/lib/api.rb index 3b62f31bf322..2890a8cc9e8f 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -17,7 +17,6 @@ class API < Grape::API mount Projects mount Issues mount Milestones - mount Keys mount Session end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index ee6f15f12186..ee693de699e2 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -60,8 +60,8 @@ class Issue < Grape::Entity expose :closed, :updated_at, :created_at end - class Key < Grape::Entity - expose :id, :title, :key + class SSHKey < Grape::Entity + expose :id, :title, :key end end end diff --git a/lib/api/keys.rb b/lib/api/keys.rb deleted file mode 100644 index 4c302727c4fb..000000000000 --- a/lib/api/keys.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Gitlab - # Keys API - class Keys < Grape::API - before { authenticate! } - resource :keys do - # Get currently authenticated user's keys - # - # Example Request: - # GET /keys - get do - present current_user.keys, with: Entities::Key - end - # Get single key owned by currently authenticated user - # - # Example Request: - # GET /keys/:id - get "/:id" do - key = current_user.keys.find params[:id] - present key, with: Entities::Key - end - # Add new ssh key to currently authenticated user - # - # Parameters: - # key (required) - New SSH Key - # title (required) - New SSH Key's title - # Example Request: - # POST /keys - post do - attrs = attributes_for_keys [:title, :key] - key = current_user.keys.new attrs - if key.save - present key, with: Entities::Key - else - not_found! - end - end - # Delete existed ssh key of currently authenticated user - # - # Parameters: - # id (required) - SSH Key ID - # Example Request: - # DELETE /keys/:id - delete "/:id" do - key = current_user.keys.find params[:id] - key.delete - end - end - end -end - diff --git a/lib/api/users.rb b/lib/api/users.rb index 98ced6f8e5b1..0ca8fb2a1ae6 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -25,12 +25,59 @@ class Users < Grape::API end end - # Get currently authenticated user - # - # Example Request: - # GET /user - get "/user" do - present @current_user, with: Entities::User + resource :user do + # Get currently authenticated user + # + # Example Request: + # GET /user + get do + present @current_user, with: Entities::User + end + + # Get currently authenticated user's keys + # + # Example Request: + # GET /user/keys + get "keys" do + present current_user.keys, with: Entities::SSHKey + end + + # Get single key owned by currently authenticated user + # + # Example Request: + # GET /user/keys/:id + get "keys/:id" do + key = current_user.keys.find params[:id] + present key, with: Entities::SSHKey + end + + # Add new ssh key to currently authenticated user + # + # Parameters: + # key (required) - New SSH Key + # title (required) - New SSH Key's title + # Example Request: + # POST /user/keys + post "keys" do + attrs = attributes_for_keys [:title, :key] + key = current_user.keys.new attrs + if key.save + present key, with: Entities::SSHKey + else + not_found! + end + end + + # Delete existed ssh key of currently authenticated user + # + # Parameters: + # id (required) - SSH Key ID + # Example Request: + # DELETE /user/keys/:id + delete "keys/:id" do + key = current_user.keys.find params[:id] + key.delete + end end end end diff --git a/spec/requests/api/ssh_keys_spec.rb b/spec/requests/api/ssh_keys_spec.rb deleted file mode 100644 index 7fb8c920fb17..000000000000 --- a/spec/requests/api/ssh_keys_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Keys do - include ApiHelpers - let(:user) { - user = Factory.create :user - user.reset_authentication_token! - user - } - let(:key) { Factory.create :key, { user: user}} - - describe "GET /keys" do - context "when unauthenticated" do - it "should return authentication error" do - get api("/keys") - response.status.should == 401 - end - end - context "when authenticated" do - it "should return array of ssh keys" do - user.keys << key - user.save - get api("/keys", user) - response.status.should == 200 - json_response.should be_an Array - json_response.first["title"].should == key.title - end - end - end - - describe "GET /keys/:id" do - it "should returm single key" do - user.keys << key - user.save - get api("/keys/#{key.id}", user) - response.status.should == 200 - json_response["title"].should == key.title - end - it "should return 404 Not Found within invalid ID" do - get api("/keys/42", user) - response.status.should == 404 - end - end - - describe "POST /keys" do - it "should not create invalid ssh key" do - post api("/keys", user), { title: "invalid key" } - response.status.should == 404 - end - it "should create ssh key" do - key_attrs = Factory.attributes :key - expect { - post api("/keys", user), key_attrs - }.to change{ user.keys.count }.by(1) - end - end - - describe "DELETE /keys/:id" do - it "should delete existed key" do - user.keys << key - user.save - expect { - delete api("/keys/#{key.id}", user) - }.to change{user.keys.count}.by(-1) - end - it "should return 404 Not Found within invalid ID" do - delete api("/keys/42", user) - response.status.should == 404 - end - end - -end - diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index e25fe1341d5f..5d7ef99c481c 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -3,7 +3,8 @@ describe Gitlab::API do include ApiHelpers - let(:user) { Factory :user } + let(:user) { Factory :user } + let(:key) { Factory :key, user: user } describe "GET /users" do context "when unauthenticated" do @@ -38,4 +39,64 @@ json_response['email'].should == user.email end end + + describe "GET /user/keys" do + context "when unauthenticated" do + it "should return authentication error" do + get api("/user/keys") + response.status.should == 401 + end + end + context "when authenticated" do + it "should return array of ssh keys" do + user.keys << key + user.save + get api("/user/keys", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first["title"].should == key.title + end + end + end + + describe "GET /user/keys/:id" do + it "should returm single key" do + user.keys << key + user.save + get api("/user/keys/#{key.id}", user) + response.status.should == 200 + json_response["title"].should == key.title + end + it "should return 404 Not Found within invalid ID" do + get api("/user/keys/42", user) + response.status.should == 404 + end + end + + describe "POST /user/keys" do + it "should not create invalid ssh key" do + post api("/user/keys", user), { title: "invalid key" } + response.status.should == 404 + end + it "should create ssh key" do + key_attrs = Factory.attributes :key + expect { + post api("/user/keys", user), key_attrs + }.to change{ user.keys.count }.by(1) + end + end + + describe "DELETE /user/keys/:id" do + it "should delete existed key" do + user.keys << key + user.save + expect { + delete api("/user/keys/#{key.id}", user) + }.to change{user.keys.count}.by(-1) + end + it "should return 404 Not Found within invalid ID" do + delete api("/user/keys/42", user) + response.status.should == 404 + end + end end From 1bae64d7f608e3d68d52fd59755216db6c70f7f4 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 04:53:13 -0700 Subject: [PATCH 17/34] whitespace --- spec/requests/api/users_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 5d7ef99c481c..243f70f5230d 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -47,6 +47,7 @@ response.status.should == 401 end end + context "when authenticated" do it "should return array of ssh keys" do user.keys << key @@ -67,6 +68,7 @@ response.status.should == 200 json_response["title"].should == key.title end + it "should return 404 Not Found within invalid ID" do get api("/user/keys/42", user) response.status.should == 404 @@ -78,6 +80,7 @@ post api("/user/keys", user), { title: "invalid key" } response.status.should == 404 end + it "should create ssh key" do key_attrs = Factory.attributes :key expect { @@ -94,6 +97,7 @@ delete api("/user/keys/#{key.id}", user) }.to change{user.keys.count}.by(-1) end + it "should return 404 Not Found within invalid ID" do delete api("/user/keys/42", user) response.status.should == 404 From 130433158981bd4f95121060d75d8fb56c14f80d Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 05:00:20 -0700 Subject: [PATCH 18/34] remove commits API section from help --- app/views/help/api.html.haml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index 1f0ce8793818..d317bfa7bfe1 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -19,8 +19,6 @@ = link_to "Issues", "#issues", 'data-toggle' => 'tab' %li = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' - %li - = link_to "Commits", "#commits", 'data-toggle' => 'tab' .tab-content .tab-pane.active#README @@ -85,12 +83,3 @@ .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")) From 4162566e11d9239d82b532e34c503ad1cbfe4d78 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 05:03:50 -0700 Subject: [PATCH 19/34] separate project repositories API docs --- app/views/help/api.html.haml | 11 +++ doc/api/projects.md | 166 ----------------------------------- doc/api/repositories.md | 166 +++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 166 deletions(-) create mode 100644 doc/api/repositories.md diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index d317bfa7bfe1..00085166bcf9 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -11,6 +11,8 @@ = link_to "Projects", "#projects", 'data-toggle' => 'tab' %li = link_to "Snippets", "#snippets", 'data-toggle' => 'tab' + %li + = link_to "Repositories", "#repositories", 'data-toggle' => 'tab' %li = link_to "Users", "#users", 'data-toggle' => 'tab' %li @@ -48,6 +50,15 @@ = preserve do = markdown File.read(Rails.root.join("doc", "api", "snippets.md")) + .tab-pane#repositories + .file_holder + .file_title + %i.icon-file + Projects + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "repositories.md")) + .tab-pane#users .file_holder .file_title diff --git a/doc/api/projects.md b/doc/api/projects.md index 2d67bfa96743..d06a41c2d744 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -239,169 +239,3 @@ Parameters: + `hook_id` (required) - The ID of hook to delete Will return status `200 OK` on success, or `404 Not found` on fail. - -## Project repository branches - -Get a list of repository branches from a project, sorted by name alphabetically. - -``` -GET /projects/:id/repository/branches -``` - -Parameters: - -+ `id` (required) - The ID or code name of a project - -```json -[ - { - "name": "master", - "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" - } - } -] -``` - -Get a single project repository branch. - -``` -GET /projects/:id/repository/branches/:branch -``` - -Parameters: - -+ `id` (required) - The ID or code name of a project -+ `branch` (required) - The name of the branch - -```json -{ - "name": "master", - "commit": { - "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", - "parents": [ - { - "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" - } - ], - "tree": "46e82de44b1061621357f24c05515327f2795a95", - "message": "add projects API", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "John Smith", - "email": "john@example.com" - }, - "authored_date": "2012-06-27T05:51:39-07:00", - "committed_date": "2012-06-28T03:44:20-07:00" - } -} -``` - -## Project repository tags - -Get a list of repository tags from a project, sorted by name in reverse alphabetical order. - -``` -GET /projects/:id/repository/tags -``` - -Parameters: - -+ `id` (required) - The ID or code name of a project - -```json -[ - { - "name": "v1.0.0", - "commit": { - "id": "2695effb5807a22ff3d138d593fd856244e155e7", - "parents": [ - - ], - "tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d", - "message": "Initial commit", - "author": { - "name": "John Smith", - "email": "john@example.com" - }, - "committer": { - "name": "Jack Smith", - "email": "jack@example.com" - }, - "authored_date": "2012-05-28T04:42:42-07:00", - "committed_date": "2012-05-28T04:42:42-07:00" - } - } -] -``` - -## Project repository commits - -Get a list of repository commits in a project. - -``` -GET /projects/:id/repository/commits -``` - -Parameters: - -+ `id` (required) - The ID or code name of a project -+ `ref_name` (optional) - The name of a repository branch or tag - -```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" - } -] -``` - -## Raw blob content - -Get the raw file contents for a file. - -``` -GET /projects/:id/repository/commits/:sha/blob -``` - -Parameters: - -+ `id` (required) - The ID or code name of a project -+ `sha` (required) - The commit or branch name -+ `filepath` (required) - The path the file - -Will return the raw file contents. - diff --git a/doc/api/repositories.md b/doc/api/repositories.md new file mode 100644 index 000000000000..487ad9b27184 --- /dev/null +++ b/doc/api/repositories.md @@ -0,0 +1,166 @@ +## Project repository branches + +Get a list of repository branches from a project, sorted by name alphabetically. + +``` +GET /projects/:id/repository/branches +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project + +```json +[ + { + "name": "master", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "parents": [ + { + "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + } + ], + "tree": "46e82de44b1061621357f24c05515327f2795a95", + "message": "add projects API", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "John Smith", + "email": "john@example.com" + }, + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00" + } + } +] +``` + +## Project repository branch + +Get a single project repository branch. + +``` +GET /projects/:id/repository/branches/:branch +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `branch` (required) - The name of the branch + +```json +{ + "name": "master", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "parents": [ + { + "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + } + ], + "tree": "46e82de44b1061621357f24c05515327f2795a95", + "message": "add projects API", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "John Smith", + "email": "john@example.com" + }, + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00" + } +} +``` + +## Project repository tags + +Get a list of repository tags from a project, sorted by name in reverse alphabetical order. + +``` +GET /projects/:id/repository/tags +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project + +```json +[ + { + "name": "v1.0.0", + "commit": { + "id": "2695effb5807a22ff3d138d593fd856244e155e7", + "parents": [ + + ], + "tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d", + "message": "Initial commit", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "Jack Smith", + "email": "jack@example.com" + }, + "authored_date": "2012-05-28T04:42:42-07:00", + "committed_date": "2012-05-28T04:42:42-07:00" + } + } +] +``` + +## Project repository commits + +Get a list of repository commits in a project. + +``` +GET /projects/:id/repository/commits +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `ref_name` (optional) - The name of a repository branch or tag + +```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" + } +] +``` + +## Raw blob content + +Get the raw file contents for a file. + +``` +GET /projects/:id/repository/commits/:sha/blob +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `sha` (required) - The commit or branch name ++ `filepath` (required) - The path the file + +Will return the raw file contents. From bbdb2c3fef5a71802131c08226d7f4dfa18ddd89 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Fri, 21 Sep 2012 05:06:36 -0700 Subject: [PATCH 20/34] fix links in API README --- doc/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 443ec7bf1ca0..36a36f8f6a4d 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -33,6 +33,6 @@ When listing resources you can pass the following parameters: + [Session](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/session.md) + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) + [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.md) ++ [Repositories](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/repositories.md) + [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) + [Milestones](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/milestones.md) -+ [SSH Keys](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/keys.md) From 2cd0caaf7300d18a565cfe304997b42bca12a947 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 22 Sep 2012 11:20:04 -0400 Subject: [PATCH 21/34] Rename 4_resque_queues initializer to 4_resque --- config/initializers/{4_resque_queues.rb => 4_resque.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/initializers/{4_resque_queues.rb => 4_resque.rb} (100%) diff --git a/config/initializers/4_resque_queues.rb b/config/initializers/4_resque.rb similarity index 100% rename from config/initializers/4_resque_queues.rb rename to config/initializers/4_resque.rb From 6ddbee5d89b3ea0e5d2a8f2b72416dcb7ab39fe5 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 22 Sep 2012 11:23:12 -0400 Subject: [PATCH 22/34] Consolidate all Resque-related initializers into "4_resque" --- config/initializers/4_resque.rb | 30 ++++++++++++++++++++ config/initializers/resque.rb | 8 ------ config/initializers/resque_authentication.rb | 14 --------- config/initializers/resque_mailer.rb | 1 - 4 files changed, 30 insertions(+), 23 deletions(-) delete mode 100644 config/initializers/resque.rb delete mode 100644 config/initializers/resque_authentication.rb delete mode 100644 config/initializers/resque_mailer.rb diff --git a/config/initializers/4_resque.rb b/config/initializers/4_resque.rb index 5b0087ab0252..2a5721ec742c 100644 --- a/config/initializers/4_resque.rb +++ b/config/initializers/4_resque.rb @@ -1 +1,31 @@ +# Custom Redis configuration +rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..' +rails_env = ENV['RAILS_ENV'] || 'development' +config_file = File.join(rails_root, 'config', 'resque.yml') + +if File.exists?(config_file) + resque_config = YAML.load_file(config_file) + Resque.redis = resque_config[rails_env] +end + +# Queues Resque.watch_queue(PostReceive.instance_variable_get("@queue")) + +# Authentication +require 'resque/server' +class Authentication + def initialize(app) + @app = app + end + + def call(env) + account = env['warden'].authenticate!(:database_authenticatable, :rememberable, scope: :user) + raise "Access denied" if !account.admin? + @app.call(env) + end +end + +Resque::Server.use Authentication + +# Mailer +Resque::Mailer.excluded_environments = [] diff --git a/config/initializers/resque.rb b/config/initializers/resque.rb deleted file mode 100644 index b333ceeea1ae..000000000000 --- a/config/initializers/resque.rb +++ /dev/null @@ -1,8 +0,0 @@ -rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..' -rails_env = ENV['RAILS_ENV'] || 'development' -config_file = File.join(rails_root, 'config', 'resque.yml') - -if File.exists?(config_file) - resque_config = YAML.load_file(config_file) - Resque.redis = resque_config[rails_env] -end diff --git a/config/initializers/resque_authentication.rb b/config/initializers/resque_authentication.rb deleted file mode 100644 index a439d3228047..000000000000 --- a/config/initializers/resque_authentication.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'resque/server' -class Authentication - def initialize(app) - @app = app - end - - def call(env) - account = env['warden'].authenticate!(:database_authenticatable, :rememberable, scope: :user) - raise "Access denied" if !account.admin? - @app.call(env) - end -end - -Resque::Server.use Authentication \ No newline at end of file diff --git a/config/initializers/resque_mailer.rb b/config/initializers/resque_mailer.rb deleted file mode 100644 index cec9dec9d0ef..000000000000 --- a/config/initializers/resque_mailer.rb +++ /dev/null @@ -1 +0,0 @@ -Resque::Mailer.excluded_environments = [] From ad3eefdcb8cf08007c45876afea20109b5984876 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 22 Sep 2012 17:06:19 -0400 Subject: [PATCH 23/34] Minor grammar change [ci skip] --- app/views/events/_event_last_push.html.haml | 2 +- features/steps/dashboard/dashboard.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml index aa1d28f2be31..81b9994cff5c 100644 --- a/app/views/events/_event_last_push.html.haml +++ b/app/views/events/_event_last_push.html.haml @@ -2,7 +2,7 @@ .event_lp %div = image_tag gravatar_icon(event.author_email), class: "avatar" - %span Your pushed to + %span You pushed to = event.ref_type = link_to project_commits_path(event.project, ref: event.ref_name) do %strong= truncate(event.ref_name, length: 28) diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index 6c603bbea558..154b97e34d36 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -16,7 +16,7 @@ class Dashboard < Spinach::FeatureSteps end Then 'I should see last push widget' do - page.should have_content "Your pushed to branch new_design" + page.should have_content "You pushed to branch new_design" page.should have_link "Create Merge Request" end From 80bcba4ee25b34052c920d2c8ff58f7a72b44852 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Sun, 23 Sep 2012 08:53:48 -0700 Subject: [PATCH 24/34] install jquery-atwho-rails --- Gemfile | 1 + Gemfile.lock | 2 ++ app/assets/javascripts/application.js | 1 + app/assets/stylesheets/application.css | 1 + 4 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 8e569c5b2e52..3024d92c3cc6 100644 --- a/Gemfile +++ b/Gemfile @@ -96,6 +96,7 @@ group :assets do gem "therubyracer" gem 'chosen-rails' + gem 'jquery-atwho-rails', '0.1.6' gem "jquery-rails", "2.0.2" gem "jquery-ui-rails", "0.5.0" gem "modernizr", "2.5.3" diff --git a/Gemfile.lock b/Gemfile.lock index 3d27d3fbe816..e517bb36f2c2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -199,6 +199,7 @@ GEM httpauth (0.1) i18n (0.6.1) journey (1.0.4) + jquery-atwho-rails (0.1.6) jquery-rails (2.0.2) railties (>= 3.2.0, < 5.0) thor (~> 0.14) @@ -440,6 +441,7 @@ DEPENDENCIES haml-rails headless httparty + jquery-atwho-rails (= 0.1.6) jquery-rails (= 2.0.2) jquery-ui-rails (= 0.5.0) kaminari diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f9fdb0f7dc2b..02ef6caba386 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,6 +11,7 @@ //= require jquery.endless-scroll //= require jquery.highlight //= require jquery.waitforimages +//= require jquery.atwho //= require bootstrap //= require modernizr //= require chosen-jquery diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 92d542a9866d..424ba71f7cbe 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -4,6 +4,7 @@ * the top of the compiled file, but it's generally better to create a new file per style scope. *= require jquery.ui.all *= require jquery.ui.aristo + *= require jquery.atwho *= require chosen *= require_self *= require main From 9c75fcbef16e68dd3898545fc5d11b1261de1a26 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Sun, 23 Sep 2012 09:52:01 -0700 Subject: [PATCH 25/34] auto complete team member mentions --- app/views/notes/_common_form.html.haml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/views/notes/_common_form.html.haml b/app/views/notes/_common_form.html.haml index fc6e3c7ee6eb..f91e921bbc7d 100644 --- a/app/views/notes/_common_form.html.haml +++ b/app/views/notes/_common_form.html.haml @@ -37,3 +37,8 @@ = f.file_field :attachment, class: "input-file" %span.hint Any file less than 10 MB +:javascript + $(function(){ + var names = #{@project.users.pluck(:name)}; + $('.note-text').atWho('@', { data: names }); + }); From c701507b6cf9ab4099d4d5847516436ca35658d8 Mon Sep 17 00:00:00 2001 From: Staicu Ionut Date: Mon, 24 Sep 2012 10:06:41 +0300 Subject: [PATCH 26/34] Removed float on emoji -`remove comment` button will not make the text jump anymore. --- app/assets/stylesheets/sections/notes.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 267a9b4356c6..d24d070df1ea 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -43,7 +43,9 @@ padding: 8px 0; overflow: hidden; display: block; + position:relative; img {float: left; margin-right: 10px;} + img.emoji {float:none;margin:0;} .note-author cite{font-style: italic;} p { color:$style_color; } .note-author { color: $style_color;} @@ -55,7 +57,9 @@ .delete-note { display:none; - float:right; + position:absolute; + right:0; + top:0; } &:hover { From a6f58b9c435e1680f102ae68a8aedea981a52486 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Sep 2012 10:45:55 +0300 Subject: [PATCH 27/34] Up to v2.9.1 --- CHANGELOG | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 99641ad3a95b..3fec2d86dfc7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v 2.9.1 + - Fixed resque custom config init + v 2.9.0 - fixed inline notes bugs - refactored rspecs diff --git a/VERSION b/VERSION index c8e38b614057..dedcc7d4335d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.9.0 +2.9.1 From d23022c6f68bd78a1d3b63a8bf7551145b1f46fd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Sep 2012 12:32:51 +0300 Subject: [PATCH 28/34] Working on dashboard restyle and events refactoring --- app/assets/stylesheets/common.scss | 81 -------------- .../stylesheets/gitlab_bootstrap/lists.scss | 4 +- app/assets/stylesheets/main.scss | 1 + app/assets/stylesheets/sections/commits.scss | 46 ++++---- app/assets/stylesheets/sections/events.scss | 105 ++++++++++++++++++ app/views/events/_commit.html.haml | 2 +- app/views/events/_event.html.haml | 17 +-- app/views/events/_event_issue.html.haml | 18 ++- .../_event_membership_changed.html.haml | 15 +-- .../events/_event_merge_request.html.haml | 26 ++--- app/views/events/_event_push.html.haml | 49 ++++---- 11 files changed, 194 insertions(+), 170 deletions(-) create mode 100644 app/assets/stylesheets/sections/events.scss diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index c5b379160867..f13a1d6d196e 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -185,36 +185,6 @@ span.update-author { } } -.event_label { - @extend .label; - background-color: #999; - - &.pushed { - background-color: #4A97BD; - } - - &.opened { - background-color: #469847; - } - - &.closed { - background-color: #B94A48; - } - - &.merged { - background-color: #2A2; - } - - &.joined { - background-color: #1ca9dd; - } - - &.left { - background-color: #888; - float:none; - } -} - form { @extend .form-horizontal; @@ -355,41 +325,6 @@ p.time { border:2px solid #ddd; } -.event_feed { - min-height:40px; - border-bottom:1px solid #ddd; - .avatar { - width:32px; - } - .event_icon { - float:right; - margin-right:2px; - img { - width:20px; - } - } - ul { - margin-left:50px; - margin-bottom:5px; - .avatar { - width:24px; - } - } - - padding: 15px 5px; - &:last-child { border:none } - .wll:hover { background:none } - - .event_commits { - margin-top: 5px; - - li.commit { - background: transparent; - padding:5px; - border:none; - } - } -} .ico { background: url("images.png") no-repeat -85px -77px; @@ -639,22 +574,6 @@ li.note { background:#fff; } -/** - * Push event widget - * - */ -.event_lp { - @extend .ui-box; - color:#777; - margin-bottom:20px; - padding:8px; - @include border-radius(4px); - min-height:22px; - - .avatar { - width:24px; - } -} .supp_diff_link, .mr_show_all_commits { diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss index 402ba04bd00d..5585c35c0890 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss @@ -1,6 +1,6 @@ /** LISTS **/ -ul { +ul { /** * List li block element #1 * @@ -18,7 +18,7 @@ ul { .author { color: #999; } p { - padding-top:5px; + padding-top:5px; margin:0; color:#222; img { diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 75001d3a7c34..14b289c0a5dc 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -143,6 +143,7 @@ $hover: #fdf5d9; @import "sections/projects.scss"; @import "sections/merge_requests.scss"; @import "sections/graph.scss"; +@import "sections/events.scss"; /** * This scss file redefine chozen selectbox styles for diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 75e38aeea93c..33b051351f38 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -1,7 +1,7 @@ .commit-box { @extend .main_box; - .commit-head { + .commit-head { @extend .top_box_content; .commit-title { @@ -29,11 +29,11 @@ .sha-block { text-align:right; - &:first-child { + &:first-child { padding-bottom:6px; } - a { + a { border-bottom: 1px solid #aaa; margin-left: 9px; } @@ -54,7 +54,7 @@ } /** - * + * * COMMIT SHOw * */ @@ -71,7 +71,7 @@ background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); - span { + span { font-size:14px; } } @@ -111,8 +111,8 @@ } } - &.img_compared { - img { + &.img_compared { + img { max-width:300px; } } @@ -120,12 +120,12 @@ } .diff_file_content{ - table { + table { border:none; margin:0px; padding:0px; tr { - td { + td { font-size:12px; } } @@ -145,29 +145,29 @@ moz-user-select: none; -khtml-user-select: none; user-select: none; - a { + a { float:left; width:35px; font-weight:normal; color:#666; - &:hover { + &:hover { text-decoration:underline; } } } - .line_content { - white-space:pre; + .line_content { + white-space:pre; height:14px; margin:0px; padding:0px; border:none; - &.new { + &.new { background: #CFD; } - &.old { + &.old { background: #FDD; } - &.matched { + &.matched { color:#ccc; background:#fafafa; } @@ -182,32 +182,32 @@ /** COMMIT ROW **/ -.commit { +.commit { @extend .wll; - .browse_code_link_holder { + .browse_code_link_holder { @extend .span2; float:right; } - .committed_ago { + .committed_ago { float:right; @extend .cgray; } - code { + code { background:#FCEEC1; color:$style_color; } - .commit_short_id { + .commit_short_id { float:left; @extend .lined; min-width:65px; font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; } - - .commit-author-name { + + .commit-author-name { color: #777; } } diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss new file mode 100644 index 000000000000..7c414d052d33 --- /dev/null +++ b/app/assets/stylesheets/sections/events.scss @@ -0,0 +1,105 @@ +/** + * Events labels + * + */ +.event_label { + /*@extend .label;*/ + /*background-color: #999;*/ + + /*&.pushed {*/ + /*background-color: #4A97BD;*/ + /*}*/ + + /*&.opened {*/ + /*background-color: #469847;*/ + /*}*/ + + /*&.closed {*/ + /*background-color: #B94A48;*/ + /*}*/ + + /*&.merged {*/ + /*background-color: #2A2;*/ + /*}*/ + + /*&.joined {*/ + /*background-color: #1ca9dd;*/ + /*}*/ + + /*&.left {*/ + /*background-color: #888;*/ + /*float:none;*/ + /*}*/ +} + +/** + * Dashboard events feed + * + */ +.event-item { + min-height:40px; + border-bottom:1px solid #eee; + .event-title { + color:#333; + font-weight: bold; + .author_name { + color:#777; + } + } + .event-body { + p { + color:#666; + } + } + .avatar { + width:32px; + } + .event_icon { + float: right; + border: 1px solid #EEE; + padding: 5px; + @include border-radius(5px); + background: #F9F9F9; + img { + width:20px; + } + } + ul { + margin-left:50px; + margin-bottom:5px; + .avatar { + width:22px; + } + } + + padding: 15px 5px; + &:last-child { border:none } + .wll:hover { background:none } + + .event_commits { + margin-top: 5px; + + li.commit { + background: transparent; + padding:5px; + border:none; + } + } +} + +/** + * Push event widget + * + */ +.event_lp { + @extend .ui-box; + color:#777; + margin-bottom:20px; + padding:8px; + @include border-radius(4px); + min-height:22px; + + .avatar { + width:24px; + } +} diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml index cb25d831bca4..ed4f33c0187f 100644 --- a/app/views/events/_commit.html.haml +++ b/app/views/events/_commit.html.haml @@ -2,7 +2,7 @@ %li.commit %p = link_to commit.short_id(8), project_commit_path(project, id: commit.id), class: "commit_short_id" - %strong.cdark= commit.author_name + %span= commit.author_name – = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 = gfm escape_once(truncate(commit.title, length: 50)) rescue "--broken encoding" diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 7bae8db13f7c..716a214b9bfc 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,17 +1,18 @@ - if event.allowed? - - if event.issue? - .event_feed + %div.event-item + - if event.issue? = render "events/event_issue", event: event - - elsif event.merge_request? - .event_feed + - elsif event.merge_request? = render "events/event_merge_request", event: event - - elsif event.push? - .event_feed + - elsif event.push? = render "events/event_push", event: event - - elsif event.membership_changed? - .event_feed + - elsif event.membership_changed? = render "events/event_membership_changed", event: event + %span.cgray.right + = time_ago_in_words(event.created_at) + ago. + .clearfix diff --git a/app/views/events/_event_issue.html.haml b/app/views/events/_event_issue.html.haml index 4d357b7f9122..6ac695240be7 100644 --- a/app/views/events/_event_issue.html.haml +++ b/app/views/events/_event_issue.html.haml @@ -1,11 +1,9 @@ = image_tag gravatar_icon(event.author_email), class: "avatar" -%strong #{event.author_name} -%span.event_label{class: event.action_name}= event.action_name -issue -= link_to project_issue_path(event.project, event.issue) do - %strong= truncate event.issue_title -at -%strong= link_to event.project.name, event.project -%span.cgray - = time_ago_in_words(event.created_at) - ago. +.event-title + %strong.author_name #{event.author_name} + %span.event_label{class: event.action_name}= event.action_name + issue + = link_to project_issue_path(event.project, event.issue) do + %strong= truncate event.issue_title + at + %strong= link_to event.project.name, event.project diff --git a/app/views/events/_event_membership_changed.html.haml b/app/views/events/_event_membership_changed.html.haml index 464f24b3f037..1c11f9935955 100644 --- a/app/views/events/_event_membership_changed.html.haml +++ b/app/views/events/_event_membership_changed.html.haml @@ -1,9 +1,10 @@ = image_tag gravatar_icon(event.author_email), class: "avatar" -%strong #{event.author_name} -%span.event_label{class: event.action_name}= event.action_name -project -%strong= link_to event.project_name, event.project -%span.cgray - = time_ago_in_words(event.created_at) - ago. +.event-title + %strong.author_name #{event.author_name} + %span.event_label{class: event.action_name}= event.action_name + project + %strong= link_to event.project_name, event.project + %span.cgray + = time_ago_in_words(event.created_at) + ago. diff --git a/app/views/events/_event_merge_request.html.haml b/app/views/events/_event_merge_request.html.haml index ceb39371a3a8..fe9616129d4e 100644 --- a/app/views/events/_event_merge_request.html.haml +++ b/app/views/events/_event_merge_request.html.haml @@ -1,18 +1,16 @@ - if event.action_name == "merged" .event_icon= image_tag "event_mr_merged.png" = image_tag gravatar_icon(event.author_email), class: "avatar" -%strong #{event.author_name} -%span.event_label{class: event.action_name}= event.action_name -merge request -= link_to project_merge_request_path(event.project, event.merge_request) do - %strong= truncate event.merge_request_title -at -%strong= link_to event.project.name, event.project -%span.cgray - = time_ago_in_words(event.created_at) - ago. -%br -%span= event.merge_request.source_branch -→ -%span= event.merge_request.target_branch +.event-title + %strong.author_name #{event.author_name} + %span.event_label{class: event.action_name}= event.action_name + merge request + = link_to project_merge_request_path(event.project, event.merge_request) do + %strong= truncate event.merge_request_title + at + %strong= link_to event.project.name, event.project +.event-body + %span= event.merge_request.source_branch + → + %span= event.merge_request.target_branch diff --git a/app/views/events/_event_push.html.haml b/app/views/events/_event_push.html.haml index 0adcaf9d10e1..1cedd27feb0c 100644 --- a/app/views/events/_event_push.html.haml +++ b/app/views/events/_event_push.html.haml @@ -1,30 +1,31 @@ %div .event_icon= image_tag "event_push.png" = image_tag gravatar_icon(event.author_email), class: "avatar" - %strong #{event.author_name} - %span.event_label.pushed= event.push_action_name - = event.ref_type - = link_to project_commits_path(event.project, ref: event.ref_name) do - %strong= event.ref_name - at - %strong= link_to event.project.name, event.project - %span.cgray - = time_ago_in_words(event.created_at) - ago. + + .event-title + %strong.author_name #{event.author_name} + %span.event_label.pushed= event.push_action_name + = event.ref_type + = link_to project_commits_path(event.project, ref: event.ref_name) do + %strong= event.ref_name + at + %strong= link_to event.project.name, event.project + - if event.push_with_commits? + - if event.commits_count > 1 + = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do + %strong #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} - if event.push_with_commits? - - if event.commits_count > 1 - = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do - %strong #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} - project = event.project - %ul.unstyled.event_commits - - if event.commits_count > 3 - - event.commits[0...2].each do |commit| - = render "events/commit", commit: commit, project: project - %li - %br - \... and #{event.commits_count - 2} more commits - - else - - event.commits.each do |commit| - = render "events/commit", commit: commit, project: project - + .event-body + %ul.unstyled.event_commits + - if event.commits_count > 3 + - event.commits[0...2].each do |commit| + = render "events/commit", commit: commit, project: project + %li + %br + \... and #{event.commits_count - 2} more commits + - else + - event.commits.each do |commit| + = render "events/commit", commit: commit, project: project + .clearfix From 6667f3dbf920d9bcf0e6f3218d27c92811f74224 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Sep 2012 13:33:51 +0300 Subject: [PATCH 29/34] Colored labels for events --- app/assets/stylesheets/sections/events.scss | 53 ++++++++++--------- app/models/event.rb | 1 + app/views/events/_event_issue.html.haml | 3 +- .../_event_membership_changed.html.haml | 3 +- .../events/_event_merge_request.html.haml | 10 ++-- app/views/events/_event_push.html.haml | 3 +- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 7c414d052d33..0fb010d33861 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -3,33 +3,35 @@ * */ .event_label { - /*@extend .label;*/ - /*background-color: #999;*/ - - /*&.pushed {*/ - /*background-color: #4A97BD;*/ - /*}*/ - - /*&.opened {*/ - /*background-color: #469847;*/ - /*}*/ + &.pushed { + padding:0 2px; + @extend .alert; + @extend .alert-info; + } - /*&.closed {*/ - /*background-color: #B94A48;*/ - /*}*/ + &.opened { + padding:0 2px; + @extend .alert; + @extend .alert-success; + } - /*&.merged {*/ - /*background-color: #2A2;*/ - /*}*/ + &.closed { + padding:0 2px; + @extend .alert; + @extend .alert-error; + } - /*&.joined {*/ - /*background-color: #1ca9dd;*/ - /*}*/ + &.merged { + padding:0 2px; + @extend .alert; + @extend .alert-success; + } - /*&.left {*/ - /*background-color: #888;*/ - /*float:none;*/ - /*}*/ + &.left, + &.joined { + padding:0 2px; + @extend .alert; + } } /** @@ -43,13 +45,16 @@ color:#333; font-weight: bold; .author_name { - color:#777; + color:#333; } } .event-body { p { color:#666; } + .event-info { + color:#666; + } } .avatar { width:32px; diff --git a/app/models/event.rb b/app/models/event.rb index b11b21bda3b8..dc76b6fd022e 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -132,6 +132,7 @@ def action_name end end + delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :title, to: :issue, prefix: true, allow_nil: true delegate :title, to: :merge_request, prefix: true, allow_nil: true diff --git a/app/views/events/_event_issue.html.haml b/app/views/events/_event_issue.html.haml index 6ac695240be7..60e82c4d4dc5 100644 --- a/app/views/events/_event_issue.html.haml +++ b/app/views/events/_event_issue.html.haml @@ -1,8 +1,7 @@ = image_tag gravatar_icon(event.author_email), class: "avatar" .event-title %strong.author_name #{event.author_name} - %span.event_label{class: event.action_name}= event.action_name - issue + %span.event_label{class: event.action_name} #{event.action_name} issue = link_to project_issue_path(event.project, event.issue) do %strong= truncate event.issue_title at diff --git a/app/views/events/_event_membership_changed.html.haml b/app/views/events/_event_membership_changed.html.haml index 1c11f9935955..e89065b91efc 100644 --- a/app/views/events/_event_membership_changed.html.haml +++ b/app/views/events/_event_membership_changed.html.haml @@ -1,8 +1,7 @@ = image_tag gravatar_icon(event.author_email), class: "avatar" .event-title %strong.author_name #{event.author_name} - %span.event_label{class: event.action_name}= event.action_name - project + %span.event_label{class: event.action_name} #{event.action_name} project %strong= link_to event.project_name, event.project %span.cgray = time_ago_in_words(event.created_at) diff --git a/app/views/events/_event_merge_request.html.haml b/app/views/events/_event_merge_request.html.haml index fe9616129d4e..655337f34804 100644 --- a/app/views/events/_event_merge_request.html.haml +++ b/app/views/events/_event_merge_request.html.haml @@ -3,14 +3,14 @@ = image_tag gravatar_icon(event.author_email), class: "avatar" .event-title %strong.author_name #{event.author_name} - %span.event_label{class: event.action_name}= event.action_name - merge request + %span.event_label{class: event.action_name} #{event.action_name} merge request = link_to project_merge_request_path(event.project, event.merge_request) do %strong= truncate event.merge_request_title at %strong= link_to event.project.name, event.project .event-body - %span= event.merge_request.source_branch - → - %span= event.merge_request.target_branch + .event-info + %span= event.merge_request.source_branch + → + %span= event.merge_request.target_branch diff --git a/app/views/events/_event_push.html.haml b/app/views/events/_event_push.html.haml index 1cedd27feb0c..a1bbc124d204 100644 --- a/app/views/events/_event_push.html.haml +++ b/app/views/events/_event_push.html.haml @@ -4,8 +4,7 @@ .event-title %strong.author_name #{event.author_name} - %span.event_label.pushed= event.push_action_name - = event.ref_type + %span.event_label.pushed #{event.push_action_name} #{event.ref_type} = link_to project_commits_path(event.project, ref: event.ref_name) do %strong= event.ref_name at From c3efcf7a626ca2621b6fc9977aae8740ed7b10a8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 25 Sep 2012 13:14:20 +0300 Subject: [PATCH 30/34] Pollished push event --- app/assets/stylesheets/sections/events.scss | 20 +++++++++++++------ app/views/events/_event_push.html.haml | 22 +++++++++------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 0fb010d33861..db034e25bb50 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -50,7 +50,7 @@ } .event-body { p { - color:#666; + color:#555; } .event-info { color:#666; @@ -73,7 +73,8 @@ margin-left:50px; margin-bottom:5px; .avatar { - width:22px; + width:18px; + margin-top:3px; } } @@ -84,10 +85,17 @@ .event_commits { margin-top: 5px; - li.commit { - background: transparent; - padding:5px; - border:none; + li { + &.commit { + background: transparent; + padding:3px; + border:none; + font-size:12px; + } + &.commits-stat { + display: block; + margin-top: 5px; + } } } } diff --git a/app/views/events/_event_push.html.haml b/app/views/events/_event_push.html.haml index a1bbc124d204..c0be9cf52309 100644 --- a/app/views/events/_event_push.html.haml +++ b/app/views/events/_event_push.html.haml @@ -9,22 +9,18 @@ %strong= event.ref_name at %strong= link_to event.project.name, event.project - - if event.push_with_commits? - - if event.commits_count > 1 - = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do - %strong #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} - if event.push_with_commits? - project = event.project .event-body %ul.unstyled.event_commits - - if event.commits_count > 3 - - event.commits[0...2].each do |commit| - = render "events/commit", commit: commit, project: project - %li - %br - \... and #{event.commits_count - 2} more commits - - else - - event.commits.each do |commit| - = render "events/commit", commit: commit, project: project + - few_commits = event.commits[0...2] + - few_commits.each do |commit| + = render "events/commit", commit: commit, project: project + + %li.commits-stat + - if event.commits_count > 2 + %span ... and #{event.commits_count - 2} more commits. + = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do + %strong Compare → #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} .clearfix From 6df515a56dd426abd6a65cfeb2a75305c04eed6e Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Tue, 25 Sep 2012 04:56:21 -0700 Subject: [PATCH 31/34] add auto-completion for +1, -1 emoji --- app/views/notes/_common_form.html.haml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/views/notes/_common_form.html.haml b/app/views/notes/_common_form.html.haml index f91e921bbc7d..626a448c2294 100644 --- a/app/views/notes/_common_form.html.haml +++ b/app/views/notes/_common_form.html.haml @@ -39,6 +39,12 @@ :javascript $(function(){ - var names = #{@project.users.pluck(:name)}; - $('.note-text').atWho('@', { data: names }); + var names = #{@project.users.pluck(:name)}, emoji = ['+1', '-1']; + var emoji = $.map(emoji, function(value, i) {return {key:value + ':', name:value}}); + $('#note_note'). + atWho('@', { data: names }). + atWho(':', { + data: emoji, + tpl: "
  • ${name} #{escape_javascript image_tag('emoji/${name}.png', :size => '20x20')}
  • " + }); }); From 252d3a0c9d84cef8d939c2c444f8763079eded1e Mon Sep 17 00:00:00 2001 From: Cyril Date: Tue, 25 Sep 2012 22:32:20 +0200 Subject: [PATCH 32/34] remove duplicate before_filter --- app/controllers/hooks_controller.rb | 1 - app/controllers/issues_controller.rb | 1 - app/controllers/labels_controller.rb | 1 - app/controllers/merge_requests_controller.rb | 1 - app/controllers/milestones_controller.rb | 1 - app/controllers/snippets_controller.rb | 1 - 6 files changed, 6 deletions(-) diff --git a/app/controllers/hooks_controller.rb b/app/controllers/hooks_controller.rb index c81e6b05cb37..4359e99668f2 100644 --- a/app/controllers/hooks_controller.rb +++ b/app/controllers/hooks_controller.rb @@ -1,5 +1,4 @@ class HooksController < ApplicationController - before_filter :authenticate_user! before_filter :project layout "project" diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 1d78a6d9b80b..ceeee0096abc 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -1,5 +1,4 @@ class IssuesController < ApplicationController - before_filter :authenticate_user! before_filter :project before_filter :module_enabled before_filter :issue, only: [:edit, :update, :destroy, :show] diff --git a/app/controllers/labels_controller.rb b/app/controllers/labels_controller.rb index e703f8229828..189d8d9866db 100644 --- a/app/controllers/labels_controller.rb +++ b/app/controllers/labels_controller.rb @@ -1,5 +1,4 @@ class LabelsController < ApplicationController - before_filter :authenticate_user! before_filter :project before_filter :module_enabled diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 187bb407b2df..1d0da43f7c70 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -1,5 +1,4 @@ class MergeRequestsController < ApplicationController - before_filter :authenticate_user! before_filter :project before_filter :module_enabled before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check, :raw] diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index 10f089f138b5..e8dbc8e49f1b 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -1,5 +1,4 @@ class MilestonesController < ApplicationController - before_filter :authenticate_user! before_filter :project before_filter :module_enabled before_filter :milestone, only: [:edit, :update, :destroy, :show] diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index f852e425891e..b00c92836944 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -1,5 +1,4 @@ class SnippetsController < ApplicationController - before_filter :authenticate_user! before_filter :project before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] layout "project" From 83696b127b7822482957a894816b0e3c2daea0b5 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 26 Sep 2012 04:18:10 -0700 Subject: [PATCH 33/34] cleanup rake tasks --- lib/tasks/bulk_add_permission.rake | 28 ++++------ lib/tasks/bulk_import.rake | 74 ++++++++------------------ lib/tasks/gitlab/backup.rake | 46 ++++++++-------- lib/tasks/gitlab/enable_automerge.rake | 2 +- lib/tasks/gitlab/gitolite_rebuild.rake | 5 +- lib/tasks/gitlab/setup.rake | 3 +- lib/tasks/gitlab/status.rake | 37 +++++++------ lib/tasks/gitlab/write_hook.rake | 2 - 8 files changed, 77 insertions(+), 120 deletions(-) diff --git a/lib/tasks/bulk_add_permission.rake b/lib/tasks/bulk_add_permission.rake index 55797825e0cf..bf08ace8e9c0 100644 --- a/lib/tasks/bulk_add_permission.rake +++ b/lib/tasks/bulk_add_permission.rake @@ -1,26 +1,20 @@ -desc "Add all users to all projects, system administratos are added as masters" +desc "Add all users to all projects (admin users are added as masters)" task :add_users_to_project_teams => :environment do |t, args| - users = User.find_all_by_admin(false, :select => 'id').map(&:id) - admins = User.find_all_by_admin(true, :select => 'id').map(&:id) + user_ids = User.where(:admin => false).pluck(:id) + admin_ids = User.where(:admin => true).pluck(:id) - users.each do |user| - puts "#{user}" - end - - Project.all.each do |project| - puts "Importing #{users.length} users into #{project.path}" - UsersProject.bulk_import(project, users, UsersProject::DEVELOPER) - puts "Importing #{admins.length} admins into #{project.path}" - UsersProject.bulk_import(project, admins, UsersProject::MASTER) + Project.find_each do |project| + puts "Importing #{user_ids.size} users into #{project.code}" + UsersProject.bulk_import(project, user_ids, UsersProject::DEVELOPER) + puts "Importing #{admin_ids.size} admins into #{project.code}" + UsersProject.bulk_import(project, admin_ids, UsersProject::MASTER) end end desc "Add user to as a developer to all projects" task :add_user_to_project_teams, [:email] => :environment do |t, args| - user_email = args.email - user = User.find_by_email(user_email) - - project_ids = Project.all.map(&:id) + user = User.find_by_email args.email + project_ids = Project.pluck(:id) - UsersProject.user_bulk_import(user,project_ids,UsersProject::DEVELOPER) + UsersProject.user_bulk_import(user, project_ids, UsersProject::DEVELOPER) end diff --git a/lib/tasks/bulk_import.rake b/lib/tasks/bulk_import.rake index edb4a599eb0c..914f920a8d7a 100644 --- a/lib/tasks/bulk_import.rake +++ b/lib/tasks/bulk_import.rake @@ -1,20 +1,17 @@ - desc "Imports existing Git repos from a directory into new projects in git_base_path" task :import_projects, [:directory,:email] => :environment do |t, args| - user_email = args.email - import_directory = args.directory + user_email, import_directory = args.email, args.directory repos_to_import = Dir.glob("#{import_directory}/*") git_base_path = Gitlab.config.git_base_path - puts "Found #{repos_to_import.length} repos to import" + imported_count, skipped_count, failed_count = 0 + + puts "Found #{repos_to_import.size} repos to import" - imported_count = 0 - skipped_count = 0 - failed_count = 0 repos_to_import.each do |repo_path| repo_name = File.basename repo_path + clone_path = "#{git_base_path}#{repo_name}.git" puts " Processing #{repo_name}" - clone_path = "#{git_base_path}#{repo_name}.git" if Dir.exists? clone_path if Project.find_by_code(repo_name) @@ -38,7 +35,6 @@ task :import_projects, [:directory,:email] => :environment do |t, args| else failed_count += 1 end - end puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})." @@ -49,63 +45,39 @@ def clone_bare_repo_as_git(existing_path, new_path) git_user = Gitlab.config.ssh_user begin sh "sudo -u #{git_user} -i git clone --bare '#{existing_path}' #{new_path}" - true - rescue Exception=> msg - puts " ERROR: Faild to clone #{existing_path} to #{new_path}" - puts " Make sure #{git_user} can reach #{existing_path}" - puts " Exception-MSG: #{msg}" - false + rescue Exception => msg + puts " ERROR: Failed to clone #{existing_path} to #{new_path}" + puts " Make sure #{git_user} can reach #{existing_path}" + puts " Exception-MSG: #{msg}" end end -# Creats a project in Gitlag given a @project_name@ to use (for name, web url, and code -# url) and a @user_email@ that will be assigned as the owner of the project. +# Creates a project in GitLab given a `project_name` to use +# (for name, web url, and code url) and a `user_email` that will be +# assigned as the owner of the project. def create_repo_project(project_name, user_email) - user = User.find_by_email(user_email) - if user + if user = User.find_by_email(user_email) # Using find_by_code since that's the most important identifer to be unique if Project.find_by_code(project_name) puts " INFO: Project #{project_name} already exists in Gitlab, skipping." - false else - project = nil - if Project.find_by_code(project_name) - puts " ERROR: Project already exists #{project_name}" - return false - project = Project.find_by_code(project_name) - else - project = Project.create( - name: project_name, - code: project_name, - path: project_name, - owner: user, - description: "Automatically created from Rake on #{Time.now.to_s}" - ) - end - - unless project.valid? - puts " ERROR: Failed to create project #{project} because #{project.errors.first}" - return false - end - - # Add user as admin for project - project.users_projects.create!( - :project_access => UsersProject::MASTER, - :user => user + project = Project.create( + name: project_name, + code: project_name, + path: project_name, + owner: user, + description: "Automatically created from 'import_projects' rake task on #{Time.now}" ) - # Per projects_controller.rb#37 - project.update_repository - if project.valid? - true + # Add user as admin for project + project.users_projects.create!(:project_access => UsersProject::MASTER, :user => user) + project.update_repository else puts " ERROR: Failed to create project #{project} because #{project.errors.first}" - false end end else - puts " ERROR: #{user_email} not found, skipping" - false + puts " ERROR: user with #{user_email} not found, skipping" end end diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 04d240f6b12a..06d7cb65d643 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -2,22 +2,20 @@ require 'active_record/fixtures' namespace :gitlab do namespace :app do - - # Create backup of gitlab system - desc "GITLAB | Create a backup of the gitlab system" + # Create backup of GitLab system + desc "GITLAB | Create a backup of the GitLab system" task :backup_create => :environment do - Rake::Task["gitlab:app:db_dump"].invoke Rake::Task["gitlab:app:repo_dump"].invoke Dir.chdir(Gitlab.config.backup_path) # saving additional informations - s = Hash.new - s["db_version"] = "#{ActiveRecord::Migrator.current_version}" - s["backup_created_at"] = "#{Time.now}" - s["gitlab_version"] = %x{git rev-parse HEAD}.gsub(/\n/,"") - s["tar_version"] = %x{tar --version | head -1}.gsub(/\n/,"") + s = {} + s[:db_version] = "#{ActiveRecord::Migrator.current_version}" + s[:backup_created_at] = "#{Time.now}" + s[:gitlab_version] = %x{git rev-parse HEAD}.gsub(/\n/,"") + s[:tar_version] = %x{tar --version | head -1}.gsub(/\n/,"") File.open("#{Gitlab.config.backup_path}/backup_information.yml", "w+") do |file| file << s.to_yaml.gsub(/^---\n/,'') @@ -32,7 +30,7 @@ namespace :gitlab do end # cleanup: remove tmp files - print "Deletion of tmp directories..." + print "Deleting tmp directories..." if Kernel.system("rm -rf repositories/ db/ backup_information.yml") puts "[DONE]".green else @@ -52,26 +50,23 @@ namespace :gitlab do else puts "[SKIPPING]".yellow end - end - - # Restore backup of gitlab system + # Restore backup of GitLab system desc "GITLAB | Restore a previously created backup" task :backup_restore => :environment do - Dir.chdir(Gitlab.config.backup_path) # check for existing backups in the backup dir file_list = Dir.glob("*_gitlab_backup.tar").each.map { |f| f.split(/_/).first.to_i } - puts "no backup found" if file_list.count == 0 + puts "no backups found" if file_list.count == 0 if file_list.count > 1 && ENV["BACKUP"].nil? puts "Found more than one backup, please specify which one you want to restore:" puts "rake gitlab:app:backup_restore BACKUP=timestamp_of_backup" exit 1; end - tar_file = ENV["BACKUP"].nil? ? File.join(file_list.first.to_s + "_gitlab_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_backup.tar") + tar_file = ENV["BACKUP"].nil? ? File.join("#{file_list.first}_gitlab_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_backup.tar") unless File.exists?(tar_file) puts "The specified backup doesn't exist!" @@ -102,16 +97,14 @@ namespace :gitlab do Rake::Task["gitlab:app:repo_restore"].invoke # cleanup: remove tmp files - print "Deletion of tmp directories..." + print "Deleting tmp directories..." if Kernel.system("rm -rf repositories/ db/ backup_information.yml") puts "[DONE]".green else puts "[FAILED]".red end - end - ################################################################################ ################################# invoked tasks ################################ @@ -121,7 +114,7 @@ namespace :gitlab do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) puts "Dumping repositories:" - project = Project.all.map { |n| [n.path,n.path_to_repo] } + project = Project.all.map { |n| [n.path, n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Dumping repository #{project.first}... " @@ -136,11 +129,11 @@ namespace :gitlab do task :repo_restore => :environment do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") puts "Restoring repositories:" - project = Project.all.map { |n| [n.path,n.path_to_repo] } + project = Project.all.map { |n| [n.path, n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Restoring repository #{project.first}... " - FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff + FileUtils.rm_rf(project.second) if File.dirname(project.second) # delete old stuff if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") permission_commands = [ "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", @@ -157,8 +150,9 @@ namespace :gitlab do ###################################### DB ###################################### task :db_dump => :environment do - backup_path_db = File.join(Gitlab.config.backup_path, "db") - FileUtils.mkdir_p(backup_path_db) until Dir.exists?(backup_path_db) + backup_path_db = File.join(Gitlab.config.backup_path, "db") + FileUtils.mkdir_p(backup_path_db) unless Dir.exists?(backup_path_db) + puts "Dumping database tables:" ActiveRecord::Base.connection.tables.each do |tbl| print "- Dumping table #{tbl}... " @@ -176,9 +170,11 @@ namespace :gitlab do end task :db_restore=> :environment do - backup_path_db = File.join(Gitlab.config.backup_path, "db") + backup_path_db = File.join(Gitlab.config.backup_path, "db") + puts "Restoring database tables:" Rake::Task["db:reset"].invoke + Dir.glob(File.join(backup_path_db, "*.yml") ).each do |dir| fixture_file = File.basename(dir, ".*" ) print "- Loading fixture #{fixture_file}..." diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake index 0a1a0fa73501..13b4bab6edc4 100644 --- a/lib/tasks/gitlab/enable_automerge.rake +++ b/lib/tasks/gitlab/enable_automerge.rake @@ -1,7 +1,7 @@ namespace :gitlab do namespace :app do desc "GITLAB | Enable auto merge" - task :enable_automerge => :environment do + task :enable_automerge => :environment do Gitlab::Gitolite.new.enable_automerge Project.find_each do |project| diff --git a/lib/tasks/gitlab/gitolite_rebuild.rake b/lib/tasks/gitlab/gitolite_rebuild.rake index 534aa3156311..fce10eb5b692 100644 --- a/lib/tasks/gitlab/gitolite_rebuild.rake +++ b/lib/tasks/gitlab/gitolite_rebuild.rake @@ -1,11 +1,10 @@ namespace :gitlab do namespace :gitolite do desc "GITLAB | Rebuild each project at gitolite config" - task :update_repos => :environment do + task :update_repos => :environment do puts "Starting Projects" Project.find_each(:batch_size => 100) do |project| - puts - puts "=== #{project.name}" + puts "\n=== #{project.name}" project.update_repository puts end diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index 49c86461c0b3..08f35c7e3f04 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -4,8 +4,7 @@ namespace :gitlab do task :setup => [ 'db:setup', 'db:seed_fu', - 'gitlab:app:enable_automerge' + 'gitlab:app:enable_automerge' ] end end - diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake index e5b5e122a18a..302f417c01ab 100644 --- a/lib/tasks/gitlab/status.rake +++ b/lib/tasks/gitlab/status.rake @@ -1,37 +1,37 @@ namespace :gitlab do namespace :app do - desc "GITLAB | Check gitlab installation status" + desc "GITLAB | Check GitLab installation status" task :status => :environment do - puts "Starting diagnostic".yellow + puts "Starting diagnostics".yellow git_base_path = Gitlab.config.git_base_path print "config/database.yml............" - if File.exists?(File.join Rails.root, "config", "database.yml") + if File.exists?(Rails.root.join "config", "database.yml") puts "exists".green - else + else puts "missing".red return end print "config/gitlab.yml............" - if File.exists?(File.join Rails.root, "config", "gitlab.yml") - puts "exists".green + if File.exists?(Rails.root.join "config", "gitlab.yml") + puts "exists".green else puts "missing".red return end print "#{git_base_path}............" - if File.exists?(git_base_path) - puts "exists".green - else + if File.exists?(git_base_path) + puts "exists".green + else puts "missing".red return end print "#{git_base_path} is writable?............" if File.stat(git_base_path).writable? - puts "YES".green + puts "YES".green else puts "NO".red return @@ -41,16 +41,16 @@ namespace :gitlab do `git clone #{Gitlab.config.gitolite_admin_uri} /tmp/gitolite_gitlab_test` FileUtils.rm_rf("/tmp/gitolite_gitlab_test") print "Can clone gitolite-admin?............" - puts "YES".green - rescue + puts "YES".green + rescue print "Can clone gitolite-admin?............" puts "NO".red return end print "UMASK for .gitolite.rc is 0007? ............" - unless open("#{git_base_path}/../.gitolite.rc").grep(/UMASK([ \t]*)=([ \t>]*)0007/).empty? - puts "YES".green + if open("#{git_base_path}/../.gitolite.rc").grep(/UMASK([ \t]*)=([ \t>]*)0007/).any? + puts "YES".green else puts "NO".red return @@ -69,16 +69,15 @@ namespace :gitlab do end end - - if Project.count > 0 + if Project.count > 0 puts "Validating projects repositories:".yellow Project.find_each(:batch_size => 100) do |project| print "#{project.name}....." - hook_file = File.join(project.path_to_repo, 'hooks','post-receive') + hook_file = File.join(project.path_to_repo, 'hooks', 'post-receive') unless File.exists?(hook_file) - puts "post-receive file missing".red - next + puts "post-receive file missing".red + return end puts "post-receive file ok".green diff --git a/lib/tasks/gitlab/write_hook.rake b/lib/tasks/gitlab/write_hook.rake index 5e9fc8eb3d1f..ccc96aad4f0d 100644 --- a/lib/tasks/gitlab/write_hook.rake +++ b/lib/tasks/gitlab/write_hook.rake @@ -4,7 +4,6 @@ namespace :gitlab do task :write_hooks => :environment do gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common") gitlab_hooks_path = Rails.root.join("lib", "hooks") - gitlab_hook_files = ['post-receive'] gitlab_hook_files.each do |file_name| @@ -20,4 +19,3 @@ namespace :gitlab do end end end - From 5928388b1c5b41cf11471391b3ec6226167132fd Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 26 Sep 2012 13:20:44 +0200 Subject: [PATCH 34/34] Protect users projects_limit from mass assignment. --- app/controllers/admin/users_controller.rb | 6 +++--- app/models/user.rb | 5 +++-- spec/models/user_spec.rb | 26 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index e2d61864076e..c9586ad5da93 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -30,7 +30,7 @@ def team_update def new - @admin_user = User.new(projects_limit: Gitlab.config.default_projects_limit) + @admin_user = User.new({ projects_limit: Gitlab.config.default_projects_limit }, as: :admin) end def edit @@ -60,7 +60,7 @@ def unblock def create admin = params[:user].delete("admin") - @admin_user = User.new(params[:user]) + @admin_user = User.new(params[:user], as: :admin) @admin_user.admin = (admin && admin.to_i > 0) respond_to do |format| @@ -86,7 +86,7 @@ def update @admin_user.admin = (admin && admin.to_i > 0) respond_to do |format| - if @admin_user.update_attributes(params[:user]) + if @admin_user.update_attributes(params[:user], as: :admin) format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully updated.' } format.json { head :ok } else diff --git a/app/models/user.rb b/app/models/user.rb index 47876722755d..a8626cc187a7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,8 +6,9 @@ class User < ActiveRecord::Base :recoverable, :rememberable, :trackable, :validatable, :omniauthable attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, - :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, - :theme_id, :force_random_password, :extern_uid, :provider + :name, :skype, :linkedin, :twitter, :dark_scheme, + :theme_id, :force_random_password, :extern_uid, :provider, :as => [:default, :admin] + attr_accessible :projects_limit, :as => :admin attr_accessor :force_random_password diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 081767543e2f..14a373e10a52 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -73,4 +73,30 @@ user.authentication_token.should_not be_blank end end + + describe "attributes can be changed by a regular user" do + before do + @user = Factory :user + @user.update_attributes(skype: "testskype", linkedin: "testlinkedin") + end + it { @user.skype.should == 'testskype' } + it { @user.linkedin.should == 'testlinkedin' } + end + + describe "attributes that shouldn't be changed by a regular user" do + before do + @user = Factory :user + @user.update_attributes(projects_limit: 50) + end + it { @user.projects_limit.should_not == 50 } + end + + describe "attributes can be changed by an admin user" do + before do + @admin_user = Factory :admin + @admin_user.update_attributes({ skype: "testskype", projects_limit: 50 }, as: :admin) + end + it { @admin_user.skype.should == 'testskype' } + it { @admin_user.projects_limit.should == 50 } + end end