diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a2e5948a..e3dd080f 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,7448 +1,7448 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require 'forwardable'
-require 'cgi'
-require 'iconv'
-module ApplicationHelper
- include Redmine::WikiFormatting::Macros::Definitions
- include Redmine::I18n
- include GravatarHelper::PublicMethods
- include Redmine::Pagination::Helper
- include AvatarHelper
- ## added by william
- include PraiseTreadHelper
- include CoursesHelper
-
- extend Forwardable
- def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
-
- # 课堂相关controller
- def course_controller
- ["courses", "homework_common", "student_work", "exercise", "poll", "boards", "messages", "graduation_topics", "graduation_tasks",
- "graduation_works", "files"]
- end
-
- # 实训课程相关controller
- def subjects_controller
- ["subjects", "stages"]
- end
-
- # 实训路径相关controller
- def shixuns_controller
- ["shixuns", "challenges", "myshixuns", "games"]
- end
-
- # 工程认证相关controller
- def ecs_controller
- ["ecs", "ec_courses", "ec_course_evaluations", "ec_course_supports", "ec_course_targets", "ec_graduation_requirements",
- "ec_major_schools", "ec_majors", "ec_years"]
- end
-
- def exercise_bank_json_data exercises
- exercises.map do |exercise|
- exercise_path = exercise_bank_path(exercise)
- course_list = exercise.course_list.name
- user_name = exercise.user.show_real_name
- user_path = user_path(exercise.user)
- exercise.attributes.dup.except("description", "is_public", "quotes", "container_id", "container_type", "created_at", "updated_at").merge({
- user_name: user_name,
- user_path: user_path,
- course_list: course_list,
- exercise_path: exercise_path
- })
- end
- end
-
- def ac_pass?(standard_value, real_value)
- standard_value && real_value && real_value >= standard_value ? "达成" : "未达成"
- end
-
- def ec_pass?(standard_value, real_value)
- standard_value && real_value && real_value >= standard_value ? 1 : 0
- end
-
- # 工程认证删除关联课堂
- def delete_course_correlation_ec_course_evaluations ec_course
- ec_course_evaluations = ec_course.ec_course_evaluations.where(:is_course_type => true)
- ec_course_evaluations.destroy_all if ec_course_evaluations
- end
-
- def sync_ec_year_student_score ec_subitem, ce, year_students, students, works, position=1
- year_students.each do |year_student|
- if students.map(&:id).include?(year_student.id)
- work = works.where(:user_id => students.select{|s| s.id == year_student.id}[0].try(:user_id)).first
- score = work.respond_to?(:work_score) ? work.try(:work_score) : work.try(:score)
- else
- score = 0
- end
- ec_subitem.ec_student_achievements << EcStudentAchievement.new(:ec_year_student_id => year_student.id, :student_number => year_student.student_id,
- :student_name => year_student.name, :score => score.to_f,
- :position => position, :ec_course_evaluation_id => ce.id)
- Rails.logger.info("############work_score:#{score}")
- end
- end
-
- # 同步在线课堂的考核标准和考核分项
- # ec_course: 工程认证的课程
- # course: 关联的在线课堂
- def sync_course_correlation_ec_course_evaluations ec_course, course
- # 先删除之前的关联数据
- delete_course_correlation_ec_course_evaluations ec_course
-
- students = EcYearStudent.find_by_sql("SELECT eys.id, eys.student_id, eys.name, uxe.user_id FROM ec_year_students eys JOIN
- (SELECT ue.student_id, ue.user_id FROM user_extensions ue JOIN students_for_courses sfc ON ue.`user_id` = sfc.`student_id`
- WHERE sfc.`course_id` = #{course.id})uxe ON eys.student_id = uxe.student_id WHERE eys.ec_year_id = #{ec_course.ec_year_id}")
-
- year_students = ec_course.ec_year.ec_year_students
-
- # 实训作业模块
- shixun_models = course.homework_commons.where("homework_type = 4 and publish_time < '#{Time.now}'")
- unless shixun_models.blank?
- ce = EcCourseEvaluation.create(:name => "实训作业", :evluation_count => 1, :status => 2, :ec_course_id => ec_course.id, :is_course_type => true)
- shixun_models.each do |shixun|
- ec_subitem = EcCourseEvaluationSubitem.create(:name => shixun.name, :ec_course_evaluation_id => ce.id)
-
- sync_ec_year_student_score ec_subitem, ce, year_students, students, shixun.student_works
- end
- end
-
- # 普通作业模块
- common_models = course.homework_commons.where("homework_type = 1 and publish_time < '#{Time.now}'")
- unless common_models.blank?
- ce = EcCourseEvaluation.create(:name => "普通作业", :evluation_count => 1, :status => 2, :ec_course_id => ec_course.id, :is_course_type => true)
- common_models.each do |common|
- ec_subitem = EcCourseEvaluationSubitem.create(:name => common.name, :ec_course_evaluation_id => ce.id)
-
- sync_ec_year_student_score ec_subitem, ce, year_students, students, common.student_works
- end
- end
-
- # 分组作业模块
- group_models = course.homework_commons.where("homework_type = 3 and publish_time < '#{Time.now}'")
- unless group_models.blank?
- ce = EcCourseEvaluation.create(:name => "分组作业", :evluation_count => 1, :status => 2, :ec_course_id => ec_course.id, :is_course_type => true)
- group_models.each do |group|
- ec_subitem = EcCourseEvaluationSubitem.create(:name => group.name, :ec_course_evaluation_id => ce.id)
-
- sync_ec_year_student_score ec_subitem, ce, year_students, students, group.student_works
- end
- end
-
- # 试卷模块
- exercise_models = course.exercises.where("exercise_status > 1")
- unless exercise_models.blank?
- ce = EcCourseEvaluation.create(:name => "试卷", :evluation_count => 1, :status => 2, :ec_course_id => ec_course.id, :is_course_type => true)
- exercise_models.each do |exercise|
- ec_subitem = EcCourseEvaluationSubitem.create(:name => exercise.exercise_name, :ec_course_evaluation_id => ce.id)
-
- sync_ec_year_student_score ec_subitem, ce, year_students, students, exercise.exercise_users
- end
- end
-
- # 毕设任务模块
- task_models = course.graduation_tasks.where("publish_time < '#{Time.now}'")
- unless task_models.blank?
- ce = EcCourseEvaluation.create(:name => "毕设任务", :evluation_count => task_models.size, :status => 1, :ec_course_id => ec_course.id, :is_course_type => true)
- task_models.each_with_index do |task, index|
- ec_subitem = EcCourseEvaluationSubitem.create(:name => task.name, :ec_course_evaluation_id => ce.id)
-
- sync_ec_year_student_score ec_subitem, ce, year_students, students, task.graduation_works, index + 1
- end
- end
- end
-
- # 选用实训的学校情况
- def school_user_detail shixun
- user_ids = shixun.myshixuns.pluck(:user_id)
- schools = School.where(:id => UserExtensions.where(:user_id => user_ids).pluck(:school_id))
- school_size = schools.size
- str = school_size > 0 ? "#{schools.limit(2).map(&:name).join("、")}等 #{school_size}所" : "0所"
- end
-
- def shixun_json_data shixuns
- shixuns.map do |shixun|
- school_detail = school_user_detail shixun
- preference = shixun.shixun_preference
- shixun_path = shixun_path(shixun)
- shixun.attributes.dup.merge({
- school_detail: school_detail,
- preference: preference,
- shixun_path: shixun_path
- })
- end
- end
-
- # 分班
- def member_group_name members, user_id
- member = members.where(:user_id => user_id).first
- group_name = member.try(:course_group_id).to_i == 0 ? '未分班' : member.course_group.name
- end
-
- # 分班
- def new_member_group_name course_id, user_id
- group_id = Member.where(:course_id => course_id, :user_id => user_id).pluck(:course_group_id).first
- group_id == 0 ? '未分班' : CourseGroup.where(:id => group_id).pluck(:name).first
- end
-
- # 分班id
- def member_group_id members, user_id
- member = members.where(:user_id => user_id).first
- group_id = member.try(:course_group_id).to_i
- end
-
- # 推荐实训
- def recommend_shixun shixun
- shixun_id = ShixunTagRepertoire.where("tag_repertoire_id = #{shixun.tag_repertoires.first.present? ? shixun.tag_repertoires.first.try(:id) : 0} and shixun_id != #{shixun.id}").map(&:shixun_id)
- shixuns = Shixun.select([:id, :name, :user_id, :status, :myshixuns_count, :trainee, :identifier]).where(:id => shixun_id, :status => 2, :hidden => 0).order("myshixuns_count desc").limit(3)
- if shixuns.size < 3
- ids = shixuns.size == 0 ? "(-1)" : "(" + shixuns.map(&:id).join(',') + ")"
- hot_shixuns = Shixun.select([:id, :name, :user_id, :status, :myshixuns_count, :trainee, :identifier]).where("status = 2 and hidden = 0 and id not in #{ids}").order("myshixuns_count desc").limit(3-shixuns.size)
- return shixuns + hot_shixuns
- else
- return shixuns
- end
- end
-
- # 用户获取的技能标签
- def user_get_tags challenge_ids, user=User.current
- tags = ChallengeTag.where(:challenge_id => user.games.where(:challenge_id => challenge_ids, :status => 2).pluck(:challenge_id)).pluck(:name).uniq
- return tags
- end
-
- # 所属路径
- def belongto_path shixun
- Subject.where(:id => shixun.stage_shixuns.map(&:subject_id), :hidden => 0).limit(2)
- end
-
- # 已授权老师加入示例课堂
- def join_ex_course user
- course = Course.where(:id => 1309).first
- if course
- if course.members.where(:user_id => user.id).empty?
- member = Member.new(:role_ids => [9], :user_id => user.id)
- course.members << member
- Tiding.create(:user_id => user.id, :trigger_user_id => 1, :container_id => course.id, :container_type => 'TeacherJoinCourse', :belong_container_id => course.id, :belong_container_type => "Course", :tiding_type => "System", :extra => "9")
- end
- end
- end
-
-# 成员身份
- def member_zh_role member
- role = ""
- if member.roles.first
- case member.roles.first.id
- when 3
- role = "管理人员"
- when 4
- role = "开发人员"
- when 5
- role = "报告人员"
- end
- end
- end
-
- def container_limit mirror_repositories
- container = []
- mirror_repositories.each do |mr|
- if mr.name.present?
- container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"}
- end
- end
- return container.to_json
- end
-
- # 实训作品列表的提交状态
- def list_work_status work, homework, member
- if work.work_status == 0
- str = "未提交"
- else
- if work.compelete_status == 0
- setting_time = homework_group_setting homework, member.try(:course_group_id)
- end_time = setting_time.end_time.present? ? setting_time.end_time : homework.end_time
- if end_time > Time.now || (homework.allow_late && !homework.course.is_end)
- str = "正在提交"
- else
- str = "延时提交"
- end
- else
- if work.work_status == 1
- str = "按时提交"
- else
- str = "延时提交"
- end
- end
- end
- str
- end
-
- # 试卷、问卷提交状态
- def ex_poll_work_status status
- str = ""
- case status
- when 0
- str = "未提交"
- when 1
- str = "按时提交"
- when 2
- str = "延时提交"
- end
- str
- end
-
- #传入分数,获取对应颜色
- def score_color score
- if score
- color = score >= 90 ? "color-red" : "color-green"
- else
- color = "color-grey"
- end
- color
- end
-
- # 获取两断时间的日期差
- def time_between_days t1, t2
- Date.parse(t1.to_s) - Date.parse(t2.to_s) if t1.present? && t2.present?
- end
-
- def update_valuate_time game_id, column
- record = EvaluateRecord.where(:game_id => game_id).first
- if record
- consume_time = format("%.2f", (Time.now.to_f - record.created_at.to_f)).to_f
- if column == "file_update"
- record.update_attributes!(:file_update => consume_time)
- elsif column == "pull"
- record.update_attributes!(:consume_time => consume_time)
- elsif column == "create_pod"
- record.update_attributes!(:create_pod => consume_time)
- elsif column == "pod_execute"
- record.update_attributes!(:pod_execute => consume_time)
- end
- end
- end
-
- # TPM查看权限
- # result一般为页面权限
- def shixun_view_allow shixun, result = nil
- if User.current.manager_of_shixun?(shixun)
- result ? false : true
- else
- if shixun.status == 0 || (shixun.use_scope == 1 && !shixun.schools.map(&:name).include?(User.current.school_name))
- result ? true : (render_403)
- end
- end
- end
-
- # 判断TPM的代码是否被修改了
- # 判断依据是看tpm的最新提交记录和tpi数据库中存储的commit_id是否一致
- def repository_is_modified myshixun, shixun_gpid
- g = Gitlab.client
- myshixun_commit_id = myshixun.commit_id
- if myshixun_commit_id.blank?
- myshixun_commit_id = g.commits(myshixun.gpid).last.try(:id)
- myshixun.update_column(:commit_id, myshixun_commit_id)
- end
- shixun_commit_id = g.commits(shixun_gpid).first.try(:id)
- Rails.logger.warn("###############shixun_commit_id is #{shixun_commit_id}")
- Rails.logger.warn("###############myshixun_commit_id is #{myshixun.commit_id}")
- result = myshixun_commit_id != shixun_commit_id ? true :false
- return result
- end
-
- # 定义当前关卡是否有权开启下一关
- # :实训若发布了,必须通过当前关卡才能查看下一关
- # :未发布的实训,除了最后一关,其它的关卡都可以进入下一关
- def show_next_stage?(game, shixun_status)
- if game.is_final_game? || ([2,3].include?(shixun_status.to_i) && game.try(:status) != 2)
- false
- else
- true
- end
- end
-
- # 适用与已经用url_safe编码后,回调字符串形式
- def tran_base64_decode64 str
- if str.blank?
- str
- else
- s_size = str.size % 4
- if s_size != 0
- str += "=" * (4 - s_size)
- end
- Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8")
- end
- end
-
- def challenge_path path
- cha_path = path.present? ? path.split(";") : []
- cha_path = cha_path.reject(&:blank?)[0].try(:strip)
- cha_path
- end
-
- def open_webssh
- # 如果我webssh类型, 开启webssh
- jenkins_shixuns = Redmine::Configuration['jenkins_shixuns']
- uri = URI("#{jenkins_shixuns}/jenkins-exec/webssh/getConnectInfo")
- user_id = User.current.id
- params = {userID:user_id}
- res = uri_exec uri, params
- return [host, port, username, password]
- end
-
- # 中间层启动那种语言容器的类型
- # language 语言 exec_path 需要编译的文件路径
- def post_tomcat_language language, exec_path
- if language == "Html" && !exec_path.blank?
- case exec_path.split(".")[1].downcase
- when "c"
- "C"
- when "cpp"
- 'C++'
- when "py"
- 'Python2.7'
- else
- "Java"
- end
- elsif exec_path.blank?
- "Java"
- else
- language
- end
- end
-
- def only_publish_game shixun, type
- shixun_tomcat = Redmine::Configuration['shixun_tomcat']
- gameInfo = shixun.gameInfo
- uri ="#{shixun_tomcat}/bridge/game/publishGame"
- params = {:gameInfo => "#{gameInfo}"}
- logger.info("%%%%%%%%%%%%params is #{params}")
- res = uri_exec uri, params
- if res && res['code'].to_i != 0
- raise("实训云平台繁忙(繁忙等级:90)")
- end
- end
-
- def publish_game_and_tpimodify myshixun, type
- shixun_tomcat = Redmine::Configuration['shixun_tomcat']
- git_myshixun_url = gitlab_url myshixun
- git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url)
- params = {tpiID: "#{myshixun.try(:id)}", :tpiGitURL => "#{git_myshixun_url}", :tpmID => "#{myshixun.shixun.try(:id)}"}
- uri ="#{shixun_tomcat}/bridge/game/resetTpiScript"
- params = {:gameInfo => "#{gameInfo}"}
- logger.info("%%%%%%%%%%%%params is #{params}")
- res = uri_exec uri, params
- if res && res['code'].to_i != 0
- raise("实训云平台繁忙(繁忙等级:98)")
- end
- end
-
- ## 若实训关卡位置,关卡数等信息发生变化则需要修改脚本内容
- def modify_shixun_script shixun, script
- if script.present?
- source_class_name = []
- challenge_program_name = []
- shixun.challenges.map(&:exec_path).each do |exec_path|
- challenge_program_name << "\"#{exec_path}\""
- if shixun.mirror_name.try(:first) == "Java"
- if exec_path.nil? || exec_path.split("src/")[1].nil?
- source = "\"\""
- else
- source = "\"#{exec_path.split("src/")[1].split(".java")[0]}\""
- end
- source_class_name << source.gsub("/", ".") if source.present?
- elsif shixun.mirror_name.try(:first) == "C#"
- if exec_path.nil? || exec_path.split(".")[1].nil?
- source = "\"\""
- else
- source = "\"#{exec_path.split(".")[0]}.exe\""
- end
- source_class_name << source if source.present?
- end
- end
- script = if script.include?("sourceClassName") && script.include?("challengeProgramName")
- script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{source_class_name.reject(&:blank?).join(" ")}\)")
- else
- script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)")
- end
- end
- return script
- #shixun.update_column(:evaluate_script, script)
- end
-
- # 若实训有更改,则修改已发不实训的标记为已更改
- # shixun_modifies表中1表示已更改,进入myshixun需要强制重置,0表示没有修改
- # type 0:表示已经是最新的了;1:表示已经有修改
- # res返回结果0表示正确,-1表示有异常
- def add_shixun_modify_status shixun, type
- shixun_tomcat = Redmine::Configuration['shixun_tomcat']
- gameInfo = shixun.gameInfo
- uri ="#{shixun_tomcat}/bridge/game/publishGame"
- params = {:gameInfo => "#{gameInfo}"}
- logger.info("%%%%%%%%%%%%params is #{params}")
- res = uri_exec uri, params
- if res && res['code'].to_i != 0
- raise("实训云平台繁忙(繁忙等级:90)")
- end
- end
-
- # 判断实训的路径、language是否更改,如果修改在TPI中需要重置脚本
- # 目前为止,container为challenge和game类型
- # 改工作必须在challenge或者game保存后执行
- # type 1:表示既需要提示又需要更新脚本的,0:表示仅仅需要提示
- def should_modify_myshixun_script shixun, type
- if type == 1
- shixun.update_column(:reset_time, shixun.try(:updated_at))
- else
- shixun.update_column(:modify_time, shixun.try(:updated_at))
- end
- end
-
- def shixun_modify_status_publish shixun, type
- shixun_tomcat = Redmine::Configuration['shixun_tomcat']
- # 更新测试集
- gameInfo = shixun.gameInfo
- uri ="#{shixun_tomcat}/bridge/game/publishGame"
- # 更新脚本
- tpiList =[]
- myshixuns = shixun.myshixuns
- if myshixuns.present?
- myshixuns.each do |myshixun|
- logger.info("tpiID is #{myshixun.id}")
- tpiID = myshixun.id
- instanceGitURL = gitlab_url myshixun
- logger.info("instanceGitURL is #{instanceGitURL}")
- tpiList << {:tpiID => tpiID, :instanceGitURL => instanceGitURL}
- logger.info("###############{tpiList.to_json unless tpiList.blank?}")
- end
- end
- tpiList = Base64.urlsafe_encode64(tpiList.to_json) unless tpiList.blank?
- params = {:gameInfo => "#{gameInfo}", :tpiList => "#{tpiList}" }
- logger.info("%%%%%%%%%%%%params is #{params}")
- # end
- res = uri_exec uri, params
- if res && res['code'].to_i != 0
- raise("实训云平台繁忙(繁忙等级:90)")
- end
- end
-
- # 仅仅产生记录,用于已执行publish的方法
- # ShixunModify中status 1:表示有更改,开启实训的时候需要重置,0:表示不需要重置或已重置完成
- def shixun_modify_status_without_publish shixun, type
- myshixuns = shixun.myshixuns
- unless myshixuns.blank?
- myshixuns.each do |myshixun|
- shixun_modify = ShixunModify.where(:shixun_id => shixun.id, :myshixun_id => myshixun.id).first
- if shixun_modify.nil?
- ShixunModify.create!(:shixun_id => shixun.id, :myshixun_id => myshixun.id, :status => type)
- else
- shixun_modify.update_attributes!(:status => type)
- end
- end
- end
- end
-
- # 通关后,把最后一次成功的代码存到数据库
- # type 0 创始内容, 1 最新内容
- def game_passed_code game_id, path, myshixun_gpid, type
- g = Gitlab.client
- rev = rev.nil? ? "master" : rev
- path = path.strip if path.present?
- file_content = g.files(myshixun_gpid, path, rev).content
- if file_content.blank?
- # gitlab缺陷:forked完成,短暂时间内取不了内容的,所以做一个小轮询,间隔0.1秒
- # 超过2秒则失败,需通过页面刷新
- for i in 0..30 do
- sleep(0.1)
- file_content = g.files(myshixun_gpid, path, rev).content
- unless file_content.blank?
- break
- end
- end
- end
- unless file_content.present?
- raise("获取文件代码异常")
- end
- file_content = tran_base64_decode64(file_content)
- game_code = GameCode.where(:game_id => game_id, :path => path).first
- if game_code.nil?
- GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path)
- else
- game_code.update_attributes!(:new_code => file_content)
- end
- end
-
- def game_code_init game_id, path
- game_code = GameCode.where(:game_id => game_id, :path => path).first
- GameCode.create(:game_id => game_id, :path => path) if game_code.blank?
- end
-
- # 判断用户是否认证
- def check_authentication
- # return true
- # if params[:action] == "on_search" || params[:action] == "apply_trail" # 之所以这样处理是为了避开account页面ajax加载
- # return true
- # end
- Rails.logger.info("check_authentication start")
- unless User.current.logged?
- url = request.original_url
- redirect_to signin_path(:back_url => url)
- return
- end
-=begin
- if User.current.created_on.strftime('%Y-%m-%d %H:%M:%S') > "2018-01-01 00:00:00" && User.current.phone.blank?
- redirect_to change_or_bind_path(:type => "phone")
- return
- end
-=end
- user_e = UserExtensions.where(:user_id => User.current.id).first
- if User.current.lastname.blank? || user_e.school_id.blank? || user_e.identity.blank? || User.current.mail.blank?
- redirect_to user_info_path()
- Rails.logger.info("check_authentication end")
- return
- elsif User.current.certification != 1 # 系统没有授权
- day_cer = UserDayCertification.where(:user_id => User.current.id).last
- unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400
- redirect_to my_account_path()
- Rails.logger.info("check_authentication end")
- return
- end
- end
- end
-
- def match_specific_symbol(str)
- str.gsub(" ", "").gsub(/\r\n$/, "").gsub("\r\n", "
").gsub(/\t/, "").html_safe
- end
-
- # textarea 以/r/n开头时,回车效果会被替换,因此先把\r转换成\r 再添加一个\r(直接添加\r不行)
- def match_specific_symbol1(str)
- str.gsub(/\A\r/, "\r\r")
- end
-
- # 积分表中建立记录行为,有过奖励则不重复奖励
- def reward_grade(user, container_id, container_type, score)
- grade = Grade.where(:user_id => user.id, :container_id => container_id, :container_type => container_type).first
- if grade.nil?
- Grade.create!(:user_id => user.id, :container_id => container_id, :container_type => container_type, :score => score)
- user.update_column(:grade, (score.to_i + user.grade.to_i))
- end
- end
-
- def reward_experience(user, container_id, container_type, score)
- experience = Experience.where(:user_id => user.id, :container_id => container_id, :container_type => container_type).first
- if experience.nil?
- Experience.create!(:user_id => user.id, :container_id => container_id, :container_type => container_type, :score => score)
- user.update_column(:experience, (score.to_i + user.experience.to_i))
- end
- end
-
- def shixun_name game_id
- game = Game.where(:id => game_id).first
- game.nil? ? "---" : game.challenge.shixun.name
- end
-
- def grade_shixun_name shixun_id
- shixun = Shixun.where(:id => shixun_id).first
- shixun.nil? ? "---" : shixun.name
- end
-
- def game_position game_id
- game = Game.where(:id => game_id).first
- game.nil? ? "---" : game.challenge.position
- end
-
- def managements_navigation_bar_show menu_type, sub_type, grandchild_type={}
- case menu_type
- when 1
- case sub_type
- when 1 then "统计总表"
- when 2 then "数据变化报表"
- end
- when 2
- sub_type == 1 ? "课程列表" : (sub_type == 2? "课堂列表" : (sub_type == 3? "实训作业" : "项目列表"))
- when 3
- case sub_type
- when 1
- "实训列表"
- when 2
- "实训配置列表"
- when 3
- "已发布的实训"
- when 4
- "已关闭的实训"
- when 5
- "镜像管理"
- when 6
- "学员实训列表"
- when 7
- "镜像类别图片"
- when 8
- "TPI实训列表"
- when 9
- "TPI性能测试结果"
- end
- when 4
- case sub_type
- when 1
- "实训课程列表"
- when 2
- "实训课程配置"
- when 3
- "已发布实训课程"
- end
- when 5
- case sub_type
- when 1
- "竞赛列表"
- end
- when 6
- if sub_type == 1
- link_to('单位列表', departments_part_managements_path()) + "#{grandchild_type[:next_type] == 1 ? " > #{grandchild_type[:school].name}" : ""}"
- elsif sub_type == 3
- "合作伙伴"
- else
- "单位部门列表"
- end
- when 7
- sub_type == 1 ? "用户列表" : (sub_type == 2 ? "试用授权列表" : "自动授权列表")
- when 8
- sub_type == 1 ? "作业回复" :
- (sub_type == 2 ? "实训反馈" :
- (sub_type == 3 ? "讨论区" : "课堂讨论区")
- )
- when 9
- sub_type == 1 ? "实训留言列表" : ""
- when 10
- sub_type == 1 ? "实名认证" :
- (sub_type == 2 ? "试用授权" :
- (sub_type == 3 ? "部门审批" :
- (sub_type == 4 ? "单位审批" :
- (sub_type == 5 ? "实训发布" :
- (sub_type == 6 ? "实训课程发布" : "职业认证")
- )
- )
- )
- )
- when 11
- "工程认证+"
- when 12
- sub_type == 1 ? "过关任务模板" :
- (sub_type == 2 ? "实训简介模板" :
- (sub_type == 3 ? "背景知识模板" :
- (sub_type == 4 ? "通用评测模板" :
- (sub_type == 5 ? "新课导语模板" :
- (sub_type == 6 ? "实训评分设置" :
- (sub_type == 7 ? "技术体系" : "升级通知")
- )
- )
- )
- )
- )
- end
- end
-
-
- # codeMirror语言转换
- def language_switch language
- case language
- when "Java"
- "text/x-java"
- when "C"
- "text/x-csrc"
- when "C++"
- "text/x-c++src"
- when "Python"
- "text/x-python"
- when "Ruby"
- "text/x-ruby"
- end
- end
-
- # 实训语言的种类
- def shixun_language
- ["Java", "C", "C++", "Python2.7", "Python3.6", "MySQL/Java", "Html", "JFinal", "Docker", "Ethereum", "Dynamips", "MachineLearning",
- "Verilog","Spark","MySQL/Python3.6","PHP","PHP/Web","Hadoop", "Golang","Android","Matlab","Shell", "Git", 'Perl6', 'Kotlin', 'Elixir', 'JavaScript', 'Ruby']
- end
-
- # 实训试用专业
- def shixun_major_option
- content = []
- content << ["选择实训适用的专业", 0]
- content << ["计算机科学与技术", 635]
- content << ["软件工程", 636]
- content << ["网络工程", 637]
- content << ["信息安全", 638]
- content << ["物联网工程", 639]
- content << ["信息工程", 622]
- content << ["通信工程", 619]
- end
-
- # 实训面向学员
- def shixun_trainee
- content = []
- content << ["初级学员", 1]
- content << ["中级学员", 2]
- content << ["高级学员", 3]
- content << ["顶级学员", 4]
- end
-
- # 班级设置排序中文
- def switch_to_chinese word
- case word
- when "boards"
- result = "讨论区"
- when "news"
- result = "通知"
- when "homework"
- result = "作业"
- when "exercises"
- result = "试卷"
- when "poll"
- result = "问卷"
- when "statistics"
- result = "统计"
- when "attachment"
- result ="资源"
- end
- return result
- end
-
- def allow_to_view_challenge challenge, shixun
- # 判断对应关卡的game是否开启,如果开启则允许查看
- game_count = Game.where(:challenge_id => challenge, :user_id => User.current, :status => [0,1,2]).count
- if game_count > 0
- return true
- else
- return false
- end
- end
-
- # 已通过的关卡数
- def had_passed_changllenge_count shixun, user
- myshixun = Myshixun.where(:shixun_id => shixun.id, :user_id => user.id).first
- if myshixun.nil?
- 0
- elsif myshixun.games.select{|game| game.status == 2}.count == 0
- -1
- elsif myshixun.games.select{|game| game.status == 0}.count > 0
- [myshixun.games.select{|game| game.status == 2}.count + 1]
- else
- myshixun.games.select{|game| game.status == 2}.count
- end
- end
-
- # 判断TPM已通过的管卡数
- def had_passed_games_count shixun_id, user_id
- #Game.find_by_sql("select count(*) as unpass_count from games where games.status=2 and user_id=#{user_id} and games.challenge_id in (select id from challenges where shixun_id=#{shixun_id})").first.try(:unpass_count)
- Game.find_by_sql("SELECT count(*) cnt FROM `games` g join myshixuns m on m.id = g.myshixun_id where m.user_id = #{user_id} and m.shixun_id = #{shixun_id} and g.status = 2;").first.try(:cnt)
- end
-
- # 用户实训评测状态
- def user_evaluate_status shixun, user
- myshixun = shixun.myshixuns.where(:user_id => user.id).first
- if myshixun.blank?
- "--"
- else
- game_id = myshixun.games.map(&:id)
- output = Output.where(:game_id => game_id).reorder("updated_at desc").first
- if output.blank?
- "--"
- else
- if output.try(:code) == -1
- time_from_now(output.updated_at).to_s + "评测失败"
- else
- time_from_now(output.updated_at).to_s + "评测成功"
- end
- end
- end
- end
-
- def student_work_performance score
- case score
- when (90..100)
- '优秀'
- when (70...90)
- '良好'
- when (60...70)
- '及格'
- when (0...60)
- '不及格'
- end
- end
-
- # 已通过的关卡数 返回int类型(包含查看参考答案的)
- def had_passed_changllenge_num myshixun
- if myshixun.nil?
- 0
- else
- myshixun.games.select{|game| game.status == 2}.count
- end
- end
-
- # 已通过的关卡数 返回int类型(未查看参考答案)
- def had_passed_no_ans_changllenge_num myshixun
- if myshixun.nil?
- 0
- else
- myshixun.games.select{|game| game.status == 2 && game.final_score > 0}.count
- end
- end
-
- # TPI状态 :已通关、未通关、未开启
- def my_shixun_status shixun, user
- status = ""
- myshixun = Myshixun.where(:shixun_id => shixun.id, :user_id => user.id).first
- if myshixun.nil?
- status = "未开启"
- else
- status = myshixun.is_complete? ? "已通关" : "未通关"
- end
- status
- end
-
- # 定义实训相关方法
- def sum_final_score
- Game.find_by_sql("SELECT sum(final_score) as total_score FROM `games` where user_id=#{User.current.id}").first.try(:total_score)
- end
-
- # 获取某个myshixun的得分
- def sum_myshixun_score myshixun_id
- Game.find_by_sql("SELECT sum(final_score) as total_score FROM `games` where myshixun_id=#{myshixun_id}").first.try(:total_score)
- end
-
- # myshixun 最高分
- def top_score shixun, position
- Game.find_by_sql("SELECT max(final_score) as top_score FROM `games` g, `challenges` c where g.challenge_id = c.id and c.position=#{position} and g.myshixun_id in (SELECT id FROM `myshixuns` ms where ms.shixun_id=#{shixun.id})").first.try(:top_score)
- end
-
- # 实训平均分
- def shixun_avg_score shixun, position
- Game.find_by_sql("SELECT avg(g.final_score) as avg_score FROM `games` g, `challenges` c where g.challenge_id=c.id and c.position=#{position} and g.myshixun_id in (SELECT id FROM `myshixuns` ms where ms.shixun_id=#{shixun.id})").first.try(:avg_score)
- end
-
- # 正在进行中任务
- def shixun_running shixun, position
- Shixun.find_by_sql("SELECT count(*) as count FROM `myshixuns` ms, `games` g, `challenges` c where g.myshixun_id = ms.id and ms.shixun_id =#{shixun.id} and g.challenge_id=c.id and c.position=#{position} and g.status in ('0','1');").first.try(:count)
- end
-
- # 已完成任务
- def shixun_done shixun, position
- Shixun.find_by_sql("SELECT count(*) as count FROM `myshixuns` ms, `games` g, `challenges` c where g.myshixun_id = ms.id and ms.shixun_id =#{shixun.id} and g.challenge_id=c.id and c.position=#{position} and g.status=2;").first.try(:count)
- end
-
- # 测评次数
- def shixun_exec_total_count shixun, position
- Game.find_by_sql("SELECT * FROM `outputs` op, `games` g, `myshixuns` m where op.game_id = g.id and g.stage='#{position}' and m.parent_id = '#{shixun.id}';")
- end
-
- # 平均耗时
- def game_avg_day created_at, updated_at
- time = (updated_at - created_at).to_i
- day = time / 86400
- end
-
- # 平均耗时
- def game_avg_hour created_at, updated_at
- time = (updated_at - created_at).to_i
- hour = time % (24*60*60) / (60*60)
- end
-
- # 平均耗时
- def game_avg_min created_at, updated_at
- time = (updated_at - created_at).to_i
- min = time % (24*60*60) % (60*60) / 60
- end
-
- # 耗时:天、小时、分、秒
- # 小于1分钟则不显示
- def game_spend_time time
- day = time / 86400
- hour = time % (24*60*60) / (60*60)
- min = time % (24*60*60) % (60*60) / 60
- sec = time % (24*60*60) % (60*60) % 60
- if day < 1
- if hour < 1
- if min < 1
- if sec < 1
- time = "--"
- else
- time = "#{sec}秒"
- end
- else
- time = "#{min}分钟 #{sec}秒"
- end
- else
- time = "#{hour}小时 #{min}分钟 #{sec}秒"
- end
- else
- time = "#{day}天 #{hour}小时 #{min}分钟 #{sec}秒"
- end
- return time
- end
-
- # 耗时:天、小时、分
- # 小于1分钟则不显示
- def work_spend_time time
- if time == 0
- time = "0小时"
- else
- day = time / 86400
- hour = time % (24*60*60) / (60*60)
- min = (time % (24*60*60) % (60*60) / 60.0).ceil
- if day < 1
- if hour < 1
- if min < 1
- time = "1分"
- else
- time = "#{min}分"
- end
- else
- time = "#{hour}小时#{min}分"
- end
- else
- time = "#{day}天#{hour}小时#{min}分"
- end
- end
- return time
- end
-
- # 耗时:小时、分、秒 00:00:00
- # 小于1秒钟则不显示
- def com_spend_time time
- hour = time / (60*60)
- min = time % (60*60) / 60
- sec = time % (60*60) % 60
- hour_str = "00"
- min_str = "00"
- sec_str = "00"
- if hour >= 1 && hour < 10
- hour_str = "0#{hour}"
- elsif hour >= 10
- hour_str = "#{hour}"
- end
-
- if min >= 1 && min < 10
- min_str = "0#{min}"
- elsif min >= 10
- min_str = "#{min}"
- end
-
- if sec >= 1 && sec < 10
- sec_str = "0#{sec}"
- elsif sec >= 10
- sec_str = "#{sec}"
- end
-
- time = "#{hour_str} : #{min_str} : #{sec_str}"
- return time
- end
-
- def consume_time time
- time.strftime('%Y/%m/%d %H:%M:%S')
- end
-
- def avg_spend_time shixun_id, position
- Game.find_by_sql("SELECT avg(g.end_time - g.open_time) as avg_time FROM `games` g, `challenges` c where c.id=g.challenge_id and g.status =2 and c.position = #{position} and g.myshixun_id in (SELECT id FROM `myshixuns` where shixun_id= #{shixun_id});").first.try(:avg_time).to_i
- end
-
- # 已闯关
- def had_pass shixun_id, position
- Game.find_by_sql("SELECT count(*) as count FROM `games` g, `challenges` c where c.id=g.challenge_id and g.status =2 and c.position =#{position} and g.myshixun_id in (SELECT id FROM `myshixuns` where shixun_id=#{shixun_id});").first.try(:count)
- end
-
- # 单个game测评次数
- def avg_my_pass game
- Output.where(:game_id => game).count
- end
-
- def shixun_final_score myshixun
- Game.find_by_sql("SELECT sum(final_score) as final_score FROM `games` where myshixun_id='#{myshixun.id}';").first.try(:final_score)
- end
-
- # def user_blogs_path(resource,parameters={})
- # super
- # end
- # 复制一个任务
- def publish_games challenge, myshixun_id, index
- game = Game.new
- game.attributes = challenge.attributes.dup.except("id","shixun_id","user_id","visits")
- game.myshixun_id = myshixun_id
- game.user_id = User.current.id
- game.stage = challenge.position
- index == 0 ? game.status = 0 : game.status = 3
- challenge_samples = challenge.challenge_samples
- test_sets = challenge.test_sets
- if game.save
- unless challenge_samples.blank?
- challenge_samples.each do |cs|
- ChallengeSample.create(:game_id => game.id, :input => cs.input, :output => cs.output, :challenge_id => -1)
- end
- end
- unless test_sets.blank?
- test_sets.each do |ts|
- TestSet.create(:game_id => game.id, :input => ts.input, :output => ts.output, :challenge_id => -1)
- end
- end
- end
- end
-
- def git_repository_url project, type
- if type == "Shixun"
- rep_identify = Repository.where(:shixun_id => project.id, :type => "Repository::Gitlab").first.try(:identifier)
- elsif type == "Myshixun"
- rep_identify = Repository.where(:myshixun_id => project.id, :type => "Repository::Gitlab").first.try(:identifier)
- else
- rep_identify = Repository.where(:project_id => project.id, :type => "Repository::Gitlab").first.try(:identifier)
- end
- gitlab_address = Redmine::Configuration['gitlab_address']
- gitUrl = gitlab_address.to_s+"/"+project.owner.to_s+"/"+ rep_identify + "."+"git"
- end
-
- def gitlab_url container
- g = Gitlab.client
- url = "#{Redmine::Configuration['gitlab_address_ip']}/#{g.project(container.try(:gpid)).try(:path_with_namespace)}.git"
- end
-
- def gitlab_address_url container
- g = Gitlab.client
- url = "#{Redmine::Configuration['gitlab_address']}/#{g.project(container.try(:gpid)).try(:path_with_namespace)}.git"
- end
-
- # paranet_gpid 为fork的源头
- # u_gid 为当前用户在gitlab中对应的用户id
- def sync_gitlab_rep container, parent_gpid, u_gid
- Rails.logger.info("# sync_gitlab_rep # parent_gpid is #{parent_gpid}, u_gid is #{u_gid}")
- if container.class == Myshixun
- gshixun = Gitlab.client.fork(parent_gpid, u_gid)
- container.update_attribute(:gpid, gshixun.id)
- end
- return gshixun.try(:id)
- end
-
- # def git_shixun_url shixun, login
- # rep_identify = Repository.where(:shixun_id => shixun.id, :type => "Repository::Gitlab").first.try(:identifier)
- # gitlab_address = Redmine::Configuration['gitlab_address']
- # gitUrl = gitlab_address.to_s+"/"+login+"/"+ rep_identify + "."+"git"
- # end
-
- # def git_shixun_url_ip shixun, login
- # rep_identify = Repository.where(:shixun_id => shixun.id, :type => "Repository::Gitlab").first.try(:identifier)
- # gitlab_address = Redmine::Configuration['gitlab_address_ip']
- # gitUrl = gitlab_address.to_s+"/"+login+"/"+ rep_identify + "."+"git"
- # end
-
- # def git_myshixun_url_ip myshixun, user_id
- # g = Gitlab.client
- # login = User.where(:id => user_id).first.try(:login)
- # rep_identify = g.project(myshixun.gpid).try(:name)
- # gitlab_address = Redmine::Configuration['gitlab_address_ip']
- # gitUrl = gitlab_address.to_s+"/"+login+"/"+ rep_identify + "."+"git"
- # end
-
- # myshixun git url by domain
- # def git_myshixun_url myshixun, user_id
- # g = Gitlab.client
- # login = User.where(:id => user_id).first.try(:login)
- # rep_identify = g.project(myshixun.gpid).try(:name)
- # gitlab_address = Redmine::Configuration['gitlab_address']
- # gitUrl = gitlab_address.to_s+"/"+login+"/"+ rep_identify + "."+"git"
- # end
-
- def uri_exec uri, params
- begin
- Rails.logger.info("@parmas is #{params}, url is #{uri}")
- uri = URI.parse(URI.encode(uri.strip))
- res = Net::HTTP.post_form(uri, params).body
- res = JSON.parse(res)
- rescue => e
- Rails.logger.error("failed to post data to brige! #{e}")
- raise("实训云平台繁忙(繁忙等级:84)")
- end
- end
-
- # type 为繁忙等级
- # status-> 501:check检查版本库是否有代码异常
- # status-> 502:实训评测异常;503实训版本库check异常
- def interface_post uri, params, status
- begin
- uri = URI.parse(URI.encode(uri.strip))
- res = Net::HTTP.post_form(uri, params).body
- res = JSON.parse(res)
- if (res && res['code'] != 0)
- raise(status)
- end
- res
- rescue Exception => e
- Rails.logger.error("post failed! #{e}")
- raise("实训云平台繁忙(繁忙等级:#{status})")
- end
- end
-
- def get_url_exec uri, options={}
- begin
- uri = URI.parse(URI.encode(uri.strip))
- res = Net::HTTP.get_response(uri).body
- res = JSON.parse(res)
- rescue => e
- logger.error("get response failed ! #{e}")
- raise("实训云平台繁忙(繁忙等级:84)")
- end
- end
-
- def uri_json_exec uri, params
- Net::HTTP.start(uri.hostname, uri.port) {|http|
- http.post(uri.path, params.to_json)
- }
-
- http = Net::HTTP.new(uri.host, uri.port)
- res = Net::HTTP.post(uri, params.to_json).body
- res = JSON.parse(res)
- end
-
- def last_reply_time container_id
- message = Message.where(:root_id => container_id).order("created_on desc").first
- time = message.created_on
- return time
- end
-
- def judge_Chinese_num str
- cn_reg = /[\u4e00-\u9fa5]{1}/
- cn_number = str.scan(cn_reg).size
- en_number = str.size - cn_number
- size = 1.9* cn_number + en_number
- end
-
- # homework_common状态
- # 0:挂起;1:提交中;2:匿评中;3:评阅中
- def new_homework_common_status status
- case status
- when 0
- "未发布"
- when 1
- "提交中"
- when 2
- "补交中"
- when 3
- "匿评中"
- when 4
- "申诉中"
- when 5
- "评阅中"
- when 6
- "已结束"
- end
- end
-
- # 作业不同状态的不同样式
- def homework_status_color status
- style = ""
- case status
- when '未发布'
- style = 'edu-filter-btn-no-late'
- when '提交中', '评阅中', '匿评中', '交叉评阅中'
- style = 'edu-filter-btn-orange'
- when '已开启补交'
- style = 'edu-filter-btn-green'
- when '已截止', '未开启补交'
- style = 'edu-filter-btn-red'
- when '已结束'
- style = 'edu-filter-btn-end'
- when '申诉中'
- style = 'edu-filter-btn-appeal'
- end
- end
-
- # 有分班权限的课堂 学生提交作品时发送的消息对象
- def tiding_teachers course, member
- if course.teacher_course_groups.count > 0
- member_ids = course.teacher_course_groups.where(:course_group_id => member.try(:course_group_id)).pluck(:member_id)
-
- teachers = course.teachers.where("members.id not in (#{course.teacher_course_groups.pluck(:member_id).size > 0 ? course.teacher_course_groups.pluck(:member_id).join(',') : -1}) or
- members.id in (#{member_ids.size > 0 ? member_ids.join(',') : -1})")
- else
- teachers = course.teachers
- end
- teachers
- end
-
- # 分班管理的老师所看到的成员数
- def group_student_count course
- member = @course.members.where(:user_id => User.current.id).first
- if User.current.allowed_to?(:as_teacher, course) && member.present? && member.teacher_course_groups.count > 0
- student_count = course.members.where(:course_group_id => member.teacher_course_groups.pluck(:course_group_id)).select{|member| member.roles.to_s.include?("Student")}.count
- else
- student_count = course.student.count
- end
- student_count
- end
-
- # 已提交作品
- def late_commit_work_status work, homework
- if homework.allow_late
- link_to "补交附件", student_work_path(work, :is_focus => 1), :class => 'edu-filter-btn edu-activity-orange ml15 fl mt5', :title => "可追加作品修订附件"
- else
- "未开启补交".html_safe
- end
- end
-
- # 未提交作品
- def un_commit_work_status project, homework
- if homework.allow_late
- if homework.homework_type == 3 && project.nil? && homework.homework_detail_group.base_on_project == 1
- link_to "补交作品", "javascript:void(0)", :class => 'edu-filter-btn edu-activity-orange ml15 fl mt5', :style => "cursor:not-allowed", :title => '请先关联项目再补交作品'
- else
- link_to "补交作品", new_student_work_url_without_domain(homework.id), :class => 'edu-filter-btn edu-activity-orange ml15 fl mt5'
- end
- else
- "未开启补交".html_safe
- end
- end
-
- # 判断作业有多少人提交了
- #
- def had_commit_studentwork_count homework_common
- member = homework_common.course.members.where(:user_id => User.current.id).first
- student_works = homework_common.student_works
- if member.present? && member.teacher_course_groups.count > 0
- group_students = homework_common.course.members.where(:course_group_id => member.teacher_course_groups.pluck(:course_group_id)).map(&:user_id)
- student_works = student_works.where(:user_id => group_students)
- end
- student_works.where("work_status !=?", 0).count
- end
-
- # 实训作业的有效作品数
- def effective_shixun_work_count homework_common
- count = 0
- shixun = homework_common.shixuns
- if shixun
- homework_common.student_works.where("work_status !=?", 0).each do |work|
- myshixun = work.myshixun
- count = count + (myshixun && myshixun.games.select{|game| game.status == 2}.size > 0 ? 1 : 0)
- end
- end
- count
- end
-
- # 实训作业的通关作品数
- def tongguan_shixun_work_count homework_common
- count = 0
- shixun = homework_common.shixuns.first
- if shixun
- challenge_count = shixun.challenges.count
- homework_common.student_works.where("work_status !=?", 0).each do |work|
- myshixun = work.myshixun
- if myshixun && myshixun.games.select{|game| game.status == 2}.size == challenge_count
- count = count + 1
- end
- end
- end
- count
- end
-
- # 未提交作品数统计
- def had_uncommit_studentwork_count homework_common
- member = homework_common.course.members.where(:user_id => User.current.id).first
- student_works = homework_common.student_works
- if member.present? && member.teacher_course_groups.count > 0
- group_students = homework_common.course.members.where(:course_group_id => member.teacher_course_groups.pluck(:course_group_id)).map(&:user_id)
- student_works = student_works.where(:user_id => group_students)
- end
- student_works.where("work_status =?", 0).count
- end
-
- # 未评阅
- def had_unevaluate_count homework_common
- #count = StudentWorksScore.find_by_sql("SELECT count(distinct student_work_id) as count FROM student_works_scores sws, student_works sw, homework_commons hc where hc.id =#{homework_common.id} and sw.homework_common_id=hc.id and sw.is_delete = 0 and sws.student_work_id = sw.id and sws.user_id=#{User.current.id};").first.try(:count).to_i
- member = homework_common.course.members.where(:user_id => User.current.id).first
- student_works = homework_common.student_works
- if member.present? && member.teacher_course_groups.count > 0
- group_students = homework_common.course.members.where(:course_group_id => member.teacher_course_groups.pluck(:course_group_id)).map(&:user_id)
- student_works = student_works.where(:user_id => group_students)
- end
- has_comment = StudentWorksScore.where(:student_work_id => student_works.map(&:id), :reviewer_role => [1, 2]).group_by(&:student_work_id).count
- student_count = student_works.count
- return student_count - has_comment
- end
-
- # 该阶段还有多长时间结束/距下一阶段还有多长时间
- def homework_curr_time homework_common
- result = {}
- status = ""
- time = ""
- if homework_common.course.try(:is_end)
- status = "已结束"
- time = format_date homework_common.course.end_date
- else
- ho_detail_manual = homework_common.homework_detail_manual
- if ho_detail_manual
- case ho_detail_manual.comment_status
- when 0
- status = "未发布"
- when 1
- if homework_common.end_time && homework_common.end_time >= Time.now
- status = "提交中"
- time = how_much_time(homework_common.end_time)
- end
- when 3
- if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now
- status = "匿评中"
- time = how_much_time(ho_detail_manual.evaluation_end)
- end
- when 4
- if ho_detail_manual.appeal_time && ho_detail_manual.appeal_time > Time.now
- status = "申诉中"
- time = how_much_time(ho_detail_manual.appeal_time)
- end
- when 5
- status = "评阅中"
- when 6
- status = "评阅中"
- end
- end
- end
- result[:status] = status
- result[:time] = time
- result
- end
-
- # 试卷:该阶段还有多长时间结束/距下一阶段还有多长时间
- def exercise_curr_time exercise
- result = {}
- status = ""
- time = ""
- case exercise.exercise_status
- when 1
- status = "未发布"
- when 2
- if exercise.end_time && exercise.end_time >= Time.now
- status = "提交中"
- time = how_much_time(exercise.end_time)
- end
- when 3
- status = "已截止"
- time = format_time exercise.end_time
- end
- result[:status] = status
- result[:time] = time
- result
- end
-
- # 问卷:该阶段还有多长时间结束/距下一阶段还有多长时间
- def poll_curr_time poll
- result = {}
- status = ""
- time = ""
- case poll.polls_status
- when 1
- status = "未发布"
- when 2
- if poll.end_time && poll.end_time >= Time.now
- status = "提交中"
- time = how_much_time(poll.end_time)
- end
- when 3
- status = "已截止"
- time = format_time poll.end_time
- end
- result[:status] = status
- result[:time] = time
- result
- end
-
- # 公共分页
- def paginator_list objs, objs_count, limit, is_remote
- @is_remote = is_remote
- @objs_count = objs.count
- @obj_pages = Paginator.new @objs_count, limit, params['page'] || 1
- @offset ||= @obj_pages.offset
- @objs = paginateHelper @attachments,25
- end
-
- # 判断当前用户能否对消息进行操作
- def allow_to_show applied_message
- (User.current.id == applied_message.user_id && applied_message.status == 0) ? true : false
- end
-
- # 获取竞赛的管理人员
- def contest_managers contest
- contest.contest_members.select{|cm| cm.roles.to_s.include?("ContestManager")}
- end
-
- # 获取竞赛的评委人员
- def contest_judges contest
- contest.contest_members.select{|cm| cm.roles.to_s.include?("Judge")}
- end
-
- # 获取竞赛的参赛人员
- def contest_contestants contest
- contest.contest_members.select{|cm| cm.roles.to_s.include?("Contestant")}
- end
-
- # 字符串加密
- def aes_encrypt(key, encrypted_string)
- aes = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
- aes.encrypt
- aes.key = key
- txt = aes.update(encrypted_string) << aes.final
- txt.unpack('H*')[0].upcase
- end
-
- # 字符串解密
- def aes_dicrypt(key, dicrypted_string)
- aes = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
- aes.decrypt
- aes.key = key
- aes.update([dicrypted_string].pack('H*')) << aes.final
- end
- # 获取多种类型的user用户名
- def user_message_username user
- user.try(:show_name)
- end
-
- # 超出1w后用k+形式显示
- def switch_integer_into_k number
- number > 10000 ? (number.to_f / 1000).round.to_s + "k" : number
- end
-
- # 判断某个课程是否包含仅对自己可见的作业
- def course_has_score_open_common_homework course
- course.homework_commons.select{|hc| hc.score_open == 0}.count > 0 ? true : false
- end
-
- def welcome_course_message_count course_id
- board_id = Board.where(:course_id => course_id).first.try(:id)
- message_count = Message.where(:board_id => board_id).count
- return message_count
- end
-
- # 可以查看到资源库的资源
- def welcome_course_file_count course
- course.attachments.count
- end
-
- # 超级管理员实训评分设置的横轴
- def shixun_quality_show quality
- lower = quality.lower_limit
- upper = quality.upper_limit
- result = "#{quality.name}"
- if lower.present? && upper.present?
- result = if(lower > lower.round)
- "#{result}(#{lower.round},"
- else
- "#{result}[#{lower.round},"
- end
-
- result = if(upper >= upper.round)
- "#{result}#{upper.round}]"
- else
- "#{result}#{upper.round})"
- end
- end
- return result
- end
-
- # 管理员实训评分中 "指标"与"标准"的对应
- def description_of_quality indicator, position
- indicator.score_quality_descriptions.where(:position => position).first.try(:name) if indicator.present?
- end
-
- # 获取目录下所有文件,返回一个文件名的数组 type是查看文件的类型image表示图片
- # type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"]]
- def get_dir_filename path, type, game_id
- answer_picture = []
- image = ["png", "jpg", "gif", "jpeg", "bmp", "pic"]
- if File.directory? path
- Dir.foreach(path) do |file|
- if file !="." and file !=".."
- extension = file.split(".")[1].try(:downcase)
- if image.include?(extension) && type == 1
- answer_picture << file
- @type = "image"
- elsif extension == "html" && type == 4
- answer_picture << file
- @type = "html"
- elsif extension == "txt" && type == 3
- answer_picture << file
- @contents = ""
- f = File.open("#{path}/#{file}", "r")
- # ... process the file
- f.each_line do |line|
- if line.include?("Your score")
- game = Game.find(game_id)
- max_query_index = game.query_index - 1
- a = line[11, line.length-1].try(:strip)
- outputs = game.outputs.where(:query_index => max_query_index)
- outputs.update_all(:text_scor => a) if outputs.present?
- end
- @contents += "#{line}"
- end
- f.close
- @type = "txt"
- end
- end
- end
- end
- return answer_picture
- end
-
- # 隐藏项目以外的信息
- # return: true 显示,false 不显示
- def hidden_unproject_infos
- hidden_info = Setting.find_by_name("hidden_non_project")
- (hidden_info && hidden_info.value == "1") ? true : false
- end
-
- # 获取当前用户的fork数量
- def get_fork_from_project forked_from_project_id
- Project.find(forked_from_project_id)
- end
-
- # 判断当前用户是否已经fork过当前项目
- # project: current_project
- def has_forked_cur_project project
- cur_user_projects = Project.where(:user_id => User.current.id)
- if cur_user_projects.count == 0
- false
- else
- has_forked = cur_user_projects.select{|cur_user_project| cur_user_project.forked_from_project_id == project.id}
- has_forked.length > 0 ? true : false
- end
- end
-
- # 判断当前用户是否已经实训过当前项目
- # project: current_project
- def has_exec_cur_shixun shixun
- Myshixun.where(:user_id => User.current.id, :shixun_id => shixun.id).count > 0 ? true : false
- end
-
- # 用户必须登录;必须创建了关卡;有实践任务的必须提交了版本库代码
- def allow_shixun_exec shixun
- g = Gitlab.client
- result = User.current.logged? && shixun.challenges.count > 0
- if shixun.challenges.where(:st => 0).count > 0
- result = result && g.trees(shixun.gpid).count.to_i > 0
- end
- result
- end
-
- # 判断当前用户是否可以开始实战
- def link_to_shixun_exec myshixun, shixun, str
- is_modify = ShixunModify.where(:myshixun_id => myshixun.try(:id), :shixun_id => shixun.try(:id), :status => 1).first.blank?
- if User.current.mail.blank?
- link_to str, "javascript:void(0);", :onclick => "notice_box_redirect('#{security_settings_path}', '开启实训,请先绑定邮箱')", :class => "fr shixun-task-btn task-btn-orange mr15", :target => "_blank"
- else
- if is_modify || myshixun.blank?
- link_to str, shixun_exec_shixun_path(shixun), :class => "fr shixun-task-btn task-btn-orange mr15", :target => "_blank"
- else
- link_to str, "javascript:void(0);", :onclick => "sure_box_redirect('#{myshixun_reset_myshixun_path(myshixun)}', '实训已经更新啦,系统正在为您重置')", :class => "fr shixun-task-btn task-btn-orange mr15"
- end
- end
- end
-
- # 通过系统外部邮箱查找用户,如果用户不存在则用邮箱替换
- def get_user_by_mail mail
- user = User.find_by_mail(mail)
- user.nil? ? User.find(2) : user
- end
-
- # 通过登录名查找用户,能查到返回用户姓名,否则返回登录名
- def link_to_user_login login, css_class
- user = User.find_by_login(login)
- user = user.nil? ? login : user
- if user.is_a?(User)
- name = user.show_name
- link_to name, {:controller=> 'users', :action => 'show', id: user.id}, :class => css_class, :target => "_blank"
- else
- "#{h(user.to_s)}".html_safe
- end
- end
-
- def link_to_user_mail(mail, css_class)
- user = User.find_by_mail(mail)
- user = user.nil? ? mail : user
- if user.is_a?(User)
- name = user.show_name
- link_to name, {:controller=> 'users', :action => 'show', id: user.id}, :class => css_class, :target => "_blank"
- else
- "#{h(user.to_s)}".html_safe
- end
- end
-
- # 通过系统外部用户名查找用户,如果用户不存在则用邮箱替换
- def get_user_by_login_and login
- user = User.find_by_login(login)
- (user.nil? || login == "root") ? User.find(2) : user
- end
-
- # 登录名来自外部系统
- # 通过登录名查找用户,如果用户存在则显示用户姓名,否则显示登录名
- def get_user_by_login login
- user = User.find_by_login(login)
- user.nil? ? login : user.show_name
- end
-
- # 重置user_path,目的是将id转换成用户名
- def user_path(resource, parameters = {})
- if Fixnum === resource
- resource = User.find(resource)
- end
- super
- end
-
- # 重置user_path,目的是将id转换成用户名
- # def shixun_path(resource, parameters = {})
- # if Fixnum === resource
- # resource = Shixun.find(resource)
- # end
- # super
- # end
-
- # 历史数据(老版本库数据)处理完则可以修改该放放
- def get_rep_identifier_by_project project
- identifier = Repository.where(:project_id => project.id, :type => "Repository::Gitlab").first.try(:identifier)
- result = identifier.nil? ? Repository.where(:project_id => project.id).first.try(:identifier) : identifier
- result
- end
-
- # 项目版本库导出Excel功能
- def export_rep_xls(gpid, options = {})
- g = Gitlab.client
- cycle = params[:cycle]
- rev = params[:rev]
- if cycle == "week"
- statics = g.rep_stats_week(gpid, :rev => rev)
- elsif cycle == "month"
- statics = g.rep_stats_month(gpid, :rev => rev)
- end
- xls_report = StringIO.new
- book = Spreadsheet::Workbook.new
- sheet1 = book.create_worksheet :name => l(:project_module_repository)
- blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
- sheet1.row(0).default_format = blue
- sheet1.row(0).concat([l(:rep_branch),l(:rep_author),l(:rep_changeset),l(:rep_code_add),l(:rep_code_delete),l(:rep_code_modified),l(:rep_sode_time),l(:rep_sode_cycle),l(:rep_author_mail)])
- count_row = 1
- statics.each do |static|
- user = User.where(:mail => static.email).first
- sheet1[count_row,0] = rev
- sheet1[count_row,1] = user.nil? ? static.uname : user.show_name
- sheet1[count_row,2] = static.commits_num
- sheet1[count_row,3] = static.add
- sheet1[count_row,4] = static.del
- sheet1[count_row,5] = static.changes
- sheet1[count_row,6] = Time.now.strftime('%Y-%m-%d %H:%M:%S')
- sheet1[count_row,7] = cycle == "week" ? "最近1周" : "最近一月"
- sheet1[count_row,8] = static.email
- count_row += 1
- end
- book.write xls_report
- xls_report.string
- end
-
- # 项目issue列表导出Excel功能
- def issue_list_xls issues
- xls_report = StringIO.new
- book = Spreadsheet::Workbook.new
- sheet1 = book.create_worksheet :name => "issues"
- blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
- sheet1.row(0).default_format = blue
- sheet1.row(0).concat([l(:issue_xls_id),l(:issue_xls_tracker_id),l(:issue_xls_title),l(:issue_xls_description),l(:issue_xls_status),l(:issue_xls_assign),l(:issue_xls_priority),l(:issue_xls_author),l(:issue_xls_created_at),l(:milestone),l(:issue_xls_start),l(:issue_xls_due),l(:issue_xls_ratio)])
- count_row = 1
- issues.each do |issue|
- sheet1[count_row,0] = issue.id
- sheet1[count_row,1] = issue_tracker_change(issue.tracker_id)
- sheet1[count_row,2] = issue.subject
- sheet1[count_row,3] = (issue.description.gsub(/<\/?.*?>/,"")).html_safe
- sheet1[count_row,4] = issue_status_change(issue.status_id)
- sheet1[count_row,5] = issue.assigned_to.try(:show_name)
- sheet1[count_row,6] = issue_priority_change(issue.priority_id)
- sheet1[count_row,7] = issue.author.show_name
- sheet1[count_row,8] = issue.created_on.nil? ? issue.created_on : issue.created_on.strftime('%Y-%m-%d %H:%M:%S')
- sheet1[count_row,9] = issue.fixed_version.try(:name)
- sheet1[count_row,10] = issue.start_date.nil? ? issue.start_date : issue.start_date.strftime('%Y-%m-%d')
- sheet1[count_row,11] = issue.due_date.nil? ? issue.due_date : issue.due_date.strftime('%Y-%m-%d')
- sheet1[count_row,12] = issue_ratio_change(issue.done_ratio, issue.status_id)
- count_row += 1
- end
- book.write xls_report
- xls_report.string
- end
-
- # 用户资料是否完善
- def user_data_complete user
- user_extension = UserExtensions.where(:user_id => user.id).first
- data = true
- if user_extension.gender.nil? || user_extension.school_id.nil? || user.lastname.blank? || (user_extension.identity == 3 && user_extension.school_id.nil?)
- data = false
- end
- return data
- end
-
- # 获取用户单位
- # 优先获取高校信息,如果改信息不存在则获取occupation
- def get_occupation_from_user user
- School.where("id=?",user.user_extensions.school_id).first.try(:name).nil? ? user.user_extensions.try(:occupation) : School.where("id=?",user.user_extensions.school_id).first.try(:name)
- end
-
- def update_visiti_count container
- container.update_column(:visits, container.visits + 1)
- end
-
- def if_hidden_subdomain field
- domains = field.sub_domains.select{|domain| domain.hide.to_i == 0}
- result = domains.length > 0 ? true : false
- return result
- end
-
- # 判断某个资源是否可以申请
- def attach_show_allow attach_id
- attachment = Attachment.find(attach_id)
- case attachment.container_type
- when "Project"
- User.current.member_of?(attachment.container) ? true : false
- when "Course"
- User.current.member_of_course?(attachment.container) ? true : false
- when "OrgSubfield"
- User.current.member_of_org?(attachment.container.organization) ? true : false
- when "Principal"
- User.current.id == attachment.author_id ? true : false
- end
- end
-
- # 判断某个私有资源是否可以发送下载权限
- # 结果为true不能下载,false可以下载
- def private_attachment_allow attachment_id
- attach = Attachment.find(attachment_id)
- # 条件取否,result结果为true则不能下载
- result = attach.is_public == 0 && attach.author != User.current && !attach.get_apply_resource_status(attach.id, User.current.id) && !attach_show_allow(attach)
- end
-
- # Time 2015-03-24 15:27:29
- # Author lizanle
- # Description 从硬盘上删除对应的资源文件
- def delete_kindeditor_assets_from_disk owner_id,owner_type
- assets = Kindeditor::Asset.where(["owner_id = ? and owner_type = ?",owner_id,owner_type])
- if !assets.nil? && !assets.blank?
- assets.all.each do |asset|
- next if asset.nil?
- filepath = File.join(Rails.root,"public","files","uploads",
- asset[:created_at].to_s.gsub("+0800","").to_datetime.strftime("%Y%m").to_s,
- asset[:asset].to_s)
- File.delete(filepath) if File.exist?filepath
- end
- end
- end
-
- def link_to_user_version(version, options = {})
- return '' unless version && version.is_a?(Version)
- link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, :class => "linkBlue"
- end
-
- # 判断课程是否为精品课程
- def is_excellent_course course
- (course.is_excellent? or course.excellent_option?) ? true : false
- end
-
- # 判断课程对成员是否可见
- def visible_course?(course)
- (course.is_delete? or (!course.is_public? && !User.current.member_of_course?(course))) ? false : true
- end
-
- # 获取项目/课程总分
- # 发布缺陷 4分 回复缺陷 1分 提交一次 4分 讨论帖子 2分 回复帖子 1分 发布新闻 1分
- def static_project_score obj
- score = obj.issue_num * 4 + obj.issue_journal_num + (obj.changeset_num||0) * 4 + obj.board_num * 2 + obj.board_message_num + obj.attach_num * 5
- end
-
- # 获取组织成员中文名字
- def get_org_member_role_name member
- unless member.roles[0].nil?
- case member.roles[0].name
- when 'orgManager'
- '管理人员'
- when 'orgMember'
- '组织成员'
- end
- end
- end
-
- # 判断组织左侧展开或者隐藏
- def is_hide_org_left obj
- if obj.nil?
- return true
- else
- if obj.hide == 0
- return true
- else
- return false
- end
- end
- end
-
- # Time 2015-03-24 16:38:05
- # Author lizanle
- # Description after save后需要进行资源记录的更新
- # owner_type = 1 对应的是 memo
- # owner_type = 2 对应的是forum
- # owner_type = 3 对应的是message
- # owner_type = 4 对应的是news
- # owner_type = 5 对应的是comment
- def update_kindeditor_assets_owner ids,owner_id,owner_type
- ids.each do |id|
- asset = Kindeditor::Asset.find(id.to_i)
- asset.owner_id = owner_id
- asset.owner_type = owner_type
- asset.save
- end
- end
-
- # 更新课程活跃度得分
- def course_member_score(course_id,user_id,type)
- course_contributor_score = CourseContributorScore.where("course_id =? and user_id =?", course_id, user_id).first
- case type
- when "HomeworkCommon"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :homework_journal_num => 1)
- else
- score = course_contributor_score.homework_journal_num.to_i + 1
- course_contributor_score.update_column(:homework_journal_num, score)
- end
- # 课程留言
- when "Course"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :journal_num => 1)
- else
- score = course_contributor_score.journal_num.to_i + 1
- course_contributor_score.update_column(:journal_num, score)
- end
- when "Message"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_num => 1)
- else
- score = course_contributor_score.message_num.to_i + 1
- course_contributor_score.update_column(:message_num, score)
- end
- when "MessageReply"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_reply_num => 1)
- else
- score = course_contributor_score.message_reply_num.to_i + 1
- course_contributor_score.update_column(:message_reply_num, score)
- end
- when "NewReply"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :news_reply_num => 1)
- else
- score = course_contributor_score.news_reply_num.to_i + 1
- course_contributor_score.update_column(:news_reply_num, score)
- end
- when "News"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :news_num => 1)
- else
- score = course_contributor_score.news_num.to_i + 1
- course_contributor_score.update_column(:news_num, score)
- end
- when "Attachment"
- if course_contributor_score.nil?
- CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :resource_num => 1)
- else
- score = course_contributor_score.resource_num.to_i + 1
- course_contributor_score.update_column(:resource_num, score)
- end
- end
- end
-
- # 删除某条记录相应减少课程统计数
- def down_course_score_num (course_id,user_id,type)
- course_contributor_score = CourseContributorScore.where("course_id =? and user_id =?", course_id, user_id).first
- case type
- when "HomeworkCommon"
- unless course_contributor_score.nil?
- score = course_contributor_score.homework_journal_num.to_i - 1
- course_contributor_score.update_column(:homework_journal_num, score < 0 ? 0 : score)
- end
- # 课程留言
- when "Course"
- unless course_contributor_score.nil?
- score = course_contributor_score.journal_num.to_i - 1
- course_contributor_score.update_column(:journal_num, score < 0 ? 0 : score)
- end
- when "Message"
- unless course_contributor_score.nil?
- score = course_contributor_score.message_num.to_i - 1
- course_contributor_score.update_column(:message_num, score < 0 ? 0 : score)
- end
- when "MessageReply"
- unless course_contributor_score.nil?
- score = course_contributor_score.message_reply_num.to_i - 1
- course_contributor_score.update_column(:message_reply_num, score < 0 ? 0 : score)
- end
- when "NewReply"
- unless course_contributor_score.nil?
- score = course_contributor_score.news_reply_num.to_i - 1
- course_contributor_score.update_column(:news_reply_num, score < 0 ? 0 : score)
- end
- when "News"
- unless course_contributor_score.nil?
- score = course_contributor_score.news_num.to_i - 1
- course_contributor_score.update_column(:news_num, score < 0 ? 0 : score)
- end
- when "Attachment"
- unless course_contributor_score.nil?
- score = course_contributor_score.resource_num.to_i - 1
- course_contributor_score.update_column(:resource_num, score < 0 ? 0 : score)
- end
- end
- end
-
- # Added by young
- # Define the course menu's link class
- # 不是数组的转化成数组,然后判断当前menu_item是否在给定的列表
- # REVIEW: 目测menu的机制,貌似不是很需要转换,再说
- def link_class(label)
- labels = label.is_a?(Array) ? label : ([] << label)
- #a = current_menu_item
- labels.include?(current_menu_item) ? 'selected' : ''
-
- end
- #Ended by young
- # Return true if user is authorized for controller/action, otherwise false
- def authorize_for(controller, action)
- User.current.allowed_to?({:controller => controller, :action => action}, @project)
- end
-
- # add by nwb
- def authorize_for_course(controller, action)
- User.current.allowed_to?({:controller => controller, :action => action}, @course)
- end
-
- def authorize_for_contest(controller, action)
- User.current.allowed_to?({:controller => controller, :action => action}, @contest)
- end
-
- # Display a link if user is authorized
- #
- # @param [String] name Anchor text (passed to link_to)
- # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
- # @param [optional, Hash] html_options Options passed to link_to
- # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
- def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
- link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
- end
-
- def link_to_if_authorized_course(name, options = {}, html_options = nil, *parameters_for_method_reference)
- link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_course(options[:controller] || params[:controller], options[:action])
- end
-
- def link_to_if_authorized_contest(name, options = {}, html_options = nil, *parameters_for_method_reference)
- link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_contest(options[:controller] || params[:controller], options[:action])
- end
- # Displays a link to user's account page if active
- def link_to_user(user, canShowRealName = false, options={})
- if user.is_a?(User)
- if canShowRealName
- name = h(user.realname(options[:format]))
- else
- name = h(user.name(options[:format]))
- end
-
- #if user.active? || (User.current.admin? && user.logged?)
- # link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.host_user}, :class => user.css_classes
- #else
- # name
- #end
- link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.host_user}, :class => user.css_classes
- else
- h(user.to_s)
- end
- end
-
- def link_to_isuue_user(user, options={})
- if user.is_a?(User)
- if options[:format]
- name = h(user.name(options[:format]))
- else
- name = h(user.show_name)
- end
- link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.host_user}, :class => "pro_info_p"
- else
- h(user.to_s)
- end
- end
-
- def link_to_settings_user(user, options={})
- if user.is_a?(User)
- name = h(user.name(options[:format]))
- link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.host_user}, :class => "w90 c_orange fl"
- else
- h(user.to_s)
- end
- end
-
- #重载上面方法,增加样式显示
- def link_to_user_header user,canShowRealName=false,options={}
- if user.is_a?(User)
- if canShowRealName
- name = user.show_name
- name = user.login if name == ""
- else
- name = user.login
- end
- link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.host_user}, :class => options[:class]
- else
- h(user.to_s)
- end
- end
-
- # Displays a link to +issue+ with its subject.
- # Examples:
- #
- # link_to_issue(issue) # => Defect #6: This is the subject
- # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
- # link_to_issue(issue, :subject => false) # => Defect #6
- # link_to_issue(issue, :project => true) # => Foo - Defect #6
- # link_to_issue(issue, :subject => false, :tracker => false) # => #6
- #
- def link_to_issue(issue, options={})
- title = nil
- subject = nil
- text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}"
- if options[:subject] == false
- title = truncate(issue.subject, :length => 60)
- else
- subject = issue.subject
- if options[:truncate]
- subject = truncate(subject, :length => options[:truncate])
- end
- end
- s = link_to text, issue_path(issue), :class => issue.css_classes, :title => title
- s << h(": #{subject}") if subject
- s = h("#{issue.project} - ") + s if options[:project]
- s
- end
-
- def link_to_issue_version(issue, options={})
- title = nil
- subject = nil
- text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}"
- if options[:subject] == false
- title = truncate(issue.subject, :length => 60)
- else
- subject = issue.subject
- if options[:truncate]
- subject = truncate(subject, :length => 60)
- end
- end
- # status_id:3、已解决 5、已关闭
- if issue.status_id == 3
- s = link_to text, issue_path(issue), :class => "text_line_s fl", :title => title
- elsif issue.status_id == 5
- s = link_to text, issue_path(issue), :class => "text_line_s del_line fl", :title => title
- else
- s = link_to text, issue_path(issue), :class => "c_blue fl", :title => title
- end
- s << h(": #{subject}".html_safe) if subject
- s = h("#{issue.project} - ") + s if options[:project]
- s
- end
-
- # Generates a link to an attachment.
- # Options:
- # * :text - Link text (default to attachment filename)
- # * :download - Force download (default: false)
- def link_to_short_attachment(attachment, options={})
- length = options[:length] ? options[:length]:23
- text = h(truncate(options.delete(:text) || attachment.filename, length: length, omission: '...'))
- route_method = options.delete(:download) ? :download_named_attachment_url_without_domain : :named_attachment_url_without_domain
- html_options = options.slice!(:only_path)
- url = send(route_method, attachment, attachment.filename, options)
- link_to text, url, html_options
- end
-
- # Generates a link to an attachment.
- # Options:
- # * :text - Link text (default to attachment filename)
- # * :download - Force download (default: false)
- def link_to_attachment(attachment, options={})
- token = options[:token] if options[:token]
- text = options.delete(:text) || attachment.filename
- route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
- html_options = options.slice!(:only_path)
- url = send(route_method, attachment, attachment.filename, options)
- url << "?token=#{token}" unless token.nil?
- link_to text, url, html_options
- end
-
- def link_to_attachment_img(attachment, options={})
- text = options.delete(:text) || attachment.filename
- route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
- html_options = options.slice!(:only_path)
- url = send(route_method, attachment, attachment.filename, options)
- image_tag url, html_options
- end
-
- # Generates a link to a SCM revision
- # Options:
- # * :text - Link text (default to the formatted revision)
- def link_to_revision(revision, repository, options={})
- if repository.is_a?(Project)
- repository = repository.repository
- end
- text = options.delete(:text) || format_revision(revision)
- rev = revision.respond_to?(:identifier) ? revision.identifier : revision
- link_to(
- h(text),
- {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev},
- :title => l(:label_revision_id, format_revision(revision))
- )
- end
-
- # Generates a link to a message
- def link_to_message(message, options={}, html_options = nil)
- link_to(
- truncate(message.subject, :length => 60),
- board_message_path(message.board_id, message.parent_id || message.id, {
- :r => (message.parent_id && message.id),
- :anchor => (message.parent_id ? "message-#{message.id}" : nil)
- }.merge(options)),
- html_options
- )
- end
-
- # Generates a link to a project if active
- # Examples:
- #
- # link_to_project(project) # => link to the specified project overview
- # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
- # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
- #
- def link_to_project(project, options={}, html_options = nil)
- if project.archived?
- h(project.name)
- elsif options.key?(:action)
- ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
- url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
- link_to project.name, url, html_options
- else
- link_to project.name, project_path(project, options), html_options
- end
- end
-
- def link_to_course(course, options={}, html_options = nil)
- if course.archived?
- h(course.name)
- elsif options.key?(:action)
- ActiveSupport::Deprecation.warn "#link_to_course with :action option is deprecated and will be removed in Redmine 3.0."
- url = {:controller => 'courses', :action => 'show', :id => project}.merge(options)
- link_to course.name, url, html_options
- else
- link_to course.name, course_path(course, options), html_options
- end
- end
-
- # Generates a link to a project settings if active
- def link_to_project_settings(project, options={}, html_options=nil)
- if project.active?
- link_to project.name, settings_project_path(project, options), html_options
- elsif project.archived?
- h(project.name)
- else
- link_to project.name, project_path(project, options), html_options
- end
- end
-
- def wiki_page_path(page, options={})
- url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options))
- end
-
- def thumbnail_tag(attachment)
- link_to image_tag(thumbnail_path(attachment)),
- named_attachment_path(attachment, attachment.filename),
- :title => attachment.filename
- end
-
- def thumbnail_issue_tag(attachment)
- imagesize = attachment.thumbnail(:size => "200*200")
- imagepath = named_attachment_path(attachment, attachment.filename)
- if imagesize
- link_to image_tag(thumbnail_path(attachment), height: '73', width: '100', class: 'issue_attachment_picture'),
- imagepath,
- :title => attachment.filename
-
- else
- link_to image_tag(imagepath , height: '73', width: '100', class: 'issue_attachment_picture'),
- imagepath,
- :title => attachment.filename
- end
- end
-
- def thumbnail_challenge_tag(attachment)
- imagepath = named_attachment_path(attachment, attachment.filename)
- image_tag(imagepath)
- end
-
- # 图片缩略图链接
- def thumbnail_small_tag(attachment)
- imagesize = attachment.thumbnail(:size => "200*200")
- imagepath = named_attachment_path(attachment, attachment.filename)
- if imagesize
- link_to image_tag(imagesize),
- imagepath,
- :title => attachment.filename
- else
- link_to image_tag(imagepath , height: '200', width: '250'),
- imagepath,
- :title => attachment.filename
- end
- end
-
- def toggle_link(name, id, options={})
- onclick = "$('##{id}').slideToggle(); "
- onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ")
- onclick << "return false;"
- link_to(name, "javascript:void(0)", :onclick => onclick,:class => options[:class])
- end
-
- def image_to_function(name, function, html_options = {})
- html_options.symbolize_keys!
- tag(:input, html_options.merge({
- :type => "image", :src => image_path(name),
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
- }))
- end
-
- def format_activity_title(text)
- h(truncate_single_line(text, :length => 100))
- end
-
- def format_activity_day(date)
- date == User.current.today ? l(:label_today).titleize : format_date(date)
- end
-
- def format_activity_description(text)
- h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
").html_safe
- #h(truncate(text.to_s, :length => 120).gsub(/<\/?.*?>/,"")).html_safe
- end
-
- def format_version_name(version)
- if version.project == @project
- h(truncate(version.name,:length=>20))
- else
- h("#{version.project} - #{truncate(version.name,:length=>20)}")
- end
- end
-
- def due_date_distance_in_words(date)
- if date
- l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
- end
- end
-
- # Renders a tree of projects as a nested set of unordered lists
- # The given collection may be a subset of the whole project tree
- # (eg. some intermediate nodes are private and can not be seen)
- #Modified by nie.
- def render_project_nested_lists(projects)
- s = ''
- if projects.any?
- ancestors = []
- original_project = @project
- #modified by nie
- projects.each do |project|
- # set the project environment to please macros.
- @project = project
- if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
-# s << "
'.html_safe + l(:label_export_to)) - yield Redmine::Views::OtherFormatsBuilder.new(self) - concat('
'.html_safe) - end - - def page_header_title - if @project.nil? || @project.new_record? - h(Setting.app_title) - else - b = [] - ancestors = (@project.root? ? [] : @project.ancestors.visible.all) - if ancestors.any? - root = ancestors.shift - b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') - if ancestors.size > 2 - b << "\xe2\x80\xa6" - ancestors = ancestors[-2, 2] - end - b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } - end - b << h(@project) - b.join(" \xc2\xbb ").html_safe - end - end - - def html_title(*args) - #點擊項目版本庫 多觸發一次 字符串為"/" - #暫時解決方法 直接判斷 - if(args == ["/"]) - args = [] - end - # first_page = FirstPage.find_by_page_type('project') - if args.empty? - title = @html_title || [] - if @project - title << (@project.name.present? ? @project.name : "项目") - elsif params[:controller] == "projects" - title << "项目" - elsif @welcome - title << "创新源于实践" - elsif @course - title << (@course.name.nil? ? "课堂" : @course.name) - elsif params[:controller] == "homework_bank" || params[:controller] == "question_banks" || params[:controller] == "exercise_bank" - title << ("题库") - elsif params[:controller] == "managements" - title << ("后台管理") - elsif params[:controller] == "colleges" && params[:action] == "statistics" - title << ("#{@school.name}") - elsif params[:controller] == "account" && params[:action] == "help" - if params[:index] - case params[:index] - when "1" - title << ("关于我们") - when "2" - title << ("联系我们") - when "3" - title << ("合作伙伴") - when "4" - title << ("服务协议") - when "5" - title << ("帮助中心") - when "6" - title << ("意见反馈") - end - else - title << ("关于我们") - end - elsif params[:controller] == "courses" && params[:action] == "index" - title << ("翻转课堂") - elsif params[:controller] == "competitions" && params[:action] == "index" - title << ("竞赛") - elsif @competition - title << (@competition.name.nil? ? "竞赛" : @competition.name) - elsif @contest - title << (@contest.name.nil? ? "创新源于实践" : @contest.name) - elsif @shixun - title << (@shixun.name.nil? ? "开发社区" : @shixun.name) - elsif @my_shixun - title << ("我的实训") - elsif params[:controller] == "shixuns" && params[:action] == "index" - title << ("开发社区") - elsif @subject - title << (@subject.name.nil? ? "实训课程" : @subject.name) - elsif params[:controller] == "subjects" && params[:action] == "index" - title << ("实训课程") - elsif @organization - title << (@organization.name.nil? ? "创新源于实践" : @organization.name) - elsif @forum || params[:controller] == "forums" - title << "讨论区" - elsif @my_syllabuses - title << "我的课堂" - elsif params[:controller] == 'ecs' - title << '专业列表' - elsif params[:controller] == 'ec_major_schools' - name = EcMajorSchool.find(params[:id]).name - title << name - elsif params[:controller] == 'ec_years' - if params[:action] == 'training_objectives' - title << '培养目标' - elsif params[:action] == 'graduation_requirement' - title << '毕业要求' - elsif params[:action] == 'requirement_vs_objective' - title << '毕业要求 vs 培养目标' - elsif params[:action] == 'requirement_vs_standard' - title << '毕业要求 vs 通用标准' - elsif params[:action] == 'ec_course_setting' || params[:action] == 'completion_calculation' - title << '课程体系' - else - title << '工程认证' - end - elsif params[:controller] == 'ec_courses' - if params[:action] == 'ec_course_support_setting' - title << '课程体系 vs 毕业要求' - end - elsif @user - if !@project_community.blank? || !@user_projectlist.blank? - title << "项目" - elsif !@course_community.blank? || !@user_courselist.blank? - title << "课堂" - elsif !@contest_community.blank? - title << @contest_community - elsif !@manage_issues.blank? - title << @manage_issues - elsif !@receive_issues.blank? - title << @receive_issues - elsif !@manage_homeworks.blank? - title << @manage_homeworks - elsif !@receive_homeworks.blank? - title << @receive_homeworks - else - title << @user.show_name - end - elsif @syllabus - title << (@syllabus.title.nil? ? "课堂" : @syllabus.title) - else - title << (User.current.id == 2 ? "未登录" : User.current.show_name) - end - # if first_page.nil? || first_page.web_title.nil? - # title << Setting.app_title unless Setting.app_title == title.last - # else - # title << first_page.web_title unless first_page.web_title == title.last - # end - title.select {|t| !t.blank? }.join(' - ') - else - @html_title ||= [] - @html_title += args - end - end - - # Returns the theme, controller name, and action as css classes for the - # HTML body. - def body_css_classes - css = [] - if theme = Redmine::Themes.theme(Setting.ui_theme) - css << 'theme-' + theme.name - end - - css << 'controller-' + controller_name - css << 'action-' + action_name - css.join(' ') - end - - def accesskey(s) - @used_accesskeys ||= [] - key = Redmine::AccessKeys.key_for(s) - return nil if @used_accesskeys.include?(key) - @used_accesskeys << key - key - end - - # Formats text according to system settings. - # 2 ways to call this method: - # * with a String: textilizable(text, options) - # * with an object and one of its attribute: textilizable(issue, :description, options) - def textilizable(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - case args.size - when 1 - obj = options[:object] - text = args.shift - when 2 - obj = args.shift - attr = args.shift - text = obj.send(attr).to_s - else - raise ArgumentError, 'invalid arguments to textilizable' - end - return '' if text.blank? - project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) - only_path = options.delete(:only_path) == false ? false : true - - text = text.dup - macros = catch_macros(text) - text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) - - @parsed_headings = [] - @heading_anchors = {} - @current_section = 0 if options[:edit_section_links] - - parse_sections(text, project, obj, attr, only_path, options) - text = parse_non_pre_blocks(text, obj, macros) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| - send method_name, text, project, obj, attr, only_path, options - end - end - parse_headings(text, project, obj, attr, only_path, options) - - if @parsed_headings.any? - replace_toc(text, @parsed_headings) - end - - text.html_safe - end - - # - #格式化字符串,不转义html代码 - def textAreailizable(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - case args.size - when 1 - obj = options[:object] - text = args.shift - when 2 - obj = args.shift - attr = args.shift - text = obj.send(attr).to_s - else - raise ArgumentError, 'invalid arguments to textilizable' - end - return '' if text.blank? - project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) - only_path = options.delete(:only_path) == false ? false : true - - text = text.dup - macros = catch_macros(text) - #text = Redmine::WikiFormatting.to_html("CKEditor", text, :object => obj, :attribute => attr) - - @parsed_headings = [] - @heading_anchors = {} - @current_section = 0 if options[:edit_section_links] - - parse_sections(text, project, obj, attr, only_path, options) - text = parse_non_pre_blocks(text, obj, macros) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| - send method_name, text, project, obj, attr, only_path, options - end - end - parse_headings(text, project, obj, attr, only_path, options) - - if @parsed_headings.any? - replace_toc(text, @parsed_headings) - end - - text.html_safe - end - - def parse_non_pre_blocks(text, obj, macros) - s = StringScanner.new(text) - tags = [] - parsed = '' - while !s.eos? - s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) - text, full_tag, closing, tag = s[1], s[2], s[3], s[4] - if tags.empty? - yield text - inject_macros(text, obj, macros) if macros.any? - else - inject_macros(text, obj, macros, false) if macros.any? - end - parsed << text - if tag - if closing - if tags.last == tag.downcase - tags.pop - end - else - tags << tag.downcase - end - parsed << full_tag - end - end - # Close any non closing tags - while tag = tags.pop - parsed << "#{tag}>" - end - parsed - end - - def parse_inline_attachments(text, project, obj, attr, only_path, options) - # when using an image link, try to use an attachment, if possible - attachments = options[:attachments] || [] - attachments += obj.attachments if obj.respond_to?(:attachments) - if attachments.present? - text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| - filename, ext, alt, alttext = $1.downcase, $2, $3, $4 - # search for the picture in attachments - if found = Attachment.latest_attach(attachments, filename) - image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) - desc = found.description.to_s.gsub('"', '') - if !desc.blank? && alttext.blank? - alt = " title=\"#{desc}\" alt=\"#{desc}\"" - end - "src=\"#{image_url}\"#{alt}" - else - m - end - end - end - end - - # 判断课程、项目、组织是否有权限删除历史资源 - # 项目管理员或者附件的作者可以删除 - # (is_project_manager?(User.current.id, @project.id) || User.current.id == history.author_id) - def allow_to_delete_attachment history - attachment = history.attachment - case attachment.try(:container_type) - when "Project" - result = is_project_manager?(User.current.id, attachment.container_id) || User.current.id == history.author_id || User.current.admin? - when "Course" - result = User.current.allowed_to?(:as_teacher, attachment.container) || User.current.id == history.author_id || User.current.admin? - when "OrgSubfield" - result = User.current.id == history.author_id || User.current.admin_of_org?(attachment.container) || User.current.admin? - end - end - - # Wiki links - # - # Examples: - # [[mypage]] - # [[mypage|mytext]] - # wiki links can refer other project wikis, using project name or identifier: - # [[project:]] -> wiki starting page - # [[project:|mytext]] - # [[project:mypage]] - # [[project:mypage|mytext]] - def parse_wiki_links(text, project, obj, attr, only_path, options) - text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| - link_project = project - esc, all, page, title = $1, $2, $3, $5 - if esc.nil? - if page =~ /^([^\:]+)\:(.*)$/ - identifier, page = $1, $2 - link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) - title ||= identifier if page.blank? - end - - if link_project && link_project.wiki - # extract anchor - anchor = nil - if page =~ /^(.+?)\#(.+)$/ - page, anchor = $1, $2 - end - anchor = sanitize_anchor_name(anchor) if anchor.present? - # check if page exists - wiki_page = link_project.wiki.find_page(page) - url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page - "##{anchor}" - else - case options[:wiki_links] - when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') - when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export - else - wiki_page_id = page.present? ? Wiki.titleize(page) : nil - parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil - url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, - :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) - end - end - link_to(title.present? ? title.html_safe : h(page), User.current.logged? ? url : signin_url_without_domain, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) - else - # project or wiki doesn't exist - all - end - else - all - end - end - end - - def select_option_helper option - tmp = Hash.new - tmp={"" => ""} - if option.nil? - else - option.each do |project| - tmp[project.name] = project.id - end - end - tmp - end - # Redmine links - # - # Examples: - # Issues: - # #52 -> Link to issue #52 - # Changesets: - # r52 -> Link to revision 52 - # commit:a85130f -> Link to scmid starting with a85130f - # Documents: - # document#17 -> Link to document with id 17 - # document:Greetings -> Link to the document with title "Greetings" - # document:"Some document" -> Link to the document with title "Some document" - # Versions: - # version#3 -> Link to version with id 3 - # version:1.0.0 -> Link to version named "1.0.0" - # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" - # Attachments: - # attachment:file.zip -> Link to the attachment of the current object named file.zip - # Source files: - # source:some/file -> Link to the file located at /some/file in the project's repository - # source:some/file@52 -> Link to the file's revision 52 - # source:some/file#L120 -> Link to line 120 of the file - # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 - # export:some/file -> Force the download of the file - # Forum messages: - # message#1218 -> Link to message with id 1218 - # - # Links can refer other objects from other projects, using project identifier: - # identifier:r52 - # identifier:document:"Some document" - # identifier:version:1.0.0 - # identifier:source:some/file - def parse_redmine_links(text, default_project, obj, attr, only_path, options) - text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| - leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 - link = nil - project = default_project - if project_identifier - project = Project.visible.find_by_identifier(project_identifier) - end - if esc.nil? - if prefix.nil? && sep == 'r' - if project - repository = nil - if repo_identifier - repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} - else - repository = project.repository - end - # project.changesets.visible raises an SQL error because of a double join on repositories - if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier)) - link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision}, - :class => 'changeset', - :title => truncate_single_line(changeset.comments, :length => 100)) - end - end - elsif sep == '#' - oid = identifier.to_i - case prefix - when nil - if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) - anchor = comment_id ? "note-#{comment_id}" : nil - link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, - :class => issue.css_classes, - :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") - end - when 'document' - if document = Document.visible.find_by_id(oid) - link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, - :class => 'document' - end - when 'version' - if version = Version.visible.find_by_id(oid) - link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, - :class => 'version' - end - when 'message' - if message = Message.visible.find_by_id(oid, :include => :parent) - link = link_to_message(message, {:only_path => only_path}, :class => 'message') - end - when 'forum' - if board = Board.visible.find_by_id(oid) - link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, - :class => 'board' - end - when 'news' - if news = News.visible.find_by_id(oid) - link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, - :class => 'news' - end - when 'project' - if p = Project.visible.find_by_id(oid) - link = link_to_project(p, {:only_path => only_path}, :class => 'project') - end - end - elsif sep == ':' - # removes the double quotes if any - name = identifier.gsub(%r{^"(.*)"$}, "\\1") - case prefix - when 'document' - if project && document = project.documents.visible.find_by_title(name) - link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, - :class => 'document' - end - when 'version' - if project && version = project.versions.visible.find_by_name(name) - link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, - :class => 'version' - end - when 'forum' - if project && board = project.boards.visible.find_by_name(name) - link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, - :class => 'board' - end - when 'news' - if project && news = project.news.visible.find_by_title(name) - link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, - :class => 'news' - end - when 'commit', 'source', 'export' - if project - repository = nil - if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$} - repo_prefix, repo_identifier, name = $1, $2, $3 - repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} - else - repository = project.repository - end - if prefix == 'commit' - if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) - link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier}, - :class => 'changeset', - :title => truncate_single_line(changeset.comments, :length => 100) - end - else - if repository && User.current.allowed_to?(:browse_repository, project) - name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} - path, rev, anchor = $1, $3, $5 - link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, - :path => to_path_param(path), - :rev => rev, - :anchor => anchor}, - :class => (prefix == 'export' ? 'source download' : 'source') - end - end - repo_prefix = nil - end - when 'attachment' - attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) - if attachments && attachment = Attachment.latest_attach(attachments, name) - link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') - end - when 'project' - if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first - link = link_to_project(p, {:only_path => only_path}, :class => 'project') - end - end - end - end - (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) - end - end - - HEADING_RE = /(\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) - - # Renders the TOC with given headings - def replace_toc(text, headings) - text.gsub!(TOC_RE) do - # Keep only the 4 first levels - headings = headings.select{|level, anchor, item| level <= 4} - if headings.empty? - '' - else - div_class = 'toc' - div_class << ' right' if $1 == '>' - div_class << ' left' if $1 == '<' - out = "
'.html_safe + l(:label_export_to)) + yield Redmine::Views::OtherFormatsBuilder.new(self) + concat('
'.html_safe) + end + + def page_header_title + if @project.nil? || @project.new_record? + h(Setting.app_title) + else + b = [] + ancestors = (@project.root? ? [] : @project.ancestors.visible.all) + if ancestors.any? + root = ancestors.shift + b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') + if ancestors.size > 2 + b << "\xe2\x80\xa6" + ancestors = ancestors[-2, 2] + end + b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } + end + b << h(@project) + b.join(" \xc2\xbb ").html_safe + end + end + + def html_title(*args) + #點擊項目版本庫 多觸發一次 字符串為"/" + #暫時解決方法 直接判斷 + if(args == ["/"]) + args = [] + end + # first_page = FirstPage.find_by_page_type('project') + if args.empty? + title = @html_title || [] + if @project + title << (@project.name.present? ? @project.name : "项目") + elsif params[:controller] == "projects" + title << "项目" + elsif @welcome + title << "创新源于实践" + elsif @course + title << (@course.name.nil? ? "课堂" : @course.name) + elsif params[:controller] == "homework_bank" || params[:controller] == "question_banks" || params[:controller] == "exercise_bank" + title << ("题库") + elsif params[:controller] == "managements" + title << ("后台管理") + elsif params[:controller] == "colleges" && params[:action] == "statistics" + title << ("#{@school.name}") + elsif params[:controller] == "account" && params[:action] == "help" + if params[:index] + case params[:index] + when "1" + title << ("关于我们") + when "2" + title << ("联系我们") + when "3" + title << ("合作伙伴") + when "4" + title << ("服务协议") + when "5" + title << ("帮助中心") + when "6" + title << ("意见反馈") + end + else + title << ("关于我们") + end + elsif params[:controller] == "courses" && params[:action] == "index" + title << ("翻转课堂") + elsif params[:controller] == "competitions" && params[:action] == "index" + title << ("竞赛") + elsif @competition + title << (@competition.name.nil? ? "竞赛" : @competition.name) + elsif @contest + title << (@contest.name.nil? ? "创新源于实践" : @contest.name) + elsif @shixun + title << (@shixun.name.nil? ? "开发社区" : @shixun.name) + elsif @my_shixun + title << ("我的实训") + elsif params[:controller] == "shixuns" && params[:action] == "index" + title << ("开发社区") + elsif @subject + title << (@subject.name.nil? ? "实训课程" : @subject.name) + elsif params[:controller] == "subjects" && params[:action] == "index" + title << ("实训课程") + elsif @organization + title << (@organization.name.nil? ? "创新源于实践" : @organization.name) + elsif @forum || params[:controller] == "forums" + title << "讨论区" + elsif @my_syllabuses + title << "我的课堂" + elsif params[:controller] == 'ecs' + title << '专业列表' + elsif params[:controller] == 'ec_major_schools' + name = EcMajorSchool.find(params[:id]).name + title << name + elsif params[:controller] == 'ec_years' + if params[:action] == 'training_objectives' + title << '培养目标' + elsif params[:action] == 'graduation_requirement' + title << '毕业要求' + elsif params[:action] == 'requirement_vs_objective' + title << '毕业要求 vs 培养目标' + elsif params[:action] == 'requirement_vs_standard' + title << '毕业要求 vs 通用标准' + elsif params[:action] == 'ec_course_setting' || params[:action] == 'completion_calculation' + title << '课程体系' + else + title << '工程认证' + end + elsif params[:controller] == 'ec_courses' + if params[:action] == 'ec_course_support_setting' + title << '课程体系 vs 毕业要求' + end + elsif @user + if !@project_community.blank? || !@user_projectlist.blank? + title << "项目" + elsif !@course_community.blank? || !@user_courselist.blank? + title << "课堂" + elsif !@contest_community.blank? + title << @contest_community + elsif !@manage_issues.blank? + title << @manage_issues + elsif !@receive_issues.blank? + title << @receive_issues + elsif !@manage_homeworks.blank? + title << @manage_homeworks + elsif !@receive_homeworks.blank? + title << @receive_homeworks + else + title << @user.show_name + end + elsif @syllabus + title << (@syllabus.title.nil? ? "课堂" : @syllabus.title) + else + title << (User.current.id == 2 ? "未登录" : User.current.show_name) + end + # if first_page.nil? || first_page.web_title.nil? + # title << Setting.app_title unless Setting.app_title == title.last + # else + # title << first_page.web_title unless first_page.web_title == title.last + # end + title.select {|t| !t.blank? }.join(' - ') + else + @html_title ||= [] + @html_title += args + end + end + + # Returns the theme, controller name, and action as css classes for the + # HTML body. + def body_css_classes + css = [] + if theme = Redmine::Themes.theme(Setting.ui_theme) + css << 'theme-' + theme.name + end + + css << 'controller-' + controller_name + css << 'action-' + action_name + css.join(' ') + end + + def accesskey(s) + @used_accesskeys ||= [] + key = Redmine::AccessKeys.key_for(s) + return nil if @used_accesskeys.include?(key) + @used_accesskeys << key + key + end + + # Formats text according to system settings. + # 2 ways to call this method: + # * with a String: textilizable(text, options) + # * with an object and one of its attribute: textilizable(issue, :description, options) + def textilizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = text.dup + macros = catch_macros(text) + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @heading_anchors = {} + @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) + text = parse_non_pre_blocks(text, obj, macros) do |text| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + parse_headings(text, project, obj, attr, only_path, options) + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text.html_safe + end + + # + #格式化字符串,不转义html代码 + def textAreailizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = text.dup + macros = catch_macros(text) + #text = Redmine::WikiFormatting.to_html("CKEditor", text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @heading_anchors = {} + @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) + text = parse_non_pre_blocks(text, obj, macros) do |text| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + parse_headings(text, project, obj, attr, only_path, options) + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text.html_safe + end + + def parse_non_pre_blocks(text, obj, macros) + s = StringScanner.new(text) + tags = [] + parsed = '' + while !s.eos? + s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) + text, full_tag, closing, tag = s[1], s[2], s[3], s[4] + if tags.empty? + yield text + inject_macros(text, obj, macros) if macros.any? + else + inject_macros(text, obj, macros, false) if macros.any? + end + parsed << text + if tag + if closing + if tags.last == tag.downcase + tags.pop + end + else + tags << tag.downcase + end + parsed << full_tag + end + end + # Close any non closing tags + while tag = tags.pop + parsed << "#{tag}>" + end + parsed + end + + def parse_inline_attachments(text, project, obj, attr, only_path, options) + # when using an image link, try to use an attachment, if possible + attachments = options[:attachments] || [] + attachments += obj.attachments if obj.respond_to?(:attachments) + if attachments.present? + text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| + filename, ext, alt, alttext = $1.downcase, $2, $3, $4 + # search for the picture in attachments + if found = Attachment.latest_attach(attachments, filename) + image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) + desc = found.description.to_s.gsub('"', '') + if !desc.blank? && alttext.blank? + alt = " title=\"#{desc}\" alt=\"#{desc}\"" + end + "src=\"#{image_url}\"#{alt}" + else + m + end + end + end + end + + # 判断课程、项目、组织是否有权限删除历史资源 + # 项目管理员或者附件的作者可以删除 + # (is_project_manager?(User.current.id, @project.id) || User.current.id == history.author_id) + def allow_to_delete_attachment history + attachment = history.attachment + case attachment.try(:container_type) + when "Project" + result = is_project_manager?(User.current.id, attachment.container_id) || User.current.id == history.author_id || User.current.admin? + when "Course" + result = User.current.allowed_to?(:as_teacher, attachment.container) || User.current.id == history.author_id || User.current.admin? + when "OrgSubfield" + result = User.current.id == history.author_id || User.current.admin_of_org?(attachment.container) || User.current.admin? + end + end + + # Wiki links + # + # Examples: + # [[mypage]] + # [[mypage|mytext]] + # wiki links can refer other project wikis, using project name or identifier: + # [[project:]] -> wiki starting page + # [[project:|mytext]] + # [[project:mypage]] + # [[project:mypage|mytext]] + def parse_wiki_links(text, project, obj, attr, only_path, options) + text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| + link_project = project + esc, all, page, title = $1, $2, $3, $5 + if esc.nil? + if page =~ /^([^\:]+)\:(.*)$/ + identifier, page = $1, $2 + link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) + title ||= identifier if page.blank? + end + + if link_project && link_project.wiki + # extract anchor + anchor = nil + if page =~ /^(.+?)\#(.+)$/ + page, anchor = $1, $2 + end + anchor = sanitize_anchor_name(anchor) if anchor.present? + # check if page exists + wiki_page = link_project.wiki.find_page(page) + url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page + "##{anchor}" + else + case options[:wiki_links] + when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') + when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export + else + wiki_page_id = page.present? ? Wiki.titleize(page) : nil + parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil + url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, + :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) + end + end + link_to(title.present? ? title.html_safe : h(page), User.current.logged? ? url : signin_url_without_domain, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) + else + # project or wiki doesn't exist + all + end + else + all + end + end + end + + def select_option_helper option + tmp = Hash.new + tmp={"" => ""} + if option.nil? + else + option.each do |project| + tmp[project.name] = project.id + end + end + tmp + end + # Redmine links + # + # Examples: + # Issues: + # #52 -> Link to issue #52 + # Changesets: + # r52 -> Link to revision 52 + # commit:a85130f -> Link to scmid starting with a85130f + # Documents: + # document#17 -> Link to document with id 17 + # document:Greetings -> Link to the document with title "Greetings" + # document:"Some document" -> Link to the document with title "Some document" + # Versions: + # version#3 -> Link to version with id 3 + # version:1.0.0 -> Link to version named "1.0.0" + # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" + # Attachments: + # attachment:file.zip -> Link to the attachment of the current object named file.zip + # Source files: + # source:some/file -> Link to the file located at /some/file in the project's repository + # source:some/file@52 -> Link to the file's revision 52 + # source:some/file#L120 -> Link to line 120 of the file + # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 + # export:some/file -> Force the download of the file + # Forum messages: + # message#1218 -> Link to message with id 1218 + # + # Links can refer other objects from other projects, using project identifier: + # identifier:r52 + # identifier:document:"Some document" + # identifier:version:1.0.0 + # identifier:source:some/file + def parse_redmine_links(text, default_project, obj, attr, only_path, options) + text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| + leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 + link = nil + project = default_project + if project_identifier + project = Project.visible.find_by_identifier(project_identifier) + end + if esc.nil? + if prefix.nil? && sep == 'r' + if project + repository = nil + if repo_identifier + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + # project.changesets.visible raises an SQL error because of a double join on repositories + if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier)) + link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100)) + end + end + elsif sep == '#' + oid = identifier.to_i + case prefix + when nil + if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) + anchor = comment_id ? "note-#{comment_id}" : nil + link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, + :class => issue.css_classes, + :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") + end + when 'document' + if document = Document.visible.find_by_id(oid) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if version = Version.visible.find_by_id(oid) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'message' + if message = Message.visible.find_by_id(oid, :include => :parent) + link = link_to_message(message, {:only_path => only_path}, :class => 'message') + end + when 'forum' + if board = Board.visible.find_by_id(oid) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if news = News.visible.find_by_id(oid) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'project' + if p = Project.visible.find_by_id(oid) + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + elsif sep == ':' + # removes the double quotes if any + name = identifier.gsub(%r{^"(.*)"$}, "\\1") + case prefix + when 'document' + if project && document = project.documents.visible.find_by_title(name) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if project && version = project.versions.visible.find_by_name(name) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'forum' + if project && board = project.boards.visible.find_by_name(name) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if project && news = project.news.visible.find_by_title(name) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'commit', 'source', 'export' + if project + repository = nil + if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$} + repo_prefix, repo_identifier, name = $1, $2, $3 + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + if prefix == 'commit' + if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) + link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100) + end + else + if repository && User.current.allowed_to?(:browse_repository, project) + name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} + path, rev, anchor = $1, $3, $5 + link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, + :path => to_path_param(path), + :rev => rev, + :anchor => anchor}, + :class => (prefix == 'export' ? 'source download' : 'source') + end + end + repo_prefix = nil + end + when 'attachment' + attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) + if attachments && attachment = Attachment.latest_attach(attachments, name) + link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') + end + when 'project' + if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + end + end + (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) + end + end + + HEADING_RE = /(\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) + + # Renders the TOC with given headings + def replace_toc(text, headings) + text.gsub!(TOC_RE) do + # Keep only the 4 first levels + headings = headings.select{|level, anchor, item| level <= 4} + if headings.empty? + '' + else + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "