Commit 2e34a6d3 authored by miks's avatar miks

Merge branch 'master' into project_hooks_api

parents fdb5c82c 8674fba1
source "http://rubygems.org" source "http://rubygems.org"
def darwin_only(require_as)
RUBY_PLATFORM.include?('darwin') && require_as
end
def linux_only(require_as)
RUBY_PLATFORM.include?('linux') && require_as
end
gem "rails", "3.2.8" gem "rails", "3.2.8"
# Supported DBs # Supported DBs
...@@ -44,7 +52,8 @@ gem "ffaker" ...@@ -44,7 +52,8 @@ gem "ffaker"
gem "seed-fu" gem "seed-fu"
# Markdown to HTML # Markdown to HTML
gem "redcarpet", "~> 2.1.1" gem "redcarpet", "~> 2.1.1"
gem "github-markup", "~> 0.7.4"
# Servers # Servers
gem "thin" gem "thin"
...@@ -101,13 +110,20 @@ group :development, :test do ...@@ -101,13 +110,20 @@ group :development, :test do
gem "capybara" gem "capybara"
gem "capybara-webkit" gem "capybara-webkit"
gem "headless" gem "headless"
gem "autotest"
gem "autotest-rails"
gem "pry" gem "pry"
gem "awesome_print" gem "awesome_print"
gem "database_cleaner" gem "database_cleaner"
gem "launchy" gem "launchy"
gem 'factory_girl_rails' gem 'factory_girl_rails'
# Guard
gem 'guard-rspec'
gem 'guard-cucumber'
# Notification
gem 'rb-fsevent', :require => darwin_only('rb-fsevent')
gem 'growl', :require => darwin_only('growl')
gem 'rb-inotify', :require => linux_only('rb-inotify')
end end
group :test do group :test do
......
...@@ -68,7 +68,6 @@ GIT ...@@ -68,7 +68,6 @@ GIT
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
ZenTest (4.8.1)
actionmailer (3.2.8) actionmailer (3.2.8)
actionpack (= 3.2.8) actionpack (= 3.2.8)
mail (~> 2.4.4) mail (~> 2.4.4)
...@@ -100,10 +99,6 @@ GEM ...@@ -100,10 +99,6 @@ GEM
rails (~> 3.0) rails (~> 3.0)
addressable (2.2.8) addressable (2.2.8)
arel (3.0.2) arel (3.0.2)
autotest (4.4.6)
ZenTest (>= 4.4.1)
autotest-rails (4.1.2)
ZenTest (~> 4.5)
awesome_print (1.0.2) awesome_print (1.0.2)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
blankslate (2.1.2.4) blankslate (2.1.2.4)
...@@ -178,6 +173,7 @@ GEM ...@@ -178,6 +173,7 @@ GEM
gherkin (2.11.0) gherkin (2.11.0)
json (>= 1.4.6) json (>= 1.4.6)
git (1.2.5) git (1.2.5)
github-markup (0.7.4)
gitlab_meta (2.9) gitlab_meta (2.9)
grape (0.2.1) grape (0.2.1)
hashie (~> 1.2) hashie (~> 1.2)
...@@ -185,6 +181,15 @@ GEM ...@@ -185,6 +181,15 @@ GEM
multi_xml multi_xml
rack rack
rack-mount rack-mount
growl (1.0.3)
guard (1.3.2)
listen (>= 0.4.2)
thor (>= 0.14.6)
guard-cucumber (1.2.0)
cucumber (>= 1.2.0)
guard (>= 1.1.0)
guard-rspec (1.2.1)
guard (>= 1.1)
haml (3.1.6) haml (3.1.6)
haml-rails (0.3.4) haml-rails (0.3.4)
actionpack (~> 3.0) actionpack (~> 3.0)
...@@ -218,6 +223,7 @@ GEM ...@@ -218,6 +223,7 @@ GEM
libv8 (3.3.10.4) libv8 (3.3.10.4)
libwebsocket (0.1.3) libwebsocket (0.1.3)
addressable addressable
listen (0.5.0)
mail (2.4.4) mail (2.4.4)
i18n (>= 0.4.0) i18n (>= 0.4.0)
mime-types (~> 1.16) mime-types (~> 1.16)
...@@ -273,6 +279,9 @@ GEM ...@@ -273,6 +279,9 @@ GEM
raindrops (0.9.0) raindrops (0.9.0)
rake (0.9.2.2) rake (0.9.2.2)
raphael-rails (1.5.2) raphael-rails (1.5.2)
rb-fsevent (0.9.1)
rb-inotify (0.8.8)
ffi (>= 0.5.0)
rdoc (3.12) rdoc (3.12)
json (~> 1.4) json (~> 1.4)
redcarpet (2.1.1) redcarpet (2.1.1)
...@@ -376,8 +385,6 @@ PLATFORMS ...@@ -376,8 +385,6 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
acts-as-taggable-on (= 2.3.1) acts-as-taggable-on (= 2.3.1)
annotate! annotate!
autotest
autotest-rails
awesome_print awesome_print
bootstrap-sass (= 2.0.4) bootstrap-sass (= 2.0.4)
capybara capybara
...@@ -396,11 +403,15 @@ DEPENDENCIES ...@@ -396,11 +403,15 @@ DEPENDENCIES
ffaker ffaker
foreman foreman
git git
github-markup (~> 0.7.4)
gitlab_meta (= 2.9) gitlab_meta (= 2.9)
gitolite! gitolite!
grack! grack!
grape (~> 0.2.1) grape (~> 0.2.1)
grit! grit!
growl
guard-cucumber
guard-rspec
haml-rails haml-rails
headless headless
httparty httparty
...@@ -418,6 +429,8 @@ DEPENDENCIES ...@@ -418,6 +429,8 @@ DEPENDENCIES
rack-mini-profiler rack-mini-profiler
rails (= 3.2.8) rails (= 3.2.8)
raphael-rails (= 1.5.2) raphael-rails (= 1.5.2)
rb-fsevent
rb-inotify
redcarpet (~> 2.1.1) redcarpet (~> 2.1.1)
resque (~> 1.20.0) resque (~> 1.20.0)
resque_mailer resque_mailer
......
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'rspec', :version => 2 do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
# Capybara request specs
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
# Turnip features and steps
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
guard 'cucumber' do
watch(%r{^features/.+\.feature$})
watch(%r{^features/support/.+$}) { 'features' }
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
end
...@@ -5,7 +5,7 @@ function switchToNewIssue(form){ ...@@ -5,7 +5,7 @@ function switchToNewIssue(form){
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#new_issue_dialog").show("fade", { direction: "right" }, 150); $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
$('.top-tabs .add_new').hide(); $('.top-tabs .add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn"); disableButtonIfEmptyField("#issue_title", ".save-btn");
}); });
} }
...@@ -16,7 +16,7 @@ function switchToEditIssue(form){ ...@@ -16,7 +16,7 @@ function switchToEditIssue(form){
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150); $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
$('.add_new').hide(); $('.add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn"); disableButtonIfEmptyField("#issue_title", ".save-btn");
}); });
} }
......
$(document).ready(function(){
$(".one_click_select").live("click", function(){
$(this).select();
});
$('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;
}
})
$(".account-box").mouseenter(showMenu);
$(".account-box").mouseleave(resetMenu);
$("#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;
}
});
/**
* 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();
}
});
/**
* Commit show suppressed diff
*
*/
$(".supp_diff_link").bind("click", function() {
showDiff(this);
});
/**
* Note markdown preview
*
*/
$(document).on('click', '#preview-link', function(e) {
$('#preview-note').text('Loading...');
var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
$(this).text(previewLinkText);
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);
});
$('#preview-note, #note_note').toggle();
e.preventDefault();
});
});
function focusSearch() {
$("#search").focus();
}
function updatePage(data){
$.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
}
function showMenu() {
$(this).toggleClass('hover');
}
function resetMenu() {
$(this).removeClass("hover");
}
function slugify(text) {
return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();
}
function showDiff(link) {
$(link).next('table').show();
$(link).remove();
}
(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);
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");
}
})
}
window.updatePage = (data) ->
$.ajax({type: "GET", url: location.href, data: data, dataType: "script"})
window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
window.ajaxGet = (url) ->
$.ajax({type: "GET", url: url, dataType: "script"})
# Disable button if text field is empty
window.disableButtonIfEmptyField = (field_selector, button_selector) ->
field = $(field_selector)
closest_submit = field.closest("form").find(button_selector)
closest_submit.disable() if field.val() is ""
field.on "keyup", ->
if $(this).val() is ""
closest_submit.disable()
else
closest_submit.enable()
$ ->
# Click a .one_click_select field, select the contents
$(".one_click_select").live 'click', -> $(this).select()
# Initialize chosen selects
$('select.chosen').chosen()
# 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.disable()
else
buttons.enable()
# Show/Hide the profile menu when hovering the account box
$('.account-box').hover -> $(this).toggleClass('hover')
# 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")
switch e.which
when 115
$("#search").focus()
e.preventDefault()
# Commit show suppressed diff
$(".supp_diff_link").bind "click", ->
$(this).next('table').show()
$(this).remove()
# Note markdown preview
$(document).on 'click', '#preview-link', (e) ->
$('#preview-note').text('Loading...')
previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview'
$(this).text(previewLinkText)
note = $('#note_note').val()
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()
false
(($) ->
_chosen = $.fn.chosen
$.fn.extend chosen: (options) ->
default_options = search_contains: "true"
$.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)
...@@ -25,14 +25,14 @@ var NoteList = { ...@@ -25,14 +25,14 @@ var NoteList = {
$(this).closest('li').fadeOut(); }); $(this).closest('li').fadeOut(); });
$(".note-form-holder").live("ajax:before", function(){ $(".note-form-holder").live("ajax:before", function(){
$(".submit_note").attr("disabled", "disabled"); $(".submit_note").disable()
}) })
$(".note-form-holder").live("ajax:complete", function(){ $(".note-form-holder").live("ajax:complete", function(){
$(".submit_note").removeAttr("disabled"); $(".submit_note").enable()
}) })
disableButtonIfEmtpyField(".note-text", ".submit_note"); disableButtonIfEmptyField(".note-text", ".submit_note");
$(".note-text").live("focus", function(){ $(".note-text").live("focus", function(){
$(this).css("height", "80px"); $(this).css("height", "80px");
...@@ -177,6 +177,6 @@ var PerLineNotes = { ...@@ -177,6 +177,6 @@ var PerLineNotes = {
form.show(); form.show();
return false; return false;
}); });
disableButtonIfEmtpyField(".line-note-text", ".submit_inline_note"); disableButtonIfEmptyField(".line-note-text", ".submit_inline_note");
} }
} }
...@@ -8,7 +8,7 @@ window.Projects = -> ...@@ -8,7 +8,7 @@ window.Projects = ->
$('.save-project-loader').show() $('.save-project-loader').show()
$('form #project_default_branch').chosen() $('form #project_default_branch').chosen()
disableButtonIfEmtpyField '#project_name', '.project-submit' disableButtonIfEmptyField '#project_name', '.project-submit'
# Git clone panel switcher # Git clone panel switcher
$ -> $ ->
......
...@@ -179,6 +179,15 @@ span.update-author { ...@@ -179,6 +179,15 @@ span.update-author {
&.merged { &.merged {
background-color: #2A2; background-color: #2A2;
} }
&.joined {
background-color: #1ca9dd;
}
&.left {
background-color: #888;
float:none;
}
} }
form { form {
......
require 'github/markup'
class RefsController < ApplicationController class RefsController < ApplicationController
include Gitlab::Encode include Gitlab::Encode
before_filter :project before_filter :project
......
...@@ -8,7 +8,9 @@ class EventDecorator < ApplicationDecorator ...@@ -8,7 +8,9 @@ class EventDecorator < ApplicationDecorator
"#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title "#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title
elsif self.push? elsif self.push?
"#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name "#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name
else elsif self.membership_changed?
"#{self.author_name} #{self.action_name} #{self.project.name}"
else
"" ""
end end
end end
......
...@@ -2,5 +2,9 @@ module ProjectsHelper ...@@ -2,5 +2,9 @@ module ProjectsHelper
def grouper_project_members(project) def grouper_project_members(project)
@project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access)
end end
def remove_from_team_message(project, member)
"You are going to remove #{member.user_name} from #{project.name}. Are you sure?"
end
end end
...@@ -24,4 +24,14 @@ module TreeHelper ...@@ -24,4 +24,14 @@ module TreeHelper
content.name content.name
end end
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 end
...@@ -10,6 +10,8 @@ class Event < ActiveRecord::Base ...@@ -10,6 +10,8 @@ class Event < ActiveRecord::Base
Pushed = 5 Pushed = 5
Commented = 6 Commented = 6
Merged = 7 Merged = 7
Joined = 8 # User joined project
Left = 9 # User left project
belongs_to :project belongs_to :project
belongs_to :target, polymorphic: true belongs_to :target, polymorphic: true
...@@ -37,7 +39,7 @@ class Event < ActiveRecord::Base ...@@ -37,7 +39,7 @@ class Event < ActiveRecord::Base
# - new issue # - new issue
# - merge request # - merge request
def allowed? def allowed?
push? || issue? || merge_request? push? || issue? || merge_request? || membership_changed?
end end
def push? def push?
...@@ -84,6 +86,18 @@ class Event < ActiveRecord::Base ...@@ -84,6 +86,18 @@ class Event < ActiveRecord::Base
[Closed, Reopened].include?(action) [Closed, Reopened].include?(action)
end end
def joined?
action == Joined
end
def left?
action == Left
end
def membership_changed?
joined? || left?
end
def issue def issue
target if target_type == "Issue" target if target_type == "Issue"
end end
...@@ -101,6 +115,10 @@ class Event < ActiveRecord::Base ...@@ -101,6 +115,10 @@ class Event < ActiveRecord::Base
"closed" "closed"
elsif merged? elsif merged?
"merged" "merged"
elsif joined?
'joined'
elsif left?
'left'
else else
"opened" "opened"
end end
......
...@@ -162,7 +162,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -162,7 +162,7 @@ class MergeRequest < ActiveRecord::Base
end end
def automerge!(current_user) 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) self.merge!(current_user.id)
true true
end end
......
...@@ -23,7 +23,7 @@ class UsersProject < ActiveRecord::Base ...@@ -23,7 +23,7 @@ class UsersProject < ActiveRecord::Base
def self.bulk_delete(project, user_ids) def self.bulk_delete(project, user_ids)
UsersProject.transaction do UsersProject.transaction do
UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project|
users_project.delete users_project.destroy
end end
end end
end end
......
class UsersProjectObserver < ActiveRecord::Observer class UsersProjectObserver < ActiveRecord::Observer
def after_create(users_project) def after_create(users_project)
Notify.project_access_granted_email(users_project.id).deliver 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 end
def after_update(users_project) def after_update(users_project)
Notify.project_access_granted_email(users_project.id).deliver Notify.project_access_granted_email(users_project.id).deliver
end 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 end
...@@ -90,6 +90,8 @@ module PushEvent ...@@ -90,6 +90,8 @@ module PushEvent
def push_with_commits? def push_with_commits?
md_ref? && commits.any? && parent_commit && last_commit md_ref? && commits.any? && parent_commit && last_commit
rescue Grit::NoSuchPathError
false
end end
def last_push_to_non_root? def last_push_to_non_root?
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
- unless project.new_record? - unless project.new_record?
.clearfix .clearfix
= f.label :owner_id = f.label :owner_id
.input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'}
- if project.repo_exists? - if project.repo_exists?
.clearfix .clearfix
...@@ -69,7 +69,6 @@ ...@@ -69,7 +69,6 @@
:javascript :javascript
$(function(){ $(function(){
$('#project_owner_id').chosen();
new Projects(); new Projects();
}) })
...@@ -71,25 +71,11 @@ ...@@ -71,25 +71,11 @@
%th Project Access: %th Project Access:
%tr %tr
%td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5'
%td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"}
%tr %tr
%td= submit_tag 'Add', class: "btn primary" %td= submit_tag 'Add', class: "btn primary"
%td %td
Read more about project permissions Read more about project permissions
%strong= link_to "here", help_permissions_path, class: "vlink" %strong= link_to "here", help_permissions_path, class: "vlink"
:css
form select {
width:150px;
}
#user_ids {
width:300px;
}
:javascript
$('select#user_ids').chosen();
$('select#repo_access').chosen();
$('select#project_access').chosen();
...@@ -8,20 +8,9 @@ ...@@ -8,20 +8,9 @@
.clearfix .clearfix
%label Project Access: %label Project Access:
.input .input
= f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select" = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select chosen span3"
%br %br
.actions .actions
= f.submit 'Save', class: "btn primary" = f.submit 'Save', class: "btn primary"
= link_to 'Cancel', :back, class: "btn" = link_to 'Cancel', :back, class: "btn"
:css
form select {
width:300px;
}
:javascript
$('select#team_member_user_id').chosen();
$('select#team_member_project_id').chosen();
$('select#team_member_repo_access').chosen();
$('select#team_member_project_access').chosen();
...@@ -68,8 +68,8 @@ ...@@ -68,8 +68,8 @@
%th Project Access: %th Project Access:
%tr %tr
%td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5'
%td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3"
%tr %tr
%td= submit_tag 'Add', class: "btn primary" %td= submit_tag 'Add', class: "btn primary"
...@@ -97,17 +97,3 @@ ...@@ -97,17 +97,3 @@
%td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled
%td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small"
%td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger"
:css
form select {
width:150px;
}
#project_ids {
width:300px;
}
:javascript
$('select#project_ids').chosen();
$('select#repo_access').chosen();
$('select#project_access').chosen();
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li %li
= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
= select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select chosen"
= hidden_field_tag :destination, "commits" = hidden_field_tag :destination, "commits"
%li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"}
...@@ -26,8 +26,3 @@ ...@@ -26,8 +26,3 @@
%span.rss-icon %span.rss-icon
= link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do
= image_tag "rss_ui.png", title: "feed" = image_tag "rss_ui.png", title: "feed"
:javascript
$(function(){
$('.project-refs-select').chosen();
});
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
$(function() { $(function() {
$('#new_user').toggle(); $('#new_user').toggle();
}); });
= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f|
= f.text_field :email, :class => "text top", :placeholder => "Email" = f.text_field :email, :class => "text top", :placeholder => "Email"
= f.password_field :password, :class => "text bottom", :placeholder => "Password" = f.password_field :password, :class => "text bottom", :placeholder => "Password"
- if devise_mapping.rememberable? - if devise_mapping.rememberable?
......
...@@ -11,3 +11,7 @@ ...@@ -11,3 +11,7 @@
.event_feed .event_feed
= render "events/event_push", event: event = render "events/event_push", event: event
- elsif event.membership_changed?
.event_feed
= render "events/event_membership_changed", event: event
= image_tag gravatar_icon(event.author_email), class: "avatar"
%strong #{event.author_name}
%span.event_label{class: event.action_name}= event.action_name
project
%strong= link_to event.project.name, event.project
%span.cgray
= time_ago_in_words(event.created_at)
ago.
...@@ -18,12 +18,12 @@ ...@@ -18,12 +18,12 @@
= f.label :assignee_id do = f.label :assignee_id do
%i.icon-user %i.icon-user
Assign to Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }) .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'})
.issue_milestone .issue_milestone
= f.label :milestone_id do = f.label :milestone_id do
%i.icon-time %i.icon-time
Milestone Milestone
.input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }) .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
.issue_description .issue_description
.clearfix .clearfix
......
= render "form" = render "form"
:javascript
$(function(){
$('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen();
});
= render "form" = render "form"
:javascript
$(function(){
$('select#issue_assignee_id').chosen();
$('select#issue_milestone_id').chosen();
});
...@@ -34,12 +34,4 @@ ...@@ -34,12 +34,4 @@
source: #{raw search_autocomplete_source}, source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url } 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();
}
});
}); });
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.padded .padded
= f.label :source_branch, "From", class: "control-label" = f.label :source_branch, "From", class: "control-label"
.controls .controls
= f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'})
.mr_source_commit .mr_source_commit
.span2 .span2
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
.padded .padded
= f.label :target_branch, "To", class: "control-label" = f.label :target_branch, "To", class: "control-label"
.controls .controls
= f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'})
.mr_target_commit .mr_target_commit
%h4.cdark 2. Fill info %h4.cdark 2. Fill info
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
= f.label :assignee_id do = f.label :assignee_id do
%i.icon-user %i.icon-user
Assign to Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, style: "width:250px") .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
.control-group .control-group
...@@ -56,18 +56,12 @@ ...@@ -56,18 +56,12 @@
= link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do
Cancel Cancel
:javascript :javascript
$(function(){ $(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();
var source_branch = $("#merge_request_source_branch"); var source_branch = $("#merge_request_source_branch");
var target_branch = $("#merge_request_target_branch"); var target_branch = $("#merge_request_target_branch");
$.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() });
$.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() });
...@@ -79,4 +73,3 @@ ...@@ -79,4 +73,3 @@
$.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() }); $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() });
}); });
}); });
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
:javascript :javascript
$(function() { $(function() {
disableButtonIfEmtpyField("#milestone_title", ".save-btn"); disableButtonIfEmptyField("#milestone_title", ".save-btn");
$( ".datepicker" ).datepicker({ $( ".datepicker" ).datepicker({
dateFormat: "yy-mm-dd", dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
......
= render "form" = render "form"
:javascript
$(function(){
$('select#issue_assignee_id').chosen();
});
= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
= select_tag "ref", grouped_options_refs, onchange: "this.form.submit();", class: "project-refs-select" = select_tag "ref", grouped_options_refs, onchange: "this.form.submit();", class: "project-refs-select chosen"
= hidden_field_tag :destination, destination = hidden_field_tag :destination, destination
:javascript
$(function(){
$('.project-refs-select').chosen();
})
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
.entry.clearfix .entry.clearfix
= f.label :name, "Branch" = f.label :name, "Branch"
.span3 .span3
= f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , { include_blank: "-- Select branch" }, { class: "span3" }) = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"})
&nbsp; &nbsp;
= f.submit 'Protect', class: "primary btn" = f.submit 'Protect', class: "primary btn"
...@@ -46,6 +46,3 @@ ...@@ -46,6 +46,3 @@
%td %td
- if can? current_user, :admin_project, @project - if can? current_user, :admin_project, @project
= link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small"
:javascript
$('select#protected_branch_name').chosen();
%ul.nav.nav-tabs %ul.nav.nav-tabs
%li %li
= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form", remote: true do = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form", remote: true do
= select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select chosen"
= hidden_field_tag :destination, "tree" = hidden_field_tag :destination, "tree"
= hidden_field_tag :path, params[:path] = hidden_field_tag :path, params[:path]
%li{class: "#{'active' if (controller.controller_name == "refs") }"} %li{class: "#{'active' if (controller.controller_name == "refs") }"}
......
...@@ -43,18 +43,11 @@ ...@@ -43,18 +43,11 @@
%i.icon-file %i.icon-file
= content.name = content.name
.file_content.wiki .file_content.wiki
- if content.name =~ /\.(md|markdown)$/i = raw GitHub::Markup.render(content.name, content.data)
= preserve do
= markdown(content.data)
- else
= simple_format(content.data)
:javascript :javascript
$(function(){ $(function(){
$('.project-refs-select').chosen();
history.pushState({ path: this.path }, '', "#{@history_path}"); history.pushState({ path: this.path }, '', "#{@history_path}");
}); });
// Load last commit log for each file in tree // Load last commit log for each file in tree
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
= link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" = 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" = link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small"
- if file.text? - if file.text?
- if name =~ /\.(md|markdown)$/i - if markup?(name)
.file_content.wiki .file_content.wiki
= preserve do = raw GitHub::Markup.render(name, file.data)
= markdown(file.data)
- else - else
.file_content.code .file_content.code
- unless file.empty? - unless file.empty?
......
...@@ -38,8 +38,3 @@ ...@@ -38,8 +38,3 @@
= preserve do = preserve do
%pre %pre
= Gitlab::Encode.utf8 lines.join("\n") = Gitlab::Encode.utf8 lines.join("\n")
:javascript
$(function(){
$('.project-refs-select').chosen();
});
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.input= f.text_field :file_name, placeholder: "example.rb" .input= f.text_field :file_name, placeholder: "example.rb"
.clearfix .clearfix
= f.label "Lifetime" = f.label "Lifetime"
.input= f.select :expires_at, lifetime_select_options, {}, style: "width:200px;" .input= f.select :expires_at, lifetime_select_options, {}, {class: 'chosen span2'}
.clearfix .clearfix
= f.label :content, "Code" = f.label :content, "Code"
.input= f.text_area :content, class: "span8" .input= f.text_area :content, class: "span8"
...@@ -26,11 +26,3 @@ ...@@ -26,11 +26,3 @@
= link_to "Cancel", project_snippets_path(@project), class: " btn" = link_to "Cancel", project_snippets_path(@project), class: " btn"
- unless @snippet.new_record? - unless @snippet.new_record?
.right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" .right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}"
:javascript
$(function(){
$('select#snippet_expires_at').chosen();
});
...@@ -10,21 +10,14 @@ ...@@ -10,21 +10,14 @@
%h6 1. Choose people you want in the team %h6 1. Choose people you want in the team
.clearfix .clearfix
= f.label :user_ids, "Peolpe" = f.label :user_ids, "People"
.input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), { class: "xxlarge", multiple: true }) .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true})
%h6 2. Set access level for them %h6 2. Set access level for them
.clearfix .clearfix
= f.label :project_access, "Project Access" = f.label :project_access, "Project Access"
.input= select_tag :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 chosen"
.actions .actions
= f.submit 'Save', class: "btn save-btn" = f.submit 'Save', class: "btn save-btn"
= link_to "Cancel", team_project_path(@project), class: "btn cancel-btn" = link_to "Cancel", team_project_path(@project), class: "btn cancel-btn"
:javascript
$('select#user_ids').chosen();
$('select#project_access').chosen();
- user = member.user - user = member.user
- allow_admin = can? current_user, :admin_project, @project - allow_admin = can? current_user, :admin_project, @project
%tr{id: dom_id(member), class: "team_member_row user_#{user.id}"} %tr{id: dom_id(member), class: "team_member_row user_#{user.id}"}
%td %td.span6
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
= image_tag gravatar_icon(user.email, 40), class: "avatar s32" = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
= link_to project_team_member_path(@project, member), title: user.name, class: "dark" do = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
%strong= truncate(user.name, lenght: 40) %strong= truncate(user.name, lenght: 40)
%br %br
%div.cgray= user.email %small.cgray= user.email
%td %td.span5
.right .right
- if current_user == user
%span.btn.disabled This is you!
- if @project.owner == user - if @project.owner == user
%span.btn.disabled.success Project Owner %span.btn.disabled.success Owner
- if user.blocked - elsif user.blocked
%span.btn.disabled.blocked Blocked %span.btn.disabled.blocked Blocked
- elsif allow_admin
= link_to project_team_member_path(project_id: @project, id: member.id), confirm: remove_from_team_message(@project, member), method: :delete, class: "very_small btn danger" do
%i.icon-minus.icon-white
- if allow_admin - if allow_admin
= form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f| = 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" = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2"
...@@ -33,11 +33,12 @@ app: ...@@ -33,11 +33,12 @@ app:
git_host: git_host:
admin_uri: git@localhost:gitolite-admin admin_uri: git@localhost:gitolite-admin
base_path: /home/git/repositories/ base_path: /home/git/repositories/
# hooks_path: /var/lib/gitolite/.gitolite/hooks/ # only needed when gitolite is not installed according the manual hooks_path: /home/git/.gitolite/hooks/
# host: localhost gitolite_admin_key: gitlab
git_user: git git_user: git
upload_pack: true upload_pack: true
receive_pack: true receive_pack: true
# host: localhost
# port: 22 # port: 22
# Git settings # Git settings
......
...@@ -102,6 +102,10 @@ class Settings < Settingslogic ...@@ -102,6 +102,10 @@ class Settings < Settingslogic
git_host['admin_uri'] || 'git@localhost:gitolite-admin' git_host['admin_uri'] || 'git@localhost:gitolite-admin'
end end
def gitolite_admin_key
git_host['gitolite_admin_key'] || 'gitlab'
end
def default_projects_limit def default_projects_limit
app['default_projects_limit'] || 10 app['default_projects_limit'] || 10
end end
......
...@@ -113,17 +113,20 @@ Generate key: ...@@ -113,17 +113,20 @@ Generate key:
Clone GitLab's fork of the Gitolite source code: Clone GitLab's fork of the Gitolite source code:
cd /home/git 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: 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 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 cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
sudo chmod 0444 /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; gitolite setup -pk /home/git/gitlab.pub"
sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gl-setup -q /home/git/gitlab.pub" sudo -u git -H sed -i 's/0077/0007/g' /home/git/.gitolite.rc
Permissions: Permissions:
...@@ -189,8 +192,8 @@ and ensure you have followed all of the above steps carefully. ...@@ -189,8 +192,8 @@ and ensure you have followed all of the above steps carefully.
#### Setup GitLab hooks #### Setup GitLab hooks
sudo cp ./lib/hooks/post-receive /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/share/gitolite/hooks/common/post-receive sudo chown git:git /home/git/.gitolite/hooks/common/post-receive
#### Check application status #### Check application status
......
...@@ -15,4 +15,14 @@ Feature: Dashboard ...@@ -15,4 +15,14 @@ Feature: Dashboard
And I click "Create Merge Request" link And I click "Create Merge Request" link
Then I see prefilled new Merge Request page Then I see prefilled new Merge Request page
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 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
...@@ -109,3 +109,28 @@ Given /^I have authored merge requests$/ do ...@@ -109,3 +109,28 @@ Given /^I have authored merge requests$/ do
:author => @user, :author => @user,
:project => project2 :project => project2
end 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
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
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
if @project ||= current_user.projects.find_by_id(params[:id]) || if @project ||= current_user.projects.find_by_id(params[:id]) ||
current_user.projects.find_by_code(params[:id]) current_user.projects.find_by_code(params[:id])
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
@project @project
...@@ -19,7 +19,48 @@ module Gitlab ...@@ -19,7 +19,48 @@ module Gitlab
end end
def authenticate! def authenticate!
error!({'message' => '401 Unauthorized'}, 401) unless current_user unauthorized! unless current_user
end
def authorize! action, subject
unless abilities.allowed?(current_user, action, subject)
forbidden!
end
end
# error helpers
def forbidden!
render_api_error!('403 Forbidden', 403)
end
def not_found!(resource = nil)
message = ["404"]
message << resource if resource
message << "Not Found"
render_api_error!(message.join(' '), 404)
end
def unauthorized!
render_api_error!('401 Unauthorized', 401)
end
def not_allowed!
render_api_error!('Method Not Allowed', 405)
end
def render_api_error!(message, status)
error!({'message' => message}, status)
end
private
def abilities
@abilities ||= begin
abilities = Six.new
abilities << Ability
abilities
end
end end
end end
end end
...@@ -60,7 +60,7 @@ module Gitlab ...@@ -60,7 +60,7 @@ module Gitlab
if @issue.save if @issue.save
present @issue, with: Entities::Issue present @issue, with: Entities::Issue
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -79,6 +79,8 @@ module Gitlab ...@@ -79,6 +79,8 @@ module Gitlab
# PUT /projects/:id/issues/:issue_id # PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do put ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id]) @issue = user_project.issues.find(params[:issue_id])
authorize! :modify_issue, @issue
parameters = { parameters = {
title: (params[:title] || @issue.title), title: (params[:title] || @issue.title),
description: (params[:description] || @issue.description), description: (params[:description] || @issue.description),
...@@ -91,7 +93,7 @@ module Gitlab ...@@ -91,7 +93,7 @@ module Gitlab
if @issue.update_attributes(parameters) if @issue.update_attributes(parameters)
present @issue, with: Entities::Issue present @issue, with: Entities::Issue
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -103,7 +105,7 @@ module Gitlab ...@@ -103,7 +105,7 @@ module Gitlab
# Example Request: # Example Request:
# DELETE /projects/:id/issues/:issue_id # DELETE /projects/:id/issues/:issue_id
delete ":id/issues/:issue_id" do delete ":id/issues/:issue_id" do
error!({'message' => 'method not allowed'}, 405) not_allowed!
end end
end end
end end
......
...@@ -45,7 +45,7 @@ module Gitlab ...@@ -45,7 +45,7 @@ module Gitlab
if @milestone.save if @milestone.save
present @milestone, with: Entities::Milestone present @milestone, with: Entities::Milestone
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -61,6 +61,8 @@ module Gitlab ...@@ -61,6 +61,8 @@ module Gitlab
# Example Request: # Example Request:
# PUT /projects/:id/milestones/:milestone_id # PUT /projects/:id/milestones/:milestone_id
put ":id/milestones/:milestone_id" do put ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project
@milestone = user_project.milestones.find(params[:milestone_id]) @milestone = user_project.milestones.find(params[:milestone_id])
parameters = { parameters = {
title: (params[:title] || @milestone.title), title: (params[:title] || @milestone.title),
...@@ -72,7 +74,7 @@ module Gitlab ...@@ -72,7 +74,7 @@ module Gitlab
if @milestone.update_attributes(parameters) if @milestone.update_attributes(parameters)
present @milestone, with: Entities::Milestone present @milestone, with: Entities::Milestone
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
end end
......
...@@ -50,7 +50,7 @@ module Gitlab ...@@ -50,7 +50,7 @@ module Gitlab
if @project.saved? if @project.saved?
present @project, with: Entities::Project present @project, with: Entities::Project
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -74,6 +74,7 @@ module Gitlab ...@@ -74,6 +74,7 @@ module Gitlab
# Example Request: # Example Request:
# POST /projects/:id/users # POST /projects/:id/users
post ":id/users" do post ":id/users" do
authorize! :admin_project, user_project
user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access]) user_project.add_users_ids_to_team(params[:user_ids].values, params[:project_access])
nil nil
end end
...@@ -87,6 +88,7 @@ module Gitlab ...@@ -87,6 +88,7 @@ module Gitlab
# Example Request: # Example Request:
# PUT /projects/:id/add_users # PUT /projects/:id/add_users
put ":id/users" do put ":id/users" do
authorize! :admin_project, user_project
user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access]) user_project.update_users_ids_to_role(params[:user_ids].values, params[:project_access])
nil nil
end end
...@@ -99,6 +101,7 @@ module Gitlab ...@@ -99,6 +101,7 @@ module Gitlab
# Example Request: # Example Request:
# DELETE /projects/:id/users # DELETE /projects/:id/users
delete ":id/users" do delete ":id/users" do
authorize! :admin_project, user_project
user_project.delete_users_ids_from_team(params[:user_ids].values) user_project.delete_users_ids_from_team(params[:user_ids].values)
nil nil
end end
...@@ -209,7 +212,7 @@ module Gitlab ...@@ -209,7 +212,7 @@ module Gitlab
if @snippet.save if @snippet.save
present @snippet, with: Entities::ProjectSnippet present @snippet, with: Entities::ProjectSnippet
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -226,6 +229,8 @@ module Gitlab ...@@ -226,6 +229,8 @@ module Gitlab
# PUT /projects/:id/snippets/:snippet_id # PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id]) @snippet = user_project.snippets.find(params[:snippet_id])
authorize! :modify_snippet, @snippet
parameters = { parameters = {
title: (params[:title] || @snippet.title), title: (params[:title] || @snippet.title),
file_name: (params[:file_name] || @snippet.file_name), file_name: (params[:file_name] || @snippet.file_name),
...@@ -236,7 +241,7 @@ module Gitlab ...@@ -236,7 +241,7 @@ module Gitlab
if @snippet.update_attributes(parameters) if @snippet.update_attributes(parameters)
present @snippet, with: Entities::ProjectSnippet present @snippet, with: Entities::ProjectSnippet
else else
error!({'message' => '404 Not found'}, 404) not_found!
end end
end end
...@@ -249,6 +254,8 @@ module Gitlab ...@@ -249,6 +254,8 @@ module Gitlab
# DELETE /projects/:id/snippets/:snippet_id # DELETE /projects/:id/snippets/:snippet_id
delete ":id/snippets/:snippet_id" do delete ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id]) @snippet = user_project.snippets.find(params[:snippet_id])
authorize! :modify_snippet, @snippet
@snippet.destroy @snippet.destroy
end end
...@@ -277,10 +284,10 @@ module Gitlab ...@@ -277,10 +284,10 @@ module Gitlab
ref = params[:sha] ref = params[:sha]
commit = user_project.commit ref commit = user_project.commit ref
error!('404 Commit Not Found', 404) unless commit not_found! "Commit" unless commit
tree = Tree.new commit.tree, user_project, ref, params[:filepath] tree = Tree.new commit.tree, user_project, ref, params[:filepath]
error!('404 File Not Found', 404) unless tree.try(:tree) not_found! "File" unless tree.try(:tree)
if tree.text? if tree.text?
encoding = Gitlab::Encode.detect_encoding(tree.data) encoding = Gitlab::Encode.detect_encoding(tree.data)
......
...@@ -35,7 +35,7 @@ module Gitlab ...@@ -35,7 +35,7 @@ module Gitlab
end end
def enable_automerge def enable_automerge
config.admin_all_repo!(project) config.admin_all_repo!
end end
alias_method :create_repository, :update_repository alias_method :create_repository, :update_repository
......
...@@ -148,18 +148,7 @@ module Gitlab ...@@ -148,18 +148,7 @@ module Gitlab
# Enable access to all repos for gitolite admin. # Enable access to all repos for gitolite admin.
# We use it for accept merge request feature # We use it for accept merge request feature
def admin_all_repo def admin_all_repo
owner_name = "" owner_name = Gitlab.config.gitolite_admin_key
# 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 # @ALL repos premission for gitolite owner
repo_name = "@all" repo_name = "@all"
......
...@@ -21,8 +21,7 @@ module Gitlab ...@@ -21,8 +21,7 @@ module Gitlab
if output =~ /CONFLICT/ if output =~ /CONFLICT/
false false
else else
repo.git.push({}, "origin", merge_request.target_branch) !!repo.git.push({}, "origin", merge_request.target_branch)
true
end end
end end
end end
......
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
...@@ -49,4 +49,26 @@ describe Event do ...@@ -49,4 +49,26 @@ describe Event do
it { @event.branch_name.should == "master" } it { @event.branch_name.should == "master" }
it { @event.author.should == @user } it { @event.author.should == @user }
end end
describe "Joined project team" 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
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 end
...@@ -23,6 +23,14 @@ describe UsersProjectObserver do ...@@ -23,6 +23,14 @@ describe UsersProjectObserver do
Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true)) Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true))
subject.after_create(users_project) subject.after_create(users_project)
end 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 end
describe "#after_update" do describe "#after_update" do
...@@ -37,4 +45,23 @@ describe UsersProjectObserver do ...@@ -37,4 +45,23 @@ describe UsersProjectObserver do
subject.after_update(users_project) subject.after_update(users_project)
end end
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 end
...@@ -86,7 +86,7 @@ describe Gitlab::API do ...@@ -86,7 +86,7 @@ describe Gitlab::API do
it "should return a 404 error if not found" do it "should return a 404 error if not found" do
get api("/projects/42", user) get api("/projects/42", user)
response.status.should == 404 response.status.should == 404
json_response['message'].should == '404 Not found' json_response['message'].should == '404 Not Found'
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment