[issue #347] Merge branch 'master' into 347-javascript_refactoring
Conflicts: app/assets/stylesheets/design/custom.scss app/models/group.rb app/models/user.rb
This commit is contained in:
commit
510b0c0c50
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -60,4 +60,15 @@ $(document).ready(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
$('.description-top .git_help').click(function() {
|
||||
$('#git_help_data').toggle();
|
||||
var desc = $('.description-top');
|
||||
|
||||
if ($('#git_help_data').css('display') == 'none') {
|
||||
desc.css('height', '38px');
|
||||
} else {
|
||||
desc.css('height', '196px');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -3,32 +3,35 @@ $(document).ready(function() {
|
|||
var platform_id = $(this).val();
|
||||
var base_platforms = $('.all_platforms input[type=checkbox].build_bpl_ids');
|
||||
|
||||
//$('#include_repos').html($('.preloaded_include_repos .include_repos_' + platform_id).html());
|
||||
|
||||
base_platforms.each(function(){
|
||||
if ($.inArray(platform_id, base_platforms.map(function(){ return $(this).val() }).get()) >= 0) {
|
||||
if ($(this).val() == platform_id) {
|
||||
$(this).attr('checked', 'checked');
|
||||
$(this).removeAttr('disabled');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('disabled');
|
||||
if ($(this).parent().find('.offset25 label').text() == 'main') {
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').attr('checked', 'checked');
|
||||
if ($(this).attr('data-released') === '1') {
|
||||
$('#build_list_auto_publish').removeAttr('checked').attr('disabled', 'disabled');
|
||||
} else {
|
||||
$('#build_list_auto_publish').removeAttr('disabled').attr('checked', 'checked');
|
||||
}
|
||||
|
||||
$(this).attr('checked', 'checked').removeAttr('disabled').trigger('change');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('disabled');
|
||||
|
||||
var rep_name = $('#build_list_pl_id option[value="' + $(this).val() + '"]').text().match(/[\w-]+\/([\w-]+)/)[1];
|
||||
if (rep_name != 'main') {
|
||||
$(this).parent().find('.offset25 input[type="checkbox"][rep_name="' + rep_name + '"]').attr('checked', 'checked');
|
||||
}
|
||||
$(this).parent().find('.offset25 input[type="checkbox"][rep_name="main"]').attr('checked', 'checked');
|
||||
} else {
|
||||
$(this).removeAttr('checked');
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').attr('disabled', 'disabled');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('checked');
|
||||
$(this).removeAttr('checked').attr('disabled', 'disabled').trigger('change');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').attr('disabled', 'disabled').removeAttr('checked');
|
||||
}
|
||||
//$('.additional_pl').parent().find('.offset25 input[type="checkbox"]').attr('disabled', 'disabled');
|
||||
} else {
|
||||
$(this).removeAttr('disabled');
|
||||
$(this).removeAttr('checked');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('disabled');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('checked');
|
||||
//$('.additional_pl').parent().find('.offset25 input[type="checkbox"]').removeAttr('disabled');
|
||||
$(this).removeAttr('disabled').removeAttr('checked').trigger('change');
|
||||
$(this).parent().find('.offset25 input[type="checkbox"]').removeAttr('disabled').removeAttr('checked');
|
||||
$('#build_list_auto_publish').removeAttr('disabled').attr('checked', 'checked');
|
||||
}
|
||||
});
|
||||
|
||||
setBranchSelected();
|
||||
});
|
||||
$('#build_list_pl_id').trigger('change');
|
||||
|
||||
|
@ -38,11 +41,45 @@ $(document).ready(function() {
|
|||
$('.offset25 input[type="checkbox"]').click(function() {
|
||||
setPlChecked(this, $(this).attr('checked'));
|
||||
});
|
||||
|
||||
$('.build_bpl_ids').click(function() {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
function setPlChecked(pointer, checked) {
|
||||
pl_cbx = $(pointer).parent().parent().parent().find('input[type="checkbox"].build_bpl_ids');
|
||||
var pl_cbx = $(pointer).parent().parent().parent().find('input[type="checkbox"].build_bpl_ids');
|
||||
var pl_id = pl_cbx.val();
|
||||
if (checked && !$(pointer).attr('disabled')) {
|
||||
pl_cbx.attr('checked', 'checked');
|
||||
pl_cbx.attr('checked', 'checked').trigger('change');
|
||||
} else if ($('input[pl_id=' + pl_id + '][checked="checked"]').size() == 0) {
|
||||
pl_cbx.removeAttr('checked').trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
function setBranchSelected() {
|
||||
var pl_id = $('#build_list_pl_id').val();
|
||||
// Checks if selected platform is main or not:
|
||||
if ( $('.all_platforms').find('input[type="checkbox"][value=' + pl_id + '].build_bpl_ids').size() > 0 ) {
|
||||
var pl_name = $('#build_list_pl_id option[value="' + pl_id + '"]').text().match(/([\w-]+)\/[\w-]+/)[1];
|
||||
var branch_pl_opt = $('#build_list_project_version option[value="latest_' + pl_name + '"]');
|
||||
// If there is branch we need - set it selected:
|
||||
if ( branch_pl_opt.size() > 0 ) {
|
||||
$('#build_list_project_version option[selected]').removeAttr('selected');
|
||||
branch_pl_opt.attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function platformChange() {
|
||||
var rel = !!$('input[type="checkbox"].build_bpl_ids').filter(function(index) {
|
||||
var $this = $(this);
|
||||
return !!$this.attr('checked') && ($this.attr('data-released') === '1');
|
||||
}).length;
|
||||
|
||||
if (rel) {
|
||||
$('#build_list_auto_publish').removeAttr('checked').attr('disabled', 'disabled');
|
||||
} else {
|
||||
$('#build_list_auto_publish').removeAttr('disabled').attr('checked', 'checked');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,28 +128,28 @@ $(document).ready(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
function remExecutor(form) {
|
||||
var el = form.find('.people.selected.remove_executor');
|
||||
function remAssignee(form) {
|
||||
var el = form.find('.people.selected.remove_assignee');
|
||||
var id = el.attr('id');
|
||||
$('#manage_issue_users_list .add_executor.people.selected').removeClass('select');
|
||||
$('#manage_issue_users_list .add_assignee.people.selected').removeClass('select');
|
||||
el.remove();
|
||||
}
|
||||
|
||||
$('.add_executor.people.selected').live('click', function() {
|
||||
$('.add_assignee.people.selected').live('click', function() {
|
||||
var form_new = $('form.issue');
|
||||
var form_edit = $('form.edit_form.issue');
|
||||
form_new.find('#people-span').fadeOut(0);
|
||||
remExecutor(form_new);
|
||||
var clone = $(this).clone().removeClass('add_executor').addClass('remove_executor');
|
||||
form_new.find('#issue_executor').html(clone);
|
||||
$('.current_executor').html(clone.removeClass('select'));
|
||||
remAssignee(form_new);
|
||||
var clone = $(this).clone().removeClass('add_assignee').addClass('remove_assignee');
|
||||
form_new.find('#issue_assignee').html(clone);
|
||||
$('.current_assignee').html(clone.removeClass('select'));
|
||||
$(this).addClass('select');
|
||||
});
|
||||
|
||||
$('.remove_executor.people.selected').live('click', function() {
|
||||
$('.remove_assignee.people.selected').live('click', function() {
|
||||
var form = $('form.issue, form.edit_form issue');
|
||||
form.find('#people-span').fadeIn(0);
|
||||
remExecutor(form);
|
||||
remAssignee(form);
|
||||
});
|
||||
|
||||
function remLabel(form, id) {
|
||||
|
@ -241,9 +241,9 @@ $(document).ready(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
$('.button.manage_executor').live('click', function() {
|
||||
$('form#search_user, .button.update_executor').fadeIn(0);
|
||||
$('.current_executor .people').addClass('remove_executor selected').removeClass('nopointer');
|
||||
$('.button.manage_assignee').live('click', function() {
|
||||
$('form#search_user, .button.update_assignee').fadeIn(0);
|
||||
$('.current_assignee .people').addClass('remove_assignee selected').removeClass('nopointer');
|
||||
$(this).fadeOut(0);
|
||||
});
|
||||
|
||||
|
@ -254,16 +254,16 @@ $(document).ready(function() {
|
|||
$(this).fadeOut(0);
|
||||
});
|
||||
|
||||
$('.button.update_executor').live('click', function() {
|
||||
var form = $('form.edit_executor.issue');
|
||||
$('.button.update_assignee').live('click', function() {
|
||||
var form = $('form.edit_assignee.issue');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: form.attr("action"),
|
||||
data: form.serialize(),
|
||||
success: function(data){
|
||||
$('.current_executor .people').removeClass('remove_executor selected').addClass('nopointer');
|
||||
$('form#search_user, .button.update_executor').fadeOut(0);
|
||||
$('.button.manage_executor').fadeIn(0);
|
||||
$('.current_assignee .people').removeClass('remove_assignee selected').addClass('nopointer');
|
||||
$('form#search_user, .button.update_assignee').fadeOut(0);
|
||||
$('.button.manage_assignee').fadeIn(0);
|
||||
$('#manage_issue_users_list').html('');
|
||||
},
|
||||
error: function(data){
|
||||
|
|
|
@ -851,3 +851,73 @@ input.placeholder,
|
|||
textarea.placeholder {
|
||||
color: #CFCFCF;
|
||||
}
|
||||
|
||||
div.description-top div.git_help {
|
||||
float: left;
|
||||
margin-top: 11px;
|
||||
margin-left: 10px;
|
||||
font-size: 11px;
|
||||
color: green;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div#git_help_data {
|
||||
display: none;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
div#git_help_data p {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
// for bootstrap
|
||||
.close {
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 18px;
|
||||
color: #000000;
|
||||
text-shadow: 0 1px 0 #ffffff;
|
||||
opacity: 0.2;
|
||||
filter: alpha(opacity=20);
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
opacity: 0.4;
|
||||
filter: alpha(opacity=40);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal {
|
||||
margin: -150px 0 0 -280px;
|
||||
}
|
||||
|
||||
#forkModal.modal .btn.btn-primary {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.zip {
|
||||
float: left;
|
||||
padding-left: 5px;
|
||||
margin-top: 6px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav > li > a:hover {
|
||||
text-decoration: none;
|
||||
background-color: #DCECFA;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dropdown.open .dropdown-toggle {
|
||||
background: none repeat scroll 0 0;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@ class ActivityFeedsController < ApplicationController
|
|||
@activity_feeds = current_user.activity_feeds
|
||||
@activity_feeds = @activity_feeds.where(:kind => "ActivityFeed::#{@filter.upcase}".constantize) unless @filter == :all
|
||||
@activity_feeds = @activity_feeds.paginate :page => params[:page]
|
||||
if request.format == '*/*'
|
||||
render '_list', :layout => false
|
||||
else
|
||||
render 'index'
|
||||
respond_to do |format|
|
||||
format.html { request.xhr? ? render('_list', :layout => false) : render('index') }
|
||||
format.atom
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
layout :layout_by_resource
|
||||
|
||||
# Hack to prevent token auth on all pages except atom feed:
|
||||
prepend_before_filter lambda { redirect_to(new_user_session_path) if params[:token] && params[:format] != 'atom'}
|
||||
|
||||
before_filter :set_locale
|
||||
before_filter lambda { EventLog.current_controller = self },
|
||||
:only => [:create, :destroy, :open_id, :cancel, :publish, :change_visibility] # :update
|
||||
|
|
|
@ -7,8 +7,9 @@ class BuildListsController < ApplicationController
|
|||
before_filter :authenticate_build_service!, :only => CALLBACK_ACTIONS
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :index, :search] if APP_CONFIG['anonymous_access']
|
||||
before_filter :find_project, :only => NESTED_ACTIONS
|
||||
before_filter :find_build_list, :only => [:show, :publish, :cancel]
|
||||
before_filter :find_build_list, :only => [:show, :publish, :cancel, :reject_publish]
|
||||
before_filter :find_build_list_by_bs, :only => [:publish_build, :status_build, :pre_build, :post_build, :circle_build]
|
||||
before_filter :find_platform, :only => [:create]
|
||||
|
||||
load_and_authorize_resource :project, :only => NESTED_ACTIONS
|
||||
load_and_authorize_resource :build_list, :through => :project, :only => NESTED_ACTIONS, :shallow => true
|
||||
|
@ -40,12 +41,13 @@ class BuildListsController < ApplicationController
|
|||
|
||||
def create
|
||||
notices, errors = [], []
|
||||
params[:build_list].delete(:auto_publish) if @platform.released
|
||||
Arch.where(:id => params[:arches]).each do |arch|
|
||||
Platform.main.where(:id => params[:bpls]).each do |bpl|
|
||||
@build_list = @project.build_lists.build(params[:build_list])
|
||||
@build_list.commit_hash = @project.git_repository.commits(@build_list.project_version.match(/^latest_(.+)/).to_a.last || @build_list.project_version).first.id if @build_list.project_version
|
||||
@build_list.bpl = bpl; @build_list.arch = arch; @build_list.user = current_user
|
||||
@build_list.include_repos = @build_list.include_repos.select { |ir| @build_list.bpl.repository_ids.include? ir.to_i }
|
||||
@build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.bpl.repository_ids.include? ir.to_i}
|
||||
@build_list.priority = 100 # User builds more priority than mass rebuild with zero priority
|
||||
flash_options = {:project_version => @build_list.project_version, :arch => arch.name, :bpl => bpl.name, :pl => @build_list.pl}
|
||||
if @build_list.save
|
||||
|
@ -78,6 +80,14 @@ class BuildListsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def reject_publish
|
||||
if @build_list.reject_publish
|
||||
redirect_to :back, :notice => t('layout.build_lists.reject_publish_success')
|
||||
else
|
||||
redirect_to :back, :notice => t('layout.build_lists.reject_publish_fail')
|
||||
end
|
||||
end
|
||||
|
||||
def cancel
|
||||
if @build_list.cancel
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_success')
|
||||
|
@ -94,7 +104,6 @@ class BuildListsController < ApplicationController
|
|||
else
|
||||
@build_list.status = BuildList::FAILED_PUBLISH
|
||||
end
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -106,7 +115,6 @@ class BuildListsController < ApplicationController
|
|||
@item.save
|
||||
|
||||
@build_list.container_path = params[:container_path]
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -114,7 +122,6 @@ class BuildListsController < ApplicationController
|
|||
|
||||
def pre_build
|
||||
@build_list.status = BuildServer::BUILD_STARTED
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -123,7 +130,6 @@ class BuildListsController < ApplicationController
|
|||
def post_build
|
||||
@build_list.status = params[:status]
|
||||
@build_list.container_path = params[:container_path]
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -134,7 +140,6 @@ class BuildListsController < ApplicationController
|
|||
def circle_build
|
||||
@build_list.is_circle = true
|
||||
@build_list.container_path = params[:container_path]
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -147,7 +152,6 @@ class BuildListsController < ApplicationController
|
|||
@build_list.set_items(ActiveSupport::JSON.decode(params[:items]))
|
||||
@build_list.is_circle = (params[:is_circular].to_i != 0)
|
||||
@build_list.bs_id = params[:id]
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -159,6 +163,10 @@ class BuildListsController < ApplicationController
|
|||
@project = Project.find_by_id params[:project_id]
|
||||
end
|
||||
|
||||
def find_platform
|
||||
@platform = Platform.find params[:build_list][:pl_id]
|
||||
end
|
||||
|
||||
def find_build_list
|
||||
@build_list = BuildList.find(params[:id])
|
||||
end
|
||||
|
|
|
@ -1,26 +1,17 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class CommentsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
load_and_authorize_resource :project
|
||||
before_filter :find_commentable
|
||||
before_filter :find_or_build_comment
|
||||
load_and_authorize_resource
|
||||
|
||||
load_resource :project
|
||||
before_filter :set_commentable
|
||||
before_filter :find_comment, :only => [:edit, :update, :destroy]
|
||||
authorize_resource
|
||||
|
||||
def index
|
||||
@comments = @commentable.comments
|
||||
end
|
||||
include CommentsHelper
|
||||
|
||||
def create
|
||||
@comment = @commentable.comments.build(params[:comment]) if @commentable.class == Issue
|
||||
if @commentable.class == Grit::Commit
|
||||
@comment = Comment.new(params[:comment].merge(:commentable_id => @commentable.id.hex, :commentable_type => @commentable.class.name))
|
||||
end
|
||||
@comment.project = @project
|
||||
@comment.user_id = current_user.id
|
||||
if @comment.save
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to commentable_path
|
||||
redirect_to project_commentable_path(@project, @commentable)
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
|
@ -28,19 +19,12 @@ class CommentsController < ApplicationController
|
|||
end
|
||||
|
||||
def edit
|
||||
@update_url = case @commentable.class.name
|
||||
when "Issue"
|
||||
project_issue_comment_path(@project, @commentable, @comment)
|
||||
when "Grit::Commit"
|
||||
project_commit_comment_path(@project, @commentable, @comment)
|
||||
end
|
||||
@commentable_path = commentable_path
|
||||
end
|
||||
|
||||
def update
|
||||
if @comment.update_attributes(params[:comment])
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to commentable_path
|
||||
redirect_to project_commentable_path(@project, @commentable)
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
|
@ -49,30 +33,19 @@ class CommentsController < ApplicationController
|
|||
|
||||
def destroy
|
||||
@comment.destroy
|
||||
|
||||
flash[:notice] = t("flash.comment.destroyed")
|
||||
redirect_to commentable_path
|
||||
redirect_to project_commentable_path(@project, @commentable)
|
||||
end
|
||||
|
||||
private
|
||||
protected
|
||||
|
||||
def set_commentable
|
||||
@commentable = if params[:issue_id].present?
|
||||
@project.issues.find_by_serial_id params[:issue_id]
|
||||
elsif params[:commit_id].present?
|
||||
@project.git_repository.commit params[:commit_id]
|
||||
end
|
||||
def find_commentable
|
||||
@commentable = params[:issue_id].present? && @project.issues.find_by_serial_id(params[:issue_id]) ||
|
||||
params[:commit_id].present? && @project.git_repository.commit(params[:commit_id])
|
||||
end
|
||||
|
||||
def find_comment
|
||||
@comment = Comment.find(params[:id])
|
||||
if @comment.commit_comment?
|
||||
@comment.project = @project
|
||||
end
|
||||
def find_or_build_comment
|
||||
@comment = params[:id].present? && Comment.find(params[:id]) ||
|
||||
current_user.comments.build(params[:comment]) {|c| c.commentable = @commentable; c.project = @project}
|
||||
end
|
||||
|
||||
def commentable_path
|
||||
@commentable.class == Issue ? [@project, @commentable] : commit_path(@project, @commentable.id)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class DownloadsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@downloads = Download.paginate :page => params[:page], :per_page => 30
|
||||
end
|
||||
|
||||
def refresh
|
||||
Download.rotate_nginx_log
|
||||
Download.parse_and_remove_nginx_log
|
||||
|
||||
redirect_to downloads_path, :notice => t('flash.downloads.statistics_refreshed')
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Git::BaseController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw] if APP_CONFIG['anonymous_access']
|
||||
skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw, :archive] if APP_CONFIG['anonymous_access']
|
||||
load_and_authorize_resource :project
|
||||
|
||||
before_filter :find_git_repository
|
||||
|
|
|
@ -15,4 +15,18 @@ class Git::TreesController < Git::BaseController
|
|||
@tree = @tree / @path if @path
|
||||
render :template => "git/trees/show"
|
||||
end
|
||||
|
||||
def archive
|
||||
treeish = params[:treeish].presence || @project.default_branch
|
||||
format = params[:format] || 'tar'
|
||||
commit = @project.git_repository.log(treeish, nil, :max_count => 1).first
|
||||
name = "#{@project.owner.uname}-#{@project.name}#{@project.tags.include?(treeish) ? "-#{treeish}" : ''}-#{commit.id[0..19]}"
|
||||
fullname = "#{name}.#{format == 'tar' ? 'tar.gz' : 'zip'}"
|
||||
file = Tempfile.new fullname, 'tmp'
|
||||
system("cd #{@project.path}; git archive --format=#{format} --prefix=#{name}/ #{treeish} #{format == 'tar' ? ' | gzip -9' : ''} > #{file.path}")
|
||||
file.close
|
||||
send_file file.path, :disposition => 'attachment', :type => "application/#{format == 'tar' ? 'x-tar-gz' : 'zip'}",
|
||||
:filename => fullname
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class IssuesController < ApplicationController
|
|||
@status = params[:status] == 'closed' ? 'closed' : 'open'
|
||||
@labels = params[:labels] || []
|
||||
@issues = @project.issues
|
||||
@issues = @issues.where(:user_id => current_user.id) if @is_assigned_to_me
|
||||
@issues = @issues.where(:assignee_id => current_user.id) if @is_assigned_to_me
|
||||
@issues = @issues.joins(:labels).where(:labels => {:name => @labels}) unless @labels == []
|
||||
|
||||
if params[:search_issue]
|
||||
|
@ -25,7 +25,7 @@ class IssuesController < ApplicationController
|
|||
@issues = @issues.where(:status => @status)
|
||||
|
||||
|
||||
@issues = @issues.includes(:creator, :user).order('serial_id desc').uniq.paginate :per_page => 10, :page => params[:page]
|
||||
@issues = @issues.includes(:assignee, :user).order('serial_id desc').uniq.paginate :per_page => 10, :page => params[:page]
|
||||
if status == 200
|
||||
render 'index', :layout => request.format == '*/*' ? 'issues' : 'application' # maybe FIXME '*/*'?
|
||||
else
|
||||
|
@ -38,9 +38,9 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
|
||||
def create
|
||||
@user_uname = params[:user_uname]
|
||||
@assignee_uname = params[:assignee_uname]
|
||||
@issue = @project.issues.new(params[:issue])
|
||||
@issue.creator_id = current_user.id
|
||||
@issue.user_id = current_user.id
|
||||
|
||||
if @issue.save
|
||||
@issue.subscribe_creator(current_user.id)
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class ProductsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :find_product, :only => [:show, :edit, :update, :destroy]
|
||||
before_filter :find_platform
|
||||
before_filter :build_product_stub, :only => [:new, :create]
|
||||
|
||||
|
||||
load_and_authorize_resource :platform
|
||||
load_and_authorize_resource :product, :through => :platform
|
||||
|
||||
|
@ -20,24 +17,17 @@ class ProductsController < ApplicationController
|
|||
@product.build_script = DEFAULT_BUILD
|
||||
end
|
||||
|
||||
# def clone
|
||||
# @template = @platform.products.find(params[:id])
|
||||
# @product = @platform.products.new
|
||||
# @product.clone_from!(@template)
|
||||
#
|
||||
# render :template => "products/new"
|
||||
# end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def create
|
||||
@product = @platform.products.new params[:product]
|
||||
if @product.save
|
||||
flash[:notice] = t('flash.product.saved')
|
||||
redirect_to platform_product_path(@platform, @product)
|
||||
else
|
||||
flash[:error] = t('flash.product.save_error')
|
||||
flash[:warning] = @product.errors.full_messages.join('. ')
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
@ -45,9 +35,10 @@ class ProductsController < ApplicationController
|
|||
def update
|
||||
if @product.update_attributes(params[:product])
|
||||
flash[:notice] = t('flash.product.saved')
|
||||
redirect_to @platform
|
||||
redirect_to platform_product_path(@platform, @product)
|
||||
else
|
||||
flash[:error] = t('flash.product.save_error')
|
||||
flash[:warning] = @product.errors.full_messages.join('. ')
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
|
@ -61,17 +52,4 @@ class ProductsController < ApplicationController
|
|||
redirect_to platform_products_path(@platform)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_product
|
||||
@product = Product.find params[:id]
|
||||
end
|
||||
|
||||
def find_platform
|
||||
@platform = Platform.find params[:platform_id]
|
||||
end
|
||||
|
||||
def build_product_stub
|
||||
@product = Product.new(:platform_id => params[:platform_id])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,9 +26,10 @@ class ProjectsController < ApplicationController
|
|||
@project = Project.new params[:project]
|
||||
@project.owner = choose_owner
|
||||
@who_owns = (@project.owner_type == 'User' ? :me : :group)
|
||||
authorize! :update, @project.owner if @project.owner.class == Group
|
||||
|
||||
if @project.save
|
||||
flash[:notice] = t('flash.project.saved')
|
||||
flash[:notice] = t('flash.project.saved')
|
||||
redirect_to @project
|
||||
else
|
||||
flash[:error] = t('flash.project.save_error')
|
||||
|
@ -56,7 +57,9 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
|
||||
def fork
|
||||
if forked = @project.fork(current_user) and forked.valid?
|
||||
owner = (Group.find params[:group] if params[:group].present?) || current_user
|
||||
authorize! :update, owner if owner.class == Group
|
||||
if forked = @project.fork(owner) and forked.valid?
|
||||
redirect_to forked, :notice => t("flash.project.forked")
|
||||
else
|
||||
flash[:warning] = t("flash.project.fork_error")
|
||||
|
|
|
@ -3,4 +3,11 @@ module ActivityFeedsHelper
|
|||
def render_activity_feed(activity_feed)
|
||||
render :partial => activity_feed.partial, :locals => activity_feed.data.merge(:activity_feed => activity_feed)
|
||||
end
|
||||
|
||||
def get_feed_title_from_content(content)
|
||||
# removes html tags and haml generator indentation whitespaces and new line chars:
|
||||
feed_title = strip_tags(content).gsub(/(^\s+|\n| )/, ' ')
|
||||
# removes multiple whitespaces in a row and strip it:
|
||||
feed_title = feed_title.gsub(/\s{2,}/, ' ').strip
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,8 @@ module BuildListsHelper
|
|||
return 'success'
|
||||
end
|
||||
if [BuildServer::BUILD_ERROR, BuildServer::PLATFORM_NOT_FOUND,
|
||||
BuildServer::PROJECT_NOT_FOUND,BuildServer::PROJECT_VERSION_NOT_FOUND, BuildList::FAILED_PUBLISH].include? status
|
||||
BuildServer::PROJECT_NOT_FOUND, BuildServer::PROJECT_VERSION_NOT_FOUND,
|
||||
BuildList::FAILED_PUBLISH, BuildList::REJECTED_PUBLISH].include? status
|
||||
return 'error'
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module CommentsHelper
|
||||
def project_commentable_comment_path(project, commentable, comment)
|
||||
case
|
||||
when Comment.issue_comment?(commentable.class)
|
||||
project_issue_comment_path(project, commentable, comment)
|
||||
when 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)
|
||||
commit_path project, commentable.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ class Ability
|
|||
|
||||
# Shared rights between guests and registered users
|
||||
can :show, Project, :visibility => 'open'
|
||||
can :archive, Project, :visibility => 'open'
|
||||
can :read, Issue, :project => {:visibility => 'open'}
|
||||
can :search, BuildList
|
||||
can :read, BuildList, :project => {:visibility => 'open'}
|
||||
|
@ -51,13 +52,15 @@ class Ability
|
|||
|
||||
can :create, Project
|
||||
can :read, Project, :visibility => 'open'
|
||||
can :read, Project, :owner_type => 'User', :owner_id => user.id
|
||||
can :read, Project, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
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(:write, Project) {|project| local_writer? project} # for grack
|
||||
can([:update, :sections, :manage_collaborators], Project) {|project| local_admin? project}
|
||||
can(:fork, Project) {|project| can? :read, project}
|
||||
can(:fork_to_group, 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.objects.exists?(:object_type => 'User', :object_id => user.id, :role => 'admin')}
|
||||
can :remove_user, Project
|
||||
|
||||
can [:read, :owned], BuildList, :user_id => user.id
|
||||
|
@ -65,7 +68,12 @@ class Ability
|
|||
can [:read, :related], BuildList, :project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can(:read, BuildList, read_relations_for('build_lists', 'projects')) {|build_list| can? :read, build_list.project}
|
||||
can(:create, BuildList) {|build_list| build_list.project.is_rpm && can?(:write, build_list.project)}
|
||||
can(:publish, BuildList) {|build_list| build_list.can_publish? && can?(:write, build_list.project)}
|
||||
can(:publish, BuildList) do |build_list|
|
||||
build_list.can_publish? and build_list.pl.released ? local_admin?(build_list.pl) : can?(:write, build_list.project)
|
||||
end
|
||||
can(:reject_publish, BuildList) do |build_list|
|
||||
build_list.can_reject_publish? and build_list.pl.released and local_admin?(build_list.pl)
|
||||
end
|
||||
can(:cancel, BuildList) {|build_list| build_list.can_cancel? && can?(:write, build_list.project)}
|
||||
|
||||
can [:read, :members], Platform, :visibility => 'open'
|
||||
|
|
|
@ -19,23 +19,23 @@ class ActivityFeedObserver < ActiveRecord::Observer
|
|||
ActivityFeed.create(
|
||||
:user => recipient,
|
||||
:kind => 'new_issue_notification',
|
||||
:data => {:user_name => record.creator.name, :user_email => record.creator.email, :user_id => record.creator_id,:issue_serial_id => record.serial_id,
|
||||
:data => {:user_name => record.user.name, :user_email => record.user.email, :user_id => record.user_id,:issue_serial_id => record.serial_id,
|
||||
:issue_title => record.title, :project_id => record.project.id, :project_name => record.project.name, :project_owner => record.project.owner.uname}
|
||||
)
|
||||
end
|
||||
|
||||
if record.user_id_changed?
|
||||
UserMailer.delay.issue_assign_notification(record, record.user) if record.user.notifier.issue_assign && record.user.notifier.can_notify
|
||||
if record.assignee_id_changed?
|
||||
UserMailer.delay.issue_assign_notification(record, record.assignee) if record.assignee.notifier.issue_assign && record.assignee.notifier.can_notify
|
||||
ActivityFeed.create(
|
||||
:user => record.user,
|
||||
:kind => 'issue_assign_notification',
|
||||
:data => {:user_name => record.creator.name, :user_email => record.creator.email, :user_id => record.creator_id, :issue_serial_id => record.serial_id,
|
||||
:data => {:user_name => record.user.name, :user_email => record.user.email, :user_id => record.user_id, :issue_serial_id => record.serial_id,
|
||||
:project_id => record.project.id, :issue_title => record.title, :project_name => record.project.name, :project_owner => record.project.owner.uname}
|
||||
)
|
||||
end
|
||||
|
||||
when 'Comment'
|
||||
if record.commentable.class == Issue
|
||||
if record.issue_comment?
|
||||
subscribes = record.commentable.subscribes
|
||||
subscribes.each do |subscribe|
|
||||
if record.user_id != subscribe.user_id
|
||||
|
@ -70,6 +70,7 @@ class ActivityFeedObserver < ActiveRecord::Observer
|
|||
end
|
||||
|
||||
when 'GitHook'
|
||||
return unless record.project
|
||||
change_type = record.change_type
|
||||
branch_name = record.refname.split('/').last
|
||||
|
||||
|
@ -120,12 +121,12 @@ class ActivityFeedObserver < ActiveRecord::Observer
|
|||
def after_update(record)
|
||||
case record.class.to_s
|
||||
when 'Issue'
|
||||
if record.user_id && record.user_id_changed?
|
||||
UserMailer.delay.issue_assign_notification(record, record.user) if record.user.notifier.issue_assign && record.user.notifier.can_notify
|
||||
if record.assignee_id && record.assignee_id_changed?
|
||||
UserMailer.delay.issue_assign_notification(record, record.assignee) if record.assignee.notifier.issue_assign && record.assignee.notifier.can_notify
|
||||
ActivityFeed.create(
|
||||
:user => record.user,
|
||||
:user => record.assignee,
|
||||
:kind => 'issue_assign_notification',
|
||||
:data => {:user_name => record.user.name, :user_email => record.user.email, :issue_serial_id => record.serial_id, :issue_title => record.title,
|
||||
:data => {:user_name => record.assignee.name, :user_email => record.assignee.email, :issue_serial_id => record.serial_id, :issue_title => record.title,
|
||||
:project_id => record.project.id, :project_name => record.project.name, :project_owner => record.project.owner.uname}
|
||||
)
|
||||
end
|
||||
|
@ -138,7 +139,7 @@ class ActivityFeedObserver < ActiveRecord::Observer
|
|||
ActivityFeed.create(
|
||||
:user => User.find(recipient),
|
||||
:kind => 'build_list_notification',
|
||||
:data => {:task_num => record.bs_id, :build_list_id => record.id, :status => record.status, :notified_at => record.notified_at,
|
||||
:data => {:task_num => record.bs_id, :build_list_id => record.id, :status => record.status, :updated_at => record.updated_at,
|
||||
:project_id => record.project_id, :project_name => record.project.name, :project_owner => record.project.owner.uname,
|
||||
:user_name => record.user.name, :user_email => record.user.email, :user_id => record.user_id}
|
||||
)
|
||||
|
|
|
@ -23,6 +23,7 @@ class BuildList < ActiveRecord::Base
|
|||
BUILD_PUBLISHED = 6000
|
||||
BUILD_PUBLISH = 7000
|
||||
FAILED_PUBLISH = 8000
|
||||
REJECTED_PUBLISH = 9000
|
||||
|
||||
STATUSES = [ WAITING_FOR_RESPONSE,
|
||||
BUILD_CANCELED,
|
||||
|
@ -30,6 +31,7 @@ class BuildList < ActiveRecord::Base
|
|||
BUILD_PUBLISHED,
|
||||
BUILD_PUBLISH,
|
||||
FAILED_PUBLISH,
|
||||
REJECTED_PUBLISH,
|
||||
BuildServer::SUCCESS,
|
||||
BuildServer::BUILD_STARTED,
|
||||
BuildServer::BUILD_ERROR,
|
||||
|
@ -47,6 +49,7 @@ class BuildList < ActiveRecord::Base
|
|||
BUILD_PUBLISHED => :build_published,
|
||||
BUILD_PUBLISH => :build_publish,
|
||||
FAILED_PUBLISH => :failed_publish,
|
||||
REJECTED_PUBLISH => :rejected_publish,
|
||||
BuildServer::BUILD_ERROR => :build_error,
|
||||
BuildServer::BUILD_STARTED => :build_started,
|
||||
BuildServer::SUCCESS => :success,
|
||||
|
@ -59,32 +62,23 @@ class BuildList < ActiveRecord::Base
|
|||
}
|
||||
|
||||
scope :recent, order("#{table_name}.updated_at DESC")
|
||||
# scope :current, lambda {
|
||||
# outdatable_statuses = [BuildServer::SUCCESS, BuildServer::ERROR, BuildServer::PLATFORM_NOT_FOUND, BuildServer::PLATFORM_PENDING, BuildServer::PROJECT_NOT_FOUND, BuildServer::PROJECT_VERSION_NOT_FOUND]
|
||||
# where(["status in (?) OR (status in (?) AND notified_at >= ?)", [WAITING_FOR_RESPONSE, BUILD_PENDING, BuildServer::BUILD_STARTED], outdatable_statuses, Time.now - 2.days])
|
||||
# }
|
||||
|
||||
scope :for_status, lambda {|status| where(:status => status) }
|
||||
scope :for_user, lambda { |user| where(:user_id => user.id) }
|
||||
scope :scoped_to_arch, lambda {|arch| where(:arch_id => arch) }
|
||||
scope :scoped_to_project_version, lambda {|project_version| where(:project_version => project_version) }
|
||||
scope :scoped_to_is_circle, lambda {|is_circle| where(:is_circle => is_circle) }
|
||||
scope :for_creation_date_period, lambda{|start_date, end_date|
|
||||
if start_date && end_date
|
||||
where(["#{table_name}.created_at BETWEEN ? AND ?", start_date, end_date])
|
||||
elsif start_date && !end_date
|
||||
where(["#{table_name}.created_at >= ?", start_date])
|
||||
elsif !start_date && end_date
|
||||
where(["#{table_name}.created_at <= ?", end_date])
|
||||
end
|
||||
s = scoped
|
||||
s = s.where(["build_lists.created_at >= ?", start_date]) if start_date
|
||||
s = s.where(["build_lists.created_at <= ?", end_date]) if end_date
|
||||
s
|
||||
}
|
||||
scope :for_notified_date_period, lambda{|start_date, end_date|
|
||||
if start_date && end_date
|
||||
where(["notified_at BETWEEN ? AND ?", start_date, end_date])
|
||||
elsif start_date && !end_date
|
||||
where(["notified_at >= ?", start_date])
|
||||
elsif !start_date && end_date
|
||||
where(["notified_at <= ?", end_date])
|
||||
end
|
||||
s = scoped
|
||||
s = s.where(["build_lists.updated_at >= ?", start_date]) if start_date
|
||||
s = s.where(["build_lists.updated_at <= ?", end_date]) if end_date
|
||||
s
|
||||
}
|
||||
scope :scoped_to_project_name, lambda {|project_name| joins(:project).where('projects.name LIKE ?', "%#{project_name}%")}
|
||||
|
||||
|
@ -123,6 +117,15 @@ class BuildList < ActiveRecord::Base
|
|||
status == BuildServer::SUCCESS or status == FAILED_PUBLISH
|
||||
end
|
||||
|
||||
def reject_publish
|
||||
return false unless can_reject_publish?
|
||||
update_attribute(:status, REJECTED_PUBLISH)
|
||||
end
|
||||
|
||||
def can_reject_publish?
|
||||
can_publish? and pl.released
|
||||
end
|
||||
|
||||
def cancel
|
||||
return false unless can_cancel?
|
||||
has_canceled = BuildServer.delete_build_list bs_id
|
||||
|
@ -139,6 +142,23 @@ class BuildList < ActiveRecord::Base
|
|||
{:project => project.name, :version => project_version, :arch => arch.name}.inspect
|
||||
end
|
||||
|
||||
def current_duration
|
||||
(Time.now.utc - started_at.utc).to_i
|
||||
end
|
||||
|
||||
def human_current_duration
|
||||
I18n.t("layout.build_lists.human_current_duration", {:hours => (current_duration/3600).to_i, :minutes => (current_duration%3600/60).to_i})
|
||||
end
|
||||
|
||||
def human_duration
|
||||
I18n.t("layout.build_lists.human_duration", {:hours => (duration/3600).to_i, :minutes => (duration%3600/60).to_i})
|
||||
end
|
||||
|
||||
def in_work?
|
||||
status == BuildServer::BUILD_STARTED
|
||||
#[WAITING_FOR_RESPONSE, BuildServer::BUILD_PENDING, BuildServer::BUILD_STARTED].include?(status)
|
||||
end
|
||||
|
||||
private
|
||||
def set_default_status
|
||||
self.status = WAITING_FOR_RESPONSE unless self.status.present?
|
||||
|
|
|
@ -22,8 +22,8 @@ class BuildList::Filter
|
|||
if @options[:created_at_start] || @options[:created_at_end]
|
||||
build_lists = build_lists.for_creation_date_period(@options[:created_at_start], @options[:created_at_end])
|
||||
end
|
||||
if @options[:notified_at_start] || @options[:notified_at_end]
|
||||
build_lists = build_lists.for_notified_date_period(@options[:notified_at_start], @options[:notified_at_end])
|
||||
if @options[:updated_at_start] || @options[:updated_at_end]
|
||||
build_lists = build_lists.for_notified_date_period(@options[:updated_at_start], @options[:updated_at_end])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -47,8 +47,8 @@ class BuildList::Filter
|
|||
:status => nil,
|
||||
:created_at_start => nil,
|
||||
:created_at_end => nil,
|
||||
:notified_at_start => nil,
|
||||
:notified_at_end => nil,
|
||||
:updated_at_start => nil,
|
||||
:updated_at_end => nil,
|
||||
:arch_id => nil,
|
||||
:is_circle => nil,
|
||||
:project_version => nil,
|
||||
|
@ -60,8 +60,8 @@ class BuildList::Filter
|
|||
@options[:status] = @options[:status].present? ? @options[:status].to_i : nil
|
||||
@options[:created_at_start] = build_date_from_params(:created_at_start, @options)
|
||||
@options[:created_at_end] = build_date_from_params(:created_at_end, @options)
|
||||
@options[:notified_at_start] = build_date_from_params(:notified_at_start, @options)
|
||||
@options[:notified_at_end] = build_date_from_params(:notified_at_end, @options)
|
||||
@options[:updated_at_start] = build_date_from_params(:updated_at_start, @options)
|
||||
@options[:updated_at_end] = build_date_from_params(:updated_at_end, @options)
|
||||
@options[:project_version] = @options[:project_version].presence
|
||||
@options[:arch_id] = @options[:arch_id].present? ? @options[:arch_id].to_i : nil
|
||||
@options[:is_circle] = @options[:is_circle].present? ? @options[:is_circle] == "1" : nil
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class BuildList::Item < ActiveRecord::Base
|
||||
|
||||
belongs_to :build_list
|
||||
belongs_to :build_list, :touch => true
|
||||
|
||||
attr_protected :build_list_id
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class BuildListObserver < ActiveRecord::Observer
|
||||
observe :build_list
|
||||
|
||||
def before_update(record)
|
||||
if record.status_changed?
|
||||
record.started_at = Time.now if record.status == BuildServer::BUILD_STARTED
|
||||
if [BuildServer::BUILD_ERROR, BuildServer::SUCCESS].include? record.status
|
||||
# stores time interval beetwin build start and finish in seconds
|
||||
record.duration = record.current_duration
|
||||
|
||||
if record.status == BuildServer::SUCCESS
|
||||
# Update project average build time
|
||||
build_count = record.project.build_count
|
||||
new_av_time = ( record.project.average_build_time * build_count + record.duration ) / ( build_count + 1 )
|
||||
record.project.update_attributes({ :average_build_time => new_av_time, :build_count => build_count + 1 }, :without_protection => true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,23 +6,45 @@ class Comment < ActiveRecord::Base
|
|||
|
||||
validates :body, :user_id, :commentable_id, :commentable_type, :project_id, :presence => true
|
||||
|
||||
scope :for_commit, lambda {|c| where(:commentable_id => c.id.hex, :commentable_type => c.class)}
|
||||
default_scope order('created_at')
|
||||
|
||||
after_create :subscribe_on_reply, :unless => lambda {|c| c.commit_comment?}
|
||||
after_create :subscribe_users
|
||||
after_initialize do |comment|
|
||||
class_eval { def commentable; project.git_repository.commit(commentable_id.to_s(16)); end } if commit_comment?
|
||||
|
||||
attr_accessible :body
|
||||
|
||||
def commentable
|
||||
commit_comment? ? project.git_repository.commit(commentable_id.to_s(16)) : super
|
||||
end
|
||||
|
||||
attr_accessible :body, :commentable_id, :commentable_type
|
||||
attr_readonly :commentable_id, :commentable_type
|
||||
def commentable=(c)
|
||||
if self.class.commit_comment?(c.class)
|
||||
self.commentable_id = c.id.hex
|
||||
self.commentable_type = c.class.name
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def own_comment?(user)
|
||||
user_id == user.id
|
||||
def self.commit_comment?(class_name)
|
||||
class_name.to_s == 'Grit::Commit'
|
||||
end
|
||||
|
||||
def commit_comment?
|
||||
commentable_type == 'Grit::Commit'
|
||||
self.class.commit_comment?(commentable_type)
|
||||
end
|
||||
|
||||
def self.issue_comment?(class_name)
|
||||
class_name.to_s == 'Issue'
|
||||
end
|
||||
|
||||
def issue_comment?
|
||||
self.class.issue_comment?(commentable_type)
|
||||
end
|
||||
|
||||
def own_comment?(user)
|
||||
user_id == user.id
|
||||
end
|
||||
|
||||
def can_notify_on_new_comment?(subscribe)
|
||||
|
@ -32,19 +54,19 @@ class Comment < ActiveRecord::Base
|
|||
protected
|
||||
|
||||
def subscribe_on_reply
|
||||
self.commentable.subscribes.create(:user_id => self.user_id) if !self.commentable.subscribes.exists?(:user_id => self.user_id)
|
||||
commentable.subscribes.create(:user_id => user_id) if !commentable.subscribes.exists?(:user_id => user_id)
|
||||
end
|
||||
|
||||
def subscribe_users
|
||||
if self.commentable.class == Issue
|
||||
self.commentable.subscribes.create(:user => self.user) if !self.commentable.subscribes.exists?(:user_id => self.user.id)
|
||||
elsif self.commit_comment?
|
||||
recipients = self.project.relations.by_role('admin').where(:object_type => 'User').map &:object # admins
|
||||
recipients << self.user << User.where(:email => self.commentable.committer.email).first # commentor and committer
|
||||
recipients << self.project.owner if self.project.owner_type == 'User' # project owner
|
||||
if issue_comment?
|
||||
commentable.subscribes.create(:user => user) if !commentable.subscribes.exists?(:user_id => user.id)
|
||||
elsif commit_comment?
|
||||
recipients = project.relations.by_role('admin').where(:object_type => 'User').map &:object # admins
|
||||
recipients << user << User.where(:email => commentable.committer.email).first # commentor and committer
|
||||
recipients << project.owner if project.owner_type == 'User' # project owner
|
||||
recipients.compact.uniq.each do |user|
|
||||
options = {:project_id => self.project.id, :subscribeable_id => self.commentable_id, :subscribeable_type => self.commentable.class.name, :user_id => user.id}
|
||||
Subscribe.subscribe_to_commit(options) if Subscribe.subscribed_to_commit?(self.project, user, self.commentable)
|
||||
options = {:project_id => project.id, :subscribeable_id => commentable_id, :subscribeable_type => commentable.class.name, :user_id => user.id}
|
||||
Subscribe.subscribe_to_commit(options) if Subscribe.subscribed_to_commit?(project, user, commentable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,30 +4,28 @@ class Issue < ActiveRecord::Base
|
|||
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
belongs_to :creator, :class_name => 'User', :foreign_key => 'creator_id'
|
||||
belongs_to :assignee, :class_name => 'User', :foreign_key => 'assignee_id'
|
||||
belongs_to :closer, :class_name => 'User', :foreign_key => 'closed_by'
|
||||
|
||||
has_many :comments, :as => :commentable, :dependent => :destroy #, :finder_sql => proc { "comments.commentable_id = '#{self.id}' AND comments.commentable_type = '#{self.class.name}'"}
|
||||
has_many :subscribes, :as => :subscribeable, :dependent => :destroy #, :finder_sql => proc { "subscribes.subscribeable_id = '#{self.id}' AND subscribes.subscribeable_type = '#{self.class.name}'"}
|
||||
has_many :comments, :as => :commentable, :dependent => :destroy
|
||||
has_many :subscribes, :as => :subscribeable, :dependent => :destroy
|
||||
has_many :labels, :through => :labelings, :uniq => true
|
||||
has_many :labelings
|
||||
|
||||
validates :title, :body, :project_id, :presence => true
|
||||
|
||||
#attr_readonly :serial_id
|
||||
|
||||
after_create :set_serial_id
|
||||
after_create :subscribe_users
|
||||
after_update :subscribe_issue_assigned_user
|
||||
|
||||
attr_accessible :labelings_attributes, :title, :body, :user_id
|
||||
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")
|
||||
|
||||
def assign_uname
|
||||
user.uname if user
|
||||
assignee.uname if assignee
|
||||
end
|
||||
|
||||
def to_param
|
||||
|
@ -57,7 +55,7 @@ class Issue < ActiveRecord::Base
|
|||
|
||||
def collect_recipient_ids
|
||||
recipients = self.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) }
|
||||
recipients = recipients | [self.user_id] if self.user_id
|
||||
recipients = recipients | [self.assignee_id] if self.assignee_id
|
||||
recipients = recipients | [self.project.owner_id] if self.project.owner_type == 'User'
|
||||
|
||||
recipients
|
||||
|
@ -80,10 +78,10 @@ class Issue < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def subscribe_issue_assigned_user
|
||||
if self.user_id && self.user_id_changed?
|
||||
self.subscribes.where(:user_id => self.user_id_was).first.destroy unless self.user_id_was.blank?
|
||||
if self.user.notifier.issue_assign && !self.subscribes.exists?(:user_id => self.user_id)
|
||||
self.subscribes.create(:user_id => self.user_id)
|
||||
if self.assignee_id && self.assignee_id_changed?
|
||||
self.subscribes.where(:user_id => self.assignee_id_was).first.destroy unless self.assignee_id_was.blank?
|
||||
if self.assignee.notifier.issue_assign && !self.subscribes.exists?(:user_id => self.assignee_id)
|
||||
self.subscribes.create(:user_id => self.assignee_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,7 +29,7 @@ class Platform < ActiveRecord::Base
|
|||
after_update :update_owner_relation
|
||||
|
||||
scope :search_order, order("CHAR_LENGTH(name) ASC")
|
||||
scope :search, lambda {|q| where("name ILIKE ?", "%#{q.strip}%")}
|
||||
scope :search, lambda {|q| where("name ILIKE ?", "%#{q.to_s.strip}%")}
|
||||
scope :by_visibilities, lambda {|v| where(:visibility => v)}
|
||||
scope :opened, where(:visibility => 'open')
|
||||
scope :hidden, where(:visibility => 'hidden')
|
||||
|
|
|
@ -15,6 +15,10 @@ class Product < ActiveRecord::Base
|
|||
|
||||
scope :recent, order("name ASC")
|
||||
|
||||
attr_accessible :name, :counter, :ks, :menu, :tar, :cron_tab, :use_cron
|
||||
attr_accessible :description, :build_script, :delete_tar
|
||||
attr_readonly :platform_id
|
||||
|
||||
def delete_tar
|
||||
@delete_tar ||= "0"
|
||||
end
|
||||
|
|
|
@ -16,17 +16,20 @@ class ProductBuildList < ActiveRecord::Base
|
|||
|
||||
belongs_to :product
|
||||
|
||||
validates :product, :status, :presence => true
|
||||
validates :product_id, :status, :presence => true
|
||||
validates :status, :inclusion => { :in => [BUILD_STARTED, BUILD_COMPLETED, BUILD_FAILED] }
|
||||
|
||||
attr_accessor :base_url
|
||||
attr_accessible :status, :notified_at, :base_url
|
||||
attr_readonly :product_id
|
||||
|
||||
|
||||
scope :default_order, order('notified_at DESC')
|
||||
scope :for_status, lambda {|status| where(:status => status) }
|
||||
scope :for_user, lambda { |user| where(:user_id => user.id) }
|
||||
scope :scoped_to_product_name, lambda {|product_name| joins(:product).where('products.name LIKE ?', "%#{product_name}%")}
|
||||
scope :recent, order("#{table_name}.updated_at DESC")
|
||||
|
||||
attr_accessor :base_url
|
||||
|
||||
after_create :xml_rpc_create
|
||||
after_destroy :xml_delete_iso_container
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class Project < ActiveRecord::Base
|
|||
validates :name, :uniqueness => {:scope => [:owner_id, :owner_type], :case_sensitive => false}, :presence => true, :format => {:with => /^[a-zA-Z0-9_\-\+\.]+$/}
|
||||
validates :owner, :presence => true
|
||||
validate { errors.add(:base, :can_have_less_or_equal, :count => MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS }
|
||||
|
||||
|
||||
validates_attachment_size :srpm, :less_than => 500.megabytes
|
||||
validates_attachment_content_type :srpm, :content_type => ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], :message => I18n.t('layout.invalid_content_type')
|
||||
|
||||
|
@ -29,7 +29,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.strip}%")}
|
||||
scope :search, lambda {|q| by_name("%#{q.to_s.strip}%")}
|
||||
scope :by_name, lambda {|name| where('projects.name ILIKE ?', name)}
|
||||
scope :by_visibilities, lambda {|v| where(:visibility => v)}
|
||||
scope :opened, where(:visibility => 'open')
|
||||
|
@ -37,11 +37,12 @@ class Project < ActiveRecord::Base
|
|||
|
||||
after_create :attach_to_personal_repository
|
||||
after_create :create_git_repo
|
||||
after_create {|p| p.delay(:queue => 'fork', :priority => 20).fork_git_repo unless is_root?}
|
||||
after_save :create_wiki
|
||||
|
||||
after_destroy :destroy_git_repo
|
||||
after_destroy :destroy_wiki
|
||||
after_save {|p| p.delay.import_attached_srpm if p.srpm?} # should be after create_git_repo
|
||||
after_save {|p| p.delay(:queue => 'import', :priority => 10).import_attached_srpm if p.srpm?} # should be after create_git_repo
|
||||
# after_rollback lambda { destroy_git_repo rescue true if new_record? }
|
||||
|
||||
has_ancestry
|
||||
|
@ -50,18 +51,25 @@ class Project < ActiveRecord::Base
|
|||
|
||||
include Modules::Models::Owner
|
||||
|
||||
def build_for(platform, user, arch = 'i586') # Return i586 after mass rebuild
|
||||
def build_for(platform, user, arch = 'i586')
|
||||
# Select main and project platform repository(contrib, non-free and etc)
|
||||
# If main does not exist, will connect only project platform repository
|
||||
# If project platform repository is main, only main will be connect
|
||||
build_reps = [platform.repositories.find_by_name('main')]
|
||||
build_reps += platform.repositories.select {|rep| self.repository_ids.include? rep.id}
|
||||
build_ids = build_reps.compact.map(&:id).uniq
|
||||
|
||||
arch = Arch.find_by_name(arch) if arch.acts_like?(:string)
|
||||
build_lists.create do |bl|
|
||||
bl.pl = platform
|
||||
bl.bpl = platform
|
||||
bl.update_type = 'newpackage'
|
||||
bl.arch = arch
|
||||
bl.project_version = "latest_#{platform.name}" # "latest_import_mandriva2011"
|
||||
bl.project_version = "latest_#{platform.name}"
|
||||
bl.build_requires = false # already set as db default
|
||||
bl.user = user
|
||||
bl.auto_publish = true # already set as db default
|
||||
bl.include_repos = [platform.repositories.find_by_name('main').id]
|
||||
bl.include_repos = build_ids
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -117,6 +125,13 @@ class Project < ActiveRecord::Base
|
|||
tags.map(&:name) + branches.map{|b| "latest_#{b.name}"}
|
||||
end
|
||||
|
||||
def versions_for_group_select
|
||||
[
|
||||
['Branches', branches.map{|b| "latest_#{b.name}"}],
|
||||
['Tags', tags.map(&:name)]
|
||||
]
|
||||
end
|
||||
|
||||
def members
|
||||
collaborators + groups.map(&:members).flatten
|
||||
end
|
||||
|
@ -180,10 +195,6 @@ class Project < ActiveRecord::Base
|
|||
system("#{Rails.root.join('bin', 'import_srpm.sh')} #{srpm_path} #{path} #{branch_name} >> /dev/null 2>&1")
|
||||
end
|
||||
|
||||
def self.commit_comments(commit, project)
|
||||
comments = Comment.where(:commentable_id => commit.id.hex, :commentable_type => 'Grit::Commit')
|
||||
end
|
||||
|
||||
def owner?(user)
|
||||
owner == user
|
||||
end
|
||||
|
@ -199,6 +210,11 @@ class Project < ActiveRecord::Base
|
|||
recipients
|
||||
end
|
||||
|
||||
def human_average_build_time
|
||||
time = average_build_time
|
||||
I18n.t("layout.projects.human_average_build_time", {:hours => (time/3600).to_i, :minutes => (time%3600/60).to_i})
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_path(dir)
|
||||
|
@ -214,8 +230,15 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def create_git_repo
|
||||
is_root? ? Grit::Repo.init_bare(path) : parent.git_repository.repo.delay.fork_bare(path)
|
||||
write_hook.delay
|
||||
if is_root?
|
||||
Grit::Repo.init_bare(path)
|
||||
write_hook.delay(:queue => 'fork', :priority => 15)
|
||||
end
|
||||
end
|
||||
|
||||
def fork_git_repo
|
||||
dummy = Grit::Repo.new(path) rescue parent.git_repository.repo.fork_bare(path)
|
||||
write_hook
|
||||
end
|
||||
|
||||
def destroy_git_repo
|
||||
|
@ -248,7 +271,7 @@ class Project < ActiveRecord::Base
|
|||
hook = File.join(::Rails.root.to_s, 'tmp', "post-receive-hook")
|
||||
FileUtils.cp(File.join(::Rails.root.to_s, 'bin', "post-receive-hook.partial"), hook)
|
||||
File.open(hook, 'a') do |f|
|
||||
s = "\n /bin/bash -l -c \"cd #{is_production ? '/srv/rosa_build/current' : Rails.root.to_s} && #{is_production ? 'RAILS_ENV=production' : ''} bundle exec rails runner 'Project.delay.process_hook(\\\"$owner\\\", \\\"$reponame\\\", \\\"$newrev\\\", \\\"$oldrev\\\", \\\"$ref\\\", \\\"$newrev_type\\\", \\\"$oldrev_type\\\")'\""
|
||||
s = "\n /bin/bash -l -c \"cd #{is_production ? '/srv/rosa_build/current' : Rails.root.to_s} && #{is_production ? 'RAILS_ENV=production' : ''} bundle exec rails runner 'Project.delay(:queue => \\\"hook\\\").process_hook(\\\"$owner\\\", \\\"$reponame\\\", \\\"$newrev\\\", \\\"$oldrev\\\", \\\"$ref\\\", \\\"$newrev_type\\\", \\\"$oldrev_type\\\")'\""
|
||||
s << " > /dev/null 2>&1" if is_production
|
||||
s << "\ndone\n"
|
||||
f.write(s)
|
||||
|
|
|
@ -5,7 +5,7 @@ class User < ActiveRecord::Base
|
|||
LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last)
|
||||
MAX_AVATAR_SIZE = 5.megabyte
|
||||
|
||||
devise :database_authenticatable, :registerable, :omniauthable, # :token_authenticatable, :encryptable, :timeoutable
|
||||
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'},
|
||||
|
@ -55,6 +55,7 @@ class User < ActiveRecord::Base
|
|||
include Modules::Models::ActsLikeMember
|
||||
|
||||
after_create lambda { self.create_notifier }
|
||||
before_create :ensure_authentication_token
|
||||
|
||||
def admin?
|
||||
role == 'admin'
|
||||
|
|
|
@ -30,10 +30,10 @@ class CommentPresenter < ApplicationPresenter
|
|||
def buttons
|
||||
project = options[:project]
|
||||
commentable = options[:commentable]
|
||||
(ep, dp) = if commentable.class == Issue
|
||||
(ep, dp) = if Comment.issue_comment?(commentable.class)
|
||||
[edit_project_issue_comment_path(project, commentable, comment),
|
||||
project_issue_comment_path(project, commentable, comment)]
|
||||
elsif commentable.class == Grit::Commit
|
||||
elsif Comment.commit_comment?(commentable.class)
|
||||
[edit_project_commit_comment_path(project, commentable, comment),
|
||||
project_commit_comment_path(project, commentable, comment)]
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- @activity_feeds.each do |activity_feed|
|
||||
.activity
|
||||
.activity{:id => "#feed#{activity_feed.id}"}
|
||||
= render_activity_feed(activity_feed)
|
||||
- if @activity_feeds.next_page
|
||||
%a{:href => root_path({:filter => @filter, :page => @activity_feeds.next_page}), :class => 'more_activities'}
|
||||
.messages.messages-last=t('layout.activity_feed.load_messages')
|
||||
.messages.messages-last=t('layout.activity_feed.load_messages')
|
||||
|
|
|
@ -18,30 +18,15 @@
|
|||
%td
|
||||
= link_to t("layout.activity_feed.all_my_projects"), projects_path
|
||||
.block
|
||||
- midnight = Time.new.midnight
|
||||
- midnight = Date.today
|
||||
%h3= t("layout.activity_feed.my_builds_by_day")
|
||||
%table{:cellpadding => "0", :cellspacing => "0"}
|
||||
%tbody
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{:build_published}"), build_lists_path(:filter => {:status => BuildList::BUILD_PUBLISHED, :notified_at => midnight})
|
||||
%td= BuildList.for_status(BuildList::BUILD_PUBLISHED).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{:success}"), build_lists_path(:filter => {:status => BuildServer::SUCCESS, :notified_at => midnight})
|
||||
%td= BuildList.for_status(BuildServer::SUCCESS).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{:build_started}"), build_lists_path(:filter => {:status => BuildServer::BUILD_STARTED, :notified_at => midnight})
|
||||
%td= BuildList.for_status(BuildServer::BUILD_STARTED).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{:build_pending}"), build_lists_path(:filter => {:status => BuildList::BUILD_PENDING, :notified_at => midnight})
|
||||
%td= BuildList.for_status(BuildList::BUILD_PENDING).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{:build_error}"), build_lists_path(:filter => {:status => BuildServer::BUILD_ERROR, :notified_at => midnight})
|
||||
%td= BuildList.for_status(BuildServer::BUILD_ERROR).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
- ['BuildList::BUILD_PUBLISHED', 'BuildServer::SUCCESS', 'BuildServer::BUILD_STARTED', 'BuildList::BUILD_PENDING', 'BuildServer::BUILD_ERROR'].each do |state|
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.build_lists.statuses.#{state.demodulize.downcase}"), build_lists_path(:filter => {:status => state.constantize, :'updated_at_start(1i)' => midnight.year, :'updated_at_start(2i)' => midnight.month, :'updated_at_start(3i)' => midnight.day})
|
||||
%td= BuildList.for_status(state.constantize).for_user(current_user).for_notified_date_period(midnight, nil).count
|
||||
%tr
|
||||
%td.first
|
||||
= link_to t("layout.activity_feed.all_my_builds"), build_lists_path
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
atom_feed do |feed|
|
||||
feed.title(t("layout.activity_feed.atom_title"))
|
||||
feed.updated(@activity_feeds[0].created_at) if @activity_feeds.length > 0
|
||||
|
||||
@activity_feeds.each do |activity_feed|
|
||||
feed.entry(activity_feed, :url => root_url(:anchor => "feed#{activity_feed.id}")) do |entry|
|
||||
feed_content = raw(render(:inline => true, :partial => activity_feed.partial, :locals => activity_feed.data.merge(:activity_feed => activity_feed)))
|
||||
|
||||
entry.title(truncate(get_feed_title_from_content(feed_content), :length => 50))
|
||||
entry.content(feed_content, :type => 'html')
|
||||
|
||||
entry.author do |author|
|
||||
author.name(activity_feed.data[:user_name])
|
||||
author.email(activity_feed.data[:user_email])
|
||||
end if activity_feed.kind != 'git_delete_branch_notification'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,5 +15,5 @@
|
|||
- else ['failed', t("layout.build_lists.statuses.#{BuildList::HUMAN_STATUSES[status]}")]
|
||||
= raw t("notifications.bodies.build_status.#{message}", :error => error)
|
||||
.both
|
||||
%span.date= notified_at
|
||||
%span.date= updated_at
|
||||
.both
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
%td= build_list.arch.name
|
||||
%td= link_to build_list.user.try(:fullname), build_list.user
|
||||
%td= link_to image_tag('x.png', :class => 'delete-row', :id => "delete-row#{build_list_counter}"), cancel_build_list_path(build_list), :method => :put, :confirm => t('layout.confirm') if build_list.can_cancel? and can?(:cancel, build_list)
|
||||
%td= build_list.notified_at
|
||||
%td= build_list.updated_at
|
||||
|
|
|
@ -47,14 +47,14 @@
|
|||
.date_select= f.date_select(:created_at_start, :include_blank => true, :selected => @filter.created_at_start)
|
||||
%h3.small= t("layout.build_lists.created_at_end")
|
||||
.date_select= f.date_select(:created_at_end, :include_blank => true, :selected => @filter.created_at_end)
|
||||
%h3.small= t("layout.build_lists.notified_at_start")
|
||||
.date_select= f.date_select(:notified_at_start, :include_blank => true, :selected => @filter.notified_at_start)
|
||||
%h3.small= t("layout.build_lists.notified_at_end")
|
||||
.date_select= f.date_select(:notified_at_end, :include_blank => true, :selected => @filter.notified_at_end)
|
||||
%h3.small= t("layout.build_lists.updated_at_start")
|
||||
.date_select= f.date_select(:updated_at_start, :include_blank => true, :selected => @filter.updated_at_start)
|
||||
%h3.small= t("layout.build_lists.updated_at_end")
|
||||
.date_select= f.date_select(:updated_at_end, :include_blank => true, :selected => @filter.updated_at_end)
|
||||
%h3.small= t("layout.build_lists.project_name_search")
|
||||
= f.text_field :project_name
|
||||
%h3.small= t("layout.build_lists.bs_id_search")
|
||||
= f.text_field :bs_id
|
||||
%br
|
||||
%br
|
||||
= f.submit t("layout.search.header")
|
||||
= f.submit t("layout.search.header")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- platform.repositories.each do |repo|
|
||||
.both
|
||||
= check_box_tag "build_list[include_repos][]", repo.id, repo.name == 'main' || @project.repositories.map(&:id).include?(repo.id), :id => "include_repos_#{repo.id}" # (params[:build_list]||[]).fetch(:include_repos, []).include?(repo.id.to_s)
|
||||
= label_tag "include_repos_#{repo.id}", repo.name
|
||||
= check_box_tag "build_list[include_repos][]", repo.id, repo.name == 'main' || @project.repositories.map(&:id).include?(repo.id), :id => "include_repos_#{repo.id}", :pl_id => platform.id, :rep_name => repo.name
|
||||
= label_tag "include_repos_#{repo.id}", repo.name
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
%td= link_to (platform_build_list.bs_id.present? ? platform_build_list.bs_id : t("layout.build_lists.bs_id_not_set")), platform_build_list
|
||||
%td= platform_build_list.human_status
|
||||
%td= link_to platform_build_list.project.name, platform_build_list.project
|
||||
%td= platform_build_list.notified_at
|
||||
%td= platform_build_list.updated_at
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
%th.lpadding16= t("activerecord.attributes.build_list.arch")
|
||||
%th.lpadding16= t("activerecord.attributes.build_list.user")
|
||||
%th= t("layout.build_lists.action")
|
||||
%th.lpadding16= t("activerecord.attributes.build_list.notified_at")
|
||||
%th.lpadding16= t("activerecord.attributes.build_list.updated_at")
|
||||
%tbody= render @build_lists
|
||||
.both
|
||||
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
-set_meta_tags :title => [title_object(@project), t('layout.build_lists.new_header')]
|
||||
= form_for [@project, @build_list], :html => { :class => :form, :method => :post } do |f|
|
||||
%section.left
|
||||
%h3= t("activerecord.attributes.build_list.project_version")
|
||||
.lineForm= f.select :project_version, @project.versions
|
||||
%h3= t("activerecord.attributes.build_list.bpl")
|
||||
.all_platforms
|
||||
- Platform.main.each do |pl|
|
||||
- if pl.repository_ids.size > 0
|
||||
.both
|
||||
= check_box_tag "bpls[]", pl.id, (params[:bpls]||[]).include?(pl.id.to_s), :class => 'build_bpl_ids', :id => "bpls_#{pl.id}"
|
||||
= check_box_tag "bpls[]", pl.id, (params[:bpls]||[]).include?(pl.id.to_s), :class => 'build_bpl_ids', :id => "bpls_#{pl.id}", :'data-released' => pl.released ? 1 : 0
|
||||
= label_tag "bpls_#{pl.id}", pl.name
|
||||
.offset25{:style => 'padding-left: 25px'}
|
||||
= render 'include_repos', :platform => pl
|
||||
%section.right
|
||||
%h3= t("activerecord.attributes.build_list.pl")
|
||||
.lineForm= f.select :pl_id, @project.repositories.collect{|r| ["#{r.platform.name}/#{r.name}", r.platform.id]}
|
||||
%h3= t("activerecord.attributes.build_list.project_version")
|
||||
- if controller.action_name == 'new'
|
||||
.lineForm= f.select :project_version, @project.versions_for_group_select, :selected => "latest_" + @project.default_branch
|
||||
- else
|
||||
.lineForm= f.select :project_version, @project.versions_for_group_select
|
||||
%h3= t("activerecord.attributes.build_list.arch")
|
||||
- Arch.recent.each do |arch|
|
||||
.both
|
||||
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}"
|
||||
- if controller.action_name == 'new'
|
||||
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}", :checked => 'checked'
|
||||
- else
|
||||
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}"
|
||||
= label_tag "arches_#{arch.id}", arch.name
|
||||
%h3= t("activerecord.attributes.build_list.pl")
|
||||
.lineForm= f.select :pl_id, @project.repositories.collect{|r| ["#{r.platform.name}/#{r.name}", r.platform.id]}
|
||||
%h3= t("activerecord.attributes.build_list.update_type")
|
||||
.lineForm= f.select :update_type, BuildList::UPDATE_TYPES
|
||||
%h3= t("activerecord.attributes.build_list.preferences")
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
= link_to @build_list.user.try(:fullname), @build_list.user
|
||||
.both
|
||||
= link_to t("layout.publish"), publish_build_list_path(@build_list), :method => "put", :confirm => t("layout.confirm"), :class => "button tmargin10" if @build_list.can_publish? and can?(:publish, @build_list)
|
||||
= link_to t("layout.reject_publish"), reject_publish_build_list_path(@build_list), :method => "put", :confirm => t("layout.confirm"), :class => "button tmargin10" if @build_list.can_reject_publish? and can?(:reject_publish, @build_list)
|
||||
.hr
|
||||
%h3= t("layout.build_lists.main_data")
|
||||
.leftside.width125= t("activerecord.attributes.build_list.bpl")
|
||||
|
@ -46,12 +47,24 @@
|
|||
.leftside.width125= t("activerecord.attributes.build_list.arch")
|
||||
.leftside= @build_list.arch.name
|
||||
.both
|
||||
.leftside.width125= t("activerecord.attributes.build_list.notified_at")
|
||||
.leftside= @build_list.notified_at
|
||||
.leftside.width125= t("activerecord.attributes.build_list.updated_at")
|
||||
.leftside= @build_list.updated_at
|
||||
.both
|
||||
.leftside.width125= t("activerecord.attributes.build_list.is_circle")
|
||||
.leftside= t("layout.#{@build_list.is_circle?}_")
|
||||
.both
|
||||
- if !@build_list.in_work? && @build_list.started_at
|
||||
%br
|
||||
.leftside.width125
|
||||
.leftside= @build_list.human_duration
|
||||
.both
|
||||
- if @build_list.in_work?
|
||||
%br
|
||||
.leftside.width125
|
||||
.leftside
|
||||
= "#{@build_list.human_current_duration} / #{@build_list.project.human_average_build_time}"
|
||||
.both
|
||||
|
||||
.hr
|
||||
%h3= t("layout.build_lists.items_header")
|
||||
- if @item_groups.blank?
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#open-comment.comment.view
|
||||
%h3.tmargin0= t("layout.comments.new_header")
|
||||
- if commentable.class == Issue
|
||||
- if Comment.issue_comment?(commentable.class)
|
||||
- new_path = project_issue_comments_path(project, commentable)
|
||||
- is_subscribed = commentable.subscribes.exists?(:user_id => current_user.id)
|
||||
- subscribe_path = is_subscribed ? project_issue_subscribe_path(project, commentable, current_user.id) : project_issue_subscribes_path(project, commentable)
|
||||
- else commentable.class == Grit::Commit
|
||||
- else Comment.commit_comment?(commentable.class)
|
||||
- new_path = project_commit_comments_path(project, commentable)
|
||||
- is_subscribed = Subscribe.subscribed_to_commit?(project, current_user, commentable)
|
||||
- subscribe_path = is_subscribed ? unsubscribe_commit_path(project, commentable) : subscribe_commit_path(project, commentable)
|
||||
|
|
|
@ -1,14 +1,2 @@
|
|||
.wrapper
|
||||
= f.text_area :body, :cols => 80
|
||||
.comment-right
|
||||
= submit_tag t("layout.save")
|
||||
-#.group
|
||||
= f.label :body, t("activerecord.attributes.comment.body"), :class => :label
|
||||
= f.text_area :body, :class => 'text_field', :cols => 80
|
||||
|
||||
-#.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("choose.png", :alt => t("layout.save"))
|
||||
= t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), @commentable_path , :class => "text_button_padding link_button"
|
||||
.wrapper= f.text_area :body, :cols => 80
|
||||
.comment-right= submit_tag t("layout.save")
|
|
@ -3,37 +3,4 @@
|
|||
%h3= t("layout.comments.comments_header")
|
||||
- list.each do |comment|
|
||||
- CommentPresenter.present(comment, :project => project, :commentable => commentable) do |presenter|
|
||||
= render :partial => 'shared/feed_message', :locals => {:presenter => presenter}
|
||||
-#.block#block-list
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.comments_header")
|
||||
.inner
|
||||
%ul.list
|
||||
- list.each do |comment|
|
||||
%li
|
||||
.left
|
||||
= link_to comment.user.uname, user_path(comment.user.uname)
|
||||
.item
|
||||
= comment.body
|
||||
%br
|
||||
%br
|
||||
- if commentable.class == Issue
|
||||
- edit_path = edit_project_issue_comment_path(project, commentable, comment)
|
||||
- delete_path = project_issue_comment_path(project, commentable, comment)
|
||||
- elsif commentable.class == Grit::Commit
|
||||
- edit_path = edit_project_commit_comment_path(project, commentable, comment)
|
||||
- delete_path = project_commit_comment_path(project, commentable, comment)
|
||||
= link_to t("layout.edit"), edit_path if can? :update, comment
|
||||
=# link_to image_tag("x.png", :alt => t("layout.delete")) + " " + t("layout.delete"), delete_path, :method => "delete", :class => "button", :confirm => t("layout.comments.confirm_delete") if can? :delete, comment
|
||||
= link_to t("layout.delete"), delete_path, :method => "delete", :confirm => t("layout.comments.confirm_delete") if can? :delete, comment
|
||||
|
||||
-#.block
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.comments.new_header")
|
||||
.inner
|
||||
- new_path = project_issue_comments_path(project, commentable) if commentable.class == Issue
|
||||
- new_path = project_commit_comments_path(project, commentable) if commentable.class == Grit::Commit
|
||||
= form_for :comment, :url => new_path, :method => :post, :html => { :class => :form } do |f|
|
||||
= render :partial => "comments/form", :locals => {:f => f}
|
||||
= render :partial => 'shared/feed_message', :locals => {:presenter => presenter}
|
|
@ -2,10 +2,10 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.comments.back"), @commentable_path
|
||||
%li.first= link_to t("layout.comments.back"), project_commentable_path(@project, @commentable)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.comments.edit_header")
|
||||
.inner
|
||||
= form_for @comment, :url => @update_url, :html => { :class => :form } do |f|
|
||||
= form_for @comment, :url => project_commentable_comment_path(@project, @commentable, @comment), :html => {:class => :form} do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
%nav
|
||||
%a{:href => new_register_request_path}
|
||||
%p=t("layout.devise.shared_links.sign_up")
|
||||
/ Top block
|
||||
%header
|
||||
.logo
|
||||
/ Page
|
||||
%article
|
||||
%br
|
||||
%h1= title t('devise.passwords.edit')
|
||||
|
@ -17,11 +15,11 @@
|
|||
= f.hidden_field :reset_password_token
|
||||
.left.first=t('activerecord.attributes.user.password')
|
||||
.right.first
|
||||
= f.text_field :password, :id => 'password', :class => "registartion-input #{password_error ? 'registartion-input-error' : ''}"
|
||||
= f.password_field :password, :id => 'password', :class => "registartion-input #{password_error ? 'registartion-input-error' : ''}"
|
||||
.both
|
||||
.left=t('activerecord.attributes.user.password_confirm')
|
||||
.right
|
||||
= f.text_field :password_confirmation, :id => 'password2', :class => "registartion-input #{password_error ? 'registartion-input-error' : ''}"
|
||||
= f.password_field :password_confirmation, :id => 'password2', :class => "registartion-input #{password_error ? 'registartion-input-error' : ''}"
|
||||
.both
|
||||
%br
|
||||
=f.submit t("devise.passwords.edit_button"), :class => 'button', :id => 'btnLogin'
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
.block
|
||||
.content
|
||||
%h2.title
|
||||
= title t("layout.downloads.title")
|
||||
.inner
|
||||
%h3= t("layout.downloads.message")
|
||||
.inner
|
||||
%table.table
|
||||
%tr
|
||||
%th.first= t("activerecord.attributes.download.name")
|
||||
%th= t("activerecord.attributes.download.version")
|
||||
%th= t("activerecord.attributes.download.distro")
|
||||
%th= t("activerecord.attributes.download.platform")
|
||||
%th.last= t("activerecord.attributes.download.counter")
|
||||
- @downloads.each do |download|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td
|
||||
= download.name
|
||||
%td
|
||||
= download.version
|
||||
%td
|
||||
= download.distro
|
||||
%td
|
||||
= download.platform
|
||||
%td.last
|
||||
= download.counter
|
||||
.actions-bar.wat-cf
|
||||
.actions
|
||||
= will_paginate @downloads
|
||||
= render 'admin/submenu'
|
|
@ -16,5 +16,5 @@
|
|||
#repo-wrapper
|
||||
= render :partial => 'show'
|
||||
|
||||
= render :partial => "comments/list", :locals => {:list => Project.commit_comments(@commit, @project), :project => @project, :commentable => @commit}
|
||||
= render :partial => "comments/list", :locals => {:list => Comment.for_commit(@commit), :project => @project, :commentable => @commit}
|
||||
= render :partial => "comments/add", :locals => {:project => @project, :commentable => @commit} if current_user
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
- if owner.projects.exists? :name => @project.name
|
||||
- is_group = owner.class == Group ? "(#{t 'activerecord.models.group'})" : ''
|
||||
%p.center
|
||||
=t 'layout.projects.already_exists'
|
||||
=link_to "#{owner.uname}/#{@project.name} #{is_group}", project_path(owner.projects.by_name(@project.name).first.id)
|
||||
- else
|
||||
= form_for @project, :url => fork_project_path(@project), :html => { :class => :form, :multipart => true, :method => :post } do |f|
|
||||
= hidden_field_tag :group, owner.id if owner.class == Group
|
||||
=f.submit t('layout.projects.fork_to', :to => "#{owner.uname} #{is_group}"), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_fork'
|
||||
|
||||
:javascript
|
||||
$('#create_fork').click(function () {
|
||||
$(this).button('loading');
|
||||
})
|
|
@ -1,2 +1,11 @@
|
|||
- if can? :fork, @project
|
||||
.r#fork-and-edit= link_to t('layout.projects.fork_and_edit'), fork_project_path(@project), :method => :post, :confirm => t("layout.confirm"), :class => 'button'
|
||||
.r#fork-and-edit= link_to t('layout.projects.fork_and_edit'), '#forkModal', :class => 'button', 'data-toggle' => 'modal'
|
||||
#forkModal.modal{:style => 'display: none;'}
|
||||
.modal-header
|
||||
%a.close{"data-dismiss" => "modal"} ×
|
||||
%h3=t 'layout.projects.fork_modal_header'
|
||||
.modal-footer=render :partial => 'git/shared/choose_fork', :locals => {:owner => current_user}
|
||||
- Group.can_own_project(current_user).each do |group|
|
||||
.modal-footer=render :partial => 'git/shared/choose_fork', :locals => {:owner => group}
|
||||
- if can? :create, @project.build_lists.new
|
||||
.r{:style => "display: block"}= link_to t('layout.projects.new_build_list'), new_project_build_list_path(@project), :class => 'button'
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
.leftlist= t('activerecord.attributes.issue.body') + ':'
|
||||
.rightlist= f.text_area :body
|
||||
.both
|
||||
.leftlist= t('activerecord.attributes.issue.user') + ':'
|
||||
.leftlist= t('activerecord.attributes.issue.assignee') + ':'
|
||||
.rightlist
|
||||
%span#people-span.small-text= t('layout.issues.choose_user_on_left')
|
||||
#issue_executor
|
||||
#issue_assignee
|
||||
.both
|
||||
.leftlist= t('layout.issues.labels')
|
||||
.leftlist= t('layout.issues.labels') + ':'
|
||||
.rightlist
|
||||
%span#flag-span.small-text= t('layout.issues.choose_labels_on_left')
|
||||
#issue_labels
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
%tr
|
||||
%td=radio_button_tag :myradio, 'to_me', @is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'}
|
||||
%td=t("layout.issues.to_me")
|
||||
%td.width30.right=@project.issues.where(:user_id => current_user).count
|
||||
%td.width30.right=@project.issues.where(:assignee_id => current_user.id).count
|
||||
=form_tag project_issues_path(@project), :id => 'search_issue', :method => :get do
|
||||
.bordered.bpadding20
|
||||
=tracker_search_field(:search_issue, t('layout.issues.search'))
|
||||
|
|
|
@ -7,15 +7,15 @@
|
|||
%div.issue_title=issue.title
|
||||
.smalltext
|
||||
=issue.created_at.to_s(:long)
|
||||
=t("layout.by") if issue.creator
|
||||
=link_to(issue.creator.uname, user_path(issue.creator)) if issue.creator
|
||||
=t("layout.by") if issue.user
|
||||
=link_to(issue.user.uname, user_path(issue.user)) if issue.user
|
||||
-issue.labels.each do |label|
|
||||
.left.nomargin
|
||||
.label.selected.tracker.left
|
||||
.labeltext.selected{:style => "background: ##{label.color};"}=label.name
|
||||
%td.td3
|
||||
.avatar
|
||||
=link_to image_tag(avatar_url(issue.user), :alt => 'avatar'), user_path(issue.user) if issue.user
|
||||
=link_to image_tag(avatar_url(issue.assignee), :alt => 'avatar'), user_path(issue.assignee) if issue.assignee
|
||||
%a{:href => "#{project_issue_path @project, issue}#block-list"}
|
||||
.answers
|
||||
.pic= image_tag 'answers.png'
|
||||
|
|
|
@ -10,30 +10,30 @@
|
|||
=form_tag [@project, @issue], :id => 'update_issue_status', :method => :put do
|
||||
=hidden_field_tag "issue_status", @issue.closed? ? 'closed' : 'open', :name => "issue[status]"
|
||||
.bordered.nopadding
|
||||
%h3=t('layout.issues.executor')
|
||||
%h3=t('layout.issues.assignee')
|
||||
- if @issue.persisted?
|
||||
-if can_manage
|
||||
=form_for :issue, :url => [@project, @issue], :method => :put, :html => { :class => 'edit_executor issue'} do |f|
|
||||
=hidden_field_tag "user-default_executor", nil, :name => 'issue[user_id]'
|
||||
.current_executor
|
||||
- if @issue.user
|
||||
=form_for :issue, :url => [@project, @issue], :method => :put, :html => { :class => 'edit_assignee issue'} do |f|
|
||||
=hidden_field_tag "user-default_assignee", nil, :name => 'issue[assignee_id]'
|
||||
.current_assignee
|
||||
- if @issue.assignee
|
||||
#user-0.people.nopointer
|
||||
.avatar=image_tag avatar_url(@issue.user), :alt => 'avatar'
|
||||
.name="#{@issue.user.uname} (#{@issue.user.name})"
|
||||
=hidden_field_tag "user-0", @issue.user.id, :name => 'issue[user_id]'
|
||||
.avatar=image_tag avatar_url(@issue.assignee), :alt => 'avatar'
|
||||
.name="#{@issue.user.uname} (#{@issue.assignee.name})"
|
||||
=hidden_field_tag "user-0", @issue.assignee.id, :name => 'issue[assignee_id]'
|
||||
.both
|
||||
- elsif @issue.user
|
||||
- elsif @issue.assignee
|
||||
.people.nopointer
|
||||
.avatar=image_tag avatar_url(@issue.user), :alt => 'avatar'
|
||||
.name="#{@issue.user.uname} (#{@issue.user.name})"
|
||||
.avatar=image_tag avatar_url(@issue.assignee), :alt => 'avatar'
|
||||
.name="#{@issue.assignee.uname} (#{@issue.assignee.name})"
|
||||
.both
|
||||
=link_to(t('layout.issues.label_manage'), '#', :class => "button tmargin10 manage_executor") if can_manage
|
||||
=link_to(t('layout.issues.label_manage'), '#', :class => "button tmargin10 manage_assignee") if can_manage
|
||||
- if can_manage
|
||||
=form_tag search_collaborators_project_issues_path(@project), :id => 'search_user', :method => :get, :style => @issue.persisted? ? 'display:none' : '' do
|
||||
=tracker_search_field(:search_user, t('layout.issues.search_user'))
|
||||
#manage_issue_users_list
|
||||
=render 'issues/search_collaborators'
|
||||
=link_to(t('layout.issues.done'), '#', :class => "button tmargin10 update_executor", :style => 'display:none') if can_manage
|
||||
=link_to(t('layout.issues.done'), '#', :class => "button tmargin10 update_assignee", :style => 'display:none') if can_manage
|
||||
|
||||
.block
|
||||
%h3=t('layout.issues.labels')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- (@users || []).each_with_index do |user, index|
|
||||
.people.selected{:id => "user-#{index}", :class => 'add_executor'}
|
||||
.people.selected{:id => "user-#{index}", :class => 'add_assignee'}
|
||||
.avatar= image_tag(avatar_url(user), :alt => 'avatar')
|
||||
.name="#{user.uname} (#{user.name})"
|
||||
=hidden_field_tag "user-#{index}", user.id, :name => 'issue[user_id]'
|
||||
=hidden_field_tag "user-#{index}", user.id, :name => 'issue[assignee_id]'
|
||||
.both
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
.activity
|
||||
.top
|
||||
.image
|
||||
=image_tag(avatar_url(@issue.creator, :medium), :alt => 'avatar') if @issue.creator
|
||||
=image_tag(avatar_url(@issue.user, :medium), :alt => 'avatar') if @issue.user
|
||||
.text
|
||||
%span.name=link_to("#{@issue.creator.uname} (#{@issue.creator.name})", user_path(@issue.creator)) if @issue.creator
|
||||
%span.name=link_to("#{@issue.user.uname} (#{@issue.user.name})", user_path(@issue.user)) if @issue.user
|
||||
%br/
|
||||
%span.date=@issue.created_at.to_s(:long)
|
||||
%br/
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
= javascript_include_tag "application"
|
||||
= csrf_meta_tag
|
||||
= display_meta_tags :site => APP_CONFIG['project_name'], :reverse => true, :separator => '-'
|
||||
- if user_signed_in?
|
||||
= auto_discovery_link_tag :atom, root_path(:format => 'atom', :token => current_user.authentication_token), :title => t("layout.atom_link_tag_title", :nickname => current_user.name, :app_name => APP_CONFIG['project_name'])
|
||||
|
||||
%body
|
||||
.wrap{:class => content_for?(:sidebar) ? 'columns' : ''}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
%table.tablesorter{:cellpadding => "0", :cellspacing => "0"}
|
||||
%thead
|
||||
%tr
|
||||
-#%th.lpadding16= t("activerecord.attributes.product_build_list.bs_id")
|
||||
%th.lpadding16= t("activerecord.attributes.product_build_list.id")
|
||||
%th.lpadding16= t("activerecord.attributes.product_build_list.status")
|
||||
%th.lpadding16= t("activerecord.attributes.product_build_list.container_path")
|
||||
|
|
|
@ -37,16 +37,9 @@
|
|||
|
||||
= render :partial => "products/crontab", :locals => { :form => f }
|
||||
|
||||
- content_for :commented do
|
||||
.leftlist= f.label :system_wide, :class => :label
|
||||
.rightlist= f.check_box :system_wide, :class => 'check_box'
|
||||
|
||||
.both
|
||||
.button_block
|
||||
= submit_tag t("layout.save")
|
||||
-#%input.button{:type => "submit", :class => "button"}
|
||||
-#= image_tag("choose.png", :alt => t("layout.save"))
|
||||
-#= t("layout.clone")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), @product.new_record? ? platform_path(@platform) : platform_product_path(@platform, @product), :class => "button"
|
||||
|
||||
|
|
|
@ -10,15 +10,3 @@
|
|||
= form_for [@platform, @product], :html => { :class => :form, :multipart => true } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
||||
|
||||
-#.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to @platform.name, platform_path(@platform) + "#products"
|
||||
%li.active= link_to @product.name, edit_platform_product_path(@platform, @product)
|
||||
.content
|
||||
%h2.title= t("layout.products.edit_header")
|
||||
.inner
|
||||
= form_for [@platform, @product], :html => { :class => :form, :multipart => true } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
||||
|
||||
-#- content_for :sidebar, render(:partial => 'sidebar')
|
||||
|
|
|
@ -4,16 +4,4 @@
|
|||
|
||||
= form_for [@platform, @product], :html => { :class => :form, :multipart => true } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
||||
|
||||
-#.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to @platform.name, platform_path(@platform) + "#products"
|
||||
%li.active= link_to t("layout.products.new"), new_platform_product_path(@platform)
|
||||
.content
|
||||
%h2.title= t("layout.products.new_header")
|
||||
.inner
|
||||
= form_for [@platform, @product], :html => { :class => :form, :multipart => true } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
||||
|
||||
-#- content_for :sidebar, render(:partial => 'sidebar')
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
= link_to image_tag("code.png", :alt => t("layout.edit")) + " " + t("layout.edit"), edit_platform_product_path(@platform, @product), :class => "button"
|
||||
- if can? :destroy, @product
|
||||
= link_to image_tag("x.png", :alt => t("layout.delete")) + " " + t("layout.delete"), platform_product_path(@platform, @product), :method => "delete", :class => "button", :confirm => t("layout.products.confirm_delete")
|
||||
-# if @product.can_clone?
|
||||
=# link_to t("layout.products.clone"), clone_platform_product_path(@platform, @product), :class => "button"
|
||||
- if can?(:create, @product.product_build_lists.build)
|
||||
= link_to t("layout.products.build"), platform_product_product_build_lists_path(@platform, @product), :class => "button", :method => 'post', :confirm => t("layout.confirm")
|
||||
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
.description-top
|
||||
%ul.nav.zip
|
||||
%li#menu-archive.dropdown
|
||||
%a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#menu-archive"}
|
||||
=image_tag 'zip.png', :alt => 'ZIP'
|
||||
%b.caret
|
||||
%ul.dropdown-menu
|
||||
%li=link_to "tar.gz", archive_path(project.id, 'tar', @treeish)
|
||||
%li=link_to "zip", archive_path(project.id, 'zip', @treeish)
|
||||
|
||||
= text_field_tag :url, git_repo_url(project.git_repo_name), :class => 'name', :spellcheck => 'false', :readonly => true
|
||||
.git_help ?
|
||||
.role= can?(:write, project) ? t("layout.read_write_access") : t("layout.read_access")
|
||||
= render :partial => 'projects/branch_select', :locals => {:project => project}
|
||||
#git_help_data
|
||||
%p= t("layout.projects.git_help.cloning") + ":"
|
||||
%p
|
||||
%p~ "git clone #{git_repo_url(project.git_repo_name)} #{project.name}"
|
||||
%p~ "cd #{project.name}"
|
||||
%p
|
||||
%p= t("layout.projects.git_help.remote") + ":"
|
||||
%p
|
||||
%p~ "git remote add #{project.name} #{git_repo_url(project.git_repo_name)}"
|
||||
%p~ "git fetch #{project.name}"
|
||||
%p~ "git checkout -b my-local-tracking-branch #{project.name}/master_or_other_branch"
|
||||
.both
|
||||
:javascript
|
||||
$(document).ready(function() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%p== Hello, #{@user.user_appeal}.
|
||||
|
||||
- if @comment.commentable.class == Issue
|
||||
- if @comment.issue_comment?
|
||||
- link = link_to @comment.commentable.title, project_issue_url(@comment.commentable.project, @comment.commentable)
|
||||
- object = 'issue'
|
||||
- elsif @comment.commit_comment?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%p== Здравствуйте, #{@user.user_appeal}.
|
||||
|
||||
- if @comment.commentable.class == Issue
|
||||
- if @comment.issue_comment?
|
||||
- link = link_to @comment.commentable.title, project_issue_url(@comment.commentable.project, @comment.commentable)
|
||||
- object = 'задаче'
|
||||
- elsif @comment.commit_comment?
|
||||
|
|
|
@ -31,7 +31,7 @@ module Rosa
|
|||
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
||||
|
||||
# Activate observers that should always be running.
|
||||
config.active_record.observers = :event_log_observer, :activity_feed_observer
|
||||
config.active_record.observers = :event_log_observer, :activity_feed_observer, :build_list_observer
|
||||
|
||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
|
|
|
@ -11,7 +11,6 @@ set :default_environment, {
|
|||
|
||||
require 'rvm/capistrano'
|
||||
require 'bundler/capistrano'
|
||||
require 'delayed/recipes'
|
||||
require 'airbrake/capistrano'
|
||||
|
||||
set :whenever_command, "bundle exec whenever"
|
||||
|
@ -38,6 +37,7 @@ set :deploy_via, :remote_cache
|
|||
require 'lib/recipes/nginx'
|
||||
require 'lib/recipes/unicorn'
|
||||
require 'lib/recipes/bluepill'
|
||||
require 'lib/recipes/delayed_job'
|
||||
|
||||
namespace :deploy do
|
||||
task :stub_xml_rpc do
|
||||
|
@ -49,11 +49,11 @@ namespace :deploy do
|
|||
|
||||
task :symlink_all, :roles => :app do
|
||||
run "mkdir -p #{fetch :shared_path}/config"
|
||||
|
||||
|
||||
# Setup DB
|
||||
run "cp -n #{fetch :release_path}/config/database.yml.sample #{fetch :shared_path}/config/database.yml"
|
||||
run "ln -nfs #{fetch :shared_path}/config/database.yml #{fetch :release_path}/config/database.yml"
|
||||
|
||||
|
||||
# Setup application
|
||||
run "cp -n #{fetch :release_path}/config/deploy/application.#{fetch :stage}.yml #{fetch :shared_path}/config/application.yml"
|
||||
run "ln -nfs #{fetch :shared_path}/config/application.yml #{fetch :release_path}/config/application.yml"
|
||||
|
@ -66,7 +66,7 @@ namespace :deploy do
|
|||
task :symlink_pids, :roles => :app do
|
||||
run "cd #{fetch :shared_path}/tmp && ln -nfs ../pids pids"
|
||||
end
|
||||
|
||||
|
||||
# Speed up precompile (http://www.bencurtis.com/2011/12/skipping-asset-compilation-with-capistrano )
|
||||
# namespace :assets do
|
||||
# task :precompile, :roles => :web, :except => { :no_release => true } do
|
||||
|
@ -77,7 +77,7 @@ namespace :deploy do
|
|||
# logger.info "Skipping asset pre-compilation because there were no asset changes"
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
after "deploy:finalize_update", "deploy:symlink_all"
|
||||
|
@ -88,7 +88,7 @@ after "deploy:setup", "deploy:symlink_pids"
|
|||
# DJ
|
||||
after "deploy:stop", "delayed_job:stop"
|
||||
after "deploy:start", "delayed_job:start"
|
||||
# after "deploy:restart", "delayed_job:restart"
|
||||
after "deploy:restart", "delayed_job:restart"
|
||||
|
||||
after "deploy:restart", "deploy:cleanup"
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ en:
|
|||
true_: True
|
||||
false_: False
|
||||
publish: Publish
|
||||
reject_publish: Reject
|
||||
add: Add
|
||||
upload: Upload
|
||||
not_access: Access denied!
|
||||
|
@ -44,6 +45,7 @@ en:
|
|||
back: Back
|
||||
processing: working ...
|
||||
invalid_content_type: incorrect type
|
||||
atom_link_tag_title: Private feed for %{nickname} | %{app_name}
|
||||
|
||||
settings:
|
||||
label: Settings
|
||||
|
@ -64,11 +66,6 @@ en:
|
|||
unlock: Do not receive unlock instructions?
|
||||
sign_in_through: Sign in by %{provider}
|
||||
|
||||
downloads:
|
||||
title: Downloads statistic
|
||||
message: Automatically updated every 24 hours
|
||||
refresh_btn: Refresh
|
||||
|
||||
weekdays:
|
||||
Monday: Monday
|
||||
Tuesday: Tuesday
|
||||
|
@ -137,9 +134,6 @@ en:
|
|||
|
||||
exception_message: Access violation to this page!
|
||||
|
||||
downloads:
|
||||
statistics_refreshed: Statistics refreshed
|
||||
|
||||
collaborators:
|
||||
successfully_changed: Collaborators list successfully changed
|
||||
error_in_changing: Collaborators list changing error
|
||||
|
@ -172,7 +166,6 @@ en:
|
|||
arch: Arch
|
||||
private_user: Private user
|
||||
product_build_list: Product build list
|
||||
download: Statistics
|
||||
|
||||
attributes:
|
||||
settings:
|
||||
|
@ -195,9 +188,3 @@ en:
|
|||
created_at: Created
|
||||
updated_at: Updated
|
||||
|
||||
download:
|
||||
name: Name
|
||||
version: Version
|
||||
distro: Source
|
||||
platform: Platform
|
||||
counter: Downloads
|
||||
|
|
|
@ -3,7 +3,6 @@ en:
|
|||
repositories: Repositories
|
||||
personal_repository: My repository
|
||||
products: Products
|
||||
downloads: Statistics
|
||||
top_menu:
|
||||
platforms: Platforms
|
||||
projects: Projects
|
||||
|
@ -38,5 +37,4 @@ en:
|
|||
users: Users
|
||||
register_requests: Invites
|
||||
event_logs: Event log
|
||||
downloads: Download statistic
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ ru:
|
|||
products: Продукты
|
||||
repositories: Репозитории
|
||||
personal_repository: Мой репозиторий
|
||||
downloads: Статистика
|
||||
top_menu:
|
||||
platforms: Платформы
|
||||
projects: Проекты
|
||||
|
@ -38,4 +37,3 @@ ru:
|
|||
users: Пользователи
|
||||
register_requests: Инвайты
|
||||
event_logs: Лог событий
|
||||
downloads: Статистика закачек пакетов
|
||||
|
|
|
@ -8,6 +8,7 @@ en:
|
|||
my_builds_by_day: My today builds
|
||||
new_project: Create project
|
||||
load_messages: show previous messages
|
||||
atom_title: Activity Feed
|
||||
|
||||
notifications:
|
||||
subjects:
|
||||
|
|
|
@ -8,6 +8,7 @@ ru:
|
|||
my_builds_by_day: Мои сборки за день
|
||||
new_project: Создать проект
|
||||
load_messages: показать предыдущие сообщения
|
||||
atom_title: Лента активности
|
||||
|
||||
notifications:
|
||||
subjects:
|
||||
|
|
|
@ -14,10 +14,9 @@ en:
|
|||
arch_id: Architecture
|
||||
arch: Architecture
|
||||
is_circle: Recurrent build
|
||||
notified_at: Notified at
|
||||
updated_at: Notified at
|
||||
additional_repos: Additional repositories
|
||||
include_repos: Included repositories
|
||||
updated_at: Updated on
|
||||
created_at: Created on
|
||||
pl: Repository for package storage
|
||||
pl_id: Repository for package storage
|
||||
|
@ -29,6 +28,8 @@ en:
|
|||
project_version: Version
|
||||
user: User
|
||||
preferences: Preferences
|
||||
started_at: Build started at
|
||||
duration: Build duration in seconds
|
||||
|
||||
build_list/item:
|
||||
name: Name
|
||||
|
@ -43,8 +44,8 @@ en:
|
|||
current: Curent
|
||||
created_at_start: "Build to start on:"
|
||||
created_at_end: "Build to start until:"
|
||||
notified_at_start: "Last update from BS on:"
|
||||
notified_at_end: " Last update from BS until:"
|
||||
updated_at_start: "Last update from BS on:"
|
||||
updated_at_end: " Last update from BS until:"
|
||||
bs_id_search: 'Search by Id'
|
||||
project_name_search: Search by project name
|
||||
bs_id_not_set: Id has not been configured yet
|
||||
|
@ -54,11 +55,15 @@ en:
|
|||
cancel_success: 'Build canceled'
|
||||
cancel_fail: 'Errors during build cancelation!'
|
||||
publish_success: 'Build is queued for publishing'
|
||||
reject_publish_success: 'Publishing rejected'
|
||||
publish_fail: 'Errors during build publishing!'
|
||||
reject_publish_fail: 'Rejecting publishing failed'
|
||||
container_published: 'Container published in a repository'
|
||||
action: Action
|
||||
new_header: New build
|
||||
main_data: Main data
|
||||
human_current_duration: Build currently takes %{hours} h. %{minutes} min.
|
||||
human_duration: Builded in %{hours} h. %{minutes} min.
|
||||
|
||||
ownership:
|
||||
header: Build list ownership
|
||||
|
@ -84,6 +89,7 @@ en:
|
|||
statuses:
|
||||
build_error: Build error
|
||||
build_published: Build has been published
|
||||
rejected_publish: Publishing rejected
|
||||
build_publish: Build is being publishing
|
||||
failed_publish: Publishing error
|
||||
dependencies_fail: Dependences not found
|
||||
|
@ -95,7 +101,7 @@ en:
|
|||
success: Build complete
|
||||
build_started: Build started
|
||||
platform_not_found: Platform not found
|
||||
platform_pending: Platforn pending
|
||||
platform_pending: Platform pending
|
||||
project_not_found: Project not found
|
||||
project_version_not_found: Project version not found
|
||||
|
||||
|
|
|
@ -14,10 +14,9 @@ ru:
|
|||
arch_id: Архитектура
|
||||
arch: Архитектура
|
||||
is_circle: Циклическая сборка
|
||||
notified_at: Информация получена
|
||||
updated_at: Информация получена
|
||||
additional_repos: Дополнительные репозитории
|
||||
include_repos: Подключаемые репозитории
|
||||
updated_at: Обновлен
|
||||
created_at: Создан
|
||||
pl: Репозиторий для сохранения пакетов
|
||||
pl_id: Репозиторий для сохранения пакетов
|
||||
|
@ -29,6 +28,7 @@ ru:
|
|||
project_version: Версия
|
||||
user: Пользователь
|
||||
preferences: Настройки
|
||||
duration: Длительность билда в секундах
|
||||
|
||||
build_list/item:
|
||||
name: Название
|
||||
|
@ -43,8 +43,8 @@ ru:
|
|||
current: Текущие
|
||||
created_at_start: "Время постановки на сборку с:"
|
||||
created_at_end: "Время постановки на сборку по:"
|
||||
notified_at_start: "Время последнего обновления от BS с:"
|
||||
notified_at_end: "Время последнего обновления от BS по:"
|
||||
updated_at_start: "Время последнего обновления от BS с:"
|
||||
updated_at_end: "Время последнего обновления от BS по:"
|
||||
bs_id_search: 'Поиск по Id'
|
||||
project_name_search: Поиск по названию проекта
|
||||
bs_id_not_set: Id еще не присвоен
|
||||
|
@ -54,12 +54,17 @@ ru:
|
|||
cancel_success: 'Сборка отменена.'
|
||||
cancel_fail: 'При отмене сборки произошла ошибка!'
|
||||
publish_success: 'Сборка поставлена в очередь на публикацию.'
|
||||
reject_publish_success: 'Публикация отклонена'
|
||||
publish_fail: 'При публикации сборки произошла ошибка!'
|
||||
reject_publish_fail: 'Не удалось отклонить публикацию сборки'
|
||||
container_published: 'Контейнер размещен в репозитории'
|
||||
action: Действие
|
||||
new_header: Новая сборка
|
||||
main_data: Основные данные
|
||||
|
||||
human_current_duration: Сборка длится уже %{hours} ч. %{minutes} мин.
|
||||
human_duration: Собрано за %{hours} ч. %{minutes} мин.
|
||||
|
||||
ownership:
|
||||
header: Принадлежность заданий
|
||||
owned: Мне
|
||||
|
@ -84,6 +89,7 @@ ru:
|
|||
statuses:
|
||||
build_error: ошибка сборки
|
||||
build_published: опубликован
|
||||
rejected_publish: публикация отклонена
|
||||
build_publish: публикуется
|
||||
failed_publish: ошибка публикации
|
||||
dependencies_fail: зависимости не найдены
|
||||
|
|
|
@ -4,8 +4,8 @@ en:
|
|||
issue:
|
||||
title: Name
|
||||
body: Description
|
||||
user: Assigned
|
||||
user_id: Assigned
|
||||
assignee: Assigned
|
||||
assignee_id: Assigned
|
||||
project: Project
|
||||
status: Status
|
||||
|
||||
|
@ -41,10 +41,10 @@ en:
|
|||
update_label: Update label
|
||||
label_custom_color: Custom color
|
||||
label_manage: Manage labels
|
||||
executor: Executor
|
||||
assignee: Assignee
|
||||
search_user: Find user...
|
||||
search_labels: Find labels...
|
||||
choose_user_on_left: Choose executor on the left
|
||||
choose_user_on_left: Choose assignee on the left
|
||||
choose_labels_on_left: Choose labels on the left
|
||||
at: at
|
||||
cancel_button: Cancel
|
||||
|
|
|
@ -4,8 +4,8 @@ ru:
|
|||
issue:
|
||||
title: Название
|
||||
body: Описание
|
||||
user: Назначена
|
||||
user_id: Назначена
|
||||
assignee: Назначена
|
||||
assignee_id: Назначена
|
||||
project: Проект
|
||||
status: Статус
|
||||
|
||||
|
@ -41,7 +41,7 @@ ru:
|
|||
update_label: Обновить метку
|
||||
label_custom_color: Свой цвет
|
||||
label_manage: Управление
|
||||
executor: Исполнитель
|
||||
assignee: Исполнитель
|
||||
search_user: Найти пользователя...
|
||||
search_labels: Найти метки...
|
||||
choose_user_on_left: выберите исполнителя слева
|
||||
|
|
|
@ -4,12 +4,16 @@ en:
|
|||
add: Add
|
||||
edit: Settings
|
||||
fork_and_edit: Fork
|
||||
fork_to: Fork to %{to}
|
||||
fork_modal_header: Where do you want to fork this project?
|
||||
already_exists: Project already exists
|
||||
list: List
|
||||
list_header: Projects
|
||||
edit_header: Edit project
|
||||
show: Project
|
||||
build: Build
|
||||
new_build: New build %{project_name}
|
||||
new_build_list: New build
|
||||
confirm_delete: Are you sure you want to delete this project?
|
||||
new: New project
|
||||
location: Location
|
||||
|
@ -29,6 +33,11 @@ en:
|
|||
sections: Sections
|
||||
has_issue_description: Tracker adds a lightweight issue management system tightly integrated with your repository.
|
||||
has_wiki_description: Wikis are the simplest way to allow other users to contribute content. Any user can create and edit pages for documentation, examples, support or anything you wish.
|
||||
human_average_build_time: Expected time is %{hours} h. %{minutes} min.
|
||||
|
||||
git_help:
|
||||
cloning: Cloning the repository
|
||||
remote: Add this repository as a remote to an existing local repository
|
||||
|
||||
diff_show_header: "%{files} with %{additions} and %{deletions}."
|
||||
about_subheader: "About project"
|
||||
|
|
|
@ -4,12 +4,16 @@ ru:
|
|||
add: Добавить
|
||||
edit: Настройки
|
||||
fork_and_edit: Клонировать
|
||||
fork_to: Клонировать в %{to}
|
||||
fork_modal_header: Куда Вы хотите клонировать проект?
|
||||
already_exists: Проект уже существует
|
||||
list: Список
|
||||
list_header: Проекты
|
||||
edit_header: Редактировать проект
|
||||
show: Проект
|
||||
build: Собрать
|
||||
new_build: Новая сборка %{project_name}
|
||||
new_build_list: Новая сборка
|
||||
confirm_delete: Вы уверены, что хотите удалить этот проект?
|
||||
new: Новый проект
|
||||
location: Расположение
|
||||
|
@ -29,6 +33,7 @@ ru:
|
|||
sections: Разделы
|
||||
has_issue_description: Трэкер предоставляет лекговесный менеджер для задач по разработке Вашего проекта.
|
||||
has_wiki_description: Wiki - это самый простой способ предоставить другим вносить свой вклад в развитие Вашего проекта. Каждый пользователь нашего сервиса может использовать Wiki для документирования, примеров, поддержки или всего другого, в чем у Вас появится необходимость.
|
||||
human_average_build_time: 'Ожидаемое время: %{hours} ч. %{minutes} мин.'
|
||||
|
||||
diff_show_header: "%{files} с %{additions} и %{deletions}."
|
||||
about_subheader: "О проекте"
|
||||
|
@ -44,7 +49,11 @@ ru:
|
|||
current_branch: Текущая ветка/тег
|
||||
current_commit: Текущий коммит
|
||||
files_in_project: Файлы в
|
||||
|
||||
|
||||
git_help:
|
||||
cloning: Клонирование этого репозитория
|
||||
remote: Добавление этого репозитория как удаленного к существующему локальному репозиторию
|
||||
|
||||
flash:
|
||||
project:
|
||||
saved: Проект успешно сохранен
|
||||
|
|
|
@ -36,6 +36,7 @@ ru:
|
|||
true_: Да
|
||||
false_: Нет
|
||||
publish: Опубликовать
|
||||
reject_publish: Отклонить
|
||||
add: Добавить
|
||||
upload: Загрузить
|
||||
not_access: Нет доступа!
|
||||
|
@ -44,6 +45,7 @@ ru:
|
|||
back: Назад
|
||||
processing: Обрабатывается...
|
||||
invalid_content_type: имеет неверный тип
|
||||
atom_link_tag_title: Приватная лента для %{nickname} | %{app_name}
|
||||
|
||||
settings:
|
||||
label: 'Настройки'
|
||||
|
@ -64,11 +66,6 @@ ru:
|
|||
unlock: Не получили инструкции по разблокировке?
|
||||
sign_in_through: Войти через %{provider}
|
||||
|
||||
downloads:
|
||||
title: Статистика закачек пакетов
|
||||
message: Обновляется автоматически каждые 24 часа
|
||||
refresh_btn: Обновить
|
||||
|
||||
weekdays:
|
||||
Monday: Понедельник
|
||||
Tuesday: Вторник
|
||||
|
@ -137,9 +134,6 @@ ru:
|
|||
|
||||
exception_message: У Вас нет доступа к этой странице!
|
||||
|
||||
downloads:
|
||||
statistics_refreshed: Статистика обновлена
|
||||
|
||||
collaborators:
|
||||
successfully_changed: Список коллабораторов успешно изменен
|
||||
error_in_changing: Ошибка изменения списка коллабораторов
|
||||
|
@ -172,7 +166,6 @@ ru:
|
|||
arch: Arch
|
||||
private_user: Приватный пользователь
|
||||
product_build_list: Сборочный лист продукта
|
||||
download: Статистика
|
||||
auto_build_list: Автоматическая пересборка пакетов
|
||||
|
||||
attributes:
|
||||
|
@ -196,9 +189,3 @@ ru:
|
|||
created_at: Создана
|
||||
updated_at: Обновлена
|
||||
|
||||
download:
|
||||
name: Название
|
||||
version: Версия
|
||||
distro: Дистрибутив
|
||||
platform: Архитектура
|
||||
counter: Закачки
|
||||
|
|
|
@ -4,16 +4,18 @@ app_name = ENV['APP_NAME'] || 'rosa_build'
|
|||
Bluepill.application(app_name) do |app|
|
||||
app.uid = app.gid = 'rosa'
|
||||
app.working_dir = "/srv/#{app_name}/current"
|
||||
app.process("delayed_job") do |process|
|
||||
process.start_grace_time = 10.seconds
|
||||
process.stop_grace_time = 10.seconds
|
||||
process.restart_grace_time = 10.seconds
|
||||
%w(fork import hook default).each do |queue|
|
||||
app.process("delayed_job_#{queue}_queue") do |process|
|
||||
process.start_grace_time = 10.seconds
|
||||
process.stop_grace_time = 10.seconds
|
||||
process.restart_grace_time = 10.seconds
|
||||
|
||||
process.start_command = "/usr/bin/env ruby script/delayed_job start"
|
||||
process.stop_command = "/usr/bin/env ruby script/delayed_job stop"
|
||||
process.pid_file = File.join(app.working_dir, 'tmp', 'pids', 'delayed_job.pid')
|
||||
process.start_command = "/usr/bin/env ruby script/delayed_job --queue=#{queue} -p #{queue} --pid-dir=/srv/#{app_name}/current/tmp/#{queue}_pids start"
|
||||
process.stop_command = "/usr/bin/env ruby script/delayed_job --pid-dir=/srv/#{app_name}/current/tmp/#{queue}_pids stop"
|
||||
process.pid_file = File.join(app.working_dir, 'tmp', "#{queue}_pids", 'delayed_job.pid')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
app.process("newrelic") do |process|
|
||||
process.start_grace_time = 10.seconds
|
||||
process.stop_grace_time = 10.seconds
|
||||
|
|
|
@ -8,9 +8,11 @@ Rosa::Application.routes.draw do
|
|||
get '/users/new' => 'admin/users#new', :as => :new_user
|
||||
get '/users/list' => 'admin/users#list', :as => :users_list
|
||||
post '/users/create' => 'admin/users#create', :as => :create_user
|
||||
get '/users/:id/edit' => 'admin/users#profile', :as => :edit_user
|
||||
put '/users/:id/edit' => 'admin/users#update', :as => :update_user
|
||||
delete '/users/:id/delete' => 'admin/users#destroy', :as => :delete_user
|
||||
constraints :id => /\d+/ do
|
||||
get '/users/:id/edit' => 'admin/users#profile', :as => :edit_user
|
||||
put '/users/:id/edit' => 'admin/users#update', :as => :update_user
|
||||
delete '/users/:id/delete' => 'admin/users#destroy', :as => :delete_user
|
||||
end
|
||||
end
|
||||
devise_for :users, :controllers => {:omniauth_callbacks => 'users/omniauth_callbacks'}
|
||||
resources :users, :only => [:show, :profile, :update] do
|
||||
|
@ -28,7 +30,7 @@ Rosa::Application.routes.draw do
|
|||
end
|
||||
end
|
||||
get 'users/:id/settings/private' => 'users#private', :as => :user_private_settings
|
||||
get 'users/:id/settings/private' => 'users#private', :as => :user_private_settings
|
||||
put 'users/:id/settings/private' => 'users#private'
|
||||
|
||||
resources :groups do
|
||||
get :autocomplete_group_uname, :on => :collection
|
||||
|
@ -144,6 +146,8 @@ Rosa::Application.routes.draw do
|
|||
# Raw
|
||||
get '/projects/:project_id/raw/:treeish/*path' => "git/blobs#raw", :defaults => {:treeish => :master}, :as => :raw, :format => false
|
||||
|
||||
get '/projects/:project_id/archive/:format/tree/:treeish' => "git/trees#archive", :defaults => {:treeish => :master}, :as => :archive, :format => /zip|tar/
|
||||
|
||||
# Core callbacks
|
||||
match 'build_lists/publish_build', :to => "build_lists#publish_build"
|
||||
match 'build_lists/status_build', :to => "build_lists#status_build"
|
||||
|
@ -157,6 +161,7 @@ Rosa::Application.routes.draw do
|
|||
member do
|
||||
put :cancel
|
||||
put :publish
|
||||
put :reject_publish
|
||||
end
|
||||
collection { post :search }
|
||||
end
|
||||
|
@ -166,18 +171,15 @@ Rosa::Application.routes.draw do
|
|||
|
||||
resources :event_logs, :only => :index
|
||||
|
||||
match 'statistics/' => 'downloads#index', :as => :downloads
|
||||
match 'statistics/refresh' => 'downloads#refresh', :as => :downloads_refresh
|
||||
|
||||
match '/forbidden', :to => 'pages#forbidden', :as => 'forbidden'
|
||||
match '/terms-of-service', :to => 'pages#tos', :as => 'tos'
|
||||
|
||||
if APP_CONFIG['anonymous_access']
|
||||
authenticated do
|
||||
root :to => "activity_feeds#index"
|
||||
get "/(.:format)" => "activity_feeds#index", :as => :root
|
||||
end
|
||||
root :to => 'pages#root'
|
||||
else
|
||||
root :to => "activity_feeds#index"
|
||||
get "/(.:format)" => "activity_feeds#index", :as => :root
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,12 +7,6 @@
|
|||
# runner "Download.parse_and_remove_nginx_log"
|
||||
#end
|
||||
|
||||
every 1.day, :at => '5:00' do
|
||||
#rake "sudo_test:projects"
|
||||
runner "Download.rotate_nginx_log"
|
||||
runner "Download.parse_and_remove_nginx_log"
|
||||
end
|
||||
|
||||
every 1.day, :at => '4:00 am' do
|
||||
rake "import:sync:all", :output => 'log/sync.log'
|
||||
end
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class RemoveContainersAndRpms < ActiveRecord::Migration
|
||||
def up
|
||||
drop_table :containers
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class CustomizePlatform < ActiveRecord::Migration
|
||||
def self.up
|
||||
change_column_null :platforms, :name, false
|
||||
change_column_null :platforms, :distrib_type, false
|
||||
#change_column_null :platforms, :distrib_type, false
|
||||
change_column_null :platforms, :platform_type, false
|
||||
change_column_null :platforms, :released, false
|
||||
change_column_null :platforms, :visibility, false
|
||||
|
@ -16,4 +17,4 @@ class CustomizePlatform < ActiveRecord::Migration
|
|||
change_column_null :platforms, :visibility, true
|
||||
remove_index "platforms", ["name"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class ClearProduct < ActiveRecord::Migration
|
||||
def self.up
|
||||
remove_column :products, :build_status
|
||||
remove_column :products, :build_path
|
||||
remove_column :products, :system_wide
|
||||
end
|
||||
|
||||
def self.down
|
||||
add_column :products, :build_status, :integer, :default => 2, :null => false
|
||||
add_column :products, :build_path, :string
|
||||
add_column :products, :system_wide, :boolean, :default => false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
class ModifyDefaultQueue < ActiveRecord::Migration
|
||||
def up
|
||||
change_column :delayed_jobs, :queue, :string, :default => 'default'
|
||||
execute "UPDATE delayed_jobs SET queue = 'default'"
|
||||
end
|
||||
|
||||
def down
|
||||
change_column :delayed_jobs, :queue, :string, :default => nil
|
||||
execute "UPDATE delayed_jobs SET queue = null"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class AddStartedAtAndDurationToBuildLists < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :build_lists, :started_at, :datetime
|
||||
add_column :build_lists, :duration, :integer
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class BuildAverageTime < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :projects, :average_build_time, :integer, :null => false, :default => 0
|
||||
add_column :projects, :build_count, :integer, :null => false, :default => 0
|
||||
end
|
||||
|
||||
ActivityFeed.where(:kind => 'build_list_notification').destroy_all
|
||||
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
class AddAssigneeToIssues < ActiveRecord::Migration
|
||||
def up
|
||||
rename_column :issues, :user_id, :assignee_id
|
||||
rename_column :issues, :creator_id, :user_id
|
||||
end
|
||||
|
||||
def down
|
||||
rename_column :issues, :user_id, :creator_id
|
||||
rename_column :issues, :assignee_id, :user_id
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
class RemoveDownloads < ActiveRecord::Migration
|
||||
def up
|
||||
drop_table :downloads
|
||||
end
|
||||
|
||||
def down
|
||||
create_table "downloads", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.string "version"
|
||||
t.string "distro"
|
||||
t.string "platform"
|
||||
t.integer "counter", :default => 0
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
class AddTokenAuthenticatableToUsers < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :users, :authentication_token, :string
|
||||
add_index :users, :authentication_token
|
||||
|
||||
User.all.each do |user|
|
||||
user.ensure_authentication_token!
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :users, :authentication_token
|
||||
remove_index :users, :authentication_token
|
||||
end
|
||||
end
|
53
db/schema.rb
53
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20120331180541) do
|
||||
ActiveRecord::Schema.define(:version => 20120418100619) do
|
||||
|
||||
create_table "activity_feeds", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
|
@ -75,6 +75,8 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.string "package_version"
|
||||
t.string "commit_hash"
|
||||
t.integer "priority", :default => 0, :null => false
|
||||
t.datetime "started_at"
|
||||
t.integer "duration"
|
||||
end
|
||||
|
||||
add_index "build_lists", ["arch_id"], :name => "index_build_lists_on_arch_id"
|
||||
|
@ -102,21 +104,11 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.string "locked_by"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "queue"
|
||||
t.string "queue", :default => "default"
|
||||
end
|
||||
|
||||
add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
|
||||
|
||||
create_table "downloads", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.string "version"
|
||||
t.string "distro"
|
||||
t.string "platform"
|
||||
t.integer "counter", :default => 0
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "event_logs", :force => true do |t|
|
||||
t.integer "user_id"
|
||||
t.string "user_name"
|
||||
|
@ -145,13 +137,13 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
create_table "issues", :force => true do |t|
|
||||
t.integer "serial_id"
|
||||
t.integer "project_id"
|
||||
t.integer "user_id"
|
||||
t.integer "assignee_id"
|
||||
t.string "title"
|
||||
t.text "body"
|
||||
t.string "status", :default => "open"
|
||||
t.string "status", :default => "open"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "creator_id"
|
||||
t.integer "user_id"
|
||||
t.datetime "closed_at"
|
||||
t.integer "closed_by"
|
||||
end
|
||||
|
@ -188,7 +180,7 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.string "owner_type"
|
||||
t.string "visibility", :default => "open", :null => false
|
||||
t.string "platform_type", :default => "main", :null => false
|
||||
t.string "distrib_type", :null => false
|
||||
t.string "distrib_type"
|
||||
end
|
||||
|
||||
add_index "platforms", ["name"], :name => "index_platforms_on_name", :unique => true, :case_sensitive => false
|
||||
|
@ -215,8 +207,6 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
create_table "products", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.integer "platform_id", :null => false
|
||||
t.integer "build_status", :default => 2, :null => false
|
||||
t.string "build_path"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.text "build_script"
|
||||
|
@ -227,7 +217,6 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.string "tar_content_type"
|
||||
t.integer "tar_file_size"
|
||||
t.datetime "tar_updated_at"
|
||||
t.boolean "system_wide", :default => false
|
||||
t.text "cron_tab"
|
||||
t.boolean "use_cron", :default => false
|
||||
t.text "description"
|
||||
|
@ -258,29 +247,29 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.datetime "updated_at"
|
||||
t.integer "owner_id"
|
||||
t.string "owner_type"
|
||||
t.string "visibility", :default => "open"
|
||||
t.string "visibility", :default => "open"
|
||||
t.text "description"
|
||||
t.string "ancestry"
|
||||
t.boolean "has_issues", :default => true
|
||||
t.boolean "has_issues", :default => true
|
||||
t.boolean "has_wiki", :default => false
|
||||
t.string "srpm_file_name"
|
||||
t.string "srpm_content_type"
|
||||
t.integer "srpm_file_size"
|
||||
t.datetime "srpm_updated_at"
|
||||
t.boolean "has_wiki", :default => false
|
||||
t.string "default_branch", :default => "master"
|
||||
t.boolean "is_rpm", :default => true
|
||||
t.string "default_branch", :default => "master"
|
||||
t.boolean "is_rpm", :default => true
|
||||
t.integer "average_build_time", :default => 0, :null => false
|
||||
t.integer "build_count", :default => 0, :null => false
|
||||
end
|
||||
|
||||
add_index "projects", ["owner_id"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false
|
||||
|
||||
create_table "register_requests", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "email"
|
||||
t.string "token"
|
||||
t.boolean "approved", :default => false
|
||||
t.boolean "rejected", :default => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "interest"
|
||||
t.text "more"
|
||||
end
|
||||
|
@ -342,6 +331,9 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.string "uname"
|
||||
t.string "role"
|
||||
t.string "language", :default => "en"
|
||||
t.string "confirmation_token"
|
||||
t.datetime "confirmed_at"
|
||||
t.datetime "confirmation_sent_at"
|
||||
t.integer "own_projects_count", :default => 0, :null => false
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.text "professional_experience"
|
||||
|
@ -355,11 +347,10 @@ ActiveRecord::Schema.define(:version => 20120331180541) do
|
|||
t.integer "failed_attempts", :default => 0
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.string "confirmation_token"
|
||||
t.datetime "confirmed_at"
|
||||
t.datetime "confirmation_sent_at"
|
||||
t.string "authentication_token"
|
||||
end
|
||||
|
||||
add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token"
|
||||
add_index "users", ["confirmation_token"], :name => "index_users_on_confirmation_token", :unique => true
|
||||
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
|
||||
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
|
||||
|
|
|
@ -1,323 +0,0 @@
|
|||
КРАТКОЕ ОПИСАНИЕ ACL
|
||||
====================
|
||||
|
||||
Предназначение
|
||||
--------------
|
||||
|
||||
ACL предназначена для контроля прав пользователя на выполнение действий в
|
||||
системе и доступа к моделям по областям видимости.
|
||||
|
||||
Решаемые задачи
|
||||
---------------
|
||||
|
||||
* Проверка наличия у пользователя прав для выполнения метода контроллера;
|
||||
* Прозрачная фильтрация моделей для исключения невидимых для пользователя
|
||||
записей.
|
||||
|
||||
Возможности
|
||||
-----------
|
||||
|
||||
* Неограниченное количество моделей, над которыми могут выполняться
|
||||
действия (`target`);
|
||||
* Неограниченное количество моделей, которые могут выполнять действия над
|
||||
другими (`acter`);
|
||||
* Геренатор прав основывающийся на структуре приложения (см. далее);
|
||||
* Неограниченное количество ролей, которые могут назначаться для `acter` и
|
||||
содержать любую комбинацию прав и доступных видимостей;
|
||||
* Объединение прав `acter`-ов на глубину одной модели (см. далее);
|
||||
* Разграничение назначения ролей по классам (не завершено, на данный
|
||||
момент не критично);
|
||||
* Разграничение ролей на глобальные и локальные (см. далее).
|
||||
|
||||
Типы моделей, с которыми взаимодействует ACL
|
||||
--------------------------------------------
|
||||
|
||||
* __ActerModel__ -- модель, которая может выполнять действия, разрешенные
|
||||
ролями, над другими моделями;
|
||||
* __TargetTarget__ -- модель, над которой могут выполняться действия,
|
||||
разрешенные ролями.
|
||||
|
||||
__ActerModel__ может иметь глобальную роль, которая определяет возможность
|
||||
выполнения действий без привязки к конкретному экземпляру __TargetModel__ и
|
||||
неограниченное количество прав по отношению к конкретному экземпляру
|
||||
__TargetModel__.
|
||||
|
||||
__TODO__: *Реализовать дополнение необходимым функционалом моделей, выбранных
|
||||
в качестве __ActerModel__ или __TargetModel__ при декларировании их роли в
|
||||
системе*
|
||||
|
||||
Схема взаимодействия объектов ACL
|
||||
---------------------------------
|
||||
|
||||
Функционал ACL реализуется путем взаимодействия моделей `Right, Role, Relation`,
|
||||
реализующих основной функционал и особых моделей проекта, обозначенных на схеме
|
||||
как `ActerModel` и `TargetModel`.
|
||||
|
||||
Экземпляры __ActerModel__ и __TargetModel__ связываются посредством модели
|
||||
`Relation`, через которую экземпляр __ActerModel__ получает неограниченное
|
||||
количество ролей по отношению к экземпляру __TargetModel__.
|
||||
|
||||
### Схема связей моделей:
|
||||
|
||||
--------------
|
||||
| ActerModel |
|
||||
/ --------------
|
||||
--------- -------- |
|
||||
| Right | | Role | V
|
||||
--------- -------- ------------
|
||||
... <= ... <= | Relation |
|
||||
--------- -------- ------------
|
||||
| Right | | Role | |
|
||||
--------- -------- V
|
||||
---------------
|
||||
| TargetModel |
|
||||
---------------
|
||||
|
||||
* Обозначения: <= -- Связь с несколькими моделями
|
||||
<-,/,| -- Связь с одной моделью
|
||||
|
||||
|
||||
Генератор прав
|
||||
--------------
|
||||
|
||||
Генератор ролей является Rake-task-ом и запускается командой
|
||||
`rake rights:generate`.
|
||||
|
||||
Желательно запускать после добавления нового метода в контроллер для того,
|
||||
чтобы на этот метод в системе появилось право.
|
||||
|
||||
Загрузка ролей из дампа
|
||||
-----------------------
|
||||
|
||||
Загрузку ролей из заранее подготовленного дампа можно произвести двумя
|
||||
способами:
|
||||
|
||||
* В консоли, используя Rake task `rake roles:load`, который загрузит в базу
|
||||
роли, описанные в `config/roles.yml`
|
||||
* Через Web-интерфейс, на странице `/roles`, если у пользователя есть
|
||||
соответствующие права. Для загрузки через Web-интерфейс необходимо выбрать
|
||||
файл в поле выбора вверху страницы и нажать __Загрузить__.
|
||||
|
||||
Получение дампа ролей
|
||||
---------------------
|
||||
|
||||
Дамп ролей может получить пользователь, имеющий на это права, зайдя на страницу
|
||||
`roles` и нажав кнопку `Скачать в YML`.
|
||||
|
||||
Задание областей видимости моделей
|
||||
----------------------------------
|
||||
*Этот функционал скорее всего будет изменяться*
|
||||
|
||||
Если модель должна иметь несколько областей видимости, нужно сделать следующее:
|
||||
|
||||
* Добавить в модель константу `VISIBILITIES`, в которой задать названия областей
|
||||
видимости;
|
||||
* Добавить к таблице моделей поле `visibility:text`;
|
||||
* Добавить `attr_accessible :visibility` в модель;
|
||||
* Создать `scope :by_visibility`, принимающий аргументом массив областей
|
||||
видимости.
|
||||
|
||||
После выполнения этих действий на странице редактирования роли появится поле
|
||||
выбора областей видимости для этой модели.
|
||||
|
||||
### Пример:
|
||||
|
||||
model VisibilitiesExample < ActiveRecord::Base
|
||||
VISIBILITIES = ['open', 'hidden', 'open_for_admins']
|
||||
attr_accessible :visibility
|
||||
|
||||
scope :by_visibility, lambda {|v| {:conditions => ['visibility in (?)', v]}}
|
||||
end
|
||||
|
||||
*Назначение методов описано в API*
|
||||
|
||||
Задание типа модели
|
||||
-------------------
|
||||
*Этот функционал скорее всего будет изменяться*
|
||||
|
||||
Если модель должна иметь возможность быть связанной с другими с использованием
|
||||
ролей, необходимо произвести следующие действия:
|
||||
|
||||
* Добавить в модель декларацию `relationable`, с аргументом `:as`, который
|
||||
может принимать заначения из `[:object, :target]`. Если модель будет
|
||||
__acter__-ом, передается `:object`, иначе `:target`
|
||||
Пример: `relationable :as => :object`
|
||||
* Добавить в модель связь `belongs_to :global_role, :class_name => 'Role'`
|
||||
* Добавить в модель связь с моделью `Relation`
|
||||
* Если модель -- __acter__ и она должна использовать как свои роли, так и
|
||||
роли из другой модели, необходимо добавить декларацию `inherit_rights_from`
|
||||
которой аргументом присвоить имя/имена связей с моделями, из которых должны
|
||||
браться роли.
|
||||
|
||||
### Примеры:
|
||||
|
||||
* Модель, являющаяся __acter__:
|
||||
|
||||
class ActerModel < ActiveRecord::Base
|
||||
relationable :as => :object
|
||||
|
||||
belongs_to :global_role, :class_name => 'Role'
|
||||
has_many :targets, :as => :object, :class_name => 'Relation'
|
||||
end
|
||||
* Модель, являющаяся __acter__ и наследующая права другой модели:
|
||||
|
||||
class ActerWithInheritableRolesModel < ActiveRecord::Base
|
||||
relationable :as => :object
|
||||
ingerit_rights_from :another_acter_model
|
||||
|
||||
has_many :another_acters_models
|
||||
|
||||
belongs_to :global_role, :class_name => 'Role'
|
||||
has_many :targets, :as => :object, :class_name => 'Relation'
|
||||
end
|
||||
* Модель, являющаяся __target__:
|
||||
|
||||
class TargetModel < ActiveRecord::Base
|
||||
relationable :as => :target
|
||||
|
||||
has_many :objects, :as => :target, :class_name => 'Relation'
|
||||
end
|
||||
* Модель, являющаяся и __acter__, и __target__:
|
||||
|
||||
class ActerAndTargetModel < ActiveRecord::Base
|
||||
relationable :as => :object
|
||||
relationable :as => :target
|
||||
|
||||
belongs_to :global_role, :class_name => 'Role'
|
||||
has_many :targets, :as => :object, :class_name => 'Relation'
|
||||
has_many :objects, :as => :target, :class_name => 'Relation'
|
||||
end
|
||||
|
||||
*Назначение методов описано в API*
|
||||
|
||||
Использование ACL в контроллере
|
||||
-------------------------------
|
||||
|
||||
Если необходимо ограничить доступ ко всем методам контроллера по глобальной
|
||||
роли пользователя вне зависимости от текущей модели, необходимо установить
|
||||
`before_filter :check_global_rights`.
|
||||
В случае, если у пользователя нет прав для выполнения текущего действия, он
|
||||
будет переотправлен на предыдущую страницу.
|
||||
|
||||
Если необходимо проверить, может ли пользователь выполнить конкретное действие,
|
||||
необходимо в начале этого метода вызвать метод `can_perform?`. Если методу
|
||||
передан параметр, являющийся экземпляром класса __TargetModel__, метод возвратит
|
||||
`true`, если одна или несколько ролей пользователя над этой моделью позволяет
|
||||
ему выполнить может выполнить действие и `false` в противном случае. Если
|
||||
необязательный параметр опущен, или в качестве параметра передано `:system`,
|
||||
учитываются только глобальные роли.
|
||||
|
||||
### Примеры
|
||||
|
||||
* Контроллер, некоторые методы которого доступны для всех:
|
||||
|
||||
class StuffController < ApplicationController
|
||||
def index # доступ у всех
|
||||
...
|
||||
end
|
||||
|
||||
def show # 'Что-то полезное' выполнится только у тех, чьи роли над
|
||||
# @data позволяют выполнить конкретное действие.
|
||||
@data = Stuff.find(params[:id])
|
||||
if can_perform? @data
|
||||
#что-то полезное
|
||||
else
|
||||
# сообщаем пользователю, что он не может выполнить действие
|
||||
end
|
||||
end
|
||||
|
||||
def create # 'Что-то полезное' выполнится только у тех, чьи
|
||||
# глобальные роли позволяют выполнить метод
|
||||
if can_perform?
|
||||
# что-то полезное
|
||||
else
|
||||
# сообщаем пользователю, что он не может выполнить действие
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
* Контроллер, доступ к методам которого возможен только при наличии необходимых
|
||||
прав в глобальных ролях:
|
||||
|
||||
class StuffController < ApplicationController
|
||||
before_filter :check_global_rights # разрешаем доступ только тем,
|
||||
# чьи роли это позволяют.
|
||||
|
||||
def index # доступ только у тех, кому это позволяет глобальная роль
|
||||
...
|
||||
end
|
||||
|
||||
def show # 'Что-то полезное' выполнится только у тех, чьи роли
|
||||
# над @data это позволяют
|
||||
@data = Stuff.find(params[:id])
|
||||
if can_perform? @data
|
||||
#что-то полезное
|
||||
else
|
||||
# сообщаем пользователю, что он не может выполнить действие
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Использование ACL во view
|
||||
-------------------------
|
||||
|
||||
Используется метод `can_perform?` модели, для которой нужно проверить права
|
||||
доступа. Обычно этой моделью является `current_user`.
|
||||
|
||||
### Примеры:
|
||||
|
||||
* Проверка на возможность выполнения глобального действия:
|
||||
|
||||
-if current_user.can_perform?('some_controller', 'some_aciton')
|
||||
%a{:href => controller_action_path}= Some description
|
||||
|
||||
* Проверка на возможность выполнения действия над текущей моделью:
|
||||
|
||||
-if current_user.can_perform?('some_controller', 'some_aciton', @data)
|
||||
%a{:href => controller_action_path(@data)}= Some description
|
||||
|
||||
API для работы с ACL
|
||||
--------------------
|
||||
*Этот функционал скорее всего будет изменяться*
|
||||
|
||||
### Методы потомков `ActiveRecord::Base`
|
||||
|
||||
* Методы классов:
|
||||
- `relationable` -- устанавливает, кем является модель (acter/target)
|
||||
- `relationable?` -- может ли иметь связь с ролью/ролями с другими
|
||||
- `relation_acters` -- список моделей, которые могут иметь роли
|
||||
по отношению к другим (след. метод)
|
||||
- `relation_targets` -- список моделей, над которыми могут совершаться
|
||||
действия
|
||||
- `relation_acter? (model)`, `relation_target? (model)` -- является ли
|
||||
тем или другим
|
||||
- `inherit_rights_from (:relation_name | [:relation_names])` -- права из
|
||||
каких связанных моделей наследовать
|
||||
- `visible_to (model)` -- все видимые для модели записи, может
|
||||
включаться в цепочку (например, для paginate)
|
||||
|
||||
* Методы инстансов:
|
||||
- `add_role_to(acter, role)` -- привязать acter-а с ролью к текущей записи
|
||||
- `add_role_on(target, role)` -- привязать текущую модель с ролью
|
||||
- `roles_to(object)` -- если object == :system, возвращает глобальные роли
|
||||
текущей записи, если передана запись -- то роли текущей модели над записью
|
||||
- `rights_to(object)` -- аргументы те же, но возвращается список прав,
|
||||
собранный из всех ролей
|
||||
- `right_to(controller_name, action)` -- возвращает запись с правом на
|
||||
выполнение действия action в контроллере c именем `controller_name`
|
||||
- `can_perform? (controller_name, action, target = :system)` -- показывает,
|
||||
может ли текущая модель выполнить действие контроллера над целью
|
||||
|
||||
### Методы потомков `ActiveController::Base`
|
||||
*Возможно, будут вынесены в хелпер для универсализации системы*
|
||||
|
||||
- `can_perform? (target = :system)` -- может ли `current_user` выполнить
|
||||
текущее действие
|
||||
- `check_global_access` -- делает редирект назад или на главную, если
|
||||
пользователь вообще не может совершить текущее действие
|
||||
- `roles_to(object)` -- возвращает список ролей `current_user`-а по отношению
|
||||
к объекту
|
||||
- `rights_to(object)` -- возвращает список прав `current_user`-а по отношению
|
||||
к объекту
|
||||
|
|
@ -23,9 +23,12 @@
|
|||
<div class="middle">
|
||||
<!--Main menu-->
|
||||
<menu>
|
||||
<div class="logo">
|
||||
<a href="#"><img src="pics/logo-mini.png" alt="Главная" /></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="first">Главная</a>
|
||||
<a href="#">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="active">Проекты</a>
|
||||
|
@ -43,9 +46,7 @@
|
|||
<a href="#">Документация</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo">
|
||||
<img src="pics/logo-mini.png" alt="logo" />
|
||||
</div>
|
||||
|
||||
</menu>
|
||||
<div class="information">
|
||||
<!--Search-->
|
||||
|
|
|
@ -22,9 +22,12 @@
|
|||
<div class="middle">
|
||||
<!--Main menu-->
|
||||
<menu>
|
||||
<div class="logo">
|
||||
<a href="#"><img src="pics/logo-mini.png" alt="Главная" /></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="first">Главная</a>
|
||||
<a href="#">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="active">Проекты</a>
|
||||
|
@ -42,9 +45,6 @@
|
|||
<a href="#">Документация</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo">
|
||||
<img src="pics/logo-mini.png" alt="logo" />
|
||||
</div>
|
||||
</menu>
|
||||
<div class="information">
|
||||
<!--Search-->
|
||||
|
|
|
@ -24,9 +24,12 @@
|
|||
<div class="middle">
|
||||
<!--Main menu-->
|
||||
<menu>
|
||||
<div class="logo">
|
||||
<a href="#"><img src="pics/logo-mini.png" alt="Главная" /></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="first">Главная</a>
|
||||
<a href="#">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="active">Проекты</a>
|
||||
|
@ -44,9 +47,7 @@
|
|||
<a href="#">Документация</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo">
|
||||
<img src="pics/logo-mini.png" alt="logo" />
|
||||
</div>
|
||||
|
||||
</menu>
|
||||
<div class="information">
|
||||
<!--Search-->
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
<div class="middle">
|
||||
<!--Main menu-->
|
||||
<menu>
|
||||
<div class="logo">
|
||||
<a href="#"><img src="pics/logo-mini.png" alt="Главная" /></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="first">Главная</a>
|
||||
<a href="#">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="active">Проекты</a>
|
||||
|
@ -38,9 +41,7 @@
|
|||
<a href="#">Документация</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo">
|
||||
<img src="pics/logo-mini.png" alt="logo" />
|
||||
</div>
|
||||
|
||||
</menu>
|
||||
<div class="information">
|
||||
<!--Search-->
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
<div class="middle">
|
||||
<!--Main menu-->
|
||||
<menu>
|
||||
<div class="logo">
|
||||
<a href="#"><img src="pics/logo-mini.png" alt="Главная" /></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="first">Главная</a>
|
||||
<a href="#">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="active">Проекты</a>
|
||||
|
@ -40,9 +43,6 @@
|
|||
<a href="#">Документация</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo">
|
||||
<img src="pics/logo-mini.png" alt="logo" />
|
||||
</div>
|
||||
</menu>
|
||||
<div class="information">
|
||||
<!--Search-->
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue