[issue #64] Merge branch 'master' into 64-project_wiki
Conflicts: config/routes.rb db/schema.rb
|
@ -4,7 +4,7 @@ class ApplicationController < ActionController::Base
|
|||
layout :layout_by_resource
|
||||
|
||||
before_filter lambda { EventLog.current_controller = self },
|
||||
:only => [:create, :destroy, :open_id, :auto_build, :process_build, :cancel, :publish, :change_visibility] # :update
|
||||
:only => [:create, :destroy, :open_id, :auto_build, :cancel, :publish, :change_visibility] # :update
|
||||
after_filter lambda { EventLog.current_controller = nil }
|
||||
|
||||
helper_method :get_owner
|
||||
|
|
|
@ -1,35 +1,22 @@
|
|||
class BuildListsController < ApplicationController
|
||||
CALLBACK_ACTIONS = [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt]
|
||||
CALLBACK_ACTIONS = [:publish_build, :status_build, :pre_build, :post_build, :circle_build, :new_bbdt]
|
||||
NESTED_ACTIONS = [:index, :new, :create]
|
||||
|
||||
before_filter :authenticate_user!, :except => CALLBACK_ACTIONS
|
||||
before_filter :authenticate_build_service!, :only => CALLBACK_ACTIONS
|
||||
before_filter :find_project, :only => [:filter, :show, :publish]
|
||||
before_filter :find_arches, :only => [:index]
|
||||
# before_filter :find_project_versions, :only => [:index]
|
||||
before_filter :find_build_list_by_bs, :only => [:status_build, :pre_build, :post_build]
|
||||
before_filter :find_project, :only => NESTED_ACTIONS
|
||||
before_filter :find_build_list, :only => [:show, :publish, :cancel]
|
||||
before_filter :find_build_list_by_bs, :only => [:publish_build, :status_build, :pre_build, :post_build, :circle_build]
|
||||
|
||||
load_and_authorize_resource :project, :only => :index
|
||||
load_and_authorize_resource :through => :project, :only => :index, :shallow => true
|
||||
|
||||
load_and_authorize_resource :except => CALLBACK_ACTIONS.concat([:index])
|
||||
|
||||
def cancel
|
||||
build_list = BuildList.find(params[:id])
|
||||
if build_list.cancel_build_list
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_successed')
|
||||
else
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_failed')
|
||||
end
|
||||
end
|
||||
load_and_authorize_resource :project, :only => NESTED_ACTIONS
|
||||
load_and_authorize_resource :build_list, :through => :project, :only => NESTED_ACTIONS, :shallow => true
|
||||
load_and_authorize_resource :except => CALLBACK_ACTIONS.concat(NESTED_ACTIONS)
|
||||
|
||||
def index
|
||||
filter_params = params[:filter] || {}
|
||||
if params[:project_id]
|
||||
find_project
|
||||
find_project_versions
|
||||
if @project
|
||||
@action_url = project_build_lists_path(@project)
|
||||
else
|
||||
@project = nil
|
||||
@action_url = build_lists_path
|
||||
end
|
||||
|
||||
|
@ -43,16 +30,61 @@ class BuildListsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@build_list = BuildList.new
|
||||
end
|
||||
|
||||
def create
|
||||
notices, errors = [], []
|
||||
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.bpl = bpl; @build_list.arch = arch; @build_list.user = current_user
|
||||
flash_options = {:project_version => @build_list.project_version, :arch => arch.name, :bpl => bpl.name, :pl => @build_list.pl}
|
||||
if @build_list.save
|
||||
notices << t("flash.build_list.saved", flash_options)
|
||||
else
|
||||
errors << t("flash.build_list.save_error", flash_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
errors << t("flash.build_list.no_arch_or_platform_selected") if errors.blank? and notices.blank?
|
||||
if errors.present?
|
||||
@build_list ||= BuildList.new
|
||||
flash[:error] = errors.join('<br>').html_safe
|
||||
render :action => :new
|
||||
else
|
||||
flash[:notice] = notices.join('<br>').html_safe
|
||||
redirect_to @project
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@build_list = @project.build_lists.find(params[:id])
|
||||
@item_groups = @build_list.items.group_by_level
|
||||
end
|
||||
|
||||
def publish
|
||||
@build_list = @project.build_lists.find(params[:id])
|
||||
@build_list.publish
|
||||
if @build_list.publish
|
||||
redirect_to :back, :notice => t('layout.build_lists.publish_success')
|
||||
else
|
||||
redirect_to :back, :notice => t('layout.build_lists.publish_fail')
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to project_build_lists_path(@project)
|
||||
def cancel
|
||||
if @build_list.cancel
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_success')
|
||||
else
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_fail')
|
||||
end
|
||||
end
|
||||
|
||||
def publish_build
|
||||
@build_list.status = (params[:status].to_i == 0 ? BuildList::BUILD_PUBLISHED : BuildList::FAILED_PUBLISH)
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
end
|
||||
|
||||
def status_build
|
||||
|
@ -62,7 +94,6 @@ class BuildListsController < ApplicationController
|
|||
|
||||
@build_list.container_path = params[:container_path]
|
||||
@build_list.notified_at = Time.current
|
||||
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -71,7 +102,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
|
||||
|
@ -81,9 +111,10 @@ class BuildListsController < ApplicationController
|
|||
@build_list.status = params[:status]
|
||||
@build_list.container_path = params[:container_path]
|
||||
@build_list.notified_at = Time.current
|
||||
|
||||
@build_list.save
|
||||
|
||||
@build_list.delay.publish if @build_list.auto_publish # && @build_list.can_publish?
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
end
|
||||
|
||||
|
@ -91,7 +122,6 @@ class BuildListsController < ApplicationController
|
|||
@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
|
||||
|
@ -102,10 +132,9 @@ class BuildListsController < ApplicationController
|
|||
@build_list.name = params[:name]
|
||||
@build_list.additional_repos = ActiveSupport::JSON.decode(params[:additional_repos])
|
||||
@build_list.set_items(ActiveSupport::JSON.decode(params[:items]))
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.is_circle = (params[:is_circular] != "0")
|
||||
@build_list.is_circle = (params[:is_circular].to_i != 0)
|
||||
@build_list.bs_id = params[:id]
|
||||
params[:arch]
|
||||
@build_list.notified_at = Time.current
|
||||
@build_list.save
|
||||
|
||||
render :nothing => true, :status => 200
|
||||
|
@ -114,16 +143,11 @@ class BuildListsController < ApplicationController
|
|||
protected
|
||||
|
||||
def find_project
|
||||
@project = Project.find params[:project_id]
|
||||
@project = Project.find_by_id params[:project_id]
|
||||
end
|
||||
|
||||
def find_arches
|
||||
@arches = Arch.recent
|
||||
end
|
||||
|
||||
def find_project_versions
|
||||
@git_repository = @project.git_repository
|
||||
@project_versions = @project.versions
|
||||
def find_build_list
|
||||
@build_list = BuildList.find(params[:id])
|
||||
end
|
||||
|
||||
def find_build_list_by_bs
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
class CommentsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :set_commentable, :only => [:index, :edit, :create]
|
||||
before_filter :find_project, :only => [:index]
|
||||
before_filter :find_comment, :only => [:edit, :update, :destroy]
|
||||
|
||||
authorize_resource :only => [:show, :edit, :update, :destroy]
|
||||
authorize_resource :project, :only => [:index]
|
||||
|
||||
def index
|
||||
@comments = @commentable.comments
|
||||
end
|
||||
|
||||
def create
|
||||
@comment = @commentable.comments.build(params[:comment])
|
||||
@comment.user = current_user
|
||||
if @comment.save
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to :back
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@issue = @commentable
|
||||
@project = @issue.project
|
||||
end
|
||||
|
||||
def update
|
||||
if @comment.update_attributes(params[:comment])
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
#redirect_to :back
|
||||
redirect_to [@comment.commentable.project, @comment.commentable]
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.save_error")
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@comment.destroy
|
||||
|
||||
flash[:notice] = t("flash.comment.destroyed")
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_commentable
|
||||
#params.each do |name, value|
|
||||
# if name =~ /(.+)_id$/
|
||||
# return $1.classify.constantize.find(value)
|
||||
# end
|
||||
#end
|
||||
#nil
|
||||
return Issue.find(params[:issue_id])
|
||||
end
|
||||
|
||||
def set_commentable
|
||||
@commentable = find_commentable
|
||||
end
|
||||
|
||||
def find_comment
|
||||
@comment = Comment.find(params[:id])
|
||||
end
|
||||
|
||||
def find_project
|
||||
@project = @comment.commentable.project
|
||||
end
|
||||
end
|
|
@ -0,0 +1,76 @@
|
|||
class IssuesController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :find_project
|
||||
before_filter :find_issue_by_serial_id, :only => [:show, :edit, :update, :destroy]
|
||||
|
||||
load_and_authorize_resource :project
|
||||
load_and_authorize_resource :issue, :through => :project, :find_by => :serial_id
|
||||
|
||||
autocomplete :user, :uname
|
||||
|
||||
def index
|
||||
@issues = @project.issues
|
||||
case params[:status]
|
||||
when 'open'
|
||||
@issues = @issues.where(:status => 'open')
|
||||
when 'closed'
|
||||
@issues = @issues.where(:status => 'closed')
|
||||
end
|
||||
@issues = @issues.paginate :per_page => 10, :page => params[:page]
|
||||
end
|
||||
|
||||
def new
|
||||
@issue = Issue.new(:project => @project)
|
||||
end
|
||||
|
||||
def create
|
||||
@user_id = params[:user_id]
|
||||
@user_uname = params[:user_uname]
|
||||
|
||||
@issue = Issue.new(params[:issue])
|
||||
@issue.user_id = @user_id
|
||||
@issue.project_id = @project.id
|
||||
if @issue.save
|
||||
flash[:notice] = I18n.t("flash.issue.saved")
|
||||
redirect_to project_issues_path(@project)
|
||||
else
|
||||
flash[:error] = I18n.t("flash.issue.save_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@user_id = @issue.user_id
|
||||
@user_uname = @issue.user.uname
|
||||
end
|
||||
|
||||
def update
|
||||
@user_id = params[:user_id].blank? ? @issue.user_id : params[:user_id]
|
||||
@user_uname = params[:user_uname].blank? ? @issue.user.uname : params[:user_uname]
|
||||
|
||||
if @issue.update_attributes( params[:issue].merge({:user_id => @user_id}) )
|
||||
flash[:notice] = I18n.t("flash.issue.saved")
|
||||
redirect_to [@project, @issue]
|
||||
else
|
||||
flash[:error] = I18n.t("flash.issue.save_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@issue.destroy
|
||||
|
||||
flash[:notice] = t("flash.issue.destroyed")
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_project
|
||||
@project = Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def find_issue_by_serial_id
|
||||
@issue = @project.issues.find_by_serial_id!(params[:id])
|
||||
end
|
||||
end
|
|
@ -30,7 +30,7 @@ class PlatformsController < ApplicationController
|
|||
{:name => p.name,
|
||||
:architectures => ['i586', 'x86_64'],
|
||||
:repositories => p.repositories.map(&:name),
|
||||
:url => "http://#{request.host_with_port}/downloads/#{p.name}/repository/"}
|
||||
:url => p.public_downloads_url(request.host_with_port)}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ class PlatformsController < ApplicationController
|
|||
flash[:notice] = I18n.t("flash.platform.saved")
|
||||
redirect_to @platform
|
||||
else
|
||||
flash[:error] = I18n.t("flash.platform.saved_error")
|
||||
flash[:error] = I18n.t("flash.platform.save_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
@ -81,7 +81,7 @@ class PlatformsController < ApplicationController
|
|||
flash[:notice] = I18n.t("flash.platform.saved")
|
||||
redirect_to @platform
|
||||
else
|
||||
flash[:error] = I18n.t("flash.platform.saved_error")
|
||||
flash[:error] = I18n.t("flash.platform.save_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,14 +4,12 @@ class ProjectsController < ApplicationController
|
|||
belongs_to :user, :group, :polymorphic => true, :optional => true
|
||||
|
||||
before_filter :authenticate_user!, :except => :auto_build
|
||||
before_filter :find_project, :only => [:show, :edit, :update, :destroy, :fork, :build, :process_build]
|
||||
before_filter :find_project, :only => [:show, :edit, :update, :destroy, :fork]
|
||||
before_filter :get_paths, :only => [:new, :create, :edit, :update]
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
# puts parent.inspect
|
||||
# puts parent.is_a? User
|
||||
@projects = if parent? and !parent.nil?
|
||||
parent.projects
|
||||
else
|
||||
|
@ -95,54 +93,6 @@ class ProjectsController < ApplicationController
|
|||
render :nothing => true
|
||||
end
|
||||
|
||||
def build
|
||||
@arches = Arch.recent
|
||||
@bpls = Platform.main
|
||||
@pls = @project.repositories.collect { |rep| ["#{rep.platform.name}/#{rep.name}", rep.platform.id] }
|
||||
@project_versions = @project.versions
|
||||
end
|
||||
|
||||
def process_build
|
||||
@arch_ids = params[:build][:arches].select{|_,v| v == "1"}.collect{|x| x[0].to_i }
|
||||
@arches = Arch.where(:id => @arch_ids)
|
||||
|
||||
@project_version = params[:build][:project_version]
|
||||
|
||||
bpls_ids = params[:build][:bpl].blank? ? [] : params[:build][:bpl].select{|_,v| v == "1"}.collect{|x| x[0].to_i }
|
||||
bpls = Platform.where(:id => bpls_ids)
|
||||
|
||||
pl = Platform.find params[:build][:pl]
|
||||
update_type = params[:build][:update_type]
|
||||
build_requires = params[:build][:build_requires]
|
||||
|
||||
@project_versions = @project.versions
|
||||
|
||||
if !check_arches || !check_project_versions
|
||||
@arches = Arch.recent
|
||||
@bpls = Platform.main
|
||||
@pls = @project.repositories.collect { |rep| ["#{rep.platform.name}/#{rep.name}", rep.platform.id] }
|
||||
|
||||
render :action => "build"
|
||||
else
|
||||
flash[:notice], flash[:error] = "", ""
|
||||
@arches.each do |arch|
|
||||
bpls.each do |bpl|
|
||||
build_list = @project.build_lists.new(:arch => arch, :project_version => @project_version,
|
||||
:pl => pl, :bpl => bpl, :update_type => update_type,
|
||||
:build_requires => build_requires, :user => current_user)
|
||||
|
||||
if build_list.save
|
||||
flash[:notice] += t("flash.build_list.saved", :project_version => @project_version, :arch => arch.name, :bpl => bpl.name, :pl => pl)
|
||||
else
|
||||
flash[:error] += t("flash.build_list.save_error", :project_version => @project_version, :arch => arch.name, :bpl => bpl.name, :pl => pl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to project_path(@project)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def get_paths
|
||||
|
@ -163,28 +113,4 @@ class ProjectsController < ApplicationController
|
|||
def find_project
|
||||
@project = Project.find params[:id]
|
||||
end
|
||||
|
||||
def check_arches
|
||||
if @arch_ids.blank?
|
||||
flash[:error] = t("flash.build_list.no_arch_selected")
|
||||
false
|
||||
elsif @arch_ids.length != @arches.length
|
||||
flash[:error] = t("flash.build_list.no_arch_found")
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def check_project_versions
|
||||
if @project_version.blank?
|
||||
flash[:error] = t("flash.build_list.no_project_version_selected")
|
||||
false
|
||||
elsif !@project_versions.flatten.include?(@project_version)
|
||||
flash[:error] = t("flash.build_list.no_project_version_found", :project_version => @project_version)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,7 +54,6 @@ class RepositoriesController < ApplicationController
|
|||
def add_project
|
||||
if params[:project_id]
|
||||
@project = Project.find(params[:project_id])
|
||||
# params[:project_id] = nil
|
||||
unless @repository.projects.find_by_name(@project.name)
|
||||
@repository.projects << @project
|
||||
flash[:notice] = t('flash.repository.project_added')
|
||||
|
@ -63,13 +62,35 @@ class RepositoriesController < ApplicationController
|
|||
end
|
||||
redirect_to repository_path(@repository)
|
||||
else
|
||||
if @repository.platform.platform_type == 'main'
|
||||
@projects = Project.addable_to_repository(@repository.id).by_visibilities(['open']).paginate(:page => params[:project_page])
|
||||
else
|
||||
@projects = Project.addable_to_repository(@repository.id).paginate(:page => params[:project_page])
|
||||
render :projects_list
|
||||
end
|
||||
render 'projects_list'
|
||||
end
|
||||
|
||||
def projects_list
|
||||
owner_subquery = "
|
||||
INNER JOIN (
|
||||
SELECT id, 'User' AS type, uname
|
||||
FROM users
|
||||
UNION
|
||||
SELECT id, 'Group' AS type, uname
|
||||
FROM groups
|
||||
) AS owner
|
||||
ON projects.owner_id = owner.id AND projects.owner_type = owner.type"
|
||||
colName = ['owner.uname', 'projects.name']
|
||||
sort_col = params[:iSortCol_0] || 0
|
||||
sort_dir = params[:sSortDir_0]=="asc" ? 'asc' : 'desc'
|
||||
order = "#{colName[sort_col.to_i]} #{sort_dir}"
|
||||
|
||||
@projects = Project.joins(owner_subquery).addable_to_repository(@repository.id)
|
||||
@projects = @projects.paginate(:page => (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i).to_i + 1, :per_page => params[:iDisplayLength])
|
||||
@projects = @projects.by_visibilities(['open']) if @repository.platform.platform_type == 'main'
|
||||
|
||||
@total_projects = @projects.count
|
||||
@projects = @projects.where(['projects.name LIKE ?', "#{params[:sSearch]}%"]) if params[:sSearch] and !params[:sSearch].empty?
|
||||
@total_project = @projects.count
|
||||
@projects = @projects.order(order)#.includes(:owner) #WTF????
|
||||
|
||||
render :partial => 'proj_ajax', :layout => false
|
||||
end
|
||||
|
||||
def remove_project
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
class SubscribesController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
|
||||
load_and_authorize_resource :project
|
||||
load_and_authorize_resource :issue, :through => :project, :find_by => :serial_id
|
||||
load_and_authorize_resource :subscribe, :through => :issue, :find_by => :user_id
|
||||
|
||||
def create
|
||||
@subscribe = @issue.subscribes.build(:user_id => current_user.id)
|
||||
if @subscribe.save
|
||||
flash[:notice] = I18n.t("flash.subscribe.saved")
|
||||
redirect_to :back
|
||||
else
|
||||
flash[:error] = I18n.t("flash.subscribe.saved_error")
|
||||
redirect_to :back
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@subscribe.destroy
|
||||
|
||||
flash[:notice] = t("flash.subscribe.destroyed")
|
||||
redirect_to :back
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module CommentsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module IssuesHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module SubscribesHelper
|
||||
end
|
|
@ -5,7 +5,31 @@ class UserMailer < ActionMailer::Base
|
|||
|
||||
def new_user_notification(user)
|
||||
@user = user
|
||||
mail(:to => user.email, :subject => "Регистрация на проекте «#{APP_CONFIG['project_name']}»") do |format|
|
||||
mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_user_notification", :project_name => APP_CONFIG['project_name'])) do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def new_comment_notification(comment, user)
|
||||
@user = user
|
||||
@comment = comment
|
||||
mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_comment_notification")) do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def new_issue_notification(issue, user)
|
||||
@user = user
|
||||
@issue = issue
|
||||
mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_issue_notification")) do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
||||
def issue_assign_notification(issue, user)
|
||||
@user = user
|
||||
@issue = issue
|
||||
mail(:to => user.email, :subject => I18n.t("notifications.subjects.issue_assign_notification")) do |format|
|
||||
format.html
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,147 +1,97 @@
|
|||
# If rules goes one by one CanCan joins them by 'OR' sql operator
|
||||
# If rule has multiple conditions CanCan joins them by 'AND' sql operator
|
||||
# WARNING:
|
||||
# - put cannot rules _after_ can rules and not before!
|
||||
# - beware inner joins. Use sub queries against them!
|
||||
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
user ||= User.new # guest user (not logged in)
|
||||
@user = user
|
||||
|
||||
if user.admin?
|
||||
can :manage, :all
|
||||
cannot :destroy, Subscribe
|
||||
cannot :create, Subscribe
|
||||
else
|
||||
#WARNING:
|
||||
# - put cannot rules _after_ can rules and not before!
|
||||
# - beware inner joins. Use sub queries against them!
|
||||
# Shared rights between guests and registered users
|
||||
can :forbidden, Platform
|
||||
|
||||
can :read, [Repository, Platform], :visibility => 'open'
|
||||
# TODO remove because auth callbacks skipped
|
||||
can :auto_build, Project
|
||||
can [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt], BuildList
|
||||
can [:publish_build, :status_build, :pre_build, :post_build, :circle_build, :new_bbdt], BuildList
|
||||
|
||||
# Guest rights
|
||||
if user.guest?
|
||||
if user.guest? # Guest rights
|
||||
can :create, User
|
||||
# Registered user rights
|
||||
else
|
||||
can [:read, :platforms], Category
|
||||
else # Registered user rights
|
||||
can [:show, :autocomplete_user_uname], User
|
||||
|
||||
can [:read, :create], Group
|
||||
can [:update, :manage_members], Group do |group|
|
||||
group.objects.exists?(:object_type => 'User', :object_id => user.id, :role => 'admin') # or group.owner_id = user.id
|
||||
end
|
||||
can :destroy, Group, :owner_id => user.id
|
||||
|
||||
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, Project, read_relations_for('projects')) {|project| local_reader? project}
|
||||
can(:write, Project) {|project| local_writer? project} # for grack
|
||||
can([:update, :manage_collaborators], Project) {|project| local_admin? project}
|
||||
can(:fork, Project) {|project| can? :read, project}
|
||||
can(:destroy, Project) {|project| owner? project}
|
||||
|
||||
can :create, AutoBuildList
|
||||
can [:index, :destroy], AutoBuildList, :project_id => user.own_project_ids
|
||||
# If rules goes one by one CanCan joins them by 'OR' sql operator
|
||||
can :read, Project, :visibility => 'open'
|
||||
can :read, Group
|
||||
can :read, User
|
||||
cannot :index, User
|
||||
can :manage_collaborators, Project do |project|
|
||||
project.relations.exists? :object_id => user.id, :object_type => 'User', :role => 'admin'
|
||||
end
|
||||
can :manage_members, Group do |group|
|
||||
group.objects.exists? :object_id => user.id, :object_type => 'User', :role => 'admin'
|
||||
end
|
||||
|
||||
# Put here model names which objects can user create
|
||||
can :create, Project
|
||||
can :create, Group
|
||||
can :publish, BuildList do |build_list|
|
||||
build_list.can_published? && build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
can [:index, :read], BuildList, ["build_lists.project_id IN (SELECT id FROM projects WHERE visibility = ?)", 'open'] do |build_list|
|
||||
build_list.project.public?
|
||||
end
|
||||
can [:index, :read], BuildList, build_lists_in_relations_with(:object_type => 'User', :object_id => user.id) do |build_list|
|
||||
build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
can :read, BuildList, :project => {:visibility => 'open'}
|
||||
can :read, BuildList, :project => {:owner_type => 'User', :owner_id => user.id}
|
||||
can :read, 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| can? :write, build_list.project}
|
||||
can(:publish, BuildList) {|build_list| build_list.can_publish? && can?(:write, build_list.project)}
|
||||
|
||||
can :read, Platform, :visibility => 'open'
|
||||
can :read, Platform, :owner_type => 'User', :owner_id => user.id
|
||||
can :read, Platform, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
can(:read, Platform, read_relations_for('platforms')) {|platform| local_reader? platform}
|
||||
can(:update, Platform) {|platform| local_admin? platform}
|
||||
can([:freeze, :unfreeze, :destroy], Platform) {|platform| owner? platform}
|
||||
can :autocomplete_user_uname, Platform
|
||||
|
||||
# TODO delegate to platform?
|
||||
can :read, Repository, :visibility => 'open'
|
||||
can :read, Repository, :owner_type => 'User', :owner_id => user.id
|
||||
can :read, Repository, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
can(:read, Repository, read_relations_for('repositories')) {|repository| local_reader? repository}
|
||||
can(:create, Repository) {|repository| local_admin? repository.platform}
|
||||
can([:update, :add_project, :remove_project], Repository) {|repository| local_admin? repository}
|
||||
can([:change_visibility, :settings, :destroy], Repository) {|repository| owner? repository}
|
||||
|
||||
can :read, Product, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
can :read, Product, :platform => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can(:manage, Product, read_relations_for('products', 'platforms')) {|product| local_admin? product.platform}
|
||||
|
||||
can [:read, :platforms], Category
|
||||
|
||||
can [:read, :create], PrivateUser, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
|
||||
# If rule has multiple conditions CanCan joins them by 'AND' sql operator
|
||||
can [:read, :update, :process_build, :build, :destroy], Project, :owner_type => 'User', :owner_id => user.id
|
||||
#can :read, Project, :relations => {:role => 'reader'}
|
||||
can :read, Project, projects_in_relations_with(:role => 'reader', :object_type => 'User', :object_id => user.id) do |project|
|
||||
#The can? and cannot? call cannot be used with a raw sql 'can' definition.
|
||||
project.relations.exists?(:role => 'reader', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
#can [:update, :process_build, :build], Project, :relations => {:role => 'writer'}
|
||||
can [:read, :update, :process_build, :build], Project, projects_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |project|
|
||||
project.relations.exists?(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
|
||||
can [:read, :update, :destroy], Product, products_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |product|
|
||||
product.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
# Small CanCan hack by Product.new(:platform_id => ...)
|
||||
can [:new, :create], Product do |product|
|
||||
product.platform.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
|
||||
can [:read, :update], Group, groups_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |group|
|
||||
group.objects.exists?(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
|
||||
can :manage, Platform, :owner_type => 'User', :owner_id => user.id
|
||||
can :manage, Platform, platforms_in_relations_with(:role => 'admin', :object_type => 'User', :object_id => user.id) do |platform|
|
||||
platform.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
#can :read, Platform, :members => {:id => user.id}
|
||||
can :read, Platform, platforms_in_relations_with(:role => 'reader', :object_type => 'User', :object_id => user.id) do |platform|
|
||||
platform.relations.exists?(:role => 'reader', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
|
||||
can [:manage, :add_project, :remove_project, :change_visibility, :settings], Repository, :owner_type => 'User', :owner_id => user.id
|
||||
can :manage, Repository, repositories_in_relations_with(:role => 'admin', :object_type => 'User', :object_id => user.id) do |repository|
|
||||
repository.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
#can :read, Repository, :members => {:id => user.id}
|
||||
can :read, Repository, repositories_in_relations_with(:role => 'reader', :object_type => 'User', :object_id => user.id) do |repository|
|
||||
repository.relations.exists?(:role => 'reader', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
# Small CanCan hack by Repository.new(:platform_id => ...)
|
||||
can [:new, :create], Repository do |repository|
|
||||
repository.platform.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
|
||||
end
|
||||
|
||||
#can :read, Repository
|
||||
# TODO: Add personal repos rules
|
||||
|
||||
# Same rights for groups:
|
||||
can [:read, :create], PrivateUser, :platform => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can :publish, BuildList do |build_list|
|
||||
build_list.can_published? && build_list.project.relations.exists?(:object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
can [:index, :read], BuildList, build_lists_in_relations_with(:object_type => 'Group', :object_id => user.group_ids) do |build_list|
|
||||
build_list.project.relations.exists?(:object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
|
||||
can :manage_collaborators, Project, projects_in_relations_with(:role => 'admin', :object_type => 'Group', :object_id => user.group_ids) do |project|
|
||||
project.relations.exists? :object_id => user.group_ids, :object_type => 'Group', :role => 'admin'
|
||||
end
|
||||
# can :read, Issue, :status => 'open'
|
||||
can :read, Issue, :project => {:visibility => 'open'}
|
||||
can :read, Issue, :project => {:owner_type => 'User', :owner_id => user.id}
|
||||
can :read, Issue, :project => {:owner_type => 'Group', :owner_id => user.group_ids}
|
||||
can(:read, Issue, read_relations_for('issues', 'projects')) {|issue| can? :read, issue.project rescue nil}
|
||||
can(:create, Issue) {|issue| can? :write, issue.project}
|
||||
can([:update, :destroy], Issue) {|issue| issue.user_id == user.id or local_admin?(issue.project)}
|
||||
cannot :manage, Issue, :project => {:has_issues => false} # switch off issues
|
||||
|
||||
can [:read, :update, :process_build, :build, :destroy], Project, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
#can :read, Project, :relations => {:role => 'reader', :object_type => 'Group', :object_id => user.group_ids}
|
||||
can :read, Project, projects_in_relations_with(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids) do |project|
|
||||
project.relations.exists?(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
#can [:update, :process_build, :build], Project, :relations => {:role => 'writer', :object_type => 'Group', :object_id => user.group_ids}
|
||||
can [:read, :update, :process_build, :build], Project, projects_in_relations_with(:role => ['writer', 'admin'], :object_type => 'Group', :object_id => user.group_ids) do |project|
|
||||
project.relations.exists?(:role => ['writer', 'admin'], :object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
|
||||
can :manage, Platform, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
#can :read, Platform, :groups => {:id => user.group_ids}
|
||||
can :read, Platform, platforms_in_relations_with(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids) do |platform|
|
||||
platform.relations.exists?(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
|
||||
can [:manage, :add_project, :remove_project], Repository, :owner_type => 'Group', :owner_id => user.group_ids
|
||||
#can :read, Platform, :groups => {:id => user.group_ids}
|
||||
can :read, Repository, repositories_in_relations_with(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids) do |repository|
|
||||
repository.relations.exists?(:role => 'reader', :object_type => 'Group', :object_id => user.group_ids)
|
||||
end
|
||||
|
||||
can(:fork, Project) {|p| can? :read, p}
|
||||
|
||||
# Things that can not do simple user
|
||||
cannot :create, [Platform, User]
|
||||
can(:create, Comment) {|comment| can? :read, comment.commentable.project}
|
||||
can(:update, Comment) {|comment| comment.user_id == user.id or local_admin?(comment.commentable.project)}
|
||||
cannot :manage, Comment, :commentable => {:project => {:has_issues => false}} # switch off issues
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,34 +99,44 @@ class Ability
|
|||
cannot :destroy, Platform, :platform_type => 'personal'
|
||||
cannot :destroy, Repository, :platform => {:platform_type => 'personal'}
|
||||
cannot :fork, Project, :owner_id => user.id, :owner_type => user.class.to_s
|
||||
end
|
||||
cannot :destroy, Issue
|
||||
|
||||
# Sub query for platforms, projects relations
|
||||
# TODO: Replace table names list by method_missing way
|
||||
%w[platforms projects products repositories groups].each do |table_name|
|
||||
define_method table_name + "_in_relations_with" do |opts|
|
||||
query = "#{ table_name }.id IN (SELECT target_id FROM relations WHERE relations.target_type = '#{ table_name.singularize.camelize }'"
|
||||
opts.each do |key, value|
|
||||
query = query + " AND relations.#{ key } #{ value.class == Array ? 'IN (?)' : '= ?' } "
|
||||
can :create, Subscribe do |subscribe|
|
||||
!subscribe.subscribeable.subscribes.exists?(:user_id => user.id)
|
||||
end
|
||||
query = query + ")"
|
||||
|
||||
return opts.values.unshift query
|
||||
can :destroy, Subscribe do |subscribe|
|
||||
subscribe.subscribeable.subscribes.exists?(:user_id => user.id) && user.id == subscribe.user_id
|
||||
end
|
||||
end
|
||||
|
||||
def build_lists_in_relations_with(opts)
|
||||
query = "build_lists.project_id IN (SELECT target_id FROM relations WHERE relations.target_type = 'Project'"
|
||||
opts.each do |key, value|
|
||||
query = query + " AND relations.#{ key } #{ value.class == Array ? 'IN (?)' : '= ?' } "
|
||||
end
|
||||
query = query + ")"
|
||||
|
||||
return opts.values.unshift query
|
||||
# TODO group_ids ??
|
||||
def read_relations_for(table, parent = nil)
|
||||
key = parent ? "#{parent.singularize}_id" : 'id'
|
||||
parent ||= table
|
||||
["#{table}.#{key} IN (
|
||||
SELECT target_id FROM relations WHERE relations.target_type = ? AND
|
||||
(relations.object_type = 'User' AND relations.object_id = ? OR
|
||||
relations.object_type = 'Group' AND relations.object_id IN (?)))", parent.classify, @user, @user.group_ids]
|
||||
end
|
||||
|
||||
## Sub query for project relations
|
||||
#def projects_in_relations_with(opts={})
|
||||
# ["projects.id IN (SELECT target_id FROM relations WHERE relations.object_id #{ opts[:object_id].class == Array ? 'IN (?)' : '= ?' } AND relations.object_type = '#{ opts[:object_type] }' AND relations.target_type = 'Platform') AND relations.role", opts[:object_id]]
|
||||
#end
|
||||
def relation_exists_for(object, roles)
|
||||
object.relations.exists?(:object_id => @user.id, :object_type => 'User', :role => roles) or
|
||||
object.relations.exists?(:object_id => @user.group_ids, :object_type => 'Group', :role => roles)
|
||||
end
|
||||
|
||||
def local_reader?(object)
|
||||
relation_exists_for(object, %w{reader writer admin}) or owner?(object)
|
||||
end
|
||||
|
||||
def local_writer?(object)
|
||||
relation_exists_for(object, %w{writer admin}) or owner?(object)
|
||||
end
|
||||
|
||||
def local_admin?(object)
|
||||
relation_exists_for(object, 'admin') or owner?(object)
|
||||
end
|
||||
|
||||
def owner?(object)
|
||||
object.owner == @user or @user.own_groups.include?(object.owner)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,28 +6,27 @@ class BuildList < ActiveRecord::Base
|
|||
belongs_to :user
|
||||
has_many :items, :class_name => "BuildList::Item", :dependent => :destroy
|
||||
|
||||
validates :project_id, :presence => true
|
||||
validates :project_version, :presence => true
|
||||
#validates_inclusion_of :update_type, :in => UPDATE_TYPES#, :message => "extension %s is not included in the list"
|
||||
validates :project_id, :project_version, :arch, :include_repos, :presence => true
|
||||
UPDATE_TYPES = %w[security bugfix enhancement recommended newpackage]
|
||||
validates :update_type, :inclusion => UPDATE_TYPES
|
||||
validate lambda {
|
||||
errors.add(:bpl, I18n.t('flash.build_list.wrong_platform')) if pl.platform_type == 'main' && pl_id != bpl_id
|
||||
}
|
||||
validate lambda {
|
||||
errors.add(:bpl, I18n.t('flash.build_list.can_not_published')) if status == BUILD_PUBLISHED && status_was != BuildServer::SUCCESS
|
||||
}
|
||||
|
||||
# The kernel does not send these statuses directly
|
||||
BUILD_CANCELED = 5000
|
||||
WAITING_FOR_RESPONSE = 4000
|
||||
BUILD_PENDING = 2000
|
||||
BUILD_PUBLISHED = 6000
|
||||
BUILD_PUBLISH = 7000
|
||||
FAILED_PUBLISH = 8000
|
||||
|
||||
STATUSES = [ WAITING_FOR_RESPONSE,
|
||||
BUILD_CANCELED,
|
||||
BUILD_PENDING,
|
||||
BUILD_PUBLISHED,
|
||||
BUILD_PUBLISH,
|
||||
FAILED_PUBLISH,
|
||||
BuildServer::SUCCESS,
|
||||
BuildServer::BUILD_STARTED,
|
||||
BuildServer::BUILD_ERROR,
|
||||
|
@ -42,6 +41,8 @@ class BuildList < ActiveRecord::Base
|
|||
BUILD_CANCELED => :build_canceled,
|
||||
BUILD_PENDING => :build_pending,
|
||||
BUILD_PUBLISHED => :build_published,
|
||||
BUILD_PUBLISH => :build_publish,
|
||||
FAILED_PUBLISH => :failed_publish,
|
||||
BuildServer::BUILD_ERROR => :build_error,
|
||||
BuildServer::BUILD_STARTED => :build_started,
|
||||
BuildServer::SUCCESS => :success,
|
||||
|
@ -83,6 +84,7 @@ class BuildList < ActiveRecord::Base
|
|||
scope :scoped_to_project_name, lambda {|project_name| joins(:project).where('projects.name LIKE ?', "%#{project_name}%")}
|
||||
|
||||
serialize :additional_repos
|
||||
serialize :include_repos
|
||||
|
||||
before_create :set_default_status
|
||||
after_create :place_build
|
||||
|
@ -106,27 +108,26 @@ class BuildList < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def publish
|
||||
return false unless can_published?
|
||||
|
||||
BuildServer.publish_container bs_id
|
||||
self.update_attribute(:status, BUILD_PUBLISHED)
|
||||
#self.destroy # self.delete
|
||||
return false unless can_publish?
|
||||
has_published = BuildServer.publish_container bs_id
|
||||
update_attribute(:status, has_published == 0 ? BUILD_PUBLISH : FAILED_PUBLISH)
|
||||
return has_published == 0
|
||||
end
|
||||
|
||||
def can_published?
|
||||
self.status == BuildServer::SUCCESS
|
||||
def can_publish?
|
||||
status == BuildServer::SUCCESS or status == FAILED_PUBLISH
|
||||
end
|
||||
|
||||
def cancel_build_list
|
||||
def cancel
|
||||
return false unless can_cancel?
|
||||
has_canceled = BuildServer.delete_build_list bs_id
|
||||
update_attribute(:status, BUILD_CANCELED) if has_canceled == 0
|
||||
|
||||
return has_canceled == 0
|
||||
end
|
||||
|
||||
#TODO: Share this checking on product owner.
|
||||
def can_cancel?
|
||||
self.status == BUILD_PENDING && bs_id
|
||||
status == BUILD_PENDING && bs_id
|
||||
end
|
||||
|
||||
def event_log_message
|
||||
|
@ -140,8 +141,8 @@ class BuildList < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def place_build
|
||||
#XML-RPC params: project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web
|
||||
self.status = BuildServer.add_build_list project.name, project_version, pl.name, arch.name, (pl_id == bpl_id ? '' : bpl.name), update_type, build_requires, id
|
||||
#XML-RPC params: project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web, include_repos
|
||||
self.status = BuildServer.add_build_list project.name, project_version, pl.name, arch.name, (pl_id == bpl_id ? '' : bpl.name), update_type, build_requires, id, include_repos
|
||||
self.status = BUILD_PENDING if self.status == 0
|
||||
save
|
||||
end
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class Comment < ActiveRecord::Base
|
||||
belongs_to :commentable, :polymorphic => true
|
||||
belongs_to :user
|
||||
|
||||
validates :body, :user_id, :commentable_id, :commentable_type, :presence => true
|
||||
|
||||
after_create :deliver_new_comment_notification
|
||||
|
||||
protected
|
||||
|
||||
def deliver_new_comment_notification
|
||||
recipients = self.commentable.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) }
|
||||
recipients = recipients | [self.commentable.user_id]
|
||||
recipients = recipients | [self.commentable.project.owner_id] if self.commentable.project.owner_type == 'User'
|
||||
recipients.each do |recipient_id|
|
||||
recipient = User.find(recipient_id)
|
||||
UserMailer.delay.new_comment_notification(self, recipient)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
class Issue < ActiveRecord::Base
|
||||
STATUSES = ['open', 'closed']
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
|
||||
has_many :comments, :as => :commentable
|
||||
has_many :subscribes, :as => :subscribeable
|
||||
|
||||
validates :title, :body, :project_id, :presence => true
|
||||
|
||||
#attr_readonly :serial_id
|
||||
|
||||
after_create :set_serial_id
|
||||
after_create :subscribe_users
|
||||
after_create :deliver_new_issue_notification
|
||||
after_create :deliver_issue_assign_notification
|
||||
after_update :deliver_issue_assign_notification
|
||||
|
||||
def assign_uname
|
||||
user.uname if user
|
||||
end
|
||||
|
||||
def to_param
|
||||
serial_id.to_s
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_serial_id
|
||||
self.serial_id = self.project.issues.count
|
||||
self.save!
|
||||
end
|
||||
|
||||
def deliver_new_issue_notification
|
||||
recipients = collect_recipient_ids
|
||||
recipients.each do |recipient_id|
|
||||
recipient = User.find(recipient_id)
|
||||
UserMailer.delay.new_issue_notification(self, recipient)#.deliver
|
||||
end
|
||||
end
|
||||
|
||||
def deliver_issue_assign_notification
|
||||
UserMailer.delay.issue_assign_notification(self, self.user) if self.user_id_was != self.user_id
|
||||
end
|
||||
|
||||
def subscribe_users
|
||||
recipients = collect_recipient_ids
|
||||
recipients.each do |recipient_id|
|
||||
ss = self.subscribes.build(:user_id => recipient_id)
|
||||
ss.save!
|
||||
end
|
||||
end
|
||||
|
||||
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.project.owner_id] if self.project.owner_type == 'User'
|
||||
recipients
|
||||
end
|
||||
|
||||
end
|
|
@ -14,7 +14,7 @@ class Platform < ActiveRecord::Base
|
|||
has_many :groups, :through => :objects, :source => :object, :source_type => 'Group'
|
||||
|
||||
validates :description, :presence => true, :uniqueness => true
|
||||
validates :name, :uniqueness => true, :presence => true, :format => { :with => /^[a-zA-Z0-9_]+$/ }
|
||||
validates :name, :uniqueness => true, :presence => true, :format => { :with => /^[a-zA-Z0-9_\-]+$/ }
|
||||
validates :distrib_type, :presence => true, :inclusion => {:in => APP_CONFIG['distr_types']}
|
||||
|
||||
before_create :xml_rpc_create, :unless => lambda {Thread.current[:skip]}
|
||||
|
@ -43,14 +43,17 @@ class Platform < ActiveRecord::Base
|
|||
urpmi_commands[pl.name] = []
|
||||
local_pair = pl.id != self.id ? blank_pair : pair
|
||||
head = hidden? ? "http://#{local_pair[:login]}@#{local_pair[:pass]}:#{host}/private/" : "http://#{host}/downloads/"
|
||||
if pl.distrib_type == APP_CONFIG['distr_types'].first
|
||||
# prefix = prefix_url hidden?, :host => host, :login => local_pair[:login], :password => local_pair[:pass]
|
||||
if pl.distrib_type == APP_CONFIG['distr_types'].first # mdv
|
||||
Arch.all.each do |arch|
|
||||
tail = "/#{arch.name}/main/release"
|
||||
urpmi_commands[pl.name] << "urpmi.addmedia #{name} #{head}#{name}/repository/#{pl.name}#{tail}"
|
||||
# urpmi_commands[pl.name] << "urpmi.addmedia #{name} #{prefix}/#{name}/repository#{pl.downloads_url '', arch.name, 'main', 'release'}"
|
||||
end
|
||||
else
|
||||
tail = ''
|
||||
urpmi_commands[pl.name] << "urpmi.addmedia #{name} #{head}#{name}/repository/#{pl.name}#{tail}"
|
||||
# urpmi_commands[pl.name] << "urpmi.addmedia #{name} #{prefix}/#{name}/repository#{pl.downloads_url ''}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -65,6 +68,27 @@ class Platform < ActiveRecord::Base
|
|||
Rails.root.join("public", "downloads", name)
|
||||
end
|
||||
|
||||
def prefix_url(pub, options = {})
|
||||
options[:host] ||= EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
|
||||
pub ? "http://#{options[:host]}/downloads" : "http://#{options[:login]}:#{options[:password]}@#{options[:host]}/private"
|
||||
end
|
||||
|
||||
def public_downloads_url(host = nil, arch = nil, repo = nil, suffix = nil)
|
||||
downloads_url prefix_url(true, :host => host), arch, repo, suffix
|
||||
end
|
||||
|
||||
def private_downloads_url(login, password, host = nil, arch = nil, repo = nil, suffix = nil)
|
||||
downloads_url prefix_url(false, :host => host, :login => login, :password => password), arch, repo, suffix
|
||||
end
|
||||
|
||||
def downloads_url(prefix, arch = nil, repo = nil, suffix = nil)
|
||||
"#{prefix}/#{name}/repository/".tap do |url|
|
||||
url << "#{arch}/" if arch.present?
|
||||
url << "#{repo}/" if repo.present?
|
||||
url << "#{suffix}/" if suffix.present?
|
||||
end
|
||||
end
|
||||
|
||||
def hidden?
|
||||
visibility == 'hidden'
|
||||
end
|
||||
|
@ -115,9 +139,7 @@ class Platform < ActiveRecord::Base
|
|||
system("sudo mkdir -p #{mount_path}")
|
||||
system("sudo mount --bind #{path} #{mount_path}")
|
||||
Arch.all.each do |arch|
|
||||
host = EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
|
||||
url = "http://#{host}/downloads/#{name}/repository/"
|
||||
str = "country=Russian Federation,city=Moscow,latitude=52.18,longitude=48.88,bw=1GB,version=2011,arch=#{arch.name},type=distrib,url=#{url}\n"
|
||||
str = "country=Russian Federation,city=Moscow,latitude=52.18,longitude=48.88,bw=1GB,version=2011,arch=#{arch.name},type=distrib,url=#{public_downloads_url}\n"
|
||||
File.open(File.join(mount_path, "#{name}.#{arch.name}.list"), 'w') {|f| f.write(str) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,11 +3,9 @@ class Product < ActiveRecord::Base
|
|||
|
||||
belongs_to :platform
|
||||
has_many :product_build_lists, :dependent => :destroy
|
||||
has_many :relations, :as => :target, :dependent => :destroy
|
||||
|
||||
after_validation :merge_tar_errors
|
||||
before_save :destroy_tar?
|
||||
after_create :add_admin_relations
|
||||
|
||||
has_attached_file :tar
|
||||
|
||||
|
@ -77,13 +75,4 @@ class Product < ActiveRecord::Base
|
|||
errors[:tar] += errors[:tar_content_type]
|
||||
errors[:tar_content_type] = []
|
||||
end
|
||||
|
||||
def add_admin_relations
|
||||
platform.relations.where(:role => 'admin').each do |rel|
|
||||
r = relations.build(:role => 'admin', :object_type => rel.object_type)
|
||||
r.object_id = rel.object_id
|
||||
r.save
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class Project < ActiveRecord::Base
|
|||
belongs_to :category, :counter_cache => true
|
||||
belongs_to :owner, :polymorphic => true
|
||||
|
||||
has_many :issues, :dependent => :destroy
|
||||
has_many :build_lists, :dependent => :destroy
|
||||
has_many :auto_build_lists, :dependent => :destroy
|
||||
|
||||
|
@ -136,6 +137,10 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def platforms
|
||||
@platforms ||= repositories.map(&:platform).uniq
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_path(dir)
|
||||
|
|
|
@ -7,4 +7,14 @@ class ProjectToRepository < ActiveRecord::Base
|
|||
after_create lambda { project.xml_rpc_create(repository) }, :unless => lambda {Thread.current[:skip]}
|
||||
after_destroy lambda { project.xml_rpc_destroy(repository) }
|
||||
# after_rollback lambda { project.xml_rpc_destroy(repository) rescue true if new_record? }
|
||||
|
||||
validate :one_project_in_platform_repositories
|
||||
|
||||
protected
|
||||
|
||||
def one_project_in_platform_repositories
|
||||
c = Platform.scoped.select('projects.*').joins(:repositories => :projects).where(
|
||||
:projects => {:name => project.name}, :id => repository.platform_id).count
|
||||
errors.add(:project, 'should be one in platform') if c > 0
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,6 +10,7 @@ class Relation < ActiveRecord::Base
|
|||
|
||||
scope :by_object, lambda {|obj| {:conditions => ['object_id = ? AND object_type = ?', obj.id, obj.class.to_s]}}
|
||||
scope :by_target, lambda {|tar| {:conditions => ['target_id = ? AND target_type = ?', tar.id, tar.class.to_s]}}
|
||||
scope :by_role, lambda {|role| {:conditions => ['role = ?', role]}}
|
||||
|
||||
def self.create_with_role(object, target, role)
|
||||
r = new
|
||||
|
|
|
@ -11,7 +11,7 @@ class Repository < ActiveRecord::Base
|
|||
has_many :groups, :through => :objects, :source => :object, :source_type => 'Group'
|
||||
|
||||
validates :description, :uniqueness => {:scope => :platform_id}, :presence => true
|
||||
validates :name, :uniqueness => {:scope => :platform_id}, :presence => true, :format => { :with => /^[a-z0-9_]+$/ }
|
||||
validates :name, :uniqueness => {:scope => :platform_id}, :presence => true, :format => { :with => /^[a-z0-9_\-]+$/ }
|
||||
# validates :platform_id, :presence => true # if you uncomment this platform clone will not work
|
||||
|
||||
scope :recent, order("name ASC")
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
class Subscribe < ActiveRecord::Base
|
||||
belongs_to :subscribeable, :polymorphic => true
|
||||
belongs_to :user
|
||||
end
|
|
@ -5,6 +5,7 @@ class User < ActiveRecord::Base
|
|||
:recoverable, :rememberable, :validatable #, :trackable, :confirmable, :lockable
|
||||
|
||||
has_many :authentications, :dependent => :destroy
|
||||
has_many :build_lists, :dependent => :destroy
|
||||
|
||||
has_many :relations, :as => :object, :dependent => :destroy
|
||||
has_many :targets, :as => :object, :class_name => 'Relation'
|
||||
|
|
|
@ -6,22 +6,20 @@
|
|||
%th= t("activerecord.attributes.build_list.project")
|
||||
%th= t("activerecord.attributes.build_list.arch")
|
||||
%th= t("activerecord.attributes.build_list.user")
|
||||
%th= t("activerecord.attributes.build_list.is_circle")
|
||||
- if controller.action_name = 'all'
|
||||
- unless @project
|
||||
%th= t("layout.build_lists.cancel_button_header")
|
||||
%th.last= t("activerecord.attributes.build_list.notified_at")
|
||||
|
||||
- build_lists.each do |build_list|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td= link_to (build_list.bs_id.present? ? build_list.bs_id : t("layout.build_lists.bs_id_not_set")), project_build_list_path(build_list.project, build_list)
|
||||
%td= link_to (build_list.bs_id.present? ? build_list.bs_id : t("layout.build_lists.bs_id_not_set")), build_list
|
||||
%td= build_list.human_status
|
||||
%td= link_to build_list.project_version, "#"
|
||||
%td= link_to build_list.project.name, project_path(build_list.project)
|
||||
%td= build_list.arch.name
|
||||
%td= build_list.user.fullname
|
||||
%td= t("layout.#{build_list.is_circle?}_")
|
||||
- if controller.action_name = 'all'
|
||||
%td= link_to t("layout.build_lists.cancel_button"), build_list_cancel_path(build_list) if build_list.can_cancel?
|
||||
%td= build_list.user.try(:fullname)
|
||||
- unless @project
|
||||
%td= link_to t("layout.build_lists.cancel_button"), cancel_build_list_path(build_list), :method => "put", :confirm => t("layout.confirm") if build_list.can_cancel?
|
||||
%td.last= build_list.notified_at
|
||||
|
||||
= will_paginate build_lists
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
= f.select :status, BuildList::STATUSES.collect{|status| [BuildList.human_status(status), status]}, :include_blank => true, :selected => @filter.status
|
||||
.group
|
||||
= f.label :arch_id, t("activerecord.attributes.build_list.arch"), :class => :label
|
||||
= f.select :arch_id, @arches.collect{|arch| [arch.name, arch.id]}, :include_blank => true, :selected => @filter.arch_id
|
||||
= f.select :arch_id, Arch.recent.collect{|arch| [arch.name, arch.id]}, :include_blank => true, :selected => @filter.arch_id
|
||||
.column.right
|
||||
- if @project_versions
|
||||
- if @project
|
||||
.group
|
||||
= f.label :project_version, t("activerecord.attributes.build_list.project_version"), :class => :label
|
||||
= f.select :project_version, @project_versions, :include_blank => true, :selected => @filter.project_version
|
||||
= f.select :project_version, @project.versions, :include_blank => true, :selected => @filter.project_version
|
||||
.group
|
||||
= f.label :is_circle, t("activerecord.attributes.build_list.is_circle"), :class => :label
|
||||
= f.select :is_circle, [[t("layout.yes_"), 1], [t("layout.no_"), 0]], :include_blank => true, :selected => @filter.is_circle.present? ? (@filter.is_circle ? "1" : "0") : nil
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
- platform.repositories.each do |repo|
|
||||
= 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
|
|
@ -1,10 +1,10 @@
|
|||
.block.notice
|
||||
%h3= t("layout.repositories.current_repository_header")
|
||||
.content
|
||||
- @project.repositories.each do |repository|
|
||||
- project.repositories.each do |repository|
|
||||
%p= link_to "#{repository.name} (#{repository.platform.name})", platform_repository_path(repository.platform, repository)
|
||||
|
||||
.block.notice
|
||||
%h3= t("layout.projects.current_project_header")
|
||||
.content
|
||||
%p= link_to @project.name, project_path(@project)
|
||||
%p= link_to project.name, project
|
|
@ -1,12 +1,12 @@
|
|||
.block
|
||||
- if controller.action_name != 'all'
|
||||
- if @project
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.build_lists.current"), project_path(@project) + "#build_lists"
|
||||
%li.active= link_to t("layout.build_lists.all"), project_build_lists_path(@project)
|
||||
|
||||
.content
|
||||
- if controller.action_name == 'all'
|
||||
- unless @project
|
||||
.inner
|
||||
%h2= t('layout.build_lists.build_server_status.header')
|
||||
.field
|
||||
|
@ -25,4 +25,4 @@
|
|||
.inner
|
||||
= render :partial => "build_lists/build_lists", :object => @build_lists
|
||||
|
||||
- content_for :sidebar, render(:partial => 'sidebar') if controller.action_name != 'all'
|
||||
- content_for :sidebar, render('sidebar', :project => @project) if @project
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first=# link_to t("layout.projects.list"), platform_repository_path(@platform, @repository) + "#projects"
|
||||
%li= link_to t("layout.projects.new"), new_project_path
|
||||
%li= link_to t("layout.projects.show"), project_path(@project)
|
||||
%li=# link_to "git-repo", project_repo_path(@platform, @repository, @project)
|
||||
%li.active= link_to t("layout.projects.build"), new_project_build_list_path(@project)
|
||||
|
||||
.content
|
||||
%h2.title= t("layout.projects.new_build", :project_name => @project.name)
|
||||
|
||||
.inner
|
||||
= form_for [@project, @build_list], :html => { :class => :form, :method => :post } do |f|
|
||||
.columns.wat-cf
|
||||
.column.left
|
||||
.group
|
||||
= f.label :project_version, t("activerecord.attributes.build_list.project_version"), :class => :label
|
||||
= f.select :project_version, @project.versions
|
||||
|
||||
.group.base_platforms
|
||||
= f.label :bpl, t("activerecord.attributes.build_list.bpl"), :class => :label
|
||||
- Platform.main.each do |bpl|
|
||||
= check_box_tag "bpls[]", bpl.id, (params[:bpls]||[]).include?(bpl.id.to_s), :class => 'build_bpl_ids', :id => "bpls_#{bpl.id}"
|
||||
= label_tag "bpls_#{bpl.id}", bpl.name
|
||||
%br
|
||||
|
||||
.group
|
||||
= f.label :update_type, t("activerecord.attributes.build_list.update_type"), :class => :label
|
||||
= f.select :update_type, BuildList::UPDATE_TYPES
|
||||
|
||||
.group
|
||||
= f.check_box :build_requires
|
||||
= f.label :build_requires, t("activerecord.attributes.build_list.build_requires")
|
||||
|
||||
|
||||
.column.right
|
||||
.group
|
||||
= f.label :arches, t("activerecord.attributes.build_list.arch"), :class => :label
|
||||
- Arch.recent.each do |arch|
|
||||
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}"
|
||||
= label_tag "arches_#{arch.id}", arch.name
|
||||
%br
|
||||
|
||||
.group
|
||||
= f.label :pl_id, t("activerecord.attributes.build_list.pl"), :class => :label
|
||||
= f.select :pl_id, @project.repositories.collect{|r| ["#{r.platform.name}/#{r.name}", r.platform.id]}
|
||||
|
||||
.group
|
||||
= f.label :include_repos, t("activerecord.attributes.build_list.include_repos"), :class => :label
|
||||
#include_repos
|
||||
|
||||
.group
|
||||
= f.check_box :auto_publish
|
||||
= f.label :auto_publish, t("activerecord.attributes.build_list.auto_publish")
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.projects.build_button"))
|
||||
= t("layout.projects.build_button")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), root_path, :class => "text_button_padding link_button"
|
||||
|
||||
.preloaded_include_repos{:style => 'display: none'}
|
||||
- @project.platforms.each do |p|
|
||||
%div{:class => "include_repos_#{p.id}"}= render 'include_repos', :platform => p
|
|
@ -1,9 +1,9 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.build_lists.current"), project_path(@project) + "#build_lists"
|
||||
%li= link_to t("layout.build_lists.all"), project_build_lists_path(@project)
|
||||
%li.active= link_to t("layout.build_lists.show"), project_build_list_path(@project, @build_list)
|
||||
%li.first= link_to t("layout.build_lists.current"), project_path(@build_list.project) + "#build_lists"
|
||||
%li= link_to t("layout.build_lists.all"), project_build_lists_path(@build_list.project)
|
||||
%li.active= link_to t("layout.build_lists.show"), @build_list
|
||||
|
||||
.content
|
||||
.inner
|
||||
|
@ -34,6 +34,11 @@
|
|||
= t("activerecord.attributes.build_list.pl")
|
||||
\:
|
||||
= @build_list.pl.name
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.build_list.include_repos")
|
||||
\:
|
||||
= (@build_list.include_repos||[]).map{|r| Repository.find(r).name}.join(', ')
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.build_list.update_type")
|
||||
|
@ -44,6 +49,11 @@
|
|||
= t("activerecord.attributes.build_list.build_requires")
|
||||
\:
|
||||
= @build_list.build_requires
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.build_list.auto_publish")
|
||||
\:
|
||||
= @build_list.auto_publish
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.build_list.status")
|
||||
|
@ -68,7 +78,7 @@
|
|||
%b
|
||||
= t("activerecord.attributes.build_list.user")
|
||||
\:
|
||||
= @build_list.user.fullname
|
||||
= @build_list.user.try(:fullname)
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.build_list.notified_at")
|
||||
|
@ -80,9 +90,9 @@
|
|||
\:
|
||||
= t("layout.#{@build_list.is_circle?}_")
|
||||
|
||||
- if @build_list.can_published?
|
||||
- if @build_list.can_publish?
|
||||
.wat-cf
|
||||
= link_to image_tag("web-app-theme/icons/tick.png", :alt => t("layout.publish")) + " " + t("layout.publish"), publish_project_build_list_path(@project, @build_list), :method => "post", :class => "button", :confirm => t("layout.build_lists.confirm_publish")
|
||||
= link_to image_tag("web-app-theme/icons/tick.png", :alt => t("layout.publish")) + " " + t("layout.publish"), publish_build_list_path(@build_list), :method => "put", :class => "button", :confirm => t("layout.confirm")
|
||||
|
||||
.block
|
||||
.content
|
||||
|
@ -106,4 +116,4 @@
|
|||
%td= item.version
|
||||
%td.last= item.human_status
|
||||
|
||||
- content_for :sidebar, render(:partial => 'sidebar')
|
||||
- content_for :sidebar, render('sidebar', :project => @build_list.project)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.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("web-app-theme/icons/tick.png", :alt => t("layout.save"))
|
||||
= t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), [@issue.project, @issue], :class => "text_button_padding link_button"
|
|
@ -0,0 +1,10 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issue_path(@project, @issue)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.edit_header")
|
||||
.inner
|
||||
= form_for @comment, :url => project_issue_comment_path(@project, @issue, @comment), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -4,7 +4,7 @@
|
|||
%li= link_to t("layout.projects.new"), new_project_path
|
||||
%li= link_to t("layout.projects.show"), project_path(@project)
|
||||
%li.active= link_to t("layout.git.repositories.source"), project_repo_path(@project)
|
||||
%li= link_to t("layout.projects.build"), build_project_path(@project)
|
||||
%li= link_to t("layout.projects.build"), new_project_build_list_path(@project)
|
||||
|
||||
%ul#git_submenu.sub-wat-cf.wat-cf
|
||||
%li= link_to t("layout.git.repositories.commits"), commits_path(@project, :treeish => @treeish)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
= javascript_include_tag "autocomplete-rails.js"
|
||||
|
||||
.group
|
||||
= f.label :title, :class => :label
|
||||
= f.text_field :title, :class => 'text_field'
|
||||
|
||||
.group
|
||||
= f.label :body, :class => :label
|
||||
= f.text_area :body, :class => 'text_field', :cols => 80
|
||||
|
||||
- unless @issue.new_record?
|
||||
.group
|
||||
= f.label :status, :class => :label
|
||||
= f.select :status, Issue::STATUSES, :class => 'text_field'
|
||||
|
||||
.group
|
||||
= label_tag "", t("activerecord.attributes.issue.user_id"), :class => :label
|
||||
= autocomplete_field_tag 'user_id', @user_uname, autocomplete_user_uname_platforms_path, :id_element => '#user_id_field'
|
||||
= hidden_field_tag 'user_id', @user_id, :id => 'user_id_field'
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save"))
|
||||
= t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), project_path(@project), :class => "text_button_padding link_button"
|
|
@ -0,0 +1,18 @@
|
|||
%table.table
|
||||
%tr
|
||||
%th.first= t("activerecord.attributes.issue.title")
|
||||
%th.first= t("activerecord.attributes.issue.user")
|
||||
%th.first= t("activerecord.attributes.issue.status")
|
||||
%th.last
|
||||
- @issues.each do |issue|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td
|
||||
= link_to issue.title, [@project, issue]
|
||||
%td
|
||||
= link_to issue.user.uname, user_path(issue.user) if issue.user
|
||||
%td
|
||||
= issue.status
|
||||
%td.last
|
||||
= link_to t("layout.show"), [@project, issue]
|
||||
|
|
||||
= link_to t("layout.delete"), project_issue_path(@project, issue), :method => :delete, :confirm => t("layout.issues.confirm_delete") if can? :destroy, issue
|
|
@ -0,0 +1,11 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.new"), new_project_issue_path(@project)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.edit_header")
|
||||
.inner
|
||||
= form_for @issue, :url => project_issue_path(@project, @issue), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -0,0 +1,22 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first.active= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.new"), new_project_issue_path(@project) if can? :new, Issue.new(:project_id => @project.id)
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li{:class => "first " + (params[:status].blank? ? "active" : "")}
|
||||
= link_to t("layout.issues.statuses.any"), project_issues_path(@project)
|
||||
%li{:class => "first " + (params[:status] == 'open' ? "active" : "")}
|
||||
= link_to t("layout.issues.statuses.open"), project_issues_path(@project, :status => 'open')
|
||||
%li{:class => "first " + (params[:status] == 'closed' ? "active" : "")}
|
||||
= link_to t("layout.issues.statuses.closed"), project_issues_path(@project, :status => 'closed')
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.list_header")
|
||||
.inner
|
||||
= render :partial => 'shared/search_form'
|
||||
= render :partial => 'issues/list'
|
||||
.actions-bar.wat-cf
|
||||
.actions
|
||||
= will_paginate @issues, :param_name => :issue_page
|
|
@ -0,0 +1,11 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to "#{t("layout.issues.list")}", project_issues_path(@project)
|
||||
%li.active= link_to "#{t("layout.issues.new")}", new_project_issue_path(@project)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.new_header")
|
||||
.inner
|
||||
= form_for :issue, :url => project_issues_path(@project), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -0,0 +1,56 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.edit"), edit_project_issue_path(@project, @issue) if can? :edit, @issue
|
||||
.content
|
||||
.inner
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.issue.title")
|
||||
\:
|
||||
= @issue.title
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.issue.body")
|
||||
\:
|
||||
= @issue.body
|
||||
%p
|
||||
%b
|
||||
= t('activerecord.attributes.issue.status')
|
||||
\:
|
||||
= @issue.status
|
||||
%p
|
||||
%b
|
||||
= t('layout.issues.subscribe')
|
||||
\:
|
||||
- if @issue.subscribes.exists? :user_id => current_user.id
|
||||
= link_to t('layout.issues.unsubscribe_btn'), project_issue_subscribe_path(@project, @issue, current_user.id), :method => :delete
|
||||
- else
|
||||
= link_to t('layout.issues.subscribe_btn'), project_issue_subscribes_path(@project, @issue), :method => :post
|
||||
|
||||
%a{ :name => "comments" }
|
||||
.block#block-list
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.comments_header")
|
||||
.inner
|
||||
%ul.list
|
||||
- @issue.comments.each do |comment|
|
||||
%li
|
||||
.left
|
||||
= link_to comment.user.uname, user_path(comment.user.uname)
|
||||
.item
|
||||
= comment.body
|
||||
%br
|
||||
%br
|
||||
= link_to t("layout.edit"), edit_project_issue_comment_path(@project, @issue.id, comment) if can? :update, comment
|
||||
= link_to image_tag("web-app-theme/icons/cross.png", :alt => t("layout.delete")) + " " + t("layout.delete"), project_issue_comment_path(@project, @issue.id, comment), :method => "delete", :class => "button", :confirm => t("layout.comments.confirm_delete") if can? :delete, comment
|
||||
|
||||
.block
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.comments.new_header")
|
||||
.inner
|
||||
= form_for :comment, :url => project_issue_comments_path(@project, @issue), :method => :post, :html => { :class => :form } do |f|
|
||||
= render :partial => "comments/form", :locals => {:f => f}
|
|
@ -1,6 +1,6 @@
|
|||
-#= include_stylesheets :application
|
||||
|
||||
= stylesheet_link_tag "web-app-theme/base.css", "web-app-theme/themes/default/style.css", "web-app-theme/override.css", "git/style.css"
|
||||
= stylesheet_link_tag "jquery-ui-1.8.16.custom.css"
|
||||
= stylesheet_link_tag "jquery-ui-1.8.16.custom.css", "datatable.css", "patches.css"
|
||||
|
||||
= yield :stylesheets
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
.group
|
||||
= f.label :description, t("activerecord.attributes.project.description"), :class => :label
|
||||
= f.text_area :description, :class => 'text_field', :cols => 80
|
||||
.group
|
||||
= f.label :has_issues, t("activerecord.attributes.project.has_issues"), :class => :label
|
||||
= f.check_box :has_issues
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first=# link_to t("layout.projects.list"), platform_repository_path(@platform, @repository) + "#projects"
|
||||
%li= link_to t("layout.projects.new"), new_project_path
|
||||
%li= link_to t("layout.projects.show"), project_path(@project)
|
||||
%li=# link_to "git-repo", project_repo_path(@platform, @repository, @project)
|
||||
%li.active= link_to t("layout.projects.build"), build_project_path(@project)
|
||||
|
||||
.content
|
||||
%h2.title= t("layout.projects.new_build", :project_name => @project.name)
|
||||
|
||||
.inner
|
||||
= form_for :build, :url => process_build_project_path(@project), :html => { :class => :form, :method => :post } do |f|
|
||||
.columns.wat-cf
|
||||
.column.left
|
||||
.group
|
||||
= f.label :project_version, t("activerecord.attributes.build_list.project_version"), :class => :label
|
||||
= f.select :project_version, @project_versions
|
||||
|
||||
.group.pl_ids_container
|
||||
= f.label :bpl, t("activerecord.attributes.build_list.bpl"), :class => :label
|
||||
- @bpls.each do |bpl|
|
||||
= f.check_box "bpl[#{bpl.id}]", :bpl_id => bpl.id, :class => 'build_bpl_ids'
|
||||
= bpl.name
|
||||
%br
|
||||
|
||||
.group
|
||||
= f.label :update_type, t("activerecord.attributes.build_list.update_type"), :class => :label
|
||||
= f.select :update_type, BuildList::UPDATE_TYPES.collect { |ut| [ut, ut] }
|
||||
|
||||
.group
|
||||
= f.check_box :build_requires
|
||||
= t("activerecord.attributes.build_list.build_requires")
|
||||
|
||||
|
||||
.column.right
|
||||
.group
|
||||
= f.label :arches, t("activerecord.attributes.build_list.arch"), :class => :label
|
||||
- @arches.each do |arch|
|
||||
= f.check_box "arches[#{arch.id}]"
|
||||
= arch.name
|
||||
%br
|
||||
|
||||
.group
|
||||
= f.label :pl, t("activerecord.attributes.build_list.pl"), :class => :label
|
||||
= f.select :pl, @pls
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.projects.build_button"))
|
||||
= t("layout.projects.build_button")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), root_path, :class => "text_button_padding link_button"
|
||||
|
||||
-# content_for :sidebar, render(:partial => 'sidebar')
|
|
@ -5,7 +5,8 @@
|
|||
%li= link_to t("layout.projects.new"), new_project_path
|
||||
%li.active= link_to t("layout.projects.show"), project_path(@project)
|
||||
%li= link_to t("layout.git.repositories.source"), project_repo_path(@project)
|
||||
%li= link_to t("layout.projects.build"), build_project_path(@project)
|
||||
%li= link_to t("layout.projects.build"), new_project_build_list_path(@project)
|
||||
%li= link_to t("layout.projects.issues"), project_issues_path(@project)
|
||||
|
||||
.content
|
||||
.inner
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"sEcho": <%=h params[:sEcho].to_i || -1 %>,
|
||||
"iTotalRecords": <%= @total_projects %>,
|
||||
"iTotalDisplayRecords": <%= @total_project %>,
|
||||
"aaData": [
|
||||
<% @projects.each do |project| %>
|
||||
[
|
||||
"<%=j link_to project.owner.uname, project.owner %>",
|
||||
"<%=j link_to project.name, project %>",
|
||||
"<%=j link_to t("layout.add"), url_for(:controller => :repositories, :action => :add_project, :project_id => project.id) %>"
|
||||
]<%= project == @projects.last ? '' : ',' %>
|
||||
<% end %>
|
||||
]
|
||||
}
|
||||
|
|
@ -1,11 +1,21 @@
|
|||
%table.table
|
||||
%tr
|
||||
%th.first= t("activerecord.attributes.project.name")
|
||||
%th.last
|
||||
- @projects.each do |project|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td
|
||||
= link_to project.owner.name + '/' + project.name, project_path(project)
|
||||
%td.last
|
||||
#{link_to t("layout.show"), project_path(project)} | #{link_to t("layout.add"), url_for(:controller => :repositories, :action => :add_project, :project_id => project.id)}
|
||||
- columns = [{:type => 'html', :searchable => false}, {:type => 'html'}, {:type => nil, :sortable => false, :searchable => false}]
|
||||
= raw datatable(columns, {:sort_by => "[1, 'asc']", :search_label => t("layout.search_by_name"), :processing => t("layout.processing"),
|
||||
:pagination_labels => {:first => t("datatables.first_label"), :previous => t("datatables.previous_label"),
|
||||
:next => t("datatables.next_label"), :last => t("datatables.last_label")},
|
||||
:empty_label => t("datatables.empty_label"),
|
||||
:info_label => t("datatables.info_label"),
|
||||
:info_empty_label => t("datatables.info_empty_label"),
|
||||
:filtered_label => t("datatables.filtered_label"),
|
||||
:ajax_source => "#{url_for :controller => :repositories, :action => :projects_list, :id => @repository.id}" })
|
||||
|
||||
%table.table.datatable
|
||||
%thead
|
||||
%tr
|
||||
%th.first{:style => 'width: 80px'}= t("activerecord.attributes.user.uname")
|
||||
%th= t("activerecord.attributes.project.name")
|
||||
%th.last
|
||||
%tbody
|
||||
%br
|
||||
|
||||
= content_for :javascripts do
|
||||
= javascript_include_tag 'jquery.dataTables.min.js'
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
%h2.title
|
||||
= t("layout.projects.list_header")
|
||||
.inner
|
||||
= render :partial => 'shared/search_form'
|
||||
-#= render :partial => 'shared/search_form'
|
||||
= render :partial => 'proj_list', :object => @projects
|
||||
.actions-bar.wat-cf
|
||||
-#.actions-bar.wat-cf
|
||||
.actions
|
||||
= will_paginate @projects, :param_name => :project_page
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
%p== Здравствуйте, #{@user.name}.
|
||||
|
||||
|
||||
%p Вам была назначена задача #{ link_to @issue.title, [@issue.project, @issue] }
|
||||
|
||||
|
||||
%p== Команда поддержки «ROSA Build System»
|
|
@ -0,0 +1,7 @@
|
|||
%p== Здравствуйте, #{@user.name}.
|
||||
|
||||
|
||||
%p К задаче #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } был добавлен новый комментарий.
|
||||
|
||||
|
||||
%p== Команда поддержки «ROSA Build System»
|
|
@ -0,0 +1,7 @@
|
|||
%p== Здравствуйте, #{@user.name}.
|
||||
|
||||
|
||||
%p К проекту #{ link_to @issue.project.name, project_path(@issue.project) } была добавлена задача #{ link_to @issue.title, [@issue.project, @issue] }
|
||||
|
||||
|
||||
%p== Команда поддержки «ROSA Build System»
|
|
@ -23,8 +23,8 @@ ru:
|
|||
open_id: 'вход через OpenID'
|
||||
projects_controller:
|
||||
auto_build: 'отправлен на автоматическую сборку'
|
||||
process_build: 'отправлен на сборку'
|
||||
build_lists_controller:
|
||||
create: 'отправлен на сборку'
|
||||
cancel: 'сборка отменена'
|
||||
publish: 'сборка опубликована'
|
||||
auto_build_lists_controller:
|
||||
|
|
|
@ -4,6 +4,16 @@ ru:
|
|||
next_label: Следующая ›
|
||||
page_gap: ...
|
||||
|
||||
datatables:
|
||||
previous_label: ‹ Пред.
|
||||
next_label: След. ›
|
||||
first_label: « Первая
|
||||
last_label: Последняя »
|
||||
empty_label: Нет доступных данных
|
||||
info_label: Показаны записи с _START_ по _END_ из _TOTAL_
|
||||
info_empty_label: Показаны записи с 0 по 0 из 0
|
||||
filtered_label: (отфильтровано из _MAX_)
|
||||
|
||||
layout:
|
||||
logged_in_as: Вы вошли как
|
||||
logout: Выйти
|
||||
|
@ -30,6 +40,7 @@ ru:
|
|||
not_access: Нет доступа!
|
||||
owner: Владелец
|
||||
confirm: Уверенны?
|
||||
processing: Обрабатывается...
|
||||
|
||||
downloads:
|
||||
title: Статистика закачек пакетов
|
||||
|
@ -83,6 +94,7 @@ ru:
|
|||
confirm_regenerate: Вы уверены, что хотите перегенерировать эту пару логин/пароль?
|
||||
regenerate_btn: Перегенерировать
|
||||
warning_message: Примечание - При получении новых данных старые становятся недействительными
|
||||
|
||||
categories:
|
||||
list: Список
|
||||
new: Создать
|
||||
|
@ -93,6 +105,27 @@ ru:
|
|||
edit_header: Редактировать категорию
|
||||
confirm_delete: Вы уверены, что хотите удалить эту категорию?
|
||||
|
||||
issues:
|
||||
list: Список
|
||||
edit: Редактировать
|
||||
comments_header: Комментарии
|
||||
new: Новая задача
|
||||
list_header: Список
|
||||
confirm_delete: Вы уверены, что хотите удалить эту задачу?
|
||||
edit_header: Редактирование задачи
|
||||
new_header: Новая задача
|
||||
statuses:
|
||||
open: Открытые
|
||||
closed: Закрытые
|
||||
any: Все
|
||||
subscribe: Подписка на уведомления
|
||||
subscribe_btn: Подписаться
|
||||
unsubscribe_btn: Отписаться
|
||||
|
||||
comments:
|
||||
confirm_delete: Вы уверены, что хотите удалить комментарий?
|
||||
new_header: Новый комментарий
|
||||
|
||||
platforms:
|
||||
admin_id: Владелец
|
||||
build_all: Собрать все
|
||||
|
@ -214,6 +247,7 @@ ru:
|
|||
collaborators: Коллабораторы
|
||||
groups: Группы
|
||||
edit_collaborators: Изменить список участников
|
||||
issues: Задачи
|
||||
|
||||
collaborators:
|
||||
back_to_proj: Вернуться к проекту
|
||||
|
@ -280,7 +314,6 @@ ru:
|
|||
build_lists:
|
||||
filter_header: Фильтр
|
||||
current: Текущие
|
||||
all: Все
|
||||
created_at_start: "Время постановки на сборку с:"
|
||||
created_at_end: "Время постановки на сборку по:"
|
||||
notified_at_start: "Время последнего обновления от BS с:"
|
||||
|
@ -291,11 +324,12 @@ ru:
|
|||
items_header: Элементы сборки
|
||||
no_items_data: Данных нет
|
||||
show: Просмотр
|
||||
confirm_publish: Вы уверены, что хотите опубликовать контейнер?
|
||||
cancel_button_header: Действие
|
||||
cancel_button: Отмена
|
||||
cancel_successed: 'Сборка отменена.'
|
||||
cancel_failed: 'При отмене сборки произошла ошибка!'
|
||||
cancel_success: 'Сборка отменена.'
|
||||
cancel_fail: 'При отмене сборки произошла ошибка!'
|
||||
publish_success: 'Сборка поставлена в очередь на публикацию.'
|
||||
publish_fail: 'При публикации сборки произошла ошибка!'
|
||||
|
||||
build_server_status:
|
||||
header: Статус сборочного сервера
|
||||
|
@ -314,6 +348,8 @@ ru:
|
|||
statuses:
|
||||
build_error: ошибка сборки
|
||||
build_published: опубликован
|
||||
build_publish: публикуется
|
||||
failed_publish: ошибка публикации
|
||||
dependencies_fail: зависимости не найдены
|
||||
waiting_for_response: ожидает ответа
|
||||
build_pending: ожидает сборку
|
||||
|
@ -328,6 +364,10 @@ ru:
|
|||
project_version_not_found: версия не найден
|
||||
|
||||
flash:
|
||||
subscribe:
|
||||
saved: Вы подписаны на оповещения для этой задачи
|
||||
destroyed: Подписка на оповещения для этой задачи убрана
|
||||
|
||||
exception_message: У Вас нет доступа к этой странице!
|
||||
|
||||
downloads:
|
||||
|
@ -359,6 +399,16 @@ ru:
|
|||
save_error: Не удалось сохранить категорию
|
||||
destroyed: Категория успешно удалена
|
||||
|
||||
comment:
|
||||
saved: Комментарий успешно сохранен
|
||||
save_error: Ошибка сохранения комментария
|
||||
destroyed: Комментарий удален
|
||||
|
||||
issue:
|
||||
saved: Задача успешно сохранена
|
||||
save_error: Не удалось сохранить задачу
|
||||
destroyed: Задача успешно удалена
|
||||
|
||||
project:
|
||||
saved: Проект успешно сохранен
|
||||
save_error: Не удалось сохранить проект
|
||||
|
@ -378,10 +428,6 @@ ru:
|
|||
destroyed: Группа успешно удалена
|
||||
user_uname_exists: Пользователь с таким именем уже зарегестрирован
|
||||
|
||||
role:
|
||||
saved: Роль успешно сохранена
|
||||
save_error: Ошибка сохранения роли
|
||||
|
||||
repository:
|
||||
saved: Репозиторий успешно добавлен
|
||||
save_error: Не удалось добавить репозиторий
|
||||
|
@ -399,7 +445,7 @@ ru:
|
|||
|
||||
platform:
|
||||
saved: Платформа успешно добавлена
|
||||
saved_error: Не удалось создать платформу
|
||||
save_error: Не удалось создать платформу
|
||||
freezed: Платформа успешно заморожена
|
||||
freeze_error: Не удалось заморозить платформу, попробуйте еще раз
|
||||
unfreezed: Платформа успешно разморожена
|
||||
|
@ -412,8 +458,7 @@ ru:
|
|||
save_error: Не удалось сохранить билд лист для версии '%{project_version}', платформы '%{bpl}' и архитектуры '%{arch}'
|
||||
no_project_version_selected: Выберите какую-нибудь версию
|
||||
no_project_version_found: Выбранная версия '%{project_version}' не найдена
|
||||
no_arch_selected: Выберите хотя бы одну ахритектуру
|
||||
no_arch_found: Выбранные ахритектуры не найдены
|
||||
no_arch_or_platform_selected: Выберите хотя бы одну ахритектуру и платформу
|
||||
wrong_platform: Для основного репозитория (main) может быть выбран только его же основная платформа!
|
||||
can_not_published: Опубликовать сборку можно только со статусом "Собран"
|
||||
|
||||
|
@ -456,6 +501,18 @@ ru:
|
|||
arch_id: Архитектура
|
||||
arch: Архитектура
|
||||
|
||||
comment:
|
||||
body: Содержание
|
||||
user: Автор
|
||||
|
||||
issue:
|
||||
title: Заголовок
|
||||
body: Содержание
|
||||
user: Назначена
|
||||
user_id: Назначена
|
||||
project: Проект
|
||||
status: Статус
|
||||
|
||||
private_user:
|
||||
login: Логин
|
||||
password: Пароль
|
||||
|
@ -536,6 +593,7 @@ ru:
|
|||
repository: Репозиторий
|
||||
created_at: Создан
|
||||
updated_at: Обновлен
|
||||
has_issues: Включить трэкер
|
||||
|
||||
rpm:
|
||||
name: Название
|
||||
|
@ -590,6 +648,7 @@ ru:
|
|||
is_circle: Циклическая сборка
|
||||
notified_at: Информация получена
|
||||
additional_repos: Дополнительные репозитории
|
||||
include_repos: Подключаемые репозитории
|
||||
updated_at: Обновлен
|
||||
created_at: Создан
|
||||
pl: Репозиторий для сохранения пакетов
|
||||
|
@ -598,6 +657,7 @@ ru:
|
|||
bpl_id: Платформа
|
||||
update_type: Критичность обновления
|
||||
build_requires: Пересборка с зависимостями
|
||||
auto_publish: Автоматическая публикация
|
||||
project_version: Версия
|
||||
user: Пользователь
|
||||
|
||||
|
@ -613,3 +673,9 @@ ru:
|
|||
distro: Дистрибутив
|
||||
platform: Архитектура
|
||||
counter: Закачки
|
||||
notifications:
|
||||
subjects:
|
||||
new_comment_notification: Новый комментарий к Вашей задаче
|
||||
new_issue_notification: Новая задача добавлена к проекту
|
||||
new_user_notification: Регистрация на проекте «%{ project_name }»
|
||||
issue_assign_notification: Вам назначили задачу
|
||||
|
|
|
@ -24,23 +24,17 @@ Rosa::Application.routes.draw do
|
|||
|
||||
match '/private/:platform_name/*file_path' => 'privates#show'
|
||||
|
||||
# match 'build_lists/' => 'build_lists#index', :as => :all_build_lists
|
||||
# match 'build_lists/:id/cancel/' => 'build_lists#cancel', :as => :build_list_cancel
|
||||
# match 'build_lists/status_build', :to => "build_lists#status_build"
|
||||
# match 'build_lists/post_build', :to => "build_lists#post_build"
|
||||
# match 'build_lists/pre_build', :to => "build_lists#pre_build"
|
||||
# match 'build_lists/circle_build', :to => "build_lists#circle_build"
|
||||
# match 'build_lists/new_bbdt', :to => "build_lists#new_bbdt"
|
||||
match 'build_lists/publish_build', :to => "build_lists#publish_build"
|
||||
match 'build_lists/status_build', :to => "build_lists#status_build"
|
||||
match 'build_lists/post_build', :to => "build_lists#post_build"
|
||||
match 'build_lists/pre_build', :to => "build_lists#pre_build"
|
||||
match 'build_lists/circle_build', :to => "build_lists#circle_build"
|
||||
match 'build_lists/new_bbdt', :to => "build_lists#new_bbdt"
|
||||
|
||||
|
||||
resources :build_lists, :only => [:index, :cancel, :status_build, :post_build, :pre_build, :circle_build, :new_bbdt] do
|
||||
resources :build_lists, :only => [:index, :show] do
|
||||
member do
|
||||
get :cancel
|
||||
get :status_build
|
||||
get :post_build
|
||||
get :pre_build
|
||||
get :circle_build
|
||||
get :new_bbdt
|
||||
put :cancel
|
||||
put :publish
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -85,7 +79,6 @@ Rosa::Application.routes.draw do
|
|||
end
|
||||
|
||||
resources :projects do
|
||||
resource :repo, :controller => "git/repositories", :only => [:show]
|
||||
resources :wiki do
|
||||
collection do
|
||||
# Uncomment if gollum can revert page without name
|
||||
|
@ -104,15 +97,12 @@ Rosa::Application.routes.draw do
|
|||
match 'compare/*versions' => 'wiki#compare', :as => :compare_versions, :via => :get
|
||||
end
|
||||
end
|
||||
resources :build_lists, :only => [:index, :show] do
|
||||
collection do
|
||||
get :recent
|
||||
post :filter
|
||||
end
|
||||
member do
|
||||
post :publish
|
||||
end
|
||||
resources :issues do
|
||||
resources :comments, :only => [:edit, :create, :update, :destroy]
|
||||
resources :subscribes, :only => [:create, :destroy]
|
||||
end
|
||||
resource :repo, :controller => "git/repositories", :only => [:show]
|
||||
resources :build_lists, :only => [:index, :new, :create]
|
||||
|
||||
resources :collaborators, :only => [:index, :edit, :update, :add] do
|
||||
collection do
|
||||
|
@ -128,8 +118,6 @@ Rosa::Application.routes.draw do
|
|||
# end
|
||||
|
||||
member do
|
||||
get :build
|
||||
post :process_build
|
||||
post :fork
|
||||
end
|
||||
collection do
|
||||
|
@ -141,6 +129,7 @@ Rosa::Application.routes.draw do
|
|||
member do
|
||||
get :add_project
|
||||
get :remove_project
|
||||
get :projects_list
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class CreateIssues < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :issues do |t|
|
||||
t.integer :serial_id
|
||||
t.integer :project_id
|
||||
t.integer :user_id
|
||||
t.string :title
|
||||
t.text :body
|
||||
t.string :status
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :issues, [:project_id, :serial_id], :unique => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :issues
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
class CreateComments < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :comments do |t|
|
||||
t.integer :commentable_id
|
||||
t.string :commentable_type
|
||||
t.integer :user_id
|
||||
t.text :body
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :comments
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class AddHasIssuesToProjects < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :projects, :has_issues, :boolean, :default => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :projects, :has_issues
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class AddIncludeReposToBuildLists < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :build_lists, :include_repos, :text
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :build_lists, :include_repos
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class AddUserIdToBuildLists < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :build_lists, :user_id, :integer
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :build_lists, :user_id
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
class CreateSubscribes < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :subscribes do |t|
|
||||
t.integer :subscribeable_id
|
||||
t.string :subscribeable_type
|
||||
t.integer :user_id
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :subscribes
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class AddAutoPublishToBuildLists < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :build_lists, :auto_publish, :boolean, :default => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :build_lists, :auto_publish
|
||||
end
|
||||
end
|
34
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20111221194422) do
|
||||
ActiveRecord::Schema.define(:version => 20111228182425) do
|
||||
|
||||
create_table "arches", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
|
@ -71,6 +71,7 @@ ActiveRecord::Schema.define(:version => 20111221194422) do
|
|||
t.integer "pl_id"
|
||||
t.text "include_repos"
|
||||
t.integer "user_id"
|
||||
t.boolean "auto_publish", :default => true
|
||||
end
|
||||
|
||||
add_index "build_lists", ["arch_id"], :name => "index_build_lists_on_arch_id"
|
||||
|
@ -85,6 +86,15 @@ ActiveRecord::Schema.define(:version => 20111221194422) do
|
|||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "comments", :force => true do |t|
|
||||
t.integer "commentable_id"
|
||||
t.string "commentable_type"
|
||||
t.integer "user_id"
|
||||
t.text "body"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "containers", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.integer "project_id", :null => false
|
||||
|
@ -142,6 +152,19 @@ ActiveRecord::Schema.define(:version => 20111221194422) do
|
|||
t.string "uname"
|
||||
end
|
||||
|
||||
create_table "issues", :force => true do |t|
|
||||
t.integer "serial_id"
|
||||
t.integer "project_id"
|
||||
t.integer "user_id"
|
||||
t.string "title"
|
||||
t.text "body"
|
||||
t.string "status"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "issues", ["project_id", "serial_id"], :name => "index_issues_on_project_id_and_serial_id", :unique => true
|
||||
|
||||
create_table "platforms", :force => true do |t|
|
||||
t.string "description"
|
||||
t.string "name"
|
||||
|
@ -214,6 +237,7 @@ ActiveRecord::Schema.define(:version => 20111221194422) do
|
|||
t.text "description"
|
||||
t.string "ancestry"
|
||||
t.boolean "has_wiki"
|
||||
t.boolean "has_issues", :default => true
|
||||
end
|
||||
|
||||
add_index "projects", ["category_id"], :name => "index_projects_on_category_id"
|
||||
|
@ -249,6 +273,14 @@ ActiveRecord::Schema.define(:version => 20111221194422) do
|
|||
add_index "rpms", ["project_id", "arch_id"], :name => "index_rpms_on_project_id_and_arch_id"
|
||||
add_index "rpms", ["project_id"], :name => "index_rpms_on_project_id"
|
||||
|
||||
create_table "subscribes", :force => true do |t|
|
||||
t.integer "subscribeable_id"
|
||||
t.string "subscribeable_type"
|
||||
t.integer "user_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "users", :force => true do |t|
|
||||
t.string "name"
|
||||
t.string "email", :default => "", :null => false
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
=== Basic bootstrap
|
||||
|
||||
* rake db:drop db:setup
|
||||
|
||||
==
|
||||
|
||||
=== Setup autostart
|
||||
Add to /etc/rc.d/rc.local following /srv/rosa_build/current/bin/autostart.sh
|
||||
==
|
||||
|
||||
Add to /etc/rc.d/rc.local
|
||||
|
||||
/srv/rosa_build/current/bin/autostart.sh
|
||||
|
||||
Add to /etc/rc.d/rc.sysinit
|
||||
|
||||
# force run rc.local
|
||||
if [ -f /etc/rc.local ]; then
|
||||
. /etc/rc.local
|
||||
fi
|
||||
|
||||
==
|
||||
|
|
|
@ -72,8 +72,15 @@ class BuildServer
|
|||
self.client.call('add_to_repo', name, repo_name)
|
||||
end
|
||||
|
||||
def self.add_build_list project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web
|
||||
self.client.call('add_build_list', project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web)
|
||||
def self.add_build_list project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web, include_repos
|
||||
include_repos_hash = {}.tap do |h|
|
||||
include_repos.each do |r|
|
||||
repo = Repository.find r
|
||||
h[repo.name] = repo.platform.public_downloads_url(nil, arch, repo.name)
|
||||
end
|
||||
end
|
||||
# raise include_repos_hash.inspect
|
||||
self.client.call('add_build_list', project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web, include_repos_hash)
|
||||
end
|
||||
|
||||
def self.delete_build_list idlist
|
||||
|
|
|
@ -28,7 +28,7 @@ module Grack
|
|||
end
|
||||
|
||||
def action
|
||||
write? ? :update : :read
|
||||
write? ? :write : :read
|
||||
end
|
||||
|
||||
def project
|
||||
|
|
After Width: | Height: | Size: 612 B |
After Width: | Height: | Size: 807 B |
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 635 B |
After Width: | Height: | Size: 852 B |
After Width: | Height: | Size: 263 B |
After Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 260 B |
After Width: | Height: | Size: 251 B |
|
@ -1,42 +1,25 @@
|
|||
function check_by_ids(ids) {
|
||||
for(var i = 0; i < ids.length; i++){
|
||||
$('#'+ids[i]).attr('checked', true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function uncheck_by_ids(ids) {
|
||||
for(var i = 0; i < ids.length; i++){
|
||||
$('#'+ids[i]).attr('checked', false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.pl_ids_container input[type="hidden"]').remove();
|
||||
$('select#build_list_pl_id').change(function() {
|
||||
var platform_id = $(this).val();
|
||||
var base_platforms = $('.base_platforms input[type=checkbox]');
|
||||
|
||||
$('select#build_pl').change(function() {
|
||||
var is_pl_main = false;
|
||||
var granted_bpl_id = '';
|
||||
var pl_id = $('select#build_pl').val();
|
||||
$('#include_repos').html($('.preloaded_include_repos .include_repos_' + platform_id).html());
|
||||
|
||||
$('input.build_bpl_ids').each(function(i,el) {
|
||||
var bpl_id = $(el).attr('bpl_id');
|
||||
if (pl_id == bpl_id) {
|
||||
is_pl_main = true;
|
||||
//granted_bpl_id = $(el).attr('bpl_id');
|
||||
}
|
||||
});
|
||||
|
||||
if (is_pl_main) {
|
||||
$('input.build_bpl_ids').attr('disabled', 'disabled');
|
||||
$('input.build_bpl_ids[bpl_id="'+pl_id+'"]').removeAttr('disabled');
|
||||
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');
|
||||
} else {
|
||||
$('input.build_bpl_ids').removeAttr('disabled');
|
||||
$(this).removeAttr('checked');
|
||||
$(this).attr('disabled', 'disabled');
|
||||
}
|
||||
} else {
|
||||
$(this).removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
$('select#build_pl').trigger('change');
|
||||
});
|
||||
$('select#build_list_pl_id').trigger('change');
|
||||
|
||||
$('input.user_role_chbx').click(function() {
|
||||
var current = $(this);
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* File: jquery.dataTables.min.js
|
||||
* Version: 1.8.2
|
||||
* Author: Allan Jardine (www.sprymedia.co.uk)
|
||||
* Info: www.datatables.net
|
||||
*
|
||||
* Copyright 2008-2011 Allan Jardine, all rights reserved.
|
||||
*
|
||||
* This source file is free software, under either the GPL v2 license or a
|
||||
* BSD style license, as supplied with this software.
|
||||
*
|
||||
* This source file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
||||
*/
|
||||
(function(i,za,p){i.fn.dataTableSettings=[];var D=i.fn.dataTableSettings;i.fn.dataTableExt={};var n=i.fn.dataTableExt;n.sVersion="1.8.2";n.sErrMode="alert";n.iApiIndex=0;n.oApi={};n.afnFiltering=[];n.aoFeatures=[];n.ofnSearch={};n.afnSortData=[];n.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",
|
||||
sPageButtonStaticDisabled:"paginate_button paginate_button_disabled",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",
|
||||
sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:""};n.oJUIClasses={sPagePrevEnabled:"fg-button ui-button ui-state-default ui-corner-left",
|
||||
sPagePrevDisabled:"fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",sPageNextEnabled:"fg-button ui-button ui-state-default ui-corner-right",sPageNextDisabled:"fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",sPageJUINext:"ui-icon ui-icon-circle-arrow-e",sPageJUIPrev:"ui-icon ui-icon-circle-arrow-w",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"fg-button ui-button ui-state-default ui-state-disabled",sPageButtonStaticDisabled:"fg-button ui-button ui-state-default ui-state-disabled",
|
||||
sPageFirst:"first ui-corner-tl ui-corner-bl",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last ui-corner-tr ui-corner-br",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"ui-state-default",sSortDesc:"ui-state-default",sSortable:"ui-state-default",
|
||||
sSortableAsc:"ui-state-default",sSortableDesc:"ui-state-default",sSortableNone:"ui-state-default",sSortColumn:"sorting_",sSortJUIAsc:"css_right ui-icon ui-icon-triangle-1-n",sSortJUIDesc:"css_right ui-icon ui-icon-triangle-1-s",sSortJUI:"css_right ui-icon ui-icon-carat-2-n-s",sSortJUIAscAllowed:"css_right ui-icon ui-icon-carat-1-n",sSortJUIDescAllowed:"css_right ui-icon ui-icon-carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollWrapper:"dataTables_scroll",
|
||||
sScrollHead:"dataTables_scrollHead ui-state-default",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot ui-state-default",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:"ui-state-default"};n.oPagination={two_button:{fnInit:function(g,l,s){var t,w,y;if(g.bJUI){t=p.createElement("a");w=p.createElement("a");y=p.createElement("span");y.className=g.oClasses.sPageJUINext;w.appendChild(y);y=p.createElement("span");y.className=g.oClasses.sPageJUIPrev;
|
||||
t.appendChild(y)}else{t=p.createElement("div");w=p.createElement("div")}t.className=g.oClasses.sPagePrevDisabled;w.className=g.oClasses.sPageNextDisabled;t.title=g.oLanguage.oPaginate.sPrevious;w.title=g.oLanguage.oPaginate.sNext;l.appendChild(t);l.appendChild(w);i(t).bind("click.DT",function(){g.oApi._fnPageChange(g,"previous")&&s(g)});i(w).bind("click.DT",function(){g.oApi._fnPageChange(g,"next")&&s(g)});i(t).bind("selectstart.DT",function(){return false});i(w).bind("selectstart.DT",function(){return false});
|
||||
if(g.sTableId!==""&&typeof g.aanFeatures.p=="undefined"){l.setAttribute("id",g.sTableId+"_paginate");t.setAttribute("id",g.sTableId+"_previous");w.setAttribute("id",g.sTableId+"_next")}},fnUpdate:function(g){if(g.aanFeatures.p)for(var l=g.aanFeatures.p,s=0,t=l.length;s<t;s++)if(l[s].childNodes.length!==0){l[s].childNodes[0].className=g._iDisplayStart===0?g.oClasses.sPagePrevDisabled:g.oClasses.sPagePrevEnabled;l[s].childNodes[1].className=g.fnDisplayEnd()==g.fnRecordsDisplay()?g.oClasses.sPageNextDisabled:
|
||||
g.oClasses.sPageNextEnabled}}},iFullNumbersShowPages:5,full_numbers:{fnInit:function(g,l,s){var t=p.createElement("span"),w=p.createElement("span"),y=p.createElement("span"),F=p.createElement("span"),x=p.createElement("span");t.innerHTML=g.oLanguage.oPaginate.sFirst;w.innerHTML=g.oLanguage.oPaginate.sPrevious;F.innerHTML=g.oLanguage.oPaginate.sNext;x.innerHTML=g.oLanguage.oPaginate.sLast;var v=g.oClasses;t.className=v.sPageButton+" "+v.sPageFirst;w.className=v.sPageButton+" "+v.sPagePrevious;F.className=
|
||||
v.sPageButton+" "+v.sPageNext;x.className=v.sPageButton+" "+v.sPageLast;l.appendChild(t);l.appendChild(w);l.appendChild(y);l.appendChild(F);l.appendChild(x);i(t).bind("click.DT",function(){g.oApi._fnPageChange(g,"first")&&s(g)});i(w).bind("click.DT",function(){g.oApi._fnPageChange(g,"previous")&&s(g)});i(F).bind("click.DT",function(){g.oApi._fnPageChange(g,"next")&&s(g)});i(x).bind("click.DT",function(){g.oApi._fnPageChange(g,"last")&&s(g)});i("span",l).bind("mousedown.DT",function(){return false}).bind("selectstart.DT",
|
||||
function(){return false});if(g.sTableId!==""&&typeof g.aanFeatures.p=="undefined"){l.setAttribute("id",g.sTableId+"_paginate");t.setAttribute("id",g.sTableId+"_first");w.setAttribute("id",g.sTableId+"_previous");F.setAttribute("id",g.sTableId+"_next");x.setAttribute("id",g.sTableId+"_last")}},fnUpdate:function(g,l){if(g.aanFeatures.p){var s=n.oPagination.iFullNumbersShowPages,t=Math.floor(s/2),w=Math.ceil(g.fnRecordsDisplay()/g._iDisplayLength),y=Math.ceil(g._iDisplayStart/g._iDisplayLength)+1,F=
|
||||
"",x,v=g.oClasses;if(w<s){t=1;x=w}else if(y<=t){t=1;x=s}else if(y>=w-t){t=w-s+1;x=w}else{t=y-Math.ceil(s/2)+1;x=t+s-1}for(s=t;s<=x;s++)F+=y!=s?'<span class="'+v.sPageButton+'">'+s+"</span>":'<span class="'+v.sPageButtonActive+'">'+s+"</span>";x=g.aanFeatures.p;var z,$=function(M){g._iDisplayStart=(this.innerHTML*1-1)*g._iDisplayLength;l(g);M.preventDefault()},X=function(){return false};s=0;for(t=x.length;s<t;s++)if(x[s].childNodes.length!==0){z=i("span:eq(2)",x[s]);z.html(F);i("span",z).bind("click.DT",
|
||||
$).bind("mousedown.DT",X).bind("selectstart.DT",X);z=x[s].getElementsByTagName("span");z=[z[0],z[1],z[z.length-2],z[z.length-1]];i(z).removeClass(v.sPageButton+" "+v.sPageButtonActive+" "+v.sPageButtonStaticDisabled);if(y==1){z[0].className+=" "+v.sPageButtonStaticDisabled;z[1].className+=" "+v.sPageButtonStaticDisabled}else{z[0].className+=" "+v.sPageButton;z[1].className+=" "+v.sPageButton}if(w===0||y==w||g._iDisplayLength==-1){z[2].className+=" "+v.sPageButtonStaticDisabled;z[3].className+=" "+
|
||||
v.sPageButtonStaticDisabled}else{z[2].className+=" "+v.sPageButton;z[3].className+=" "+v.sPageButton}}}}}};n.oSort={"string-asc":function(g,l){if(typeof g!="string")g="";if(typeof l!="string")l="";g=g.toLowerCase();l=l.toLowerCase();return g<l?-1:g>l?1:0},"string-desc":function(g,l){if(typeof g!="string")g="";if(typeof l!="string")l="";g=g.toLowerCase();l=l.toLowerCase();return g<l?1:g>l?-1:0},"html-asc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return g<
|
||||
l?-1:g>l?1:0},"html-desc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return g<l?1:g>l?-1:0},"date-asc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||l==="")l=Date.parse("01/01/1970 00:00:00");return g-l},"date-desc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||l==="")l=Date.parse("01/01/1970 00:00:00");return l-
|
||||
g},"numeric-asc":function(g,l){return(g=="-"||g===""?0:g*1)-(l=="-"||l===""?0:l*1)},"numeric-desc":function(g,l){return(l=="-"||l===""?0:l*1)-(g=="-"||g===""?0:g*1)}};n.aTypes=[function(g){if(typeof g=="number")return"numeric";else if(typeof g!="string")return null;var l,s=false;l=g.charAt(0);if("0123456789-".indexOf(l)==-1)return null;for(var t=1;t<g.length;t++){l=g.charAt(t);if("0123456789.".indexOf(l)==-1)return null;if(l=="."){if(s)return null;s=true}}return"numeric"},function(g){var l=Date.parse(g);
|
||||
if(l!==null&&!isNaN(l)||typeof g=="string"&&g.length===0)return"date";return null},function(g){if(typeof g=="string"&&g.indexOf("<")!=-1&&g.indexOf(">")!=-1)return"html";return null}];n.fnVersionCheck=function(g){var l=function(x,v){for(;x.length<v;)x+="0";return x},s=n.sVersion.split(".");g=g.split(".");for(var t="",w="",y=0,F=g.length;y<F;y++){t+=l(s[y],3);w+=l(g[y],3)}return parseInt(t,10)>=parseInt(w,10)};n._oExternConfig={iNextUnique:0};i.fn.dataTable=function(g){function l(){this.fnRecordsTotal=
|
||||
function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsTotal,10):this.aiDisplayMaster.length};this.fnRecordsDisplay=function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsDisplay,10):this.aiDisplay.length};this.fnDisplayEnd=function(){return this.oFeatures.bServerSide?this.oFeatures.bPaginate===false||this._iDisplayLength==-1?this._iDisplayStart+this.aiDisplay.length:Math.min(this._iDisplayStart+this._iDisplayLength,this._iRecordsDisplay):this._iDisplayEnd};this.sInstance=
|
||||
this.oInstance=null;this.oFeatures={bPaginate:true,bLengthChange:true,bFilter:true,bSort:true,bInfo:true,bAutoWidth:true,bProcessing:false,bSortClasses:true,bStateSave:false,bServerSide:false,bDeferRender:false};this.oScroll={sX:"",sXInner:"",sY:"",bCollapse:false,bInfinite:false,iLoadGap:100,iBarWidth:0,bAutoCss:true};this.aanFeatures=[];this.oLanguage={sProcessing:"Processing...",sLengthMenu:"Show _MENU_ entries",sZeroRecords:"No matching records found",sEmptyTable:"No data available in table",
|
||||
sLoadingRecords:"Loading...",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sInfoThousands:",",sSearch:"Search:",sUrl:"",oPaginate:{sFirst:"First",sPrevious:"Previous",sNext:"Next",sLast:"Last"},fnInfoCallback:null};this.aoData=[];this.aiDisplay=[];this.aiDisplayMaster=[];this.aoColumns=[];this.aoHeader=[];this.aoFooter=[];this.iNextId=0;this.asDataSearch=[];this.oPreviousSearch={sSearch:"",
|
||||
bRegex:false,bSmart:true};this.aoPreSearchCols=[];this.aaSorting=[[0,"asc",0]];this.aaSortingFixed=null;this.asStripeClasses=[];this.asDestroyStripes=[];this.sDestroyWidth=0;this.fnFooterCallback=this.fnHeaderCallback=this.fnRowCallback=null;this.aoDrawCallback=[];this.fnInitComplete=this.fnPreDrawCallback=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=this.bDeferLoading=false;this.aoOpenRows=[];this.sDom="lfrtip";this.sPaginationType=
|
||||
"two_button";this.iCookieDuration=7200;this.sCookiePrefix="SpryMedia_DataTables_";this.fnCookieCallback=null;this.aoStateSave=[];this.aoStateLoad=[];this.sAjaxSource=this.oLoadedState=null;this.sAjaxDataProp="aaData";this.bAjaxDataGet=true;this.jqXHR=null;this.fnServerData=function(a,b,c,d){d.jqXHR=i.ajax({url:a,data:b,success:function(f){i(d.oInstance).trigger("xhr",d);c(f)},dataType:"json",cache:false,error:function(f,e){e=="parsererror"&&alert("DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})};
|
||||
this.aoServerParams=[];this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=a+"";a=b.split("");var c="";b=b.length;for(var d=0;d<b;d++){if(d%3===0&&d!==0)c=this.oLanguage.sInfoThousands+c;c=a[b-d-1]+c}}return c};this.aLengthMenu=[10,25,50,100];this.bDrawing=this.iDraw=0;this.iDrawError=-1;this._iDisplayLength=10;this._iDisplayStart=0;this._iDisplayEnd=10;this._iRecordsDisplay=this._iRecordsTotal=0;this.bJUI=false;this.oClasses=n.oStdClasses;this.bSortCellsTop=this.bSorted=this.bFiltered=false;
|
||||
this.oInit=null;this.aoDestroyCallback=[]}function s(a){return function(){var b=[A(this[n.iApiIndex])].concat(Array.prototype.slice.call(arguments));return n.oApi[a].apply(this,b)}}function t(a){var b,c,d=a.iInitDisplayStart;if(a.bInitialised===false)setTimeout(function(){t(a)},200);else{Aa(a);X(a);M(a,a.aoHeader);a.nTFoot&&M(a,a.aoFooter);K(a,true);a.oFeatures.bAutoWidth&&ga(a);b=0;for(c=a.aoColumns.length;b<c;b++)if(a.aoColumns[b].sWidth!==null)a.aoColumns[b].nTh.style.width=q(a.aoColumns[b].sWidth);
|
||||
if(a.oFeatures.bSort)R(a);else if(a.oFeatures.bFilter)N(a,a.oPreviousSearch);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}if(a.sAjaxSource!==null&&!a.oFeatures.bServerSide){c=[];ha(a,c);a.fnServerData.call(a.oInstance,a.sAjaxSource,c,function(f){var e=f;if(a.sAjaxDataProp!=="")e=aa(a.sAjaxDataProp)(f);for(b=0;b<e.length;b++)v(a,e[b]);a.iInitDisplayStart=d;if(a.oFeatures.bSort)R(a);else{a.aiDisplay=a.aiDisplayMaster.slice();E(a);C(a)}K(a,false);w(a,f)},a)}else if(!a.oFeatures.bServerSide){K(a,
|
||||
false);w(a)}}}function w(a,b){a._bInitComplete=true;if(typeof a.fnInitComplete=="function")typeof b!="undefined"?a.fnInitComplete.call(a.oInstance,a,b):a.fnInitComplete.call(a.oInstance,a)}function y(a,b,c){a.oLanguage=i.extend(true,a.oLanguage,b);typeof b.sEmptyTable=="undefined"&&typeof b.sZeroRecords!="undefined"&&o(a.oLanguage,b,"sZeroRecords","sEmptyTable");typeof b.sLoadingRecords=="undefined"&&typeof b.sZeroRecords!="undefined"&&o(a.oLanguage,b,"sZeroRecords","sLoadingRecords");c&&t(a)}function F(a,
|
||||
b){var c=a.aoColumns.length;b={sType:null,_bAutoType:true,bVisible:true,bSearchable:true,bSortable:true,asSorting:["asc","desc"],sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,sTitle:b?b.innerHTML:"",sName:"",sWidth:null,sWidthOrig:null,sClass:null,fnRender:null,bUseRendered:true,iDataSort:c,mDataProp:c,fnGetData:null,fnSetData:null,sSortDataType:"std",sDefaultContent:null,sContentPadding:"",nTh:b?b:p.createElement("th"),nTf:null};a.aoColumns.push(b);if(typeof a.aoPreSearchCols[c]==
|
||||
"undefined"||a.aoPreSearchCols[c]===null)a.aoPreSearchCols[c]={sSearch:"",bRegex:false,bSmart:true};else{if(typeof a.aoPreSearchCols[c].bRegex=="undefined")a.aoPreSearchCols[c].bRegex=true;if(typeof a.aoPreSearchCols[c].bSmart=="undefined")a.aoPreSearchCols[c].bSmart=true}x(a,c,null)}function x(a,b,c){b=a.aoColumns[b];if(typeof c!="undefined"&&c!==null){if(typeof c.sType!="undefined"){b.sType=c.sType;b._bAutoType=false}o(b,c,"bVisible");o(b,c,"bSearchable");o(b,c,"bSortable");o(b,c,"sTitle");o(b,
|
||||
c,"sName");o(b,c,"sWidth");o(b,c,"sWidth","sWidthOrig");o(b,c,"sClass");o(b,c,"fnRender");o(b,c,"bUseRendered");o(b,c,"iDataSort");o(b,c,"mDataProp");o(b,c,"asSorting");o(b,c,"sSortDataType");o(b,c,"sDefaultContent");o(b,c,"sContentPadding")}b.fnGetData=aa(b.mDataProp);b.fnSetData=Ba(b.mDataProp);if(!a.oFeatures.bSort)b.bSortable=false;if(!b.bSortable||i.inArray("asc",b.asSorting)==-1&&i.inArray("desc",b.asSorting)==-1){b.sSortingClass=a.oClasses.sSortableNone;b.sSortingClassJUI=""}else if(b.bSortable||
|
||||
i.inArray("asc",b.asSorting)==-1&&i.inArray("desc",b.asSorting)==-1){b.sSortingClass=a.oClasses.sSortable;b.sSortingClassJUI=a.oClasses.sSortJUI}else if(i.inArray("asc",b.asSorting)!=-1&&i.inArray("desc",b.asSorting)==-1){b.sSortingClass=a.oClasses.sSortableAsc;b.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed}else if(i.inArray("asc",b.asSorting)==-1&&i.inArray("desc",b.asSorting)!=-1){b.sSortingClass=a.oClasses.sSortableDesc;b.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed}}function v(a,b){var c;
|
||||
c=i.isArray(b)?b.slice():i.extend(true,{},b);b=a.aoData.length;var d={nTr:null,_iId:a.iNextId++,_aData:c,_anHidden:[],_sRowStripe:""};a.aoData.push(d);for(var f,e=0,h=a.aoColumns.length;e<h;e++){c=a.aoColumns[e];typeof c.fnRender=="function"&&c.bUseRendered&&c.mDataProp!==null&&O(a,b,e,c.fnRender({iDataRow:b,iDataColumn:e,aData:d._aData,oSettings:a}));if(c._bAutoType&&c.sType!="string"){f=G(a,b,e,"type");if(f!==null&&f!==""){f=ia(f);if(c.sType===null)c.sType=f;else if(c.sType!=f&&c.sType!="html")c.sType=
|
||||
"string"}}}a.aiDisplayMaster.push(b);a.oFeatures.bDeferRender||z(a,b);return b}function z(a,b){var c=a.aoData[b],d;if(c.nTr===null){c.nTr=p.createElement("tr");typeof c._aData.DT_RowId!="undefined"&&c.nTr.setAttribute("id",c._aData.DT_RowId);typeof c._aData.DT_RowClass!="undefined"&&i(c.nTr).addClass(c._aData.DT_RowClass);for(var f=0,e=a.aoColumns.length;f<e;f++){var h=a.aoColumns[f];d=p.createElement("td");d.innerHTML=typeof h.fnRender=="function"&&(!h.bUseRendered||h.mDataProp===null)?h.fnRender({iDataRow:b,
|
||||
iDataColumn:f,aData:c._aData,oSettings:a}):G(a,b,f,"display");if(h.sClass!==null)d.className=h.sClass;if(h.bVisible){c.nTr.appendChild(d);c._anHidden[f]=null}else c._anHidden[f]=d}}}function $(a){var b,c,d,f,e,h,j,k,m;if(a.bDeferLoading||a.sAjaxSource===null){j=a.nTBody.childNodes;b=0;for(c=j.length;b<c;b++)if(j[b].nodeName.toUpperCase()=="TR"){k=a.aoData.length;a.aoData.push({nTr:j[b],_iId:a.iNextId++,_aData:[],_anHidden:[],_sRowStripe:""});a.aiDisplayMaster.push(k);h=j[b].childNodes;d=e=0;for(f=
|
||||
h.length;d<f;d++){m=h[d].nodeName.toUpperCase();if(m=="TD"||m=="TH"){O(a,k,e,i.trim(h[d].innerHTML));e++}}}}j=ba(a);h=[];b=0;for(c=j.length;b<c;b++){d=0;for(f=j[b].childNodes.length;d<f;d++){e=j[b].childNodes[d];m=e.nodeName.toUpperCase();if(m=="TD"||m=="TH")h.push(e)}}h.length!=j.length*a.aoColumns.length&&J(a,1,"Unexpected number of TD elements. Expected "+j.length*a.aoColumns.length+" and got "+h.length+". DataTables does not support rowspan / colspan in the table body, and there must be one cell for each row/column combination.");
|
||||
d=0;for(f=a.aoColumns.length;d<f;d++){if(a.aoColumns[d].sTitle===null)a.aoColumns[d].sTitle=a.aoColumns[d].nTh.innerHTML;j=a.aoColumns[d]._bAutoType;m=typeof a.aoColumns[d].fnRender=="function";e=a.aoColumns[d].sClass!==null;k=a.aoColumns[d].bVisible;var u,r;if(j||m||e||!k){b=0;for(c=a.aoData.length;b<c;b++){u=h[b*f+d];if(j&&a.aoColumns[d].sType!="string"){r=G(a,b,d,"type");if(r!==""){r=ia(r);if(a.aoColumns[d].sType===null)a.aoColumns[d].sType=r;else if(a.aoColumns[d].sType!=r&&a.aoColumns[d].sType!=
|
||||
"html")a.aoColumns[d].sType="string"}}if(m){r=a.aoColumns[d].fnRender({iDataRow:b,iDataColumn:d,aData:a.aoData[b]._aData,oSettings:a});u.innerHTML=r;a.aoColumns[d].bUseRendered&&O(a,b,d,r)}if(e)u.className+=" "+a.aoColumns[d].sClass;if(k)a.aoData[b]._anHidden[d]=null;else{a.aoData[b]._anHidden[d]=u;u.parentNode.removeChild(u)}}}}}function X(a){var b,c,d;a.nTHead.getElementsByTagName("tr");if(a.nTHead.getElementsByTagName("th").length!==0){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;
|
||||
a.aoColumns[b].sClass!==null&&i(c).addClass(a.aoColumns[b].sClass);if(a.aoColumns[b].sTitle!=c.innerHTML)c.innerHTML=a.aoColumns[b].sTitle}}else{var f=p.createElement("tr");b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;c.innerHTML=a.aoColumns[b].sTitle;a.aoColumns[b].sClass!==null&&i(c).addClass(a.aoColumns[b].sClass);f.appendChild(c)}i(a.nTHead).html("")[0].appendChild(f);Y(a.aoHeader,a.nTHead)}if(a.bJUI){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;f=p.createElement("div");
|
||||
f.className=a.oClasses.sSortJUIWrapper;i(c).contents().appendTo(f);var e=p.createElement("span");e.className=a.oClasses.sSortIcon;f.appendChild(e);c.appendChild(f)}}d=function(){this.onselectstart=function(){return false};return false};if(a.oFeatures.bSort)for(b=0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable!==false){ja(a,a.aoColumns[b].nTh,b);i(a.aoColumns[b].nTh).bind("mousedown.DT",d)}else i(a.aoColumns[b].nTh).addClass(a.oClasses.sSortableNone);a.oClasses.sFooterTH!==""&&i(a.nTFoot).children("tr").children("th").addClass(a.oClasses.sFooterTH);
|
||||
if(a.nTFoot!==null){c=S(a,null,a.aoFooter);b=0;for(d=a.aoColumns.length;b<d;b++)if(typeof c[b]!="undefined")a.aoColumns[b].nTf=c[b]}}function M(a,b,c){var d,f,e,h=[],j=[],k=a.aoColumns.length;if(typeof c=="undefined")c=false;d=0;for(f=b.length;d<f;d++){h[d]=b[d].slice();h[d].nTr=b[d].nTr;for(e=k-1;e>=0;e--)!a.aoColumns[e].bVisible&&!c&&h[d].splice(e,1);j.push([])}d=0;for(f=h.length;d<f;d++){if(h[d].nTr){a=0;for(e=h[d].nTr.childNodes.length;a<e;a++)h[d].nTr.removeChild(h[d].nTr.childNodes[0])}e=0;
|
||||
for(b=h[d].length;e<b;e++){k=c=1;if(typeof j[d][e]=="undefined"){h[d].nTr.appendChild(h[d][e].cell);for(j[d][e]=1;typeof h[d+c]!="undefined"&&h[d][e].cell==h[d+c][e].cell;){j[d+c][e]=1;c++}for(;typeof h[d][e+k]!="undefined"&&h[d][e].cell==h[d][e+k].cell;){for(a=0;a<c;a++)j[d+a][e+k]=1;k++}h[d][e].cell.rowSpan=c;h[d][e].cell.colSpan=k}}}}function C(a){var b,c,d=[],f=0,e=false;b=a.asStripeClasses.length;c=a.aoOpenRows.length;if(!(a.fnPreDrawCallback!==null&&a.fnPreDrawCallback.call(a.oInstance,a)===
|
||||
false)){a.bDrawing=true;if(typeof a.iInitDisplayStart!="undefined"&&a.iInitDisplayStart!=-1){a._iDisplayStart=a.oFeatures.bServerSide?a.iInitDisplayStart:a.iInitDisplayStart>=a.fnRecordsDisplay()?0:a.iInitDisplayStart;a.iInitDisplayStart=-1;E(a)}if(a.bDeferLoading){a.bDeferLoading=false;a.iDraw++}else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!Ca(a))return}else a.iDraw++;if(a.aiDisplay.length!==0){var h=a._iDisplayStart,j=a._iDisplayEnd;if(a.oFeatures.bServerSide){h=0;j=a.aoData.length}for(h=
|
||||
h;h<j;h++){var k=a.aoData[a.aiDisplay[h]];k.nTr===null&&z(a,a.aiDisplay[h]);var m=k.nTr;if(b!==0){var u=a.asStripeClasses[f%b];if(k._sRowStripe!=u){i(m).removeClass(k._sRowStripe).addClass(u);k._sRowStripe=u}}if(typeof a.fnRowCallback=="function"){m=a.fnRowCallback.call(a.oInstance,m,a.aoData[a.aiDisplay[h]]._aData,f,h);if(!m&&!e){J(a,0,"A node was not returned by fnRowCallback");e=true}}d.push(m);f++;if(c!==0)for(k=0;k<c;k++)m==a.aoOpenRows[k].nParent&&d.push(a.aoOpenRows[k].nTr)}}else{d[0]=p.createElement("tr");
|
||||
if(typeof a.asStripeClasses[0]!="undefined")d[0].className=a.asStripeClasses[0];e=a.oLanguage.sZeroRecords.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()));if(a.iDraw==1&&a.sAjaxSource!==null&&!a.oFeatures.bServerSide)e=a.oLanguage.sLoadingRecords;else if(typeof a.oLanguage.sEmptyTable!="undefined"&&a.fnRecordsTotal()===0)e=a.oLanguage.sEmptyTable;b=p.createElement("td");b.setAttribute("valign","top");b.colSpan=Z(a);b.className=a.oClasses.sRowEmpty;b.innerHTML=e;d[f].appendChild(b)}typeof a.fnHeaderCallback==
|
||||
"function"&&a.fnHeaderCallback.call(a.oInstance,i(a.nTHead).children("tr")[0],ca(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);typeof a.fnFooterCallback=="function"&&a.fnFooterCallback.call(a.oInstance,i(a.nTFoot).children("tr")[0],ca(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);f=p.createDocumentFragment();b=p.createDocumentFragment();if(a.nTBody){e=a.nTBody.parentNode;b.appendChild(a.nTBody);if(!a.oScroll.bInfinite||!a._bInitComplete||a.bSorted||a.bFiltered){c=a.nTBody.childNodes;for(b=
|
||||
c.length-1;b>=0;b--)c[b].parentNode.removeChild(c[b])}b=0;for(c=d.length;b<c;b++)f.appendChild(d[b]);a.nTBody.appendChild(f);e!==null&&e.appendChild(a.nTBody)}for(b=a.aoDrawCallback.length-1;b>=0;b--)a.aoDrawCallback[b].fn.call(a.oInstance,a);i(a.oInstance).trigger("draw",a);a.bSorted=false;a.bFiltered=false;a.bDrawing=false;if(a.oFeatures.bServerSide){K(a,false);typeof a._bInitComplete=="undefined"&&w(a)}}}function da(a){if(a.oFeatures.bSort)R(a,a.oPreviousSearch);else if(a.oFeatures.bFilter)N(a,
|
||||
a.oPreviousSearch);else{E(a);C(a)}}function Ca(a){if(a.bAjaxDataGet){a.iDraw++;K(a,true);var b=Da(a);ha(a,b);a.fnServerData.call(a.oInstance,a.sAjaxSource,b,function(c){Ea(a,c)},a);return false}else return true}function Da(a){var b=a.aoColumns.length,c=[],d,f;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",value:ka(a)});c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",value:a.oFeatures.bPaginate!==false?a._iDisplayLength:
|
||||
-1});for(f=0;f<b;f++){d=a.aoColumns[f].mDataProp;c.push({name:"mDataProp_"+f,value:typeof d=="function"?"function":d})}if(a.oFeatures.bFilter!==false){c.push({name:"sSearch",value:a.oPreviousSearch.sSearch});c.push({name:"bRegex",value:a.oPreviousSearch.bRegex});for(f=0;f<b;f++){c.push({name:"sSearch_"+f,value:a.aoPreSearchCols[f].sSearch});c.push({name:"bRegex_"+f,value:a.aoPreSearchCols[f].bRegex});c.push({name:"bSearchable_"+f,value:a.aoColumns[f].bSearchable})}}if(a.oFeatures.bSort!==false){d=
|
||||
a.aaSortingFixed!==null?a.aaSortingFixed.length:0;var e=a.aaSorting.length;c.push({name:"iSortingCols",value:d+e});for(f=0;f<d;f++){c.push({name:"iSortCol_"+f,value:a.aaSortingFixed[f][0]});c.push({name:"sSortDir_"+f,value:a.aaSortingFixed[f][1]})}for(f=0;f<e;f++){c.push({name:"iSortCol_"+(f+d),value:a.aaSorting[f][0]});c.push({name:"sSortDir_"+(f+d),value:a.aaSorting[f][1]})}for(f=0;f<b;f++)c.push({name:"bSortable_"+f,value:a.aoColumns[f].bSortable})}return c}function ha(a,b){for(var c=0,d=a.aoServerParams.length;c<
|
||||
d;c++)a.aoServerParams[c].fn.call(a.oInstance,b)}function Ea(a,b){if(typeof b.sEcho!="undefined")if(b.sEcho*1<a.iDraw)return;else a.iDraw=b.sEcho*1;if(!a.oScroll.bInfinite||a.oScroll.bInfinite&&(a.bSorted||a.bFiltered))la(a);a._iRecordsTotal=b.iTotalRecords;a._iRecordsDisplay=b.iTotalDisplayRecords;var c=ka(a);if(c=typeof b.sColumns!="undefined"&&c!==""&&b.sColumns!=c)var d=Fa(a,b.sColumns);b=aa(a.sAjaxDataProp)(b);for(var f=0,e=b.length;f<e;f++)if(c){for(var h=[],j=0,k=a.aoColumns.length;j<k;j++)h.push(b[f][d[j]]);
|
||||
v(a,h)}else v(a,b[f]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=false;C(a);a.bAjaxDataGet=true;K(a,false)}function Aa(a){var b=p.createElement("div");a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=p.createElement("div");a.nTableWrapper.className=a.oClasses.sWrapper;a.sTableId!==""&&a.nTableWrapper.setAttribute("id",a.sTableId+"_wrapper");a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),f,e,h,j,k,m,u,r=0;r<d.length;r++){e=0;h=d[r];if(h==
|
||||
"<"){j=p.createElement("div");k=d[r+1];if(k=="'"||k=='"'){m="";for(u=2;d[r+u]!=k;){m+=d[r+u];u++}if(m=="H")m="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";else if(m=="F")m="fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";if(m.indexOf(".")!=-1){k=m.split(".");j.setAttribute("id",k[0].substr(1,k[0].length-1));j.className=k[1]}else if(m.charAt(0)=="#")j.setAttribute("id",m.substr(1,m.length-1));else j.className=m;r+=u}c.appendChild(j);
|
||||
c=j}else if(h==">")c=c.parentNode;else if(h=="l"&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange){f=Ga(a);e=1}else if(h=="f"&&a.oFeatures.bFilter){f=Ha(a);e=1}else if(h=="r"&&a.oFeatures.bProcessing){f=Ia(a);e=1}else if(h=="t"){f=Ja(a);e=1}else if(h=="i"&&a.oFeatures.bInfo){f=Ka(a);e=1}else if(h=="p"&&a.oFeatures.bPaginate){f=La(a);e=1}else if(n.aoFeatures.length!==0){j=n.aoFeatures;u=0;for(k=j.length;u<k;u++)if(h==j[u].cFeature){if(f=j[u].fnInit(a))e=1;break}}if(e==1&&f!==null){if(typeof a.aanFeatures[h]!=
|
||||
"object")a.aanFeatures[h]=[];a.aanFeatures[h].push(f);c.appendChild(f)}}b.parentNode.replaceChild(a.nTableWrapper,b)}function Ja(a){if(a.oScroll.sX===""&&a.oScroll.sY==="")return a.nTable;var b=p.createElement("div"),c=p.createElement("div"),d=p.createElement("div"),f=p.createElement("div"),e=p.createElement("div"),h=p.createElement("div"),j=a.nTable.cloneNode(false),k=a.nTable.cloneNode(false),m=a.nTable.getElementsByTagName("thead")[0],u=a.nTable.getElementsByTagName("tfoot").length===0?null:a.nTable.getElementsByTagName("tfoot")[0],
|
||||
r=typeof g.bJQueryUI!="undefined"&&g.bJQueryUI?n.oJUIClasses:n.oStdClasses;c.appendChild(d);e.appendChild(h);f.appendChild(a.nTable);b.appendChild(c);b.appendChild(f);d.appendChild(j);j.appendChild(m);if(u!==null){b.appendChild(e);h.appendChild(k);k.appendChild(u)}b.className=r.sScrollWrapper;c.className=r.sScrollHead;d.className=r.sScrollHeadInner;f.className=r.sScrollBody;e.className=r.sScrollFoot;h.className=r.sScrollFootInner;if(a.oScroll.bAutoCss){c.style.overflow="hidden";c.style.position="relative";
|
||||
e.style.overflow="hidden";f.style.overflow="auto"}c.style.border="0";c.style.width="100%";e.style.border="0";d.style.width="150%";j.removeAttribute("id");j.style.marginLeft="0";a.nTable.style.marginLeft="0";if(u!==null){k.removeAttribute("id");k.style.marginLeft="0"}d=i(a.nTable).children("caption");h=0;for(k=d.length;h<k;h++)j.appendChild(d[h]);if(a.oScroll.sX!==""){c.style.width=q(a.oScroll.sX);f.style.width=q(a.oScroll.sX);if(u!==null)e.style.width=q(a.oScroll.sX);i(f).scroll(function(){c.scrollLeft=
|
||||
this.scrollLeft;if(u!==null)e.scrollLeft=this.scrollLeft})}if(a.oScroll.sY!=="")f.style.height=q(a.oScroll.sY);a.aoDrawCallback.push({fn:Ma,sName:"scrolling"});a.oScroll.bInfinite&&i(f).scroll(function(){if(!a.bDrawing)if(i(this).scrollTop()+i(this).height()>i(a.nTable).height()-a.oScroll.iLoadGap)if(a.fnDisplayEnd()<a.fnRecordsDisplay()){ma(a,"next");E(a);C(a)}});a.nScrollHead=c;a.nScrollFoot=e;return b}function Ma(a){var b=a.nScrollHead.getElementsByTagName("div")[0],c=b.getElementsByTagName("table")[0],
|
||||
d=a.nTable.parentNode,f,e,h,j,k,m,u,r,H=[],L=a.nTFoot!==null?a.nScrollFoot.getElementsByTagName("div")[0]:null,T=a.nTFoot!==null?L.getElementsByTagName("table")[0]:null,B=i.browser.msie&&i.browser.version<=7;h=a.nTable.getElementsByTagName("thead");h.length>0&&a.nTable.removeChild(h[0]);if(a.nTFoot!==null){k=a.nTable.getElementsByTagName("tfoot");k.length>0&&a.nTable.removeChild(k[0])}h=a.nTHead.cloneNode(true);a.nTable.insertBefore(h,a.nTable.childNodes[0]);if(a.nTFoot!==null){k=a.nTFoot.cloneNode(true);
|
||||
a.nTable.insertBefore(k,a.nTable.childNodes[1])}if(a.oScroll.sX===""){d.style.width="100%";b.parentNode.style.width="100%"}var U=S(a,h);f=0;for(e=U.length;f<e;f++){u=Na(a,f);U[f].style.width=a.aoColumns[u].sWidth}a.nTFoot!==null&&P(function(I){I.style.width=""},k.getElementsByTagName("tr"));f=i(a.nTable).outerWidth();if(a.oScroll.sX===""){a.nTable.style.width="100%";if(B&&(d.scrollHeight>d.offsetHeight||i(d).css("overflow-y")=="scroll"))a.nTable.style.width=q(i(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sXInner!==
|
||||
"")a.nTable.style.width=q(a.oScroll.sXInner);else if(f==i(d).width()&&i(d).height()<i(a.nTable).height()){a.nTable.style.width=q(f-a.oScroll.iBarWidth);if(i(a.nTable).outerWidth()>f-a.oScroll.iBarWidth)a.nTable.style.width=q(f)}else a.nTable.style.width=q(f);f=i(a.nTable).outerWidth();e=a.nTHead.getElementsByTagName("tr");h=h.getElementsByTagName("tr");P(function(I,na){m=I.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;r=i(I).width();na.style.width=
|
||||
q(r);H.push(r)},h,e);i(h).height(0);if(a.nTFoot!==null){j=k.getElementsByTagName("tr");k=a.nTFoot.getElementsByTagName("tr");P(function(I,na){m=I.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;r=i(I).width();na.style.width=q(r);H.push(r)},j,k);i(j).height(0)}P(function(I){I.innerHTML="";I.style.width=q(H.shift())},h);a.nTFoot!==null&&P(function(I){I.innerHTML="";I.style.width=q(H.shift())},j);if(i(a.nTable).outerWidth()<f){j=d.scrollHeight>d.offsetHeight||
|
||||
i(d).css("overflow-y")=="scroll"?f+a.oScroll.iBarWidth:f;if(B&&(d.scrollHeight>d.offsetHeight||i(d).css("overflow-y")=="scroll"))a.nTable.style.width=q(j-a.oScroll.iBarWidth);d.style.width=q(j);b.parentNode.style.width=q(j);if(a.nTFoot!==null)L.parentNode.style.width=q(j);if(a.oScroll.sX==="")J(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width.");else a.oScroll.sXInner!==""&&J(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else{d.style.width=
|
||||
q("100%");b.parentNode.style.width=q("100%");if(a.nTFoot!==null)L.parentNode.style.width=q("100%")}if(a.oScroll.sY==="")if(B)d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth);if(a.oScroll.sY!==""&&a.oScroll.bCollapse){d.style.height=q(a.oScroll.sY);B=a.oScroll.sX!==""&&a.nTable.offsetWidth>d.offsetWidth?a.oScroll.iBarWidth:0;if(a.nTable.offsetHeight<d.offsetHeight)d.style.height=q(i(a.nTable).height()+B)}B=i(a.nTable).outerWidth();c.style.width=q(B);b.style.width=q(B+a.oScroll.iBarWidth);
|
||||
if(a.nTFoot!==null){L.style.width=q(a.nTable.offsetWidth+a.oScroll.iBarWidth);T.style.width=q(a.nTable.offsetWidth)}if(a.bSorted||a.bFiltered)d.scrollTop=0}function ea(a){if(a.oFeatures.bAutoWidth===false)return false;ga(a);for(var b=0,c=a.aoColumns.length;b<c;b++)a.aoColumns[b].nTh.style.width=a.aoColumns[b].sWidth}function Ha(a){var b=a.oLanguage.sSearch;b=b.indexOf("_INPUT_")!==-1?b.replace("_INPUT_",'<input type="text" />'):b===""?'<input type="text" />':b+' <input type="text" />';var c=p.createElement("div");
|
||||
c.className=a.oClasses.sFilter;c.innerHTML="<label>"+b+"</label>";a.sTableId!==""&&typeof a.aanFeatures.f=="undefined"&&c.setAttribute("id",a.sTableId+"_filter");b=i("input",c);b.val(a.oPreviousSearch.sSearch.replace('"',"""));b.bind("keyup.DT",function(){for(var d=a.aanFeatures.f,f=0,e=d.length;f<e;f++)d[f]!=i(this).parents("div.dataTables_filter")[0]&&i("input",d[f]).val(this.value);this.value!=a.oPreviousSearch.sSearch&&N(a,{sSearch:this.value,bRegex:a.oPreviousSearch.bRegex,bSmart:a.oPreviousSearch.bSmart})});
|
||||
b.bind("keypress.DT",function(d){if(d.keyCode==13)return false});return c}function N(a,b,c){Oa(a,b.sSearch,c,b.bRegex,b.bSmart);for(b=0;b<a.aoPreSearchCols.length;b++)Pa(a,a.aoPreSearchCols[b].sSearch,b,a.aoPreSearchCols[b].bRegex,a.aoPreSearchCols[b].bSmart);n.afnFiltering.length!==0&&Qa(a);a.bFiltered=true;i(a.oInstance).trigger("filter",a);a._iDisplayStart=0;E(a);C(a);oa(a,0)}function Qa(a){for(var b=n.afnFiltering,c=0,d=b.length;c<d;c++)for(var f=0,e=0,h=a.aiDisplay.length;e<h;e++){var j=a.aiDisplay[e-
|
||||
f];if(!b[c](a,fa(a,j,"filter"),j)){a.aiDisplay.splice(e-f,1);f++}}}function Pa(a,b,c,d,f){if(b!==""){var e=0;b=pa(b,d,f);for(d=a.aiDisplay.length-1;d>=0;d--){f=qa(G(a,a.aiDisplay[d],c,"filter"),a.aoColumns[c].sType);if(!b.test(f)){a.aiDisplay.splice(d,1);e++}}}}function Oa(a,b,c,d,f){var e=pa(b,d,f);if(typeof c=="undefined"||c===null)c=0;if(n.afnFiltering.length!==0)c=1;if(b.length<=0){a.aiDisplay.splice(0,a.aiDisplay.length);a.aiDisplay=a.aiDisplayMaster.slice()}else if(a.aiDisplay.length==a.aiDisplayMaster.length||
|
||||
a.oPreviousSearch.sSearch.length>b.length||c==1||b.indexOf(a.oPreviousSearch.sSearch)!==0){a.aiDisplay.splice(0,a.aiDisplay.length);oa(a,1);for(c=0;c<a.aiDisplayMaster.length;c++)e.test(a.asDataSearch[c])&&a.aiDisplay.push(a.aiDisplayMaster[c])}else{var h=0;for(c=0;c<a.asDataSearch.length;c++)if(!e.test(a.asDataSearch[c])){a.aiDisplay.splice(c-h,1);h++}}a.oPreviousSearch.sSearch=b;a.oPreviousSearch.bRegex=d;a.oPreviousSearch.bSmart=f}function oa(a,b){if(!a.oFeatures.bServerSide){a.asDataSearch.splice(0,
|
||||
a.asDataSearch.length);b=typeof b!="undefined"&&b==1?a.aiDisplayMaster:a.aiDisplay;for(var c=0,d=b.length;c<d;c++)a.asDataSearch[c]=ra(a,fa(a,b[c],"filter"))}}function ra(a,b){var c="";if(typeof a.__nTmpFilter=="undefined")a.__nTmpFilter=p.createElement("div");for(var d=a.__nTmpFilter,f=0,e=a.aoColumns.length;f<e;f++)if(a.aoColumns[f].bSearchable)c+=qa(b[f],a.aoColumns[f].sType)+" ";if(c.indexOf("&")!==-1){d.innerHTML=c;c=d.textContent?d.textContent:d.innerText;c=c.replace(/\n/g," ").replace(/\r/g,
|
||||
"")}return c}function pa(a,b,c){if(c){a=b?a.split(" "):sa(a).split(" ");a="^(?=.*?"+a.join(")(?=.*?")+").*$";return new RegExp(a,"i")}else{a=b?a:sa(a);return new RegExp(a,"i")}}function qa(a,b){if(typeof n.ofnSearch[b]=="function")return n.ofnSearch[b](a);else if(b=="html")return a.replace(/\n/g," ").replace(/<.*?>/g,"");else if(typeof a=="string")return a.replace(/\n/g," ");else if(a===null)return"";return a}function R(a,b){var c,d,f,e,h=[],j=[],k=n.oSort;d=a.aoData;var m=a.aoColumns;if(!a.oFeatures.bServerSide&&
|
||||
(a.aaSorting.length!==0||a.aaSortingFixed!==null)){h=a.aaSortingFixed!==null?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(c=0;c<h.length;c++){var u=h[c][0];f=ta(a,u);e=a.aoColumns[u].sSortDataType;if(typeof n.afnSortData[e]!="undefined"){var r=n.afnSortData[e](a,u,f);f=0;for(e=d.length;f<e;f++)O(a,f,u,r[f])}}c=0;for(d=a.aiDisplayMaster.length;c<d;c++)j[a.aiDisplayMaster[c]]=c;var H=h.length;a.aiDisplayMaster.sort(function(L,T){var B,U;for(c=0;c<H;c++){B=m[h[c][0]].iDataSort;U=m[B].sType;
|
||||
B=k[(U?U:"string")+"-"+h[c][1]](G(a,L,B,"sort"),G(a,T,B,"sort"));if(B!==0)return B}return k["numeric-asc"](j[L],j[T])})}if((typeof b=="undefined"||b)&&!a.oFeatures.bDeferRender)V(a);a.bSorted=true;i(a.oInstance).trigger("sort",a);if(a.oFeatures.bFilter)N(a,a.oPreviousSearch,1);else{a.aiDisplay=a.aiDisplayMaster.slice();a._iDisplayStart=0;E(a);C(a)}}function ja(a,b,c,d){i(b).bind("click.DT",function(f){if(a.aoColumns[c].bSortable!==false){var e=function(){var h,j;if(f.shiftKey){for(var k=false,m=0;m<
|
||||
a.aaSorting.length;m++)if(a.aaSorting[m][0]==c){k=true;h=a.aaSorting[m][0];j=a.aaSorting[m][2]+1;if(typeof a.aoColumns[h].asSorting[j]=="undefined")a.aaSorting.splice(m,1);else{a.aaSorting[m][1]=a.aoColumns[h].asSorting[j];a.aaSorting[m][2]=j}break}k===false&&a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0])}else if(a.aaSorting.length==1&&a.aaSorting[0][0]==c){h=a.aaSorting[0][0];j=a.aaSorting[0][2]+1;if(typeof a.aoColumns[h].asSorting[j]=="undefined")j=0;a.aaSorting[0][1]=a.aoColumns[h].asSorting[j];
|
||||
a.aaSorting[0][2]=j}else{a.aaSorting.splice(0,a.aaSorting.length);a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0])}R(a)};if(a.oFeatures.bProcessing){K(a,true);setTimeout(function(){e();a.oFeatures.bServerSide||K(a,false)},0)}else e();typeof d=="function"&&d(a)}})}function V(a){var b,c,d,f,e,h=a.aoColumns.length,j=a.oClasses;for(b=0;b<h;b++)a.aoColumns[b].bSortable&&i(a.aoColumns[b].nTh).removeClass(j.sSortAsc+" "+j.sSortDesc+" "+a.aoColumns[b].sSortingClass);f=a.aaSortingFixed!==null?a.aaSortingFixed.concat(a.aaSorting):
|
||||
a.aaSorting.slice();for(b=0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable){e=a.aoColumns[b].sSortingClass;d=-1;for(c=0;c<f.length;c++)if(f[c][0]==b){e=f[c][1]=="asc"?j.sSortAsc:j.sSortDesc;d=c;break}i(a.aoColumns[b].nTh).addClass(e);if(a.bJUI){c=i("span",a.aoColumns[b].nTh);c.removeClass(j.sSortJUIAsc+" "+j.sSortJUIDesc+" "+j.sSortJUI+" "+j.sSortJUIAscAllowed+" "+j.sSortJUIDescAllowed);c.addClass(d==-1?a.aoColumns[b].sSortingClassJUI:f[d][1]=="asc"?j.sSortJUIAsc:j.sSortJUIDesc)}}else i(a.aoColumns[b].nTh).addClass(a.aoColumns[b].sSortingClass);
|
||||
e=j.sSortColumn;if(a.oFeatures.bSort&&a.oFeatures.bSortClasses){d=Q(a);if(a.oFeatures.bDeferRender)i(d).removeClass(e+"1 "+e+"2 "+e+"3");else if(d.length>=h)for(b=0;b<h;b++)if(d[b].className.indexOf(e+"1")!=-1){c=0;for(a=d.length/h;c<a;c++)d[h*c+b].className=i.trim(d[h*c+b].className.replace(e+"1",""))}else if(d[b].className.indexOf(e+"2")!=-1){c=0;for(a=d.length/h;c<a;c++)d[h*c+b].className=i.trim(d[h*c+b].className.replace(e+"2",""))}else if(d[b].className.indexOf(e+"3")!=-1){c=0;for(a=d.length/
|
||||
h;c<a;c++)d[h*c+b].className=i.trim(d[h*c+b].className.replace(" "+e+"3",""))}j=1;var k;for(b=0;b<f.length;b++){k=parseInt(f[b][0],10);c=0;for(a=d.length/h;c<a;c++)d[h*c+k].className+=" "+e+j;j<3&&j++}}}function La(a){if(a.oScroll.bInfinite)return null;var b=p.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;n.oPagination[a.sPaginationType].fnInit(a,b,function(c){E(c);C(c)});typeof a.aanFeatures.p=="undefined"&&a.aoDrawCallback.push({fn:function(c){n.oPagination[c.sPaginationType].fnUpdate(c,
|
||||
function(d){E(d);C(d)})},sName:"pagination"});return b}function ma(a,b){var c=a._iDisplayStart;if(b=="first")a._iDisplayStart=0;else if(b=="previous"){a._iDisplayStart=a._iDisplayLength>=0?a._iDisplayStart-a._iDisplayLength:0;if(a._iDisplayStart<0)a._iDisplayStart=0}else if(b=="next")if(a._iDisplayLength>=0){if(a._iDisplayStart+a._iDisplayLength<a.fnRecordsDisplay())a._iDisplayStart+=a._iDisplayLength}else a._iDisplayStart=0;else if(b=="last")if(a._iDisplayLength>=0){b=parseInt((a.fnRecordsDisplay()-
|
||||
1)/a._iDisplayLength,10)+1;a._iDisplayStart=(b-1)*a._iDisplayLength}else a._iDisplayStart=0;else J(a,0,"Unknown paging action: "+b);i(a.oInstance).trigger("page",a);return c!=a._iDisplayStart}function Ka(a){var b=p.createElement("div");b.className=a.oClasses.sInfo;if(typeof a.aanFeatures.i=="undefined"){a.aoDrawCallback.push({fn:Ra,sName:"information"});a.sTableId!==""&&b.setAttribute("id",a.sTableId+"_info")}return b}function Ra(a){if(!(!a.oFeatures.bInfo||a.aanFeatures.i.length===0)){var b=a._iDisplayStart+
|
||||
1,c=a.fnDisplayEnd(),d=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),e=a.fnFormatNumber(b),h=a.fnFormatNumber(c),j=a.fnFormatNumber(d),k=a.fnFormatNumber(f);if(a.oScroll.bInfinite)e=a.fnFormatNumber(1);e=a.fnRecordsDisplay()===0&&a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfoEmpty+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()===0?a.oLanguage.sInfoEmpty+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",j)+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfo.replace("_START_",
|
||||
e).replace("_END_",h).replace("_TOTAL_",k)+a.oLanguage.sInfoPostFix:a.oLanguage.sInfo.replace("_START_",e).replace("_END_",h).replace("_TOTAL_",k)+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+a.oLanguage.sInfoPostFix;if(a.oLanguage.fnInfoCallback!==null)e=a.oLanguage.fnInfoCallback(a,b,c,d,f,e);a=a.aanFeatures.i;b=0;for(c=a.length;b<c;b++)i(a[b]).html(e)}}function Ga(a){if(a.oScroll.bInfinite)return null;var b='<select size="1" '+(a.sTableId===""?"":'name="'+
|
||||
a.sTableId+'_length"')+">",c,d;if(a.aLengthMenu.length==2&&typeof a.aLengthMenu[0]=="object"&&typeof a.aLengthMenu[1]=="object"){c=0;for(d=a.aLengthMenu[0].length;c<d;c++)b+='<option value="'+a.aLengthMenu[0][c]+'">'+a.aLengthMenu[1][c]+"</option>"}else{c=0;for(d=a.aLengthMenu.length;c<d;c++)b+='<option value="'+a.aLengthMenu[c]+'">'+a.aLengthMenu[c]+"</option>"}b+="</select>";var f=p.createElement("div");a.sTableId!==""&&typeof a.aanFeatures.l=="undefined"&&f.setAttribute("id",a.sTableId+"_length");
|
||||
f.className=a.oClasses.sLength;f.innerHTML="<label>"+a.oLanguage.sLengthMenu.replace("_MENU_",b)+"</label>";i('select option[value="'+a._iDisplayLength+'"]',f).attr("selected",true);i("select",f).bind("change.DT",function(){var e=i(this).val(),h=a.aanFeatures.l;c=0;for(d=h.length;c<d;c++)h[c]!=this.parentNode&&i("select",h[c]).val(e);a._iDisplayLength=parseInt(e,10);E(a);if(a.fnDisplayEnd()==a.fnRecordsDisplay()){a._iDisplayStart=a.fnDisplayEnd()-a._iDisplayLength;if(a._iDisplayStart<0)a._iDisplayStart=
|
||||
0}if(a._iDisplayLength==-1)a._iDisplayStart=0;C(a)});return f}function Ia(a){var b=p.createElement("div");a.sTableId!==""&&typeof a.aanFeatures.r=="undefined"&&b.setAttribute("id",a.sTableId+"_processing");b.innerHTML=a.oLanguage.sProcessing;b.className=a.oClasses.sProcessing;a.nTable.parentNode.insertBefore(b,a.nTable);return b}function K(a,b){if(a.oFeatures.bProcessing){a=a.aanFeatures.r;for(var c=0,d=a.length;c<d;c++)a[c].style.visibility=b?"visible":"hidden"}}function Na(a,b){for(var c=-1,d=0;d<
|
||||
a.aoColumns.length;d++){a.aoColumns[d].bVisible===true&&c++;if(c==b)return d}return null}function ta(a,b){for(var c=-1,d=0;d<a.aoColumns.length;d++){a.aoColumns[d].bVisible===true&&c++;if(d==b)return a.aoColumns[d].bVisible===true?c:null}return null}function W(a,b){var c,d;c=a._iDisplayStart;for(d=a._iDisplayEnd;c<d;c++)if(a.aoData[a.aiDisplay[c]].nTr==b)return a.aiDisplay[c];c=0;for(d=a.aoData.length;c<d;c++)if(a.aoData[c].nTr==b)return c;return null}function Z(a){for(var b=0,c=0;c<a.aoColumns.length;c++)a.aoColumns[c].bVisible===
|
||||
true&&b++;return b}function E(a){a._iDisplayEnd=a.oFeatures.bPaginate===false?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||a._iDisplayLength==-1?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Sa(a,b){if(!a||a===null||a==="")return 0;if(typeof b=="undefined")b=p.getElementsByTagName("body")[0];var c=p.createElement("div");c.style.width=q(a);b.appendChild(c);a=c.offsetWidth;b.removeChild(c);return a}function ga(a){var b=0,c,d=0,f=a.aoColumns.length,e,h=i("th",
|
||||
a.nTHead);for(e=0;e<f;e++)if(a.aoColumns[e].bVisible){d++;if(a.aoColumns[e].sWidth!==null){c=Sa(a.aoColumns[e].sWidthOrig,a.nTable.parentNode);if(c!==null)a.aoColumns[e].sWidth=q(c);b++}}if(f==h.length&&b===0&&d==f&&a.oScroll.sX===""&&a.oScroll.sY==="")for(e=0;e<a.aoColumns.length;e++){c=i(h[e]).width();if(c!==null)a.aoColumns[e].sWidth=q(c)}else{b=a.nTable.cloneNode(false);e=a.nTHead.cloneNode(true);d=p.createElement("tbody");c=p.createElement("tr");b.removeAttribute("id");b.appendChild(e);if(a.nTFoot!==
|
||||
null){b.appendChild(a.nTFoot.cloneNode(true));P(function(k){k.style.width=""},b.getElementsByTagName("tr"))}b.appendChild(d);d.appendChild(c);d=i("thead th",b);if(d.length===0)d=i("tbody tr:eq(0)>td",b);h=S(a,e);for(e=d=0;e<f;e++){var j=a.aoColumns[e];if(j.bVisible&&j.sWidthOrig!==null&&j.sWidthOrig!=="")h[e-d].style.width=q(j.sWidthOrig);else if(j.bVisible)h[e-d].style.width="";else d++}for(e=0;e<f;e++)if(a.aoColumns[e].bVisible){d=Ta(a,e);if(d!==null){d=d.cloneNode(true);if(a.aoColumns[e].sContentPadding!==
|
||||
"")d.innerHTML+=a.aoColumns[e].sContentPadding;c.appendChild(d)}}f=a.nTable.parentNode;f.appendChild(b);if(a.oScroll.sX!==""&&a.oScroll.sXInner!=="")b.style.width=q(a.oScroll.sXInner);else if(a.oScroll.sX!==""){b.style.width="";if(i(b).width()<f.offsetWidth)b.style.width=q(f.offsetWidth)}else if(a.oScroll.sY!=="")b.style.width=q(f.offsetWidth);b.style.visibility="hidden";Ua(a,b);f=i("tbody tr:eq(0)",b).children();if(f.length===0)f=S(a,i("thead",b)[0]);if(a.oScroll.sX!==""){for(e=d=c=0;e<a.aoColumns.length;e++)if(a.aoColumns[e].bVisible){c+=
|
||||
a.aoColumns[e].sWidthOrig===null?i(f[d]).outerWidth():parseInt(a.aoColumns[e].sWidth.replace("px",""),10)+(i(f[d]).outerWidth()-i(f[d]).width());d++}b.style.width=q(c);a.nTable.style.width=q(c)}for(e=d=0;e<a.aoColumns.length;e++)if(a.aoColumns[e].bVisible){c=i(f[d]).width();if(c!==null&&c>0)a.aoColumns[e].sWidth=q(c);d++}a.nTable.style.width=q(i(b).outerWidth());b.parentNode.removeChild(b)}}function Ua(a,b){if(a.oScroll.sX===""&&a.oScroll.sY!==""){i(b).width();b.style.width=q(i(b).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sX!==
|
||||
"")b.style.width=q(i(b).outerWidth())}function Ta(a,b){var c=Va(a,b);if(c<0)return null;if(a.aoData[c].nTr===null){var d=p.createElement("td");d.innerHTML=G(a,c,b,"");return d}return Q(a,c)[b]}function Va(a,b){for(var c=-1,d=-1,f=0;f<a.aoData.length;f++){var e=G(a,f,b,"display")+"";e=e.replace(/<.*?>/g,"");if(e.length>c){c=e.length;d=f}}return d}function q(a){if(a===null)return"0px";if(typeof a=="number"){if(a<0)return"0px";return a+"px"}var b=a.charCodeAt(a.length-1);if(b<48||b>57)return a;return a+
|
||||
"px"}function Za(a,b){if(a.length!=b.length)return 1;for(var c=0;c<a.length;c++)if(a[c]!=b[c])return 2;return 0}function ia(a){for(var b=n.aTypes,c=b.length,d=0;d<c;d++){var f=b[d](a);if(f!==null)return f}return"string"}function A(a){for(var b=0;b<D.length;b++)if(D[b].nTable==a)return D[b];return null}function ca(a){for(var b=[],c=a.aoData.length,d=0;d<c;d++)b.push(a.aoData[d]._aData);return b}function ba(a){for(var b=[],c=0,d=a.aoData.length;c<d;c++)a.aoData[c].nTr!==null&&b.push(a.aoData[c].nTr);
|
||||
return b}function Q(a,b){var c=[],d,f,e,h,j;f=0;var k=a.aoData.length;if(typeof b!="undefined"){f=b;k=b+1}for(f=f;f<k;f++){j=a.aoData[f];if(j.nTr!==null){b=[];e=0;for(h=j.nTr.childNodes.length;e<h;e++){d=j.nTr.childNodes[e].nodeName.toLowerCase();if(d=="td"||d=="th")b.push(j.nTr.childNodes[e])}e=d=0;for(h=a.aoColumns.length;e<h;e++)if(a.aoColumns[e].bVisible)c.push(b[e-d]);else{c.push(j._anHidden[e]);d++}}}return c}function sa(a){return a.replace(new RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^)",
|
||||
"g"),"\\$1")}function ua(a,b){for(var c=-1,d=0,f=a.length;d<f;d++)if(a[d]==b)c=d;else a[d]>b&&a[d]--;c!=-1&&a.splice(c,1)}function Fa(a,b){b=b.split(",");for(var c=[],d=0,f=a.aoColumns.length;d<f;d++)for(var e=0;e<f;e++)if(a.aoColumns[d].sName==b[e]){c.push(e);break}return c}function ka(a){for(var b="",c=0,d=a.aoColumns.length;c<d;c++)b+=a.aoColumns[c].sName+",";if(b.length==d)return"";return b.slice(0,-1)}function J(a,b,c){a=a.sTableId===""?"DataTables warning: "+c:"DataTables warning (table id = '"+
|
||||
a.sTableId+"'): "+c;if(b===0)if(n.sErrMode=="alert")alert(a);else throw a;else typeof console!="undefined"&&typeof console.log!="undefined"&&console.log(a)}function la(a){a.aoData.splice(0,a.aoData.length);a.aiDisplayMaster.splice(0,a.aiDisplayMaster.length);a.aiDisplay.splice(0,a.aiDisplay.length);E(a)}function va(a){if(!(!a.oFeatures.bStateSave||typeof a.bDestroying!="undefined")){var b,c,d,f="{";f+='"iCreate":'+(new Date).getTime()+",";f+='"iStart":'+(a.oScroll.bInfinite?0:a._iDisplayStart)+",";
|
||||
f+='"iEnd":'+(a.oScroll.bInfinite?a._iDisplayLength:a._iDisplayEnd)+",";f+='"iLength":'+a._iDisplayLength+",";f+='"sFilter":"'+encodeURIComponent(a.oPreviousSearch.sSearch)+'",';f+='"sFilterEsc":'+!a.oPreviousSearch.bRegex+",";f+='"aaSorting":[ ';for(b=0;b<a.aaSorting.length;b++)f+="["+a.aaSorting[b][0]+',"'+a.aaSorting[b][1]+'"],';f=f.substring(0,f.length-1);f+="],";f+='"aaSearchCols":[ ';for(b=0;b<a.aoPreSearchCols.length;b++)f+='["'+encodeURIComponent(a.aoPreSearchCols[b].sSearch)+'",'+!a.aoPreSearchCols[b].bRegex+
|
||||
"],";f=f.substring(0,f.length-1);f+="],";f+='"abVisCols":[ ';for(b=0;b<a.aoColumns.length;b++)f+=a.aoColumns[b].bVisible+",";f=f.substring(0,f.length-1);f+="]";b=0;for(c=a.aoStateSave.length;b<c;b++){d=a.aoStateSave[b].fn(a,f);if(d!=="")f=d}f+="}";Wa(a.sCookiePrefix+a.sInstance,f,a.iCookieDuration,a.sCookiePrefix,a.fnCookieCallback)}}function Xa(a,b){if(a.oFeatures.bStateSave){var c,d,f;d=wa(a.sCookiePrefix+a.sInstance);if(d!==null&&d!==""){try{c=typeof i.parseJSON=="function"?i.parseJSON(d.replace(/'/g,
|
||||
'"')):eval("("+d+")")}catch(e){return}d=0;for(f=a.aoStateLoad.length;d<f;d++)if(!a.aoStateLoad[d].fn(a,c))return;a.oLoadedState=i.extend(true,{},c);a._iDisplayStart=c.iStart;a.iInitDisplayStart=c.iStart;a._iDisplayEnd=c.iEnd;a._iDisplayLength=c.iLength;a.oPreviousSearch.sSearch=decodeURIComponent(c.sFilter);a.aaSorting=c.aaSorting.slice();a.saved_aaSorting=c.aaSorting.slice();if(typeof c.sFilterEsc!="undefined")a.oPreviousSearch.bRegex=!c.sFilterEsc;if(typeof c.aaSearchCols!="undefined")for(d=0;d<
|
||||
c.aaSearchCols.length;d++)a.aoPreSearchCols[d]={sSearch:decodeURIComponent(c.aaSearchCols[d][0]),bRegex:!c.aaSearchCols[d][1]};if(typeof c.abVisCols!="undefined"){b.saved_aoColumns=[];for(d=0;d<c.abVisCols.length;d++){b.saved_aoColumns[d]={};b.saved_aoColumns[d].bVisible=c.abVisCols[d]}}}}}function Wa(a,b,c,d,f){var e=new Date;e.setTime(e.getTime()+c*1E3);c=za.location.pathname.split("/");a=a+"_"+c.pop().replace(/[\/:]/g,"").toLowerCase();var h;if(f!==null){h=typeof i.parseJSON=="function"?i.parseJSON(b):
|
||||
eval("("+b+")");b=f(a,h,e.toGMTString(),c.join("/")+"/")}else b=a+"="+encodeURIComponent(b)+"; expires="+e.toGMTString()+"; path="+c.join("/")+"/";f="";e=9999999999999;if((wa(a)!==null?p.cookie.length:b.length+p.cookie.length)+10>4096){a=p.cookie.split(";");for(var j=0,k=a.length;j<k;j++)if(a[j].indexOf(d)!=-1){var m=a[j].split("=");try{h=eval("("+decodeURIComponent(m[1])+")")}catch(u){continue}if(typeof h.iCreate!="undefined"&&h.iCreate<e){f=m[0];e=h.iCreate}}if(f!=="")p.cookie=f+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
|
||||
c.join("/")+"/"}p.cookie=b}function wa(a){var b=za.location.pathname.split("/");a=a+"_"+b[b.length-1].replace(/[\/:]/g,"").toLowerCase()+"=";b=p.cookie.split(";");for(var c=0;c<b.length;c++){for(var d=b[c];d.charAt(0)==" ";)d=d.substring(1,d.length);if(d.indexOf(a)===0)return decodeURIComponent(d.substring(a.length,d.length))}return null}function Y(a,b){b=i(b).children("tr");var c,d,f,e,h,j,k,m,u=function(L,T,B){for(;typeof L[T][B]!="undefined";)B++;return B};a.splice(0,a.length);d=0;for(j=b.length;d<
|
||||
j;d++)a.push([]);d=0;for(j=b.length;d<j;d++){f=0;for(k=b[d].childNodes.length;f<k;f++){c=b[d].childNodes[f];if(c.nodeName.toUpperCase()=="TD"||c.nodeName.toUpperCase()=="TH"){var r=c.getAttribute("colspan")*1,H=c.getAttribute("rowspan")*1;r=!r||r===0||r===1?1:r;H=!H||H===0||H===1?1:H;m=u(a,d,0);for(h=0;h<r;h++)for(e=0;e<H;e++){a[d+e][m+h]={cell:c,unique:r==1?true:false};a[d+e].nTr=b[d]}}}}}function S(a,b,c){var d=[];if(typeof c=="undefined"){c=a.aoHeader;if(typeof b!="undefined"){c=[];Y(c,b)}}b=0;
|
||||
for(var f=c.length;b<f;b++)for(var e=0,h=c[b].length;e<h;e++)if(c[b][e].unique&&(typeof d[e]=="undefined"||!a.bSortCellsTop))d[e]=c[b][e].cell;return d}function Ya(){var a=p.createElement("p"),b=a.style;b.width="100%";b.height="200px";b.padding="0px";var c=p.createElement("div");b=c.style;b.position="absolute";b.top="0px";b.left="0px";b.visibility="hidden";b.width="200px";b.height="150px";b.padding="0px";b.overflow="hidden";c.appendChild(a);p.body.appendChild(c);b=a.offsetWidth;c.style.overflow="scroll";
|
||||
a=a.offsetWidth;if(b==a)a=c.clientWidth;p.body.removeChild(c);return b-a}function P(a,b,c){for(var d=0,f=b.length;d<f;d++)for(var e=0,h=b[d].childNodes.length;e<h;e++)if(b[d].childNodes[e].nodeType==1)typeof c!="undefined"?a(b[d].childNodes[e],c[d].childNodes[e]):a(b[d].childNodes[e])}function o(a,b,c,d){if(typeof d=="undefined")d=c;if(typeof b[c]!="undefined")a[d]=b[c]}function fa(a,b,c){for(var d=[],f=0,e=a.aoColumns.length;f<e;f++)d.push(G(a,b,f,c));return d}function G(a,b,c,d){var f=a.aoColumns[c];
|
||||
if((c=f.fnGetData(a.aoData[b]._aData))===undefined){if(a.iDrawError!=a.iDraw&&f.sDefaultContent===null){J(a,0,"Requested unknown parameter '"+f.mDataProp+"' from the data source for row "+b);a.iDrawError=a.iDraw}return f.sDefaultContent}if(c===null&&f.sDefaultContent!==null)c=f.sDefaultContent;else if(typeof c=="function")return c();if(d=="display"&&c===null)return"";return c}function O(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,d)}function aa(a){if(a===null)return function(){return null};
|
||||
else if(typeof a=="function")return function(c){return a(c)};else if(typeof a=="string"&&a.indexOf(".")!=-1){var b=a.split(".");return b.length==2?function(c){return c[b[0]][b[1]]}:b.length==3?function(c){return c[b[0]][b[1]][b[2]]}:function(c){for(var d=0,f=b.length;d<f;d++)c=c[b[d]];return c}}else return function(c){return c[a]}}function Ba(a){if(a===null)return function(){};else if(typeof a=="function")return function(c,d){return a(c,d)};else if(typeof a=="string"&&a.indexOf(".")!=-1){var b=a.split(".");
|
||||
return b.length==2?function(c,d){c[b[0]][b[1]]=d}:b.length==3?function(c,d){c[b[0]][b[1]][b[2]]=d}:function(c,d){for(var f=0,e=b.length-1;f<e;f++)c=c[b[f]];c[b[b.length-1]]=d}}else return function(c,d){c[a]=d}}this.oApi={};this.fnDraw=function(a){var b=A(this[n.iApiIndex]);if(typeof a!="undefined"&&a===false){E(b);C(b)}else da(b)};this.fnFilter=function(a,b,c,d,f){var e=A(this[n.iApiIndex]);if(e.oFeatures.bFilter){if(typeof c=="undefined")c=false;if(typeof d=="undefined")d=true;if(typeof f=="undefined")f=
|
||||
true;if(typeof b=="undefined"||b===null){N(e,{sSearch:a,bRegex:c,bSmart:d},1);if(f&&typeof e.aanFeatures.f!="undefined"){b=e.aanFeatures.f;c=0;for(d=b.length;c<d;c++)i("input",b[c]).val(a)}}else{e.aoPreSearchCols[b].sSearch=a;e.aoPreSearchCols[b].bRegex=c;e.aoPreSearchCols[b].bSmart=d;N(e,e.oPreviousSearch,1)}}};this.fnSettings=function(){return A(this[n.iApiIndex])};this.fnVersionCheck=n.fnVersionCheck;this.fnSort=function(a){var b=A(this[n.iApiIndex]);b.aaSorting=a;R(b)};this.fnSortListener=function(a,
|
||||
b,c){ja(A(this[n.iApiIndex]),a,b,c)};this.fnAddData=function(a,b){if(a.length===0)return[];var c=[],d,f=A(this[n.iApiIndex]);if(typeof a[0]=="object")for(var e=0;e<a.length;e++){d=v(f,a[e]);if(d==-1)return c;c.push(d)}else{d=v(f,a);if(d==-1)return c;c.push(d)}f.aiDisplay=f.aiDisplayMaster.slice();if(typeof b=="undefined"||b)da(f);return c};this.fnDeleteRow=function(a,b,c){var d=A(this[n.iApiIndex]);a=typeof a=="object"?W(d,a):a;var f=d.aoData.splice(a,1),e=i.inArray(a,d.aiDisplay);d.asDataSearch.splice(e,
|
||||
1);ua(d.aiDisplayMaster,a);ua(d.aiDisplay,a);typeof b=="function"&&b.call(this,d,f);if(d._iDisplayStart>=d.aiDisplay.length){d._iDisplayStart-=d._iDisplayLength;if(d._iDisplayStart<0)d._iDisplayStart=0}if(typeof c=="undefined"||c){E(d);C(d)}return f};this.fnClearTable=function(a){var b=A(this[n.iApiIndex]);la(b);if(typeof a=="undefined"||a)C(b)};this.fnOpen=function(a,b,c){var d=A(this[n.iApiIndex]);this.fnClose(a);var f=p.createElement("tr"),e=p.createElement("td");f.appendChild(e);e.className=c;
|
||||
e.colSpan=Z(d);if(typeof b.jquery!="undefined"||typeof b=="object")e.appendChild(b);else e.innerHTML=b;b=i("tr",d.nTBody);i.inArray(a,b)!=-1&&i(f).insertAfter(a);d.aoOpenRows.push({nTr:f,nParent:a});return f};this.fnClose=function(a){for(var b=A(this[n.iApiIndex]),c=0;c<b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a){(a=b.aoOpenRows[c].nTr.parentNode)&&a.removeChild(b.aoOpenRows[c].nTr);b.aoOpenRows.splice(c,1);return 0}return 1};this.fnGetData=function(a,b){var c=A(this[n.iApiIndex]);if(typeof a!=
|
||||
"undefined"){a=typeof a=="object"?W(c,a):a;if(typeof b!="undefined")return G(c,a,b,"");return typeof c.aoData[a]!="undefined"?c.aoData[a]._aData:null}return ca(c)};this.fnGetNodes=function(a){var b=A(this[n.iApiIndex]);if(typeof a!="undefined")return typeof b.aoData[a]!="undefined"?b.aoData[a].nTr:null;return ba(b)};this.fnGetPosition=function(a){var b=A(this[n.iApiIndex]),c=a.nodeName.toUpperCase();if(c=="TR")return W(b,a);else if(c=="TD"||c=="TH"){c=W(b,a.parentNode);for(var d=Q(b,c),f=0;f<b.aoColumns.length;f++)if(d[f]==
|
||||
a)return[c,ta(b,f),f]}return null};this.fnUpdate=function(a,b,c,d,f){var e=A(this[n.iApiIndex]);b=typeof b=="object"?W(e,b):b;if(i.isArray(a)&&typeof a=="object"){e.aoData[b]._aData=a.slice();for(c=0;c<e.aoColumns.length;c++)this.fnUpdate(G(e,b,c),b,c,false,false)}else if(a!==null&&typeof a=="object"){e.aoData[b]._aData=i.extend(true,{},a);for(c=0;c<e.aoColumns.length;c++)this.fnUpdate(G(e,b,c),b,c,false,false)}else{a=a;O(e,b,c,a);if(e.aoColumns[c].fnRender!==null){a=e.aoColumns[c].fnRender({iDataRow:b,
|
||||
iDataColumn:c,aData:e.aoData[b]._aData,oSettings:e});e.aoColumns[c].bUseRendered&&O(e,b,c,a)}if(e.aoData[b].nTr!==null)Q(e,b)[c].innerHTML=a}c=i.inArray(b,e.aiDisplay);e.asDataSearch[c]=ra(e,fa(e,b,"filter"));if(typeof f=="undefined"||f)ea(e);if(typeof d=="undefined"||d)da(e);return 0};this.fnSetColumnVis=function(a,b,c){var d=A(this[n.iApiIndex]),f,e;e=d.aoColumns.length;var h,j;if(d.aoColumns[a].bVisible!=b){if(b){for(f=j=0;f<a;f++)d.aoColumns[f].bVisible&&j++;j=j>=Z(d);if(!j)for(f=a;f<e;f++)if(d.aoColumns[f].bVisible){h=
|
||||
f;break}f=0;for(e=d.aoData.length;f<e;f++)if(d.aoData[f].nTr!==null)j?d.aoData[f].nTr.appendChild(d.aoData[f]._anHidden[a]):d.aoData[f].nTr.insertBefore(d.aoData[f]._anHidden[a],Q(d,f)[h])}else{f=0;for(e=d.aoData.length;f<e;f++)if(d.aoData[f].nTr!==null){h=Q(d,f)[a];d.aoData[f]._anHidden[a]=h;h.parentNode.removeChild(h)}}d.aoColumns[a].bVisible=b;M(d,d.aoHeader);d.nTFoot&&M(d,d.aoFooter);f=0;for(e=d.aoOpenRows.length;f<e;f++)d.aoOpenRows[f].nTr.colSpan=Z(d);if(typeof c=="undefined"||c){ea(d);C(d)}va(d)}};
|
||||
this.fnPageChange=function(a,b){var c=A(this[n.iApiIndex]);ma(c,a);E(c);if(typeof b=="undefined"||b)C(c)};this.fnDestroy=function(){var a=A(this[n.iApiIndex]),b=a.nTableWrapper.parentNode,c=a.nTBody,d,f;a.bDestroying=true;d=0;for(f=a.aoDestroyCallback.length;d<f;d++)a.aoDestroyCallback[d].fn();d=0;for(f=a.aoColumns.length;d<f;d++)a.aoColumns[d].bVisible===false&&this.fnSetColumnVis(d,true);i(a.nTableWrapper).find("*").andSelf().unbind(".DT");i("tbody>tr>td."+a.oClasses.sRowEmpty,a.nTable).parent().remove();
|
||||
if(a.nTable!=a.nTHead.parentNode){i(a.nTable).children("thead").remove();a.nTable.appendChild(a.nTHead)}if(a.nTFoot&&a.nTable!=a.nTFoot.parentNode){i(a.nTable).children("tfoot").remove();a.nTable.appendChild(a.nTFoot)}a.nTable.parentNode.removeChild(a.nTable);i(a.nTableWrapper).remove();a.aaSorting=[];a.aaSortingFixed=[];V(a);i(ba(a)).removeClass(a.asStripeClasses.join(" "));if(a.bJUI){i("th",a.nTHead).removeClass([n.oStdClasses.sSortable,n.oJUIClasses.sSortableAsc,n.oJUIClasses.sSortableDesc,n.oJUIClasses.sSortableNone].join(" "));
|
||||
i("th span."+n.oJUIClasses.sSortIcon,a.nTHead).remove();i("th",a.nTHead).each(function(){var e=i("div."+n.oJUIClasses.sSortJUIWrapper,this),h=e.contents();i(this).append(h);e.remove()})}else i("th",a.nTHead).removeClass([n.oStdClasses.sSortable,n.oStdClasses.sSortableAsc,n.oStdClasses.sSortableDesc,n.oStdClasses.sSortableNone].join(" "));a.nTableReinsertBefore?b.insertBefore(a.nTable,a.nTableReinsertBefore):b.appendChild(a.nTable);d=0;for(f=a.aoData.length;d<f;d++)a.aoData[d].nTr!==null&&c.appendChild(a.aoData[d].nTr);
|
||||
if(a.oFeatures.bAutoWidth===true)a.nTable.style.width=q(a.sDestroyWidth);i(c).children("tr:even").addClass(a.asDestroyStripes[0]);i(c).children("tr:odd").addClass(a.asDestroyStripes[1]);d=0;for(f=D.length;d<f;d++)D[d]==a&&D.splice(d,1);a=null};this.fnAdjustColumnSizing=function(a){var b=A(this[n.iApiIndex]);ea(b);if(typeof a=="undefined"||a)this.fnDraw(false);else if(b.oScroll.sX!==""||b.oScroll.sY!=="")this.oApi._fnScrollDraw(b)};for(var xa in n.oApi)if(xa)this[xa]=s(xa);this.oApi._fnExternApiFunc=
|
||||
s;this.oApi._fnInitialise=t;this.oApi._fnInitComplete=w;this.oApi._fnLanguageProcess=y;this.oApi._fnAddColumn=F;this.oApi._fnColumnOptions=x;this.oApi._fnAddData=v;this.oApi._fnCreateTr=z;this.oApi._fnGatherData=$;this.oApi._fnBuildHead=X;this.oApi._fnDrawHead=M;this.oApi._fnDraw=C;this.oApi._fnReDraw=da;this.oApi._fnAjaxUpdate=Ca;this.oApi._fnAjaxParameters=Da;this.oApi._fnAjaxUpdateDraw=Ea;this.oApi._fnServerParams=ha;this.oApi._fnAddOptionsHtml=Aa;this.oApi._fnFeatureHtmlTable=Ja;this.oApi._fnScrollDraw=
|
||||
Ma;this.oApi._fnAdjustColumnSizing=ea;this.oApi._fnFeatureHtmlFilter=Ha;this.oApi._fnFilterComplete=N;this.oApi._fnFilterCustom=Qa;this.oApi._fnFilterColumn=Pa;this.oApi._fnFilter=Oa;this.oApi._fnBuildSearchArray=oa;this.oApi._fnBuildSearchRow=ra;this.oApi._fnFilterCreateSearch=pa;this.oApi._fnDataToSearch=qa;this.oApi._fnSort=R;this.oApi._fnSortAttachListener=ja;this.oApi._fnSortingClasses=V;this.oApi._fnFeatureHtmlPaginate=La;this.oApi._fnPageChange=ma;this.oApi._fnFeatureHtmlInfo=Ka;this.oApi._fnUpdateInfo=
|
||||
Ra;this.oApi._fnFeatureHtmlLength=Ga;this.oApi._fnFeatureHtmlProcessing=Ia;this.oApi._fnProcessingDisplay=K;this.oApi._fnVisibleToColumnIndex=Na;this.oApi._fnColumnIndexToVisible=ta;this.oApi._fnNodeToDataIndex=W;this.oApi._fnVisbleColumns=Z;this.oApi._fnCalculateEnd=E;this.oApi._fnConvertToWidth=Sa;this.oApi._fnCalculateColumnWidths=ga;this.oApi._fnScrollingWidthAdjust=Ua;this.oApi._fnGetWidestNode=Ta;this.oApi._fnGetMaxLenString=Va;this.oApi._fnStringToCss=q;this.oApi._fnArrayCmp=Za;this.oApi._fnDetectType=
|
||||
ia;this.oApi._fnSettingsFromNode=A;this.oApi._fnGetDataMaster=ca;this.oApi._fnGetTrNodes=ba;this.oApi._fnGetTdNodes=Q;this.oApi._fnEscapeRegex=sa;this.oApi._fnDeleteIndex=ua;this.oApi._fnReOrderIndex=Fa;this.oApi._fnColumnOrdering=ka;this.oApi._fnLog=J;this.oApi._fnClearTable=la;this.oApi._fnSaveState=va;this.oApi._fnLoadState=Xa;this.oApi._fnCreateCookie=Wa;this.oApi._fnReadCookie=wa;this.oApi._fnDetectHeader=Y;this.oApi._fnGetUniqueThs=S;this.oApi._fnScrollBarWidth=Ya;this.oApi._fnApplyToChildren=
|
||||
P;this.oApi._fnMap=o;this.oApi._fnGetRowData=fa;this.oApi._fnGetCellData=G;this.oApi._fnSetCellData=O;this.oApi._fnGetObjectDataFn=aa;this.oApi._fnSetObjectDataFn=Ba;var ya=this;return this.each(function(){var a=0,b,c,d,f;a=0;for(b=D.length;a<b;a++){if(D[a].nTable==this)if(typeof g=="undefined"||typeof g.bRetrieve!="undefined"&&g.bRetrieve===true)return D[a].oInstance;else if(typeof g.bDestroy!="undefined"&&g.bDestroy===true){D[a].oInstance.fnDestroy();break}else{J(D[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to destory the old table and create a new one, set bDestroy to true (note that a lot of changes to the configuration can be made through the API which is usually much faster).");
|
||||
return}if(D[a].sTableId!==""&&D[a].sTableId==this.getAttribute("id")){D.splice(a,1);break}}var e=new l;D.push(e);var h=false,j=false;a=this.getAttribute("id");if(a!==null){e.sTableId=a;e.sInstance=a}else e.sInstance=n._oExternConfig.iNextUnique++;if(this.nodeName.toLowerCase()!="table")J(e,0,"Attempted to initialise DataTables on a node which is not a table: "+this.nodeName);else{e.nTable=this;e.oInstance=ya.length==1?ya:i(this).dataTable();e.oApi=ya.oApi;e.sDestroyWidth=i(this).width();if(typeof g!=
|
||||
"undefined"&&g!==null){e.oInit=g;o(e.oFeatures,g,"bPaginate");o(e.oFeatures,g,"bLengthChange");o(e.oFeatures,g,"bFilter");o(e.oFeatures,g,"bSort");o(e.oFeatures,g,"bInfo");o(e.oFeatures,g,"bProcessing");o(e.oFeatures,g,"bAutoWidth");o(e.oFeatures,g,"bSortClasses");o(e.oFeatures,g,"bServerSide");o(e.oFeatures,g,"bDeferRender");o(e.oScroll,g,"sScrollX","sX");o(e.oScroll,g,"sScrollXInner","sXInner");o(e.oScroll,g,"sScrollY","sY");o(e.oScroll,g,"bScrollCollapse","bCollapse");o(e.oScroll,g,"bScrollInfinite",
|
||||
"bInfinite");o(e.oScroll,g,"iScrollLoadGap","iLoadGap");o(e.oScroll,g,"bScrollAutoCss","bAutoCss");o(e,g,"asStripClasses","asStripeClasses");o(e,g,"asStripeClasses");o(e,g,"fnPreDrawCallback");o(e,g,"fnRowCallback");o(e,g,"fnHeaderCallback");o(e,g,"fnFooterCallback");o(e,g,"fnCookieCallback");o(e,g,"fnInitComplete");o(e,g,"fnServerData");o(e,g,"fnFormatNumber");o(e,g,"aaSorting");o(e,g,"aaSortingFixed");o(e,g,"aLengthMenu");o(e,g,"sPaginationType");o(e,g,"sAjaxSource");o(e,g,"sAjaxDataProp");o(e,
|
||||
g,"iCookieDuration");o(e,g,"sCookiePrefix");o(e,g,"sDom");o(e,g,"bSortCellsTop");o(e,g,"oSearch","oPreviousSearch");o(e,g,"aoSearchCols","aoPreSearchCols");o(e,g,"iDisplayLength","_iDisplayLength");o(e,g,"bJQueryUI","bJUI");o(e.oLanguage,g,"fnInfoCallback");typeof g.fnDrawCallback=="function"&&e.aoDrawCallback.push({fn:g.fnDrawCallback,sName:"user"});typeof g.fnServerParams=="function"&&e.aoServerParams.push({fn:g.fnServerParams,sName:"user"});typeof g.fnStateSaveCallback=="function"&&e.aoStateSave.push({fn:g.fnStateSaveCallback,
|
||||
sName:"user"});typeof g.fnStateLoadCallback=="function"&&e.aoStateLoad.push({fn:g.fnStateLoadCallback,sName:"user"});if(e.oFeatures.bServerSide&&e.oFeatures.bSort&&e.oFeatures.bSortClasses)e.aoDrawCallback.push({fn:V,sName:"server_side_sort_classes"});else e.oFeatures.bDeferRender&&e.aoDrawCallback.push({fn:V,sName:"defer_sort_classes"});if(typeof g.bJQueryUI!="undefined"&&g.bJQueryUI){e.oClasses=n.oJUIClasses;if(typeof g.sDom=="undefined")e.sDom='<"H"lfr>t<"F"ip>'}if(e.oScroll.sX!==""||e.oScroll.sY!==
|
||||
"")e.oScroll.iBarWidth=Ya();if(typeof g.iDisplayStart!="undefined"&&typeof e.iInitDisplayStart=="undefined"){e.iInitDisplayStart=g.iDisplayStart;e._iDisplayStart=g.iDisplayStart}if(typeof g.bStateSave!="undefined"){e.oFeatures.bStateSave=g.bStateSave;Xa(e,g);e.aoDrawCallback.push({fn:va,sName:"state_save"})}if(typeof g.iDeferLoading!="undefined"){e.bDeferLoading=true;e._iRecordsTotal=g.iDeferLoading;e._iRecordsDisplay=g.iDeferLoading}if(typeof g.aaData!="undefined")j=true;if(typeof g!="undefined"&&
|
||||
typeof g.aoData!="undefined")g.aoColumns=g.aoData;if(typeof g.oLanguage!="undefined")if(typeof g.oLanguage.sUrl!="undefined"&&g.oLanguage.sUrl!==""){e.oLanguage.sUrl=g.oLanguage.sUrl;i.getJSON(e.oLanguage.sUrl,null,function(u){y(e,u,true)});h=true}else y(e,g.oLanguage,false)}else g={};if(typeof g.asStripClasses=="undefined"&&typeof g.asStripeClasses=="undefined"){e.asStripeClasses.push(e.oClasses.sStripeOdd);e.asStripeClasses.push(e.oClasses.sStripeEven)}c=false;d=i(this).children("tbody").children("tr");
|
||||
a=0;for(b=e.asStripeClasses.length;a<b;a++)if(d.filter(":lt(2)").hasClass(e.asStripeClasses[a])){c=true;break}if(c){e.asDestroyStripes=["",""];if(i(d[0]).hasClass(e.oClasses.sStripeOdd))e.asDestroyStripes[0]+=e.oClasses.sStripeOdd+" ";if(i(d[0]).hasClass(e.oClasses.sStripeEven))e.asDestroyStripes[0]+=e.oClasses.sStripeEven;if(i(d[1]).hasClass(e.oClasses.sStripeOdd))e.asDestroyStripes[1]+=e.oClasses.sStripeOdd+" ";if(i(d[1]).hasClass(e.oClasses.sStripeEven))e.asDestroyStripes[1]+=e.oClasses.sStripeEven;
|
||||
d.removeClass(e.asStripeClasses.join(" "))}c=[];var k;a=this.getElementsByTagName("thead");if(a.length!==0){Y(e.aoHeader,a[0]);c=S(e)}if(typeof g.aoColumns=="undefined"){k=[];a=0;for(b=c.length;a<b;a++)k.push(null)}else k=g.aoColumns;a=0;for(b=k.length;a<b;a++){if(typeof g.saved_aoColumns!="undefined"&&g.saved_aoColumns.length==b){if(k[a]===null)k[a]={};k[a].bVisible=g.saved_aoColumns[a].bVisible}F(e,c?c[a]:null)}if(typeof g.aoColumnDefs!="undefined")for(a=g.aoColumnDefs.length-1;a>=0;a--){var m=
|
||||
g.aoColumnDefs[a].aTargets;i.isArray(m)||J(e,1,"aTargets must be an array of targets, not a "+typeof m);c=0;for(d=m.length;c<d;c++)if(typeof m[c]=="number"&&m[c]>=0){for(;e.aoColumns.length<=m[c];)F(e);x(e,m[c],g.aoColumnDefs[a])}else if(typeof m[c]=="number"&&m[c]<0)x(e,e.aoColumns.length+m[c],g.aoColumnDefs[a]);else if(typeof m[c]=="string"){b=0;for(f=e.aoColumns.length;b<f;b++)if(m[c]=="_all"||i(e.aoColumns[b].nTh).hasClass(m[c]))x(e,b,g.aoColumnDefs[a])}}if(typeof k!="undefined"){a=0;for(b=k.length;a<
|
||||
b;a++)x(e,a,k[a])}a=0;for(b=e.aaSorting.length;a<b;a++){if(e.aaSorting[a][0]>=e.aoColumns.length)e.aaSorting[a][0]=0;k=e.aoColumns[e.aaSorting[a][0]];if(typeof e.aaSorting[a][2]=="undefined")e.aaSorting[a][2]=0;if(typeof g.aaSorting=="undefined"&&typeof e.saved_aaSorting=="undefined")e.aaSorting[a][1]=k.asSorting[0];c=0;for(d=k.asSorting.length;c<d;c++)if(e.aaSorting[a][1]==k.asSorting[c]){e.aaSorting[a][2]=c;break}}V(e);a=i(this).children("thead");if(a.length===0){a=[p.createElement("thead")];this.appendChild(a[0])}e.nTHead=
|
||||
a[0];a=i(this).children("tbody");if(a.length===0){a=[p.createElement("tbody")];this.appendChild(a[0])}e.nTBody=a[0];a=i(this).children("tfoot");if(a.length>0){e.nTFoot=a[0];Y(e.aoFooter,e.nTFoot)}if(j)for(a=0;a<g.aaData.length;a++)v(e,g.aaData[a]);else $(e);e.aiDisplay=e.aiDisplayMaster.slice();e.bInitialised=true;h===false&&t(e)}})}})(jQuery,window,document);
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* File: demo_table.css
|
||||
* CVS: $Id$
|
||||
* Description: CSS descriptions for DataTables demo pages
|
||||
* Author: Allan Jardine
|
||||
* Created: Tue May 12 06:47:22 BST 2009
|
||||
* Modified: $Date$ by $Author$
|
||||
* Language: CSS
|
||||
* Project: DataTables
|
||||
*
|
||||
* Copyright 2009 Allan Jardine. All Rights Reserved.
|
||||
*
|
||||
* ***************************************************************************
|
||||
* DESCRIPTION
|
||||
*
|
||||
* The styles given here are suitable for the demos that are used with the standard DataTables
|
||||
* distribution (see www.datatables.net). You will most likely wish to modify these styles to
|
||||
* meet the layout requirements of your site.
|
||||
*
|
||||
* Common issues:
|
||||
* 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
|
||||
* no conflict between the two pagination types. If you want to use full_numbers pagination
|
||||
* ensure that you either have "example_alt_pagination" as a body class name, or better yet,
|
||||
* modify that selector.
|
||||
* Note that the path used for Images is relative. All images are by default located in
|
||||
* ../images/ - relative to this CSS file.
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables features
|
||||
*/
|
||||
|
||||
.dataTables_wrapper {
|
||||
position: relative;
|
||||
min-height: 302px;
|
||||
clear: both;
|
||||
_height: 302px;
|
||||
zoom: 1; /* Feeling sorry for IE */
|
||||
}
|
||||
|
||||
.dataTables_processing {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 250px;
|
||||
height: 30px;
|
||||
margin-left: -125px;
|
||||
margin-top: -15px;
|
||||
padding: 14px 0 2px 0;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dataTables_length {
|
||||
width: 40%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_filter {
|
||||
width: 50%;
|
||||
float: right;
|
||||
text-align: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dataTables_info {
|
||||
width: 40%;
|
||||
height: 30px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dataTables_paginate {
|
||||
width: 44px;
|
||||
* width: 50px;
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Pagination nested */
|
||||
.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next {
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
margin-left: 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.paginate_disabled_previous {
|
||||
background-image: url('/images/datatables/back_disabled.jpg');
|
||||
}
|
||||
|
||||
.paginate_enabled_previous {
|
||||
background-image: url('/images/datatables/back_enabled.jpg');
|
||||
}
|
||||
|
||||
.paginate_disabled_next {
|
||||
background-image: url('/images/datatables/forward_disabled.jpg');
|
||||
}
|
||||
|
||||
.paginate_enabled_next {
|
||||
background-image: url('/images/datatables/forward_enabled.jpg');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables display
|
||||
*/
|
||||
table.datatable.display {
|
||||
margin: 0 auto;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
|
||||
/* Note Firefox 3.5 and before have a bug with border-collapse
|
||||
* ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 )
|
||||
* border-spacing: 0; is one possible option. Conditional-css.com is
|
||||
* useful for this kind of thing
|
||||
*
|
||||
* Further note IE 6/7 has problems when calculating widths with border width.
|
||||
* It subtracts one px relative to the other browsers from the first column, and
|
||||
* adds one to the end...
|
||||
*
|
||||
* If you want that effect I'd suggest setting a border-top/left on th/td's and
|
||||
* then filling in the gaps with other borders.
|
||||
*/
|
||||
}
|
||||
|
||||
table.datatable.display thead th {
|
||||
padding: 3px 18px 3px 10px;
|
||||
border-bottom: 1px solid black;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
* cursor: hand;
|
||||
}
|
||||
|
||||
table.datatable.display tfoot th {
|
||||
padding: 3px 18px 3px 10px;
|
||||
border-top: 1px solid black;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.datatable.display tr.heading2 td {
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.datatable.display td {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
table.datatable.display td.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables sorting
|
||||
*/
|
||||
|
||||
.datatable .sorting_asc {
|
||||
background: url('/images/datatables/sort_asc.png') no-repeat center right #EAEAEA;
|
||||
}
|
||||
|
||||
.datatable .sorting_desc {
|
||||
background: url('/images/datatables/sort_desc.png') no-repeat center right #EAEAEA;
|
||||
}
|
||||
|
||||
.datatable .sorting {
|
||||
background: url('/images/datatables/sort_both.png') no-repeat center right #EAEAEA;
|
||||
}
|
||||
|
||||
.datatable .sorting_asc_disabled {
|
||||
background: url('/images/datatables/sort_asc_disabled.png') no-repeat center right #EAEAEA;
|
||||
}
|
||||
|
||||
.datatable .sorting_desc_disabled {
|
||||
background: url('/images/datatables/sort_desc_disabled.png') no-repeat center right #EAEAEA;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* DataTables row classes
|
||||
*/
|
||||
table.datatable.display tr.odd.gradeA {
|
||||
background-color: #ddffdd;
|
||||
}
|
||||
|
||||
table.datatable.display tr.even.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
table.datatable.display tr.odd.gradeC {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
table.datatable.display tr.even.gradeC {
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
|
||||
table.datatable.display tr.odd.gradeX {
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
table.datatable.display tr.even.gradeX {
|
||||
background-color: #ffeeee;
|
||||
}
|
||||
|
||||
table.datatable.display tr.odd.gradeU {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
table.datatable.display tr.even.gradeU {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
/*
|
||||
tr.odd {
|
||||
background-color: #E2E4FF;
|
||||
}
|
||||
|
||||
tr.even {
|
||||
background-color: white;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Misc
|
||||
*/
|
||||
.dataTables_scroll {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_scrollBody {
|
||||
*margin-top: -1px;
|
||||
}
|
||||
|
||||
.top, .bottom {
|
||||
padding: 15px;
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.top .dataTables_info {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.dataTables_empty {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tfoot input {
|
||||
margin: 0.5em 0;
|
||||
width: 100%;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
tfoot input.search_init {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
td.group {
|
||||
background-color: #d1cfd0;
|
||||
border-bottom: 2px solid #A19B9E;
|
||||
border-top: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
td.details {
|
||||
background-color: #d1cfd0;
|
||||
border: 2px solid #A19B9E;
|
||||
}
|
||||
|
||||
|
||||
.example_alt_pagination div.dataTables_info {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.paging_full_numbers {
|
||||
width: 400px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.paging_full_numbers span.paginate_button,
|
||||
.paging_full_numbers span.paginate_active {
|
||||
border-radius: 2px 2px 2px 2px;
|
||||
background-color: #F4F4F4;
|
||||
background-image: url("/stylesheets/web-app-theme/themes/default/images/button-background.png");
|
||||
border: 1px solid #C3C4BA;
|
||||
color: #111111;
|
||||
margin-right: 5px;
|
||||
min-width: 15px;
|
||||
padding: 6px 10px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paging_full_numbers span.paginate_button:hover{
|
||||
border: 1px solid #818171;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.paging_full_numbers span.paginate_button_disabled:hover{
|
||||
border: 1px solid #C3C4BA;
|
||||
box-shadow: 0 0 0;
|
||||
}
|
||||
|
||||
.paging_full_numbers span.paginate_active {
|
||||
background: none repeat scroll 0 0 #261F1F;
|
||||
border: 1px solid #261F1F;
|
||||
color: white;
|
||||
}
|
||||
|
||||
table.display tr.even.row_selected td {
|
||||
background-color: #B0BED9;
|
||||
}
|
||||
|
||||
table.display tr.odd.row_selected td {
|
||||
background-color: #9FAFD1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting classes for columns
|
||||
*/
|
||||
/* For the standard odd/even */
|
||||
/*
|
||||
tr.odd td.sorting_1 {
|
||||
background-color: #D3D6FF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_2 {
|
||||
background-color: #DADCFF;
|
||||
}
|
||||
|
||||
tr.odd td.sorting_3 {
|
||||
background-color: #E0E2FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_1 {
|
||||
background-color: #EAEBFF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_2 {
|
||||
background-color: #F2F3FF;
|
||||
}
|
||||
|
||||
tr.even td.sorting_3 {
|
||||
background-color: #F9F9FF;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/* For the Conditional-CSS grading rows */
|
||||
/*
|
||||
Colour calculations (based off the main row colours)
|
||||
Level 1:
|
||||
dd > c4
|
||||
ee > d5
|
||||
Level 2:
|
||||
dd > d1
|
||||
ee > e2
|
||||
*/
|
||||
tr.odd.gradeA td.sorting_1 {
|
||||
background-color: #c4ffc4;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_2 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.odd.gradeA td.sorting_3 {
|
||||
background-color: #d1ffd1;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_1 {
|
||||
background-color: #d5ffd5;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_2 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.even.gradeA td.sorting_3 {
|
||||
background-color: #e2ffe2;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_1 {
|
||||
background-color: #c4c4ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_2 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeC td.sorting_3 {
|
||||
background-color: #d1d1ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_1 {
|
||||
background-color: #d5d5ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_2 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.even.gradeC td.sorting_3 {
|
||||
background-color: #e2e2ff;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_1 {
|
||||
background-color: #ffc4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_2 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeX td.sorting_3 {
|
||||
background-color: #ffd1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_1 {
|
||||
background-color: #ffd5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_2 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeX td.sorting_3 {
|
||||
background-color: #ffe2e2;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_1 {
|
||||
background-color: #c4c4c4;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_2 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.odd.gradeU td.sorting_3 {
|
||||
background-color: #d1d1d1;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_1 {
|
||||
background-color: #d5d5d5;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_2 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
tr.even.gradeU td.sorting_3 {
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Row highlighting example
|
||||
*/
|
||||
.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
|
||||
background-color: #ECFFB3;
|
||||
}
|
||||
|
||||
.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
|
||||
background-color: #E6FF99;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover {
|
||||
background-color: #ECFFB3;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_1 {
|
||||
background-color: #DDFF75;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_2 {
|
||||
background-color: #E7FF9E;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.even:hover td.sorting_3 {
|
||||
background-color: #E2FF89;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover {
|
||||
background-color: #E6FF99;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_1 {
|
||||
background-color: #D6FF5C;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_2 {
|
||||
background-color: #E0FF84;
|
||||
}
|
||||
|
||||
.ex_highlight_row #example tr.odd:hover td.sorting_3 {
|
||||
background-color: #DBFF70;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* KeyTable
|
||||
*/
|
||||
table.KeyTable td {
|
||||
border: 3px solid transparent;
|
||||
}
|
||||
|
||||
table.KeyTable td.focus {
|
||||
border: 3px solid #3366FF;
|
||||
}
|
||||
|
||||
table.display tr.gradeA {
|
||||
background-color: #eeffee;
|
||||
}
|
||||
|
||||
table.display tr.gradeC {
|
||||
background-color: #ddddff;
|
||||
}
|
||||
|
||||
table.display tr.gradeX {
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
table.display tr.gradeU {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
div.box {
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
border: 1px solid #8080FF;
|
||||
background-color: #E5E5FF;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
ul.list li .item {
|
||||
margin-left: 180px;
|
||||
}
|
||||
|
|
@ -26,7 +26,48 @@ describe BuildListsController do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'create build list' do
|
||||
it 'should be able to perform new action' do
|
||||
get :new, :project_id => @project.id
|
||||
response.should render_template(:new)
|
||||
end
|
||||
|
||||
it 'should be able to perform create action' do
|
||||
post :create, {:project_id => @project.id}.merge(@create_params)
|
||||
response.should redirect_to(@project)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'not create build list' do
|
||||
it 'should not be able to perform new action' do
|
||||
get :new, :project_id => @project.id
|
||||
response.should redirect_to(forbidden_url)
|
||||
end
|
||||
|
||||
it 'should not be able to perform create action' do
|
||||
post :create, {:project_id => @project.id}.merge(@create_params)
|
||||
response.should redirect_to(forbidden_url)
|
||||
end
|
||||
end
|
||||
|
||||
before { stub_rsync_methods }
|
||||
|
||||
context 'crud' do
|
||||
before(:each) do
|
||||
platform = Factory(:platform_with_repos)
|
||||
@create_params = {
|
||||
:build_list => {
|
||||
:project_version => 'v1.0',
|
||||
:pl_id => platform.id,
|
||||
:update_type => 'security',
|
||||
:include_repos => [platform.repositories.first.id]
|
||||
},
|
||||
:arches => [Factory(:arch).id],
|
||||
:bpls => [platform.id]
|
||||
}
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
end
|
||||
|
||||
context 'for guest' do
|
||||
it 'should not be able to perform index action' do
|
||||
get :index
|
||||
|
@ -36,7 +77,6 @@ describe BuildListsController do
|
|||
|
||||
context 'for user' do
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
@build_list = Factory(:build_list_core)
|
||||
@project = @build_list.project
|
||||
@owner_user = @project.owner
|
||||
|
@ -47,7 +87,6 @@ describe BuildListsController do
|
|||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@show_params = {:project_id => @project.id, :id => @build_list.id}
|
||||
|
||||
end
|
||||
|
||||
context 'for all build lists' do
|
||||
|
@ -55,9 +94,8 @@ describe BuildListsController do
|
|||
@build_list1 = Factory(:build_list_core)
|
||||
@build_list2 = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
@build_list3 = Factory(:build_list_core, :project => Factory(:project, :owner => @user, :visibility => 'hidden'))
|
||||
b = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
b.project.relations.create :role => 'reader', :object_id => @user.id, :object_type => 'User'
|
||||
@build_list4 = b
|
||||
@build_list4 = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
@build_list4.project.relations.create :role => 'reader', :object_id => @user.id, :object_type => 'User'
|
||||
end
|
||||
|
||||
it 'should be able to perform index action' do
|
||||
|
@ -76,15 +114,18 @@ describe BuildListsController do
|
|||
|
||||
context 'for open project' do
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
|
||||
context 'if user is project owner' do
|
||||
before(:each) {set_session_for(@owner_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'create build list'
|
||||
end
|
||||
|
||||
context 'if user is project member' do
|
||||
context 'if user is project read member' do
|
||||
before(:each) {set_session_for(@member_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -95,23 +136,24 @@ describe BuildListsController do
|
|||
end
|
||||
|
||||
it_should_behave_like 'not show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
|
||||
context 'if user is project owner' do
|
||||
before(:each) {set_session_for(@owner_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'create build list'
|
||||
end
|
||||
|
||||
context 'if user is project member' do
|
||||
context 'if user is project read member' do
|
||||
before(:each) {set_session_for(@member_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'for group' do
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
@owner_group = Factory(:group)
|
||||
@owner_user = Factory(:user)
|
||||
@owner_group.objects.create :role => 'reader', :object_id => @owner_user.id, :object_type => 'User'
|
||||
|
@ -137,9 +179,8 @@ describe BuildListsController do
|
|||
@build_list1 = Factory(:build_list_core)
|
||||
@build_list2 = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
@build_list3 = Factory(:build_list_core, :project => Factory(:project, :owner => @group, :visibility => 'hidden'))
|
||||
b = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
b.project.relations.create :role => 'reader', :object_id => @group.id, :object_type => 'Group'
|
||||
@build_list4 = b
|
||||
@build_list4 = Factory(:build_list_core, :project => Factory(:project, :visibility => 'hidden'))
|
||||
@build_list4.project.relations.create :role => 'reader', :object_id => @group.id, :object_type => 'Group'
|
||||
end
|
||||
|
||||
it 'should be able to perform index action' do
|
||||
|
@ -158,15 +199,18 @@ describe BuildListsController do
|
|||
|
||||
context 'for open project' do
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
|
||||
context 'if user is group owner' do
|
||||
before(:each) {set_session_for(@owner_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'create build list'
|
||||
end
|
||||
|
||||
context 'if user is group member' do
|
||||
context 'if user is group read member' do
|
||||
before(:each) {set_session_for(@member_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -177,15 +221,18 @@ describe BuildListsController do
|
|||
end
|
||||
|
||||
it_should_behave_like 'not show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
|
||||
context 'if user is group owner' do
|
||||
before(:each) {set_session_for(@owner_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'create build list'
|
||||
end
|
||||
|
||||
context 'if user is group member' do
|
||||
context 'if user is group read member' do
|
||||
before(:each) {set_session_for(@member_user)}
|
||||
it_should_behave_like 'show build list'
|
||||
it_should_behave_like 'not create build list'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -210,7 +257,6 @@ describe BuildListsController do
|
|||
context 'filter' do
|
||||
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
set_session_for Factory(:admin)
|
||||
|
||||
@build_list1 = Factory(:build_list_core)
|
||||
|
@ -250,5 +296,99 @@ describe BuildListsController do
|
|||
end
|
||||
|
||||
context 'callbacks' do
|
||||
let(:build_list) { Factory(:build_list_core) }
|
||||
|
||||
describe 'publish_build' do
|
||||
def do_get(status)
|
||||
get :publish_build, :id => build_list.bs_id, :status => status
|
||||
build_list.reload
|
||||
end
|
||||
|
||||
it { do_get(BuildServer::SUCCESS); response.should be_ok }
|
||||
it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISHED) }
|
||||
it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildList::FAILED_PUBLISH) }
|
||||
it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :notified_at) }
|
||||
end
|
||||
|
||||
describe 'status_build' do
|
||||
before { @item = build_list.items.create(:name => build_list.project.name, :version => build_list.project_version, :level => 0) }
|
||||
|
||||
def do_get
|
||||
get :status_build, :id => build_list.bs_id, :package_name => build_list.project.name, :status => BuildServer::SUCCESS, :container_path => '/path/to'
|
||||
build_list.reload
|
||||
@item.reload
|
||||
end
|
||||
|
||||
it { do_get; response.should be_ok }
|
||||
it { lambda{ do_get }.should change(@item, :status) }
|
||||
it { lambda{ do_get }.should change(build_list, :container_path) }
|
||||
it { lambda{ do_get }.should change(build_list, :notified_at) }
|
||||
end
|
||||
|
||||
describe 'pre_build' do
|
||||
def do_get
|
||||
get :pre_build, :id => build_list.bs_id
|
||||
build_list.reload
|
||||
end
|
||||
|
||||
it { do_get; response.should be_ok }
|
||||
it { lambda{ do_get }.should change(build_list, :status).to(BuildServer::BUILD_STARTED) }
|
||||
it { lambda{ do_get }.should change(build_list, :notified_at) }
|
||||
end
|
||||
|
||||
describe 'post_build' do
|
||||
def do_get(status)
|
||||
get :post_build, :id => build_list.bs_id, :status => status, :container_path => '/path/to'
|
||||
build_list.reload
|
||||
end
|
||||
|
||||
it { do_get(BuildServer::SUCCESS); response.should be_ok }
|
||||
it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :container_path) }
|
||||
it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :notified_at) }
|
||||
|
||||
context 'with auto_publish' do
|
||||
it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISH) }
|
||||
it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildServer::ERROR) }
|
||||
end
|
||||
|
||||
context 'without auto_publish' do
|
||||
before { build_list.update_attribute(:auto_publish, false) }
|
||||
|
||||
it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildServer::SUCCESS) }
|
||||
it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildServer::ERROR) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'circle_build' do
|
||||
def do_get
|
||||
get :circle_build, :id => build_list.bs_id, :container_path => '/path/to'
|
||||
build_list.reload
|
||||
end
|
||||
|
||||
it { do_get; response.should be_ok }
|
||||
it { lambda{ do_get }.should change(build_list, :is_circle).to(true) }
|
||||
it { lambda{ do_get }.should change(build_list, :container_path) }
|
||||
it { lambda{ do_get }.should change(build_list, :notified_at) }
|
||||
end
|
||||
|
||||
describe 'new_bbdt' do
|
||||
before { @items = build_list.items }
|
||||
|
||||
def do_get
|
||||
get :new_bbdt, :id => 123, :web_id => build_list.id, :name => build_list.project.name, :is_circular => 1,
|
||||
:additional_repos => ActiveSupport::JSON.encode([{:name => 'build_repos'}, {:name => 'main'}]),
|
||||
:items => ActiveSupport::JSON.encode(0 => [{:name => build_list.project.name, :version => build_list.project_version}])
|
||||
build_list.reload
|
||||
@items.reload
|
||||
end
|
||||
|
||||
it { do_get; response.should be_ok }
|
||||
it { lambda{ do_get }.should change(build_list, :name).to(build_list.project.name) }
|
||||
it { lambda{ do_get }.should change(build_list, :additional_repos) }
|
||||
it { lambda{ do_get }.should change(@items, :first) }
|
||||
it { lambda{ do_get }.should change(build_list, :is_circle).to(true) }
|
||||
it { lambda{ do_get }.should change(build_list, :bs_id).to(123) }
|
||||
it { lambda{ do_get }.should change(build_list, :notified_at) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
require 'spec_helper'
|
||||
|
||||
shared_examples_for 'user with create comment rights' do
|
||||
it 'should be able to perform create action' do
|
||||
post :create, @create_params
|
||||
response.should redirect_to(project_issue_path(@project, @issue))
|
||||
end
|
||||
|
||||
it 'should create subscribe object into db' do
|
||||
lambda{ post :create, @create_params }.should change{ Comment.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user with update own comment rights' do
|
||||
it 'should be able to perform update action' do
|
||||
put :update, {:id => @own_comment.id}.merge(@update_params)
|
||||
response.should redirect_to([@project, @issue])
|
||||
end
|
||||
|
||||
it 'should update subscribe body' do
|
||||
put :update, {:id => @own_comment.id}.merge(@update_params)
|
||||
@own_comment.reload.body.should == 'updated'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user with update stranger comment rights' do
|
||||
it 'should be able to perform update action' do
|
||||
put :update, {:id => @comment.id}.merge(@update_params)
|
||||
response.should redirect_to([@project, @issue])
|
||||
end
|
||||
|
||||
it 'should update issue title' do
|
||||
put :update, {:id => @comment.id}.merge(@update_params)
|
||||
@comment.reload.body.should == 'updated'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user without update stranger comment rights' do
|
||||
it 'should not be able to perform update action' do
|
||||
put :update, {:id => @comment.id}.merge(@update_params)
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not update issue title' do
|
||||
put :update, {:id => @comment.id}.merge(@update_params)
|
||||
@comment.reload.body.should_not == 'updated'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user without destroy comment rights' do
|
||||
it 'should not be able to perform destroy action' do
|
||||
delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not reduce comments count' do
|
||||
lambda{ delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id }.should change{ Issue.count }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
#shared_examples_for 'user with destroy rights' do
|
||||
# it 'should be able to perform destroy action' do
|
||||
# delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id
|
||||
# response.should redirect_to([@project, @issue])
|
||||
# end
|
||||
#
|
||||
# it 'should reduce comments count' do
|
||||
# lambda{ delete :destroy, :id => @comment.id, :issue_id => @issue.id, :project_id => @project.id }.should change{ Comment.count }.by(-1)
|
||||
# end
|
||||
#end
|
||||
|
||||
describe CommentsController do
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
|
||||
@project = Factory(:project)
|
||||
@issue = Factory(:issue, :project_id => @project.id)
|
||||
@comment = Factory(:comment, :commentable => @issue)
|
||||
|
||||
@create_params = {:comment => {:body => 'I am a comment!'}, :project_id => @project.id, :issue_id => @issue.id}
|
||||
@update_params = {:comment => {:body => 'updated'}, :project_id => @project.id, :issue_id => @issue.id}
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
|
||||
@request.env['HTTP_REFERER'] = project_issue_path(@project, @issue)
|
||||
end
|
||||
|
||||
context 'for project admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
|
||||
@own_comment = Factory(:comment, :commentable => @issue, :user => @user)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user with create comment rights'
|
||||
it_should_behave_like 'user with update stranger comment rights'
|
||||
it_should_behave_like 'user with update own comment rights'
|
||||
it_should_behave_like 'user without destroy comment rights'
|
||||
end
|
||||
|
||||
context 'for project owner user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.update_attribute(:owner, @user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
|
||||
@own_comment = Factory(:comment, :commentable => @issue, :user => @user)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user with create comment rights'
|
||||
it_should_behave_like 'user with update stranger comment rights'
|
||||
it_should_behave_like 'user with update own comment rights'
|
||||
it_should_behave_like 'user without destroy comment rights'
|
||||
end
|
||||
|
||||
context 'for project reader user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'reader')
|
||||
|
||||
@own_comment = Factory(:comment, :commentable => @issue, :user => @user)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user with create comment rights'
|
||||
it_should_behave_like 'user without update stranger comment rights'
|
||||
it_should_behave_like 'user with update own comment rights'
|
||||
it_should_behave_like 'user without destroy comment rights'
|
||||
end
|
||||
|
||||
context 'for project writer user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'writer')
|
||||
|
||||
@own_comment = Factory(:comment, :commentable => @issue, :user => @user)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user with create comment rights'
|
||||
it_should_behave_like 'user without update stranger comment rights'
|
||||
it_should_behave_like 'user with update own comment rights'
|
||||
it_should_behave_like 'user without destroy comment rights'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,187 @@
|
|||
require 'spec_helper'
|
||||
|
||||
shared_examples_for 'issue user with project reader rights' do
|
||||
it 'should be able to perform index action' do
|
||||
get :index, :project_id => @project.id
|
||||
response.should render_template(:index)
|
||||
end
|
||||
|
||||
it 'should be able to perform show action' do
|
||||
get :show, :project_id => @project.id, :id => @issue.serial_id
|
||||
response.should render_template(:show)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'issue user with project writer rights' do
|
||||
it 'should be able to perform create action' do
|
||||
post :create, @create_params
|
||||
response.should redirect_to(project_issues_path(@project))
|
||||
end
|
||||
|
||||
it 'should create issue object into db' do
|
||||
lambda{ post :create, @create_params }.should change{ Issue.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user with issue update rights' do
|
||||
it 'should be able to perform update action' do
|
||||
put :update, {:id => @issue.serial_id}.merge(@update_params)
|
||||
response.should redirect_to([@project, @issue])
|
||||
end
|
||||
|
||||
it 'should update issue title' do
|
||||
put :update, {:id => @issue.serial_id}.merge(@update_params)
|
||||
@issue.reload.title.should == 'issue2'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user without issue update rights' do
|
||||
it 'should not be able to perform update action' do
|
||||
put :update, {:id => @issue.serial_id}.merge(@update_params)
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not update issue title' do
|
||||
put :update, {:id => @issue.serial_id}.merge(@update_params)
|
||||
@issue.reload.title.should_not == 'issue2'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user without issue destroy rights' do
|
||||
it 'should not be able to perform destroy action' do
|
||||
delete :destroy, :id => @issue.serial_id, :project_id => @project.id
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not reduce issues count' do
|
||||
lambda{ delete :destroy, :id => @issue.serial_id, :project_id => @project.id }.should change{ Issue.count }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'project with issues turned off' do
|
||||
pending 'should not be able to perform index action' do
|
||||
get :index, :project_id => @project_with_turned_off_issues.id
|
||||
response.should render_template(:index)
|
||||
end
|
||||
|
||||
it 'should not be able to perform show action' do
|
||||
get :show, :project_id => @project_with_turned_off_issues.id, :id => @turned_of_issue.serial_id
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
end
|
||||
|
||||
describe IssuesController do
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
|
||||
@project = Factory(:project)
|
||||
@issue_user = Factory(:user)
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
|
||||
@issue = Factory(:issue, :project_id => @project.id, :user_id => @issue_user.id)
|
||||
@create_params = {
|
||||
:project_id => @project.id,
|
||||
:issue => {
|
||||
:title => "issue1",
|
||||
:body => "issue body",
|
||||
:project_id => @project.id
|
||||
},
|
||||
:user_id => @issue_user.id,
|
||||
:user_uname => @issue_user.uname
|
||||
}
|
||||
@update_params = {
|
||||
:project_id => @project.id,
|
||||
:issue => {
|
||||
:title => "issue2"
|
||||
}
|
||||
}
|
||||
|
||||
@project_with_turned_off_issues = Factory(:project, :has_issues => false)
|
||||
@turned_of_issue = Factory(:issue, :project_id => @project_with_turned_off_issues.id, :user_id => @issue_user.id)
|
||||
end
|
||||
|
||||
context 'for global admin user' do
|
||||
before(:each) do
|
||||
@admin = Factory(:admin)
|
||||
set_session_for(@admin)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
end
|
||||
|
||||
context 'for project admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it_should_behave_like 'issue user with project reader rights'
|
||||
it_should_behave_like 'issue user with project writer rights'
|
||||
it_should_behave_like 'user with issue update rights'
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
it_should_behave_like 'project with issues turned off'
|
||||
end
|
||||
|
||||
context 'for project owner user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.update_attribute(:owner, @user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it_should_behave_like 'issue user with project reader rights'
|
||||
it_should_behave_like 'issue user with project writer rights'
|
||||
it_should_behave_like 'user with issue update rights'
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
it_should_behave_like 'project with issues turned off'
|
||||
end
|
||||
|
||||
context 'for project reader user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'reader')
|
||||
end
|
||||
|
||||
it_should_behave_like 'issue user with project reader rights'
|
||||
it_should_behave_like 'user without issue update rights'
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
it_should_behave_like 'project with issues turned off'
|
||||
|
||||
it 'should not be able to perform create action' do
|
||||
post :create, @create_params
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not create issue object into db' do
|
||||
lambda{ post :create, @create_params }.should change{ Issue.count }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for project writer user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'writer')
|
||||
end
|
||||
|
||||
it_should_behave_like 'issue user with project reader rights'
|
||||
it_should_behave_like 'issue user with project writer rights'
|
||||
it_should_behave_like 'user without issue update rights'
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
it_should_behave_like 'project with issues turned off'
|
||||
end
|
||||
|
||||
context 'for issue assign user' do
|
||||
before(:each) do
|
||||
set_session_for(@issue_user)
|
||||
end
|
||||
|
||||
it_should_behave_like 'user with issue update rights'
|
||||
it_should_behave_like 'user without issue destroy rights'
|
||||
it_should_behave_like 'project with issues turned off'
|
||||
end
|
||||
end
|
|
@ -61,8 +61,7 @@ describe ProductsController do
|
|||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
r = @product.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
r = @platform.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
@platform.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it 'should be able to perform create action' do
|
||||
|
|
|
@ -8,17 +8,6 @@ describe ProjectsController do
|
|||
@another_user = Factory(:user)
|
||||
@create_params = {:project => {:name => 'pro'}}
|
||||
@update_params = {:project => {:name => 'pro2'}}
|
||||
|
||||
platform = Factory(:platform)
|
||||
@process_build_params = {:build => {
|
||||
:arches => {Factory(:arch).id => '1'},
|
||||
:project_version => 'v1.0',
|
||||
:bpl => {platform.id => '1'},
|
||||
:pl => platform.id,
|
||||
:update_type => 'security'
|
||||
}}
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
end
|
||||
|
||||
context 'for guest' do
|
||||
|
@ -39,7 +28,7 @@ describe ProjectsController do
|
|||
set_session_for(@admin)
|
||||
end
|
||||
|
||||
it_should_behave_like 'projects user with writer rights'
|
||||
it_should_behave_like 'projects user with admin rights'
|
||||
it_should_behave_like 'projects user with reader rights'
|
||||
|
||||
it 'should be able to perform create action' do
|
||||
|
@ -60,7 +49,7 @@ describe ProjectsController do
|
|||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it_should_behave_like 'projects user with writer rights'
|
||||
it_should_behave_like 'projects user with admin rights'
|
||||
it_should_behave_like 'user with rights to view projects'
|
||||
|
||||
it 'should be able to perform destroy action' do
|
||||
|
@ -101,7 +90,6 @@ describe ProjectsController do
|
|||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'writer')
|
||||
end
|
||||
|
||||
it_should_behave_like 'projects user with writer rights'
|
||||
it_should_behave_like 'projects user with reader rights'
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
require 'spec_helper'
|
||||
|
||||
shared_examples_for 'can subscribe' do
|
||||
it 'should be able to perform create action' do
|
||||
post :create, @create_params
|
||||
response.should redirect_to(project_issue_path(@project, @issue))
|
||||
end
|
||||
|
||||
it 'should create subscribe object into db' do
|
||||
lambda{ post :create, @create_params }.should change{ Subscribe.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'can not subscribe' do
|
||||
it 'should not be able to perform create action' do
|
||||
post :create, @create_params
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not create subscribe object into db' do
|
||||
lambda{ post :create, @create_params }.should change{ Subscribe.count }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'can unsubscribe' do
|
||||
it 'should be able to perform destroy action' do
|
||||
delete :destroy, @destroy_params
|
||||
|
||||
response.should redirect_to([@project, @issue])
|
||||
end
|
||||
|
||||
it 'should reduce subscribes count' do
|
||||
lambda{ delete :destroy, @destroy_params }.should change{ Subscribe.count }.by(-1)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'can not unsubscribe' do
|
||||
it 'should not be able to perform destroy action' do
|
||||
delete :destroy, @destroy_params
|
||||
|
||||
response.should redirect_to(forbidden_path)
|
||||
end
|
||||
|
||||
it 'should not reduce subscribes count' do
|
||||
lambda{ delete :destroy, @destroy_params }.should change{ Subscribe.count }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe SubscribesController do
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
|
||||
@project = Factory(:project)
|
||||
@issue = Factory(:issue, :project_id => @project.id)
|
||||
|
||||
@create_params = {:issue_id => @issue.serial_id, :project_id => @project.id}
|
||||
@destroy_params = {:issue_id => @issue.serial_id, :project_id => @project.id}
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
|
||||
@request.env['HTTP_REFERER'] = project_issue_path(@project, @issue)
|
||||
end
|
||||
|
||||
context 'for global admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:admin)
|
||||
set_session_for(@user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
@destroy_params = @destroy_params.merge({:id => @user.id})
|
||||
end
|
||||
|
||||
context 'subscribed' do
|
||||
before(:each) do
|
||||
ss = @issue.subscribes.build(:user => @user)
|
||||
ss.save!
|
||||
end
|
||||
|
||||
it_should_behave_like 'can unsubscribe'
|
||||
it_should_behave_like 'can not subscribe'
|
||||
end
|
||||
|
||||
context 'not subscribed' do
|
||||
it_should_behave_like 'can subscribe'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for simple user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
set_session_for(@user)
|
||||
@destroy_params = @destroy_params.merge({:id => @user.id})
|
||||
end
|
||||
|
||||
context 'subscribed' do
|
||||
before(:each) do
|
||||
ss = @issue.subscribes.build(:user => @user)
|
||||
ss.save!
|
||||
end
|
||||
|
||||
it_should_behave_like 'can unsubscribe'
|
||||
it_should_behave_like 'can not subscribe'
|
||||
end
|
||||
|
||||
context 'not subscribed' do
|
||||
it_should_behave_like 'can subscribe'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,11 +1,13 @@
|
|||
Factory.define(:build_list) do |p|
|
||||
p.association :project, :factory => :project
|
||||
p.association :pl, :factory => :platform
|
||||
p.association :arch, :factory => :arch
|
||||
p.bpl { |bl| bl.pl }
|
||||
p.association :user
|
||||
p.association :project
|
||||
p.association :pl, :factory => :platform_with_repos
|
||||
p.association :arch
|
||||
p.bpl {|bl| bl.pl}
|
||||
p.project_version "1.0"
|
||||
p.build_requires true
|
||||
p.update_type 'security'
|
||||
p.include_repos {|bl| bl.pl.repositories.map(&:id)}
|
||||
end
|
||||
|
||||
Factory.define(:build_list_core, :parent => :build_list) do |p|
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Factory.define(:comment) do |p|
|
||||
p.body { Factory.next(:string) }
|
||||
p.association :user, :factory => :user
|
||||
p.association :commentable, :factory => :issue
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
Factory.define(:issue) do |p|
|
||||
p.title { Factory.next(:string) }
|
||||
p.body { Factory.next(:string) }
|
||||
p.association :project, :factory => :project
|
||||
p.association :user, :factory => :user
|
||||
p.status "open"
|
||||
end
|
|
@ -5,3 +5,7 @@ Factory.define(:platform) do |p|
|
|||
p.distrib_type APP_CONFIG['distr_types'].first
|
||||
p.association :owner, :factory => :user
|
||||
end
|
||||
|
||||
Factory.define(:platform_with_repos, :parent => :platform) do |p|
|
||||
p.repositories {|r| [r.association(:repository)]}
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
Factory.define(:subscribe) do |p|
|
||||
p.association :subscribeable, :factory => :issue
|
||||
p.association :user, :factory => :user
|
||||
end
|
|
@ -50,8 +50,8 @@ describe CanCan do
|
|||
guest_create
|
||||
end
|
||||
|
||||
it 'should be able to read open platform' do
|
||||
@ability.should be_able_to(:read, open_platform)
|
||||
it 'should not be able to read open platform' do
|
||||
@ability.should_not be_able_to(:read, open_platform)
|
||||
end
|
||||
|
||||
it 'should not be able to read hidden platform' do
|
||||
|
@ -62,7 +62,7 @@ describe CanCan do
|
|||
@ability.should be_able_to(:auto_build, Project)
|
||||
end
|
||||
|
||||
[:status_build, :pre_build, :post_build, :circle_build, :new_bbdt].each do |action|
|
||||
[:publish_build, :status_build, :pre_build, :post_build, :circle_build, :new_bbdt].each do |action|
|
||||
it "should be able to #{ action } build list" do
|
||||
@ability.should be_able_to(action, BuildList)
|
||||
end
|
||||
|
@ -78,12 +78,14 @@ describe CanCan do
|
|||
user_create
|
||||
end
|
||||
|
||||
[Platform, User, Repository].each do |model_name|
|
||||
it "should not be able to create #{ model_name.to_s }" do
|
||||
[Platform, Repository].each do |model_name|
|
||||
it "should not be able to read #{model_name}" do
|
||||
@ability.should be_able_to(:read, model_name)
|
||||
end
|
||||
end
|
||||
|
||||
it { @ability.should be_able_to(:show, User) }
|
||||
|
||||
it "shoud be able to read another user object" do
|
||||
admin_create
|
||||
@ability.should be_able_to(:read, @admin)
|
||||
|
@ -118,6 +120,7 @@ describe CanCan do
|
|||
context 'as project collaborator' do
|
||||
before(:each) do
|
||||
@project = Factory(:project)
|
||||
@issue = Factory(:issue, :project_id => @project.id)
|
||||
end
|
||||
|
||||
context 'with read rights' do
|
||||
|
@ -129,21 +132,32 @@ describe CanCan do
|
|||
@ability.should be_able_to(:read, @project)
|
||||
end
|
||||
|
||||
it 'should be able to read project' do
|
||||
it 'should be able to read open platform' do
|
||||
@ability.should be_able_to(:read, open_platform)
|
||||
end
|
||||
|
||||
it 'should be able to read issue' do
|
||||
@ability.should be_able_to(:read, @issue)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with write rights' do
|
||||
context 'with writer rights' do
|
||||
before(:each) do
|
||||
@project.relations.create!(:object_id => @user.id, :object_type => 'User', :role => 'writer')
|
||||
end
|
||||
|
||||
[:read, :update, :process_build, :build].each do |action|
|
||||
[:read, :create, :new].each do |action|
|
||||
it "should be able to #{ action } project" do
|
||||
@ability.should be_able_to(action, @project)
|
||||
end
|
||||
end
|
||||
|
||||
[:new, :create].each do |action|
|
||||
it "should be able to #{action} build_list" do
|
||||
@build_list = Factory(:build_list, :project => @project)
|
||||
@ability.should be_able_to(action, @build_list)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with admin rights' do
|
||||
|
@ -151,27 +165,54 @@ describe CanCan do
|
|||
@project.relations.create!(:object_id => @user.id, :object_type => 'User', :role => 'admin')
|
||||
end
|
||||
|
||||
[:read, :update, :process_build, :build].each do |action|
|
||||
[:read, :update].each do |action|
|
||||
it "should be able to #{ action } project" do
|
||||
@ability.should be_able_to(action, @project)
|
||||
end
|
||||
end
|
||||
|
||||
[:new, :create].each do |action|
|
||||
it "should be able to #{action} build_list" do
|
||||
@build_list = Factory(:build_list, :project => @project)
|
||||
@ability.should be_able_to(action, @build_list)
|
||||
end
|
||||
end
|
||||
|
||||
it "should be able to manage collaborators of project" do
|
||||
@ability.should be_able_to(:manage_collaborators, @project)
|
||||
end
|
||||
|
||||
[:read, :create, :new, :update, :edit].each do |action|
|
||||
it "should be able to #{ action } issue" do
|
||||
@ability.should be_able_to(action, @issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with owner rights' do
|
||||
before(:each) do
|
||||
@project.update_attribute(:owner, @user)
|
||||
@issue.project.reload
|
||||
end
|
||||
|
||||
[:read, :update, :process_build, :build, :destroy].each do |action|
|
||||
[:read, :update, :destroy].each do |action|
|
||||
it "should be able to #{ action } project" do
|
||||
@ability.should be_able_to(action, @project)
|
||||
end
|
||||
end
|
||||
|
||||
[:new, :create].each do |action|
|
||||
it "should be able to #{action} build_list" do
|
||||
@build_list = Factory(:build_list, :project => @project)
|
||||
@ability.should be_able_to(action, @build_list)
|
||||
end
|
||||
end
|
||||
|
||||
[:read, :update, :edit].each do |action|
|
||||
it "should be able to #{ action } issue" do
|
||||
@ability.should be_able_to(action, @issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -186,8 +227,10 @@ describe CanCan do
|
|||
@platform.update_attribute(:owner, @user)
|
||||
end
|
||||
|
||||
it 'should be able to manage platform' do
|
||||
@ability.should be_able_to(:manage, @platform)
|
||||
[:read, :update, :destroy, :freeze, :unfreeze].each do |action|
|
||||
it "should be able to #{action} platform" do
|
||||
@ability.should be_able_to(action, @platform)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -212,11 +255,16 @@ describe CanCan do
|
|||
@repository.update_attribute(:owner, @user)
|
||||
end
|
||||
|
||||
[:manage, :add_project, :remove_project, :change_visibility, :settings].each do |action|
|
||||
it "should be able to #{ action } repository" do
|
||||
[:read, :update, :destroy, :add_project, :remove_project, :change_visibility, :settings].each do |action|
|
||||
it "should be able to #{action} repository" do
|
||||
@ability.should be_able_to(action, @repository)
|
||||
end
|
||||
end
|
||||
|
||||
it do
|
||||
@repository.platform.update_attribute(:owner, @user)
|
||||
@ability.should be_able_to(:create, @repository)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with read rights' do
|
||||
|
@ -233,7 +281,7 @@ describe CanCan do
|
|||
context 'build list relations' do
|
||||
before(:each) do
|
||||
@project = Factory(:project)
|
||||
@project.relations.create!(:object_id => @user.id, :object_type => 'User', :role => 'reader')
|
||||
@project.relations.create!(:object_id => @user.id, :object_type => 'User', :role => 'writer')
|
||||
@build_list = Factory(:build_list, :project => @project)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
require 'spec_helper'
|
||||
require "cancan/matchers"
|
||||
|
||||
def set_testable_data
|
||||
@ability = Ability.new(@user)
|
||||
|
||||
@project = Factory(:project)
|
||||
@issue = Factory(:issue, :project_id => @project.id)
|
||||
|
||||
@comment = Factory(:comment, :commentable => @issue, :user => @user)
|
||||
@stranger_comment = Factory(:comment, :commentable => @issue, :user => @stranger)
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
end
|
||||
|
||||
describe Comment do
|
||||
context 'for global admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:admin)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
end
|
||||
|
||||
it 'should create comment' do
|
||||
@ability.should be_able_to(:create, Comment.new(:commentable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
it 'should update comment' do
|
||||
@ability.should be_able_to(:update, @comment)
|
||||
end
|
||||
|
||||
it 'should update stranger comment' do
|
||||
@ability.should be_able_to(:update, @stranger_comment)
|
||||
end
|
||||
|
||||
it 'should destroy own comment' do
|
||||
@ability.should be_able_to(:destroy, @comment)
|
||||
end
|
||||
|
||||
it 'should destroy stranger comment' do
|
||||
@ability.should be_able_to(:destroy, @stranger_comment)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for project admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it 'should create comment' do
|
||||
@ability.should be_able_to(:create, Comment.new(:commentable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
it 'should update comment' do
|
||||
@ability.should be_able_to(:update, @comment)
|
||||
end
|
||||
|
||||
it 'should update stranger comment' do
|
||||
@ability.should be_able_to(:update, @stranger_comment)
|
||||
end
|
||||
|
||||
it 'should not destroy comment' do
|
||||
@ability.should_not be_able_to(:destroy, @comment)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for project owner user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
|
||||
@project.update_attribute(:owner, @user)
|
||||
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin')
|
||||
end
|
||||
|
||||
it 'should create comment' do
|
||||
@ability.should be_able_to(:create, Comment.new(:commentable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
it 'should update comment' do
|
||||
@ability.should be_able_to(:update, @comment)
|
||||
end
|
||||
|
||||
it 'should update stranger comment' do
|
||||
@ability.should be_able_to(:update, @stranger_comment)
|
||||
end
|
||||
|
||||
it 'should not destroy comment' do
|
||||
@ability.should_not be_able_to(:destroy, @comment)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for simple user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
end
|
||||
|
||||
it 'should create comment' do
|
||||
@ability.should be_able_to(:create, Comment.new(:commentable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
it 'should update comment' do
|
||||
@ability.should be_able_to(:update, @comment)
|
||||
end
|
||||
|
||||
it 'should not update stranger comment' do
|
||||
@ability.should_not be_able_to(:update, @stranger_comment)
|
||||
end
|
||||
|
||||
it 'should not destroy comment' do
|
||||
@ability.should_not be_able_to(:destroy, @comment)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Issue do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
|
@ -1,5 +1,18 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ProjectToRepository do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
before(:each) do
|
||||
stub_rsync_methods
|
||||
@platform = Factory(:platform)
|
||||
@first_repo = Factory(:repository, :platform_id => @platform.id)
|
||||
@second_repo = Factory(:repository, :platform_id => @platform.id)
|
||||
@project = Factory(:project)
|
||||
@first_repo.projects << @project
|
||||
@first_repo.save
|
||||
end
|
||||
|
||||
it 'should not add the same project in different repositories of same platform' do
|
||||
p2r = @second_repo.project_to_repositories.build :project_id => @project.id
|
||||
p2r.should_not be_valid
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
require 'spec_helper'
|
||||
require "cancan/matchers"
|
||||
|
||||
def set_testable_data
|
||||
@ability = Ability.new(@user)
|
||||
|
||||
@project = Factory(:project)
|
||||
@issue = Factory(:issue, :project_id => @project.id)
|
||||
|
||||
any_instance_of(Project, :versions => ['v1.0', 'v2.0'])
|
||||
end
|
||||
|
||||
describe Subscribe do
|
||||
context 'for global admin user' do
|
||||
before(:each) do
|
||||
@user = Factory(:admin)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
end
|
||||
|
||||
it 'should create subscribe' do
|
||||
@ability.should be_able_to(:create, Subscribe.new(:subscribeable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
context 'destroy' do
|
||||
before(:each) do
|
||||
@subscribe = Factory(:subscribe, :subscribeable => @issue, :user => @user)
|
||||
@stranger_subscribe = Factory(:subscribe, :subscribeable => @issue, :user => @stranger)
|
||||
end
|
||||
|
||||
context 'own subscribe' do
|
||||
it 'should destroy subscribe' do
|
||||
@ability.should be_able_to(:destroy, @subscribe)
|
||||
end
|
||||
end
|
||||
|
||||
context 'stranger subscribe' do
|
||||
it 'should not destroy subscribe' do
|
||||
@ability.should_not be_able_to(:destroy, @stranger_subscribe)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'for simple user' do
|
||||
before(:each) do
|
||||
@user = Factory(:user)
|
||||
@stranger = Factory(:user)
|
||||
|
||||
set_testable_data
|
||||
end
|
||||
|
||||
it 'should create subscribe' do
|
||||
@ability.should be_able_to(:create, Subscribe.new(:subscribeable => @issue, :user => @user))
|
||||
end
|
||||
|
||||
context 'destroy' do
|
||||
before(:each) do
|
||||
@subscribe = Factory(:subscribe, :subscribeable => @issue, :user => @user)
|
||||
@stranger_subscribe = Factory(:subscribe, :subscribeable => @issue, :user => @stranger)
|
||||
end
|
||||
|
||||
context 'own subscribe' do
|
||||
it 'should destroy subscribe' do
|
||||
@ability.should be_able_to(:destroy, @subscribe)
|
||||
end
|
||||
end
|
||||
|
||||
context 'stranger subscribe' do
|
||||
it 'should not destroy subscribe' do
|
||||
@ability.should_not be_able_to(:destroy, @stranger_subscribe)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -37,9 +37,9 @@ def stub_rsync_methods
|
|||
any_instance_of(Platform, :umount_directory_for_rsync => true)
|
||||
end
|
||||
|
||||
Delayed::Worker.delay_jobs = false # Execute all jobs realtime
|
||||
|
||||
# Add testing root_path
|
||||
%x(rm -Rf #{Rails.root}/tmp/test_root)
|
||||
%x(mkdir -p #{Rails.root}/tmp/test_root)
|
||||
APP_CONFIG['root_path'] = "#{Rails.root}/tmp/test_root"
|
||||
|
||||
|
||||
|
|
|
@ -7,21 +7,11 @@ shared_examples_for 'projects user with reader rights' do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'projects user with writer rights' do
|
||||
shared_examples_for 'projects user with admin rights' do
|
||||
it 'should be able to perform update action' do
|
||||
put :update, {:id => @project.id}.merge(@update_params)
|
||||
response.should redirect_to(project_path(@project))
|
||||
end
|
||||
|
||||
it 'should be able to perform build action' do
|
||||
get :build, :id => @project.id
|
||||
response.should render_template(:build)
|
||||
end
|
||||
|
||||
it 'should be able to perform process_build action' do
|
||||
post :process_build, {:id => @project.id}.merge(@process_build_params)
|
||||
response.should redirect_to(project_path(@project))
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'user with rights to view projects' do
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2009 [name of plugin creator]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,138 @@
|
|||
## RailsDatatables
|
||||
|
||||
A simpler, Rails-friendly interface to using the [DataTables](http://datatables.net) jQuery library.
|
||||
|
||||
### Prerequisites
|
||||
Make sure you have jQuery.js and jQuery.dataTables.js in /public/javascripts/ and that they're included in your layout.
|
||||
|
||||
### Setup
|
||||
|
||||
Give table a class of 'datatable' so that the Javascript knows which table to alter. NOTE: If you want to use multiple tables on a single page, include the :table_dom_id in the options hash to specify the ID table to be altered.
|
||||
|
||||
Add thead around the table header (These elements will associate to the columns array created below, allowing sorting).
|
||||
|
||||
Add tbody around the table rows (These are the elements that will be sorted and paginated.)
|
||||
|
||||
Activate using <%= datatable() %>, passing in the columns, how to filter them (sorting type), and any other settings (ajax source, search?, label for search, processing image)
|
||||
|
||||
<% columns = [{:type => 'html', :class => "first"}, {:type => 'html'}, {:type => 'html'}, {:type => nil, :class => "last"}] %>
|
||||
<%= datatable(columns, {:sort_by => "[0, 'desc']", :processing => image_tag("spinner.gif") }) %>
|
||||
|
||||
<table id='users' class='datatable'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Account Level</th>
|
||||
<th>Email</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%- @users.each do |user| -%>
|
||||
<tr id="<%= dom_id(user) %>">
|
||||
<td><%= user.name %></td>
|
||||
<td><%= user.account.account_level.name %></td>
|
||||
<td><%= user.email %></td>
|
||||
<td><%= link_to "Edit", edit_system_user_path(user) %></td>
|
||||
</tr>
|
||||
<%- end -%>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Options
|
||||
|
||||
#### Table Options
|
||||
|
||||
:sort_by - array, default column number (0 - n-1) and sort order. e.g. "[2, 'desc']". Defaults to initial order.
|
||||
:search - boolean, display the search field. Defaults to true.
|
||||
:search_label - string, the label for the search field. Defaults to "Search".
|
||||
:processing - string, the text or image to display while processing data. Defaults to "Processing".
|
||||
:persist_state - boolean, remember the sorting and page of the tables for the user. Defaults to true.
|
||||
:additional_data - hash, pass along additional data, such as filter values. Default is none.
|
||||
:table_dom_id - string, the ID of the table to alter. If nothing is passed, it will look for a class of 'datatable'. Necessary if you want to have multiple DataTables on a single page.
|
||||
:per_page - the number of rows to show per page (renamed from display_length)
|
||||
:append - functions to all at the end of the dataTable() call. Useful for [Datatables plugins](http://www.datatables.net/plug-ins/api)
|
||||
:no_records_message - Message to display if no records are found, whether on load or after searching
|
||||
:auto_width - Automatically adjust the width of the columns. Defaults to true.
|
||||
:row_callback - a function to run on each row in the table. Inserted in to "'fnRowCallback': function( nRow, aData, iDisplayIndex ) { }". See [documentation for fnRowCallback](http://www.datatables.net/usage/callbacks) for more information.
|
||||
|
||||
#### Column Options
|
||||
|
||||
:class - string, the class to assign to the table cell. Default is none.
|
||||
:type - string, the type of content in the column, for non-Ajax tables. 'html' will strip all HTML and sort on the inner value, as a string. Default is string.
|
||||
:sortable - boolean, allow this column to be sorted on. Default is true.
|
||||
:searchable - boolean, allow this column to be searched, for non-Ajax tables. Default is true.
|
||||
|
||||
#### AJAX Options
|
||||
|
||||
When you're working with large datasets it's not reasonable to load everything on page load. Use an :ajax_source to load just the records that are being displayed, do custom searching (DB, Solr, etc).
|
||||
|
||||
:ajax_source - string, for large datasets, use an ajax source to load each page on its own. For smaller datasets, just load the whole set and let datatable do the sorting
|
||||
|
||||
Add a datatable method on your controller to return JSON
|
||||
* Return the objects to be displayed
|
||||
* Return the total number of objects
|
||||
* Add a method to handle sorting - DataTables returns the column that is being sorted (0 - n), so you need to know which column is which and sort on it.
|
||||
|
||||
### AJAX Example
|
||||
|
||||
#### Datatable view example - datatable.html.erb
|
||||
|
||||
{"sEcho": <%= params[:sEcho] || -1 %>,
|
||||
"iTotalRecords": <%= @total_objects %>,
|
||||
"iTotalDisplayRecords": <%= @total_object %>,
|
||||
"aaData":[
|
||||
<% @objects.each do |object| %>
|
||||
['<%= link_to(object.user.name, user) %>',
|
||||
'<%= object.description || "-" %>',
|
||||
'<%= object.created_at %>'
|
||||
],
|
||||
<% end %>
|
||||
]}
|
||||
|
||||
#### Controller example - using will_paginate
|
||||
|
||||
def datatable
|
||||
@objects = current_objects(params)
|
||||
@total_objectss = total_objects(params)
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_objects(params={})
|
||||
current_page = (params[:iDisplayStart].to_i/params[:iDisplayLength].to_i rescue 0)+1
|
||||
@current_objects = Object.paginate :page => current_page,
|
||||
:include => [:user],
|
||||
:order => "#{datatable_columns(params[:iSortCol_0])} #{params[:sSortDir_0] || "DESC"}",
|
||||
:conditions => conditions,
|
||||
:per_page => params[:iDisplayLength]
|
||||
end
|
||||
|
||||
def total_objects(params={})
|
||||
@total_objects = Object.count :include => [:user], :conditions => conditions
|
||||
end
|
||||
|
||||
def datatable_columns(column_id)
|
||||
case column_id.to_i
|
||||
when 1
|
||||
return "objects.description"
|
||||
when 2
|
||||
return "objects.created_at"
|
||||
else
|
||||
return "users.name"
|
||||
end
|
||||
end
|
||||
|
||||
def conditions
|
||||
conditions = []
|
||||
conditions << "(objects.description ILIKE '%#{params[:sSearch]}%' OR users.name ILIKE '%#{params[:sSearch]}%')" if(params[:sSearch])
|
||||
return conditions.join(" AND ")
|
||||
end
|
||||
|
||||
### Note
|
||||
There is a more functionality offered by DataTables than this plugin currently provides. We add to it as we find need for other features. If there's a feature of DataTables that you'd like to see, fork this repo and add it so we can all benefit.
|
||||
|
||||
### Credits
|
||||
|
||||
Copyright (c) 2009 [Phronos](http://phronos.com), released under the MIT license
|