Merge remote-tracking branch 'origin/szzh' into szzh

This commit is contained in:
lizanle 2015-03-20 11:08:47 +08:00
commit cdad43fdfc
192 changed files with 524 additions and 10808 deletions

1
.gitignore vendored
View File

@ -22,3 +22,4 @@
.DS_Store .DS_Store
public/api_doc/ public/api_doc/
/.metadata /.metadata
vendor/cache

20
Gemfile
View File

@ -1,5 +1,4 @@
source 'http://rubygems.org' source 'http://ruby.taobao.org'
#source 'http://ruby.taobao.com'
#source 'http://ruby.sdutlinux.org/' #source 'http://ruby.sdutlinux.org/'
unless RUBY_PLATFORM =~ /w32/ unless RUBY_PLATFORM =~ /w32/
@ -11,11 +10,11 @@ end
gem 'grape', '~> 0.9.0' gem 'grape', '~> 0.9.0'
gem 'grape-entity' gem 'grape-entity'
gem 'seems_rateable', path: 'lib/seems_rateable' gem 'seems_rateable', '~> 1.0.13'
gem "rails", "3.2.13" gem "rails", "3.2.13"
gem "jquery-rails", "~> 2.0.2" gem "jquery-rails", "~> 2.0.2"
gem "i18n", "~> 0.6.0" gem "i18n", "~> 0.6.0"
gem "coderay", "~> 1.0.6" gem 'coderay', '~> 1.1.0'
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby] gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
gem "builder", "3.0.0" gem "builder", "3.0.0"
gem 'acts-as-taggable-on', '2.4.1' gem 'acts-as-taggable-on', '2.4.1'
@ -28,11 +27,16 @@ gem 'rails_kindeditor'
group :development do group :development do
gem 'grape-swagger' gem 'grape-swagger'
#gem 'grape-swagger-ui', git: 'https://github.com/guange2015/grape-swagger-ui.git' #gem 'grape-swagger-ui', git: 'https://github.com/guange2015/grape-swagger-ui.git'
#gem 'puma' gem 'puma' if RbConfig::CONFIG['host_os'] =~ /linux/
gem 'pry-rails' gem 'pry-rails'
gem 'pry-byebug' if RUBY_VERSION >= '2.0.0'
gem 'better_errors', path: 'lib/better_errors' gem 'pry-byebug'
gem 'rack-mini-profiler', path: 'lib/rack-mini-profiler' else
gem 'pry-debugger'
end
gem 'pry-stack_explorer'
gem 'better_errors', '~> 1.1.0'
gem 'rack-mini-profiler', '~> 0.9.3'
end end
group :test do group :test do

View File

@ -2,6 +2,7 @@
module Mobile module Mobile
module Apis module Apis
class Comments < Grape::API class Comments < Grape::API
include ApplicationHelper
resource :comments do resource :comments do
desc '课程通知评论' desc '课程通知评论'
params do params do
@ -82,8 +83,8 @@ module Mobile
memo: {:subject => params[:subject],:content => '该贴来自手机App意见反馈'}, memo: {:subject => params[:subject],:content => '该贴来自手机App意见反馈'},
} }
cs = CommentService.new cs = CommentService.new
memo = cs.create_feedback cs_params, current_user memo,message = cs.create_feedback cs_params, current_user
raise "commit failed #{memo.errors.full_messages}" if memo.new_record? raise message if memo.new_record?
present :status, 0 present :status, 0
end end

View File

@ -873,13 +873,15 @@ class CoursesController < ApplicationController
"show_course_news" => true, "show_course_news" => true,
"show_course_messages" => true, "show_course_messages" => true,
"show_bids" => true, "show_bids" => true,
"show_course_journals_for_messages" => true "show_course_journals_for_messages" => true,
"show_homeworks" => true
} }
@date_to ||= Date.today + 1 @date_to ||= Date.today + 1
# #
@date_from = (@date_to - @days) > @course.created_at.to_date ? (@date_to - @days) : @course.created_at.to_date @date_from = (@date_to - @days) > @course.created_at.to_date ? (@date_to - @days) : @course.created_at.to_date
#@date_from = @date_to - @days-1.years #@date_from = @date_to - @days-1.years
@author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
@author ||= @course.teacher
# 决定显示所用用户或单个用户活动 # 决定显示所用用户或单个用户活动
@activity = Redmine::Activity::Fetcher.new(User.current, :course => @course, @activity = Redmine::Activity::Fetcher.new(User.current, :course => @course,
:with_subprojects => false, :with_subprojects => false,

View File

@ -20,7 +20,7 @@ class ForumsController < ApplicationController
#@memo.author_id = User.current.id #@memo.author_id = User.current.id
#@forum = @memo.forum #@forum = @memo.forum
cs = CommentService.new cs = CommentService.new
@memo = cs.create_feedback params,User.current @memo,message = cs.create_feedback params,User.current
respond_to do |format| respond_to do |format|
if !@memo.new_record? if !@memo.new_record?
format.html { redirect_to forum_path(@memo.forum) } format.html { redirect_to forum_path(@memo.forum) }

View File

@ -0,0 +1,9 @@
class GitCallbackController < ApplicationController
def post_update
@repository = Repository.find_by_root_url(params[:root_url])
@repository.fetch_changesets
render :text => 'success'
end
end

View File

@ -58,7 +58,7 @@ class IssuesController < ApplicationController
def index def index
retrieve_query retrieve_query
sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) sort_init(@query.sort_criteria.empty? ? [['updated_on', 'desc']] : @query.sort_criteria)
sort_update(@query.sortable_columns) sort_update(@query.sortable_columns)
@query.sort_criteria = sort_criteria.to_a @query.sort_criteria = sort_criteria.to_a
@ -381,7 +381,7 @@ class IssuesController < ApplicationController
def retrieve_previous_and_next_issue_ids def retrieve_previous_and_next_issue_ids
retrieve_query_from_session retrieve_query_from_session
if @query if @query
sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) sort_init(@query.sort_criteria.empty? ? [['updated_on', 'desc']] : @query.sort_criteria)
sort_update(@query.sortable_columns, 'issues_index_sort') sort_update(@query.sortable_columns, 'issues_index_sort')
limit = 500 limit = 500
issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version]) issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version])

View File

@ -109,7 +109,7 @@ class MembersController < ApplicationController
end end
if params[:flag] if params[:flag]
unless members.present? && members.all? {|m| m.valid? } unless members.present? && members.all? {|m| m.valid? }
flash[:error] = members.collect {|m| m.errors.full_messages}.flatten.uniq.join(', ') flash[:error] = members.empty? ? l(:label_user_role_null) :members.collect {|m| m.errors.full_messages}.flatten.uniq.join(', ')
else else
flash[:notice] = l(:label_invite_success) flash[:notice] = l(:label_invite_success)
end end

View File

@ -340,6 +340,7 @@ class ProjectsController < ApplicationController
@is_zhuce =false @is_zhuce =false
flash[:notice] = l(:notice_email_sent, :value => email) flash[:notice] = l(:notice_email_sent, :value => email)
else else
flash[:error] = l(:notice_registed_success, :value => email)
@is_zhuce = true @is_zhuce = true
end end
respond_to do |format| respond_to do |format|

View File

@ -92,6 +92,22 @@ class RepositoriesController < ApplicationController
render :action => 'show', :layout => 'base_projects' render :action => 'show', :layout => 'base_projects'
end end
HOOK_TEMPLATE = %Q{#!/bin/sh
exec sh -c '
function update()
{
CMD_PATH=`dirname $0`;
cd $CMD_PATH;
PY_PATH=$PWD/../../git_refresh_changes.py;
[[ -s "$PY_PATH" ]] && $(which python) $PY_PATH $PWD;
cd -;
}
git update-server-info
update
'
}
def create def create
if params[:repository_scm].to_s == 'Gitlab' if params[:repository_scm].to_s == 'Gitlab'
# add by nwb # add by nwb
@ -127,7 +143,6 @@ class RepositoriesController < ApplicationController
if attrs[:attrs_extra].keys.any? if attrs[:attrs_extra].keys.any?
@repository.merge_extra_info(attrs[:attrs_extra]) @repository.merge_extra_info(attrs[:attrs_extra])
end end
#by xianbo
@repository.project = @project @repository.project = @project
if request.post? && @repository.save if request.post? && @repository.save
@ -145,12 +160,11 @@ class RepositoriesController < ApplicationController
"</Limit> \n ' >> "+ "</Limit> \n ' >> "+
@root_path+"htdocs/"+ @repository_name+"/.htaccess" @root_path+"htdocs/"+ @repository_name+"/.htaccess"
system "cd "+@project_path+" ;git update-server-info" system "cd "+@project_path+" ;git update-server-info"
# if(create_repo_file&&create_passwd&&create_group&&init_repository&&add_privilege&&init_server_info)
# else File.open(@project_path+"/hooks/post-update", "w+") do |f|
# logger.info "An error occured when authenticating "+"create passwd"+@creat_passwd+"create_group"+ f.write(HOOK_TEMPLATE)
# crate_group+"create repository file "+create_repo_file+"init repository"+init_repostory+ end
# "aad privilege to rpository"+add_privilege+"init server infos"+init_server_info
# end
@repository.update_attributes(:login => User.current.login.to_s) @repository.update_attributes(:login => User.current.login.to_s)
end end
redirect_to settings_project_url(@project, :tab => 'repositories') redirect_to settings_project_url(@project, :tab => 'repositories')
@ -160,6 +174,8 @@ class RepositoriesController < ApplicationController
render :action => 'new', :layout =>'base_projects' render :action => 'new', :layout =>'base_projects'
end end
end end
end end
end end

View File

@ -445,15 +445,15 @@ class UsersController < ApplicationController
else else
activity = Activity.where(where_condition).where('user_id = ?', @user.id).order('id desc') activity = Activity.where(where_condition).where('user_id = ?', @user.id).order('id desc')
end end
activity = activity.reject { |e| # activity = activity.reject { |e|
e.act.nil? || # e.act.nil? ||
(!User.current.admin? && !e.act.nil? # (!User.current.admin? && !e.act.nil?
(((e.act_type == "Issue") && !e.act.project.visible?(User.current)) || # (((e.act_type == "Issue") && !e.act.project.visible?(User.current)) ||
(e.act_type == "Bid" && !e.act.courses.first.nil? && e.act.courses.first.is_public == 0 && !User.current.member_of_course?(e.act.courses.first)) || # (e.act_type == "Bid" && !e.act.courses.first.nil? && e.act.courses.first.is_public == 0 && !User.current.member_of_course?(e.act.courses.first)) ||
(e.act_type == "Journal" && e.act.respond_to?("Project") && !e.act.project.visible?(User.current)) || # (e.act_type == "Journal" && e.act.respond_to?("Project") && !e.act.project.visible?(User.current)) ||
(e.act_type == "News" && ((!e.act.project.nil? && !e.act.project.visible?(User.current)) || (!e.act.course.nil? && e.act.course.is_public == 0 && !User.current.member_of_course?(e.act.course)))) || # (e.act_type == "News" && ((!e.act.project.nil? && !e.act.project.visible?(User.current)) || (!e.act.course.nil? && e.act.course.is_public == 0 && !User.current.member_of_course?(e.act.course)))) ||
(e.act_type == "Message" && !e.act.board.nil? && ((!e.act.board.project.nil? && !e.act.board.project.visible?(User.current)) || (!e.act.board.course.nil? && e.act.board.course.is_public == 0 && !User.current.member_of_course?(e.act.board.course)))))) # (e.act_type == "Message" && !e.act.board.nil? && ((!e.act.board.project.nil? && !e.act.board.project.visible?(User.current)) || (!e.act.board.course.nil? && e.act.board.course.is_public == 0 && !User.current.member_of_course?(e.act.board.course))))))
} # }
@activity_count = activity.count @activity_count = activity.count
@activity_pages = Paginator.new @activity_count, pre_count, params['page'] @activity_pages = Paginator.new @activity_count, pre_count, params['page']
@activity = activity.slice(@activity_pages.offset,@activity_pages.per_page) @activity = activity.slice(@activity_pages.offset,@activity_pages.per_page)

View File

@ -60,4 +60,8 @@ module ApiHelper
end end
[count,is_teacher] [count,is_teacher]
end end
def get_user_language user
(user.language.nil? || user.language == "") ? 'zh':user.language
end
end end

View File

@ -1994,4 +1994,10 @@ module ApplicationHelper
end end
technical_title technical_title
end end
def ie8?
request.env["HTTP_USER_AGENT"] =~ /MSIE 8.0/
end
end end

View File

@ -43,7 +43,7 @@ module WatchersHelper
) )
method = watched ? 'delete' : 'post' method = watched ? 'delete' : 'post'
link_to text, url, :remote => true, :method => method, :style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 22px; line-height: 22px; background: none repeat scroll 0% 0% #64BDD9; TES" link_to text, url, :remote => true, :method => method, :style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 22px; line-height: 21px;padding-top:1px; background: none repeat scroll 0% 0% #64BDD9; TES"
end end
############## added by linchun ############## added by linchun
@ -278,11 +278,11 @@ module WatchersHelper
) )
method = applied ? 'delete' : 'post' method = applied ? 'delete' : 'post'
link_to text, url, :remote => true, :method => method ,:style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 22px; line-height: 22px; background: none repeat scroll 0% 0% #64BDD9; TES" link_to text, url, :remote => true, :method => method ,:style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 21px; line-height: 22px;padding-top:1px; background: none repeat scroll 0% 0% #64BDD9; TES"
end end
def exit_project_link(project) def exit_project_link(project)
link_to(l(:label_exit_project),exit_cur_project_path(project.id), link_to(l(:label_exit_project),exit_cur_project_path(project.id),
:remote => true, :confirm => l(:lable_sure_exit_project), :style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 22px; line-height: 22px; background: none repeat scroll 0% 0% #64BDD9; TES" ) :remote => true, :confirm => l(:lable_sure_exit_project), :style => "color: #fff; display:block; padding: 0px 5px; margin-right: 10px; height: 21px; line-height: 22px; background: none repeat scroll 0% 0% #64BDD9; TES;padding-top:1px;" )
end end
end end

View File

@ -61,14 +61,21 @@ class Bid < ActiveRecord::Base
end end
} }
scope :course_visible, lambda {|*args|
includes(:courses).where(Course.allowed_to_condition(args.shift || User.current, :view_homeworks, *args))
}
acts_as_watchable acts_as_watchable
acts_as_taggable acts_as_taggable
acts_as_event :title => Proc.new {|o| "#{l(:label_requirement)} ##{o.id}: #{o.name}" }, acts_as_event :title => Proc.new {|o| "#{l(:label_course_homework)} ##{o.id}: #{o.name}" },
:description => :description, :description => :description,
:author => :author, :author => :author,
:url => Proc.new {|o| {:controller => 'bids', :action => 'show', :id => o.id}} :url => Proc.new {|o| {:controller => 'bids', :action => 'show', :id => o.id}}
acts_as_activity_provider :type => 'homeworks',
:author_key => :author_id
acts_as_activity_provider :find_options => {:include => [:projects, :author]}, acts_as_activity_provider :find_options => {:include => [:projects, :author]},
:author_key => :author_id :author_key => :author_id

View File

@ -778,7 +778,7 @@ class User < Principal
(block_given? ? yield(role, self) : true) (block_given? ? yield(role, self) : true)
} }
#添加课程相关的权限判断 #添加课程相关的权限判断
elsif context && context.is_a?(Course) elsif context && context.is_a?(Course)
return false unless context.allows_to?(action) return false unless context.allows_to?(action)
# Admin users are authorized for anything else # Admin users are authorized for anything else
return true if admin? return true if admin?

View File

@ -32,40 +32,42 @@ class UserExtensions < ActiveRecord::Base
def get_brief_introduction def get_brief_introduction
return self.brief_introduction return self.brief_introduction
end end
# added by meng # added by meng
def show_identity def show_identity
if self.identity == 0 if User.current.language == 'zh'||User.current.language == ''
if User.current.language == 'zh' case self.identity
user_identity = '教师' when 0
else user_identity = l(:label_account_identity_teacher)
user_identity = 'Teacher' when 1
end user_identity = l(:label_account_identity_student)
elsif self.identity == 1 when 2
if User.current.language == 'zh' user_identity = l(:label_account_identity_enterprise)
user_identity = '学生' when 3
else user_identity = l(:label_account_identity_developer)
user_identity = 'Student' else
end user_identity = ''
elsif self.identity == 2
if User.current.language == 'zh'
user_identity = '企业'
else
user_identity = 'Enterprise'
end
elsif self.identity == 3
if User.current.language == 'zh'
user_identity = '开发者'
else
user_identity = 'Developer'
end end
else else
user_identity = '' case self.identity
when 0
user_identity = l(:label_account_identity_teacher)
when 1
user_identity = l(:label_account_identity_student)
when 2
user_identity = l(:label_account_identity_enterprise)
when 3
user_identity = l(:label_account_identity_developer)
else
user_identity = ''
end
end end
return user_identity return user_identity
end end
# end # end
def self.introduction(user, message) def self.introduction(user, message)
unless user.user_extensions.nil? unless user.user_extensions.nil?
info = user.user_extensions info = user.user_extensions

View File

@ -1,4 +1,6 @@
class CommentService class CommentService
include ApiHelper
include Redmine::I18n
#评论 #评论
def news_comments params,current_user def news_comments params,current_user
@news = News.find(params[:id]) @news = News.find(params[:id])
@ -84,7 +86,8 @@ class CommentService
@memo.forum_id = "1" @memo.forum_id = "1"
@memo.author_id = current_user.id @memo.author_id = current_user.id
@memo.save @memo.save
@memo message = "#{l(:label_commit_failed,:locale => get_user_language(current_user))}: #{@memo.errors.full_messages}" if @memo.new_record?
[@memo,message]
end end
#课程留言列表 #课程留言列表

View File

@ -346,7 +346,7 @@ class CoursesService
membership = @user.coursememberships.all(:conditions => Course.visible_condition(current_user)) membership = @user.coursememberships.all(:conditions => Course.visible_condition(current_user))
end end
if membership.nil? || membership.count == 0 if membership.nil? || membership.count == 0
raise l(:label_no_courses,:locale => current_user.language.nil? ? 'zh':current_user.language) raise l(:label_no_courses,:locale => get_user_language(current_user))
end end
membership.sort! {|older, newer| newer.created_on <=> older.created_on } membership.sort! {|older, newer| newer.created_on <=> older.created_on }
result = [] result = []
@ -355,19 +355,19 @@ class CoursesService
latest_course_dynamics = [] latest_course_dynamics = []
latest_news = course.news.order("created_on desc").first latest_news = course.news.order("created_on desc").first
unless latest_news.nil? unless latest_news.nil?
latest_course_dynamics << {:type => 1,:time => latest_news.created_on,:message => l(:label_recently_updated_notification,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 1,:time => latest_news.created_on,:message => l(:label_recently_updated_notification,:locale => get_user_language(current_user))}
end end
latest_message = course.journals_for_messages.order("created_on desc").first latest_message = course.journals_for_messages.order("created_on desc").first
unless latest_message.nil? unless latest_message.nil?
latest_course_dynamics << {:type => 2,:time => latest_message.created_on,:message => l(:label_recently_updated_message,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 2,:time => latest_message.created_on,:message => l(:label_recently_updated_message,:locale => get_user_language(current_user))}
end end
latest_attachment = course.attachments.order("created_on desc").first latest_attachment = course.attachments.order("created_on desc").first
unless latest_attachment.nil? unless latest_attachment.nil?
latest_course_dynamics << {:type => 3,:time => latest_attachment.created_on,:message => l(:label_recently_updated_courseware,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 3,:time => latest_attachment.created_on,:message => l(:label_recently_updated_courseware,:locale => get_user_language(current_user))}
end end
latest_bid = course.homeworks.order('updated_on DESC').first latest_bid = course.homeworks.order('updated_on DESC').first
unless latest_bid.nil? unless latest_bid.nil?
latest_course_dynamics << {:type => 4,:time => latest_bid.updated_on,:message => l(:label_recently_updated_homework,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 4,:time => latest_bid.updated_on,:message => l(:label_recently_updated_homework,:locale => get_user_language(current_user))}
end end
#每个作业中的最新留言 #每个作业中的最新留言
messages = [] messages = []
@ -382,7 +382,7 @@ class CoursesService
end end
latest_bid_message = messages.first latest_bid_message = messages.first
unless latest_bid_message.nil? unless latest_bid_message.nil?
latest_course_dynamics << {:type => 4,:time => latest_bid_message.created_on,:message => l(:label_recently_updated_message,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 4,:time => latest_bid_message.created_on,:message => l(:label_recently_updated_message,:locale => get_user_language(current_user))}
end end
#每个作业中学生最后提交的作业 #每个作业中学生最后提交的作业
homeworks = [] homeworks = []
@ -397,7 +397,7 @@ class CoursesService
end end
latest_homework_attach = homeworks.first latest_homework_attach = homeworks.first
unless latest_homework_attach.nil? unless latest_homework_attach.nil?
latest_course_dynamics << {:type => 4,:time => latest_homework_attach.updated_at,:message => l(:label_recently_updated_homework,:locale => current_user.language.nil? ? 'zh':current_user.language)} latest_course_dynamics << {:type => 4,:time => latest_homework_attach.updated_at,:message => l(:label_recently_updated_homework,:locale => get_user_language(current_user))}
end end
latest_course_dynamics.sort!{|order,newer| newer[:time] <=> order[:time]} latest_course_dynamics.sort!{|order,newer| newer[:time] <=> order[:time]}
latest_course_dynamic = latest_course_dynamics.first latest_course_dynamic = latest_course_dynamics.first

View File

@ -1,6 +1,6 @@
<span id="attachments_fields" xmlns="http://www.w3.org/1999/html"> <span id="attachments_fields" xmlns="http://www.w3.org/1999/html">
<% if defined?(container) && container && container.saved_attachments %> <% if defined?(container) && container && container.saved_attachments %>
<% container.attachments.each_with_index do |attachment, i| %> <% container.saved_attachments.each_with_index do |attachment, i| %>
<span id="attachments_p<%= i %>" class="attachment"> <span id="attachments_p<%= i %>" class="attachment">
<%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename readonly', :readonly=>'readonly')%> <%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename readonly', :readonly=>'readonly')%>
<%= text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 254, :placeholder => l(:label_optional_description), :class => 'description', :style=>"display: inline-block;") %> <%= text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 254, :placeholder => l(:label_optional_description), :class => 'description', :style=>"display: inline-block;") %>
@ -34,7 +34,6 @@
<%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %> <%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %>
</span> </span>
<% end %> <% end %>
<% end %> <% end %>
</span> </span>
<script type='text/javascript'> <script type='text/javascript'>
@ -49,13 +48,13 @@
<span class="add_attachment" style="font-weight:normal;"> <span class="add_attachment" style="font-weight:normal;">
<%#= button_tag "浏览", :type=>"button", :onclick=>"CompatibleSend();" %> <%#= button_tag "浏览", :type=>"button", :onclick=>"CompatibleSend();" %>
<!--%= link_to image_tag(),"javascript:void(0)", :onclick => "_file.click()"%--> <!--%= link_to image_tag(),"javascript:void(0)", :onclick => "_file.click()"%-->
<%= button_tag "浏览", :type=>"button", :onclick=>"_file.click()",:onmouseover => 'this.focus()' %> <%= button_tag l(:button_browse), :type=>"button", :onclick=>"_file.click()",:onmouseover => 'this.focus()', :style => ie8? ? 'display:none' : '' %>
<%= file_field_tag 'attachments[dummy][file]', <%= file_field_tag 'attachments[dummy][file]',
:id => '_file', :id => '_file',
:class => 'file_selector', :class => 'file_selector',
:multiple => true, :multiple => true,
:onchange => 'addInputFiles(this);', :onchange => 'addInputFiles(this);',
:style => 'display:none', :style => ie8? ? '' : 'display:none',
:data => { :data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes, :max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), :max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),

View File

@ -38,7 +38,7 @@
<span class="add_attachment"> <span class="add_attachment">
<%#= button_tag "浏览", :type=>"button", :onclick=>"CompatibleSend();" %> <%#= button_tag "浏览", :type=>"button", :onclick=>"CompatibleSend();" %>
<!--%= link_to image_tag(),"javascript:void(0)", :onclick => "_file.click()"%--> <!--%= link_to image_tag(),"javascript:void(0)", :onclick => "_file.click()"%-->
<%= button_tag "浏览", :type=>"button", :onclick=>"_file.click()" %> <%= button_tag l(:button_browse), :type=>"button", :onclick=>"_file.click()" %>
<%= file_field_tag 'attachments[dummy][file]', <%= file_field_tag 'attachments[dummy][file]',
:id => '_file', :id => '_file',
:class => 'file_selector', :class => 'file_selector',

View File

@ -1,7 +1,7 @@
$('#attachments_<%= j params[:attachment_id] %>').remove(); $('#attachments_<%= j params[:attachment_id] %>').remove();
var count=$('#attachments_fields>span').length; var count=$('#attachments_fields>span').length;
if(count<=0){ if(count<=0){
$("#upload_file_count").text("未上传文件"); $("#upload_file_count").text(<%= l(:label_no_file_uploaded)%>);
$(".remove_all").remove(); $(".remove_all").remove();
}else{ }else{
$("#upload_file_count").html("已上传"+"<span id=\"count\">"+count+"</span>"+"个文件"); $("#upload_file_count").html("已上传"+"<span id=\"count\">"+count+"</span>"+"个文件");

View File

@ -22,13 +22,13 @@
</span> </span>
</div> </div>
<button name="button" class="f_l ml10" onclick="_file.click()" onmouseover="this.focus()" type="button" style="width:20%; height:26%;"><%= l(:label_browse)%></button> <button name="button" class="f_l ml10" onclick="_file.click()" onmouseover="this.focus()" type="button" style="<%= ie8? ? 'display:none' : '' %>; width:20%; height:26%;"><%= l(:label_browse)%></button>
<%= file_field_tag 'attachments[dummy][file]', <%= file_field_tag 'attachments[dummy][file]',
:id => '_file', :id => '_file',
:class => 'file_selector', :class => 'file_selector',
:multiple => true, :multiple => true,
:onchange => 'addInputFiles(this);', :onchange => 'addInputFiles(this);',
:style => 'display:none', :style => ie8? ? '': 'display:none',
:data => { :data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes, :max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), :max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),

View File

@ -8,10 +8,10 @@
<table> <table>
<tr> <tr>
<% if versions.any? %> <% if versions.any? %>
<td><p><%= l(:field_version) %></p></td> <td><p style="padding-left: 50px;"><%= l(:field_version) %></p></td>
<td> <td>
<%= select_tag "version_id", content_tag('option', '') + <%= select_tag "version_id", content_tag('option', '') +
options_from_collection_for_select(versions, "id", "name"), {style: 'width:100px'} %> options_from_collection_for_select(versions, "id", "name"), {style: 'width:230px'} %>
</td> </td>
<% if attachmenttypes.any? %> <% if attachmenttypes.any? %>
<td><%= l(:attachment_type) %></label></td> <td><%= l(:attachment_type) %></label></td>
@ -31,14 +31,10 @@
<% end %> <% end %>
</p> </p>
<% end %> <% end %>
</tr> </tr>
</table> </table>
<p style="padding-left: 54px;"> <%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form', locals: {project: project} %></p>
</p> </p>
<p><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form', locals: {project: project} %></p>
</div> </div>
<%= submit_tag l(:button_add) %> <%= submit_tag l(:button_add) %>
<% end %> <% end %>

View File

@ -4,7 +4,8 @@
<div class="upload_box"> <div class="upload_box">
<%= error_messages_for 'attachment' %> <%= error_messages_for 'attachment' %>
<div id="network_issue" style="color: red; display: none;"><%= l(:label_file_upload_error_messages)%></div> <div id="network_issue" style="color: red; display: none;"><%= l(:label_file_upload_error_messages)%></div>
<%= form_tag(course_files_path(course), :multipart => true,:remote => true,:method => :post,:name=>"upload_form") do %>
<%= form_tag(course_files_path(course), :multipart => true,:remote => !ie8?,:name=>"upload_form") do %>
<!-- <label style="margin-top:3px;"><#%= l(:label_file_upload)%></label> --> <!-- <label style="margin-top:3px;"><#%= l(:label_file_upload)%></label> -->
<%= render :partial => 'attachement_list',:locals => {:course => course} %> <%= render :partial => 'attachement_list',:locals => {:course => course} %>
<div class="cl"></div> <div class="cl"></div>

View File

@ -12,7 +12,7 @@
<% end %> <% end %>
<%= watcher_link(@issue, User.current) %>
<%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:add_issues, @project) %> <%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:add_issues, @project) %>
<%= link_to l(:button_delete), issue_path(@issue.id), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %> <%= link_to l(:button_delete), issue_path(@issue.id), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
</div> </div>

View File

@ -1,181 +1,181 @@
<div class="project_r_h"> <div class="project_r_h">
<h2 class="project_h2"><%= l(:label_issue_plural) %></h2> <h2 class="project_h2"><%= l(:label_issue_plural) %></h2>
</div> </div>
<%# html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> <%# html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
<% html_title "#{@issue.tracker.name} #{@issue.source_from}'#'#{@issue.project_index}: #{@issue.subject}" %> <% html_title "#{@issue.tracker.name} #{@issue.source_from}'#'#{@issue.project_index}: #{@issue.subject}" %>
<%= render :partial => 'action_menu' %> <%= render :partial => 'action_menu' %>
<h3> <h3>
<%= issue_heading(@issue) %> <%= issue_heading(@issue) %>
</h3> </h3>
<style type="text/css"></style> <style type="text/css"></style>
<div class="<%= @issue.css_classes %> details"> <div class="<%= @issue.css_classes %> details">
<% if @prev_issue_id || @next_issue_id %> <% if @prev_issue_id || @next_issue_id %>
<div class="next-prev-links contextual"> <div class="next-prev-links contextual">
<%= link_to_if @prev_issue_id, <%= link_to_if @prev_issue_id,
"\xc2\xab #{l(:label_previous)}", "\xc2\xab #{l(:label_previous)}",
(@prev_issue_id ? issue_path(Issue.find_by_id(@prev_issue_id)) : nil), (@prev_issue_id ? issue_path(Issue.find_by_id(@prev_issue_id)) : nil),
:title => "##{@prev_issue_id}" %> | :title => "##{@prev_issue_id}" %> |
<% if @issue_position && @issue_count %> <% if @issue_position && @issue_count %>
<span class="position"><%= l(:label_item_position, :position => @issue_position, :count => @issue_count) %></span> | <span class="position"><%= l(:label_item_position, :position => @issue_position, :count => @issue_count) %></span> |
<% end %> <% end %>
<%= link_to_if @next_issue_id, <%= link_to_if @next_issue_id,
"#{l(:label_next)} \xc2\xbb", "#{l(:label_next)} \xc2\xbb",
(@next_issue_id ? issue_path(Issue.find_by_id(@next_issue_id)) : nil), (@next_issue_id ? issue_path(Issue.find_by_id(@next_issue_id)) : nil),
:title => "##{@next_issue_id}" %> :title => "##{@next_issue_id}" %>
</div> </div>
<% end %> <% end %>
<!-- <%#= avatar(@issue.author, :size => "50") %> --> <!-- <%#= avatar(@issue.author, :size => "50") %> -->
<div class="subject" style="word-wrap: break-word;"> <div class="subject" style="word-wrap: break-word;">
<%= render_issue_subject_with_tree(@issue) %> <%= render_issue_subject_with_tree(@issue) %>
</div> </div>
<!-- 顶和踩 在这里添加 --> <!-- 顶和踩 在这里添加 -->
<span id="praise_tread" style="float: right"> <span id="praise_tread" style="float: right">
<%= render :partial => "/praise_tread/praise_tread",:locals => {:obj => @issue,:show_flag => true,:user_id =>User.current.id,:horizontal => false}%> <%= render :partial => "/praise_tread/praise_tread",:locals => {:obj => @issue,:show_flag => true,:user_id =>User.current.id,:horizontal => false}%>
</span> </span>
<p class="author"> <p class="author">
<%= authoring @issue.created_on, @issue.author %>. <%= authoring @issue.created_on, @issue.author %>.
<% if @issue.created_on != @issue.updated_on %> <% if @issue.created_on != @issue.updated_on %>
<%= l(:label_updated_time, time_tag(@issue.updated_on)).html_safe %>. <%= l(:label_updated_time, time_tag(@issue.updated_on)).html_safe %>.
<% end %> <% end %>
</p> </p>
<!-- added by william -for tag --> <!-- added by william -for tag -->
<div id="tags"> <div id="tags">
<%= render :partial => 'tags/tag', :locals => {:obj => @issue,:object_flag => "3" }%> <%= render :partial => 'tags/tag', :locals => {:obj => @issue,:object_flag => "3" }%>
</div> </div>
<table class="attributes"> <table class="attributes">
<%= issue_fields_rows do |rows| <%= issue_fields_rows do |rows|
rows.left l(:field_status), h(@issue.status.name), :class => 'status' rows.left l(:field_status), h(@issue.status.name), :class => 'status'
rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority' rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority'
unless @issue.disabled_core_fields.include?('assigned_to_id') unless @issue.disabled_core_fields.include?('assigned_to_id')
#modified by nie #modified by nie
#modified by huang #modified by huang
rows.left l(:field_assigned_to), (image_tag url_to_avatar(@issue.assigned_to(@user)), :class => 'avatar').to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to' rows.left l(:field_assigned_to), (image_tag url_to_avatar(@issue.assigned_to(@user)), :class => 'avatar').to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to'
end end
# end huang # end huang
unless @issue.disabled_core_fields.include?('category_id') unless @issue.disabled_core_fields.include?('category_id')
rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category' rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category'
end end
unless @issue.disabled_core_fields.include?('fixed_version_id') unless @issue.disabled_core_fields.include?('fixed_version_id')
rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version' rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version'
end end
unless @issue.disabled_core_fields.include?('start_date') unless @issue.disabled_core_fields.include?('start_date')
rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date'
end end
unless @issue.disabled_core_fields.include?('due_date') unless @issue.disabled_core_fields.include?('due_date')
rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date'
end end
unless @issue.disabled_core_fields.include?('done_ratio') unless @issue.disabled_core_fields.include?('done_ratio')
rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress'
end end
unless @issue.disabled_core_fields.include?('estimated_hours') unless @issue.disabled_core_fields.include?('estimated_hours')
unless @issue.estimated_hours.nil? unless @issue.estimated_hours.nil?
rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours' rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours'
end end
end end
if User.current.allowed_to?(:view_time_entries, @project) if User.current.allowed_to?(:view_time_entries, @project)
rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? link_to(l_hours(@issue.total_spent_hours), project_issue_time_entries_path(@project, @issue)) : "-"), :class => 'spent-time' rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? link_to(l_hours(@issue.total_spent_hours), project_issue_time_entries_path(@project, @issue)) : "-"), :class => 'spent-time'
end end
end %> end %>
<%= render_custom_fields_rows(@issue) %> <%= render_custom_fields_rows(@issue) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> <%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
</table> </table>
<% if @issue.description? || @issue.attachments.any? -%> <% if @issue.description? || @issue.attachments.any? -%>
<hr /> <hr />
<% if @issue.description? %> <% if @issue.description? %>
<div class="description"> <div class="description">
<div class="contextual"> <div class="contextual">
<%= link_to l(:button_quote), quoted_issue_path(@issue.id), :remote => true, :method => 'post', :class => 'icon icon-comment' if authorize_for('issues', 'edit') %> <%= link_to l(:button_quote), quoted_issue_path(@issue.id), :remote => true, :method => 'post', :class => 'icon icon-comment' if authorize_for('issues', 'edit') %>
</div> </div>
<p><strong><%=l(:field_description)%></strong></p> <p><strong><%=l(:field_description)%></strong></p>
<div class="wiki"> <div class="wiki">
<%= textilizable @issue, :description, :attachments => @issue.attachments %> <%= textilizable @issue, :description, :attachments => @issue.attachments %>
</div> </div>
</div> </div>
<% end %> <% end %>
<%= link_to_attachments @issue, :thumbnails => true %> <%= link_to_attachments @issue, :thumbnails => true %>
<% end -%> <% end -%>
<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
<% if false # !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> <% if false # !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %>
<hr /> <hr />
<div id="issue_tree"> <div id="issue_tree">
<div class="contextual"> <div class="contextual">
<%= link_to_new_subtask(@issue) if User.current.allowed_to?(:manage_subtasks, @project) %> <%= link_to_new_subtask(@issue) if User.current.allowed_to?(:manage_subtasks, @project) %>
</div> </div>
<p><strong><%=l(:label_subtask_plural)%></strong></p> <p><strong><%=l(:label_subtask_plural)%></strong></p>
<%= render_descendants_tree(@issue) unless @issue.leaf? %> <%= render_descendants_tree(@issue) unless @issue.leaf? %>
</div> </div>
<% end %> <% end %>
<% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %> <% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %>
<hr /> <hr />
<div id="relations"> <div id="relations">
<%= render :partial => 'relations' %> <%= render :partial => 'relations' %>
</div> </div>
<% end %> <% end %>
</div> </div>
<% if @changesets.present? %> <% if @changesets.present? %>
<div id="issue-changesets"> <div id="issue-changesets">
<h3><%=l(:label_associated_revisions)%></h3> <h3><%=l(:label_associated_revisions)%></h3>
<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %> <%= render :partial => 'changesets', :locals => { :changesets => @changesets} %>
</div> </div>
<% end %> <% end %>
<% if @journals.present? %> <% if @journals.present? %>
<div id="history"> <div id="history">
<h3><%=l(:label_history)%></h3> <h3><%=l(:label_history)%></h3>
<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %> <%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %>
</div> </div>
<% end %> <% end %>
<div style="clear: both;"></div> <div style="clear: both;"></div>
<%= render :partial => 'action_menu' %> <%= render :partial => 'action_menu' %>
<div style="clear: both;"></div> <div style="clear: both;"></div>
<% if @issue.editable? %> <% if @issue.editable? %>
<div id="update"> <div id="update">
<h3><%= l(:button_update) %></h3> <h3><%= l(:button_update) %></h3>
<%= render :partial => 'edit' %> <%= render :partial => 'edit' %>
</div> </div>
<% end %> <% end %>
<% other_formats_links do |f| %> <% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
<%= f.link_to 'PDF' %> <%= f.link_to 'PDF' %>
<% end %> <% end %>
<% content_for :sidebar do %> <% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %> <%= render :partial => 'issues/sidebar' %>
<% if User.current.allowed_to?(:add_issue_watchers, @project) || <% if User.current.allowed_to?(:add_issue_watchers, @project) ||
(@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %> (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %>
<div id="watchers"> <div id="watchers">
<%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %> <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
<% end %> <% end %>
<%= context_menu issues_context_menu_path %> <%= context_menu issues_context_menu_path %>

View File

@ -194,7 +194,7 @@
</strong> </strong>
<% if show_more_fans?(@bid) %> <% if show_more_fans?(@bid) %>
<span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;"> <span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;">
<%= link_to l(:label_more), :controller => 'bids', :action => 'show_bid_user'%> <%= link_to l(:button_more), :controller => 'bids', :action => 'show_bid_user'%>
</span> </span>
<% end %> <% end %>
</div> </div>
@ -217,7 +217,7 @@
</strong> </strong>
<% if show_more_bid_project?(@bid) %> <% if show_more_bid_project?(@bid) %>
<span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;"> <span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;">
<%= link_to l(:label_more), :controller => 'bids', :action => 'show_project'%> <%= link_to l(:button_more), :controller => 'bids', :action => 'show_project'%>
</span> </span>
<% end %> <% end %>
</div> </div>
@ -244,7 +244,7 @@
</strong> </strong>
<% if show_more_participate?(@bid) %> <% if show_more_participate?(@bid) %>
<span style="font-size: 12px; display: inline; float: right;" > <span style="font-size: 12px; display: inline; float: right;" >
<%= link_to l(:label_more), :controller => "bids", :action => "show_participator"%> <%= link_to l(:button_more), :controller => "bids", :action => "show_participator"%>
</span> </span>
<% end %> <% end %>
</div> </div>

View File

@ -215,7 +215,7 @@
<%= l(:label_x_followers, :count => @contest.watcher_users.count) %> <%= l(:label_x_followers, :count => @contest.watcher_users.count) %>
</strong> </strong>
<% if show_more_fans?(@contest) %> <% if show_more_fans?(@contest) %>
<span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;"><%= link_to l(:label_more), show_contest_user_contest_path(@contest) %></span> <span style="display:inline-block; font-size: 12px; float:right; margin-bottom: -4px;"><%= link_to l(:button_more), show_contest_user_contest_path(@contest) %></span>
<% end %> <% end %>
</div> </div>
<div class="left_wf"> <div class="left_wf">

View File

@ -93,7 +93,7 @@
<%= image_tag(url_to_avatar(@project), :style => 'width:61px; height:61px;') %> <%= image_tag(url_to_avatar(@project), :style => 'width:61px; height:61px;') %>
</div> </div>
<div class="pr_info_id fl mb5"> <div class="pr_info_id fl mb5">
ID:<%= @project.id %> <%= l(:label_project_id)%><%= @project.id %>
</div> </div>
<!--关注、申请加入/退出项目--> <!--关注、申请加入/退出项目-->
<div id="join_exit_project_div"> <div id="join_exit_project_div">
@ -170,7 +170,7 @@
<% end%> <% end%>
<% unless @project.enabled_modules.where("name = 'files'").empty? %> <% unless @project.enabled_modules.where("name = 'files'").empty? %>
<div class="subNav"> <div class="subNav">
<%= link_to l(:label_course_file), project_files_path(@project), :style => "color:#3CA5C6" %> <%= link_to l(:project_module_files), project_files_path(@project), :style => "color:#3CA5C6" %>
<% unless attaments_num == 0 %> <% unless attaments_num == 0 %>
<span class="subnav_num">(<%= attaments_num %>)</span> <span class="subnav_num">(<%= attaments_num %>)</span>
<% end %> <% end %>
@ -189,7 +189,7 @@
</div> </div>
<% end %> <% end %>
<div class="subNav subNav_jiantou"><%= l(:label_more) %></div> <div class="subNav subNav_jiantou"><%= l(:label_project_more) %></div>
<ul class="navContent" style="padding-left: 0px"> <ul class="navContent" style="padding-left: 0px">
<%= render 'projects/tools_expand' %> <%= render 'projects/tools_expand' %>
</ul> </ul>

View File

@ -258,10 +258,10 @@
<% else %> <% else %>
<tr> <tr>
<td style=" float: right" width="70px" > <td style=" float: right" width="70px" >
<%= l(:label_identity)%> <span style="float: right"><%= l(:label_identity)%></span>
</td> </td>
<td class="font_lighter_sidebar" style="padding-left: 0px" width="170px"> <td class="font_lighter_sidebar" style="padding-left: 0px" width="170px">
<%= l(:label_account_student) %> <%= l(:label_account_identity_student) %>
</td> </td>
</tr> </tr>
@ -269,10 +269,10 @@
<% elsif @user.user_extensions.identity == 3 %> <% elsif @user.user_extensions.identity == 3 %>
<tr> <tr>
<td style=" float: right" width="70px" > <td style=" float: right" width="70px" >
<%= l(:label_identity)%> <span style="float: right"><%= l(:label_identity)%></span>
</td> </td>
<td class="font_lighter_sidebar" style="padding-left: 0px" width="170px"> <td class="font_lighter_sidebar" style="padding-left: 0px" width="170px">
<%= l(:label_account_developer) %> <%= l(:label_account_identity_developer) %>
</td> </td>
</tr> </tr>
<% end %> <% end %>
@ -295,7 +295,7 @@
</strong> </strong>
<% if show_more_watchers?(@user) %> <% if show_more_watchers?(@user) %>
<div style="font-size: 11px; display: inline; float: right; margin-top: 5px; margin-right: 20px" > <div style="font-size: 11px; display: inline; float: right; margin-top: 5px; margin-right: 20px" >
<%= link_to l(:label_more), :controller => "users", :action => "user_watchlist"%> <%= link_to l(:button_more), :controller => "users", :action => "user_watchlist"%>
</div> </div>
<% end %> <% end %>
</div> </div>
@ -319,7 +319,7 @@
</strong> </strong>
<% if show_more_fans?(@user) %> <% if show_more_fans?(@user) %>
<div style="font-size: 11px; display: inline; float: right; margin-top: 5px; margin-right: 20px" > <div style="font-size: 11px; display: inline; float: right; margin-top: 5px; margin-right: 20px" >
<%= link_to l(:label_more), :controller => "users", :action => "user_fanslist"%> <%= link_to l(:button_more), :controller => "users", :action => "user_fanslist"%>
</div> </div>
<% end %> <% end %>
</div> </div>

View File

@ -3,7 +3,7 @@
<div class="well"> <div class="well">
<% next if member.new_record? %> <% next if member.new_record? %>
<% unless member.created_on.nil? %> <% unless member.created_on.nil? %>
<%= content_tag "p", (User.current.language == ""|| User.current.language == "zh")?("#{format_date(member.created_on)}"+" "+"#{l(:label_member_since)}"):("#{l(:label_member_since)}+" "+#{format_date(member.created_on)}"), :class => "float_right member_since" %> <%= content_tag "p", (User.current.language == ""|| User.current.language == "zh")?("#{format_date(member.created_on)}"+" "+"#{l(:label_member_since)}"):("#{l(:label_member_since)}"+" "+"#{format_date(member.created_on)}"), :class => "float_right member_since" %>
<% end %> <% end %>
<%= member.user.nil? ? '' : (image_tag(url_to_avatar(member.user), :class => 'avatar')) %> <%= member.user.nil? ? '' : (image_tag(url_to_avatar(member.user), :class => 'avatar')) %>
<%= content_tag "div", link_to(member.user.name, user_path(member.user)), :class => "nomargin avatar_name" %> <%= content_tag "div", link_to(member.user.name, user_path(member.user)), :class => "nomargin avatar_name" %>

View File

@ -42,7 +42,7 @@
</li> </li>
<li> <li>
<% unless @project.enabled_modules.where("name = 'dts'").empty? %> <% unless @project.enabled_modules.where("name = 'dts'").empty? %>
<%= link_to l(:label_module_share) ,share_show_path(@project) %> <%= link_to l(:project_module_dts) ,share_show_path(@project) %>
<% end %> <% end %>
</li> </li>

View File

@ -17,7 +17,7 @@
<tr> <tr>
<td colspan="2" width="580px" ><p class="font_description"> <td colspan="2" width="580px" ><p class="font_description">
<% unless user.memberships.empty? %> <% unless user.memberships.empty? %>
<%= l(:label_contribute_to, :project_count => "#{user.memberships.count}") %> <%= l(:label_contribute_to, :count => user.memberships.count) %>
<% for member in user.memberships %> <% for member in user.memberships %>
<%= link_to_project(member.project) %><%= (user.memberships.last == member) ? '' : '' %> <%= link_to_project(member.project) %><%= (user.memberships.last == member) ? '' : '' %>
<% end %> <% end %>

View File

@ -1,32 +1,30 @@
<div id="tags_show"> <div id="tags_show" style="float: left;">
<%= render :partial => "tags/tag_name",:locals => {:obj => obj,:non_list_all => false ,:object_flag => object_flag} %> <%= render :partial => "tags/tag_name",:locals => {:obj => obj,:non_list_all => false ,:object_flag => object_flag} %>
</div> </div>
<div style="float: left;">
<% if User.current.logged? %> <% if User.current.logged? %>
<span> <%= toggle_link (l(:label_add_tag)), 'put-tag-form', {:focus => 'tags_name'} %> </span> <span> <%= toggle_link (l(:label_add_tag)), 'put-tag-form', {:focus => 'tags_name'} %> </span>
<% end %> <% end %>
<div id="put-tag-form" style="display: none;text-align: center"> <div id="put-tag-form" style="display: none;text-align: center">
<%= form_for "tag_for_save",:remote=>true,:url=>tag_path, <%= form_for "tag_for_save",:remote=>true,:url=>tag_path,
:update => "tags_show", :update => "tags_show",
:complete => '$("#put-tag-form").slideUp();' do |f| %> :complete => '$("#put-tag-form").slideUp();' do |f| %>
<table> <table>
<tr> <tr>
<td> <td>
<%= f.text_field :name ,:id => "tags_name",:size=>"20", <%= f.text_field :name ,:id => "tags_name",:size=>"20",
:require=>true, :require=>true,
:maxlength => Setting.tags_max_length, :maxlength => Setting.tags_max_length,
:minlength=>Setting.tags_min_length %> :minlength=>Setting.tags_min_length %>
</td> </td>
<%= f.text_field :object_id,:value=> obj.id,:style=>"display:none"%> <%= f.text_field :object_id,:value=> obj.id,:style=>"display:none"%>
<%= f.text_field :object_flag,:value=> object_flag,:style=>"display:none"%> <%= f.text_field :object_flag,:value=> object_flag,:style=>"display:none"%>
<td style="margin-left: 5px" vertical-valign="middle" >
<td style="margin-left: 5px">
<a href="#" onclick='$("#tags_name").parent().submit();' type="button" class="submit f_l"></a> <a href="#" onclick='$("#tags_name").parent().submit();' type="button" class="submit f_l"></a>
</td> </td>
<tr> <tr>
</table> </table>
<% end %> <% end %>
</div> </div>
</div>

View File

@ -31,7 +31,12 @@
<!-- 用来显示三大对象的主页中的tag 故是全部显示 --> <!-- 用来显示三大对象的主页中的tag 故是全部显示 -->
<% if @tags.size > 0 %> <% if @tags.size > 0 %>
<% @tags.each do |tag| %> <% @tags.each do |tag| %>
<div id="tag"> <!--项目暂时单独出来,后面重构-->
<% if object_flag == '2' %>
<span class="re_tag f_l">
<%= link_to tag, :controller => "tags", :action => "index", :q => tag, :object_flag => object_flag, :obj_id => obj.id %></span>
<% else %>
<div id="tag">
<span class="tag_show"> <span class="tag_show">
<%= link_to tag, :controller => "tags", :action => "index", :q => tag, :object_flag => object_flag, :obj_id => obj.id %> <%= link_to tag, :controller => "tags", :action => "index", :q => tag, :object_flag => object_flag, :obj_id => obj.id %>
<!-- 对用户主页 是本人 ,对项目,需求,问题是管理员 --> <!-- 对用户主页 是本人 ,对项目,需求,问题是管理员 -->
@ -43,13 +48,6 @@
:taggable_id => obj.id, :taggable_type => object_flag %> :taggable_id => obj.id, :taggable_type => object_flag %>
</span> </span>
<% end %> <% end %>
<% when '2' %>
<% if (ProjectInfo.find_by_project_id(obj.id)).try(:user_id) == User.current.id %>
<span class='del'>
<%= link_to 'x', :controller => "tags", :action => "remove_tag", :remote => true, :tag_name => tag,
:taggable_id => obj.id, :taggable_type => object_flag %>
</span>
<% end %>
<% when '3' %> <% when '3' %>
<% if (ProjectInfo.find_by_project_id(obj.project_id)).try(:user_id) == User.current.id %> <% if (ProjectInfo.find_by_project_id(obj.project_id)).try(:user_id) == User.current.id %>
<span class='del'> <span class='del'>
@ -101,6 +99,7 @@
<% end %> <% end %>
</span> </span>
</div> </div>
<% end %> <% end %>
<% end %>
<% end %> <% end %>
<% end %> <% end %>

View File

@ -10,7 +10,7 @@
</span> </span>
<% end %> <% end %>
<%= link_to( project.name, project_path(project.id), :class => "d-g-blue d-p-project-name",:title => "#{project.name}" )%> <%= link_to( project.name, project_path(project.id), :class => "d-g-blue d-p-project-name",:title => "#{project.name}" )%>
(<%= link_to l(:label_project_member_amount, :count=>projectCount(project)), project_member_path(project) ,:course =>'0' %>) (<%= link_to l(:label_project_member_amount, :count => projectCount(project)), project_member_path(project) ,:course =>'0' %>)
</div> </div>
<div style=" float: left;margin:5px; margin-left: 10px; width: 380px;min-height: 42px;"> <div style=" float: left;margin:5px; margin-left: 10px; width: 380px;min-height: 42px;">
<span class='font_lighter' title ='<%= project.short_description%>'> <%=project.description.truncate(90, omission: '...')%> </span> <span class='font_lighter' title ='<%= project.short_description%>'> <%=project.description.truncate(90, omission: '...')%> </span>

View File

@ -115,7 +115,7 @@
<div class="forum-topic" style="height: 25px; width: 98%; margin-left: 2px;"> <div class="forum-topic" style="height: 25px; width: 98%; margin-left: 2px;">
<h3 style="color: rgb(21, 188, 207);"><strong> <%= l(:lable_bar_active)%> </strong> <%= link_to l(:label_my_question) , newbie_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> <h3 style="color: rgb(21, 188, 207);"><strong> <%= l(:lable_bar_active)%> </strong> <%= link_to l(:label_my_question) , newbie_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%>
<%= link_to l(:label_my_feedback) , suggestion_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> </h3> <%= link_to l(:label_my_feedback) , suggestion_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> </h3>
<span style="margin-top: -30px;float: right; display: block;"> <%= link_to l(:label_more), forums_path %> </span> <span style="margin-top: -30px;float: right; display: block;"> <%= link_to l(:button_more), forums_path %> </span>
</div> </div>
<div class="welcome-box-list-new memo_activity"> <div class="welcome-box-list-new memo_activity">
<% topics = find_new_forum_topics(12) %> <% topics = find_new_forum_topics(12) %>

View File

@ -163,7 +163,6 @@ en:
label_requirement: Calls label_requirement: Calls
label_forum: Forum label_forum: Forum
label_contest: Contest label_contest: Contest
label_attachment_plural: Files
@ -203,12 +202,12 @@ en:
button_cancel: Cancel button_cancel: Cancel
label_submit: Submit label_submit: Submit
button_project_tags_add: Add button_project_tags_add: Add
label_more: "More>>"
button_download: Download button_download: Download
button_more: "More»"
button_delete: Delete button_delete: Delete
button_unfollow: Unfollow button_unfollow: Unfollow
button_follow: Follow button_follow: Follow
button_browse: Browse
# #

View File

@ -173,7 +173,7 @@ zh:
label_requirement: 需求 label_requirement: 需求
label_forum: 公共贴吧 label_forum: 公共贴吧
label_contest: 竞赛 label_contest: 竞赛
label_attachment_plural: 文件
field_description: 描述 field_description: 描述
@ -207,14 +207,16 @@ zh:
button_cancel: 取消 button_cancel: 取消
label_submit: 提交 label_submit: 提交
button_project_tags_add: 增加 button_project_tags_add: 增加
label_more: "更多>>"
button_download: 下载 button_download: 下载
button_more: 更多 button_more: "更多»"
button_delete: 删除 button_delete: 删除
button_unfollow: 取消关注 button_unfollow: 取消关注
button_follow: 关注 button_follow: 关注
button_watch: 跟踪 button_watch: 跟踪
button_unwatch: 取消跟踪 button_unwatch: 取消跟踪
button_browse: 浏览
# #
# Trustie上传头像模块 # Trustie上传头像模块
# #

View File

@ -107,7 +107,6 @@ en:
field_last_login_on: Last connection field_last_login_on: Last connection
field_effective_date: Date field_effective_date: Date
field_version: Version
field_type: Type field_type: Type
field_host: Host field_host: Host
field_port: Port field_port: Port
@ -479,7 +478,6 @@ en:
label_change_status: Change status label_change_status: Change status
label_history: History label_history: History
label_attachment: Files label_attachment: Files
label_attachment_new: New file
label_attachment_delete: Delete file label_attachment_delete: Delete file
label_file_added: File added label_file_added: File added
@ -611,12 +609,10 @@ en:
label_latest_revision_plural: Latest revisions label_latest_revision_plural: Latest revisions
label_view_revisions: View revisions label_view_revisions: View revisions
label_view_all_revisions: View all revisions label_view_all_revisions: View all revisions
label_max_size: Maximum size
label_sort_highest: Move to top label_sort_highest: Move to top
label_sort_higher: Move up label_sort_higher: Move up
label_sort_lower: Move down label_sort_lower: Move down
label_sort_lowest: Move to bottom label_sort_lowest: Move to bottom
label_roadmap: Roadmap
label_roadmap_due_in: "Due in %{value}" label_roadmap_due_in: "Due in %{value}"
label_roadmap_overdue: "%{value} late" label_roadmap_overdue: "%{value} late"
label_roadmap_no_issues: No issues for this version label_roadmap_no_issues: No issues for this version
@ -721,7 +717,6 @@ en:
label_plugins: Plugins label_plugins: Plugins
label_ldap_authentication: LDAP authentication label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_optional_description: Optional description
label_add_another_file: Add another file label_add_another_file: Add another file
label_preferences: Preferences label_preferences: Preferences
label_chronological_order: In chronological order label_chronological_order: In chronological order
@ -1028,7 +1023,7 @@ en:
label_leave_message: Message content label_leave_message: Message content
label_message: message board label_message: message board
field_add: Add before %{time} field_add: Add before %{time}
button_more: More
label_bidding_project: projects label_bidding_project: projects
button_bidding: I will participate in it button_bidding: I will participate in it
@ -1588,3 +1583,5 @@ en:
label_recently_updated_message: Recently updated the message label_recently_updated_message: Recently updated the message
label_recently_updated_courseware: Recently updated the courseware label_recently_updated_courseware: Recently updated the courseware
label_no_courses: You do not participate in any course, please search the curriculum, course, or create a course! label_no_courses: You do not participate in any course, please search the curriculum, course, or create a course!
label_commit_failed: commit failed
#api end

View File

@ -19,7 +19,9 @@ en:
# #
lable_hot_projects: Hot Projects lable_hot_projects: Hot Projects
label_private: private label_private: private
label_project_member_amount: "%{count} members" label_project_member_amount:
one: "%{count} member"
other: "%{count} members"
label_project_score_tips: "Considering all activities of the project, project's score reflects the activity level of project" label_project_score_tips: "Considering all activities of the project, project's score reflects the activity level of project"
label_project_score: Score label_project_score: Score
@ -29,7 +31,7 @@ en:
# #
# 左边栏 # 左边栏
# #
label_id: "ID:" label_project_id: "Projcet ID:"
label_apply_project: Apply to Join label_apply_project: Apply to Join
label_exit_project: Exit label_exit_project: Exit
@ -37,7 +39,7 @@ en:
label_unapply_project: Cancel the application label_unapply_project: Cancel the application
label_member: Members label_member: Members
project_module_attachments: Files project_module_attachments: Resources
label_invite: Invitation label_invite: Invitation
label_invite_new_user: "Send e-mail to invite new user" label_invite_new_user: "Send e-mail to invite new user"
@ -48,19 +50,21 @@ en:
project_module_boards: Forums project_module_boards: Forums
project_module_boards_post: New Post project_module_boards_post: New Post
# 与课程公用资源库 project_module_files: Resources
label_upload_files: New File
project_module_repository: Repository project_module_repository: Repository
project_module_create_repository: New Repository project_module_create_repository: New Repository
label_project_more: More
project_module_news: News project_module_news: News
project_module_wiki: Wiki project_module_wiki: Wiki
project_module_code_review: Code Review project_module_code_review: Code Review
project_module_calendar: Calendar project_module_calendar: Calendar
project_module_gantt: Gantt project_module_gantt: Gantt
project_module_documents: Documents project_module_documents: Documents
label_project_tool_response: Response label_roadmap: Roadmap
label_module_share: DTS Test Tool label_project_tool_response: Feedback
project_module_dts: DTS Test Tool
label_project_overview: "Profile:" label_project_overview: "Profile:"
label_expend_information: More Information label_expend_information: More Information
@ -87,7 +91,9 @@ en:
# 关注者列表 # 关注者列表
# #
label_followers: Followers label_followers: Followers
label_contribute_to: "Participates %{project_count} projects—" label_contribute_to:
one: "Participates %{count} project—"
other: "Participates %{count} projects—"
# #
@ -95,10 +101,7 @@ en:
# #
# 资源库 # 资源库
# #
lable_file_sharingarea: Files lable_file_sharingarea: Resources
label_upload_files: Upload
# 资源库(附件)公用 # 资源库(附件)公用
label_relation_files: Select an existing resource label_relation_files: Select an existing resource
@ -108,18 +111,26 @@ en:
attachment_all: "All" attachment_all: "All"
attachment_browse: "Attachment Content Browse" attachment_browse: "Attachment Content Browse"
attachment_sufix_browse: "Attachment Type Browse" attachment_sufix_browse: "Attachment Type Browse"
attachment_type: "Attachment Type" label_unknow_type: Unknow type
label_unknow_type: Unknow type
field_filename: File field_filename: File
field_filesize: Size field_filesize: Size
field_filecontenttype: Content Typ field_filecontenttype: Content
field_filetype: File Typ field_filetype: File Typ
field_downloads: Downloads field_downloads: Downloads
field_file_dense: Dense field_file_dense: Dense
# 资源库(附件)公用 > 上传文件
label_attachment_new: New file
field_version: Version
attachment_type: "Attachment Type"
label_attachment_plural: Files
label_no_file_uploaded: No file uploaded
label_max_size: Maximum size
label_optional_description: Description
label_file_count: "%{count} files were uploaded successfully"
# #
# 项目托管平台 # 项目托管平台
@ -164,7 +175,6 @@ en:
project_module_issue_tracking: Issue tracking project_module_issue_tracking: Issue tracking
project_module_time_tracking: Time tracking project_module_time_tracking: Time tracking
project_module_course: 课程 project_module_course: 课程
project_module_files: Files
project_module_boards: Forums project_module_boards: Forums
# #

View File

@ -22,7 +22,9 @@ zh:
# #
lable_hot_projects: 热门项目 lable_hot_projects: 热门项目
label_private: 私有 label_private: 私有
label_project_member_amount: "%{count}人" label_project_member_amount:
one: "%{count}人"
other: "%{count}人"
label_project_score_tips: 项目得分,综合考虑了项目的各项活动,反映了该项目的活跃程度 label_project_score_tips: 项目得分,综合考虑了项目的各项活动,反映了该项目的活跃程度
label_project_score: 项目评分 label_project_score: 项目评分
@ -32,7 +34,7 @@ zh:
# #
# 左边栏 # 左边栏
# #
label_id: "ID:" label_project_id: "项目ID:"
label_apply_project: 申请加入 label_apply_project: 申请加入
label_exit_project: 退出项目 label_exit_project: 退出项目
@ -50,18 +52,20 @@ zh:
project_module_boards: 讨论区 project_module_boards: 讨论区
project_module_boards_post: 发帖 project_module_boards_post: 发帖
# 与课程公用资源库 project_module_files: 资源库
project_module_repository: 版本库 project_module_repository: 版本库
project_module_create_repository: 创建版本库 project_module_create_repository: 创建版本库
label_project_more: 更多
project_module_news: 新闻 project_module_news: 新闻
project_module_wiki: Wiki project_module_wiki: Wiki
project_module_code_review: 代码审查 project_module_code_review: 代码审查
project_module_calendar: 日历 project_module_calendar: 日历
project_module_gantt: 甘特图 project_module_gantt: 甘特图
project_module_documents: 文档 project_module_documents: 文档
label_roadmap: 里程碑 #版本路线图
project_module_dts: DTS测试工具
label_project_tool_response: 用户反馈 label_project_tool_response: 用户反馈
label_module_share: DTS测试工具
label_project_overview: "项目简介:" label_project_overview: "项目简介:"
label_expend_information: 展开更多信息 label_expend_information: 展开更多信息
@ -88,7 +92,9 @@ zh:
# 关注者列表 # 关注者列表
# #
label_followers: 关注 label_followers: 关注
label_contribute_to: 参与了 %{project_count} 个项目: label_contribute_to:
one: "参与了 %{count}个项目:"
other: "参与了 %{count}个项目:"
# #
@ -101,7 +107,7 @@ zh:
label_upload_files: 上传文件 label_upload_files: 上传文件
# 资源库(附件)公用 # 资源库(附件)公用 > 关联资源
label_relation_files: 关联已有资源 label_relation_files: 关联已有资源
label_search_by_keyword: "按关键字搜索:" label_search_by_keyword: "按关键字搜索:"
label_files_filter: "资源过滤:" label_files_filter: "资源过滤:"
@ -116,8 +122,19 @@ zh:
attachment_sufix_browse: "文件类型" attachment_sufix_browse: "文件类型"
attachment_browse: "内容类型" attachment_browse: "内容类型"
attachment_all: "全部" attachment_all: "全部"
attachment_type: "分类"
label_unknow_type: 未知类型 label_unknow_type: 未知类型
# 资源库(附件)公用 > 上传文件
label_attachment_new: 新建文件
field_version: 版本
attachment_type: "分类"
label_attachment_plural: 文件
label_no_file_uploaded: 未上传文件
label_max_size: 最大文件大小
label_optional_description: 可选的描述
# #
# 项目托管平台 # 项目托管平台
@ -166,7 +183,6 @@ zh:
project_moule_boards_show: 项目论坛 project_moule_boards_show: 项目论坛
project_module_time_tracking: 时间跟踪 project_module_time_tracking: 时间跟踪
project_module_course: 课程 project_module_course: 课程
project_module_files: 资源库
# #
@ -179,6 +195,7 @@ zh:
label_invite_email_tips: 输入好友邮箱地址Trustie会自动为该邮箱注册用户 label_invite_email_tips: 输入好友邮箱地址Trustie会自动为该邮箱注册用户
notice_registed_success: 您输入的邮箱为空或者该邮箱已被注册! notice_registed_success: 您输入的邮箱为空或者该邮箱已被注册!
label_email_format_error: 您所填写的电子邮件格式不正确 label_email_format_error: 您所填写的电子邮件格式不正确
label_user_role_null: 用户和角色不能留空!
label_send_email: 免费发送 label_send_email: 免费发送
label_input_email: 请输入邮箱地址 label_input_email: 请输入邮箱地址

View File

@ -77,8 +77,6 @@ en:
label_technical_title: Title label_technical_title: Title
label_bidding_user_studentcode: Student ID label_bidding_user_studentcode: Student ID
label_account_developer: Developer
label_account_student: Student
# #
@ -112,7 +110,7 @@ en:
label_layouts_feedback: "a message " label_layouts_feedback: "a message "
label_of_feedback: from label_of_feedback: from
label_goto: Go to>> label_goto: "Go to»"
label_activity_project: "Project" label_activity_project: "Project"
label_active_call: call label_active_call: call
@ -180,12 +178,12 @@ en:
# #
label_responses: Messages label_responses: Messages
label_user_response: Feedback label_user_response: Feedback
label_leave_a_message: Leave him/her a message label_leave_a_message: "Leave him/her a message"
button_leave_meassge: Submit button_leave_meassge: Submit
button_clear_meassge: Reset button_clear_meassge: Reset
label_user_login_new: Login label_user_login_new: Login
label_user_login_tips: You haven't logged in, please login first to leave a message! label_user_login_tips: "You haven't logged in, please login first to leave a message!"
label_bid_respond_delete: Delete label_bid_respond_delete: Delete
label_bid_respond_quote: Respond label_bid_respond_quote: Respond

View File

@ -36,6 +36,7 @@ zh:
label_user_edit: "修改资料" label_user_edit: "修改资料"
label_user_score: 个人综合得分 label_user_score: 个人综合得分
# 用户身份在/my的修改资料下
label_user_score_of_collaboration: 协同得分 label_user_score_of_collaboration: 协同得分
label_user_score_of_influence: 影响力得分 label_user_score_of_influence: 影响力得分
label_user_score_of_skill: 技术得分 label_user_score_of_skill: 技术得分
@ -87,10 +88,9 @@ zh:
label_technicl_title_associate_professor: 副教授 label_technicl_title_associate_professor: 副教授
label_technicl_title_lecturer: 讲师 label_technicl_title_lecturer: 讲师
label_technicl_title_teaching_assistant: 助教 label_technicl_title_teaching_assistant: 助教
# 用户身份(学生、开发者)标签在/my的修改资料下
label_bidding_user_studentcode: 学号 label_bidding_user_studentcode: 学号
label_account_developer: 开发者
label_account_student: 学生
label_no_current_fans: 该用户暂无粉丝 label_no_current_fans: 该用户暂无粉丝
label_no_current_watchers: 该用户暂未关注其他用户 label_no_current_watchers: 该用户暂未关注其他用户
@ -115,7 +115,7 @@ zh:
label_of_feedback: label_of_feedback:
label_layouts_feedback: 留言 label_layouts_feedback: 留言
label_goto: 前往>> label_goto: "前往»"
label_activity_project: "项目:" label_activity_project: "项目:"
label_active_call: 需求 label_active_call: 需求

View File

@ -129,13 +129,12 @@ zh:
field_priority: 优先级 field_priority: 优先级
field_fixed_version: 目标版本 field_fixed_version: 目标版本
field_user: 用户 field_user: 用户
field_principal: 用户/用户组 field_principal: 用户
field_role: 角色 field_role: 角色
field_homepage: 主页 field_homepage: 主页
field_time: 课时 field_time: 课时
field_class_period: 学时 field_class_period: 学时
field_code: 学分 field_code: 学分
field_is_public: 公开
field_open_student: 学生列表公开 field_open_student: 学生列表公开
field_parent: 上级项目 field_parent: 上级项目
field_is_in_roadmap: 在路线图中显示 field_is_in_roadmap: 在路线图中显示
@ -144,7 +143,6 @@ zh:
field_last_login_on: 最后登录 field_last_login_on: 最后登录
field_language: 语言 field_language: 语言
field_effective_date: 日期 field_effective_date: 日期
field_version: 版本
field_type: 类型 field_type: 类型
field_host: 主机 field_host: 主机
field_port: 端口 field_port: 端口
@ -465,8 +463,6 @@ zh:
label_new_contest: 竞赛 label_new_contest: 竞赛
label_requirement_focus: 关注需求 label_requirement_focus: 关注需求
label_developer: 用户 label_developer: 用户
label_account_developer: 开发者
label_account_student: 学生
label_enterprise_into: 进入企业 label_enterprise_into: 进入企业
label_college_into: 进入高校 label_college_into: 进入高校
label_investor: 投资人: label_investor: 投资人:
@ -561,7 +557,7 @@ zh:
label_change_status: 变更状态 label_change_status: 变更状态
label_history: 历史记录 label_history: 历史记录
label_attachment: 文件 label_attachment: 文件
label_attachment_new: 新建文件
label_file_upload: 上传资料 label_file_upload: 上传资料
label_course_file_upload: 上传了课件 label_course_file_upload: 上传了课件
label_attachment_delete: 删除文件 label_attachment_delete: 删除文件
@ -691,13 +687,11 @@ zh:
label_latest_revision_plural: 最近的修订版本 label_latest_revision_plural: 最近的修订版本
label_view_revisions: 查看修订 label_view_revisions: 查看修订
label_view_all_revisions: 查看所有修订 label_view_all_revisions: 查看所有修订
label_no_file_uploaded: 未上传文件
label_max_size: 最大文件大小
label_sort_highest: 置顶 label_sort_highest: 置顶
label_sort_higher: 上移 label_sort_higher: 上移
label_sort_lower: 下移 label_sort_lower: 下移
label_sort_lowest: 置底 label_sort_lowest: 置底
label_roadmap: 里程碑 #版本路线图
label_roadmap_due_in: "截止日期到 %{value}" label_roadmap_due_in: "截止日期到 %{value}"
label_roadmap_overdue: "%{value} 延期" label_roadmap_overdue: "%{value} 延期"
label_roadmap_no_issues: 该版本没有问题 label_roadmap_no_issues: 该版本没有问题
@ -846,7 +840,7 @@ zh:
label_plugins: 插件 label_plugins: 插件
label_ldap_authentication: LDAP 认证 label_ldap_authentication: LDAP 认证
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_optional_description: 可选的描述
label_add_another_file: 添加其它文件 label_add_another_file: 添加其它文件
label_preferences: 首选项 label_preferences: 首选项
label_chronological_order: 按时间顺序 label_chronological_order: 按时间顺序
@ -1093,7 +1087,7 @@ zh:
description_all_columns: 所有列 description_all_columns: 所有列
button_export: 导出 button_export: 导出
label_export_options: "%{export_format} 导出选项" label_export_options: "%{export_format} 导出选项"
error_attachment_too_big: 该文件无法上传。超过文件大小限制 (%{max_size})
error_pic_type: "仅支持如下图片格式:" error_pic_type: "仅支持如下图片格式:"
notice_failed_to_save_time_entries: "无法保存下列所选取的 %{total} 个项目中的 %{count} 工时: %{ids}。" notice_failed_to_save_time_entries: "无法保存下列所选取的 %{total} 个项目中的 %{count} 工时: %{ids}。"
label_x_issues: label_x_issues:
@ -2032,6 +2026,9 @@ zh:
label_recently_updated_message: 最近更新了留言 label_recently_updated_message: 最近更新了留言
label_recently_updated_courseware: 最近更新了课件 label_recently_updated_courseware: 最近更新了课件
label_no_courses: 您没有参与任何课程,请搜索课程、加入课程,或者创建课程吧! label_no_courses: 您没有参与任何课程,请搜索课程、加入课程,或者创建课程吧!
label_commit_failed: 提交失败
#api end
label_end_time: 截止时间 label_end_time: 截止时间
label_send_email: 确定发送 label_send_email: 确定发送
label_input_email: 请输入邮箱地址 label_input_email: 请输入邮箱地址

View File

@ -863,6 +863,11 @@ RedmineApp::Application.routes.draw do
match 'system_log/clear' match 'system_log/clear'
##ended by lizanle ##ended by lizanle
resources :git_callback do
collection do
post 'post_update'
end
end
Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir| Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
file = File.join(plugin_dir, "config/routes.rb") file = File.join(plugin_dir, "config/routes.rb")

Binary file not shown.

View File

@ -1,4 +0,0 @@
language: ruby
rvm:
- 2.1.0
- 2.0.0

View File

@ -1 +0,0 @@
--markup markdown --no-private

View File

@ -1,3 +0,0 @@
# Changelog
See https://github.com/charliesome/better_errors/releases

View File

@ -1,10 +0,0 @@
source 'https://rubygems.org'
gemspec
gem "rake"
gem "rspec", "2.14.1"
gem "binding_of_caller", platforms: :ruby
gem "pry", "0.9.12"
gem "yard"
gem "kramdown"

View File

@ -1,22 +0,0 @@
Copyright (c) 2014 Charlie Somerville
MIT License
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.

View File

@ -1,103 +0,0 @@
# Better Errors [![Gem Version](http://img.shields.io/gem/v/better_errors.svg)](https://rubygems.org/gems/better_errors) [![Build Status](https://travis-ci.org/charliesome/better_errors.svg)](https://travis-ci.org/charliesome/better_errors) [![Code Climate](http://img.shields.io/codeclimate/github/charliesome/better_errors.svg)](https://codeclimate.com/github/charliesome/better_errors)
Better Errors replaces the standard Rails error page with a much better and more useful error page. It is also usable outside of Rails in any Rack app as Rack middleware.
![image](http://i.imgur.com/6zBGAAb.png)
## Features
* Full stack trace
* Source code inspection for all stack frames (with highlighting)
* Local and instance variable inspection
* Live REPL on every stack frame
## Installation
Add this to your Gemfile:
```ruby
group :development do
gem "better_errors"
end
```
If you would like to use Better Errors' **advanced features** (REPL, local/instance variable inspection, pretty stack frame names), you need to add the [`binding_of_caller`](https://github.com/banister/binding_of_caller) gem by [@banisterfiend](http://twitter.com/banisterfiend) to your Gemfile:
```ruby
gem "binding_of_caller"
```
This is an optional dependency however, and Better Errors will work without it.
_Note: If you discover that Better Errors isn't working - particularly after upgrading from version 0.5.0 or less - be sure to set `config.consider_all_requests_local = true` in `config/environments/development.rb`._
## Security
**NOTE:** It is *critical* you put better\_errors in the **development** section. **Do NOT run better_errors in production, or on Internet facing hosts.**
You will notice that the only machine that gets the Better Errors page is localhost, which means you get the default error page if you are developing on a remote host (or a virtually remote host, such as a Vagrant box). Obviously, the REPL is not something you want to expose to the public, but there may also be other pieces of sensitive information available in the backtrace.
To poke selective holes in this security mechanism, you can add a line like this to your startup (for example, on Rails it would be `config/environments/development.rb`)
```ruby
BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
```
Then run Rails like this:
```shell
TRUSTED_IP=66.68.96.220 rails s
```
Note that the `allow_ip!` is actually backed by a `Set`, so you can add more than one IP address or subnet.
**Tip:** You can find your apparent IP by hitting the old error page's "Show env dump" and looking at "REMOTE_ADDR".
**VirtualBox:** If you are using VirtualBox and are accessing the guest from your host's browser, you will need to use `allow_ip!` to see the error page.
## Usage
If you're using Rails, there's nothing else you need to do.
If you're not using Rails, you need to insert `BetterErrors::Middleware` into your middleware stack, and optionally set `BetterErrors.application_root` if you'd like Better Errors to abbreviate filenames within your application.
Here's an example using Sinatra:
```ruby
require "sinatra"
require "better_errors"
configure :development do
use BetterErrors::Middleware
BetterErrors.application_root = __dir__
end
get "/" do
raise "oops"
end
```
### Unicorn, Puma, and other multi-worker servers
Better Errors works by leaving a lot of context in server process memory. If
you're using a web server that runs multiple "workers" it's likely that a second
request (as happens when you click on a stack frame) will hit a different
worker. That worker won't have the necessary context in memory, and you'll see
a `Session Expired` message.
If this is the case for you, consider turning the number of workers to one (1)
in `development`. Another option would be to use Webrick, Mongrel, Thin,
or another single-process server as your `rails server`, when you are trying
to troubleshoot an issue in development.
## Get in touch!
If you're using better_errors, I'd love to hear from you. Drop me a line and tell me what you think!
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

View File

@ -1,13 +0,0 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"
namespace :test do
RSpec::Core::RakeTask.new(:with_binding_of_caller)
without_task = RSpec::Core::RakeTask.new(:without_binding_of_caller)
without_task.ruby_opts = "-I spec -r without_binding_of_caller"
task :all => [:with_binding_of_caller, :without_binding_of_caller]
end
task :default => "test:all"

View File

@ -1,27 +0,0 @@
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'better_errors/version'
Gem::Specification.new do |s|
s.name = "better_errors"
s.version = BetterErrors::VERSION
s.authors = ["Charlie Somerville"]
s.email = ["charlie@charliesomerville.com"]
s.description = %q{Provides a better error page for Rails and other Rack apps. Includes source code inspection, a live REPL and local/instance variable inspection for all stack frames.}
s.summary = %q{Better error page for Rails and other Rack apps}
s.homepage = "https://github.com/charliesome/better_errors"
s.license = "MIT"
s.files = `git ls-files`.split($/)
s.test_files = s.files.grep(%r{^(test|spec|features)/})
s.require_paths = ["lib"]
s.required_ruby_version = ">= 2.0.0"
s.add_dependency "erubis", ">= 2.6.6"
s.add_dependency "coderay", ">= 1.0.0"
# optional dependencies:
# s.add_dependency "binding_of_caller"
# s.add_dependency "pry"
end

View File

@ -1,146 +0,0 @@
require "pp"
require "erubis"
require "coderay"
require "uri"
require "better_errors/code_formatter"
require "better_errors/error_page"
require "better_errors/middleware"
require "better_errors/raised_exception"
require "better_errors/repl"
require "better_errors/stack_frame"
require "better_errors/version"
module BetterErrors
POSSIBLE_EDITOR_PRESETS = [
{ symbols: [:emacs, :emacsclient], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
{ symbols: [:macvim, :mvim], sniff: /vim/i, url: proc { |file, line| "mvim://open?url=file://#{file}&line=#{line}" } },
{ symbols: [:sublime, :subl, :st], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
{ symbols: [:textmate, :txmt, :tm], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
]
class << self
# The path to the root of the application. Better Errors uses this property
# to determine if a file in a backtrace should be considered an application
# frame. If you are using Better Errors with Rails, you do not need to set
# this attribute manually.
#
# @return [String]
attr_accessor :application_root
# The logger to use when logging exception details and backtraces. If you
# are using Better Errors with Rails, you do not need to set this attribute
# manually. If this attribute is `nil`, nothing will be logged.
#
# @return [Logger, nil]
attr_accessor :logger
# @private
attr_accessor :binding_of_caller_available
# @private
alias_method :binding_of_caller_available?, :binding_of_caller_available
# The ignored instance variables.
# @return [Array]
attr_accessor :ignored_instance_variables
end
@ignored_instance_variables = []
# Returns a proc, which when called with a filename and line number argument,
# returns a URL to open the filename and line in the selected editor.
#
# Generates TextMate URLs by default.
#
# BetterErrors.editor["/some/file", 123]
# # => txmt://open?url=file:///some/file&line=123
#
# @return [Proc]
def self.editor
@editor
end
# Configures how Better Errors generates open-in-editor URLs.
#
# @overload BetterErrors.editor=(sym)
# Uses one of the preset editor configurations. Valid symbols are:
#
# * `:textmate`, `:txmt`, `:tm`
# * `:sublime`, `:subl`, `:st`
# * `:macvim`
#
# @param [Symbol] sym
#
# @overload BetterErrors.editor=(str)
# Uses `str` as the format string for generating open-in-editor URLs.
#
# Use `%{file}` and `%{line}` as placeholders for the actual values.
#
# @example
# BetterErrors.editor = "my-editor://open?url=%{file}&line=%{line}"
#
# @param [String] str
#
# @overload BetterErrors.editor=(proc)
# Uses `proc` to generate open-in-editor URLs. The proc will be called
# with `file` and `line` parameters when a URL needs to be generated.
#
# Your proc should take care to escape `file` appropriately with
# `URI.encode_www_form_component` (please note that `URI.escape` is **not**
# a suitable substitute.)
#
# @example
# BetterErrors.editor = proc { |file, line|
# "my-editor://open?url=#{URI.encode_www_form_component file}&line=#{line}"
# }
#
# @param [Proc] proc
#
def self.editor=(editor)
POSSIBLE_EDITOR_PRESETS.each do |config|
if config[:symbols].include?(editor)
return self.editor = config[:url]
end
end
if editor.is_a? String
self.editor = proc { |file, line| editor % { file: URI.encode_www_form_component(file), line: line } }
else
if editor.respond_to? :call
@editor = editor
else
raise TypeError, "Expected editor to be a valid editor key, a format string or a callable."
end
end
end
# Enables experimental Pry support in the inline REPL
#
# If you encounter problems while using Pry, *please* file a bug report at
# https://github.com/charliesome/better_errors/issues
def self.use_pry!
REPL::PROVIDERS.unshift const: :Pry, impl: "better_errors/repl/pry"
end
# Automatically sniffs a default editor preset based on the EDITOR
# environment variable.
#
# @return [Symbol]
def self.default_editor
POSSIBLE_EDITOR_PRESETS.detect(-> { {} }) { |config|
ENV["EDITOR"] =~ config[:sniff]
}[:url] || :textmate
end
BetterErrors.editor = default_editor
end
begin
require "binding_of_caller"
require "better_errors/exception_extension"
BetterErrors.binding_of_caller_available = true
rescue LoadError => e
BetterErrors.binding_of_caller_available = false
end
require "better_errors/rails" if defined? Rails::Railtie

View File

@ -1,63 +0,0 @@
module BetterErrors
# @private
class CodeFormatter
require "better_errors/code_formatter/html"
require "better_errors/code_formatter/text"
FILE_TYPES = {
".rb" => :ruby,
"" => :ruby,
".html" => :html,
".erb" => :erb,
".haml" => :haml
}
attr_reader :filename, :line, :context
def initialize(filename, line, context = 5)
@filename = filename
@line = line
@context = context
end
def output
formatted_code
rescue Errno::ENOENT, Errno::EINVAL
source_unavailable
end
def formatted_code
formatted_lines.join
end
def coderay_scanner
ext = File.extname(filename)
FILE_TYPES[ext] || :text
end
def each_line_of(lines, &blk)
line_range.zip(lines).map { |current_line, str|
yield (current_line == line), current_line, str
}
end
def highlighted_lines
CodeRay.scan(context_lines.join, coderay_scanner).div(wrap: nil).lines
end
def context_lines
range = line_range
source_lines[(range.begin - 1)..(range.end - 1)] or raise Errno::EINVAL
end
def source_lines
@source_lines ||= File.readlines(filename)
end
def line_range
min = [line - context, 1].max
max = [line + context, source_lines.count].min
min..max
end
end
end

View File

@ -1,26 +0,0 @@
module BetterErrors
# @private
class CodeFormatter::HTML < CodeFormatter
def source_unavailable
"<p class='unavailable'>Source is not available</p>"
end
def formatted_lines
each_line_of(highlighted_lines) { |highlight, current_line, str|
class_name = highlight ? "highlight" : ""
sprintf '<pre class="%s">%s</pre>', class_name, str
}
end
def formatted_nums
each_line_of(highlighted_lines) { |highlight, current_line, str|
class_name = highlight ? "highlight" : ""
sprintf '<span class="%s">%5d</span>', class_name, current_line
}
end
def formatted_code
%{<div class="code_linenums">#{formatted_nums.join}</div><div class="code">#{super}</div>}
end
end
end

View File

@ -1,14 +0,0 @@
module BetterErrors
# @private
class CodeFormatter::Text < CodeFormatter
def source_unavailable
"# Source is not available"
end
def formatted_lines
each_line_of(context_lines) { |highlight, current_line, str|
sprintf '%s %3d %s', (highlight ? '>' : ' '), current_line, str
}
end
end
end

View File

@ -1,110 +0,0 @@
require "cgi"
require "json"
require "securerandom"
module BetterErrors
# @private
class ErrorPage
def self.template_path(template_name)
File.expand_path("../templates/#{template_name}.erb", __FILE__)
end
def self.template(template_name)
Erubis::EscapedEruby.new(File.read(template_path(template_name)))
end
attr_reader :exception, :env, :repls
def initialize(exception, env)
@exception = RaisedException.new(exception)
@env = env
@start_time = Time.now.to_f
@repls = []
end
def id
@id ||= SecureRandom.hex(8)
end
def render(template_name = "main")
self.class.template(template_name).result binding
end
def do_variables(opts)
index = opts["index"].to_i
@frame = backtrace_frames[index]
@var_start_time = Time.now.to_f
{ html: render("variable_info") }
end
def do_eval(opts)
index = opts["index"].to_i
code = opts["source"]
unless binding = backtrace_frames[index].frame_binding
return { error: "REPL unavailable in this stack frame" }
end
result, prompt, prefilled_input =
(@repls[index] ||= REPL.provider.new(binding)).send_input(code)
{ result: result,
prompt: prompt,
prefilled_input: prefilled_input,
highlighted_input: CodeRay.scan(code, :ruby).div(wrap: nil) }
end
def backtrace_frames
exception.backtrace
end
def application_frames
backtrace_frames.select(&:application?)
end
def first_frame
application_frames.first || backtrace_frames.first
end
private
def editor_url(frame)
BetterErrors.editor[frame.filename, frame.line]
end
def rack_session
env['rack.session']
end
def rails_params
env['action_dispatch.request.parameters']
end
def uri_prefix
env["SCRIPT_NAME"] || ""
end
def request_path
env["PATH_INFO"]
end
def html_formatted_code_block(frame)
CodeFormatter::HTML.new(frame.filename, frame.line).output
end
def text_formatted_code_block(frame)
CodeFormatter::Text.new(frame.filename, frame.line).output
end
def text_heading(char, str)
str + "\n" + char*str.size
end
def inspect_value(obj)
CGI.escapeHTML(obj.inspect)
rescue NoMethodError
"<span class='unsupported'>(object doesn't support inspect)</span>"
rescue Exception => e
"<span class='unsupported'>(exception was raised in inspect)</span>"
end
end
end

View File

@ -1,17 +0,0 @@
module BetterErrors
module ExceptionExtension
prepend_features Exception
def set_backtrace(*)
if caller_locations.none? { |loc| loc.path == __FILE__ }
@__better_errors_bindings_stack = binding.callers.drop(1)
end
super
end
def __better_errors_bindings_stack
@__better_errors_bindings_stack || []
end
end
end

View File

@ -1,141 +0,0 @@
require "json"
require "ipaddr"
require "set"
module BetterErrors
# Better Errors' error handling middleware. Including this in your middleware
# stack will show a Better Errors error page for exceptions raised below this
# middleware.
#
# If you are using Ruby on Rails, you do not need to manually insert this
# middleware into your middleware stack.
#
# @example Sinatra
# require "better_errors"
#
# if development?
# use BetterErrors::Middleware
# end
#
# @example Rack
# require "better_errors"
# if ENV["RACK_ENV"] == "development"
# use BetterErrors::Middleware
# end
#
class Middleware
# The set of IP addresses that are allowed to access Better Errors.
#
# Set to `{ "127.0.0.1/8", "::1/128" }` by default.
ALLOWED_IPS = Set.new
# Adds an address to the set of IP addresses allowed to access Better
# Errors.
def self.allow_ip!(addr)
ALLOWED_IPS << IPAddr.new(addr)
end
allow_ip! "127.0.0.0/8"
allow_ip! "::1/128" rescue nil # windows ruby doesn't have ipv6 support
# A new instance of BetterErrors::Middleware
#
# @param app The Rack app/middleware to wrap with Better Errors
# @param handler The error handler to use.
def initialize(app, handler = ErrorPage)
@app = app
@handler = handler
end
# Calls the Better Errors middleware
#
# @param [Hash] env
# @return [Array]
def call(env)
if allow_ip? env
better_errors_call env
else
@app.call env
end
end
private
def allow_ip?(env)
# REMOTE_ADDR is not in the rack spec, so some application servers do
# not provide it.
return true unless env["REMOTE_ADDR"] and !env["REMOTE_ADDR"].strip.empty?
ip = IPAddr.new env["REMOTE_ADDR"].split("%").first
ALLOWED_IPS.any? { |subnet| subnet.include? ip }
end
def better_errors_call(env)
case env["PATH_INFO"]
when %r{/__better_errors/(?<id>.+?)/(?<method>\w+)\z}
internal_call env, $~
when %r{/__better_errors/?\z}
show_error_page env
else
protected_app_call env
end
end
def protected_app_call(env)
@app.call env
rescue Exception => ex
@error_page = @handler.new ex, env
log_exception
show_error_page(env, ex)
end
def show_error_page(env, exception=nil)
type, content = if @error_page
if text?(env)
[ 'plain', @error_page.render('text') ]
else
[ 'html', @error_page.render ]
end
else
[ 'html', no_errors_page ]
end
status_code = 500
if defined? ActionDispatch::ExceptionWrapper
status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
end
[status_code, { "Content-Type" => "text/#{type}; charset=utf-8" }, [content]]
end
def text?(env)
env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ||
!env["HTTP_ACCEPT"].to_s.include?('html')
end
def log_exception
return unless BetterErrors.logger
message = "\n#{@error_page.exception.type} - #{@error_page.exception.message}:\n"
@error_page.backtrace_frames.each do |frame|
message << " #{frame}\n"
end
BetterErrors.logger.fatal message
end
def internal_call(env, opts)
if opts[:id] != @error_page.id
return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
end
env["rack.input"].rewind
response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
[200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(response)]]
end
def no_errors_page
"<h1>No errors</h1><p>No errors have been recorded yet.</p><hr>" +
"<code>Better Errors v#{BetterErrors::VERSION}</code>"
end
end
end

View File

@ -1,28 +0,0 @@
module BetterErrors
# @private
class Railtie < Rails::Railtie
initializer "better_errors.configure_rails_initialization" do
if use_better_errors?
insert_middleware
BetterErrors.logger = Rails.logger
BetterErrors.application_root = Rails.root.to_s
end
end
def insert_middleware
if defined? ActionDispatch::DebugExceptions
app.middleware.insert_after ActionDispatch::DebugExceptions, BetterErrors::Middleware
else
app.middleware.use BetterErrors::Middleware
end
end
def use_better_errors?
!Rails.env.production? and app.config.consider_all_requests_local
end
def app
Rails.application
end
end
end

View File

@ -1,66 +0,0 @@
# @private
module BetterErrors
class RaisedException
attr_reader :exception, :message, :backtrace
def initialize(exception)
if exception.respond_to?(:original_exception) && exception.original_exception
exception = exception.original_exception
end
@exception = exception
@message = exception.message
setup_backtrace
massage_syntax_error
end
def type
exception.class
end
private
def has_bindings?
exception.respond_to?(:__better_errors_bindings_stack) && exception.__better_errors_bindings_stack.any?
end
def setup_backtrace
if has_bindings?
setup_backtrace_from_bindings
else
setup_backtrace_from_backtrace
end
end
def setup_backtrace_from_bindings
@backtrace = exception.__better_errors_bindings_stack.map { |binding|
file = binding.eval "__FILE__"
line = binding.eval "__LINE__"
name = binding.frame_description
StackFrame.new(file, line, name, binding)
}
end
def setup_backtrace_from_backtrace
@backtrace = (exception.backtrace || []).map { |frame|
if /\A(?<file>.*?):(?<line>\d+)(:in `(?<name>.*)')?/ =~ frame
StackFrame.new(file, line.to_i, name)
end
}.compact
end
def massage_syntax_error
case exception.class.to_s
when "Haml::SyntaxError"
if /\A(.+?):(\d+)/ =~ exception.backtrace.first
backtrace.unshift(StackFrame.new($1, $2.to_i, ""))
end
when "SyntaxError"
if /\A(.+?):(\d+): (.*)/m =~ exception.message
backtrace.unshift(StackFrame.new($1, $2.to_i, ""))
@message = $3
end
end
end
end
end

View File

@ -1,30 +0,0 @@
module BetterErrors
# @private
module REPL
PROVIDERS = [
{ impl: "better_errors/repl/basic",
const: :Basic },
]
def self.provider
@provider ||= const_get detect[:const]
end
def self.provider=(prov)
@provider = prov
end
def self.detect
PROVIDERS.find { |prov|
test_provider prov
}
end
def self.test_provider(provider)
require provider[:impl]
true
rescue LoadError
false
end
end
end

View File

@ -1,20 +0,0 @@
module BetterErrors
module REPL
class Basic
def initialize(binding)
@binding = binding
end
def send_input(str)
[execute(str), ">>", ""]
end
private
def execute(str)
"=> #{@binding.eval(str).inspect}\n"
rescue Exception => e
"!! #{e.inspect rescue e.class.to_s rescue "Exception"}\n"
end
end
end
end

View File

@ -1,78 +0,0 @@
require "fiber"
require "pry"
module BetterErrors
module REPL
class Pry
class Input
def readline
Fiber.yield
end
end
class Output
def initialize
@buffer = ""
end
def puts(*args)
args.each do |arg|
@buffer << "#{arg.chomp}\n"
end
end
def tty?
false
end
def read_buffer
@buffer
ensure
@buffer = ""
end
end
def initialize(binding)
@fiber = Fiber.new do
@pry.repl binding
end
@input = Input.new
@output = Output.new
@pry = ::Pry.new input: @input, output: @output
@pry.hooks.clear_all if defined?(@pry.hooks.clear_all)
@fiber.resume
end
def send_input(str)
local ::Pry.config, color: false, pager: false do
@fiber.resume "#{str}\n"
[@output.read_buffer, *prompt]
end
end
def prompt
if indent = @pry.instance_variable_get(:@indent) and !indent.indent_level.empty?
["..", indent.indent_level]
else
[">>", ""]
end
rescue
[">>", ""]
end
private
def local(obj, attrs)
old_attrs = {}
attrs.each do |k, v|
old_attrs[k] = obj.send k
obj.send "#{k}=", v
end
yield
ensure
old_attrs.each do |k, v|
obj.send "#{k}=", v
end
end
end
end
end

View File

@ -1,111 +0,0 @@
require "set"
module BetterErrors
# @private
class StackFrame
def self.from_exception(exception)
RaisedException.new(exception).backtrace
end
attr_reader :filename, :line, :name, :frame_binding
def initialize(filename, line, name, frame_binding = nil)
@filename = filename
@line = line
@name = name
@frame_binding = frame_binding
set_pretty_method_name if frame_binding
end
def application?
if root = BetterErrors.application_root
filename.index(root) == 0 && filename.index("#{root}/vendor") != 0
end
end
def application_path
filename[(BetterErrors.application_root.length+1)..-1]
end
def gem?
Gem.path.any? { |path| filename.index(path) == 0 }
end
def gem_path
if path = Gem.path.detect { |path| filename.index(path) == 0 }
gem_name_and_version, path = filename.sub("#{path}/gems/", "").split("/", 2)
/(?<gem_name>.+)-(?<gem_version>[\w.]+)/ =~ gem_name_and_version
"#{gem_name} (#{gem_version}) #{path}"
end
end
def class_name
@class_name
end
def method_name
@method_name || @name
end
def context
if gem?
:gem
elsif application?
:application
else
:dunno
end
end
def pretty_path
case context
when :application; application_path
when :gem; gem_path
else filename
end
end
def local_variables
return {} unless frame_binding
frame_binding.eval("local_variables").each_with_object({}) do |name, hash|
if defined?(frame_binding.local_variable_get)
hash[name] = frame_binding.local_variable_get(name)
else
hash[name] = frame_binding.eval(name.to_s)
end
end
end
def instance_variables
return {} unless frame_binding
Hash[visible_instance_variables.map { |x|
[x, frame_binding.eval(x.to_s)]
}]
end
def visible_instance_variables
frame_binding.eval("instance_variables") - BetterErrors.ignored_instance_variables
end
def to_s
"#{pretty_path}:#{line}:in `#{name}'"
end
private
def set_pretty_method_name
name =~ /\A(block (\([^)]+\) )?in )?/
recv = frame_binding.eval("self")
return unless method_name = frame_binding.eval("::Kernel.__method__")
if Module === recv
@class_name = "#{$1}#{recv}"
@method_name = ".#{method_name}"
else
@class_name = "#{$1}#{Kernel.instance_method(:class).bind(recv).call}"
@method_name = "##{method_name}"
end
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
<%== text_heading("=", "%s at %s" % [exception.type, request_path]) %>
> <%== exception.message %>
<% if backtrace_frames.any? %>
<%== text_heading("-", "%s, line %i" % [first_frame.pretty_path, first_frame.line]) %>
``` ruby
<%== text_formatted_code_block(first_frame) %>```
App backtrace
-------------
<%== application_frames.map { |s| " - #{s}" }.join("\n") %>
Full backtrace
--------------
<%== backtrace_frames.map { |s| " - #{s}" }.join("\n") %>
<% end %>

View File

@ -1,70 +0,0 @@
<header class="trace_info clearfix">
<div class="title">
<h2 class="name"><%= @frame.name %></h2>
<div class="location"><span class="filename"><a href="<%= editor_url(@frame) %>"><%= @frame.pretty_path %></a></span></div>
</div>
<div class="code_block clearfix">
<%== html_formatted_code_block @frame %>
</div>
<% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
<div class="repl">
<div class="console">
<pre></pre>
<div class="prompt"><span>&gt;&gt;</span> <input/></div>
</div>
</div>
<% end %>
</header>
<% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
<div class="hint">
This is a live shell. Type in here.
</div>
<div class="variable_info"></div>
<% end %>
<% unless BetterErrors.binding_of_caller_available? %>
<div class="hint">
<strong>Tip:</strong> add <code>gem "binding_of_caller"</code> to your Gemfile to enable the REPL and local/instance variable inspection.
</div>
<% end %>
<div class="sub">
<h3>Request info</h3>
<div class='inset variables'>
<table class="var_table">
<% if rails_params %>
<tr><td class="name">Request parameters</td><td><pre><%== inspect_value rails_params %></pre></td></tr>
<% end %>
<% if rack_session %>
<tr><td class="name">Rack session</td><td><pre><%== inspect_value rack_session %></pre></td></tr>
<% end %>
</table>
</div>
</div>
<div class="sub">
<h3>Local Variables</h3>
<div class='inset variables'>
<table class="var_table">
<% @frame.local_variables.each do |name, value| %>
<tr><td class="name"><%= name %></td><td><pre><%== inspect_value value %></pre></td></tr>
<% end %>
</table>
</div>
</div>
<div class="sub">
<h3>Instance Variables</h3>
<div class="inset variables">
<table class="var_table">
<% @frame.instance_variables.each do |name, value| %>
<tr><td class="name"><%= name %></td><td><pre><%== inspect_value value %></pre></td></tr>
<% end %>
</table>
</div>
</div>
<!-- <%= Time.now.to_f - @var_start_time %> seconds -->

View File

@ -1,3 +0,0 @@
module BetterErrors
VERSION = "1.1.0"
end

View File

@ -1,92 +0,0 @@
require "spec_helper"
module BetterErrors
describe CodeFormatter do
let(:filename) { File.expand_path("../support/my_source.rb", __FILE__) }
let(:formatter) { CodeFormatter.new(filename, 8) }
it "picks an appropriate scanner" do
formatter.coderay_scanner.should == :ruby
end
it "shows 5 lines of context" do
formatter.line_range.should == (3..13)
formatter.context_lines.should == [
"three\n",
"four\n",
"five\n",
"six\n",
"seven\n",
"eight\n",
"nine\n",
"ten\n",
"eleven\n",
"twelve\n",
"thirteen\n"
]
end
it "works when the line is right on the edge" do
formatter = CodeFormatter.new(filename, 20)
formatter.line_range.should == (15..20)
end
describe CodeFormatter::HTML do
it "highlights the erroring line" do
formatter = CodeFormatter::HTML.new(filename, 8)
formatter.output.should =~ /highlight.*eight/
end
it "works when the line is right on the edge" do
formatter = CodeFormatter::HTML.new(filename, 20)
formatter.output.should_not == formatter.source_unavailable
end
it "doesn't barf when the lines don't make any sense" do
formatter = CodeFormatter::HTML.new(filename, 999)
formatter.output.should == formatter.source_unavailable
end
it "doesn't barf when the file doesn't exist" do
formatter = CodeFormatter::HTML.new("fkdguhskd7e l", 1)
formatter.output.should == formatter.source_unavailable
end
end
describe CodeFormatter::Text do
it "highlights the erroring line" do
formatter = CodeFormatter::Text.new(filename, 8)
formatter.output.should == <<-TEXT.gsub(/^ /, "")
3 three
4 four
5 five
6 six
7 seven
> 8 eight
9 nine
10 ten
11 eleven
12 twelve
13 thirteen
TEXT
end
it "works when the line is right on the edge" do
formatter = CodeFormatter::Text.new(filename, 20)
formatter.output.should_not == formatter.source_unavailable
end
it "doesn't barf when the lines don't make any sense" do
formatter = CodeFormatter::Text.new(filename, 999)
formatter.output.should == formatter.source_unavailable
end
it "doesn't barf when the file doesn't exist" do
formatter = CodeFormatter::Text.new("fkdguhskd7e l", 1)
formatter.output.should == formatter.source_unavailable
end
end
end
end

View File

@ -1,76 +0,0 @@
require "spec_helper"
module BetterErrors
describe ErrorPage do
let!(:exception) { raise ZeroDivisionError, "you divided by zero you silly goose!" rescue $! }
let(:error_page) { ErrorPage.new exception, { "PATH_INFO" => "/some/path" } }
let(:response) { error_page.render }
let(:empty_binding) {
local_a = :value_for_local_a
local_b = :value_for_local_b
@inst_c = :value_for_inst_c
@inst_d = :value_for_inst_d
binding
}
it "includes the error message" do
response.should include("you divided by zero you silly goose!")
end
it "includes the request path" do
response.should include("/some/path")
end
it "includes the exception class" do
response.should include("ZeroDivisionError")
end
context "variable inspection" do
let(:exception) { empty_binding.eval("raise") rescue $! }
if BetterErrors.binding_of_caller_available?
it "shows local variables" do
html = error_page.do_variables("index" => 0)[:html]
html.should include("local_a")
html.should include(":value_for_local_a")
html.should include("local_b")
html.should include(":value_for_local_b")
end
else
it "tells the user to add binding_of_caller to their gemfile to get fancy features" do
html = error_page.do_variables("index" => 0)[:html]
html.should include(%{gem "binding_of_caller"})
end
end
it "shows instance variables" do
html = error_page.do_variables("index" => 0)[:html]
html.should include("inst_c")
html.should include(":value_for_inst_c")
html.should include("inst_d")
html.should include(":value_for_inst_d")
end
it "shows filter instance variables" do
BetterErrors.stub(:ignored_instance_variables).and_return([ :@inst_d ])
html = error_page.do_variables("index" => 0)[:html]
html.should include("inst_c")
html.should include(":value_for_inst_c")
html.should_not include('<td class="name">@inst_d</td>')
html.should_not include("<pre>:value_for_inst_d</pre>")
end
end
it "doesn't die if the source file is not a real filename" do
exception.stub(:backtrace).and_return([
"<internal:prelude>:10:in `spawn_rack_application'"
])
response.should include("Source unavailable")
end
end
end

View File

@ -1,146 +0,0 @@
require "spec_helper"
module BetterErrors
describe Middleware do
let(:app) { Middleware.new(->env { ":)" }) }
let(:exception) { RuntimeError.new("oh no :(") }
it "passes non-error responses through" do
app.call({}).should == ":)"
end
it "calls the internal methods" do
app.should_receive :internal_call
app.call("PATH_INFO" => "/__better_errors/1/preform_awesomness")
end
it "calls the internal methods on any subfolder path" do
app.should_receive :internal_call
app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors/1/preform_awesomness")
end
it "shows the error page" do
app.should_receive :show_error_page
app.call("PATH_INFO" => "/__better_errors/")
end
it "shows the error page on any subfolder path" do
app.should_receive :show_error_page
app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors/")
end
it "doesn't show the error page to a non-local address" do
app.should_not_receive :better_errors_call
app.call("REMOTE_ADDR" => "1.2.3.4")
end
it "shows to a whitelisted IP" do
BetterErrors::Middleware.allow_ip! '77.55.33.11'
app.should_receive :better_errors_call
app.call("REMOTE_ADDR" => "77.55.33.11")
end
it "doesn't blow up when given a blank REMOTE_ADDR" do
expect { app.call("REMOTE_ADDR" => " ") }.to_not raise_error
end
it "doesn't blow up when given an IP address with a zone index" do
expect { app.call("REMOTE_ADDR" => "0:0:0:0:0:0:0:1%0" ) }.to_not raise_error
end
context "when requesting the /__better_errors manually" do
let(:app) { Middleware.new(->env { ":)" }) }
it "shows that no errors have been recorded" do
status, headers, body = app.call("PATH_INFO" => "/__better_errors")
body.join.should match /No errors have been recorded yet./
end
it "shows that no errors have been recorded on any subfolder path" do
status, headers, body = app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors")
body.join.should match /No errors have been recorded yet./
end
end
context "when handling an error" do
let(:app) { Middleware.new(->env { raise exception }) }
it "returns status 500" do
status, headers, body = app.call({})
status.should == 500
end
context "original_exception" do
class OriginalExceptionException < Exception
attr_reader :original_exception
def initialize(message, original_exception = nil)
super(message)
@original_exception = original_exception
end
end
it "shows Original Exception if it responds_to and has an original_exception" do
app = Middleware.new(->env {
raise OriginalExceptionException.new("Other Exception", Exception.new("Original Exception"))
})
status, _, body = app.call({})
status.should == 500
body.join.should_not match(/Other Exception/)
body.join.should match(/Original Exception/)
end
it "won't crash if the exception responds_to but doesn't have an original_exception" do
app = Middleware.new(->env {
raise OriginalExceptionException.new("Other Exception")
})
status, _, body = app.call({})
status.should == 500
body.join.should match(/Other Exception/)
end
end
it "returns ExceptionWrapper's status_code" do
ad_ew = double("ActionDispatch::ExceptionWrapper")
ad_ew.stub('new').with({}, exception ){ double("ExceptionWrapper", status_code: 404) }
stub_const('ActionDispatch::ExceptionWrapper', ad_ew)
status, headers, body = app.call({})
status.should == 404
end
it "returns UTF-8 error pages" do
status, headers, body = app.call({})
headers["Content-Type"].should match /charset=utf-8/
end
it "returns text pages by default" do
status, headers, body = app.call({})
headers["Content-Type"].should match /text\/plain/
end
it "returns HTML pages by default" do
# Chrome's 'Accept' header looks similar this.
status, headers, body = app.call("HTTP_ACCEPT" => "text/html,application/xhtml+xml;q=0.9,*/*")
headers["Content-Type"].should match /text\/html/
end
it "logs the exception" do
logger = Object.new
logger.should_receive :fatal
BetterErrors.stub(:logger).and_return(logger)
app.call({})
end
end
end
end

View File

@ -1,52 +0,0 @@
require "spec_helper"
module BetterErrors
describe RaisedException do
let(:exception) { RuntimeError.new("whoops") }
subject { RaisedException.new(exception) }
its(:exception) { should == exception }
its(:message) { should == "whoops" }
its(:type) { should == RuntimeError }
context "when the exception wraps another exception" do
let(:original_exception) { RuntimeError.new("something went wrong!") }
let(:exception) { double(:original_exception => original_exception) }
its(:exception) { should == original_exception }
its(:message) { should == "something went wrong!" }
end
context "when the exception is a syntax error" do
let(:exception) { SyntaxError.new("foo.rb:123: you made a typo!") }
its(:message) { should == "you made a typo!" }
its(:type) { should == SyntaxError }
it "has the right filename and line number in the backtrace" do
subject.backtrace.first.filename.should == "foo.rb"
subject.backtrace.first.line.should == 123
end
end
context "when the exception is a HAML syntax error" do
before do
stub_const("Haml::SyntaxError", Class.new(SyntaxError))
end
let(:exception) {
Haml::SyntaxError.new("you made a typo!").tap do |ex|
ex.set_backtrace(["foo.rb:123", "haml/internals/blah.rb:123456"])
end
}
its(:message) { should == "you made a typo!" }
its(:type) { should == Haml::SyntaxError }
it "has the right filename and line number in the backtrace" do
subject.backtrace.first.filename.should == "foo.rb"
subject.backtrace.first.line.should == 123
end
end
end
end

View File

@ -1,18 +0,0 @@
require "spec_helper"
require "better_errors/repl/basic"
require "better_errors/repl/shared_examples"
module BetterErrors
module REPL
describe Basic do
let(:fresh_binding) {
local_a = 123
binding
}
let(:repl) { Basic.new fresh_binding }
it_behaves_like "a REPL provider"
end
end
end

View File

@ -1,40 +0,0 @@
require "spec_helper"
require "pry"
require "better_errors/repl/pry"
require "better_errors/repl/shared_examples"
module BetterErrors
module REPL
describe Pry do
let(:fresh_binding) {
local_a = 123
binding
}
let(:repl) { Pry.new fresh_binding }
it "does line continuation" do
output, prompt, filled = repl.send_input ""
output.should == "=> nil\n"
prompt.should == ">>"
filled.should == ""
output, prompt, filled = repl.send_input "def f(x)"
output.should == ""
prompt.should == ".."
filled.should == " "
output, prompt, filled = repl.send_input "end"
if RUBY_VERSION >= "2.1.0"
output.should == "=> :f\n"
else
output.should == "=> nil\n"
end
prompt.should == ">>"
filled.should == ""
end
it_behaves_like "a REPL provider"
end
end
end

View File

@ -1,18 +0,0 @@
shared_examples_for "a REPL provider" do
it "evaluates ruby code in a given context" do
repl.send_input("local_a = 456")
fresh_binding.eval("local_a").should == 456
end
it "returns a tuple of output and the new prompt" do
output, prompt = repl.send_input("1 + 2")
output.should == "=> 3\n"
prompt.should == ">>"
end
it "doesn't barf if the code throws an exception" do
output, prompt = repl.send_input("raise Exception")
output.should include "Exception: Exception"
prompt.should == ">>"
end
end

View File

@ -1,157 +0,0 @@
require "spec_helper"
module BetterErrors
describe StackFrame do
context "#application?" do
it "is true for application filenames" do
BetterErrors.stub(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
frame.application?.should be_true
end
it "is false for everything else" do
BetterErrors.stub(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/nope", 123, "foo")
frame.application?.should be_false
end
it "doesn't care if no application_root is set" do
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
frame.application?.should be_false
end
end
context "#gem?" do
it "is true for gem filenames" do
Gem.stub(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
frame.gem?.should be_true
end
it "is false for everything else" do
Gem.stub(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/nope", 123, "foo")
frame.gem?.should be_false
end
end
context "#application_path" do
it "chops off the application root" do
BetterErrors.stub(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
frame.application_path.should == "app/controllers/crap_controller.rb"
end
end
context "#gem_path" do
it "chops of the gem path and stick (gem) there" do
Gem.stub(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
end
it "prioritizes gem path over application path" do
BetterErrors.stub(:application_root).and_return("/abc/xyz")
Gem.stub(:path).and_return(["/abc/xyz/vendor"])
frame = StackFrame.new("/abc/xyz/vendor/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
end
end
context "#pretty_path" do
it "returns #application_path for application paths" do
BetterErrors.stub(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
frame.pretty_path.should == frame.application_path
end
it "returns #gem_path for gem paths" do
Gem.stub(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
frame.pretty_path.should == frame.gem_path
end
end
it "special cases SyntaxErrors" do
begin
eval(%{ raise SyntaxError, "you wrote bad ruby!" }, nil, "my_file.rb", 123)
rescue SyntaxError => syntax_error
end
frames = StackFrame.from_exception(syntax_error)
frames.first.filename.should == "my_file.rb"
frames.first.line.should == 123
end
it "doesn't blow up if no method name is given" do
error = StandardError.allocate
error.stub(:backtrace).and_return(["foo.rb:123"])
frames = StackFrame.from_exception(error)
frames.first.filename.should == "foo.rb"
frames.first.line.should == 123
error.stub(:backtrace).and_return(["foo.rb:123: this is an error message"])
frames = StackFrame.from_exception(error)
frames.first.filename.should == "foo.rb"
frames.first.line.should == 123
end
it "ignores a backtrace line if its format doesn't make any sense at all" do
error = StandardError.allocate
error.stub(:backtrace).and_return(["foo.rb:123:in `foo'", "C:in `find'", "bar.rb:123:in `bar'"])
frames = StackFrame.from_exception(error)
frames.count.should == 2
end
it "doesn't blow up if a filename contains a colon" do
error = StandardError.allocate
error.stub(:backtrace).and_return(["crap:filename.rb:123"])
frames = StackFrame.from_exception(error)
frames.first.filename.should == "crap:filename.rb"
end
it "doesn't blow up with a BasicObject as frame binding" do
obj = BasicObject.new
def obj.my_binding
::Kernel.binding
end
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index", obj.my_binding)
frame.class_name.should == 'BasicObject'
end
it "sets method names properly" do
obj = "string"
def obj.my_method
begin
raise "foo"
rescue => err
err
end
end
frame = StackFrame.from_exception(obj.my_method).first
if BetterErrors.binding_of_caller_available?
frame.method_name.should == "#my_method"
frame.class_name.should == "String"
else
frame.method_name.should == "my_method"
frame.class_name.should == nil
end
end
if RUBY_ENGINE == "java"
it "doesn't blow up on a native Java exception" do
expect { StackFrame.from_exception(java.lang.Exception.new) }.to_not raise_error
end
end
end
end

View File

@ -1,20 +0,0 @@
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
thirteen
fourteen
fifteen
sixteen
seventeen
eighteen
nineteen
twenty

View File

@ -1,73 +0,0 @@
require "spec_helper"
describe BetterErrors do
context ".editor" do
it "defaults to textmate" do
subject.editor["foo.rb", 123].should == "txmt://open?url=file://foo.rb&line=123"
end
it "url escapes the filename" do
subject.editor["&.rb", 0].should == "txmt://open?url=file://%26.rb&line=0"
end
[:emacs, :emacsclient].each do |editor|
it "uses emacs:// scheme when set to #{editor.inspect}" do
subject.editor = editor
subject.editor[].should start_with "emacs://"
end
end
[:macvim, :mvim].each do |editor|
it "uses mvim:// scheme when set to #{editor.inspect}" do
subject.editor = editor
subject.editor[].should start_with "mvim://"
end
end
[:sublime, :subl, :st].each do |editor|
it "uses subl:// scheme when set to #{editor.inspect}" do
subject.editor = editor
subject.editor[].should start_with "subl://"
end
end
[:textmate, :txmt, :tm].each do |editor|
it "uses txmt:// scheme when set to #{editor.inspect}" do
subject.editor = editor
subject.editor[].should start_with "txmt://"
end
end
["emacsclient", "/usr/local/bin/emacsclient"].each do |editor|
it "uses emacs:// scheme when EDITOR=#{editor}" do
ENV["EDITOR"] = editor
subject.editor = subject.default_editor
subject.editor[].should start_with "emacs://"
end
end
["mvim -f", "/usr/local/bin/mvim -f"].each do |editor|
it "uses mvim:// scheme when EDITOR=#{editor}" do
ENV["EDITOR"] = editor
subject.editor = subject.default_editor
subject.editor[].should start_with "mvim://"
end
end
["subl -w", "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl"].each do |editor|
it "uses mvim:// scheme when EDITOR=#{editor}" do
ENV["EDITOR"] = editor
subject.editor = subject.default_editor
subject.editor[].should start_with "subl://"
end
end
["mate -w", "/usr/bin/mate -w"].each do |editor|
it "uses txmt:// scheme when EDITOR=#{editor}" do
ENV["EDITOR"] = editor
subject.editor = subject.default_editor
subject.editor[].should start_with "txmt://"
end
end
end
end

View File

@ -1,5 +0,0 @@
$: << File.expand_path("../../lib", __FILE__)
ENV["EDITOR"] = nil
require "better_errors"

View File

@ -1,9 +0,0 @@
module Kernel
alias_method :require_with_binding_of_caller, :require
def require(feature)
raise LoadError if feature == "binding_of_caller"
require_with_binding_of_caller(feature)
end
end

View File

@ -0,0 +1,30 @@
#coding=utf-8
#!/usr/bin/env python
# 脚本用于刷新版本库由git hooks里进行调用传入参数为git仓库路径
# 需要配置rails项目地址
# 必须装此文件放在git的存放目录现在是 /home/pdl/redmine-2.3.2-0/apache2/htdocs
import sys
import os
import urllib
import urllib2
RAILS_URL = 'http://192.168.128.128:3000/'
def get_git_path():
return sys.argv[1]
path=os.path.realpath(sys.argv[0])
if os.path.isfile(path):
path=os.path.dirname(os.path.dirname(path))
return os.path.abspath(path)
def post_http_data(url, data):
data_urlencode = urllib.urlencode(data)
req = urllib2.Request(url = url,data =data_urlencode)
res_data = urllib2.urlopen(req)
#res = res_data.read()
#return res
path = get_git_path()
post_http_data(RAILS_URL + 'git_callback/post_update', {'root_url': path})

View File

@ -1,9 +0,0 @@
language: ruby
rvm:
- 1.9.3
- 2.0.0
- 2.1.1
bundler_args: ""
services:
- redis
- memcached

View File

@ -1,181 +0,0 @@
28-June-2012 - Sam
* Started change log
* Corrected profiler so it properly captures POST requests (was supressing non 200s)
* Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
* Fixed bug where unviewed missing ids never got cleared
* Supress all '/assets/' in the rails tie (makes debugging easier)
* record_sql was mega buggy
* added MemcacheStore
9-July-2012 - Sam
* Cleaned up mechanism for profiling in production, all you need to do now
is call Rack::MiniProfiler.authorize_request to get profiling working in
production
* Added option to display full backtraces pp=full-backtrace
* Cleaned up railties, got rid of the post authorize callback
* Version 0.1.3
12-July-2012 - Sam
* Fixed incorrect profiling steps (was not indenting or measuring start time right
* Implemented native PG and MySql2 interceptors, this gives way more accurate times
* Refactored context so its a proper class and not a hash
* Added some more client probing built in to rails
* More tests
18-July-2012 - Sam
* Added First Paint time for chrome
* Bug fix to ensure non Rails installs have mini profiler
* Version 0.1.7
30-July-2012 - Sam
* Made compliant with ancient versions of Rack (including Rack used by Rails2)
* Fixed broken share link
* Fixed crashes on startup (in MemoryStore and FileStore)
* Version 0.1.8
* Unicode fix
* Version 0.1.9
7-August-2012 - Sam
* Added option to disable profiler for the current session (pp=disable / pp=enable)
* yajl compatability contributed by Sven Riedel
10-August-2012 - Sam
* Added basic prepared statement profiling for postgres
20-August-2012 - Sam
* 1.12.pre
* Cap X-MiniProfiler-Ids at 10, otherwise the header can get killed
3-September-2012 - Sam
* 1.13.pre
* pg gem prepared statements were not being logged correctly
* added setting config.backtrace_ignores = [] - an array of regexes that match on caller lines that get ignored
* added setting config.backtrace_includes = [] - an array of regexes that get included in the trace by default
* cleaned up the way client settings are stored
* made pp=full-backtrace "sticky"
* added pp=normal-backtrace to clear the "sticky" state
* change "pp=sample" to work with "caller" no need for stack trace gem
4-September-2012 - Sam
* 1.15.pre
* fixed annoying bug where client settings were not sticking
* fixed long standing issue with Rack::ConditionalGet stopping MiniProfiler from working properly
5-September-2012 - Sam
* 1.16
* fixed long standing problem specs (issue with memory store)
* fixed issue where profiler would be dumped when you got a 404 in production (and any time rails is bypassed)
* implemented stacktrace properly
9-September-2012 - Sam
* 1.17
* pp=sample was bust unless stacktrace was installed
10-September-2012 - Sam
* 1.19
* fix compat issue with 1.8.7
12-September-2012 - Sam
* 1.20
* Added pp=profile-gc , it allows you to profile the GC in Ruby 1.9.3
17-September-2012
* 1.21
* New MemchacedStore
* Rails 4 support
17-September-2012
* Allow rack-mini-profiler to be sourced from github
* Extracted the pp=profile-gc-time out, the object space profiler needs to disable gc
20-September-2012
* 1.22
* Fix permission issue in the gem
8-April-2013
* 1.24
* Flame Graph Support see: http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler
* Fix file retention leak in file_store
* New toggle_shortcut and start_hidden options
* Fix for AngularJS support and MooTools
* More robust gc profiling
* Mongoid support
* Fix for html5 implicit body tags
* script tag initialized via data-attributes
* new - Rack::MiniProfiler.counter counter_name {}
* Allow usage of existing jQuery if its already loaded
* Fix pp=enable
* 1.8.7 support ... grrr
* Net:HTTP profiling
* pre authorize to run in all non development? and production? modes
8-April-2013
* 1.25
* Missed flamegraph.html from build
11-April-2013
* 1.26
* (minor) allow Rack::MiniProfilerRails.initialize!(Rails.application), for post config intialization
26-June-2013
* 1.27
* Disable global ajax handlers on MP requests @JP
* Add Rack::MiniProfiler.config.backtrace_threshold_ms
* jQuery 2.0 support
18-July-2013
* 1.28
* diagnostics in abstract storage was raising not implemented killing
?pp=env and others
* SOLR xml unescaped by mistake
20-August-2013
* 1.29
* Bugfix: SOLR patching had an incorrect monkey patch
* Implemented exception tracing using TracePoint see pp=trace-exceptions
30-August-2013
* 1.30
* Feature: Added Rack::MiniProfiler.counter_method(klass,name) for injecting counters
* Bug: Counters were not shifting the table correctly
3-September-2013
* Ripped out flamegraph so it can be isolated into a gem
* Flamegraph now has much increased fidelity
* Ripped out pp=sample it just was never really used
17-September-2013 - Ross Wilson
* Instead of supressing all "/assets/" requests we now check the configured
config.assets.prefix path since developers can rename the path to serve Asset Pipeline
files from
12-December-2013 - Sam Saffron
* Version 0.9.0.pre (bumped up to reflect the stability of the project)
* Improved reports for pp=profile-gc
* pp=flamegraph&flamegraph_sample_rate=1 , allow you to specify sampling rates
13-March-2014 - Sam Saffron
* Version 0.9.1
* Added back Ruby 1.8 support (thanks Malet)
* Corrected Rails 3.0 support (thanks Zlatko)
* Corrected fix possible XSS (admin only)
* Amend Railstie so MiniProfiler can be launched with action view or action controller (Thanks Akira)
* Corrected Sql patching to avoid setting instance vars on nil which is frozen (thanks Andy, huoxito)

Some files were not shown because too many files have changed in this diff Show More