Merge branch 'master' into file-store-4_git_task
Conflicts: Gemfile
This commit is contained in:
commit
345e4f698b
|
@ -16,3 +16,4 @@ public/downloads/*
|
|||
*.tmproj
|
||||
.sass-cache/
|
||||
dump.rdb
|
||||
crash.log
|
||||
|
|
7
Gemfile
7
Gemfile
|
@ -4,7 +4,7 @@ gem 'rails', '3.2.8' #, :git => 'git://github.com/rails/rails.git'
|
|||
|
||||
gem 'pg', '~> 0.14.0'
|
||||
# gem 'silent-postgres', :git => 'git://github.com/dolzenko/silent-postgres.git' #'~> 0.1.1'
|
||||
gem 'redhillonrails_core', :git => 'git://github.com/chipiga/redhillonrails_core.git', :branch => 'rails31' # '~> 2.0.0.pre' # deprecated
|
||||
gem 'redhillonrails_core', :git => 'git://github.com/warpc/redhillonrails_core.git', :branch => 'rails31' # '~> 2.0.0.pre' # deprecated
|
||||
# gem 'schema_plus', '~> 0.2.1' # buggy shit!
|
||||
|
||||
gem 'devise', '~> 2.1.2'
|
||||
|
@ -32,7 +32,7 @@ gem 'diff-display', '~> 0.0.1'
|
|||
|
||||
# Wiki
|
||||
gem "gollum", '~> 2.1.3'
|
||||
gem "redcarpet", "1.17.2"
|
||||
gem "redcarpet", "~> 2.1.1"
|
||||
gem 'creole'
|
||||
gem 'rdiscount'
|
||||
# gem 'org-ruby'
|
||||
|
@ -44,7 +44,7 @@ gem 'trinidad', '~> 1.0.2', :platforms => :jruby
|
|||
gem 'newrelic_rpm', '~> 3.4.1', :platforms => [:mri, :rbx]
|
||||
gem 'whenever', '~> 0.7.3', :require => false
|
||||
|
||||
gem 'jbuilder', '~> 0.4.0'
|
||||
gem 'jbuilder', '~> 0.8.2'
|
||||
gem 'rails3-jquery-autocomplete', '~> 1.0.7'
|
||||
gem 'will_paginate', '~> 3.0.3'
|
||||
gem 'meta-tags', '~> 1.2.5', :require => 'meta_tags'
|
||||
|
@ -53,6 +53,7 @@ gem 'jquery-rails', '~> 2.0.2'
|
|||
gem 'ruby-haml-js', '~> 0.0.3'
|
||||
gem 'rails-backbone', '~> 0.7.2'
|
||||
|
||||
gem 'rack-throttle'
|
||||
gem 'rest-client', '~> 1.6.6'
|
||||
|
||||
group :assets do
|
||||
|
|
28
Gemfile.lock
28
Gemfile.lock
|
@ -1,11 +1,3 @@
|
|||
GIT
|
||||
remote: git://github.com/chipiga/redhillonrails_core.git
|
||||
revision: 5f58167c41882890c223168b0a5521d99e8d92aa
|
||||
branch: rails31
|
||||
specs:
|
||||
redhillonrails_core (2.0.0.pre)
|
||||
activerecord (>= 3.1.0.rc)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/rdblue/grack.git
|
||||
revision: 020be3fef3fb308b9d214252522aa5945bf6584a
|
||||
|
@ -21,6 +13,14 @@ GIT
|
|||
mime-types (~> 1.15)
|
||||
posix-spawn (~> 0.3.6)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/warpc/redhillonrails_core.git
|
||||
revision: c0945a4c6ad4bae4ca2750b105efcff162408b15
|
||||
branch: rails31
|
||||
specs:
|
||||
redhillonrails_core (2.0.0.pre)
|
||||
activerecord (>= 3.1.0.rc)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
|
@ -145,9 +145,8 @@ GEM
|
|||
hike (1.2.1)
|
||||
hirb (0.7.0)
|
||||
i18n (0.6.0)
|
||||
jbuilder (0.4.3)
|
||||
jbuilder (0.8.2)
|
||||
activesupport (>= 3.0.0)
|
||||
blankslate (>= 2.1.2.4)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.0.2)
|
||||
railties (>= 3.2.0, < 5.0)
|
||||
|
@ -218,6 +217,8 @@ GEM
|
|||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rack-throttle (0.3.0)
|
||||
rack (>= 1.0.0)
|
||||
rails (3.2.8)
|
||||
actionmailer (= 3.2.8)
|
||||
actionpack (= 3.2.8)
|
||||
|
@ -246,7 +247,7 @@ GEM
|
|||
rdiscount (1.6.8)
|
||||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
redcarpet (1.17.2)
|
||||
redcarpet (2.1.1)
|
||||
redis (3.0.1)
|
||||
redis-namespace (1.2.1)
|
||||
redis (~> 3.0.0)
|
||||
|
@ -381,7 +382,7 @@ DEPENDENCIES
|
|||
haml-rails (~> 0.3.4)
|
||||
highline (~> 1.6.11)
|
||||
hirb
|
||||
jbuilder (~> 0.4.0)
|
||||
jbuilder (~> 0.8.2)
|
||||
jquery-rails (~> 2.0.2)
|
||||
mailcatcher
|
||||
meta-tags (~> 1.2.5)
|
||||
|
@ -391,12 +392,13 @@ DEPENDENCIES
|
|||
paperclip (~> 3.1.4)
|
||||
perform_later (~> 1.3.0)
|
||||
pg (~> 0.14.0)
|
||||
rack-throttle
|
||||
rails (= 3.2.8)
|
||||
rails-backbone (~> 0.7.2)
|
||||
rails3-generators
|
||||
rails3-jquery-autocomplete (~> 1.0.7)
|
||||
rdiscount
|
||||
redcarpet (= 1.17.2)
|
||||
redcarpet (~> 2.1.1)
|
||||
redhillonrails_core!
|
||||
resque (~> 1.21.0)
|
||||
resque-status (~> 0.3.3)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 621 B |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 380 B |
|
@ -34,7 +34,7 @@ $(document).ready(function() {
|
|||
var current = $(this);
|
||||
current.parent().find('input.user_role_chbx').each(function(i,el) {
|
||||
if ($(el).attr('id') != current.attr('id')) {
|
||||
$(el).removeAttr('checked');
|
||||
$(el).removeAttr('checked');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -81,4 +81,10 @@ $(document).ready(function() {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
window.CodeMirrorRun = function(code) {
|
||||
CodeMirror.runMode(code.innerHTML.replace(/&/gi, '&').replace(/</gi, '<').replace(/>/gi, '>'), code.className, code);
|
||||
}
|
||||
|
||||
$('.md_and_cm code').each(function (code) { CodeMirrorRun(this); });
|
||||
});
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
$(document).ready(function() {
|
||||
var new_comment = $('#open-comment.comment.hidden.new_line_comment');
|
||||
|
||||
$(document).on('click', '.buttons a.edit_comment', function() {
|
||||
$(this).parents('div.activity').hide()
|
||||
.next().show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', '.cancel_edit_comment.button', function() {
|
||||
$(this).parents('#open-comment.comment').hide()
|
||||
.prev().show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('submit', 'form.edit_comment', function() {
|
||||
var form = $(this);
|
||||
form.parent().find('.flash').remove();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: form.attr("action"),
|
||||
data: form.serialize(),
|
||||
success: function(data){
|
||||
var cancel_button = form.find('.cancel_edit_comment.button');
|
||||
var id = cancel_button.attr('id').match(/\d+$/)[0];
|
||||
cancel_button.click();
|
||||
$('#comment'+id+', #diff-comment'+id).parent().find('.cm-s-default.md_and_cm').html(data).find('code').each(function (code) { CodeMirrorRun(this); })
|
||||
},
|
||||
error: function(data){
|
||||
form.before(data.responseText);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.new_inline_comment.button').on('click', function() {
|
||||
$(this).parents('tr').prev('tr').find("a[href='"+$(this).attr('href')+"']").click();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.add_line-comment').on('click', function() {
|
||||
function ProcessData(data) {
|
||||
if(yield) {
|
||||
var str = "<tr class='inline-comments'><td class='line_numbers' colspan='2'></td>"+"<td>"+data+"</td></tr>";
|
||||
par.after(str);
|
||||
par = par.next();
|
||||
}
|
||||
else {
|
||||
par.find('td:last').append(data);
|
||||
}
|
||||
par.find('#md_tabs.nav.nav-tabs').each(function(i) {
|
||||
$(this).find('a:first').tab('show');
|
||||
$(this).parent().find('#new_line_edit_input').focus();
|
||||
});
|
||||
}
|
||||
var line = $(this);
|
||||
var tmp = line.parents('tr');
|
||||
var yield = false;
|
||||
var par = null;
|
||||
|
||||
if(tmp.hasClass('inline-comments')) {
|
||||
par = tmp;
|
||||
}
|
||||
else {
|
||||
par = tmp.next('tr.inline-comments');
|
||||
}
|
||||
|
||||
if(par.length == 0) {
|
||||
par = tmp;
|
||||
yield = true;
|
||||
}
|
||||
|
||||
// Hide visible new comment form
|
||||
$('#open-comment.new_line_comment').parents('.inline-comments').each(function(i) {
|
||||
if($(this).find('.line-comments').length > 0) {
|
||||
$(this).find('#open-comment.new_line_comment').remove();
|
||||
$(this).find('.new_inline_comment.button').show();
|
||||
}
|
||||
else {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
par.find('.new_inline_comment.button').hide();
|
||||
|
||||
$.get(line.attr('href'), null, ProcessData);
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', '.cancel_inline_comment.button', function() {
|
||||
var tr = $(this).parents('.inline-comments');
|
||||
if(tr.find('.line-comments').length > 0) {
|
||||
tr.find('#open-comment.new_line_comment').remove();
|
||||
tr.find('.new_inline_comment.button').show();
|
||||
}
|
||||
else {
|
||||
tr.remove();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
$(".div-filter-labels").live('click', function() {
|
||||
var flag = this.id;
|
||||
flag = flag.replace("label-","flag-");
|
||||
var bg = $("#"+flag).css("background-color");
|
||||
var checkbox = $(this).find(':checkbox');
|
||||
if ($(this).css("background-color") != bg) {
|
||||
$(this).css("background-color",bg).css("color","#FFFFFF");
|
||||
checkbox.attr('checked', 'checked');
|
||||
} else {
|
||||
$(this).css("background-color","rgb(247, 247, 247)").css("color","#565657");
|
||||
checkbox.removeAttr('checked');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
$(document).ready(function() {
|
||||
var preview_url = $('#preview_url').val();
|
||||
$('#md_tabs.nav.nav-tabs').each(function(i) { $(this).find('a:first').tab('show') });
|
||||
|
||||
$(document).on('shown','#md_tabs a[data-toggle="tab"]', function (e) {
|
||||
if(e.relatedTarget) { var hash = e.relatedTarget.hash; }
|
||||
else { var hash = e.currentTarget.hash; }
|
||||
var el = $(hash+'_input');
|
||||
var el_dup = $(hash+'_input_dup');
|
||||
var preview = $(e.target.hash+' > .formatted.cm-s-default');
|
||||
if(el.val() != el_dup.val() || preview.val() === '') {
|
||||
el_dup.val(el.val());
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: preview_url,
|
||||
data: el_dup.serialize(),
|
||||
success: function(data){
|
||||
preview.html(data).find('code').each(function (code) { CodeMirrorRun(this); })
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
$(document).ready(function() {
|
||||
var upd_action = $('#update_action').val();
|
||||
var form = $('#new_pull_request');
|
||||
|
||||
$('#pull_request_to_project').on('autocompleteselect', function(event, data){
|
||||
var ref = $('#to_ref');
|
||||
ref.parent().load(data.item.get_refs_url+' #to_ref', {"selected": ref.val()});
|
||||
});
|
||||
|
||||
$('#pull_request_to_project, input#to_refs, input#from_refs').on('autocompleteselect', function(event, data){
|
||||
form.attr('action', upd_action)
|
||||
.attr('method', 'get');
|
||||
$('#update_pull').fadeIn('fast');
|
||||
$('#create_pull').fadeOut('fast');
|
||||
});
|
||||
|
||||
$('#pull_tabs a').on('click', function (e) {
|
||||
var href = $(this).attr("href");
|
||||
|
||||
if ( window.history && history.pushState ) {
|
||||
history.pushState("", "", href);
|
||||
history.replaceState("", "", href);
|
||||
} else {
|
||||
location.hash = href;
|
||||
}
|
||||
});
|
||||
|
||||
var diff_tab = $('#pull_tabs a[href="#diff"]');
|
||||
$('.link_to_full_changes').on('click', function(){
|
||||
diff_tab.tab('show');
|
||||
});
|
||||
});
|
|
@ -30,19 +30,6 @@ $(document).ready(function() {
|
|||
});
|
||||
|
||||
$("div.div-tracker-labels").live('click', function() {
|
||||
var flag = this.id;
|
||||
flag = flag.replace("label-","flag-");
|
||||
var bg = $("#"+flag).css("background-color");
|
||||
var checkbox = $(this).find(':checkbox');
|
||||
if ($(this).css("background-color") != bg) {
|
||||
$(this).css("background-color",bg);
|
||||
$(this).css("color","#FFFFFF");
|
||||
checkbox.attr('checked', 'checked');
|
||||
} else {
|
||||
$(this).css("background-color","rgb(247, 247, 247)");
|
||||
$(this).css("color","#565657");
|
||||
checkbox.removeAttr('checked');
|
||||
}
|
||||
return send_index_tracker_request('GET');
|
||||
});
|
||||
|
||||
|
@ -50,7 +37,7 @@ $(document).ready(function() {
|
|||
return send_index_tracker_request('GET');
|
||||
});
|
||||
|
||||
$('#search_issue').live('submit', function() {
|
||||
$('.ajax_search_form').live('submit', function() {
|
||||
return send_index_tracker_request('GET', $(this).attr("action"), $(this).serialize());
|
||||
});
|
||||
|
||||
|
@ -224,6 +211,7 @@ $(document).ready(function() {
|
|||
|
||||
$('.edit_form.issue').live('submit', function() {
|
||||
var form = $(this);
|
||||
form.parent().find('.flash').remove();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: form.attr("action"),
|
||||
|
@ -232,10 +220,10 @@ $(document).ready(function() {
|
|||
form.fadeOut('slow');
|
||||
$('#edit_issue_content').fadeIn('slow');
|
||||
$('h3.issue_title').html(form.find('#issue_title').attr('value'));
|
||||
$('.fulltext.view.issue_body').html(data);
|
||||
$('.fulltext.view.issue_body').html(data).find('code').each(function (code) { CodeMirrorRun(this); })
|
||||
},
|
||||
error: function(data){
|
||||
alert('error'); // TODO remove
|
||||
form.before(data.responseText);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
|
|
|
@ -38,7 +38,7 @@ div.description-top div.name input {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
article div.activity {
|
||||
article div.activity, .commits_activity {
|
||||
border: 1px solid #D6D6D6;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
color: #333333;
|
||||
|
@ -46,6 +46,18 @@ article div.activity {
|
|||
padding: 6px;
|
||||
}
|
||||
|
||||
.commits_activity table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
img { margin: 2px 0 0 2px; }
|
||||
.date { width: 140px; }
|
||||
.name { width: 250px; }
|
||||
tr:nth-child(2n) {
|
||||
.md_and_cm, .data-expander { background-color: #E2E4FF; }
|
||||
background-color: #E2E4FF;
|
||||
}
|
||||
}
|
||||
|
||||
article div.messages div.activity {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
|
@ -64,12 +76,13 @@ article div.activity .top .buttons {
|
|||
display: block;
|
||||
position: relative;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
article div.activity .top div.text {
|
||||
float: left;
|
||||
font-size: 12px;
|
||||
padding-left: 10px;
|
||||
max-width: 579px;
|
||||
}
|
||||
|
||||
article div.activity .top .imaged {
|
||||
|
@ -101,20 +114,21 @@ article div.activity .fulltext.hidden {
|
|||
display: none;
|
||||
}
|
||||
|
||||
div.activity .data-expander {
|
||||
margin-left: 10px;
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
div.activity .data-expander.collapsed {
|
||||
background: #FFF image-url('expand-gray.png') no-repeat;
|
||||
background-position: 0 2px;
|
||||
}
|
||||
|
||||
div.activity .data-expander.expanded {
|
||||
background: #FFF image-url('expand-gray2.png') no-repeat;
|
||||
background-position: 0 2px;
|
||||
div.activity, .commits_activity {
|
||||
.data-expander {
|
||||
margin-left: 10px;
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.data-expander.collapsed {
|
||||
background: #FFF image-url('expand-gray.png') no-repeat;
|
||||
background-position: 0 2px;
|
||||
}
|
||||
.data-expander.expanded {
|
||||
background: #FFF image-url('expand-gray2.png') no-repeat;
|
||||
background-position: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
div.activity .fulltext p {
|
||||
|
@ -698,48 +712,19 @@ div.toolbar a.button {
|
|||
float: left;
|
||||
}
|
||||
|
||||
div.toolbar div.legend {
|
||||
float: left;
|
||||
margin-left: 50px;
|
||||
padding: 4px 0 6px;
|
||||
div.toolbar, table.dataTable {
|
||||
> .group_owner, > .user_owner, > .group, > .user { margin-right: 15px; }
|
||||
.group_owner, .user_owner, .group, .user { padding-left: 20px; }
|
||||
.user_owner { background: image-url('user16g.png') no-repeat 0 0 transparent; }
|
||||
.group_owner { background: image-url('group16g.png') no-repeat 0 0 transparent; }
|
||||
.user { background: image-url('user16.png') no-repeat 0 0 transparent; }
|
||||
.group { background: image-url('group16.png') no-repeat 0 0 transparent; }
|
||||
}
|
||||
|
||||
table.dataTable tr td.rights span.group,
|
||||
div.toolbar div.legend.rights span.group {
|
||||
background: image-url('group16.png') no-repeat 0 0 transparent;
|
||||
}
|
||||
|
||||
table.dataTable tr td.rights span.user,
|
||||
div.toolbar div.legend.rights span.user {
|
||||
background: image-url('user16.png') no-repeat 0 0 transparent;
|
||||
}
|
||||
|
||||
table.dataTable tr td.rights span.group_owner,
|
||||
div.toolbar div.legend.rights span.group_owner {
|
||||
background: image-url('group16g.png') no-repeat 0 0 transparent;
|
||||
}
|
||||
|
||||
table.dataTable tr td.rights span.user_owner,
|
||||
div.toolbar div.legend.rights span.user_owner {
|
||||
background: image-url('user16g.png') no-repeat 0 0 transparent;
|
||||
}
|
||||
|
||||
table.dataTable tr td.rights span.group_owner,
|
||||
div.toolbar div.legend.rights span.group_owner,
|
||||
table.dataTable tr td.rights span.user_owner,
|
||||
div.toolbar div.legend.rights span.user_owner,
|
||||
table.dataTable tr td.rights span.group,
|
||||
div.toolbar div.legend.rights span.group,
|
||||
table.dataTable tr td.rights span.user,
|
||||
div.toolbar div.legend.rights span.user {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
div.toolbar div.legend.rights span.group_owner,
|
||||
div.toolbar div.legend.rights span.user_owner,
|
||||
div.toolbar div.legend.rights span.group,
|
||||
div.toolbar div.legend.rights span.user {
|
||||
margin: 0 10px;
|
||||
.div-filter-labels {
|
||||
.group { background: image-url('group16b.png') no-repeat 0 0 transparent; }
|
||||
.user { background: image-url('user16b.png') no-repeat 0 0 transparent; }
|
||||
.user, .group { padding-left: 20px; }
|
||||
}
|
||||
|
||||
.root {
|
||||
|
@ -760,7 +745,7 @@ div.tos ol li {
|
|||
}
|
||||
|
||||
div.tos_sidebar ul {
|
||||
list-style: none outside none;
|
||||
list-style: none outside none;
|
||||
margin: 20px 0 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
|
@ -948,6 +933,14 @@ div#git_help_data p {
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
.tab-content.pull_diff_fix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.diff {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Mass build forms */
|
||||
form.mass_build input[type="checkbox"] {
|
||||
width: 10px;
|
||||
|
@ -1325,6 +1318,15 @@ hr.bootstrap {
|
|||
max-height: 280px;
|
||||
}
|
||||
|
||||
.label-bootstrap.label-info.font14 {
|
||||
padding: 4px;
|
||||
line-height: 1.8;
|
||||
a { color: #FFFFFF; }
|
||||
}
|
||||
.line_numbers a {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* Flash Notifies */
|
||||
|
||||
.flash_notify {
|
||||
|
@ -1491,3 +1493,219 @@ table.tablesorter.platform-maintainers.static-search thead tr.search th input[ty
|
|||
.build_for_pl { font-weight: bold; }
|
||||
.offset25 { padding-left: 10px }
|
||||
}
|
||||
|
||||
.md_and_cm {
|
||||
overflow: auto;
|
||||
margin: 10px 0 10px;
|
||||
padding: 5px;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
background: #FFF;
|
||||
|
||||
pre {
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #D6D6D6;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
color: #333333;
|
||||
padding: 6px 10px;
|
||||
overflow: auto;
|
||||
|
||||
code {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #D6D6D6;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
margin: 0 2px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid #EDEDED;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 10px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.md_and_cm > :first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
#md_tabs {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#md_tabs.nav-tabs > li > a {
|
||||
line-height: 5px;
|
||||
}
|
||||
|
||||
#open-comment {
|
||||
textarea {
|
||||
background: none repeat scroll 0 0 #FFFFFF;
|
||||
border: 1px solid #DEDEDE;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
color: #575756;
|
||||
font-size: 12px;
|
||||
height: 110px;
|
||||
padding: 5px;
|
||||
width: 98%;
|
||||
max-width: 98%;
|
||||
margin: 10px 0 10px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
textarea#issue_title, textarea#pull_request_issue_attributes_title {
|
||||
height: 16px;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.tab-pane textarea {
|
||||
min-height: 112px;
|
||||
}
|
||||
|
||||
.edit_comment .comment-left {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#open-comment > h3.tmargin0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#md_help {
|
||||
width: 800px;
|
||||
top: 30%;
|
||||
left: 42%;
|
||||
|
||||
.modal-body {
|
||||
max-height: 560px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.col {
|
||||
width: 245px;
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin-right: 10px;
|
||||
|
||||
h3 {
|
||||
margin: 6px 0 0 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: none repeat scroll 0 0 #EDEDED;
|
||||
box-shadow: 0 3px 3px -1px rgba(18, 86, 135, 0.2);
|
||||
border: 1px solid #EDEDED;
|
||||
padding: 5px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#repo-wrapper .add_line-comment {
|
||||
position: absolute;
|
||||
width: 25px;
|
||||
height: 18px;
|
||||
margin-left: -103px;
|
||||
margin-top: 0;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
filter: alpha(Opacity=0);
|
||||
-moz-opacity:0;
|
||||
}
|
||||
|
||||
#repo-wrapper tr:hover .add_line-comment {
|
||||
opacity: 1;
|
||||
filter: alpha(Opacity=100);
|
||||
-moz-opacity:1;
|
||||
}
|
||||
|
||||
div.file .inline-comments {
|
||||
.top {
|
||||
height:auto;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.activity {
|
||||
border-radius: 0;
|
||||
max-width: 752px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
tr.inline-comments td {
|
||||
border: solid #DDD;
|
||||
border-width: 1px 0;
|
||||
}
|
||||
|
||||
.inline-comments #open-comment {
|
||||
max-width: 754px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#repo-wrapper .edit_form.issue div.comment div.wrapper {
|
||||
background: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
form#new_pull_request {
|
||||
.leftlist {
|
||||
width: 50px;
|
||||
margin: 5px 0 20px 0;
|
||||
}
|
||||
.leftlist.big-list {
|
||||
margin-top: 0;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.l {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
|
||||
input {
|
||||
height: 21px;
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 380px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#repo-wrapper form#new_pull_request .wrapper {
|
||||
background: none;
|
||||
border: none;
|
||||
height: 36px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.new_inline_comment.button {
|
||||
margin: 10px 0 10px 10px;
|
||||
}
|
||||
|
||||
.niceRadio input {
|
||||
display:none;
|
||||
}
|
||||
|
||||
table#myTable thead tr.search th form.button_to div input {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
|
|
|
@ -362,27 +362,30 @@ article div.all.verybigpadding {
|
|||
width: 545px;
|
||||
padding: 0px 40px 20px 200px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
article div.all.verybigpadding div.left {
|
||||
float: left;
|
||||
.info, .avatar {
|
||||
display: inline-block;
|
||||
}
|
||||
.avatar { margin: 0 20px 20px 0; }
|
||||
.info {
|
||||
width: 380px;
|
||||
}
|
||||
.content {
|
||||
width: 550px;
|
||||
display: inline-block;
|
||||
.pagination { position: absolute; }
|
||||
}
|
||||
img {
|
||||
padding-right: 40px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
h3, h4, p { width: 420px; }
|
||||
tmargin5 {
|
||||
padding-top: 5px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
article div.all.verybigpadding div.left img{
|
||||
padding-right: 40px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
article div.all.verybigpadding div.left h3, article div.all.verybigpadding div.left h4, article div.all.verybigpadding div.left p{
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
article div.all.verybigpadding div.left .tmargin5 {
|
||||
padding-top: 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
/* Left part of page markup */
|
||||
|
||||
aside div.bordered {
|
||||
|
@ -1931,7 +1934,7 @@ a.button.width100 {
|
|||
width: 100px;
|
||||
}
|
||||
|
||||
.div-tracker-labels {
|
||||
.div-filter-labels {
|
||||
margin: 2px 13px 2px 0px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Admin::UsersController < Admin::BaseController
|
||||
include AvatarHelper
|
||||
prepend_before_filter :find_user
|
||||
|
||||
def index
|
||||
|
@ -28,10 +29,7 @@ class Admin::UsersController < Admin::BaseController
|
|||
def update
|
||||
@user.role = params[:role]
|
||||
if @user.update_without_password(params[:user])
|
||||
if @user.avatar && params[:delete_avatar] == '1'
|
||||
@user.avatar = nil
|
||||
@user.save
|
||||
end
|
||||
update_avatar(@user, params)
|
||||
flash[:notice] = t('flash.user.saved')
|
||||
redirect_to admin_users_path
|
||||
else
|
||||
|
|
|
@ -5,8 +5,6 @@ class AdvisoriesController < ApplicationController
|
|||
load_resource :find_by => :advisory_id
|
||||
authorize_resource
|
||||
|
||||
before_filter :fetch_packages_info, :only => [:show]
|
||||
|
||||
def index
|
||||
@advisories = @advisories.scoped(:include => :platforms)
|
||||
@advisories = @advisories.search_by_id(params[:q]) if params[:q]
|
||||
|
@ -18,6 +16,7 @@ class AdvisoriesController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
@packages_info = @advisory.fetch_packages_info
|
||||
end
|
||||
|
||||
def search
|
||||
|
@ -27,24 +26,4 @@ class AdvisoriesController < ApplicationController
|
|||
format.json { render @advisory }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# this method fetches and structurize packages attached to current advisory.
|
||||
def fetch_packages_info
|
||||
@packages_info = Hash.new { |h, k| h[k] = {} } # maaagic, it's maaagic ;)
|
||||
@advisory.build_lists.find_in_batches(:include => [:save_to_platform, :packages, :project]) do |batch|
|
||||
batch.each do |build_list|
|
||||
tmp = build_list.packages.inject({:srpm => nil, :rpm => []}) do |h, p|
|
||||
p.package_type == 'binary' ? h[:rpm] << p.fullname : h[:srpm] = p.fullname
|
||||
h
|
||||
end
|
||||
h = { build_list.project => tmp }
|
||||
@packages_info[build_list.save_to_platform].merge!(h) do |pr, old, new|
|
||||
{:srpm => new[:srpm], :rpm => old[:rpm].concat(new[:rpm]).uniq}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::AdvisoriesController < Api::V1::BaseController
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:index, :show] if APP_CONFIG['anonymous_access']
|
||||
load_resource :advisory, :find_by => :advisory_id
|
||||
before_filter :find_and_authorize_build_list, :only => [:create, :update]
|
||||
authorize_resource :build_list, :only => [:create, :update]
|
||||
|
||||
def index
|
||||
@advisories = @advisories.scoped(:include => :platforms).
|
||||
paginate(paginate_params)
|
||||
end
|
||||
|
||||
def show
|
||||
@packages_info = @advisory.fetch_packages_info
|
||||
end
|
||||
|
||||
def create
|
||||
if @build_list.can_attach_to_advisory? &&
|
||||
@build_list.associate_and_create_advisory(params[:advisory]) &&
|
||||
@build_list.save
|
||||
render_json_response @advisory, 'Advisory has been created successfully'
|
||||
else
|
||||
render_validation_error @advisory, error_message(@build_list, 'Advisory has not been created')
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @advisory && @build_list.can_attach_to_advisory? &&
|
||||
@advisory.attach_build_list(@build_list) && @build_list.save
|
||||
render_json_response @advisory, "Build list '#{@build_list.id}' has been attached to advisory successfully"
|
||||
else
|
||||
render_validation_error @advisory, error_message(@build_list, 'Build list has not been attached to advisory')
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_and_authorize_build_list
|
||||
@build_list = BuildList.find params[:build_list_id]
|
||||
authorize! :update, @build_list.save_to_platform
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::ArchesController < Api::V1::BaseController
|
||||
before_filter :authenticate_user! unless APP_CONFIG['anonymous_access']
|
||||
|
||||
def index
|
||||
@arches = Arch.order(:id).paginate(paginate_params)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,114 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::BaseController < ApplicationController
|
||||
#respond_to :json
|
||||
|
||||
helper_method :member_path
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
respond_to do |format|
|
||||
format.json { render :json => {:message => t("flash.exception_message")}.to_json, :status => 403 }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_locale
|
||||
I18n.locale = :en
|
||||
end
|
||||
|
||||
def error_message(subject, message)
|
||||
[message, subject.errors.full_messages].flatten.join('. ')
|
||||
end
|
||||
|
||||
def create_subject(subject)
|
||||
class_name = subject.class.name
|
||||
if subject.save
|
||||
render_json_response subject, "#{class_name} has been created successfully"
|
||||
else
|
||||
render_validation_error subject, "#{class_name} has not been created"
|
||||
end
|
||||
end
|
||||
|
||||
def update_member_in_subject(subject, relation = :relations)
|
||||
role = params[:role]
|
||||
class_name = subject.class.name.downcase
|
||||
if member.present? && role.present? && subject.respond_to?(:owner) && subject.owner != member &&
|
||||
subject.send(relation).by_actor(member).update_all(:role => role)
|
||||
render_json_response subject, "Role for #{member.class.name.downcase} '#{member.id} has been updated in #{class_name} successfully"
|
||||
else
|
||||
render_validation_error subject, "Role for member has not been updated in #{class_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def add_member_to_subject(subject, role = 'admin')
|
||||
class_name = subject.class.name.downcase
|
||||
if member.present? && subject.add_member(member, role)
|
||||
render_json_response subject, "#{member.class.to_s} '#{member.id}' has been added to #{class_name} successfully"
|
||||
else
|
||||
render_validation_error subject, "Member has not been added to #{class_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def remove_member_from_subject(subject)
|
||||
class_name = subject.class.name.downcase
|
||||
if member.present? && subject.remove_member(member)
|
||||
render_json_response subject, "#{member.class.to_s} '#{member.id}' has been removed from #{class_name} successfully"
|
||||
else
|
||||
render_validation_error subject, "Member has not been removed from #{class_name}"
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_subject(subject)
|
||||
subject.destroy # later with resque
|
||||
render_json_response subject, "#{subject.class.name} has been destroyed successfully"
|
||||
end
|
||||
|
||||
def update_subject(subject)
|
||||
class_name = subject.class.name
|
||||
if subject.update_attributes(params[class_name.downcase.to_sym] || {})
|
||||
render_json_response subject, "#{class_name} has been updated successfully"
|
||||
else
|
||||
render_validation_error subject, "#{class_name} has not been updated"
|
||||
end
|
||||
end
|
||||
|
||||
def paginate_params
|
||||
per_page = params[:per_page].to_i
|
||||
per_page = 20 if per_page < 1
|
||||
per_page = 100 if per_page >100
|
||||
{:page => params[:page], :per_page => per_page}
|
||||
end
|
||||
|
||||
def render_json_response(subject, message, status = 200)
|
||||
id = status != 200 ? nil : subject.id
|
||||
|
||||
render :json => {
|
||||
subject.class.name.underscore.to_sym => {
|
||||
:id => id,
|
||||
:message => message
|
||||
}
|
||||
}.to_json, :status => status
|
||||
end
|
||||
|
||||
def render_validation_error(subject, message)
|
||||
render_json_response(subject, error_message(subject, message), 422)
|
||||
end
|
||||
|
||||
def member_path(subject)
|
||||
if subject.is_a?(User)
|
||||
api_v1_user_path(subject.id, :format => :json)
|
||||
else
|
||||
api_v1_group_path(subject.id, :format => :json)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def member
|
||||
if @member.blank? && %w(User Group).include?(params[:type])
|
||||
@member = params[:type].constantize.where(:id => params[:member_id]).first
|
||||
end
|
||||
@member
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::BuildListsController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :index] if APP_CONFIG['anonymous_access']
|
||||
|
||||
load_and_authorize_resource :project, :only => :index
|
||||
load_and_authorize_resource :build_list, :only => [:show, :create, :cancel, :publish, :reject_publish]
|
||||
|
||||
def index
|
||||
filter = BuildList::Filter.new(nil, current_user, params[:filter] || {})
|
||||
@build_lists = filter.find.scoped(:include => [:save_to_platform, :project, :user, :arch])
|
||||
@build_lists = @build_lists.recent.paginate(paginate_params)
|
||||
end
|
||||
|
||||
def create
|
||||
bl_params = params[:build_list] || {}
|
||||
project = Project.where(:id => bl_params[:project_id]).first
|
||||
save_to_repository = Repository.where(:id => bl_params[:save_to_repository_id]).first
|
||||
|
||||
if project && save_to_repository
|
||||
bl_params[:save_to_platform_id] = save_to_repository.platform_id
|
||||
bl_params[:auto_publish] = false unless save_to_repository.publish_without_qa?
|
||||
|
||||
@build_list = project.build_lists.build(bl_params)
|
||||
|
||||
@build_list.user = current_user
|
||||
@build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority
|
||||
|
||||
if @build_list.save
|
||||
render :action => 'show'
|
||||
else
|
||||
render :json => {:message => "Validation Failed", :errors => @build_list.errors.messages}.to_json, :status => 422
|
||||
end
|
||||
else
|
||||
render :json => {:message => "Bad Request"}.to_json, :status => 400
|
||||
end
|
||||
end
|
||||
|
||||
def cancel
|
||||
render_json :cancel
|
||||
end
|
||||
|
||||
def publish
|
||||
render_json :publish
|
||||
end
|
||||
|
||||
def reject_publish
|
||||
render_json :reject_publish
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_json(action_name)
|
||||
if @build_list.send(action_name)
|
||||
render :json => {:"is_#{action_name}ed" => true, :url => api_v1_build_list_path(@build_list, :format => :json), :message => t("layout.build_lists.#{action_name}_success")}
|
||||
else
|
||||
render :json => {:"is_#{action_name}ed" => false, :url => api_v1_build_list_path(@build_list, :format => :json), :message => t("layout.build_lists.#{action_name}_fail")}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::GroupsController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
# accessible_by(current_ability)
|
||||
@groups = current_user.groups.paginate(paginate_params)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def members
|
||||
@members = @group.members.
|
||||
where('actor_id != ?', @group.owner_id).
|
||||
order('name').paginate(paginate_params)
|
||||
end
|
||||
|
||||
def update
|
||||
update_subject @group
|
||||
end
|
||||
|
||||
def destroy
|
||||
destroy_subject @group
|
||||
end
|
||||
|
||||
def create
|
||||
@group = current_user.own_groups.new params[:group]
|
||||
create_subject @group
|
||||
end
|
||||
|
||||
def add_member
|
||||
params[:type] = 'User'
|
||||
add_member_to_subject @group, (params[:role] || 'admin')
|
||||
end
|
||||
|
||||
def remove_member
|
||||
params[:type] = 'User'
|
||||
remove_member_from_subject @group
|
||||
end
|
||||
|
||||
def update_member
|
||||
params[:type] = 'User'
|
||||
update_member_in_subject @group, :actors
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::PlatformsController < Api::V1::BaseController
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :platforms_for_build, :members] if APP_CONFIG['anonymous_access']
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@platforms = @platforms.accessible_by(current_ability, :related).
|
||||
by_type(params[:type]).paginate(paginate_params)
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def platforms_for_build
|
||||
@platforms = Platform.main.opened.paginate(paginate_params)
|
||||
render :index
|
||||
end
|
||||
|
||||
def create
|
||||
platform_params = params[:platform] || {}
|
||||
owner = User.where(:id => platform_params[:owner_id]).first
|
||||
@platform.owner = owner || get_owner
|
||||
create_subject @platform
|
||||
end
|
||||
|
||||
def update
|
||||
platform_params = params[:platform] || {}
|
||||
owner = User.where(:id => platform_params[:owner_id]).first
|
||||
platform_params[:owner] = owner if owner
|
||||
update_subject @platform
|
||||
end
|
||||
|
||||
def members
|
||||
@members = @platform.members.order('name').paginate(paginate_params)
|
||||
end
|
||||
|
||||
def add_member
|
||||
add_member_to_subject @platform
|
||||
end
|
||||
|
||||
def remove_member
|
||||
remove_member_from_subject @platform
|
||||
end
|
||||
|
||||
def clone
|
||||
platform_params = params[:platform] || {}
|
||||
platform_params[:owner] = current_user
|
||||
@cloned = @platform.full_clone(platform_params)
|
||||
if @cloned.persisted?
|
||||
render_json_response @platform, 'Platform has been cloned successfully'
|
||||
else
|
||||
render_validation_error @platform, 'Platform has not been cloned'
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@platform.clear
|
||||
render_json_response @platform, 'Platform has been cleared successfully'
|
||||
end
|
||||
|
||||
def destroy
|
||||
destroy_subject @platform
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::ProjectsController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:get_id, :show, :refs] if APP_CONFIG['anonymous_access']
|
||||
|
||||
load_and_authorize_resource :project
|
||||
|
||||
def index
|
||||
@projects = Project.accessible_by(current_ability, :membered).
|
||||
paginate(paginate_params)
|
||||
end
|
||||
|
||||
def get_id
|
||||
if @project = Project.find_by_owner_and_name(params[:owner], params[:name])
|
||||
authorize! :show, @project
|
||||
else
|
||||
raise ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def refs_list
|
||||
end
|
||||
|
||||
def update
|
||||
update_subject @project
|
||||
end
|
||||
|
||||
def destroy
|
||||
destroy_subject @project
|
||||
end
|
||||
|
||||
def create
|
||||
p_params = params[:project] || {}
|
||||
owner_type = p_params[:owner_type]
|
||||
if owner_type.present? && %w(User Group).include?(owner_type)
|
||||
@project.owner = owner_type.constantize.
|
||||
where(:id => p_params[:owner_id]).first
|
||||
else
|
||||
@project.owner = nil
|
||||
end
|
||||
authorize! :update, @project.owner if @project.owner != current_user
|
||||
create_subject @project
|
||||
end
|
||||
|
||||
def members
|
||||
@members = @project.collaborators.order('uname').paginate(paginate_params)
|
||||
end
|
||||
|
||||
def add_member
|
||||
add_member_to_subject @project, params[:role]
|
||||
end
|
||||
|
||||
def remove_member
|
||||
remove_member_from_subject @project
|
||||
end
|
||||
|
||||
def update_member
|
||||
update_member_in_subject @project
|
||||
end
|
||||
|
||||
def fork
|
||||
owner = (Group.find params[:group_id] if params[:group].present?) || current_user
|
||||
authorize! :update, owner if owner.class == Group
|
||||
if forked = @project.fork(owner) and forked.valid?
|
||||
render_json_response forked, 'Project has been forked successfully'
|
||||
else
|
||||
render_validation_error forked, 'Project has not been forked'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::RepositoriesController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :projects] if APP_CONFIG['anonymous_access']
|
||||
|
||||
load_and_authorize_resource :repository, :through => :platform, :shallow => true
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def projects
|
||||
@projects = @repository.projects.
|
||||
recent.paginate(paginate_params)
|
||||
end
|
||||
|
||||
def update
|
||||
update_subject @repository
|
||||
end
|
||||
|
||||
def add_member
|
||||
add_member_to_subject @repository
|
||||
end
|
||||
|
||||
def remove_member
|
||||
remove_member_from_subject @repository
|
||||
end
|
||||
|
||||
def destroy
|
||||
destroy_subject @repository
|
||||
end
|
||||
|
||||
def add_project
|
||||
project = Project.where(:id => params[:project_id]).first
|
||||
if project
|
||||
begin
|
||||
@repository.projects << project
|
||||
render_json_response @repository, "Project '#{project.id}' has been added to repository successfully"
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
render_validation_error @repository, t('flash.repository.project_not_added')
|
||||
end
|
||||
else
|
||||
render_validation_error @repository, "Project has not been added to repository"
|
||||
end
|
||||
end
|
||||
|
||||
def remove_project
|
||||
project_id = params[:project_id]
|
||||
ProjectToRepository.where(:project_id => project_id, :repository_id => @repository.id).destroy_all
|
||||
render_json_response @repository, "Project '#{project_id}' has been removed from repository successfully"
|
||||
end
|
||||
|
||||
def signatures
|
||||
key_pair = @repository.key_pair
|
||||
key_pair.destroy if key_pair
|
||||
key_pair = @repository.build_key_pair(params[:repository])
|
||||
key_pair.user_id = current_user.id
|
||||
if key_pair.save
|
||||
render_json_response @repository, 'Signatures have been updated for repository successfully'
|
||||
else
|
||||
render_json_response @repository, error_message(key_pair, 'Signatures have not been updated for repository'), 422
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Api::V1::UsersController < Api::V1::BaseController
|
||||
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource :user, :only => :show
|
||||
before_filter :set_current_user, :except => :show
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def show_current_user
|
||||
render :show
|
||||
end
|
||||
|
||||
def update
|
||||
user_params = params[:user] || {}
|
||||
send_confirmation = user_params[:email] != @user.email
|
||||
if @user.update_without_password(user_params)
|
||||
if send_confirmation
|
||||
@user.confirmed_at, @user.confirmation_sent_at = nil
|
||||
@user.send_confirmation_instructions
|
||||
end
|
||||
render_json_response @user, 'User has been updated successfully'
|
||||
else
|
||||
render_validation_error @user, "#{class_name} has not been updated"
|
||||
end
|
||||
end
|
||||
|
||||
def notifiers
|
||||
if request.put?
|
||||
if @user.notifier.update_attributes(params[:notifiers])
|
||||
render_json_response @user, 'User notification settings have been updated successfully'
|
||||
else
|
||||
render_json_response @user, error_message(@user.notifier, 'User notification settings have not been updated'), 422
|
||||
end
|
||||
else
|
||||
render :notifiers
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_current_user
|
||||
@user = current_user
|
||||
end
|
||||
|
||||
end
|
|
@ -1,5 +1,8 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class ApplicationController < ActionController::Base
|
||||
AIRBRAKE_IGNORE = [ActionController::InvalidAuthenticityToken,
|
||||
AbstractController::ActionNotFound]
|
||||
|
||||
protect_from_forgery
|
||||
|
||||
layout :layout_by_resource
|
||||
|
@ -14,13 +17,42 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
helper_method :get_owner
|
||||
|
||||
unless Rails.env.development?
|
||||
|
||||
rescue_from Exception, :with => :render_500
|
||||
rescue_from ActiveRecord::RecordNotFound,
|
||||
ActionController::RoutingError,
|
||||
ActionController::UnknownController,
|
||||
AbstractController::ActionNotFound, :with => :render_404
|
||||
end
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
redirect_to forbidden_url, :alert => t("flash.exception_message")
|
||||
end
|
||||
|
||||
rescue_from Grit::NoSuchPathError, :with => :not_found
|
||||
|
||||
protected
|
||||
|
||||
def render_404
|
||||
render_error 404
|
||||
end
|
||||
|
||||
def render_500(e)
|
||||
#check for exceptions Airbrake ignores by default and exclude them from manual Airbrake notification
|
||||
if Rails.env.production? && !AIRBRAKE_IGNORE.include?(e.class)
|
||||
notify_airbrake(e)
|
||||
end
|
||||
render_error 500
|
||||
end
|
||||
|
||||
def render_error(status)
|
||||
respond_to do |format|
|
||||
format.json { render :json => {:status => status, :message => t("flash.#{status}_message")}.to_json, :status => status }
|
||||
format.html { redirect_to "/#{status}.html", :alert => t("flash.#{status}_message") }
|
||||
end
|
||||
end
|
||||
|
||||
def set_locale
|
||||
I18n.locale = check_locale( get_user_locale ||
|
||||
(request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'][0,2].downcase : nil ))
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class AutocompletesController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
|
||||
autocomplete :group, :uname
|
||||
autocomplete :user, :uname
|
||||
end
|
|
@ -29,27 +29,21 @@ class Groups::MembersController < Groups::BaseController
|
|||
def remove
|
||||
all_user_ids = []
|
||||
params['user_remove'].each do |user_id, remove|
|
||||
all_user_ids << user_id if remove == ["1"] && parent.owner.id.to_s != user_id
|
||||
all_user_ids << user_id if remove == ["1"]
|
||||
end if params['user_remove']
|
||||
all_user_ids.each do |user_id|
|
||||
u = User.find(user_id)
|
||||
Relation.by_actor(u).by_target(parent).each {|r| r.destroy}
|
||||
User.where(:id => all_user_ids).each do |user|
|
||||
parent.remove_member(user)
|
||||
end
|
||||
redirect_to group_members_path(parent)
|
||||
end
|
||||
|
||||
def add
|
||||
if params['user_id'] and !params['user_id'].empty?
|
||||
if params['user_id'].present?
|
||||
@user = User.find_by_uname(params['user_id'])
|
||||
unless parent.actors.exists? :actor_id => @user.id, :actor_type => 'User'
|
||||
relation = parent.actors.build(:actor_id => @user.id, :actor_type => 'User', :role => params[:role])
|
||||
if relation.save
|
||||
flash[:notice] = t("flash.members.successfully_added")
|
||||
else
|
||||
flash[:error] = t("flash.members.error_in_adding")
|
||||
end
|
||||
if parent.add_member(@user, params[:role])
|
||||
flash[:notice] = t("flash.members.successfully_added")
|
||||
else
|
||||
flash[:error] = t("flash.members.already_added")
|
||||
flash[:error] = t("flash.members.error_in_adding")
|
||||
end
|
||||
end
|
||||
redirect_to group_members_path(parent)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Groups::ProfileController < Groups::BaseController
|
||||
include AvatarHelper
|
||||
load_and_authorize_resource :class => Group, :instance_name => 'group'
|
||||
|
||||
autocomplete :group, :uname
|
||||
skip_before_filter :authenticate_user!, :only => :show if APP_CONFIG['anonymous_access']
|
||||
|
||||
def index
|
||||
@groups = current_user.groups.paginate(:page => params[:group_page]) # accessible_by(current_ability)
|
||||
|
@ -10,7 +10,9 @@ class Groups::ProfileController < Groups::BaseController
|
|||
end
|
||||
|
||||
def show
|
||||
@projects = @group.projects.by_visibilities(['open'])
|
||||
@projects = @group.projects.by_visibilities(['open']).
|
||||
search(params[:search]).search_order.
|
||||
paginate(:page => params[:page], :per_page => 25)
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -20,8 +22,7 @@ class Groups::ProfileController < Groups::BaseController
|
|||
end
|
||||
|
||||
def create
|
||||
@group = Group.new params[:group]
|
||||
@group.owner = current_user
|
||||
@group = current_user.own_groups.new params[:group]
|
||||
if @group.save
|
||||
flash[:notice] = t('flash.group.saved')
|
||||
redirect_to group_path(@group)
|
||||
|
@ -34,6 +35,7 @@ class Groups::ProfileController < Groups::BaseController
|
|||
|
||||
def update
|
||||
if @group.update_attributes(params[:group])
|
||||
update_avatar(@group, params)
|
||||
flash[:notice] = t('flash.group.saved')
|
||||
redirect_to group_path(@group)
|
||||
else
|
||||
|
|
|
@ -5,8 +5,6 @@ class Platforms::PlatformsController < Platforms::BaseController
|
|||
skip_before_filter :authenticate_user!, :only => [:advisories, :members, :show] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource
|
||||
|
||||
autocomplete :user, :uname
|
||||
|
||||
def index
|
||||
@platforms = @platforms.accessible_by(current_ability, :related).paginate(:page => params[:page], :per_page => 20)
|
||||
end
|
||||
|
|
|
@ -123,16 +123,19 @@ class Platforms::RepositoriesController < Platforms::BaseController
|
|||
:per_page => params[:iDisplayLength].present? ? params[:iDisplayLength] : 25
|
||||
)
|
||||
|
||||
@total_projects_count = @projects.count
|
||||
@total_projects = @projects.count
|
||||
@projects = @projects.search(params[:sSearch]).search_order if params[:sSearch].present?
|
||||
@projects = @projects.order(order)
|
||||
|
||||
render :partial => (params[:added] == "true") ? 'project' : 'proj_ajax', :layout => false
|
||||
respond_to do |format|
|
||||
format.json {
|
||||
render :partial => (params[:added] == "true") ? 'project' : 'proj_ajax', :layout => false
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def remove_project
|
||||
@project = Project.find(params[:project_id])
|
||||
ProjectToRepository.where(:project_id => @project.id, :repository_id => @repository.id).destroy_all
|
||||
ProjectToRepository.where(:project_id => params[:project_id], :repository_id => @repository.id).destroy_all
|
||||
redirect_to platform_repository_path(@platform, @repository), :notice => t('flash.repository.project_removed')
|
||||
end
|
||||
|
||||
|
|
|
@ -57,8 +57,6 @@ class Projects::BuildListsController < Projects::BaseController
|
|||
Arch.where(:id => params[:arches]).each do |arch|
|
||||
Platform.main.where(:id => build_for_platforms).each do |build_for_platform|
|
||||
@build_list = @project.build_lists.build(params[:build_list])
|
||||
@build_list.commit_hash = @project.repo.commits(@build_list.project_version.match(/^latest_(.+)/).to_a.last ||
|
||||
@build_list.project_version).first.id if @build_list.project_version
|
||||
@build_list.build_for_platform = build_for_platform; @build_list.arch = arch; @build_list.user = current_user
|
||||
@build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.build_for_platform.repository_ids.include? ir.to_i}
|
||||
@build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority
|
||||
|
@ -198,23 +196,13 @@ class Projects::BuildListsController < Projects::BaseController
|
|||
|
||||
if params[:attach_advisory] == 'new'
|
||||
# create new advisory
|
||||
unless @build_list.build_advisory(params[:build_list][:advisory]) do |a|
|
||||
a.update_type = @build_list.update_type
|
||||
a.projects << @build_list.project
|
||||
a.platforms << @build_list.save_to_platform unless a.platforms.include? @build_list.save_to_platform
|
||||
end.save
|
||||
unless @build_list.associate_and_create_advisory(params[:build_list][:advisory])
|
||||
redirect_to :back, :notice => t('layout.build_lists.publish_fail') and return
|
||||
end
|
||||
else
|
||||
# attach existing advisory
|
||||
a = Advisory.where(:advisory_id => params[:attach_advisory]).limit(1).first
|
||||
if a.update_type != @build_list.update_type
|
||||
redirect_to :back, :notice => t('layout.build_lists.publish_fail') and return
|
||||
end
|
||||
a.platforms << @build_list.save_to_platform unless a.platforms.include? @build_list.save_to_platform
|
||||
a.projects << @build_list.project unless a.projects.include? @build_list.project
|
||||
@build_list.advisory = a
|
||||
unless a.save
|
||||
a = Advisory.where(:advisory_id => params[:attach_advisory]).first
|
||||
unless (a && a.attach_build_list(@build_list))
|
||||
redirect_to :back, :notice => t('layout.build_lists.publish_fail') and return
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,31 +4,34 @@ class Projects::CommentsController < Projects::BaseController
|
|||
load_and_authorize_resource :project
|
||||
before_filter :find_commentable
|
||||
before_filter :find_or_build_comment
|
||||
load_and_authorize_resource #:through => :commentable
|
||||
load_and_authorize_resource :new => :new_line
|
||||
|
||||
include CommentsHelper
|
||||
|
||||
def create
|
||||
if @comment.save
|
||||
anchor = ''
|
||||
if !@comment.set_additional_data params
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
elsif @comment.save
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to project_commentable_path(@project, @commentable)
|
||||
anchor = view_context.comment_anchor(@comment)
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
flash[:warning] = @comment.errors.full_messages.join('. ')
|
||||
end
|
||||
redirect_to "#{project_commentable_path(@project, @commentable)}##{anchor}"
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @comment.update_attributes(params[:comment])
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to project_commentable_path(@project, @commentable)
|
||||
status, message = if @comment.update_attributes(params[:comment])
|
||||
[200, view_context.markdown(@comment.body)]
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
[400, view_context.local_alert(@comment.errors.full_messages.join('. '))]
|
||||
end
|
||||
render :inline => message, :status => status
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -37,6 +40,11 @@ class Projects::CommentsController < Projects::BaseController
|
|||
redirect_to project_commentable_path(@project, @commentable)
|
||||
end
|
||||
|
||||
def new_line
|
||||
@path = view_context.project_commentable_comments_path(@project, @commentable)
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_commentable
|
||||
|
|
|
@ -24,7 +24,9 @@ class Projects::Git::BlobsController < Projects::Git::BaseController
|
|||
end
|
||||
|
||||
def raw
|
||||
send_data @blob.data, :type => @blob.content_type, :disposition => @blob.disposition
|
||||
repo = Grit::GitRuby::Repository.new(@project.repo.path)
|
||||
raw = repo.get_raw_object_by_sha1(@blob.id)
|
||||
send_data raw.content, :type => @blob.content_type, :disposition => @blob.disposition
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -9,7 +9,9 @@ class Projects::Git::CommitsController < Projects::Git::BaseController
|
|||
end
|
||||
|
||||
def show
|
||||
@commit = @project.repo.commit(params[:id])
|
||||
@commit = @commentable = @project.repo.commit(params[:id]) || raise(ActiveRecord::RecordNotFound)
|
||||
@comments = Comment.for_commit(@commit)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.diff { render :text => (@commit.diffs.map(&:diff).join("\n") rescue ''), :content_type => "text/plain" }
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Projects::Git::TreesController < Projects::Git::BaseController
|
||||
before_filter lambda{redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, :only => 'show'
|
||||
before_filter lambda{redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, :only => :show
|
||||
skip_before_filter :set_branch_and_tree, :only => :archive
|
||||
|
||||
def show
|
||||
@tree = @tree / @path if @path.present?
|
||||
|
@ -9,13 +10,18 @@ class Projects::Git::TreesController < Projects::Git::BaseController
|
|||
end
|
||||
|
||||
def archive
|
||||
@commit = @project.repo.log(@treeish, nil, :max_count => 1).first
|
||||
format = params[:format]
|
||||
if (@treeish =~ /^#{@project.owner.uname}-#{@project.name}-/) && !(@treeish =~ /[\s]+/) && (format =~ /^(zip|tar\.gz)$/)
|
||||
@treeish = @treeish.gsub(/^#{@project.owner.uname}-#{@project.name}-/, '')
|
||||
@commit = @project.repo.commits(@treeish, 1).first
|
||||
end
|
||||
raise Grit::NoSuchPathError unless @commit
|
||||
name = "#{@project.owner.uname}-#{@project.name}#{@project.repo.tags.include?(@treeish) ? "-#{@treeish}" : ''}-#{@commit.id[0..19]}"
|
||||
fullname = "#{name}.#{params[:format] == 'tar' ? 'tar.gz' : 'zip'}"
|
||||
name = "#{@project.owner.uname}-#{@project.name}-#{@treeish}"
|
||||
fullname = "#{name}.#{format == 'zip' ? 'zip' : 'tar.gz'}"
|
||||
file = Tempfile.new fullname, 'tmp'
|
||||
system("cd #{@project.path}; git archive --format=#{params[:format]} --prefix=#{name}/ #{@treeish} #{params[:format] == 'tar' ? ' | gzip -9' : ''} > #{file.path}")
|
||||
system("cd #{@project.path}; git archive --format=#{format == 'zip' ? 'zip' : 'tar'} --prefix=#{name}/ #{@treeish} #{format == 'zip' ? '' : ' | gzip -9'} > #{file.path}")
|
||||
file.close
|
||||
send_file file.path, :disposition => 'attachment', :type => "application/#{params[:format] == 'tar' ? 'x-tar-gz' : 'zip'}", :filename => fullname
|
||||
send_file file.path, :disposition => 'attachment', :type => "application/#{format == 'zip' ? 'zip' : 'x-tar-gz'}", :filename => fullname
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -10,20 +10,24 @@ class Projects::IssuesController < Projects::BaseController
|
|||
layout false, :only => [:update, :search_collaborators]
|
||||
|
||||
def index(status = 200)
|
||||
@is_assigned_to_me = params[:filter] == 'to_me'
|
||||
@status = params[:status] == 'closed' ? 'closed' : 'open'
|
||||
@labels = params[:labels] || []
|
||||
@issues = @project.issues
|
||||
@issues = @issues.where(:assignee_id => current_user.id) if @is_assigned_to_me
|
||||
@issues = @project.issues.without_pull_requests
|
||||
@issues = @issues.where(:assignee_id => current_user.id) if @is_assigned_to_me = params[:filter] == 'to_me'
|
||||
@issues = @issues.joins(:labels).where(:labels => {:name => @labels}) unless @labels == []
|
||||
# Using mb_chars for correct transform to lowercase ('Русский Текст'.downcase => "Русский Текст")
|
||||
@issues = @issues.where('issues.title ILIKE ?', "%#{params[:search_issue].mb_chars.downcase}%") if params[:search_issue]
|
||||
@issues = @issues.search(params[:search_issue])
|
||||
|
||||
@opened_issues, @closed_issues = @issues.opened.count, @issues.closed.count
|
||||
@issues = @issues.where(:status => @status)
|
||||
.includes(:assignee, :user).order('serial_id desc').uniq.paginate :per_page => 10, :page => params[:page]
|
||||
@opened_issues, @closed_issues = @issues.not_closed_or_merged.count, @issues.closed_or_merged.count
|
||||
if params[:status] == 'closed'
|
||||
@issues, @status = @issues.closed_or_merged, params[:status]
|
||||
else
|
||||
@issues, @status = @issues.not_closed_or_merged, 'open'
|
||||
end
|
||||
|
||||
@issues = @issues.includes(:assignee, :user, :pull_request).def_order.uniq
|
||||
.paginate :per_page => 10, :page => params[:page]
|
||||
if status == 200
|
||||
render 'index', :layout => request.xhr? ? 'issues' : 'application'
|
||||
render 'index', :layout => request.xhr? ? 'with_sidebar' : 'application'
|
||||
else
|
||||
render :status => status, :nothing => true
|
||||
end
|
||||
|
@ -46,15 +50,23 @@ class Projects::IssuesController < Projects::BaseController
|
|||
end
|
||||
end
|
||||
|
||||
def show
|
||||
redirect_to project_pull_request_path(@project, @issue.pull_request) if @issue.pull_request
|
||||
end
|
||||
|
||||
def update
|
||||
@issue.labelings.destroy_all if params[:update_labels]
|
||||
if params[:issue] && status = params[:issue][:status]
|
||||
@issue.set_close(current_user) if status == 'closed'
|
||||
@issue.set_open if status == 'open'
|
||||
render :partial => 'status', :status => (@issue.save ? 200 : 500)
|
||||
render :partial => 'status', :status => (@issue.save ? 200 : 400)
|
||||
elsif params[:issue]
|
||||
status = @issue.update_attributes(params[:issue]) ? 200 : 500
|
||||
render :inline => ActionController::Base.helpers.simple_format(params[:issue][:body]), :status => status
|
||||
status, message = if @issue.update_attributes(params[:issue])
|
||||
[200, view_context.markdown(@issue.body)]
|
||||
else
|
||||
[400, view_context.local_alert(@issue.errors.full_messages.join('. '))]
|
||||
end
|
||||
render :inline => message, :status => status
|
||||
else
|
||||
render :nothing => true, :status => 200
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Projects::ProjectsController < Projects::BaseController
|
||||
include ProjectsHelper
|
||||
before_filter :authenticate_user!
|
||||
load_and_authorize_resource :id_param => :project_name # to force member actions load
|
||||
|
||||
|
@ -7,8 +8,17 @@ class Projects::ProjectsController < Projects::BaseController
|
|||
@projects = Project.accessible_by(current_ability, :membered)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { @projects = @projects.recent.paginate(:page => params[:page], :per_page => 25) }
|
||||
format.json { @projects = prepare_list(@projects) }
|
||||
format.html {
|
||||
@all_projects = @projects
|
||||
@groups = current_user.groups
|
||||
@owners = User.where(:id => @projects.where(:owner_type => 'User').uniq.pluck(:owner_id))
|
||||
@projects = @projects.recent.paginate(:page => params[:page], :per_page => 25)
|
||||
}
|
||||
format.json {
|
||||
selected_groups = params[:groups] || []
|
||||
selected_owners = params[:users] || []
|
||||
@projects = prepare_list(@projects, selected_groups, selected_owners)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -93,9 +103,19 @@ class Projects::ProjectsController < Projects::BaseController
|
|||
render :json => items
|
||||
end
|
||||
|
||||
def preview
|
||||
render :inline => view_context.markdown(params[:text] || ''), :layout => false
|
||||
end
|
||||
|
||||
def refs_list
|
||||
refs = @project.repo.branches_and_tags.map(&:name)
|
||||
@selected = (refs.include? params[:selected]) ? params[:selected] : @project.default_branch
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def prepare_list(projects)
|
||||
def prepare_list(projects, groups, owners)
|
||||
res = {}
|
||||
|
||||
colName = ['name']
|
||||
|
@ -104,7 +124,13 @@ class Projects::ProjectsController < Projects::BaseController
|
|||
order = "#{colName[sort_col.to_i]} #{sort_dir}"
|
||||
|
||||
res[:total_count] = projects.count
|
||||
|
||||
if groups.present? || owners.present?
|
||||
projects = projects.by_owners(groups, owners)
|
||||
end
|
||||
|
||||
projects = projects.search(params[:sSearch]).search_order if params[:sSearch].present?
|
||||
|
||||
res[:filtered_count] = projects.count
|
||||
|
||||
projects = projects.order(order)
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Projects::PullRequestsController < Projects::BaseController
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:index, :show] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource :project
|
||||
|
||||
load_resource :issue, :through => :project, :find_by => :serial_id, :parent => false, :except => [:index, :autocomplete_to_project]
|
||||
load_and_authorize_resource :instance_name => :pull, :through => :issue, :singleton => true, :except => [:index, :autocomplete_to_project]
|
||||
|
||||
def new
|
||||
to_project = find_destination_project(false)
|
||||
authorize! :read, to_project
|
||||
|
||||
@pull = to_project.pull_requests.new
|
||||
@pull.issue = to_project.issues.new
|
||||
set_attrs
|
||||
|
||||
if PullRequest.check_ref(@pull, 'to', @pull.to_ref) && PullRequest.check_ref(@pull, 'from', @pull.from_ref) || @pull.uniq_merge
|
||||
flash.now[:warning] = @pull.errors.full_messages.join('. ')
|
||||
else
|
||||
@pull.check(false) # don't make event transaction
|
||||
if @pull.already?
|
||||
@pull.destroy
|
||||
flash.now[:warning] = I18n.t('projects.pull_requests.up_to_date', :to_ref => @pull.to_ref, :from_ref => @pull.from_ref)
|
||||
else
|
||||
load_diff_commits_data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
unless pull_params
|
||||
raise 'expect pull_request params' # for debug
|
||||
redirect :back
|
||||
end
|
||||
to_project = find_destination_project
|
||||
authorize! :read, to_project
|
||||
|
||||
@pull = to_project.pull_requests.new pull_params
|
||||
@pull.issue.user, @pull.issue.project, @pull.from_project = current_user, to_project, @project
|
||||
|
||||
if @pull.valid? # FIXME more clean/clever logics
|
||||
@pull.save # set pull id
|
||||
@pull.check(false) # don't make event transaction
|
||||
if @pull.already?
|
||||
@pull.destroy
|
||||
flash.now[:error] = I18n.t('projects.pull_requests.up_to_date', :to_ref => @pull.to_ref, :from_ref => @pull.from_ref)
|
||||
render :new
|
||||
else
|
||||
@pull.send(@pull.status == 'blocked' ? 'block' : @pull.status)
|
||||
redirect_to project_pull_request_path(@pull.to_project, @pull)
|
||||
end
|
||||
else
|
||||
flash.now[:error] = t('flash.pull_request.save_error')
|
||||
flash.now[:warning] = @pull.errors.full_messages.join('. ')
|
||||
|
||||
if @pull.errors.try(:messages) && @pull.errors.messages[:to_ref].nil? && @pull.errors.messages[:from_ref].nil?
|
||||
@pull.check(false) # don't make event transaction
|
||||
load_diff_commits_data
|
||||
end
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if (action = params[:pull_request_action]) && %w(close reopen).include?(params[:pull_request_action])
|
||||
if @pull.send("can_#{action}?")
|
||||
@pull.set_user_and_time current_user
|
||||
@pull.send(action)
|
||||
@pull.check if @pull.open?
|
||||
end
|
||||
end
|
||||
redirect_to project_pull_request_path(@pull.to_project, @pull)
|
||||
end
|
||||
|
||||
def merge
|
||||
@pull.check
|
||||
unless @pull.merge!(current_user)
|
||||
flash.now[:error] = t('flash.pull_request.save_error')
|
||||
flash.now[:warning] = @pull.errors.full_messages.join('. ')
|
||||
end
|
||||
redirect_to project_pull_request_path(@pull.to_project, @pull)
|
||||
end
|
||||
|
||||
def show
|
||||
load_diff_commits_data
|
||||
end
|
||||
|
||||
def index(status = 200)
|
||||
@issues_with_pull_request = @project.issues.joins(:pull_request)
|
||||
@issues_with_pull_request = @issues_with_pull_request.search(params[:search_pull_request])
|
||||
|
||||
@opened_issues, @closed_issues = @issues_with_pull_request.not_closed_or_merged.count, @issues_with_pull_request.closed_or_merged.count
|
||||
if params[:status] == 'closed'
|
||||
@issues_with_pull_request, @status = @issues_with_pull_request.closed_or_merged, params[:status]
|
||||
else
|
||||
@issues_with_pull_request, @status = @issues_with_pull_request.not_closed_or_merged, 'open'
|
||||
end
|
||||
|
||||
@issues_with_pull_request = @issues_with_pull_request.
|
||||
includes(:assignee, :user, :pull_request).def_order.uniq.
|
||||
paginate :per_page => 10, :page => params[:page]
|
||||
if status == 200
|
||||
render 'index', :layout => request.xhr? ? 'with_sidebar' : 'application'
|
||||
else
|
||||
render :status => status, :nothing => true
|
||||
end
|
||||
end
|
||||
|
||||
def autocomplete_to_project
|
||||
items = Project.accessible_by(current_ability, :membered) | @project.ancestors
|
||||
items.select! {|e| Regexp.new(params[:term].downcase).match(e.name_with_owner.downcase) && e.repo.branches.count > 0}
|
||||
render :json => json_for_autocomplete_base(items)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def pull_params
|
||||
@pull_params ||= params[:pull_request].presence
|
||||
end
|
||||
|
||||
def json_for_autocomplete_base items
|
||||
items.collect do |project|
|
||||
hash = {"id" => project.id.to_s, "label" => project.name_with_owner, "value" => project.name_with_owner}
|
||||
hash[:get_refs_url] = project_refs_list_path(project)
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
def load_diff_commits_data
|
||||
@commits = @pull.repo.commits_between(@pull.to_commit, @pull.from_commit)
|
||||
@total_commits = @commits.count
|
||||
@commits = @commits.last(100)
|
||||
|
||||
@stats = @pull.diff_stats
|
||||
@comments, @commentable = @issue.comments, @issue
|
||||
end
|
||||
|
||||
def find_destination_project bang=true
|
||||
args = params[:to_project].try(:split, '/') || []
|
||||
project = (args.length == 2) ? Project.find_by_owner_and_name(*args) : nil
|
||||
raise ActiveRecord::RecordNotFound if bang && !project
|
||||
project || @project
|
||||
end
|
||||
|
||||
def set_attrs
|
||||
if pull_params && pull_params[:issue_attributes]
|
||||
@pull.issue.title = pull_params[:issue_attributes][:title].presence
|
||||
@pull.issue.body = pull_params[:issue_attributes][:body].presence
|
||||
end
|
||||
@pull.from_project = @project
|
||||
@pull.to_ref = (pull_params[:to_ref].presence if pull_params) || @pull.to_project.default_branch
|
||||
@pull.from_ref = params[:treeish].presence || (pull_params[:from_ref].presence if pull_params) || @pull.from_project.default_branch
|
||||
end
|
||||
end
|
|
@ -1,8 +1,10 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Users::ProfileController < Users::BaseController
|
||||
autocomplete :user, :uname
|
||||
skip_before_filter :authenticate_user!, :only => :show if APP_CONFIG['anonymous_access']
|
||||
|
||||
def show
|
||||
@projects = @user.projects.by_visibilities(['open'])
|
||||
@projects = @user.projects.by_visibilities(['open']).
|
||||
search(params[:search]).search_order.
|
||||
paginate(:page => params[:page], :per_page => 25)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Users::SettingsController < Users::BaseController
|
||||
include AvatarHelper
|
||||
before_filter :set_current_user
|
||||
|
||||
def profile
|
||||
if request.put?
|
||||
send_confirmation = params[:user][:email] != @user.email
|
||||
if @user.update_without_password(params[:user])
|
||||
if @user.avatar && params[:delete_avatar] == '1'
|
||||
@user.avatar = nil
|
||||
@user.save
|
||||
end
|
||||
update_avatar(@user, params)
|
||||
if send_confirmation
|
||||
@user.confirmed_at, @user.confirmation_sent_at = nil
|
||||
@user.send_confirmation_instructions
|
||||
|
|
|
@ -39,4 +39,19 @@ module ApplicationHelper
|
|||
else object.class.name
|
||||
end
|
||||
end
|
||||
|
||||
def markdown(text)
|
||||
unless @redcarpet
|
||||
html_options = {filter_html: true, hard_wrap: true, with_toc_data: true}
|
||||
options = {no_intraemphasis: true, tables: true, fenced_code_blocks: true, autolink: true, strikethrough: true, lax_html_blocks: true}
|
||||
@redcarpet = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(html_options), options)
|
||||
end
|
||||
@redcarpet.render(text).html_safe
|
||||
end
|
||||
|
||||
def local_alert(text, type = 'error')
|
||||
html = "<div class='flash'><div class='alert #{type}'> #{text}"
|
||||
html << link_to('×', '#', :class => 'close close-alert', 'data-dismiss' => 'alert')
|
||||
html << '</div></div>'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
module AvatarHelper
|
||||
def update_avatar(subject, params)
|
||||
if subject.avatar && params[:delete_avatar] == '1'
|
||||
subject.avatar = nil
|
||||
subject.save
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,20 +1,30 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module CommentsHelper
|
||||
def project_commentable_comment_path(project, commentable, comment)
|
||||
case
|
||||
when Comment.issue_comment?(commentable.class)
|
||||
if Comment.issue_comment?(commentable.class)
|
||||
project_issue_comment_path(project, commentable, comment)
|
||||
when Comment.commit_comment?(commentable.class)
|
||||
elsif Comment.commit_comment?(commentable.class)
|
||||
project_commit_comment_path(project, commentable, comment)
|
||||
end
|
||||
end
|
||||
|
||||
def project_commentable_path(project, commentable)
|
||||
case
|
||||
when Comment.issue_comment?(commentable.class)
|
||||
polymorphic_path [project, commentable]
|
||||
when Comment.commit_comment?(commentable.class)
|
||||
if Comment.issue_comment?(commentable.class)
|
||||
polymorphic_path [project, commentable.pull_request ? commentable.pull_request : commentable]
|
||||
elsif Comment.commit_comment?(commentable.class)
|
||||
commit_path project, commentable.id
|
||||
end
|
||||
end
|
||||
|
||||
def project_commentable_comments_path(project, commentable)
|
||||
if commentable.is_a? Issue
|
||||
project_issue_comments_path(@project, @commentable)
|
||||
elsif commentable.is_a? Grit::Commit
|
||||
project_commit_comments_path(@project, @commentable)
|
||||
end
|
||||
end
|
||||
|
||||
def comment_anchor c
|
||||
"#{(c.data.present? && c.actual_inline_comment?) ? 'diff-' : ''}comment#{c.id}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,10 @@ module CommitHelper
|
|||
|
||||
def render_commit_stats(stats)
|
||||
res = ["<table class='commit_stats'>"]
|
||||
ind=0
|
||||
stats.files.each do |filename, adds, deletes, total|
|
||||
res << "<tr>"
|
||||
res << "<td><a href='##{h(filename)}'>#{h(filename)}</a></td>"
|
||||
res << "<td><a href='#diff-#{ind}'>#{h(filename.rtruncate 120)}</a></td>"
|
||||
res << "<td class='diffstat'>"
|
||||
res << I18n.t("layout.projects.inline_changes_count", :count => total).strip +
|
||||
" (" +
|
||||
|
@ -14,6 +15,7 @@ module CommitHelper
|
|||
I18n.t("layout.projects.inline_deletions_count", :count => deletes).strip +
|
||||
")"
|
||||
res << "</td>"
|
||||
ind +=1
|
||||
end
|
||||
res << "</table>"
|
||||
|
||||
|
|
|
@ -1,18 +1,267 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module DiffHelper
|
||||
def render_diff_stats(stats)
|
||||
path = @pull.id ? polymorphic_path([@project, @pull]) : ''
|
||||
res = ["<table class='commit_stats'>"]
|
||||
stats.each_with_index do |stat, ind|
|
||||
res << "<tr>"
|
||||
res << "<td>#{link_to stat.filename.rtruncate(120), "#{path}#diff-#{ind}"}</td>"
|
||||
res << "<td class='diffstat'>"
|
||||
res << I18n.t("layout.projects.inline_changes_count", :count => stat.additions + stat.deletions).strip +
|
||||
" (" +
|
||||
I18n.t("layout.projects.inline_additions_count", :count => stat.additions).strip +
|
||||
", " +
|
||||
I18n.t("layout.projects.inline_deletions_count", :count => stat.deletions).strip +
|
||||
")"
|
||||
res << "</td>"
|
||||
end
|
||||
res << "</table>"
|
||||
|
||||
def render_diff(diff)
|
||||
diff_display ||= Diff::Display::Unified.new(diff.diff)
|
||||
res.join("\n").html_safe.default_encoding!
|
||||
end
|
||||
|
||||
#res = "<a name='#{h(diff.a_path)}'></a>"
|
||||
#include Git::Diff::InlineCallback
|
||||
def render_diff(diff, args = {})#diff_counter, comments, opts = nil diffpath = nil)
|
||||
if diff.respond_to?(:diff)
|
||||
diff, filepath, in_discussion = diff.diff, diff.a_path, false
|
||||
comments = (args[:comments] || []).select{|c| c.data.try('[]', :path) == filepath}
|
||||
else
|
||||
filepath, in_discussion, comments = args[:diffpath], true, args[:comments]
|
||||
end
|
||||
|
||||
diff_display ||= Diff::Display::Unified.new(diff)
|
||||
url = if @pull
|
||||
@pull.id ? polymorphic_path([@project, @pull]) : ''
|
||||
elsif @commit
|
||||
commit_path @project, @commit
|
||||
end
|
||||
prepare(args.merge({:filepath => filepath, :comments => comments, :in_discussion => in_discussion}))
|
||||
|
||||
res = "<table class='diff inline' cellspacing='0' cellpadding='0'>"
|
||||
res += "<tbody>"
|
||||
res += diff_display.render(Git::Diff::InlineCallback.new)
|
||||
res += renderer diff_display.data #diff_display.render(Git::Diff::InlineCallback.new comments, path)
|
||||
res += tr_line_comments(comments) if in_discussion
|
||||
res += "</tbody>"
|
||||
res += "</table>"
|
||||
|
||||
res.html_safe
|
||||
end
|
||||
|
||||
########################################################
|
||||
# FIXME: Just to dev, remove to lib. Really need it?
|
||||
########################################################
|
||||
def prepare(args)
|
||||
@url, @diff_counter, @in_discussion = args[:url], args[:diff_counter], args[:in_discussion]
|
||||
@filepath, @line_comments, @in_wiki = args[:filepath], args[:comments], args[:in_wiki]
|
||||
@add_reply_id, @num_line = if @in_discussion
|
||||
[@line_comments[0].id, @line_comments[0].data[:line].to_i - @line_comments[0].data[:strings].lines.count.to_i-1]
|
||||
else
|
||||
[nil, -1]
|
||||
end
|
||||
end
|
||||
|
||||
def headerline(line)
|
||||
set_line_number
|
||||
"<tr class='header'>
|
||||
<td class='line_numbers'>...</td>
|
||||
<td class='line_numbers'>...</td>
|
||||
<td class='header'>#{line}</td>
|
||||
</tr>"
|
||||
end
|
||||
|
||||
def addline(line)
|
||||
set_line_number
|
||||
"<tr class='changes'>
|
||||
<td class='line_numbers'></td>
|
||||
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number}
|
||||
<td class='code ins'>
|
||||
#{line_comment}
|
||||
<pre>#{render_line(line)}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
#{render_line_comments}"
|
||||
end
|
||||
|
||||
def remline(line)
|
||||
set_line_number
|
||||
"<tr class='changes'>
|
||||
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number}
|
||||
<td class='line_numbers'></td>
|
||||
<td class='code del'>
|
||||
#{line_comment}
|
||||
<pre>#{render_line(line)}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
#{render_line_comments}"
|
||||
end
|
||||
|
||||
def modline(line)
|
||||
set_line_number
|
||||
"<tr clas='chanes line'>
|
||||
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number}
|
||||
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number}
|
||||
<td class='code unchanged modline'>
|
||||
#{line_comment}
|
||||
<pre>#{render_line(line)}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
#{render_line_comments}"
|
||||
end
|
||||
|
||||
def unmodline(line)
|
||||
set_line_number
|
||||
"<tr class='changes unmodline'>
|
||||
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number}
|
||||
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number}
|
||||
<td class='code unchanged unmodline'>
|
||||
#{line_comment}
|
||||
<pre>#{render_line(line)}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
#{render_line_comments}"
|
||||
end
|
||||
|
||||
def sepline(line)
|
||||
"<tr class='changes hunk-sep'>
|
||||
<td class='line_numbers line_num_cut'>…</td>
|
||||
<td class='line_numbers line_num_cut'>…</td>
|
||||
<td class='code cut-line'></td>
|
||||
</tr>"
|
||||
end
|
||||
|
||||
def nonewlineline(line)
|
||||
set_line_number
|
||||
"<tr class='changes'>
|
||||
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number}
|
||||
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number}
|
||||
<td class='code modline unmodline'>
|
||||
#{line_comment}
|
||||
<pre>#{render_line(line)}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
#{render_line_comments}"
|
||||
end
|
||||
|
||||
def before_headerblock(block)
|
||||
end
|
||||
|
||||
def after_headerblock(block)
|
||||
end
|
||||
|
||||
def before_unmodblock(block)
|
||||
end
|
||||
|
||||
def before_modblock(block)
|
||||
end
|
||||
|
||||
def before_remblock(block)
|
||||
end
|
||||
|
||||
def before_addblock(block)
|
||||
end
|
||||
|
||||
def before_sepblock(block)
|
||||
end
|
||||
|
||||
def before_nonewlineblock(block)
|
||||
end
|
||||
|
||||
def after_unmodblock(block)
|
||||
end
|
||||
|
||||
def after_modblock(block)
|
||||
end
|
||||
|
||||
def after_remblock(block)
|
||||
end
|
||||
|
||||
def after_addblock(block)
|
||||
end
|
||||
|
||||
def after_sepblock(block)
|
||||
end
|
||||
|
||||
def after_nonewlineblock(block)
|
||||
end
|
||||
|
||||
def new_line
|
||||
""
|
||||
end
|
||||
|
||||
def renderer(data)
|
||||
result = []
|
||||
data.each do |block|
|
||||
result << send("before_" + classify(block), block)
|
||||
result << block.map { |line| send(classify(line), line) }
|
||||
result << send("after_" + classify(block), block)
|
||||
end
|
||||
result.compact.join(new_line)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def classify(object)
|
||||
object.class.name[/\w+$/].downcase
|
||||
end
|
||||
|
||||
def escape(str)
|
||||
str.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('"', '"')
|
||||
end
|
||||
|
||||
def render_line(line)
|
||||
res = '<span class="diff-content">'
|
||||
if line.inline_changes?
|
||||
prefix, changed, postfix = line.segments.map{|segment| escape(segment) }
|
||||
res += "#{prefix}<span class='idiff'>#{changed}</span>#{postfix}"
|
||||
else
|
||||
res += escape(line)
|
||||
end
|
||||
res += '</span>'
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
def set_line_number
|
||||
@num_line = @num_line.succ
|
||||
end
|
||||
|
||||
def line_comment
|
||||
return if @in_wiki || (@in_discussion && @add_reply_id && @line_comments[0].data[:line].to_i != @num_line)
|
||||
link_to image_tag('line_comment.png', :alt => t('layout.comments.new_header')), new_comment_path, :class => 'add_line-comment'
|
||||
end
|
||||
|
||||
def render_line_comments
|
||||
unless @in_wiki || @in_discussion
|
||||
comments = @line_comments.select do |c|
|
||||
c.data.try('[]', :line) == @num_line.to_s && c.actual_inline_comment?
|
||||
end
|
||||
tr_line_comments(comments) if comments.count > 0
|
||||
end
|
||||
end
|
||||
|
||||
def td_line_link id, num
|
||||
"<td class='line_numbers' id='#{id}'><a href='#{@url}##{id}'>#{num}</a></td>"
|
||||
end
|
||||
|
||||
def tr_line_comments comments
|
||||
return if @in_wiki
|
||||
res="<tr class='inline-comments'>
|
||||
<td class='line_numbers' colspan='2'>#{comments.count}</td>
|
||||
<td>"
|
||||
comments.each do |comment|
|
||||
res << "<div class='line-comments'>
|
||||
#{render 'projects/comments/comment', :comment => comment, :data => {:project => @project, :commentable => @commentable, :add_anchor => 'inline', :in_discussion => @in_discussion}}
|
||||
</div>"
|
||||
end
|
||||
res << link_to(t('layout.comments.new_inline'), new_comment_path, :class => 'new_inline_comment button')
|
||||
res << "</td></tr>"
|
||||
end
|
||||
|
||||
def new_comment_path
|
||||
hash = {:path => @filepath, :line => @num_line}
|
||||
if @commentable.is_a? Issue
|
||||
project_new_line_pull_comment_path(@project, @commentable, hash.merge({:in_reply => @add_reply_id}))
|
||||
elsif @commentable.is_a? Grit::Commit
|
||||
new_line_commit_comment_path(@project, @commentable, hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ module GitHelper
|
|||
[ ['Branches', project.repo.branches.map{|b| "latest_#{b.name}"}],
|
||||
['Tags', project.repo.tags.map(&:name)] ]
|
||||
end
|
||||
|
||||
|
||||
def split_commits_by_date(commits)
|
||||
commits.sort{|x, y| y.authored_date <=> x.authored_date}.inject({}) do |h, commit|
|
||||
dt = commit.authored_date
|
||||
|
@ -80,4 +80,3 @@ module GitHelper
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module ProjectsHelper
|
||||
def options_for_filters(all_projects, groups, owners)
|
||||
projects_count_by_groups = all_projects.where(:owner_id => groups, :owner_type => 'Group').
|
||||
group(:owner_id).count
|
||||
projects_count_by_owners = all_projects.where(:owner_id => owners, :owner_type => 'User').
|
||||
group(:owner_id).count
|
||||
(groups + owners).map do |o|
|
||||
class_name = o.class.name
|
||||
{
|
||||
:id => "#{class_name.downcase}-#{o.id}",
|
||||
:color => '0054a6',
|
||||
:selected => false,
|
||||
:check_box_name => class_name.downcase.pluralize,
|
||||
:check_box_value => o.id,
|
||||
:name => content_tag(:div, content_tag(:span, o.uname, :class => class_name.downcase)),
|
||||
:uname => o.uname, # only for sorting
|
||||
:count => o.is_a?(User) ? projects_count_by_owners[o.id] : projects_count_by_groups[o.id]
|
||||
}
|
||||
end.sort_by{ |f| f[:uname] }
|
||||
end
|
||||
|
||||
def git_repo_url(name)
|
||||
if current_user
|
||||
"#{request.protocol}#{current_user.uname}@#{request.host_with_port}/#{name}.git"
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module PullRequestHelper
|
||||
def merge_activity comments, commits
|
||||
common_comments, pull_comments = comments.partition {|c| c.data.blank?}
|
||||
common_comments = common_comments.map{ |c| [c.created_at, c] }
|
||||
pull_comments = pull_comments.group_by(&:data).map{|data, c| [c.first.created_at, [data || {}, [c].flatten]]}
|
||||
commits = commits.map{ |c| [(c.committed_date || c.authored_date), c] }
|
||||
(common_comments + pull_comments + commits).sort_by{ |c| c[0] }.map{ |c| c[1] }
|
||||
end
|
||||
|
||||
def pull_status_label pull
|
||||
statuses = {'ready' => 'success', 'closed' => 'important', 'merged' => 'important', 'blocked' => 'warning'}
|
||||
content_tag :span, t("projects.pull_requests.statuses.#{pull.status}"), :class => "label-bootstrap label-#{statuses[pull.status]}"
|
||||
end
|
||||
|
||||
def pull_status pull
|
||||
if %w(blocked merged closed ready open).include? pull.status
|
||||
t("projects.pull_requests.#{pull.status}", :user => pull.issue.closer.try(:uname), :to_ref => show_ref(pull, 'to'),
|
||||
:from_ref => show_ref(pull, 'from'), :time => pull.issue.closed_at).html_safe
|
||||
else
|
||||
raise "pull id (#{pull.id}) wrong status #{pull.status} "
|
||||
end
|
||||
end
|
||||
|
||||
def pull_header pull
|
||||
str = "#{t '.header'} #{t 'from'} <span class='label-bootstrap label-info font14'> \
|
||||
#{show_ref pull, 'from'}</span> \
|
||||
#{t 'into'} <span class='label-bootstrap label-info font14'> \
|
||||
#{show_ref pull, 'to'}</span>"
|
||||
str << " #{t 'by'} #{link_to pull.user.uname, user_path(pull.user)}" if pull.persisted?
|
||||
str.html_safe
|
||||
end
|
||||
|
||||
#helper for helpers
|
||||
def show_ref pull, which, limit = 30
|
||||
project, ref = pull.send("#{which}_project"), pull.send("#{which}_ref")
|
||||
link_to "#{project.owner.uname.truncate limit}/#{project.name.truncate limit}: #{ref.truncate limit}", ref_path(project, ref)
|
||||
end
|
||||
|
||||
def ref_path project, ref
|
||||
return tree_path(project, ref) if project.repo.branches_and_tags.map(&:name).include? ref
|
||||
return commit_path(project, ref) if project.repo.commit ref
|
||||
'#'
|
||||
end
|
||||
|
||||
def ref_selector_options(project, current)
|
||||
res = []
|
||||
value = Proc.new {|t| [t.name.truncate(40)]}
|
||||
res << [I18n.t('layout.git.repositories.branches'), project.repo.branches.map(&value)]
|
||||
res << [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&value)]
|
||||
|
||||
grouped_options_for_select(res, current)
|
||||
end
|
||||
end
|
|
@ -5,12 +5,13 @@ module UsersHelper
|
|||
avatar_url(User.where(:email => email).first || User.new(:email => email), size)
|
||||
end
|
||||
|
||||
def avatar_url(user, size = :small)
|
||||
return image_path('group32.png') if user.kind_of? Group
|
||||
if user.try('avatar?')
|
||||
user.avatar.url(size)
|
||||
def avatar_url(subject, size = :small)
|
||||
if subject.try('avatar?')
|
||||
subject.avatar.url(size)
|
||||
elsif subject.kind_of? Group
|
||||
image_path('ava-big.png')
|
||||
else
|
||||
gravatar_url(user.email, user.avatar.styles[size].geometry.split('x').first)
|
||||
gravatar_url(subject.email, subject.avatar.styles[size].geometry.split('x').first)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ class FeedbackMailer < ActionMailer::Base
|
|||
default :to => FBM_CONFIG['email'],
|
||||
:cc => FBM_CONFIG['cc'],
|
||||
:bcc => FBM_CONFIG['bcc']
|
||||
default_url_options.merge!(:protocol => 'https') if APP_CONFIG['mailer_https_url']
|
||||
|
||||
include Resque::Mailer # send email async
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class UserMailer < ActionMailer::Base
|
||||
default :from => APP_CONFIG['do-not-reply-email']
|
||||
default_url_options.merge!(:protocol => 'https') if APP_CONFIG['mailer_https_url']
|
||||
|
||||
include Resque::Mailer # send email async
|
||||
|
||||
|
|
|
@ -14,20 +14,27 @@ class Ability
|
|||
|
||||
# Shared rights between guests and registered users
|
||||
can [:show, :archive], Project, :visibility => 'open'
|
||||
can :get_id, Project, :visibility => 'open' # api
|
||||
can :archive, Project, :visibility => 'open'
|
||||
can :read, Issue, :project => {:visibility => 'open'}
|
||||
can :read, PullRequest, :to_project => {:visibility => 'open'}
|
||||
can :search, BuildList
|
||||
can [:read, :log, :everything], BuildList, :project => {:visibility => 'open'}
|
||||
can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work
|
||||
can :read, Advisory
|
||||
|
||||
|
||||
# Core callbacks
|
||||
can [:publish_build, :status_build, :pre_build, :post_build, :circle_build, :new_bbdt], BuildList
|
||||
|
||||
# Platforms block
|
||||
can [:show, :members, :advisories], Platform, :visibility == 'open'
|
||||
can [:read, :projects_list], Repository, :platform => {:visibility => 'open'}
|
||||
can [:show, :members, :advisories], Platform, :visibility => 'open'
|
||||
can :platforms_for_build, Platform, :visibility => 'open', :platform_type => 'main'
|
||||
can [:read, :projects_list, :projects], Repository, :platform => {:visibility => 'open'}
|
||||
can :read, Product, :platform => {:visibility => 'open'}
|
||||
|
||||
can :show, Group
|
||||
can :show, User
|
||||
|
||||
if user.guest? # Guest rights
|
||||
# can [:new, :create], RegisterRequest
|
||||
else # Registered user rights
|
||||
|
@ -44,10 +51,8 @@ class Ability
|
|||
end
|
||||
|
||||
if user.user?
|
||||
can [:show, :autocomplete_user_uname], User
|
||||
|
||||
can [:read, :create, :autocomplete_group_uname], Group
|
||||
can [:update, :manage_members], Group do |group|
|
||||
can [:read, :create], Group
|
||||
can [:update, :manage_members, :members, :add_member, :remove_member, :update_member], Group do |group|
|
||||
group.actors.exists?(:actor_type => 'User', :actor_id => user.id, :role => 'admin') # or group.owner_id = user.id
|
||||
end
|
||||
can :destroy, Group, :owner_id => user.id
|
||||
|
@ -57,14 +62,18 @@ class Ability
|
|||
can :read, Project, :visibility => 'open'
|
||||
can [:read, :archive], Project, :owner_type => 'User', :owner_id => user.id
|
||||
can [:read, :archive], Project, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
can([:read, :membered], Project, read_relations_for('projects')) {|project| local_reader? project}
|
||||
can([:read, :membered, :get_id], Project, read_relations_for('projects')) {|project| local_reader? project}
|
||||
can(:write, Project) {|project| local_writer? project} # for grack
|
||||
can([:update, :sections, :manage_collaborators, :autocomplete_maintainers], Project) {|project| local_admin? project}
|
||||
can [:update, :sections, :manage_collaborators, :autocomplete_maintainers, :add_member, :remove_member, :update_member, :members], Project do |project|
|
||||
local_admin? project
|
||||
end
|
||||
can(:fork, Project) {|project| can? :read, project}
|
||||
can(:fork, Project) {|project| project.owner_type == 'Group' and can? :update, project.owner}
|
||||
can(:destroy, Project) {|project| owner? project}
|
||||
can(:destroy, Project) {|project| project.owner_type == 'Group' and project.owner.actors.exists?(:actor_type => 'User', :actor_id => user.id, :role => 'admin')}
|
||||
can :remove_user, Project
|
||||
can :preview, Project
|
||||
can(:refs_list, Project) {|project| can? :read, project}
|
||||
|
||||
can [:read, :log, :owned, :everything], BuildList, :user_id => user.id
|
||||
can [:read, :log, :related, :everything], BuildList, :project => {:owner_type => 'User', :owner_id => user.id}
|
||||
|
@ -73,28 +82,27 @@ class Ability
|
|||
can([:create, :update], BuildList) {|build_list| build_list.project.is_package && can?(:write, build_list.project)}
|
||||
|
||||
can(:publish, BuildList) do |build_list|
|
||||
build_list.can_publish? and build_list.save_to_repository.publish_without_qa ? can?(:write, build_list.project) : local_admin?(build_list.save_to_platform)
|
||||
build_list.save_to_repository.publish_without_qa ? can?(:write, build_list.project) : local_admin?(build_list.save_to_platform)
|
||||
end
|
||||
can(:reject_publish, BuildList) do |build_list|
|
||||
build_list.can_reject_publish? and not build_list.save_to_repository.publish_without_qa and local_admin?(build_list.save_to_platform)
|
||||
local_admin?(build_list.save_to_platform)
|
||||
end
|
||||
can(:cancel, BuildList) {|build_list| build_list.can_cancel? && can?(:write, build_list.project)}
|
||||
can(:cancel, BuildList) {|build_list| can?(:write, build_list.project)}
|
||||
|
||||
can [:read, :owned, :related, :members], Platform, :owner_type => 'User', :owner_id => user.id
|
||||
can [:read, :related, :members], Platform, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
can([:read, :related, :members], Platform, read_relations_for('platforms')) {|platform| local_reader? platform}
|
||||
can([:update, :members], Platform) {|platform| local_admin? platform}
|
||||
can([:destroy, :members, :add_member, :remove_member, :remove_members] , Platform) {|platform| owner?(platform) || local_admin?(platform) }
|
||||
can [:autocomplete_user_uname], Platform
|
||||
|
||||
can([:failed_builds_list, :create], MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && mass_build.platform.main? }
|
||||
can(:cancel, MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && !mass_build.stop_build && mass_build.platform.main?}
|
||||
|
||||
can [:read, :projects_list], Repository, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
can [:read, :projects_list], Repository, :platform => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can([:read, :projects_list], Repository, read_relations_for('repositories', 'platforms')) {|repository| local_reader? repository.platform}
|
||||
can([:create, :edit, :update, :destroy, :projects_list, :add_project, :remove_project], Repository) {|repository| local_admin? repository.platform}
|
||||
can([:remove_members, :remove_member, :add_member], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)}
|
||||
can [:read, :projects_list, :projects], Repository, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
can [:read, :projects_list, :projects], Repository, :platform => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can([:read, :projects_list, :projects], Repository, read_relations_for('repositories', 'platforms')) {|repository| local_reader? repository.platform}
|
||||
can([:create, :edit, :update, :destroy, :projects_list, :projects, :add_project, :remove_project], Repository) {|repository| local_admin? repository.platform}
|
||||
can([:remove_members, :remove_member, :add_member, :signatures], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)}
|
||||
can([:add_project, :remove_project], Repository) {|repository| repository.members.exists?(:id => user.id)}
|
||||
can(:clear, Platform) {|platform| local_admin?(platform) && platform.personal?}
|
||||
can([:change_visibility, :settings, :destroy, :edit, :update], Repository) {|repository| owner? repository.platform}
|
||||
|
@ -116,12 +124,20 @@ class Ability
|
|||
can :read, Issue, :project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can(:read, Issue, read_relations_for('issues', 'projects')) {|issue| can? :read, issue.project rescue nil}
|
||||
can(:create, Issue) {|issue| can? :read, issue.project}
|
||||
can([:update, :destroy], Issue) {|issue| issue.user_id == user.id or local_admin?(issue.project)}
|
||||
can(:update, Issue) {|issue| issue.user_id == user.id or local_admin?(issue.project)}
|
||||
cannot :manage, Issue, :project => {:has_issues => false} # switch off issues
|
||||
|
||||
can(:create, Comment) {|comment| can? :read, comment.project}
|
||||
can(:update, Comment) {|comment| comment.user == user or comment.project.owner == user or local_admin?(comment.project)}
|
||||
cannot :manage, Comment, :commentable_type => 'Issue', :commentable => {:project => {:has_issues => false}} # switch off issues
|
||||
can :read, PullRequest, :to_project => {:owner_type => 'User', :owner_id => user.id}
|
||||
can :read, PullRequest, :to_project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can(:read, PullRequest, read_relations_for('pull_requests', 'to_projects')) {|pull| can? :read, pull.to_project rescue nil}
|
||||
can :create, PullRequest
|
||||
can([:update, :merge], PullRequest) {|pull| pull.user_id == user.id or local_admin?(pull.to_project)}
|
||||
|
||||
can([:create, :new_line], Comment) {|comment| can? :read, comment.project}
|
||||
can([:update, :destroy], Comment) {|comment| comment.user == user or comment.project.owner == user or local_admin?(comment.project)}
|
||||
cannot :manage, Comment do |c|
|
||||
c.commentable_type == 'Issue' && !c.project.has_issues && !c.commentable.pull_request # when switch off issues
|
||||
end
|
||||
end
|
||||
|
||||
# Shared cannot rights for all users (registered, admin)
|
||||
|
|
|
@ -71,6 +71,8 @@ class ActivityFeedObserver < ActiveRecord::Observer
|
|||
|
||||
when 'GitHook'
|
||||
return unless record.project
|
||||
PullRequest.where("from_project_id = ? OR to_project_id = ?", record.project, record.project).needed_checking.each {|pull| pull.check}
|
||||
|
||||
change_type = record.change_type
|
||||
branch_name = record.refname.split('/').last
|
||||
|
||||
|
|
|
@ -21,6 +21,32 @@ class Advisory < ActiveRecord::Base
|
|||
advisory_id
|
||||
end
|
||||
|
||||
def attach_build_list(build_list)
|
||||
return false if update_type != build_list.update_type
|
||||
self.platforms << build_list.save_to_platform unless platforms.include? build_list.save_to_platform
|
||||
self.projects << build_list.project unless projects.include? build_list.project
|
||||
build_list.advisory = self
|
||||
save
|
||||
end
|
||||
|
||||
# this method fetches and structurize packages attached to current advisory.
|
||||
def fetch_packages_info
|
||||
packages_info = Hash.new { |h, k| h[k] = {} } # maaagic, it's maaagic ;)
|
||||
build_lists.find_in_batches(:include => [:save_to_platform, :packages, :project]) do |batch|
|
||||
batch.each do |build_list|
|
||||
tmp = build_list.packages.inject({:srpm => nil, :rpm => []}) do |h, p|
|
||||
p.package_type == 'binary' ? h[:rpm] << p.fullname : h[:srpm] = p.fullname
|
||||
h
|
||||
end
|
||||
h = { build_list.project => tmp }
|
||||
packages_info[build_list.save_to_platform].merge!(h) do |pr, old, new|
|
||||
{:srpm => new[:srpm], :rpm => old[:rpm].concat(new[:rpm]).uniq}
|
||||
end
|
||||
end
|
||||
end
|
||||
packages_info
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def generate_advisory_id
|
||||
|
@ -38,4 +64,4 @@ class Advisory < ActiveRecord::Base
|
|||
end
|
||||
|
||||
end
|
||||
Advisory.include_root_in_json = false
|
||||
Advisory.include_root_in_json = false
|
|
@ -0,0 +1,17 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Avatar < ActiveRecord::Base
|
||||
self.abstract_class = true
|
||||
|
||||
MAX_AVATAR_SIZE = 5.megabyte
|
||||
|
||||
has_attached_file :avatar, :styles =>
|
||||
{ :micro => { :geometry => "16x16#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:small => { :geometry => "30x30#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:medium => { :geometry => "40x40#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:big => { :geometry => "81x81#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'}
|
||||
}
|
||||
validates_inclusion_of :avatar_file_size, :in => (0..MAX_AVATAR_SIZE), :allow_nil => true
|
||||
|
||||
attr_accessible :avatar
|
||||
|
||||
end
|
|
@ -27,8 +27,18 @@ class BuildList < ActiveRecord::Base
|
|||
validate lambda {
|
||||
errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_repository')) unless save_to_repository_id.in? save_to_platform.repositories.map(&:id)
|
||||
}
|
||||
validate lambda {
|
||||
include_repos.each {|ir|
|
||||
errors.add(:save_to_repository, I18n.t('flash.build_list.wrong_include_repos')) unless build_for_platform.repository_ids.include? ir.to_i
|
||||
}
|
||||
}
|
||||
validate lambda {
|
||||
if commit_hash.blank? || project.repo.commit(commit_hash).blank?
|
||||
errors.add :commit_hash, I18n.t('flash.build_list.wrong_commit_hash', :commit_hash => commit_hash)
|
||||
end
|
||||
}
|
||||
|
||||
LIVE_TIME = 4.week # for unpublished
|
||||
LIVE_TIME = 4.week # for unpublished
|
||||
MAX_LIVE_TIME = 3.month # for published
|
||||
|
||||
# The kernel does not send these statuses directly
|
||||
|
@ -105,6 +115,7 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
after_commit :place_build
|
||||
after_destroy :delete_container
|
||||
before_validation :set_commit_and_version
|
||||
|
||||
@queue = :clone_and_build
|
||||
|
||||
|
@ -127,6 +138,10 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
after_transition :on => :published, :do => [:set_version_and_tag, :actualize_packages]
|
||||
|
||||
after_transition :on => [:published, :fail_publish, :build_error], :do => :notify_users
|
||||
after_transition :on => :build_success, :do => :notify_users,
|
||||
:unless => lambda { |build_list| build_list.auto_publish? }
|
||||
|
||||
event :place_build do
|
||||
transition :waiting_for_response => :build_pending, :if => lambda { |build_list|
|
||||
build_list.add_to_queue == BuildServer::SUCCESS
|
||||
|
@ -195,7 +210,7 @@ class BuildList < ActiveRecord::Base
|
|||
def set_version_and_tag
|
||||
pkg = self.packages.where(:package_type => 'source', :project_id => self.project_id).first
|
||||
# TODO: remove 'return' after deployment ABF kernel 2.0
|
||||
return if pkg.nil? # For old client that does not sends data about packages
|
||||
return if pkg.nil? # For old client that does not sends data about packages
|
||||
self.package_version = "#{pkg.platform.name}-#{pkg.version}-#{pkg.release}"
|
||||
system("cd #{self.project.repo.path} && git tag #{self.package_version} #{self.commit_hash}") # TODO REDO through grit
|
||||
save
|
||||
|
@ -284,12 +299,40 @@ class BuildList < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def in_work?
|
||||
status == BuildServer::BUILD_STARTED
|
||||
status == BuildServer::BUILD_STARTED
|
||||
#[WAITING_FOR_RESPONSE, BuildServer::BUILD_PENDING, BuildServer::BUILD_STARTED].include?(status)
|
||||
end
|
||||
|
||||
def associate_and_create_advisory(params)
|
||||
build_advisory(params){ |a| a.update_type = update_type }
|
||||
advisory.attach_build_list(self)
|
||||
end
|
||||
|
||||
def can_attach_to_advisory?
|
||||
!save_to_repository.publish_without_qa &&
|
||||
save_to_platform.main? &&
|
||||
save_to_platform.released &&
|
||||
status == BUILD_PUBLISHED
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def notify_users
|
||||
unless mass_build_id
|
||||
users = []
|
||||
if project # find associated users
|
||||
users = project.all_members.
|
||||
select{ |user| user.notifier.can_notify? && user.notifier.new_associated_build? }
|
||||
end
|
||||
if user.notifier.can_notify? && user.notifier.new_build?
|
||||
users = users | [user]
|
||||
end
|
||||
users.each do |user|
|
||||
UserMailer.build_list_notification(self, user).deliver
|
||||
end
|
||||
end
|
||||
end # notify_users
|
||||
|
||||
def delete_container
|
||||
if can_cancel?
|
||||
BuildServer.delete_build_list bs_id
|
||||
|
@ -306,4 +349,13 @@ class BuildList < ActiveRecord::Base
|
|||
yield p
|
||||
end
|
||||
end
|
||||
|
||||
def set_commit_and_version
|
||||
if project_version.present? && commit_hash.blank?
|
||||
self.commit_hash = project.repo.commits(project_version.match(/^latest_(.+)/).to_a.last ||
|
||||
project_version).try(:first).try(:id)
|
||||
elsif project_version.blank? && commit_hash.present?
|
||||
self.project_version = commit_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,7 +68,9 @@ class BuildList::Filter
|
|||
end
|
||||
|
||||
def build_date_from_params(field_name, params)
|
||||
if params["#{field_name}(1i)"].present? || params["#{field_name}(2i)"].present? || params["#{field_name}(3i)"].present?
|
||||
if params[field_name].present?
|
||||
Time.at(params[field_name].to_i)
|
||||
elsif params["#{field_name}(1i)"].present? || params["#{field_name}(2i)"].present? || params["#{field_name}(3i)"].present?
|
||||
Date.civil((params["#{field_name}(1i)"].presence || Date.today.year).to_i,
|
||||
(params["#{field_name}(2i)"].presence || Date.today.month).to_i,
|
||||
(params["#{field_name}(3i)"].presence || Date.today.day).to_i)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
class BuildListObserver < ActiveRecord::Observer
|
||||
PUBLICATION_STATUSES = [BuildList::BUILD_PUBLISHED, BuildList::FAILED_PUBLISH]
|
||||
STATUSES = [BuildServer::BUILD_ERROR, BuildServer::SUCCESS] + PUBLICATION_STATUSES
|
||||
|
||||
observe :build_list
|
||||
|
||||
def before_update(record)
|
||||
|
@ -18,28 +15,7 @@ class BuildListObserver < ActiveRecord::Observer
|
|||
record.project.update_attributes({ :average_build_time => new_av_time, :build_count => build_count + 1 }, :without_protection => true)
|
||||
end
|
||||
end
|
||||
BuildListObserver.notify_users(record)
|
||||
end
|
||||
end # before_update
|
||||
|
||||
private
|
||||
|
||||
def self.notify_users(build_list)
|
||||
if !build_list.mass_build_id &&
|
||||
( (build_list.auto_publish? && PUBLICATION_STATUSES.include?(build_list.status)) ||
|
||||
(!build_list.auto_publish? && STATUSES.include?(build_list.status)) )
|
||||
|
||||
users = []
|
||||
if build_list.project # find associated users
|
||||
users = build_list.project.all_members.
|
||||
select{ |user| user.notifier.can_notify? && user.notifier.new_associated_build? }
|
||||
end
|
||||
if build_list.user.notifier.can_notify? && build_list.user.notifier.new_build?
|
||||
users = users | [build_list.user]
|
||||
end
|
||||
users.each do |user|
|
||||
UserMailer.build_list_notification(build_list, user).deliver
|
||||
end
|
||||
end
|
||||
end # notify_users
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ class Comment < ActiveRecord::Base
|
|||
belongs_to :commentable, :polymorphic => true
|
||||
belongs_to :user
|
||||
belongs_to :project
|
||||
serialize :data
|
||||
|
||||
validates :body, :user_id, :commentable_id, :commentable_type, :project_id, :presence => true
|
||||
|
||||
|
@ -12,7 +13,7 @@ class Comment < ActiveRecord::Base
|
|||
after_create :subscribe_on_reply, :unless => lambda {|c| c.commit_comment?}
|
||||
after_create :subscribe_users
|
||||
|
||||
attr_accessible :body
|
||||
attr_accessible :body, :data
|
||||
|
||||
def commentable
|
||||
# raise commentable_id.inspect
|
||||
|
@ -53,6 +54,80 @@ class Comment < ActiveRecord::Base
|
|||
User.find(subscribe.user).notifier.new_comment && User.find(subscribe.user).notifier.can_notify
|
||||
end
|
||||
|
||||
def actual_inline_comment?(diff = nil, force = false)
|
||||
unless force
|
||||
raise "This is not inline comment!" if data.blank? # for debug
|
||||
return data[:actual] unless data[:actual].nil?
|
||||
return false if diff.nil?
|
||||
end
|
||||
filepath, line_number = data[:path], data[:line]
|
||||
diff_path = (diff || commentable.diffs ).select {|d| d.a_path == data[:path]}
|
||||
comment_line = data[:line].to_i
|
||||
# NB! also dont create a comment to the diff header
|
||||
return data[:actual] = false if diff_path.blank? || comment_line == 0
|
||||
return data[:actual] = true if commentable_type == 'Grit::Commit'
|
||||
res, ind = true, 0
|
||||
diff_path[0].diff.each_line do |line|
|
||||
if self.persisted? && (comment_line-2..comment_line+2).include?(ind) && data.try('[]', "line#{ind-comment_line}") != line.chomp
|
||||
break res = false
|
||||
end
|
||||
ind = ind + 1
|
||||
end
|
||||
if ind < comment_line
|
||||
return data[:actual] = false
|
||||
else
|
||||
return data[:actual] = res
|
||||
end
|
||||
end
|
||||
|
||||
def inline_diff
|
||||
data[:strings] + data['line0']
|
||||
end
|
||||
|
||||
def pull_comment?
|
||||
return true if commentable.is_a?(Issue) && commentable.pull_request.present?
|
||||
end
|
||||
|
||||
def set_additional_data params
|
||||
return true if params[:path].blank? && params[:line].blank? # not inline comment
|
||||
if params[:in_reply].present? && reply = Comment.where(:id => params[:in_reply]).first
|
||||
self.data = reply.data
|
||||
return true
|
||||
end
|
||||
self.data = {:path => params[:path], :line => params[:line]}
|
||||
if commentable.is_a?(Issue) && pull = commentable.pull_request
|
||||
diff_path = pull.diff.select {|d| d.a_path == params[:path]}
|
||||
return false unless actual_inline_comment?(pull.diff, true)
|
||||
|
||||
comment_line, line_number, strings = params[:line].to_i, -1, []
|
||||
diff_path[0].diff.each_line do |line|
|
||||
line_number = line_number.succ
|
||||
# Save 2 lines above and bottom of the diff comment line
|
||||
break if line_number > comment_line + 2
|
||||
if (comment_line-2..comment_line+2).include? line_number
|
||||
data["line#{line_number-comment_line}"] = line.chomp
|
||||
end
|
||||
|
||||
# Save lines from the closest header for rendering in the discussion
|
||||
if line_number < comment_line
|
||||
# Header is the line like "@@ -47,9 +50,8 @@ def initialize(user)"
|
||||
if line =~ Diff::Display::Unified::Generator::LINE_NUM_RE
|
||||
strings = [line]
|
||||
else
|
||||
strings << line
|
||||
end
|
||||
end
|
||||
end
|
||||
## Bug with numbers of diff lines, now store all diff
|
||||
data[:strings] = strings.join
|
||||
# Limit stored diff to 10 lines (see inline_diff)
|
||||
#data[:strings] = ((strings.count) <= 9 ? strings : [strings[0]] + strings.last(8)).join
|
||||
##
|
||||
data[:view_path] = h(diff_path[0].renamed_file ? "#{diff_path[0].a_path.rtruncate 60} -> #{diff_path[0].b_path.rtruncate 60}" : diff_path[0].a_path.rtruncate(120))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def subscribe_on_reply
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Group < ActiveRecord::Base
|
||||
class Group < Avatar
|
||||
belongs_to :owner, :class_name => 'User'
|
||||
|
||||
has_many :relations, :as => :actor, :dependent => :destroy, :dependent => :destroy
|
||||
|
@ -39,6 +39,14 @@ class Group < ActiveRecord::Base
|
|||
uname
|
||||
end
|
||||
|
||||
def add_member(member, role = 'admin')
|
||||
Relation.add_member(member, self, role, :actors)
|
||||
end
|
||||
|
||||
def remove_member(member)
|
||||
Relation.remove_member(member, self)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def add_owner_to_members
|
||||
|
|
|
@ -11,6 +11,7 @@ class Issue < ActiveRecord::Base
|
|||
has_many :subscribes, :as => :subscribeable, :dependent => :destroy
|
||||
has_many :labelings, :dependent => :destroy
|
||||
has_many :labels, :through => :labelings, :uniq => true
|
||||
has_one :pull_request, :dependent => :destroy
|
||||
|
||||
validates :title, :body, :project_id, :presence => true
|
||||
|
||||
|
@ -21,8 +22,16 @@ class Issue < ActiveRecord::Base
|
|||
attr_accessible :labelings_attributes, :title, :body, :assignee_id
|
||||
accepts_nested_attributes_for :labelings, :allow_destroy => true
|
||||
|
||||
scope :opened, where(:status => 'open', :closed_by => nil, :closed_at => nil)
|
||||
scope :closed, where(:status => 'closed').where("closed_by is not null and closed_at is not null")
|
||||
scope :opened, where(:status => 'open')
|
||||
scope :closed, where(:status => 'closed')
|
||||
|
||||
scope :needed_checking, where(:issues => {:status => ['open', 'blocked', 'ready', 'already']})
|
||||
scope :not_closed_or_merged, needed_checking
|
||||
scope :closed_or_merged, where(:issues => {:status => ['closed', 'merged']})
|
||||
# Using mb_chars for correct transform to lowercase ('Русский Текст'.downcase => "Русский Текст")
|
||||
scope :search, lambda {|q| where('issues.title ILIKE ?', "%#{q.mb_chars.downcase}%") if q.present?}
|
||||
scope :def_order, order('issues.serial_id desc')
|
||||
scope :without_pull_requests, where('NOT EXISTS (select null from pull_requests as pr where pr.issue_id = issues.id)')
|
||||
|
||||
def assign_uname
|
||||
assignee.uname if assignee
|
||||
|
@ -43,7 +52,7 @@ class Issue < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def set_close(closed_by)
|
||||
self.closed_at = Time.now
|
||||
self.closed_at = Time.now.utc
|
||||
self.closer = closed_by
|
||||
self.status = 'closed'
|
||||
end
|
||||
|
|
|
@ -20,9 +20,15 @@ class Platform < ActiveRecord::Base
|
|||
has_many :mass_builds
|
||||
|
||||
validates :description, :presence => true
|
||||
validates :owner, :presence => true
|
||||
validates :visibility, :presence => true, :inclusion => {:in => VISIBILITIES}
|
||||
validates :name, :uniqueness => {:case_sensitive => false}, :presence => true, :format => { :with => /^[a-zA-Z0-9_\-\.]+$/ }
|
||||
validates :distrib_type, :presence => true, :inclusion => {:in => APP_CONFIG['distr_types']}
|
||||
validate lambda {
|
||||
if released_was && !released
|
||||
errors.add(:released, I18n.t('flash.platform.released_status_can_not_be_changed'))
|
||||
end
|
||||
}
|
||||
|
||||
before_create :create_directory, :if => lambda {Thread.current[:skip]} # TODO remove this when core will be ready
|
||||
before_create :xml_rpc_create, :unless => lambda {Thread.current[:skip]}
|
||||
|
@ -39,8 +45,9 @@ class Platform < ActiveRecord::Base
|
|||
scope :by_visibilities, lambda {|v| where(:visibility => v)}
|
||||
scope :opened, where(:visibility => 'open')
|
||||
scope :hidden, where(:visibility => 'hidden')
|
||||
scope :main, where(:platform_type => 'main')
|
||||
scope :personal, where(:platform_type => 'personal')
|
||||
scope :by_type, lambda {|type| where(:platform_type => type) if type.present?}
|
||||
scope :main, by_type('main')
|
||||
scope :personal, by_type('personal')
|
||||
|
||||
attr_accessible :name, :distrib_type, :parent_platform_id, :platform_type, :owner, :visibility, :description, :released
|
||||
attr_readonly :name, :distrib_type, :parent_platform_id, :platform_type
|
||||
|
@ -166,7 +173,7 @@ class Platform < ActiveRecord::Base
|
|||
|
||||
def update_owner_relation
|
||||
if owner_id_was != owner_id
|
||||
r = relations.where(:actor_id => owner_id_was, :actor_type => owner_type_was)[0]
|
||||
r = relations.where(:actor_id => owner_id_was, :actor_type => owner_type_was).first
|
||||
r.update_attributes(:actor_id => owner_id, :actor_type => owner_type)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@ class Project < ActiveRecord::Base
|
|||
belongs_to :maintainer, :class_name => "User"
|
||||
|
||||
has_many :issues, :dependent => :destroy
|
||||
has_many :pull_requests, :dependent => :destroy, :foreign_key => 'to_project_id'
|
||||
has_many :labels, :dependent => :destroy
|
||||
has_many :build_lists, :dependent => :destroy
|
||||
|
||||
|
@ -36,7 +37,7 @@ class Project < ActiveRecord::Base
|
|||
scope :recent, order("name ASC")
|
||||
scope :search_order, order("CHAR_LENGTH(name) ASC")
|
||||
scope :search, lambda {|q| by_name("%#{q.to_s.strip}%")}
|
||||
scope :by_name, lambda {|name| where('projects.name ILIKE ?', name)}
|
||||
scope :by_name, lambda {|name| where('projects.name ILIKE ?', name) if name.present?}
|
||||
scope :by_visibilities, lambda {|v| where(:visibility => v)}
|
||||
scope :opened, where(:visibility => 'open')
|
||||
scope :package, where(:is_package => true)
|
||||
|
@ -49,7 +50,11 @@ class Project < ActiveRecord::Base
|
|||
WHERE (ptr.repository_id = #{ repository_id })
|
||||
)
|
||||
) }
|
||||
scope :by_owners, lambda { |group_owner_ids, user_owner_ids|
|
||||
where("(projects.owner_id in (?) AND projects.owner_type = 'Group') OR (projects.owner_id in (?) AND projects.owner_type = 'User')", group_owner_ids, user_owner_ids)
|
||||
}
|
||||
|
||||
before_validation :truncate_name, :on => :create
|
||||
before_create :set_maintainer
|
||||
after_save :attach_to_personal_repository
|
||||
|
||||
|
@ -84,6 +89,14 @@ class Project < ActiveRecord::Base
|
|||
collaborators | groups.map(&:members).flatten
|
||||
end
|
||||
|
||||
def add_member(member, role = 'admin')
|
||||
Relation.add_member(member, self, role)
|
||||
end
|
||||
|
||||
def remove_member(member)
|
||||
Relation.remove_member(member, self)
|
||||
end
|
||||
|
||||
def platforms
|
||||
@platforms ||= repositories.map(&:platform).uniq
|
||||
end
|
||||
|
@ -172,6 +185,10 @@ class Project < ActiveRecord::Base
|
|||
|
||||
protected
|
||||
|
||||
def truncate_name
|
||||
self.name = name.strip if name
|
||||
end
|
||||
|
||||
def attach_to_personal_repository
|
||||
owner_rep = self.owner.personal_repository
|
||||
if is_package
|
||||
|
@ -182,7 +199,9 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def set_maintainer
|
||||
self.maintainer_id = (owner_type == 'User') ? self.owner_id : self.owner.owner_id
|
||||
if maintainer_id.blank?
|
||||
self.maintainer_id = (owner_type == 'User') ? self.owner_id : self.owner.owner_id
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
class PullRequest < ActiveRecord::Base
|
||||
STATUSES = %w(ready already blocked merged closed)
|
||||
belongs_to :issue, :autosave => true, :dependent => :destroy, :touch => true, :validate => true
|
||||
belongs_to :to_project, :class_name => 'Project', :foreign_key => 'to_project_id'
|
||||
belongs_to :from_project, :class_name => 'Project', :foreign_key => 'from_project_id'
|
||||
delegate :user, :user_id, :title, :body, :serial_id, :assignee, :status, :to_param,
|
||||
:created_at, :updated_at, :comments, :status=, :to => :issue, :allow_nil => true
|
||||
|
||||
validate :uniq_merge
|
||||
validates_each :from_ref, :to_ref do |record, attr, value|
|
||||
check_ref record, attr, value
|
||||
end
|
||||
|
||||
before_create :clean_dir
|
||||
after_destroy :clean_dir
|
||||
|
||||
accepts_nested_attributes_for :issue
|
||||
attr_accessible :issue_attributes, :to_ref, :from_ref
|
||||
|
||||
scope :needed_checking, includes(:issue).where(:issues => {:status => ['open', 'blocked', 'ready']})
|
||||
|
||||
state_machine :status, :initial => :open do
|
||||
event :ready do
|
||||
transition [:ready, :open, :blocked] => :ready
|
||||
end
|
||||
|
||||
event :already do
|
||||
transition [:ready, :open, :blocked] => :already
|
||||
end
|
||||
|
||||
event :block do
|
||||
transition [:ready, :open, :blocked] => :blocked
|
||||
end
|
||||
|
||||
event :merging do
|
||||
transition :ready => :merged
|
||||
end
|
||||
|
||||
event :close do
|
||||
transition [:ready, :open, :blocked] => :closed
|
||||
end
|
||||
|
||||
event :reopen do
|
||||
transition :closed => :open
|
||||
end
|
||||
end
|
||||
|
||||
def check(do_transaction = true)
|
||||
res = merge
|
||||
new_status = case res
|
||||
when /Already up-to-date/
|
||||
'already'
|
||||
when /Merge made by/
|
||||
system("cd #{path} && git reset --hard HEAD^") # remove merge commit
|
||||
'ready'
|
||||
when /Automatic merge failed/
|
||||
system("cd #{path} && git reset --hard HEAD") # clean git index
|
||||
'block'
|
||||
else
|
||||
raise res
|
||||
end
|
||||
|
||||
if do_transaction
|
||||
new_status == 'already' ? (ready; merging) : send(new_status)
|
||||
self.update_inline_comments
|
||||
else
|
||||
self.status = new_status == 'block' ? 'blocked' : new_status
|
||||
end
|
||||
end
|
||||
|
||||
def merge!(who)
|
||||
return false unless can_merging?
|
||||
Dir.chdir(path) do
|
||||
system "git config user.name \"#{who.uname}\" && git config user.email \"#{who.email}\""
|
||||
if merge
|
||||
system("git push origin HEAD")
|
||||
system("git reset --hard HEAD^") # for diff maybe FIXME
|
||||
set_user_and_time who
|
||||
merging
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def path
|
||||
filename = [id, from_project.owner.uname, from_project.name].compact.join('-')
|
||||
File.join(APP_CONFIG['root_path'], 'pull_requests', to_project.owner.uname, to_project.name, filename)
|
||||
end
|
||||
|
||||
def from_branch
|
||||
if to_project != from_project
|
||||
"head_#{from_ref}"
|
||||
else
|
||||
from_ref
|
||||
end
|
||||
end
|
||||
|
||||
def common_ancestor
|
||||
return @common_ancestor if @common_ancestor
|
||||
base_commit = repo.commits(to_ref).first
|
||||
@common_ancestor = repo.commit(repo.git.merge_base({}, base_commit, from_commit)) || base_commit
|
||||
end
|
||||
alias_method :to_commit, :common_ancestor
|
||||
|
||||
def diff_stats
|
||||
stats = []
|
||||
Dir.chdir(path) do
|
||||
lines = repo.git.native(:diff, {:numstat => true, :M => true}, "#{to_commit.id}...#{from_commit.id}").split("\n")
|
||||
while !lines.empty?
|
||||
files = []
|
||||
while lines.first =~ /^([-\d]+)\s+([-\d]+)\s+(.+)/
|
||||
additions, deletions, filename = lines.shift.gsub(' => ', '=>').split
|
||||
additions, deletions = additions.to_i, deletions.to_i
|
||||
stat = Grit::DiffStat.new filename, additions, deletions
|
||||
stats << stat
|
||||
end
|
||||
end
|
||||
stats
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME maybe move to warpc/grit?
|
||||
def diff
|
||||
return @diff if @diff.present?
|
||||
diff = repo.git.native('diff', {:M => true}, "#{to_commit.id}...#{from_commit.id}")
|
||||
|
||||
if diff =~ /diff --git a/
|
||||
diff = diff.sub(/.*?(diff --git a)/m, '\1')
|
||||
else
|
||||
diff = ''
|
||||
end
|
||||
@diff = Grit::Diff.list_from_string(repo, diff)
|
||||
end
|
||||
|
||||
def set_user_and_time user
|
||||
issue.closed_at = Time.now.utc
|
||||
issue.closer = user
|
||||
end
|
||||
|
||||
def self.check_ref(record, attr, value)
|
||||
project = attr == :from_ref ? record.from_project : record.to_project
|
||||
record.errors.add attr, I18n.t('projects.pull_requests.wrong_ref') unless project.repo.branches_and_tags.map(&:name).include?(value)
|
||||
end
|
||||
|
||||
def uniq_merge
|
||||
if to_project.pull_requests.needed_checking.where(:from_project_id => from_project, :to_ref => to_ref, :from_ref => from_ref).where('pull_requests.id <> :id or :id is null', :id => id).count > 0
|
||||
errors.add(:base_branch, I18n.t('projects.pull_requests.duplicate', :from_ref => from_ref))
|
||||
end
|
||||
end
|
||||
|
||||
def repo
|
||||
return @repo if @repo.present? #&& !id_changed?
|
||||
@repo = Grit::Repo.new path
|
||||
end
|
||||
|
||||
def from_commit
|
||||
repo.commits(from_branch).first
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def merge
|
||||
clone
|
||||
message = "Merge pull request ##{serial_id} from #{from_project.name_with_owner}:#{from_ref}\r\n #{title}"
|
||||
%x(cd #{path} && git checkout #{to_ref} && git merge --no-ff #{from_branch} -m '#{message}')
|
||||
end
|
||||
|
||||
def clone
|
||||
git = Grit::Git.new(path)
|
||||
unless git.exist?
|
||||
#~ FileUtils.mkdir_p(path)
|
||||
#~ system("git clone --local --no-hardlinks #{to_project.path} #{path}")
|
||||
options = {:bare => false, :shared => false, :branch => to_ref} # shared?
|
||||
git.fs_mkdir('..')
|
||||
git.clone(options, to_project.path, path)
|
||||
if to_project != from_project
|
||||
Dir.chdir(path) do
|
||||
system 'git', 'remote', 'add', 'head', from_project.path
|
||||
end
|
||||
end
|
||||
clean # Need testing
|
||||
end
|
||||
|
||||
Dir.chdir(path) do
|
||||
system 'git', 'checkout', to_ref
|
||||
system 'git', 'pull', 'origin', to_ref
|
||||
if to_project == from_project
|
||||
system 'git', 'checkout', from_ref
|
||||
system 'git', 'pull', 'origin', from_ref
|
||||
else
|
||||
system 'git', 'fetch', 'head', "+#{from_ref}:#{from_branch}"
|
||||
end
|
||||
end
|
||||
# TODO catch errors
|
||||
end
|
||||
|
||||
def clean
|
||||
Dir.chdir(path) do
|
||||
to_project.repo.branches.each {|branch| system 'git', 'checkout', branch.name}
|
||||
system 'git', 'checkout', to_ref
|
||||
|
||||
to_project.repo.branches.each do |branch|
|
||||
system 'git', 'branch', '-D', branch.name unless [to_ref, from_branch].include? branch.name
|
||||
end
|
||||
to_project.repo.tags.each do |tag|
|
||||
system 'git', 'tag', '-d', tag.name unless [to_ref, from_branch].include? tag.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clean_dir
|
||||
FileUtils.rm_rf path
|
||||
end
|
||||
|
||||
def update_inline_comments
|
||||
self.comments.each do |c|
|
||||
if c.data.present? # maybe need add new column 'actual'?
|
||||
c.actual_inline_comment? diff, true
|
||||
c.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,17 +22,18 @@ class Relation < ActiveRecord::Base
|
|||
r.save
|
||||
end
|
||||
|
||||
def self.add_member(member, target, role)
|
||||
if target.relations.exists?(:actor_id => member.id, :actor_type => member.class.to_s) || @platform.try(:owner) == member
|
||||
def self.add_member(member, target, role, relation = :relations)
|
||||
if target.send(relation).exists?(:actor_id => member.id, :actor_type => member.class.to_s) || (target.respond_to?(:owner) && target.owner == member)
|
||||
true
|
||||
else
|
||||
rel = target.relations.build(:role => role)
|
||||
rel = target.send(relation).build(:role => role)
|
||||
rel.actor = member
|
||||
rel.save
|
||||
end
|
||||
end
|
||||
|
||||
def self.remove_member(member, target)
|
||||
return false if target.respond_to?(:owner) && target.owner == member
|
||||
Relation.by_actor(member).by_target(target).each{|r| r.destroy}
|
||||
end
|
||||
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class User < ActiveRecord::Base
|
||||
class User < Avatar
|
||||
ROLES = ['', 'admin', 'banned']
|
||||
LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']]
|
||||
LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last)
|
||||
MAX_AVATAR_SIZE = 5.megabyte
|
||||
|
||||
devise :database_authenticatable, :registerable, :omniauthable, :token_authenticatable,# :encryptable, :timeoutable
|
||||
:recoverable, :rememberable, :validatable, :lockable, :confirmable#, :reconfirmable, :trackable
|
||||
has_attached_file :avatar, :styles =>
|
||||
{ :micro => { :geometry => "16x16#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:small => { :geometry => "30x30#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:medium => { :geometry => "40x40#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'},
|
||||
:big => { :geometry => "81x81#", :format => :jpg, :convert_options => '-strip -background white -flatten -quality 70'}
|
||||
}
|
||||
validates_inclusion_of :avatar_file_size, :in => (0..MAX_AVATAR_SIZE), :allow_nil => true
|
||||
|
||||
has_one :notifier, :class_name => 'SettingsNotifier', :dependent => :destroy #:notifier
|
||||
|
||||
|
@ -43,7 +35,7 @@ class User < ActiveRecord::Base
|
|||
validates :language, :inclusion => {:in => LANGUAGES}, :allow_blank => true
|
||||
|
||||
attr_accessible :email, :password, :password_confirmation, :current_password, :remember_me, :login, :name, :uname, :language,
|
||||
:site, :company, :professional_experience, :location, :avatar
|
||||
:site, :company, :professional_experience, :location
|
||||
attr_readonly :uname
|
||||
attr_accessor :login
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class CommentPresenter < ApplicationPresenter
|
|||
@user = comment.user
|
||||
@options = opts
|
||||
|
||||
@content = simple_format(@comment.body, {}, :sanitize => true).html_safe
|
||||
@content = @comment.body
|
||||
end
|
||||
|
||||
def expandable?
|
||||
|
@ -27,23 +27,17 @@ class CommentPresenter < ApplicationPresenter
|
|||
def caption?
|
||||
false
|
||||
end
|
||||
def buttons
|
||||
project = options[:project]
|
||||
commentable = options[:commentable]
|
||||
(ep, dp) = if Comment.issue_comment?(commentable.class)
|
||||
[edit_project_issue_comment_path(project, commentable, comment),
|
||||
project_issue_comment_path(project, commentable, comment)]
|
||||
elsif Comment.commit_comment?(commentable.class)
|
||||
[edit_project_commit_comment_path(project, commentable, comment),
|
||||
project_commit_comment_path(project, commentable, comment)]
|
||||
end
|
||||
|
||||
res = []
|
||||
def buttons
|
||||
project, commentable = options[:project], options[:commentable]
|
||||
path = helpers.project_commentable_comment_path(project, commentable, comment)
|
||||
|
||||
res = [link_to(t("layout.link"), "#{helpers.project_commentable_path(project, commentable)}##{comment_anchor}", :class => "#{@options[:in_discussion].present? ? 'in_discussion_' : ''}link_to_comment").html_safe]
|
||||
if controller.can? :update, @comment
|
||||
res << link_to(t("layout.edit"), ep).html_safe
|
||||
res << link_to(t("layout.edit"), path, :id => "comment-#{comment.id}", :class => "edit_comment").html_safe
|
||||
end
|
||||
if controller.can? :delete, @comment
|
||||
res << link_to(t("layout.delete"), dp, :method => "delete",
|
||||
if controller.can? :destroy, @comment
|
||||
res << link_to(t("layout.delete"), path, :method => "delete",
|
||||
:confirm => t("layout.comments.confirm_delete")).html_safe
|
||||
end
|
||||
res
|
||||
|
@ -69,4 +63,15 @@ class CommentPresenter < ApplicationPresenter
|
|||
def comment_id
|
||||
@comment.id
|
||||
end
|
||||
|
||||
def comment_anchor
|
||||
# check for pull diff inline comment
|
||||
before = if @options[:add_anchor].present? && !@options[:in_discussion]
|
||||
'diff-'
|
||||
else
|
||||
''
|
||||
end
|
||||
"#{before}comment#{@comment.id}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
- else
|
||||
= image_tag("lock.png")
|
||||
%td
|
||||
= link_to "#{project.owner.uname}/#{project.name}", project_path(project)
|
||||
= link_to project.name_with_owner, project_path(project)
|
||||
%tr
|
||||
%td
|
||||
\
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.text
|
||||
%span
|
||||
= raw t("notifications.bodies.new_comment_notification.title", :user_link => link_to(user_name, user_path(user_id)) )
|
||||
= raw t("notifications.bodies.new_comment_notification.commit_content", {:commit_link => link_to(commit_message, commit_path(project_owner, project_name, commit_id) + "#comment##{comment_id}")})
|
||||
= raw t("notifications.bodies.new_comment_notification.commit_content", {:commit_link => link_to(commit_message, commit_path(project_owner, project_name, commit_id) + "#comment#{comment_id}")})
|
||||
= raw t("notifications.bodies.project", :project_link => link_to("#{project_owner}/#{project_name}", project_path(project_owner, project_name)) )
|
||||
.both
|
||||
%span.date= activity_feed.created_at
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.text
|
||||
%span
|
||||
= raw t("notifications.bodies.new_comment_notification.title", {:user_link => link_to(user_name, user_path(user_id))})
|
||||
= raw t("notifications.bodies.new_comment_notification.content", {:issue_link => link_to(issue_title, project_issue_path(project_owner, project_name, issue_serial_id) + "#comment##{comment_id}")})
|
||||
= raw t("notifications.bodies.new_comment_notification.content", {:issue_link => link_to(issue_title, project_issue_path(project_owner, project_name, issue_serial_id) + "#comment#{comment_id}")})
|
||||
= raw t("notifications.bodies.project", :project_link => link_to("#{project_owner}/#{project_name}", project_path(project_owner, project_name)) )
|
||||
.both
|
||||
%span.date= activity_feed.created_at
|
||||
|
|
|
@ -24,9 +24,14 @@
|
|||
%td= request.more
|
||||
%td= request.created_at
|
||||
%td
|
||||
= link_to t("layout.approve"), approve_admin_register_request_path(request) if can? :approve, request
|
||||
|
|
||||
= link_to t("layout.reject"), reject_admin_register_request_path(request) if can? :reject, request
|
||||
- links = []
|
||||
- if can? :approve, request
|
||||
- links << link_to(t("layout.approve"), approve_admin_register_request_path(request))
|
||||
- if can? :reject, request
|
||||
- links << link_to(t("layout.reject"), reject_admin_register_request_path(request))
|
||||
- if request.token
|
||||
- links << link_to('Link', new_user_registration_url(:invitation_token => request.token))
|
||||
= raw links.join('|')
|
||||
|
||||
.actions
|
||||
%input#approve_registration{:type => 'button', :value => "Approve Selected"}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
json.id advisory.advisory_id
|
||||
json.(advisory, :description)
|
||||
json.platforms advisory.platforms do |json_platform, platform|
|
||||
json_platform.(platform, :id, :released)
|
||||
json_platform.url api_v1_platform_path(platform.id, :format => :json)
|
||||
end
|
||||
json.projects advisory.projects do |json_project, project|
|
||||
json_project.(project, :id, :name)
|
||||
json_project.fullname project.name_with_owner
|
||||
json_project.url api_v1_project_path(project.id, :format => :json)
|
||||
end
|
||||
json.url api_v1_advisory_path(advisory.advisory_id, :format => :json)
|
|
@ -0,0 +1,4 @@
|
|||
json.advisories @advisories do |json, advisory|
|
||||
json.partial! 'advisory', :advisory => advisory, :json => json
|
||||
end
|
||||
json.url api_v1_advisories_path(:format => :json)
|
|
@ -0,0 +1,27 @@
|
|||
json.advisory do |json|
|
||||
json.partial! 'advisory', :advisory => @advisory, :json => json
|
||||
json.created_at @advisory.created_at.to_i
|
||||
json.updated_at @advisory.updated_at.to_i
|
||||
json.(@advisory, :update_type)
|
||||
json.references @advisory.references.split('\n')
|
||||
|
||||
json.build_lists @advisory.build_lists do |json_build_list, build_list|
|
||||
json_build_list.(build_list, :id)
|
||||
json_build_list.url api_v1_build_list_path(build_list.id, :format => :json)
|
||||
end
|
||||
|
||||
json.affected_in @packages_info do |json_platform, package_info|
|
||||
json.partial! 'api/v1/platforms/platform',
|
||||
:platform => package_info[0], :json => json_platform
|
||||
|
||||
json_platform.projects package_info[1] do |json_project, info|
|
||||
json.partial! 'api/v1/projects/project',
|
||||
:project => info[0], :json => json_project
|
||||
|
||||
packages = info[1]
|
||||
json_project.srpm packages[:srpm]
|
||||
json_project.rpm packages[:rpm]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
json.architectures @arches do |json, arch|
|
||||
json.(arch, :id, :name)
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
json.build_lists @build_lists do |json, build_list|
|
||||
json.(build_list, :id, :name, :status)
|
||||
json.url api_v1_build_list_path(build_list, :format => :json)
|
||||
end
|
||||
|
||||
json.url api_v1_build_lists_path(:format => :json, :params => {:filter => params[:filter] } )
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
json.build_list do |json|
|
||||
json.(@build_list, :id, :name, :container_path, :status, :duration)
|
||||
json.(@build_list, :is_circle, :update_type, :build_requires, :priority)
|
||||
json.(@build_list, :advisory, :mass_build)
|
||||
json.(@build_list, :auto_publish, :package_version, :commit_hash)
|
||||
json.build_log_url log_build_list_path(@build_list)
|
||||
|
||||
json.arch do |json_arch|
|
||||
json_arch.(@build_list.arch, :id, :name)
|
||||
end
|
||||
json.created_at @build_list.created_at.to_i
|
||||
json.updated_at @build_list.updated_at.to_i
|
||||
|
||||
json.project do |json_project|
|
||||
json.partial! 'api/v1/projects/project',
|
||||
:project => @build_list.project, :json => json_project
|
||||
end
|
||||
|
||||
json.save_to_repository do |json_save_to_repository|
|
||||
json.partial! 'api/v1/repositories/repository',
|
||||
:repository => @build_list.save_to_repository,
|
||||
:json => json_save_to_repository
|
||||
|
||||
json_save_to_repository.platform do |json_str_platform|
|
||||
json.partial! 'api/v1/platforms/platform',
|
||||
:platform => @build_list.save_to_repository.platform,
|
||||
:json => json_str_platform
|
||||
end
|
||||
end
|
||||
|
||||
json.build_for_platform do |json_build_for_platform|
|
||||
json.partial! 'api/v1/platforms/platform',
|
||||
:platform => @build_list.build_for_platform,
|
||||
:json => json_build_for_platform
|
||||
end
|
||||
|
||||
json.partial! 'api/v1/shared/owner', :owner => @build_list.project.owner
|
||||
|
||||
inc_repos = Repository.includes(:platform).where(:id => @build_list.include_repos)
|
||||
json.include_repos inc_repos do |json_include_repos, repo|
|
||||
json.partial! 'api/v1/repositories/repository',
|
||||
:repository => repo,
|
||||
:json => json_include_repos
|
||||
|
||||
json_include_repos.platform do |json_str_platform|
|
||||
json.partial! 'api/v1/platforms/platform',
|
||||
:platform => repo.platform,
|
||||
:json => json_str_platform
|
||||
end
|
||||
end
|
||||
|
||||
json.advisory do |json_advisory|
|
||||
json_advisory.name @build_list.advisory.advisory_id
|
||||
json_advisory.(@build_list.advisory, :description)
|
||||
end if @build_list.advisory
|
||||
|
||||
json.mass_build do |json_mass_build|
|
||||
json_mass_build.(@build_list.mass_build, :id, :name)
|
||||
end if @build_list.mass_build
|
||||
|
||||
json.url api_v1_build_list_path(@build_list, :format => :json)
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
json.groups @groups do |json, group|
|
||||
json.(group, :id, :uname, :own_projects_count, :description)
|
||||
json.created_at group.created_at.to_i
|
||||
json.updated_at group.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => group.owner
|
||||
json.avatar_url avatar_url(group, :big)
|
||||
json.url api_v1_group_path(group.id, :format => :json)
|
||||
json.html_url group_path(group.uname)
|
||||
end
|
||||
|
||||
json.url api_v1_groups_path(:format => :json)
|
|
@ -0,0 +1,5 @@
|
|||
json.group do |json|
|
||||
json.(@group, :id)
|
||||
json.partial! 'api/v1/shared/members'
|
||||
end
|
||||
json.url members_api_v1_group_path(@group.id, :format => :json)
|
|
@ -0,0 +1,9 @@
|
|||
json.group do |json|
|
||||
json.(@group, :id, :uname, :own_projects_count, :description)
|
||||
json.created_at @group.created_at.to_i
|
||||
json.updated_at @group.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => @group.owner
|
||||
json.avatar_url avatar_url(@group, :big)
|
||||
json.url api_v1_group_path(@group.id, :format => :json)
|
||||
json.html_url group_path(@group.uname)
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
json.(platform, :id, :name)
|
||||
json.url api_v1_platform_path(platform.id, :format => :json)
|
|
@ -0,0 +1,11 @@
|
|||
json.platforms @platforms do |json, platform|
|
||||
json.partial! 'platform', :platform => platform, :json => json
|
||||
json.(platform, :platform_type, :visibility)
|
||||
json.partial! 'api/v1/shared/owner', :owner => platform.owner
|
||||
json.repositories platform.repositories do |json_repos, repo|
|
||||
json_repos.(repo, :id, :name)
|
||||
json_repos.url api_v1_repository_path(repo.id, :format => :json)
|
||||
end
|
||||
end
|
||||
|
||||
json.url api_v1_platforms_path(:format => :json)
|
|
@ -0,0 +1,5 @@
|
|||
json.platform do |json|
|
||||
json.partial! 'platform', :platform => @platform, :json => json
|
||||
json.partial! 'api/v1/shared/members'
|
||||
end
|
||||
json.url members_api_v1_platform_path(@platform.id, :format => :json)
|
|
@ -0,0 +1,11 @@
|
|||
json.platform do |json|
|
||||
json.partial! 'platform', :platform => @platform, :json => json
|
||||
json.(@platform, :description, :parent_platform_id, :released, :visibility, :platform_type, :distrib_type)
|
||||
json.created_at @platform.created_at.to_i
|
||||
json.updated_at @platform.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => @platform.owner
|
||||
json.repositories @platform.repositories do |json_repos, repo|
|
||||
json_repos.(repo, :id, :name)
|
||||
json_repos.url api_v1_repository_path(repo.id, :format => :json)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
json.(project, :id, :name)
|
||||
json.fullname project.name_with_owner
|
||||
json.url api_v1_project_path(project.id, :format => :json)
|
|
@ -0,0 +1,5 @@
|
|||
json.project do |json|
|
||||
json.partial! 'project', :project => @project, :json => json
|
||||
json.(@project, :visibility)
|
||||
json.partial! 'api/v1/shared/owner', :owner => @project.owner
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
json.projects @projects do |json, project|
|
||||
json.partial! 'project', :project => project, :json => json
|
||||
json.(project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :average_build_time)
|
||||
json.created_at project.created_at.to_i
|
||||
json.updated_at project.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => project.owner
|
||||
end
|
||||
|
||||
json.url api_v1_projects_path(:format => :json)
|
|
@ -0,0 +1,5 @@
|
|||
json.project do |json|
|
||||
json.partial! 'project', :project => @project, :json => json
|
||||
json.partial! 'api/v1/shared/members'
|
||||
end
|
||||
json.url members_api_v1_project_path(@project.id, :format => :json)
|
|
@ -0,0 +1,8 @@
|
|||
json.refs_list (@project.repo.branches + @project.repo.tags) do |json_grit, grit|
|
||||
json_grit.ref grit.name
|
||||
json_grit.object do |json_object|
|
||||
json_object.type (grit.class.name =~ /Tag/ ? 'tag' : 'commit')
|
||||
json_object.sha grit.commit.id
|
||||
end
|
||||
end
|
||||
json.url refs_list_api_v1_project_path(@project.id, :format => :json)
|
|
@ -0,0 +1,18 @@
|
|||
json.project do |json|
|
||||
json.partial! 'project', :project => @project, :json => json
|
||||
json.(@project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :average_build_time)
|
||||
json.created_at @project.created_at.to_i
|
||||
json.updated_at @project.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => @project.owner
|
||||
json.maintainer do |json_maintainer|
|
||||
json.partial! 'api/v1/shared/member', :member => @project.maintainer, :tag => json_maintainer
|
||||
end
|
||||
json.repositories @project.repositories do |json_repos, repo|
|
||||
json_repos.(repo, :id, :name)
|
||||
json_repos.url api_v1_repository_path(repo.name, :format => :json)
|
||||
json_repos.platform do |json_platform|
|
||||
json_platform.(repo.platform, :id, :name)
|
||||
json_platform.url api_v1_platform_path(repo.platform, :format => :json)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
json.(repository, :id, :name)
|
||||
json.url api_v1_repository_path(repository.id, :format => :json)
|
|
@ -0,0 +1,8 @@
|
|||
json.repository do |json|
|
||||
json.partial! 'repository', :repository => @repository, :json => json
|
||||
json.projects @projects do |json_project, project|
|
||||
json.partial! 'api/v1/projects/project',
|
||||
:project => project, :json => json_project
|
||||
end
|
||||
end
|
||||
json.url projects_api_v1_repository_path(@repository.id, :format => :json)
|
|
@ -0,0 +1,10 @@
|
|||
json.repository do |json|
|
||||
json.partial! 'repository', :repository => @repository, :json => json
|
||||
json.(@repository, :description, :publish_without_qa)
|
||||
json.created_at @repository.created_at.to_i
|
||||
json.updated_at @repository.updated_at.to_i
|
||||
json.platform do |json_platform|
|
||||
json_platform.(@repository.platform, :id, :name)
|
||||
json_platform.url api_v1_platform_path(@repository.platform, :format => :json)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
tag.(member, :id, :name)
|
||||
tag.type member.class.name
|
||||
tag.url member_path(member)
|
|
@ -0,0 +1,3 @@
|
|||
json.members @members do |json_members, member|
|
||||
json.partial! 'api/v1/shared/member', :member => member, :tag => json_members
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
json.owner do |json_owner|
|
||||
json.partial! 'api/v1/shared/member', :member => owner, :tag => json_owner
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
json.user do |json|
|
||||
json.(@user, :id)
|
||||
json.notifiers do |json_notifiers|
|
||||
json_notifiers.(@user.notifier, :can_notify, :new_comment, :new_comment_reply, :new_issue, :issue_assign, :new_comment_commit_owner, :new_comment_commit_repo_owner, :new_comment_commit_commentor, :new_build, :new_associated_build)
|
||||
end
|
||||
end
|
||||
|
||||
json.url notifiers_api_v1_user_path(:json)
|
|
@ -0,0 +1,8 @@
|
|||
json.user do |json|
|
||||
json.(@user, :id, :name, :email, :uname,:language, :own_projects_count, :professional_experience, :site, :company, :location, :build_priority)
|
||||
json.created_at @user.created_at.to_i
|
||||
json.updated_at @user.updated_at.to_i
|
||||
json.avatar_url avatar_url(@user,:big)
|
||||
json.url api_v1_user_path(@user.id, :format => :json)
|
||||
json.html_url user_path(@user.uname)
|
||||
end
|
|
@ -25,7 +25,7 @@
|
|||
.hr.top
|
||||
|
||||
= form_tag add_group_members_path(parent) do
|
||||
.admin-search= autocomplete_field_tag 'user_id', params[:user_id], autocomplete_user_uname_users_path#, :id_element => '#member_id_field'
|
||||
.admin-search= autocomplete_field_tag 'user_id', params[:user_id], autocomplete_user_uname_autocompletes_path#, :id_element => '#member_id_field'
|
||||
.admin-role
|
||||
.lineForm= select_tag 'role', options_for_collaborators_roles_select
|
||||
.both
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue