From 8f7360f3901ae27a457f252b1a9a091a857434ee Mon Sep 17 00:00:00 2001 From: miks Date: Wed, 5 Sep 2012 23:01:03 +0300 Subject: [PATCH 01/50] API on adding users to project implemented --- doc/api/projects.md | 15 +++++++++++++++ lib/api/projects.rb | 12 ++++++++++++ spec/requests/api/projects_spec.rb | 12 ++++++++++++ 3 files changed, 39 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index e029522b..85b88d40 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -106,6 +106,21 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. +## Add project users + +Add users to exiting project + +``` +PUT /projects/:id/add_users +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `user_ids` (required) - new project name ++ `project_access` (required) - new project name + +Will return updated project with status `200 OK` on success, or `404 Not found` on fail. ## Project repository branches diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 3d4fde92..46e688e4 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -44,6 +44,18 @@ module Gitlab end end + # Add users to project with specified access level + # + # 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 + # Example Request: + # PUT /projects/:id/add_users + put ":id/add_users" do + user_project.add_users_ids_to_team(params[:user_ids], params[:project_access]) + end + # Get a project repository branches # # Parameters: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index cc6843cc..f8434654 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -62,6 +62,18 @@ describe Gitlab::API do end end + describe "PUT /projects/:id/add_users" do + @user2 = Factory :user + @user3 = Factory :user + + it "should add users to existing project" do + expect { + put api("/projects/#{project.code}/add_users", user), + user_ids: [@user2.id, @user3.id], project_access: UsersProject::DEVELOPER + }.to change {Project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + end + end + describe "GET /projects/:id" do it "should return a project by id" do get api("/projects/#{project.id}", user) From b78fd0c13088ce2c19d939a26a26e247ca5047ea Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 5 Sep 2012 16:49:59 -0400 Subject: [PATCH 02/50] Add github-markup gem --- Gemfile | 1 + Gemfile.lock | 2 ++ app/controllers/refs_controller.rb | 2 ++ 3 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index b0724fad..34f7c274 100644 --- a/Gemfile +++ b/Gemfile @@ -45,6 +45,7 @@ gem "seed-fu" # Markdown to HTML gem "redcarpet", "~> 2.1.1" +gem 'github-markup' # Servers gem "thin" diff --git a/Gemfile.lock b/Gemfile.lock index f350b3fc..fc730802 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -178,6 +178,7 @@ GEM gherkin (2.11.0) json (>= 1.4.6) git (1.2.5) + github-markup (0.7.4) gitlab_meta (2.9) grape (0.2.1) hashie (~> 1.2) @@ -396,6 +397,7 @@ DEPENDENCIES ffaker foreman git + github-markup gitlab_meta (= 2.9) gitolite! grack! diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index 3f81a2ca..90361437 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -1,3 +1,5 @@ +require 'github/markup' + class RefsController < ApplicationController include Gitlab::Encode before_filter :project From 52c521ffe84dac5dc72a299ee1ecf4736a10f07f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 5 Sep 2012 16:52:49 -0400 Subject: [PATCH 03/50] Use GitHub::Markup to parse markup files Closes #1382 --- app/helpers/tree_helper.rb | 10 ++++++++++ app/views/refs/_tree.html.haml | 6 +----- app/views/refs/_tree_file.html.haml | 5 ++--- spec/helpers/tree_helper_spec.rb | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 spec/helpers/tree_helper_spec.rb diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index ed3053d8..c51ee84a 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -24,4 +24,14 @@ module TreeHelper content.name end end + + # Public: Determines if a given filename is compatible with GitHub::Markup. + # + # filename - Filename string to check + # + # Returns boolean + def markup?(filename) + filename.end_with?(*%w(.mdown .md .markdown .textile .rdoc .org .creole + .mediawiki .rst .asciidoc .pod)) + end end diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml index a4765c10..297a3b5f 100644 --- a/app/views/refs/_tree.html.haml +++ b/app/views/refs/_tree.html.haml @@ -43,11 +43,7 @@ %i.icon-file = content.name .file_content.wiki - - if content.name =~ /\.(md|markdown)$/i - = preserve do - = markdown(content.data) - - else - = simple_format(content.data) + = 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 b5ed61bb..765f271a 100644 --- a/app/views/refs/_tree_file.html.haml +++ b/app/views/refs/_tree_file.html.haml @@ -9,10 +9,9 @@ = 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 name =~ /\.(md|markdown)$/i + - if markup?(name) .file_content.wiki - = preserve do - = markdown(file.data) + = raw GitHub::Markup.render(name, file.data) - else .file_content.code - unless file.empty? diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb new file mode 100644 index 00000000..bb124d8b --- /dev/null +++ b/spec/helpers/tree_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe TreeHelper do + describe '#markup?' do + %w(mdown md markdown 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 + end + + it "returns false when given a non-markup filename" do + markup?('README.rb').should_not be_true + end + end +end From 1814ee0ced59aa3203ce265410ae5a7c83e096aa Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 5 Sep 2012 17:02:23 -0400 Subject: [PATCH 04/50] Give github-markup gem a version requirement --- Gemfile | 4 ++-- Gemfile.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 34f7c274..c8d3821f 100644 --- a/Gemfile +++ b/Gemfile @@ -44,8 +44,8 @@ gem "ffaker" gem "seed-fu" # Markdown to HTML -gem "redcarpet", "~> 2.1.1" -gem 'github-markup' +gem "redcarpet", "~> 2.1.1" +gem "github-markup", "~> 0.7.4" # Servers gem "thin" diff --git a/Gemfile.lock b/Gemfile.lock index fc730802..830e28b5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -397,7 +397,7 @@ DEPENDENCIES ffaker foreman git - github-markup + github-markup (~> 0.7.4) gitlab_meta (= 2.9) gitolite! grack! From e3b1f62c6b1fda0ea711f65c699d5025ab926c9d Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 00:13:25 +0300 Subject: [PATCH 05/50] convert params hash to array --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 46e688e4..9cd86d0b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -53,7 +53,7 @@ module Gitlab # Example Request: # PUT /projects/:id/add_users put ":id/add_users" do - user_project.add_users_ids_to_team(params[:user_ids], params[:project_access]) + user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) end # Get a project repository branches From 94c50545661c21816faf1e143739f60b1058b8e1 Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 01:06:02 +0300 Subject: [PATCH 06/50] count against last project --- spec/requests/api/projects_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index f8434654..1c723058 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -70,7 +70,7 @@ describe Gitlab::API do expect { put api("/projects/#{project.code}/add_users", user), user_ids: [@user2.id, @user3.id], project_access: UsersProject::DEVELOPER - }.to change {Project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + }.to change {Project.last.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) end end From cd846ba2b55cd1380febfa174d8cf82ad9e948f7 Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 09:52:27 +0300 Subject: [PATCH 07/50] Fix tests --- spec/requests/api/projects_spec.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 1c723058..b1b5966c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -4,6 +4,8 @@ describe Gitlab::API do include ApiHelpers let(:user) { Factory :user } + let(:user2) { Factory.create(:user) } + let(:user3) { Factory.create(:user) } let!(:project) { Factory :project, owner: user } let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } before { project.add_access(user, :read) } @@ -63,13 +65,10 @@ describe Gitlab::API do end describe "PUT /projects/:id/add_users" do - @user2 = Factory :user - @user3 = Factory :user - it "should add users to existing project" do expect { put api("/projects/#{project.code}/add_users", user), - user_ids: [@user2.id, @user3.id], project_access: UsersProject::DEVELOPER + user_ids: [user2.id, user3.id], project_access: UsersProject::DEVELOPER }.to change {Project.last.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) end end From b3c8688da33ac2fd79d733fc9992a526c18c2c40 Mon Sep 17 00:00:00 2001 From: Cornelio Date: Thu, 30 Aug 2012 16:51:09 +0200 Subject: [PATCH 08/50] fix bulk_import for #1309 --- lib/tasks/bulk_import.rake | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/tasks/bulk_import.rake b/lib/tasks/bulk_import.rake index 5941eadb..edb4a599 100644 --- a/lib/tasks/bulk_import.rake +++ b/lib/tasks/bulk_import.rake @@ -1,12 +1,10 @@ -IMPORT_DIRECTORY = 'import_projects' - -desc "Imports existing Git repos into new projects from the import_projects folder" -task :import_projects, [:email] => :environment do |t, args| - REPOSITORY_DIRECTORY = Gitlab.config.git_base_path +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 - repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*") - + import_directory = 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 = 0 @@ -14,11 +12,9 @@ task :import_projects, [:email] => :environment do |t, args| failed_count = 0 repos_to_import.each do |repo_path| repo_name = File.basename repo_path - repo_full_path = File.join(Rails.root, repo_path) puts " Processing #{repo_name}" - - clone_path = "#{REPOSITORY_DIRECTORY}/#{repo_name}.git" + clone_path = "#{git_base_path}#{repo_name}.git" if Dir.exists? clone_path if Project.find_by_code(repo_name) @@ -30,7 +26,7 @@ task :import_projects, [:email] => :environment do |t, args| end else # Clone the repo - unless clone_bare_repo_as_git(repo_full_path, clone_path) + unless clone_bare_repo_as_git(repo_path, clone_path) failed_count += 1 next end @@ -48,14 +44,17 @@ task :import_projects, [:email] => :environment do |t, args| puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})." end -# Clones a repo as bare git repo using the git user +# Clones a repo as bare git repo using the git_user def clone_bare_repo_as_git(existing_path, new_path) + git_user = Gitlab.config.ssh_user begin - sh "sudo -u git -i git clone --bare '#{existing_path}' #{new_path}" + sh "sudo -u #{git_user} -i git clone --bare '#{existing_path}' #{new_path}" true - rescue + rescue Exception=> msg puts " ERROR: Faild to clone #{existing_path} to #{new_path}" - false + puts " Make sure #{git_user} can reach #{existing_path}" + puts " Exception-MSG: #{msg}" + false end end From ab057bb5dbf5806365d42371c968290235c555a8 Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 10:20:59 +0300 Subject: [PATCH 09/50] proper Grape params hash simulation --- spec/requests/api/projects_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index b1b5966c..125101ca 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -68,7 +68,7 @@ describe Gitlab::API do it "should add users to existing project" do expect { put api("/projects/#{project.code}/add_users", user), - user_ids: [user2.id, user3.id], project_access: UsersProject::DEVELOPER + user_ids: {"0" => user2.id, "1" => user3.id}, project_access: UsersProject::DEVELOPER }.to change {Project.last.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) end end From 3d3c6674fbea1b9099e80e1fc1768f85ecd3bf14 Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 16:32:26 +0300 Subject: [PATCH 10/50] Typo fixed --- doc/api/projects.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 85b88d40..972ea67e 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -117,8 +117,8 @@ PUT /projects/:id/add_users Parameters: + `id` (required) - The ID or code name of a project -+ `user_ids` (required) - new project name -+ `project_access` (required) - new project name ++ `user_ids` (required) - The ID list of users to add ++ `project_access` (required) - Project access level Will return updated project with status `200 OK` on success, or `404 Not found` on fail. From 2dc0519277417456372d6bde5c47bec895cc497e Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 23:14:42 +0300 Subject: [PATCH 11/50] bulk access roles update/deletion added --- app/models/users_project.rb | 17 +++++++++++++++++ app/roles/team.rb | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 7d172934..654b3711 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -20,6 +20,23 @@ class UsersProject < ActiveRecord::Base delegate :name, :email, to: :user, prefix: true + def self.bulk_delete(project, user_ids) + UsersProject.transaction do + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| + users_project.delete + end + end + end + + def self.bulk_update(project, user_ids, project_access) + UsersProject.transaction do + UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| + users_project.project_access = project_access + users_project.save + end + end + end + def self.bulk_import(project, user_ids, project_access) UsersProject.transaction do user_ids.each do |user_id| diff --git a/app/roles/team.rb b/app/roles/team.rb index 27b1cc65..d8798c50 100644 --- a/app/roles/team.rb +++ b/app/roles/team.rb @@ -36,4 +36,17 @@ module Team UsersProject.bulk_import(self, users_ids, access_role) self.update_repository end + + # Update multiple project users + # to same access role by user ids + def update_users_ids_to_role(users_ids, access_role) + UsersProject.bulk_update(self, users_ids, access_role) + self.update_repository + end + + # Delete multiple users from project by user ids + def delete_users_by_ids(users_ids) + UsersProject.bulk_delete(self, users_ids) + self.update_repository + end end From 909c8c345dff0851e15d81917efe7817c7f89e22 Mon Sep 17 00:00:00 2001 From: miks Date: Thu, 6 Sep 2012 23:49:29 +0300 Subject: [PATCH 12/50] Make project users API more RESTful --- doc/api/projects.md | 49 ++++++++++++++++++++++++++++-- lib/api/entities.rb | 5 +++ lib/api/projects.rb | 38 +++++++++++++++++++++-- spec/requests/api/projects_spec.rb | 27 +++++++++++++--- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 972ea67e..b26305b1 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -106,12 +106,26 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. +## Get project users + +Get users and access roles for existing project + +``` +GET /projects/:id/users +``` + +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. + ## Add project users Add users to exiting project ``` -PUT /projects/:id/add_users +POST /projects/:id/users ``` Parameters: @@ -120,7 +134,38 @@ Parameters: + `user_ids` (required) - The ID list of users to add + `project_access` (required) - Project access level -Will return updated project with status `200 OK` on success, or `404 Not found` on fail. +Will return status `201 Created` on success, or `404 Not found` on fail. + +## Update project users access level + +Update existing users to specified access level + +``` +PUT /projects/:id/users +``` + +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 + +Will return status `200 OK` on success, or `404 Not found` on fail. + +## Delete project users + +Delete users from exiting project + +``` +DELETE /projects/:id/users +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `user_ids` (required) - The ID list of users to add + +Will return status `200 OK` on success, or `404 Not found` on fail. ## Project repository branches diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 96ccd87a..fef5328d 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -16,6 +16,11 @@ module Gitlab 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 + end + class RepoObject < Grape::Entity expose :name, :commit end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 9cd86d0b..e56f8949 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -44,6 +44,17 @@ module Gitlab end end + # Get project users + # + # 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 + end + # Add users to project with specified access level # # Parameters: @@ -51,11 +62,34 @@ module Gitlab # user_ids (required) - The ID list of users to add # project_access (required) - Project access level # Example Request: - # PUT /projects/:id/add_users - put ":id/add_users" do + # POST /projects/:id/users + post ":id/users" do user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) end + # Update users to specified access level + # + # 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 + # Example Request: + # PUT /projects/:id/add_users + put ":id/users" do + user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) + end + + # Delete project users + # + # Parameters: + # id (required) - The ID or code name of a project + # user_ids (required) - The ID list of users to delete + # Example Request: + # DELETE /projects/:id/users + delete ":id/users" do + user_project.delete_users_ids_from_team(params[:user_ids].values) + end + # Get a project repository branches # # Parameters: diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 125101ca..73ec3760 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -8,6 +8,7 @@ describe Gitlab::API do let(:user3) { Factory.create(:user) } let!(:project) { Factory :project, owner: user } let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } + let!(:users_project) { Factory :users_project, user: user, project: project } before { project.add_access(user, :read) } describe "GET /projects" do @@ -64,12 +65,30 @@ describe Gitlab::API do end end - describe "PUT /projects/:id/add_users" do - it "should add users to existing project" do + describe "POST /projects/:id/users" do + it "should add users to project" do expect { - put api("/projects/#{project.code}/add_users", user), + post api("/projects/#{project.code}/users", user), user_ids: {"0" => user2.id, "1" => user3.id}, project_access: UsersProject::DEVELOPER - }.to change {Project.last.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + end + end + + describe "PUT /projects/:id/users" do + it "should update users to new access role" do + expect { + put api("/projects/#{project.code}/users", user), + user_ids: {"0" => user}, project_access: UsersProject::DEVELOPER + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) + end + end + + describe "DELETE /projects/:id/users" do + it "should delete users from project" do + expect { + delete api("/projects/#{project.code}/delete", user), + user_ids: {"0" => users_project.id} + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(-1) end end From 79021e674bab1d34609228343fbf3403d9bd9bc6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Sep 2012 08:16:29 +0300 Subject: [PATCH 13/50] Split gitolite backend. Use gitolite_config methods moved to separate class --- app/controllers/application_controller.rb | 4 - app/views/errors/invalid_ssh_key.html.haml | 3 - lib/gitlab/backend/gitolite.rb | 189 ++------------------- lib/gitlab/backend/gitolite_config.rb | 168 ++++++++++++++++++ spec/lib/gitolite_config_spec.rb | 16 ++ spec/lib/gitolite_spec.rb | 25 +++ spec/support/gitolite_stub.rb | 22 ++- 7 files changed, 241 insertions(+), 186 deletions(-) delete mode 100644 app/views/errors/invalid_ssh_key.html.haml create mode 100644 lib/gitlab/backend/gitolite_config.rb create mode 100644 spec/lib/gitolite_config_spec.rb create mode 100644 spec/lib/gitolite_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7e53b8fe..2fe2a974 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,10 +14,6 @@ class ApplicationController < ActionController::Base render "errors/gitolite", layout: "error" end - rescue_from Gitlab::Gitolite::InvalidKey do |exception| - render "errors/invalid_ssh_key", layout: "error" - end - rescue_from Encoding::CompatibilityError do |exception| render "errors/encoding", layout: "error", status: 404 end diff --git a/app/views/errors/invalid_ssh_key.html.haml b/app/views/errors/invalid_ssh_key.html.haml deleted file mode 100644 index fb7922b0..00000000 --- a/app/views/errors/invalid_ssh_key.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%h1 Git Error -%hr -%p Seems like SSH Key you provided is not a valid SSH key. diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index 3dfb574c..bc9e1f1d 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -1,202 +1,43 @@ -require 'gitolite' -require 'timeout' -require 'fileutils' +require_relative 'gitolite_config' -# TODO: refactor & cleanup module Gitlab class Gitolite class AccessDenied < StandardError; end - class InvalidKey < StandardError; end + + def config + @config ||= Gitlab::GitoliteConfig.new + end def set_key key_id, key_content, projects - configure do |c| - c.update_keys(key_id, key_content) - c.update_projects(projects) + config.apply do |config| + config.write_key(key_id, key_content) + config.update_projects(projects) end end def remove_key key_id, projects - configure do |c| - c.delete_key(key_id) - c.update_projects(projects) + config.apply do |config| + config.rm_key(key_id) + config.update_projects(projects) end end def update_repository project - configure do |c| - c.update_project(project.path, project) - end + config.update_project!(project.path, project) end - alias_method :create_repository, :update_repository - def remove_repository project - configure do |c| - c.destroy_project(project) - end + config.destroy_project!(project) end def url_to_repo path Gitlab.config.ssh_path + "#{path}.git" end - def initialize - # create tmp dir - @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") - end - def enable_automerge - configure do |git| - git.admin_all_repo - end + config.admin_all_repo!(project) end - protected - - def destroy_project(project) - FileUtils.rm_rf(project.path_to_repo) - - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) - conf = ga_repo.config - conf.rm_repo(project.path) - ga_repo.save - end - - #update or create - def update_keys(user, key) - File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) } - end - - def delete_key(user) - File.unlink(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub")) - `cd #{File.join(@local_dir,'gitolite')} ; git rm keydir/#{user}.pub` - end - - # update or create - def update_project(repo_name, project) - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) - conf = ga_repo.config - repo = update_project_config(project, conf) - conf.add_repo(repo, true) - - ga_repo.save - end - - # Updates many projects and uses project.path as the repo path - # An order of magnitude faster than update_project - def update_projects(projects) - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) - conf = ga_repo.config - - projects.each do |project| - repo = update_project_config(project, conf) - conf.add_repo(repo, true) - end - - ga_repo.save - end - - def update_project_config(project, conf) - repo_name = project.path - - repo = if conf.has_repo?(repo_name) - conf.get_repo(repo_name) - else - ::Gitolite::Config::Repo.new(repo_name) - end - - name_readers = project.repository_readers - name_writers = project.repository_writers - name_masters = project.repository_masters - - pr_br = project.protected_branches.map(&:name).join("$ ") - - repo.clean_permissions - - # Deny access to protected branches for writers - unless name_writers.blank? || pr_br.blank? - repo.add_permission("-", pr_br.strip + "$ ", name_writers) - end - - # Add read permissions - repo.add_permission("R", "", name_readers) unless name_readers.blank? - - # Add write permissions - repo.add_permission("RW+", "", name_writers) unless name_writers.blank? - repo.add_permission("RW+", "", name_masters) unless name_masters.blank? - - repo - end - - def admin_all_repo - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) - conf = ga_repo.config - owner_name = "" - - # Read gitolite-admin user - # - begin - repo = conf.get_repo("gitolite-admin") - owner_name = repo.permissions[0]["RW+"][""][0] - raise StandardError if owner_name.blank? - rescue => ex - puts "Can't determine gitolite-admin owner".red - raise StandardError - end - - # @ALL repos premission for gitolite owner - repo_name = "@all" - repo = if conf.has_repo?(repo_name) - conf.get_repo(repo_name) - else - ::Gitolite::Config::Repo.new(repo_name) - end - - repo.add_permission("RW+", "", owner_name) - conf.add_repo(repo, true) - ga_repo.save - end - - private - - def pull - # create tmp dir - @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") - Dir.mkdir @local_dir - - `git clone #{Gitlab.config.gitolite_admin_uri} #{@local_dir}/gitolite` - end - - def push - Dir.chdir(File.join(@local_dir, "gitolite")) - `git add -A` - `git commit -am "GitLab"` - `git push` - Dir.chdir(Rails.root) - - FileUtils.rm_rf(@local_dir) - end - - def configure - Timeout::timeout(30) do - File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| - begin - f.flock(File::LOCK_EX) - pull - yield(self) - push - ensure - f.flock(File::LOCK_UN) - end - end - end - rescue Exception => ex - if ex.message =~ /is not a valid SSH key string/ - raise Gitolite::InvalidKey.new("ssh key is not valid") - else - Gitlab::Logger.error(ex.message) - raise Gitolite::AccessDenied.new("gitolite timeout") - end - end + alias_method :create_repository, :update_repository end end diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb new file mode 100644 index 00000000..5cf49121 --- /dev/null +++ b/lib/gitlab/backend/gitolite_config.rb @@ -0,0 +1,168 @@ +require 'gitolite' +require 'timeout' +require 'fileutils' + +module Gitlab + class GitoliteConfig + def config_tmp_dir + @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + end + + def apply + Timeout::timeout(30) do + File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| + begin + f.flock(File::LOCK_EX) + pull + yield(self) + push + ensure + f.flock(File::LOCK_UN) + end + end + end + rescue Exception => ex + Gitlab::Logger.error(ex.message) + raise Gitolite::AccessDenied.new("gitolite timeout") + end + + def destroy_project(project) + FileUtils.rm_rf(project.path_to_repo) + + ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) + conf = ga_repo.config + conf.rm_repo(project.path) + ga_repo.save + end + + def destroy_project!(project) + apply do |config| + config.destroy_project(project) + end + end + + def write_key(id, key) + File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f| + f.write(key.gsub(/\n/,'')) + end + end + + def rm_key(user) + File.unlink(File.join(config_tmp_dir, 'gitolite/keydir',"#{user}.pub")) + `cd #{File.join(config_tmp_dir,'gitolite')} ; git rm keydir/#{user}.pub` + end + + # update or create + def update_project(repo_name, project) + ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) + conf = ga_repo.config + repo = update_project_config(project, conf) + conf.add_repo(repo, true) + + ga_repo.save + end + + def update_project!(repo_name, project) + apply do |config| + config.update_project(repo_name, project) + end + end + + # Updates many projects and uses project.path as the repo path + # An order of magnitude faster than update_project + def update_projects(projects) + ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) + conf = ga_repo.config + + projects.each do |project| + repo = update_project_config(project, conf) + conf.add_repo(repo, true) + end + + ga_repo.save + end + + def update_project_config(project, conf) + repo_name = project.path + + repo = if conf.has_repo?(repo_name) + conf.get_repo(repo_name) + else + ::Gitolite::Config::Repo.new(repo_name) + end + + name_readers = project.repository_readers + name_writers = project.repository_writers + name_masters = project.repository_masters + + pr_br = project.protected_branches.map(&:name).join("$ ") + + repo.clean_permissions + + # Deny access to protected branches for writers + unless name_writers.blank? || pr_br.blank? + repo.add_permission("-", pr_br.strip + "$ ", name_writers) + end + + # Add read permissions + repo.add_permission("R", "", name_readers) unless name_readers.blank? + + # Add write permissions + repo.add_permission("RW+", "", name_writers) unless name_writers.blank? + repo.add_permission("RW+", "", name_masters) unless name_masters.blank? + + repo + end + + def admin_all_repo + ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) + conf = ga_repo.config + owner_name = "" + + # Read gitolite-admin user + # + begin + repo = conf.get_repo("gitolite-admin") + owner_name = repo.permissions[0]["RW+"][""][0] + raise StandardError if owner_name.blank? + rescue => ex + puts "Can't determine gitolite-admin owner".red + raise StandardError + end + + # @ALL repos premission for gitolite owner + repo_name = "@all" + repo = if conf.has_repo?(repo_name) + conf.get_repo(repo_name) + else + ::Gitolite::Config::Repo.new(repo_name) + end + + repo.add_permission("RW+", "", owner_name) + conf.add_repo(repo, true) + ga_repo.save + end + + def admin_all_repo! + apply { |config| config.admin_all_repo } + end + + private + + def pull + Dir.mkdir config_tmp_dir + `git clone #{Gitlab.config.gitolite_admin_uri} #{config_tmp_dir}/gitolite` + end + + def push + Dir.chdir(File.join(config_tmp_dir, "gitolite")) + `git add -A` + `git commit -am "GitLab"` + `git push` + Dir.chdir(Rails.root) + + FileUtils.rm_rf(config_tmp_dir) + end + end +end + diff --git a/spec/lib/gitolite_config_spec.rb b/spec/lib/gitolite_config_spec.rb new file mode 100644 index 00000000..c3ce0db5 --- /dev/null +++ b/spec/lib/gitolite_config_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe Gitlab::GitoliteConfig do + let(:gitolite) { Gitlab::GitoliteConfig.new } + + it { should respond_to :write_key } + it { should respond_to :rm_key } + it { should respond_to :update_project } + it { should respond_to :update_project! } + it { should respond_to :update_projects } + it { should respond_to :destroy_project } + it { should respond_to :destroy_project! } + it { should respond_to :apply } + it { should respond_to :admin_all_repo } + it { should respond_to :admin_all_repo! } +end diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/gitolite_spec.rb new file mode 100644 index 00000000..cc8ce8b2 --- /dev/null +++ b/spec/lib/gitolite_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Gitlab::Gitolite do + let(:project) { double('Project', path: 'diaspora') } + let(:gitolite_config) { double('Gitlab::GitoliteConfig') } + let(:gitolite) { Gitlab::Gitolite.new } + + before do + gitolite.stub(config: gitolite_config) + end + + it { should respond_to :set_key } + it { should respond_to :remove_key } + + it { should respond_to :update_repository } + it { should respond_to :create_repository } + it { should respond_to :remove_repository } + + it { gitolite.url_to_repo('diaspora').should == Gitlab.config.ssh_path + "diaspora.git" } + + it "should call config update" do + gitolite_config.should_receive(:update_project!) + gitolite.update_repository project + end +end diff --git a/spec/support/gitolite_stub.rb b/spec/support/gitolite_stub.rb index 2a907f99..037b09cd 100644 --- a/spec/support/gitolite_stub.rb +++ b/spec/support/gitolite_stub.rb @@ -17,7 +17,7 @@ module GitoliteStub ) gitolite_admin = double( - 'Gitolite::GitoliteAdmin', + 'Gitolite::GitoliteAdmin', config: gitolite_config, save: true, ) @@ -27,9 +27,21 @@ module GitoliteStub end def stub_gitlab_gitolite - gitlab_gitolite = Gitlab::Gitolite.new - Gitlab::Gitolite.stub(new: gitlab_gitolite) - gitlab_gitolite.stub(configure: ->() { yield(self) }) - gitlab_gitolite.stub(update_keys: true) + gitolite_config = double('Gitlab::GitoliteConfig') + gitolite_config.stub( + apply: ->() { yield(self) }, + write_key: true, + rm_key: true, + update_projects: true, + update_project: true, + update_project!: true, + destroy_project: true, + destroy_project!: true, + admin_all_repo: true, + admin_all_repo!: true, + + ) + + Gitlab::GitoliteConfig.stub(new: gitolite_config) end end From 963746f97847cd106e5f90f830fe9dc0b5ae0102 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Sep 2012 09:15:30 +0300 Subject: [PATCH 14/50] Refactor gitolite_config --- lib/gitlab/backend/gitolite_config.rb | 71 ++++++++++++++++----------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 47870edc..ff4c9014 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -4,39 +4,64 @@ require 'fileutils' module Gitlab class GitoliteConfig - attr_reader :config_tmp_dir + attr_reader :config_tmp_dir, :ga_repo, :conf - def reset_config_tmp_dir - @config_tmp_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + def config_tmp_dir + @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + end + + def ga_repo + @ga_repo ||= ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) end def apply Timeout::timeout(30) do File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| begin + # Set exclusive lock + # to prevent race condition f.flock(File::LOCK_EX) - reset_config_tmp_dir - pull + + # Pull gitolite-admin repo + # in tmp dir before do any changes + pull(config_tmp_dir) + + # Build ga_repo object and @conf + # to access gitolite-admin configuration + @conf = ga_repo.config + + # Do any changes + # in gitolite-admin + # config here yield(self) - push + + # Save changes in + # gitolite-admin repo + # before pusht it + ga_repo.save + + # Push gitolite-admin repo + # to apply all changes + push(config_tmp_dir) + + # Remove tmp dir + # wiith gitolite-admin FileUtils.rm_rf(config_tmp_dir) ensure + # unlock so other task cann access + # gitolite configuration f.flock(File::LOCK_UN) end end end rescue Exception => ex - Gitlab::Logger.error(ex.message) + Gitlab::Logger.error(ex.class.name + " " + ex.message) raise Gitolite::AccessDenied.new("gitolite timeout") end def destroy_project(project) FileUtils.rm_rf(project.path_to_repo) - - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) - conf = ga_repo.config conf.rm_repo(project.path) - ga_repo.save end def destroy_project!(project) @@ -58,12 +83,8 @@ module Gitlab # update or create def update_project(repo_name, project) - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) - conf = ga_repo.config repo = update_project_config(project, conf) conf.add_repo(repo, true) - - ga_repo.save end def update_project!(repo_name, project) @@ -75,15 +96,10 @@ module Gitlab # Updates many projects and uses project.path as the repo path # An order of magnitude faster than update_project def update_projects(projects) - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) - conf = ga_repo.config - projects.each do |project| repo = update_project_config(project, conf) conf.add_repo(repo, true) end - - ga_repo.save end def update_project_config(project, conf) @@ -118,9 +134,9 @@ module Gitlab repo end + # Enable access to all repos for gitolite admin. + # We use it for accept merge request feature def admin_all_repo - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite')) - conf = ga_repo.config owner_name = "" # Read gitolite-admin user @@ -144,7 +160,6 @@ module Gitlab repo.add_permission("RW+", "", owner_name) conf.add_repo(repo, true) - ga_repo.save end def admin_all_repo! @@ -153,13 +168,13 @@ module Gitlab private - def pull - Dir.mkdir config_tmp_dir - `git clone #{Gitlab.config.gitolite_admin_uri} #{config_tmp_dir}/gitolite` + def pull tmp_dir + Dir.mkdir tmp_dir + `git clone #{Gitlab.config.gitolite_admin_uri} #{tmp_dir}/gitolite` end - def push - Dir.chdir(File.join(config_tmp_dir, "gitolite")) + def push tmp_dir + Dir.chdir(File.join(tmp_dir, "gitolite")) `git add -A` `git commit -am "GitLab"` `git push` From 61c7449321c526fe3c36e899cead1ac11c39c466 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Sep 2012 09:50:35 +0300 Subject: [PATCH 15/50] Bulk user add on project -> new team member --- app/controllers/team_members_controller.rb | 13 +++++----- app/views/team_members/_form.html.haml | 25 ++++++++----------- .../project/project_team_steps.rb | 4 +-- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 0846f096..606cb972 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -17,13 +17,12 @@ class TeamMembersController < ApplicationController end def create - @team_member = UsersProject.new(params[:team_member]) - @team_member.project = project - if @team_member.save - redirect_to team_project_path(@project) - else - render "new" - end + @project.add_users_ids_to_team( + params[:user_ids], + params[:project_access] + ) + + redirect_to team_project_path(@project) end def update diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 208794b9..192f2735 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -1,4 +1,5 @@ -%h3= "New Team member" +%h3.page_title + = "New Team member(s)" %hr = form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| -if @team_member.errors.any? @@ -7,27 +8,23 @@ - @team_member.errors.full_messages.each do |msg| %li= msg + %h6 1. Choose people you want in the team .clearfix - = f.label :user_id, "Name" - .input= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, { style: "width:300px" }) + = f.label :user_ids, "Peolpe" + .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), { class: "xxlarge", multiple: true }) + %h6 2. Set access level for them .clearfix = f.label :project_access, "Project Access" - .input= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select" + .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select" .actions - = f.submit 'Save', class: "btn primary" - = link_to "Cancel", team_project_path(@project), class: "btn" + = f.submit 'Save', class: "btn save-btn" + = link_to "Cancel", team_project_path(@project), class: "btn cancel-btn" -:css - form select { - width:300px; - } :javascript - $('select#team_member_user_id').chosen(); - $('select#team_member_project_access').chosen(); - //$('select#team_member_repo_access').chosen(); - //$('select#team_member_project_access').chosen(); + $('select#user_ids').chosen(); + $('select#project_access').chosen(); diff --git a/features/step_definitions/project/project_team_steps.rb b/features/step_definitions/project/project_team_steps.rb index 0979a6ea..91885e46 100644 --- a/features/step_definitions/project/project_team_steps.rb +++ b/features/step_definitions/project/project_team_steps.rb @@ -22,8 +22,8 @@ end Given /^I select "(.*?)" as "(.*?)"$/ do |arg1, arg2| user = User.find_by_name(arg1) within "#new_team_member" do - select user.name, :from => "team_member_user_id" - select arg2, :from => "team_member_project_access" + select user.name, :from => "user_ids" + select arg2, :from => "project_access" end click_button "Save" end From fed6ab2481257e67822825fad1203ed073028a22 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Sep 2012 10:42:41 +0300 Subject: [PATCH 16/50] Change representation of team members. Group by role --- Gemfile.lock | 4 ++-- app/views/keys/index.html.haml | 4 ++-- app/views/projects/_team.html.haml | 17 +++++++++-------- app/views/team_members/_show.html.haml | 16 ++++++++-------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f350b3fc..d0b6a53a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM bcrypt-ruby (3.0.1) blankslate (2.1.2.4) bootstrap-sass (2.0.4.0) - builder (3.0.0) + builder (3.0.2) capybara (1.1.2) mime-types (>= 1.16) nokogiri (>= 1.3.3) @@ -125,7 +125,7 @@ GEM charlock_holmes (0.6.8) childprocess (0.3.2) ffi (~> 1.0.6) - chosen-rails (0.9.8) + chosen-rails (0.9.8.3) railties (~> 3.0) thor (~> 0.14) coderay (1.0.6) diff --git a/app/views/keys/index.html.haml b/app/views/keys/index.html.haml index 3e919c5c..fd5a9dad 100644 --- a/app/views/keys/index.html.haml +++ b/app/views/keys/index.html.haml @@ -3,7 +3,7 @@ = link_to "Add new", new_key_path, class: "btn right" %hr -%p.slead +%p.slead SSH key allows you to establish a secure connection between your computer and GitLab @@ -15,7 +15,7 @@ %th - @keys.each do |key| = render(partial: 'show', locals: {key: key}) - - if @keys.blank? + - if @keys.blank? %tr %td{colspan: 3} %h3.nothing_here_message There are no SSH keys with access to your account. diff --git a/app/views/projects/_team.html.haml b/app/views/projects/_team.html.haml index 0ddcf17f..0ab22984 100644 --- a/app/views/projects/_team.html.haml +++ b/app/views/projects/_team.html.haml @@ -1,11 +1,12 @@ -%table - %thead - %tr - %th User - %th Permissions - %tbody - - @project.users_projects.each do |up| - = render(partial: 'team_members/show', locals: {member: up}) +- @project.users_projects.group_by(&:project_access).each do |access, members| + %table + %thead + %tr + %th.span7= Project.access_options.key(access).pluralize + %th + %tbody + - members.each do |up| + = render(partial: 'team_members/show', locals: {member: up}) :javascript diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index 2dc4fb65..d9a72494 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -2,12 +2,6 @@ - allow_admin = can? current_user, :admin_project, @project %tr{id: dom_id(member), class: "team_member_row user_#{user.id}"} %td - .right - - if @project.owner == user - %span.label Project Owner - - if user.blocked - %span.label Blocked - = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do @@ -16,5 +10,11 @@ %div.cgray= user.email %td - = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f| - = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select", disabled: !allow_admin + .right + - if @project.owner == user + %span.btn.disabled.success Project Owner + - if user.blocked + %span.btn.disabled.blocked Blocked + - if allow_admin + = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f| + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select" From 09263719d536a3935c4b1d801472126ece28f283 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 13:56:13 +0300 Subject: [PATCH 17/50] Preselected Milestone: Cucumber scenario added --- features/projects/issues/issues.feature | 10 ++++++++++ .../step_definitions/project/project_issues_steps.rb | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature index 42a3d873..f0d9b610 100644 --- a/features/projects/issues/issues.feature +++ b/features/projects/issues/issues.feature @@ -64,3 +64,13 @@ Feature: Issues And I fill in issue search with "" Then I should see "Release 0.4" in issues And I should see "Release 0.3" in issues + + @javascript + @current + Scenario: I create Issue with pre-selected milestone + Given project "Shop" has milestone "v2.2" + And project "Shop" has milestone "v3.0" + And I visit project "Shop" issues page + When I select milestone "v3.0" + And I click link "New Issue" + Then I should see selected milestone with title "v3.0" diff --git a/features/step_definitions/project/project_issues_steps.rb b/features/step_definitions/project/project_issues_steps.rb index e46c1f42..ecf0892f 100644 --- a/features/step_definitions/project/project_issues_steps.rb +++ b/features/step_definitions/project/project_issues_steps.rb @@ -55,3 +55,15 @@ Given /^I fill in issue search with "(.*?)"$/ do |arg1| end fill_in 'issue_search', with: arg1 end + +When /^I select milestone "(.*?)"$/ do |milestone_title| + select milestone_title, from: "milestone_id" +end + +Then /^I should see selected milestone with title "(.*?)"$/ do |milestone_title| + issues_milestone_selector = "#issue_milestone_id_chzn/a" + wait_until{ + page.has_content?("Details") + } + page.find(issues_milestone_selector).should have_content(milestone_title) +end From b994a65fc318a91458fa8bb219e7ce07bd893eb5 Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 7 Sep 2012 15:36:40 +0300 Subject: [PATCH 18/50] change gitolite backend behaviour to prevent error when config directory removed --- lib/gitlab/backend/gitolite.rb | 2 +- lib/gitlab/backend/gitolite_config.rb | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index bc9e1f1d..658182c7 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -5,7 +5,7 @@ module Gitlab class AccessDenied < StandardError; end def config - @config ||= Gitlab::GitoliteConfig.new + Gitlab::GitoliteConfig.new end def set_key key_id, key_content, projects diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 5cf49121..47870edc 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -4,8 +4,10 @@ require 'fileutils' module Gitlab class GitoliteConfig - def config_tmp_dir - @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + attr_reader :config_tmp_dir + + def reset_config_tmp_dir + @config_tmp_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") end def apply @@ -13,9 +15,11 @@ module Gitlab File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| begin f.flock(File::LOCK_EX) + reset_config_tmp_dir pull yield(self) push + FileUtils.rm_rf(config_tmp_dir) ensure f.flock(File::LOCK_UN) end @@ -160,8 +164,6 @@ module Gitlab `git commit -am "GitLab"` `git push` Dir.chdir(Rails.root) - - FileUtils.rm_rf(config_tmp_dir) end end end From 26552051b7af709ad21497747405714006a14b68 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 16:35:59 +0300 Subject: [PATCH 19/50] Pre-selected milestone implemented --- app/assets/javascripts/issues.js | 21 +++++++++++++++++++ app/controllers/issues_controller.rb | 1 + app/views/issues/index.html.haml | 2 +- .../project/project_issues_steps.rb | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index aae818de..7f5694d0 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -80,6 +80,10 @@ function issuesPage(){ $(this).closest("form").submit(); }); + $("#new_issue_link").click(function(){ + updateNewIssueURL(); + }); + $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){ var t = $(this), totalIssues, @@ -126,3 +130,20 @@ function issuesCheckChanged() { $('.issues_filters').show(); } } + +function updateNewIssueURL(){ + var new_issue_link = $("#new_issue_link"); + var milestone_id = $("#milestone_id").val(); + var assignee_id = $("#assignee_id").val(); + var new_href = ""; + if(milestone_id){ + new_href = "milestone_id=" + milestone_id + "&"; + } + if(assignee_id){ + new_href = new_href + "assignee_id=" + assignee_id; + } + if(new_href.length){ + new_href = new_issue_link.attr("href") + "?" + new_href; + new_issue_link.attr("href", new_href); + } +}; diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index a47b3843..b98c0b01 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -38,6 +38,7 @@ class IssuesController < ApplicationController def new @issue = @project.issues.new + @issue.milestone_id = params[:milestone_id] if params[:milestone_id].present? respond_with(@issue) end diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index 010b8856..bc5c86e6 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -6,7 +6,7 @@ .right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true do + = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true, id: "new_issue_link" do %i.icon-plus New Issue = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do diff --git a/features/step_definitions/project/project_issues_steps.rb b/features/step_definitions/project/project_issues_steps.rb index ecf0892f..e4c169ec 100644 --- a/features/step_definitions/project/project_issues_steps.rb +++ b/features/step_definitions/project/project_issues_steps.rb @@ -57,6 +57,7 @@ Given /^I fill in issue search with "(.*?)"$/ do |arg1| end When /^I select milestone "(.*?)"$/ do |milestone_title| + #puts page.body select milestone_title, from: "milestone_id" end From c818c93aa7f8102dfd449bf2f1e82b36578e3ac7 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 16:51:37 +0300 Subject: [PATCH 20/50] Cucumber scenario on pre-selected assignee added --- features/projects/issues/issues.feature | 9 ++++++++- .../project/project_issues_steps.rb | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature index f0d9b610..2cfda136 100644 --- a/features/projects/issues/issues.feature +++ b/features/projects/issues/issues.feature @@ -66,7 +66,6 @@ Feature: Issues And I should see "Release 0.3" in issues @javascript - @current Scenario: I create Issue with pre-selected milestone Given project "Shop" has milestone "v2.2" And project "Shop" has milestone "v3.0" @@ -74,3 +73,11 @@ Feature: Issues When I select milestone "v3.0" And I click link "New Issue" Then I should see selected milestone with title "v3.0" + + @javascript + @current + Scenario: I create Issue with pre-selected assignee + When I select first assignee from "Shop" project + And I click link "New Issue" + Then I should see first assignee from "Shop" as selected assignee + diff --git a/features/step_definitions/project/project_issues_steps.rb b/features/step_definitions/project/project_issues_steps.rb index e4c169ec..d78da53c 100644 --- a/features/step_definitions/project/project_issues_steps.rb +++ b/features/step_definitions/project/project_issues_steps.rb @@ -57,14 +57,25 @@ Given /^I fill in issue search with "(.*?)"$/ do |arg1| end When /^I select milestone "(.*?)"$/ do |milestone_title| - #puts page.body select milestone_title, from: "milestone_id" end Then /^I should see selected milestone with title "(.*?)"$/ do |milestone_title| issues_milestone_selector = "#issue_milestone_id_chzn/a" - wait_until{ - page.has_content?("Details") - } + wait_until{ page.has_content?("Details") } page.find(issues_milestone_selector).should have_content(milestone_title) end + +When /^I select first assignee from "(.*?)" project$/ do |project_name| + project = Project.find_by_name project_name + first_assignee = project.users.first + select first_assignee.name, from: "assignee_id" +end + +Then /^I should see first assignee from "(.*?)" as selected assignee$/ do |project_name| + issues_assignee_selector = "#issue_assignee_id_chzn/a" + wait_until{ page.has_content?("Details") } + project = Project.find_by_name project_name + assignee_name = project.users.first.name + page.find(issues_assignee_selector).should have_content(assignee_name) +end From b462b0c6ebfea32ba816ee8c30bc5aa4e5049e91 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 16:52:48 +0300 Subject: [PATCH 21/50] Pre-selected assignee implemented --- app/controllers/issues_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index b98c0b01..05f5abb8 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -39,6 +39,7 @@ class IssuesController < ApplicationController def new @issue = @project.issues.new @issue.milestone_id = params[:milestone_id] if params[:milestone_id].present? + @issue.assignee_id = params[:assignee_id] if params[:assignee_id].present? respond_with(@issue) end From 320250cd7be1bbd6c2140344b8d3270728a84946 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 17:03:38 +0300 Subject: [PATCH 22/50] Cucumber tag removed --- features/projects/issues/issues.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature index 2cfda136..b2301b3f 100644 --- a/features/projects/issues/issues.feature +++ b/features/projects/issues/issues.feature @@ -75,7 +75,6 @@ Feature: Issues Then I should see selected milestone with title "v3.0" @javascript - @current Scenario: I create Issue with pre-selected assignee When I select first assignee from "Shop" project And I click link "New Issue" From 048117c05dd73acc7d6daff623ee5fdfe85a5d25 Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 7 Sep 2012 19:57:13 +0300 Subject: [PATCH 23/50] projects helper added --- app/helpers/projects_helper.rb | 6 ++++++ app/views/projects/_team.html.haml | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 app/helpers/projects_helper.rb diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb new file mode 100644 index 00000000..34dbb06c --- /dev/null +++ b/app/helpers/projects_helper.rb @@ -0,0 +1,6 @@ +module ProjectsHelper + def grouper_project_members(project) + @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) + end +end + diff --git a/app/views/projects/_team.html.haml b/app/views/projects/_team.html.haml index 0ab22984..a0c88b59 100644 --- a/app/views/projects/_team.html.haml +++ b/app/views/projects/_team.html.haml @@ -1,8 +1,9 @@ -- @project.users_projects.group_by(&:project_access).each do |access, members| +- grouper_project_members(@project).each do |access, members| %table %thead %tr - %th.span7= Project.access_options.key(access).pluralize + %th.span7 + = Project.access_options.key(access).pluralize %th %tbody - members.each do |up| From e8f39a0a61c4c91b8a5dc016474b6139a79a52e8 Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 7 Sep 2012 20:43:51 +0300 Subject: [PATCH 24/50] gitolite -> more exceptions --- lib/gitlab/backend/gitolite_config.rb | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index ff4c9014..61ec8c11 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -4,6 +4,9 @@ require 'fileutils' module Gitlab class GitoliteConfig + class PullError < StandardError; end + class PushError < StandardError; end + attr_reader :config_tmp_dir, :ga_repo, :conf def config_tmp_dir @@ -54,6 +57,14 @@ module Gitlab end end end + rescue PullError => ex + Gitlab::Logger.error("Pull error -> " + ex.message) + raise Gitolite::AccessDenied, ex.message + + rescue PushError => ex + Gitlab::Logger.error("Push error -> " + " " + ex.message) + raise Gitolite::AccessDenied, ex.message + rescue Exception => ex Gitlab::Logger.error(ex.class.name + " " + ex.message) raise Gitolite::AccessDenied.new("gitolite timeout") @@ -171,14 +182,21 @@ module Gitlab def pull tmp_dir Dir.mkdir tmp_dir `git clone #{Gitlab.config.gitolite_admin_uri} #{tmp_dir}/gitolite` + + unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf')) + raise PullError, "unable to clone gitolite-admin repo" + end end def push tmp_dir Dir.chdir(File.join(tmp_dir, "gitolite")) - `git add -A` - `git commit -am "GitLab"` - `git push` - Dir.chdir(Rails.root) + system('git add -A') + system('git commit -am "GitLab"') + if system('git push') + Dir.chdir(Rails.root) + else + raise PushError, "unable to push gitolite-admin repo" + end end end end From 367e17cc84bd432117f283d2e858a29d033e979f Mon Sep 17 00:00:00 2001 From: randx Date: Fri, 7 Sep 2012 20:47:52 +0300 Subject: [PATCH 25/50] 5xx error status code for gitolite & encoding error --- app/controllers/application_controller.rb | 4 ++-- app/views/errors/encoding.html.haml | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2fe2a974..a0040298 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -11,11 +11,11 @@ class ApplicationController < ActionController::Base helper_method :abilities, :can? rescue_from Gitlab::Gitolite::AccessDenied do |exception| - render "errors/gitolite", layout: "error" + render "errors/gitolite", layout: "error", status: 500 end rescue_from Encoding::CompatibilityError do |exception| - render "errors/encoding", layout: "error", status: 404 + render "errors/encoding", layout: "error", status: 500 end rescue_from ActiveRecord::RecordNotFound do |exception| diff --git a/app/views/errors/encoding.html.haml b/app/views/errors/encoding.html.haml index 4662437f..d7b5e68e 100644 --- a/app/views/errors/encoding.html.haml +++ b/app/views/errors/encoding.html.haml @@ -1,5 +1,3 @@ -.alert-message.block-message.error - %h3 Encoding Error - %hr - %p - Page can't be loaded because of an encoding error. +%h1 Encoding Error +%hr +%p Page can't be loaded because of an encoding error. From 1b83af6eed3a4069a8f66a6785632e6f950e900f Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Fri, 7 Sep 2012 20:59:12 +0300 Subject: [PATCH 26/50] IssueController#new refactored --- app/assets/javascripts/issues.js | 4 ++-- app/controllers/issues_controller.rb | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 7f5694d0..148dc7b9 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -137,10 +137,10 @@ function updateNewIssueURL(){ var assignee_id = $("#assignee_id").val(); var new_href = ""; if(milestone_id){ - new_href = "milestone_id=" + milestone_id + "&"; + new_href = "issue[milestone_id]=" + milestone_id + "&"; } if(assignee_id){ - new_href = new_href + "assignee_id=" + assignee_id; + new_href = new_href + "issue[assignee_id]=" + assignee_id; } if(new_href.length){ new_href = new_issue_link.attr("href") + "?" + new_href; diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 05f5abb8..3d305238 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -37,9 +37,7 @@ class IssuesController < ApplicationController end def new - @issue = @project.issues.new - @issue.milestone_id = params[:milestone_id] if params[:milestone_id].present? - @issue.assignee_id = params[:assignee_id] if params[:assignee_id].present? + @issue = @project.issues.new(params[:issue]) respond_with(@issue) end From 5348ee62787a12855d8d917580fdcc8900910386 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 7 Sep 2012 22:14:17 +0200 Subject: [PATCH 27/50] Fix Ruby anti-pattern in Markdown --- lib/gitlab/markdown.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 17f865bb..afb61364 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -80,7 +80,7 @@ module Gitlab # # Returns parsed text def parse(text) - text = text.gsub(REFERENCE_PATTERN) do |match| + text.gsub!(REFERENCE_PATTERN) do |match| prefix = $1 || '' reference = $2 identifier = $3 || $4 || $5 @@ -93,7 +93,7 @@ module Gitlab end end - text = text.gsub(EMOJI_PATTERN) do |match| + text.gsub!(EMOJI_PATTERN) do |match| if valid_emoji?($2) image_tag("emoji/#{$2}.png", size: "20x20", class: 'emoji', title: $1, alt: $1) else From 130520fa5e9a09c53d3162ce82576f3b3544e158 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 01:06:17 +0200 Subject: [PATCH 28/50] Reorder blocks in Markdown help --- app/views/help/markdown.html.haml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml index 2086b08c..e2f8e709 100644 --- a/app/views/help/markdown.html.haml +++ b/app/views/help/markdown.html.haml @@ -20,6 +20,15 @@ %li milestones %li wiki pages + .span4 + .alert.alert-info + %p + If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent + %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax" + at Daring Fireball. + +.row + .span8 %h3 Differences from traditional Markdown %h4 Newlines @@ -93,12 +102,5 @@ %p For example in your #{link_to @project.name, project_path(@project)} project, writing: %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." %p becomes: - %pre= gfm "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." + = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." - @project = nil # Prevent this from bubbling up to page title - - .span4.right - .alert.alert-info - %p - If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent - %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax" - at Daring Fireball. From f4a90bc9f3ad4e6e9938736e3815eb84ec299af8 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 01:08:07 +0200 Subject: [PATCH 29/50] Add emoji docs to Markdown help --- app/views/help/markdown.html.haml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml index e2f8e709..aa608ed6 100644 --- a/app/views/help/markdown.html.haml +++ b/app/views/help/markdown.html.haml @@ -71,6 +71,29 @@ %p becomes = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} + %h4 Emoji + +.row + .span8 + :ruby + puts markdown %Q{Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you: + + :exclamation: You can use emoji anywhere GFM is supported. :sunglasses: + + You can use it to point out a :bug: or warn about :monkey:patches. And if someone improves your really :snail: code, send them a :bouquet: or some :candy:. People will :heart: you for that. + + If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes. + } + + .span4 + .alert.alert-info + %p + Consult the + %strong= link_to "Emoji Cheat Sheet", "http://www.emoji-cheat-sheet.com/" + for a list of all supported emoji codes. + +.row + .span8 %h4 Special GitLab references %p From 9a4c22d395b96e27f9a1c5ec90b161ddf5815cdd Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 01:11:32 +0200 Subject: [PATCH 30/50] Remove unnecessary check in Markdown helper --- app/helpers/gitlab_markdown_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index ca2cb01f..e97e46f5 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -27,7 +27,7 @@ module GitlabMarkdownHelper filter_html: true, with_toc_data: true, hard_wrap: true) - @markdown ||= Redcarpet::Markdown.new(gitlab_renderer, + @markdown = Redcarpet::Markdown.new(gitlab_renderer, # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use no_intra_emphasis: true, tables: true, From ce3fb949398786c9cc9c9d7803b72cb57f661279 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Sat, 8 Sep 2012 00:49:17 +0200 Subject: [PATCH 31/50] Fix bug where parsing of emoji was unnecessarily dependent on @project being set --- lib/gitlab/markdown.rb | 7 +++++-- spec/helpers/gitlab_markdown_helper_spec.rb | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index afb61364..f9125e03 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -47,7 +47,6 @@ module Gitlab # Note: reference links will only be generated if @project is set def gfm(text, html_options = {}) return text if text.nil? - return text if @project.nil? @html_options = html_options @@ -78,8 +77,11 @@ module Gitlab # # text - Text to parse # + # Note: reference links will only be generated if @project is set + # # Returns parsed text def parse(text) + # parse reference links text.gsub!(REFERENCE_PATTERN) do |match| prefix = $1 || '' reference = $2 @@ -91,8 +93,9 @@ module Gitlab else match end - end + end if @project + # parse emoji text.gsub!(EMOJI_PATTERN) do |match| if valid_emoji?($2) image_tag("emoji/#{$2}.png", size: "20x20", class: 'emoji', title: $1, alt: $1) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 3e7a02c6..4dd3802a 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -247,6 +247,11 @@ describe GitlabMarkdownHelper do it "ignores invalid emoji" do gfm(":invalid-emoji:").should_not match(/ Date: Sat, 8 Sep 2012 01:58:12 +0200 Subject: [PATCH 32/50] Prevent gfm() to leak changes to the string supplied through the _text_ argument --- lib/gitlab/markdown.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index f9125e03..4fc0c392 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -48,6 +48,9 @@ module Gitlab def gfm(text, html_options = {}) return text if text.nil? + # prevents the string supplied through the _text_ argument to be altered + text = text.dup + @html_options = html_options # Extract pre blocks so they are not altered From 2e76342d72fac88e98820f038dce8fa01952fefb Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 12:37:23 +0300 Subject: [PATCH 33/50] typo fixed --- app/roles/team.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/roles/team.rb b/app/roles/team.rb index d8798c50..8aef405a 100644 --- a/app/roles/team.rb +++ b/app/roles/team.rb @@ -45,7 +45,7 @@ module Team end # Delete multiple users from project by user ids - def delete_users_by_ids(users_ids) + def delete_users_ids_from_team(users_ids) UsersProject.bulk_delete(self, users_ids) self.update_repository end From cc7c6d53966e7501da0af87481b7e7ef2b2025c2 Mon Sep 17 00:00:00 2001 From: Valeriy Sizov Date: Sat, 8 Sep 2012 13:35:00 +0300 Subject: [PATCH 34/50] New project form: spec for autocomplete --- spec/requests/projects_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/requests/projects_spec.rb b/spec/requests/projects_spec.rb index 63f8a696..92e89a16 100644 --- a/spec/requests/projects_spec.rb +++ b/spec/requests/projects_spec.rb @@ -3,6 +3,16 @@ require 'spec_helper' describe "Projects" do before { login_as :user } + describe 'GET /project/new' do + it "should work autocomplete", :js => true do + visit new_project_path + + fill_in 'project_name', with: 'Awesome' + find("#project_path").value.should == 'awesome' + find("#project_code").value.should == 'awesome' + end + end + describe "GET /projects/show" do before do @project = Factory :project, owner: @user From 8559d9a156819b576127a944dbcce1fe335d68ba Mon Sep 17 00:00:00 2001 From: Dae Myung Date: Sat, 8 Sep 2012 04:24:38 -0700 Subject: [PATCH 35/50] sending argument project but there is no project to send --- lib/gitlab/backend/gitolite.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index 658182c7..fe5dcef4 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -35,7 +35,7 @@ module Gitlab end def enable_automerge - config.admin_all_repo!(project) + config.admin_all_repo! end alias_method :create_repository, :update_repository From 8a3408180ab51effd516de3c8e85d564aa4dfabd Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 17:40:36 +0300 Subject: [PATCH 36/50] move "users" test after project tests --- spec/requests/api/projects_spec.rb | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8c294594..71ed39e7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -67,33 +67,6 @@ describe Gitlab::API do 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, "1" => user3.id}, project_access: UsersProject::DEVELOPER - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) - end - end - - describe "PUT /projects/:id/users" do - it "should update users to new access role" do - expect { - put api("/projects/#{project.code}/users", user), - user_ids: {"0" => user}, project_access: UsersProject::DEVELOPER - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) - end - end - - describe "DELETE /projects/:id/users" do - it "should delete users from project" do - expect { - delete api("/projects/#{project.code}/delete", user), - user_ids: {"0" => users_project.id} - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(-1) - end - end - describe "GET /projects/:id" do it "should return a project by id" do get api("/projects/#{project.id}", user) @@ -134,6 +107,33 @@ describe Gitlab::API do 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, "1" => user3.id}, project_access: UsersProject::DEVELOPER + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + end + end + + describe "PUT /projects/:id/users" do + it "should update users to new access role" do + expect { + put api("/projects/#{project.code}/users", user), + user_ids: {"0" => user}, project_access: UsersProject::DEVELOPER + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) + end + end + + describe "DELETE /projects/:id/users" do + it "should delete users from project" do + expect { + delete api("/projects/#{project.code}/users", user), + user_ids: {"0" => users_project.id} + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(-1) + end + end + describe "GET /projects/:id/repository/tags" do it "should return an array of project tags" do get api("/projects/#{project.code}/repository/tags", user) From 0d1009af85c1ed6936a568e9bab9e4da28e69a30 Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 17:51:28 +0300 Subject: [PATCH 37/50] "users" GET test added --- spec/requests/api/projects_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 71ed39e7..e224982a 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -107,6 +107,18 @@ describe Gitlab::API do end end + describe "GET /projects/:id/users" do + it "should return project users" do + get api("/projects/#{project.code}/users", user) + + response.status.should == 200 + + json_response.should be_an Array + json_response.count.should == 1 + json_response.first['user']['id'].should == user.id + end + end + describe "POST /projects/:id/users" do it "should add users to project" do expect { From 499ff8b441b517902a0daf79600a59cc1830730e Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 19:39:10 +0300 Subject: [PATCH 38/50] fix failing tests --- spec/requests/api/projects_spec.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index e224982a..439aecce 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -8,7 +8,8 @@ describe Gitlab::API do let(:user3) { Factory.create(:user) } let!(:project) { Factory :project, owner: user } let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } - let!(:users_project) { Factory :users_project, user: user, project: project } + let!(:users_project) { Factory :users_project, user: user, project: project, project_access: UsersProject::MASTER } + let!(:users_project2) { Factory :users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER } before { project.add_access(user, :read) } describe "GET /projects" do @@ -114,7 +115,7 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array - json_response.count.should == 1 + json_response.count.should == 2 json_response.first['user']['id'].should == user.id end end @@ -123,8 +124,8 @@ describe Gitlab::API do it "should add users to project" do expect { post api("/projects/#{project.code}/users", user), - user_ids: {"0" => user2.id, "1" => user3.id}, project_access: UsersProject::DEVELOPER - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(2) + user_ids: {"0" => user2.id}, project_access: UsersProject::DEVELOPER + }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) end end @@ -132,8 +133,8 @@ describe Gitlab::API do it "should update users to new access role" do expect { put api("/projects/#{project.code}/users", user), - user_ids: {"0" => user}, project_access: UsersProject::DEVELOPER - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(1) + user_ids: {"0" => user3.id}, project_access: UsersProject::MASTER + }.to change {project.users_projects.where(:project_access => UsersProject::MASTER).count}.by(1) end end @@ -141,8 +142,8 @@ describe Gitlab::API do it "should delete users from project" do expect { delete api("/projects/#{project.code}/users", user), - user_ids: {"0" => users_project.id} - }.to change {project.users_projects.where(:project_access => UsersProject::DEVELOPER).count}.by(-1) + user_ids: {"0" => user3.id} + }.to change {project.users_projects.count}.by(-1) end end From 27e443650746ddb7bf63d9a34d4afaa15350521d Mon Sep 17 00:00:00 2001 From: miks Date: Sat, 8 Sep 2012 20:01:08 +0300 Subject: [PATCH 39/50] Return empty body --- lib/api/projects.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6e445b2a..7da83429 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -75,6 +75,7 @@ module Gitlab # POST /projects/:id/users post ":id/users" do user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) + nil end # Update users to specified access level @@ -87,6 +88,7 @@ module Gitlab # PUT /projects/:id/add_users put ":id/users" do user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) + nil end # Delete project users @@ -98,6 +100,7 @@ module Gitlab # DELETE /projects/:id/users delete ":id/users" do user_project.delete_users_ids_from_team(params[:user_ids].values) + nil end # Get a project repository branches From 1c0153682927f72f6b3011db11ddf5a139f9d16a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 05:40:22 -0400 Subject: [PATCH 40/50] Fix spelling of "empty" in disableButtonIfEmptyField function name --- app/assets/javascripts/issues.js | 4 ++-- app/assets/javascripts/note.js | 4 ++-- app/assets/javascripts/projects.js.coffee | 2 +- app/views/merge_requests/_form.html.haml | 2 +- app/views/milestones/_form.html.haml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 148dc7b9..3ddc6926 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -5,7 +5,7 @@ function switchToNewIssue(form){ $('select#issue_milestone_id').chosen(); $("#new_issue_dialog").show("fade", { direction: "right" }, 150); $('.top-tabs .add_new').hide(); - disableButtonIfEmtpyField("#issue_title", ".save-btn"); + disableButtonIfEmptyField("#issue_title", ".save-btn"); }); } @@ -16,7 +16,7 @@ function switchToEditIssue(form){ $('select#issue_milestone_id').chosen(); $("#edit_issue_dialog").show("fade", { direction: "right" }, 150); $('.add_new').hide(); - disableButtonIfEmtpyField("#issue_title", ".save-btn"); + disableButtonIfEmptyField("#issue_title", ".save-btn"); }); } diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index 9cd3e36e..160f75c9 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -32,7 +32,7 @@ var NoteList = { $(".submit_note").removeAttr("disabled"); }) - disableButtonIfEmtpyField(".note-text", ".submit_note"); + disableButtonIfEmptyField(".note-text", ".submit_note"); $(".note-text").live("focus", function(){ $(this).css("height", "80px"); @@ -177,6 +177,6 @@ var PerLineNotes = { form.show(); return false; }); - disableButtonIfEmtpyField(".line-note-text", ".submit_inline_note"); + disableButtonIfEmptyField(".line-note-text", ".submit_inline_note"); } } diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee index 85ab2a06..14738e14 100644 --- a/app/assets/javascripts/projects.js.coffee +++ b/app/assets/javascripts/projects.js.coffee @@ -8,7 +8,7 @@ window.Projects = -> $('.save-project-loader').show() $('form #project_default_branch').chosen() - disableButtonIfEmtpyField '#project_name', '.project-submit' + disableButtonIfEmptyField '#project_name', '.project-submit' # Git clone panel switcher $ -> diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index b554c051..d5271ed0 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -60,7 +60,7 @@ :javascript $(function(){ - disableButtonIfEmtpyField("#merge_request_title", ".save-btn"); + disableButtonIfEmptyField("#merge_request_title", ".save-btn"); $('select#merge_request_assignee_id').chosen(); $('select#merge_request_source_branch').chosen(); $('select#merge_request_target_branch').chosen(); diff --git a/app/views/milestones/_form.html.haml b/app/views/milestones/_form.html.haml index ce4145ba..194eac77 100644 --- a/app/views/milestones/_form.html.haml +++ b/app/views/milestones/_form.html.haml @@ -41,7 +41,7 @@ :javascript $(function() { - disableButtonIfEmtpyField("#milestone_title", ".save-btn"); + disableButtonIfEmptyField("#milestone_title", ".save-btn"); $( ".datepicker" ).datepicker({ dateFormat: "yy-mm-dd", onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } From 93daa8c568cff8c59eb77c7a47b72e0266613d5a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 05:30:49 -0400 Subject: [PATCH 41/50] Move main.js to main.js.coffee --- app/assets/javascripts/{main.js => main.js.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/{main.js => main.js.coffee} (100%) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js.coffee similarity index 100% rename from app/assets/javascripts/main.js rename to app/assets/javascripts/main.js.coffee From 3b89f140905dd1e929d5bf587fa2509866ba5d32 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 05:59:15 -0400 Subject: [PATCH 42/50] Convert main.js to coffee Remove duplicate 's' hotkey code --- app/assets/javascripts/main.js.coffee | 176 +++++++++--------------- app/views/layouts/_head_panel.html.haml | 8 -- 2 files changed, 65 insertions(+), 119 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 61af1dc3..a614cf5b 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -1,130 +1,84 @@ -$(document).ready(function(){ +window.updatePage = (data) -> + $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}) - $(".one_click_select").live("click", function(){ - $(this).select(); - }); +window.slugify = (text) -> + text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() - $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){ - var buttons = $('[type="submit"]', this); - switch( e.type ){ - case 'ajax:beforeSend': - case 'submit': - buttons.attr('disabled', 'disabled'); - break; - case ' ajax:complete': - default: - buttons.removeAttr('disabled'); - break; - } - }) +window.ajaxGet = (url) -> + $.ajax({type: "GET", url: url, dataType: "script"}) - $(".account-box").mouseenter(showMenu); - $(".account-box").mouseleave(resetMenu); + # Disable button if text field is empty +window.disableButtonIfEmptyField = (field_selector, button_selector) -> + field = $(field_selector) + closest_submit = field.closest("form").find(button_selector) - $("#projects-list .project").live('click', function(e){ - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { - location.href = $(this).attr("url"); - e.stopPropagation(); - return false; - } - }); + closest_submit.attr("disabled", "disabled").addClass("disabled") if field.val() is "" - /** - * Focus search field by pressing 's' key - */ - $(document).keypress(function(e) { - if( $(e.target).is(":input") ) return; - switch(e.which) { - case 115: focusSearch(); - e.preventDefault(); - } - }); + field.on "keyup", -> + if $(this).val() is "" + closest_submit.attr("disabled", "disabled").addClass "disabled" + else + closest_submit.removeAttr("disabled").removeClass "disabled" - /** - * Commit show suppressed diff - * - */ - $(".supp_diff_link").bind("click", function() { - showDiff(this); - }); +$ -> + $(".one_click_select").live 'click', -> + $(this).select() - /** - * Note markdown preview - * - */ - $(document).on('click', '#preview-link', function(e) { - $('#preview-note').text('Loading...'); + $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> + buttons = $('[type="submit"]', this) - var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); - $(this).text(previewLinkText); + switch e.type + when 'ajax:beforeSend', 'submit' + buttons.attr('disabled', 'disabled') + else + buttons.removeAttr('disabled') - var note = $('#note_note').val(); - if (note.trim().length === 0) { note = 'Nothing to preview'; } - $.post($(this).attr('href'), {note: note}, function(data) { - $('#preview-note').html(data); - }); + # Show/Hide the profile menu when hovering the account box + $('.account-box').hover -> $(this).toggleClass('hover') - $('#preview-note, #note_note').toggle(); - e.preventDefault(); - }); -}); + $("#projects-list .project").live 'click', (e) -> + if e.target.nodeName isnt "A" and e.target.nodeName isnt "INPUT" + location.href = $(this).attr("url") + e.stopPropagation() + false -function focusSearch() { - $("#search").focus(); -} + # Focus search field by pressing 's' key + $(document).keypress (e) -> + # Don't do anything if typing in an input + return if $(e.target).is(":input") -function updatePage(data){ - $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); -} + switch e.which + when 115 + $("#search").focus() + e.preventDefault() -function showMenu() { - $(this).toggleClass('hover'); -} + # Commit show suppressed diff + $(".supp_diff_link").bind "click", -> + $(this).next('table').show() + $(this).remove() -function resetMenu() { - $(this).removeClass("hover"); -} + # Note markdown preview + $(document).on 'click', '#preview-link', (e) -> + $('#preview-note').text('Loading...') -function slugify(text) { - return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase(); -} + previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview' + $(this).text(previewLinkText) -function showDiff(link) { - $(link).next('table').show(); - $(link).remove(); -} + note = $('#note_note').val() + note = 'Nothing to preview' if note.trim().length is 0 + $.post($(this).attr('href'), {note: note}, (data) -> + $('#preview-note').html(data) + ) -(function($){ - var _chosen = $.fn.chosen; - $.fn.extend({ - chosen: function(options) { - var default_options = {'search_contains' : 'true'}; - $.extend(default_options, options); - return _chosen.apply(this, [default_options]); - }}) -})(jQuery); + $('#preview-note, #note_note').toggle() + e.preventDefault() + false +(($) -> + _chosen = $.fn.chosen + $.fn.extend chosen: (options) -> + default_options = search_contains: "true" + $.extend default_options, options + _chosen.apply this, [default_options] -function ajaxGet(url) { - $.ajax({type: "GET", url: url, dataType: "script"}); -} - -/** - * Disable button if text field is empty - */ -function disableButtonIfEmtpyField(field_selector, button_selector) { - field = $(field_selector); - if(field.val() == "") { - field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled"); - } - - field.on('keyup', function(){ - var field = $(this); - var closest_submit = field.closest("form").find(button_selector); - if(field.val() == "") { - closest_submit.attr("disabled", "disabled").addClass("disabled"); - } else { - closest_submit.removeAttr("disabled").removeClass("disabled"); - } - }) -} +)(jQuery) diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index d6247d36..f5e423a5 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -34,12 +34,4 @@ source: #{raw search_autocomplete_source}, select: function(event, ui) { location.href = ui.item.url } }); - - $(document).keypress(function(e) { - if($(e.target).is(":input")) return; - switch(e.which) { - case 115: focusSearch(); - e.preventDefault(); - } - }); }); From ad1aa517c7052d26e7243f6574b3deacddd0b161 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 07:08:13 -0400 Subject: [PATCH 43/50] Add "enable" and "disable" jQuery functions Handles (un)setting the disabled attribute and adding/removing the 'disabled' class --- app/assets/javascripts/main.js.coffee | 19 ++++++++++++++----- app/assets/javascripts/note.js | 4 ++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index a614cf5b..84129069 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -12,26 +12,27 @@ window.disableButtonIfEmptyField = (field_selector, button_selector) -> field = $(field_selector) closest_submit = field.closest("form").find(button_selector) - closest_submit.attr("disabled", "disabled").addClass("disabled") if field.val() is "" + closest_submit.disable() if field.val() is "" field.on "keyup", -> if $(this).val() is "" - closest_submit.attr("disabled", "disabled").addClass "disabled" + closest_submit.disable() else - closest_submit.removeAttr("disabled").removeClass "disabled" + closest_submit.enable() $ -> $(".one_click_select").live 'click', -> $(this).select() + # Disable form buttons while a form is submitting $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> buttons = $('[type="submit"]', this) switch e.type when 'ajax:beforeSend', 'submit' - buttons.attr('disabled', 'disabled') + buttons.disable() else - buttons.removeAttr('disabled') + buttons.enable() # Show/Hide the profile menu when hovering the account box $('.account-box').hover -> $(this).toggleClass('hover') @@ -81,4 +82,12 @@ $ -> $.extend default_options, options _chosen.apply this, [default_options] + # Disable an element and add the 'disabled' Bootstrap class + $.fn.extend disable: -> + $(this).attr('disabled', 'disabled').addClass('disabled') + + # Enable an element and remove the 'disabled' Bootstrap class + $.fn.extend enable: -> + $(this).removeAttr('disabled').removeClass('disabled') + )(jQuery) diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index 160f75c9..79ab086b 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -25,11 +25,11 @@ var NoteList = { $(this).closest('li').fadeOut(); }); $(".note-form-holder").live("ajax:before", function(){ - $(".submit_note").attr("disabled", "disabled"); + $(".submit_note").disable() }) $(".note-form-holder").live("ajax:complete", function(){ - $(".submit_note").removeAttr("disabled"); + $(".submit_note").enable() }) disableButtonIfEmptyField(".note-text", ".submit_note"); From 3551df8eb1c1bfe3a4cef532ddab1cbdcdd96a11 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 07:17:01 -0400 Subject: [PATCH 44/50] Minor main.js refactor and docs --- app/assets/javascripts/main.js.coffee | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 84129069..6002f85d 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -21,8 +21,8 @@ window.disableButtonIfEmptyField = (field_selector, button_selector) -> closest_submit.enable() $ -> - $(".one_click_select").live 'click', -> - $(this).select() + # Click a .one_click_select field, select the contents + $(".one_click_select").live 'click', -> $(this).select() # Disable form buttons while a form is submitting $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> @@ -66,10 +66,12 @@ $ -> $(this).text(previewLinkText) note = $('#note_note').val() - note = 'Nothing to preview' if note.trim().length is 0 - $.post($(this).attr('href'), {note: note}, (data) -> - $('#preview-note').html(data) - ) + + if note.trim().length == 0 + $('#preview-note').text("Nothing to preview.") + else + $.post $(this).attr('href'), {note: note}, (data) -> + $('#preview-note').html(data) $('#preview-note, #note_note').toggle() e.preventDefault() From 5dcca7e4806730d4d77eff711a9b91b5a3ca8314 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 9 Sep 2012 07:17:43 -0400 Subject: [PATCH 45/50] Remove some JS that is no longer used --- app/assets/javascripts/main.js.coffee | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 6002f85d..a01b3932 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -37,12 +37,6 @@ $ -> # Show/Hide the profile menu when hovering the account box $('.account-box').hover -> $(this).toggleClass('hover') - $("#projects-list .project").live 'click', (e) -> - if e.target.nodeName isnt "A" and e.target.nodeName isnt "INPUT" - location.href = $(this).attr("url") - e.stopPropagation() - false - # Focus search field by pressing 's' key $(document).keypress (e) -> # Don't do anything if typing in an input From ad3a88cfd34aeed5ed69b4056e393580a686fb09 Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 29 Aug 2012 02:03:04 +0300 Subject: [PATCH 46/50] Prepared for gitolite v3 --- app/models/merge_request.rb | 2 +- app/roles/push_event.rb | 2 ++ config/gitlab.yml.example | 4 ++-- doc/installation.md | 15 +++++++++------ lib/gitlab/merge.rb | 3 +-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 542817b0..2e457f72 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -162,7 +162,7 @@ class MergeRequest < ActiveRecord::Base end def automerge!(current_user) - if Gitlab::Merge.new(self, current_user).merge + if Gitlab::Merge.new(self, current_user).merge && self.unmerged_commits.empty? self.merge!(current_user.id) true end diff --git a/app/roles/push_event.rb b/app/roles/push_event.rb index ff8e28a2..a607f212 100644 --- a/app/roles/push_event.rb +++ b/app/roles/push_event.rb @@ -90,6 +90,8 @@ module PushEvent def push_with_commits? md_ref? && commits.any? && parent_commit && last_commit + rescue Grit::NoSuchPathError + false end def last_push_to_non_root? diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index d05cc1be..77b818ba 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -33,11 +33,11 @@ app: git_host: admin_uri: git@localhost:gitolite-admin base_path: /home/git/repositories/ - # hooks_path: /var/lib/gitolite/.gitolite/hooks/ # only needed when gitolite is not installed according the manual - # host: localhost + hooks_path: /home/git/.gitolite/hooks/ git_user: git upload_pack: true receive_pack: true + # host: localhost # port: 22 # Git settings diff --git a/doc/installation.md b/doc/installation.md index e14ec711..af169d81 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -113,17 +113,20 @@ Generate key: Clone GitLab's fork of the Gitolite source code: cd /home/git - sudo -H -u git git clone https://github.com/gitlabhq/gitolite.git /home/git/gitolite + sudo -H -u git git clone -b gl-v304 https://github.com/gitlabhq/gitolite.git /home/git/gitolite Setup: + cd /home/git + sudo -u git -H mkdir bin sudo -u git sh -c 'echo -e "PATH=\$PATH:/home/git/bin\nexport PATH" >> /home/git/.profile' - sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; /home/git/gitolite/src/gl-system-install" + sudo -u git sh -c 'gitolite/install -ln /home/git/bin' + sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub sudo chmod 0444 /home/git/gitlab.pub - sudo -u git -H sed -i 's/0077/0007/g' /home/git/share/gitolite/conf/example.gitolite.rc - sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub" + sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub" + sudo -u git -H sed -i 's/0077/0007/g' /home/git/.gitolite.rc Permissions: @@ -189,8 +192,8 @@ and ensure you have followed all of the above steps carefully. #### Setup GitLab hooks - sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive - sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive + sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive + sudo chown git:git /home/git/.gitolite/hooks/common/post-receive #### Check application status diff --git a/lib/gitlab/merge.rb b/lib/gitlab/merge.rb index 134695ce..18013574 100644 --- a/lib/gitlab/merge.rb +++ b/lib/gitlab/merge.rb @@ -21,8 +21,7 @@ module Gitlab if output =~ /CONFLICT/ false else - repo.git.push({}, "origin", merge_request.target_branch) - true + !!repo.git.push({}, "origin", merge_request.target_branch) end end end From a56cec113204130385e0fbc3f2223d81101357ef Mon Sep 17 00:00:00 2001 From: randx Date: Wed, 29 Aug 2012 02:08:39 +0300 Subject: [PATCH 47/50] specify gitolite-admin owner in config --- config/gitlab.yml.example | 1 + config/initializers/1_settings.rb | 4 ++++ lib/gitlab/backend/gitolite_config.rb | 13 +------------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 77b818ba..08e3427f 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -34,6 +34,7 @@ git_host: admin_uri: git@localhost:gitolite-admin base_path: /home/git/repositories/ hooks_path: /home/git/.gitolite/hooks/ + gitolite_admin_key: gitlab git_user: git upload_pack: true receive_pack: true diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 27c5bc22..df9ccf32 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -102,6 +102,10 @@ class Settings < Settingslogic git_host['admin_uri'] || 'git@localhost:gitolite-admin' end + def gitolite_admin_key + git_host['gitolite_admin_key'] || 'gitlab' + end + def default_projects_limit app['default_projects_limit'] || 10 end diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 61ec8c11..60eef8e8 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -148,18 +148,7 @@ module Gitlab # Enable access to all repos for gitolite admin. # We use it for accept merge request feature def admin_all_repo - owner_name = "" - - # Read gitolite-admin user - # - begin - repo = conf.get_repo("gitolite-admin") - owner_name = repo.permissions[0]["RW+"][""][0] - raise StandardError if owner_name.blank? - rescue => ex - puts "Can't determine gitolite-admin owner".red - raise StandardError - end + owner_name = Gitlab.settings.gitolite_admin_key # @ALL repos premission for gitolite owner repo_name = "@all" From a86bd87afcb8ba8221aa72562a6591139fa763c0 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sun, 9 Sep 2012 23:18:28 +0300 Subject: [PATCH 48/50] User joined project event added --- app/assets/stylesheets/common.scss | 8 ++++++++ app/decorators/event_decorator.rb | 5 ++++- app/models/event.rb | 9 ++++++++- app/observers/users_project_observer.rb | 6 ++++++ app/views/events/_event.html.haml | 4 ++++ app/views/events/_event_joined.html.haml | 8 ++++++++ features/dashboard/dashboard.feature | 7 ++++++- features/step_definitions/dashboard_steps.rb | 15 +++++++++++++++ spec/models/event_spec.rb | 11 +++++++++++ spec/observers/users_project_observer_spec.rb | 8 ++++++++ 10 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 app/views/events/_event_joined.html.haml diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index aa27a280..012aad03 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -179,6 +179,14 @@ span.update-author { &.merged { background-color: #2A2; } + + &.joined { + background-color: #1cb9ff; + } + + &.left { + background-color: #ff5057; + } } form { diff --git a/app/decorators/event_decorator.rb b/app/decorators/event_decorator.rb index 7df9081f..265dbe1a 100644 --- a/app/decorators/event_decorator.rb +++ b/app/decorators/event_decorator.rb @@ -8,7 +8,10 @@ class EventDecorator < ApplicationDecorator "#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title elsif self.push? "#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name - else + elsif self.joined? + "#{self.author_name} #{self.action_name} #{self.project.name}" + + else "" end end diff --git a/app/models/event.rb b/app/models/event.rb index e20b79e2..15095d3b 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -10,6 +10,7 @@ class Event < ActiveRecord::Base Pushed = 5 Commented = 6 Merged = 7 + Joined = 8 # User joined project belongs_to :project belongs_to :target, polymorphic: true @@ -37,7 +38,7 @@ class Event < ActiveRecord::Base # - new issue # - merge request def allowed? - push? || issue? || merge_request? + push? || issue? || merge_request? || joined? end def push? @@ -84,6 +85,10 @@ class Event < ActiveRecord::Base [Closed, Reopened].include?(action) end + def joined? + action == self.class::Joined + end + def issue target if target_type == "Issue" end @@ -101,6 +106,8 @@ class Event < ActiveRecord::Base "closed" elsif merged? "merged" + elsif joined? + 'joined' else "opened" end diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index 763b2c87..2a98a194 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -1,6 +1,12 @@ class UsersProjectObserver < ActiveRecord::Observer def after_create(users_project) Notify.project_access_granted_email(users_project.id).deliver + + Event.create( + project_id: users_project.project.id, + action: Event::Joined, + author_id: users_project.user.id + ) end def after_update(users_project) diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index d49f0382..7566c094 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -11,3 +11,7 @@ .event_feed = render "events/event_push", event: event + - elsif event.joined? + .event_feed + = render "events/event_joined", event: event + diff --git a/app/views/events/_event_joined.html.haml b/app/views/events/_event_joined.html.haml new file mode 100644 index 00000000..6195da81 --- /dev/null +++ b/app/views/events/_event_joined.html.haml @@ -0,0 +1,8 @@ += image_tag gravatar_icon(event.author_email), class: "avatar" +%strong #{event.author_name} +%span.event_label{class: event.action_name}= event.action_name +%strong= link_to event.project.name, event.project +%span.cgray + = time_ago_in_words(event.created_at) + ago. + diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index a8c2205c..8775e081 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -15,4 +15,9 @@ Feature: Dashboard And I click "Create Merge Request" link Then I see prefilled new Merge Request page - + @current + Scenario: I should see User joined Project event + Given user with name "John Doe" joined project "Shop" + When I visit dashboard page + Then I should see "John Doe joined Shop" event + diff --git a/features/step_definitions/dashboard_steps.rb b/features/step_definitions/dashboard_steps.rb index 867233c8..3771fb9c 100644 --- a/features/step_definitions/dashboard_steps.rb +++ b/features/step_definitions/dashboard_steps.rb @@ -109,3 +109,18 @@ Given /^I have authored merge requests$/ do :author => @user, :project => project2 end + +Given /^user with name "(.*?)" joined project "(.*?)"$/ do |user_name, project_name| + user = Factory.create(:user, {name: user_name}) + project = Project.find_by_name project_name + Event.create( + project: project, + author_id: user.id, + action: Event::Joined + ) +end + +Then /^I should see "(.*?)" event$/ do |event_text| + page.should have_content(event_text) +end + diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index aaffda31..81459233 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -49,4 +49,15 @@ describe Event do it { @event.branch_name.should == "master" } it { @event.author.should == @user } end + + describe "New team mamber" do + let(:project) {Factory.create :project} + let(:new_user) {Factory.create :user} + it "should create event" do + UsersProject.observers.enable :users_project_observer + expect{ + UsersProject.bulk_import(project, [new_user.id], UsersProject::DEVELOPER) + }.to change{Event.count}.by(1) + end + end end diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb index 3e392040..99130aa5 100644 --- a/spec/observers/users_project_observer_spec.rb +++ b/spec/observers/users_project_observer_spec.rb @@ -23,6 +23,14 @@ describe UsersProjectObserver do Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true)) subject.after_create(users_project) end + it "should create new event" do + Event.should_receive(:create).with( + project_id: users_project.project.id, + action: Event::Joined, + author_id: users_project.user.id + ) + subject.after_create(users_project) + end end describe "#after_update" do From 1f240b09ed5f9f5476a863dd2f906398e5a9f0d4 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 10 Sep 2012 00:27:47 +0300 Subject: [PATCH 49/50] User left project event added --- app/decorators/event_decorator.rb | 3 +-- app/models/event.rb | 15 +++++++++++++-- app/models/users_project.rb | 2 +- app/observers/users_project_observer.rb | 9 +++++++++ app/views/events/_event.html.haml | 4 ++-- ...ml => _event_membership_changed.html.haml} | 1 + features/dashboard/dashboard.feature | 9 +++++++-- features/step_definitions/dashboard_steps.rb | 10 ++++++++++ spec/models/event_spec.rb | 13 ++++++++++++- spec/observers/users_project_observer_spec.rb | 19 +++++++++++++++++++ 10 files changed, 75 insertions(+), 10 deletions(-) rename app/views/events/{_event_joined.html.haml => _event_membership_changed.html.haml} (97%) diff --git a/app/decorators/event_decorator.rb b/app/decorators/event_decorator.rb index 265dbe1a..ce0aaa03 100644 --- a/app/decorators/event_decorator.rb +++ b/app/decorators/event_decorator.rb @@ -8,9 +8,8 @@ class EventDecorator < ApplicationDecorator "#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title elsif self.push? "#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name - elsif self.joined? + elsif self.membership_changed? "#{self.author_name} #{self.action_name} #{self.project.name}" - else "" end diff --git a/app/models/event.rb b/app/models/event.rb index 15095d3b..308ffd63 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -11,6 +11,7 @@ class Event < ActiveRecord::Base Commented = 6 Merged = 7 Joined = 8 # User joined project + Left = 9 # User left project belongs_to :project belongs_to :target, polymorphic: true @@ -38,7 +39,7 @@ class Event < ActiveRecord::Base # - new issue # - merge request def allowed? - push? || issue? || merge_request? || joined? + push? || issue? || merge_request? || membership_changed? end def push? @@ -86,7 +87,15 @@ class Event < ActiveRecord::Base end def joined? - action == self.class::Joined + action == Joined + end + + def left? + action == Left + end + + def membership_changed? + joined? || left? end def issue @@ -108,6 +117,8 @@ class Event < ActiveRecord::Base "merged" elsif joined? 'joined' + elsif left? + 'left' else "opened" end diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 3b951f0d..ce64a10f 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -23,7 +23,7 @@ class UsersProject < ActiveRecord::Base def self.bulk_delete(project, user_ids) UsersProject.transaction do UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| - users_project.delete + users_project.destroy end end end diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index 2a98a194..b2cea9f2 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -12,4 +12,13 @@ class UsersProjectObserver < ActiveRecord::Observer def after_update(users_project) Notify.project_access_granted_email(users_project.id).deliver end + + def after_destroy(users_project) + Event.create( + project_id: users_project.project.id, + action: Event::Left, + author_id: users_project.user.id + ) + end + end diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 7566c094..7bae8db1 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -11,7 +11,7 @@ .event_feed = render "events/event_push", event: event - - elsif event.joined? + - elsif event.membership_changed? .event_feed - = render "events/event_joined", event: event + = render "events/event_membership_changed", event: event diff --git a/app/views/events/_event_joined.html.haml b/app/views/events/_event_membership_changed.html.haml similarity index 97% rename from app/views/events/_event_joined.html.haml rename to app/views/events/_event_membership_changed.html.haml index 6195da81..b079c138 100644 --- a/app/views/events/_event_joined.html.haml +++ b/app/views/events/_event_membership_changed.html.haml @@ -1,6 +1,7 @@ = 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) diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 8775e081..98bb4980 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -15,9 +15,14 @@ Feature: Dashboard And I click "Create Merge Request" link Then I see prefilled new Merge Request page - @current Scenario: I should see User joined Project event Given user with name "John Doe" joined project "Shop" When I visit dashboard page - Then I should see "John Doe joined Shop" event + Then I should see "John Doe joined project Shop" event + + Scenario: I should see User left Project event + Given user with name "John Doe" joined project "Shop" + And user with name "John Doe" left project "Shop" + When I visit dashboard page + Then I should see "John Doe left project Shop" event diff --git a/features/step_definitions/dashboard_steps.rb b/features/step_definitions/dashboard_steps.rb index 3771fb9c..3ddc68e9 100644 --- a/features/step_definitions/dashboard_steps.rb +++ b/features/step_definitions/dashboard_steps.rb @@ -120,6 +120,16 @@ Given /^user with name "(.*?)" joined project "(.*?)"$/ do |user_name, project_n ) end +Given /^user with name "(.*?)" left project "(.*?)"$/ do |user_name, project_name| + user = User.find_by_name user_name + project = Project.find_by_name project_name + Event.create( + project: project, + author_id: user.id, + action: Event::Left + ) +end + Then /^I should see "(.*?)" event$/ do |event_text| page.should have_content(event_text) end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 81459233..ee022e95 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -50,7 +50,7 @@ describe Event do it { @event.author.should == @user } end - describe "New team mamber" do + describe "Joined project team" do let(:project) {Factory.create :project} let(:new_user) {Factory.create :user} it "should create event" do @@ -60,4 +60,15 @@ describe Event do }.to change{Event.count}.by(1) end end + describe "Left project team" do + let(:project) {Factory.create :project} + let(:new_user) {Factory.create :user} + it "should create event" do + UsersProject.bulk_import(project, [new_user.id], UsersProject::DEVELOPER) + UsersProject.observers.enable :users_project_observer + expect{ + UsersProject.bulk_delete(project, [new_user.id]) + }.to change{Event.count}.by(1) + end + end end diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb index 99130aa5..f38d9862 100644 --- a/spec/observers/users_project_observer_spec.rb +++ b/spec/observers/users_project_observer_spec.rb @@ -45,4 +45,23 @@ describe UsersProjectObserver do subject.after_update(users_project) end end + describe "#after_destroy" do + it "should called when UsersProject destroyed" do + subject.should_receive(:after_destroy) + UsersProject.observers.enable :users_project_observer do + UsersProject.bulk_delete( + users_project.project, + [users_project.user.id] + ) + end + end + it "should create new event" do + Event.should_receive(:create).with( + project_id: users_project.project.id, + action: Event::Left, + author_id: users_project.user.id + ) + subject.after_destroy(users_project) + end + end end From b565f33472d960e37ed41a8a0c09fbbc3ea65f1e Mon Sep 17 00:00:00 2001 From: randx Date: Mon, 10 Sep 2012 09:06:11 +0300 Subject: [PATCH 50/50] Auth for API --- lib/api/helpers.rb | 16 ++++++++++++++++ lib/api/issues.rb | 2 ++ lib/api/milestones.rb | 2 ++ lib/api/projects.rb | 7 +++++++ 4 files changed, 27 insertions(+) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index ce7b7b49..c0ba8747 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -21,5 +21,21 @@ module Gitlab def authenticate! error!({'message' => '401 Unauthorized'}, 401) unless current_user end + + def authorize! action, subject + unless abilities.allowed?(current_user, action, subject) + error!({'message' => '403 Forbidden'}, 403) + end + end + + private + + def abilities + @abilities ||= begin + abilities = Six.new + abilities << Ability + abilities + end + end end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 68cb7e05..4cfa7500 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -79,6 +79,8 @@ module Gitlab # PUT /projects/:id/issues/:issue_id put ":id/issues/:issue_id" do @issue = user_project.issues.find(params[:issue_id]) + authorize! :modify_issue, @issue + parameters = { title: (params[:title] || @issue.title), description: (params[:description] || @issue.description), diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 29f5efa4..7c684667 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -61,6 +61,8 @@ module Gitlab # Example Request: # PUT /projects/:id/milestones/:milestone_id put ":id/milestones/:milestone_id" do + authorize! :admin_milestone, user_project + @milestone = user_project.milestones.find(params[:milestone_id]) parameters = { title: (params[:title] || @milestone.title), diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7da83429..05b07e8d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -74,6 +74,7 @@ module Gitlab # Example Request: # POST /projects/:id/users post ":id/users" do + authorize! :admin_project, user_project user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) nil end @@ -87,6 +88,7 @@ module Gitlab # Example Request: # PUT /projects/:id/add_users put ":id/users" do + authorize! :admin_project, user_project user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) nil end @@ -99,6 +101,7 @@ module Gitlab # Example Request: # DELETE /projects/:id/users delete ":id/users" do + authorize! :admin_project, user_project user_project.delete_users_ids_from_team(params[:user_ids].values) nil end @@ -186,6 +189,8 @@ module Gitlab # PUT /projects/:id/snippets/:snippet_id put ":id/snippets/:snippet_id" do @snippet = user_project.snippets.find(params[:snippet_id]) + authorize! :modify_snippet, @snippet + parameters = { title: (params[:title] || @snippet.title), file_name: (params[:file_name] || @snippet.file_name), @@ -209,6 +214,8 @@ module Gitlab # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do @snippet = user_project.snippets.find(params[:snippet_id]) + authorize! :modify_snippet, @snippet + @snippet.destroy end