Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_item_bank

dev_jupyter
杨树林 5 years ago
commit d17578c4d1

@ -185,6 +185,9 @@ class AccountsController < ApplicationController
send_type = verify_type(login_type, type)
verification_code = code.sample(6).join
sign = Digest::MD5.hexdigest("#{OPENKEY}#{value}")
tip_exception(501, "请求不合理") if sign != params[:smscode]
logger.info("########get_verification_code: login_type #{login_type} send_type#{send_type}, ")
# 记录验证码

@ -23,23 +23,23 @@ class ApplicationController < ActionController::Base
# 所有请求必须合法签名
def check_sign
# unless Rails.env.development?
# Rails.logger.info("66666 #{params}")
# suffix = request.url.split(".").last.split("?").first
# suffix_arr = ["xls", "xlsx", "pdf"] # excel文件先注释
# unless suffix_arr.include?(suffix)
# if params[:client_key].present?
# randomcode = params[:randomcode]
# # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5)
#
# sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}")
# Rails.logger.info("2222 #{sign}")
# tip_exception(501, "请求不合理") if sign != params[:client_key]
# else
# tip_exception(501, "请求不合理")
# end
# end
# end
if !Rails.env.development? && EduSetting.get("host_name") != "https://test-newweb.educoder.net"
Rails.logger.info("66666 #{params}")
suffix = request.url.split(".").last.split("?").first
suffix_arr = ["xls", "xlsx", "pdf"] # excel文件先注释
unless suffix_arr.include?(suffix)
if params[:client_key].present?
randomcode = params[:randomcode]
# tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5)
sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}")
Rails.logger.info("2222 #{sign}")
tip_exception(501, "请求不合理") if sign != params[:client_key]
else
tip_exception(501, "请求不合理")
end
end
end
end
# 全局配置参数
@ -85,8 +85,8 @@ class ApplicationController < ActionController::Base
# 题库的访问权限
def bank_visit_auth
tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin? && @bank.user_id != current_user.id && @bank.is_public
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? ||
tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin_or_business? && @bank.user_id != current_user.id && @bank.is_public
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business? ||
(current_user.certification_teacher? && @bank.is_public)
end
@ -165,7 +165,7 @@ class ApplicationController < ActionController::Base
def find_course
return normal_status(2, '缺少course_id参数') if params[:course_id].blank?
@course = Course.find(params[:course_id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin?
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
rescue Exception => e
tip_exception(e.message)
end

@ -58,7 +58,7 @@ class CommonsController < ApplicationController
200
end
else
current_user.admin? ? 200 : 403
current_user.admin_or_business? ? 200 : 403
end
return normal_status(code, "你没有权限操作!") if code == 403
end

@ -396,7 +396,7 @@ class CoursesController < ApplicationController
def teachers
@search_str = params[:search].present? ? params[:search].strip : ""
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582
if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
@teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)
and LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{@search_str}%")
else
@ -441,7 +441,7 @@ class CoursesController < ApplicationController
@applications = CourseMessage.unhandled_join_course_requests_by_course(@course).
joins("join users on course_messages.course_message_id=users.id").
where("LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{search_str}%")
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582
if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
teacher_list = @course.course_members.where("course_members.role in (1, 2, 3)")
else
teacher_list = @course.course_members.where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id}
@ -838,7 +838,7 @@ class CoursesController < ApplicationController
# 已通过职业认证的教师复制课堂
def duplicate_course
return tip_exception("没有复制权限") unless current_user.admin? || current_user.is_teacher? || current_user.teacher_of_course?(@course)
return tip_exception("没有复制权限") unless current_user.admin_or_business? || current_user.is_teacher? || current_user.teacher_of_course?(@course)
return tip_exception("教师职业认证未通过") unless current_user.pro_certification?
new_course = @course.self_duplicate
@ -1280,7 +1280,7 @@ class CoursesController < ApplicationController
end
if @all_members.size == 0
normal_status(-1,"课堂暂时没有学生")
normal_status(-1,"暂无学生数据")
elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中")
else
@ -1308,7 +1308,7 @@ class CoursesController < ApplicationController
end
if @all_members.length == 0
normal_status(-1,"课堂暂时没有学生")
normal_status(-1,"暂无学生数据")
elsif params[:export].present? && params[:export]
normal_status(0,"正在下载中")
else
@ -1404,7 +1404,7 @@ class CoursesController < ApplicationController
# Use callbacks to share common setup or constraints between actions.
def set_course
@course = Course.find_by!(id: params[:id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin?
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
end
# Never trust parameters from the scary internet, only allow the white list through.

@ -372,7 +372,7 @@ class ExerciseBankQuestionsController < ApplicationController
private
def bank_admin
tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin_or_business?
end
def get_exercise

@ -26,7 +26,7 @@ class ExerciseBanksController < ApplicationController
search = params[:search]
type = params[:type]
# 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
if current_user.admin?
if current_user.admin_or_business?
@shixuns = Shixun.unhidden
else
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
@ -67,7 +67,7 @@ class ExerciseBanksController < ApplicationController
end
def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end
#判断实训是否已选择

@ -382,6 +382,7 @@ class GraduationWorksController < ApplicationController
tip_exception("成绩不能为空") if params[:score].blank?
tip_exception("成绩不能小于零") if params[:score].to_f < 0
tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100
tip_exception("调分原因不能超过100个字符") if params[:comment].present? && params[:comment].length > 100
ActiveRecord::Base.transaction do
begin
# 分数不为空的历史评阅都置为失效
@ -410,7 +411,7 @@ class GraduationWorksController < ApplicationController
# 删除教师/教辅的评分记录
def delete_score
score = @work.graduation_work_scores.where(id: params[:comment_id]).first
if score.present? && (score.is_invalid || score.score.nil?) && (score.user == current_user || current_user.admin?)
if score.present? && (score.is_invalid || score.score.nil?) && (score.user == current_user || current_user.admin_or_business?)
begin
score.destroy
normal_status("删除成功")

@ -26,7 +26,7 @@ class GtopicBanksController < ApplicationController
end
def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end
def gtopic_bank_params

@ -47,7 +47,7 @@ class HomeworkBanksController < ApplicationController
end
def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end
def bank_params

@ -145,7 +145,7 @@ class HomeworkCommonsController < ApplicationController
@student_works = @homework.teacher_works(@member)
@all_member_count = @student_works.size
@score_open = true
elsif @user_course_identity > Course::STUDENT && @homework.work_public
elsif @user_course_identity > Course::STUDENT
@student_works = student_works
@score_open = false
else
@ -757,7 +757,7 @@ class HomeworkCommonsController < ApplicationController
search = params[:search]
type = params[:type]
# 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
if current_user.admin?
if current_user.admin_or_business?
@shixuns = Shixun.unhidden
else
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)

@ -144,6 +144,7 @@ class MemosController < ApplicationController
def reply
tip_exception("parent_id不能为空") if params[:parent_id].blank?
tip_exception("content不能为空") if params[:content].blank?
tip_exception("content不能超过1000字符") if params[:content].length > 1000
ActiveRecord::Base.transaction do
begin

@ -63,6 +63,7 @@ class MessagesController < ApplicationController
def reply
return normal_status(2, "回复内容不能为空") if params[:content].blank?
return normal_status(2, "回复内容不能超过1000字符") if params[:content].length > 1000
@reply = Message.create!(board: @message.board, root_id: @message.root_id || @message.id,
author: current_user, parent: @message,
message_detail_attributes: {
@ -126,7 +127,7 @@ class MessagesController < ApplicationController
end
def create
return normal_status(403, "您没有权限进行该操作") unless current_user.admin? || current_user.member_of_course?(@board.course)
return normal_status(403, "您没有权限进行该操作") unless current_user.admin_or_business? || current_user.member_of_course?(@board.course)
begin
@message = Message.new(message_params)

@ -114,7 +114,7 @@ class PollBankQuestionsController < ApplicationController
private
def bank_admin
tip_exception(403, "无权限") unless @poll.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @poll.user_id == current_user.id || current_user.admin_or_business?
end
def get_poll

@ -10,7 +10,7 @@ class QuestionBanksController < ApplicationController
def bank_list
page = params[:page] || 1
limit = params[:limit] || 15
@certification_teacher = current_user.is_certification_teacher || current_user.admin?
@certification_teacher = current_user.is_certification_teacher || current_user.admin_or_business?
@objects = @object_type.classify.constantize.where(@object_filter)
@objects =
if params[:search]
@ -134,7 +134,7 @@ class QuestionBanksController < ApplicationController
def destroy
bank = current_bank
unless current_user.admin? || bank.user_id == current_user.id
unless current_user.admin_or_business? || bank.user_id == current_user.id
render_forbidden
return
end
@ -165,7 +165,7 @@ class QuestionBanksController < ApplicationController
def object_banks
banks ||= @object_type.classify.constantize.where(@object_filter).where(id: params[:object_id])
unless current_user.admin?
unless current_user.admin_or_business?
banks = banks.where(user_id: current_user.id)
end
banks
@ -202,7 +202,7 @@ class QuestionBanksController < ApplicationController
end
def teacher_or_admin
tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin?
tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin_or_business?
end
def quote_homework_bank homework, course

@ -546,6 +546,7 @@ class StudentWorksController < ApplicationController
tip_exception("成绩不能为空") if params[:score].blank?
tip_exception("成绩不能小于零") if params[:score].to_f < 0
tip_exception("成绩不能大于100") if params[:score].to_f.round(1) > 100
tip_exception("调分原因不能超过100个字符") if params[:comment].present? && params[:comment].length > 100
ActiveRecord::Base.transaction do
begin
# 分数不为空的历史评阅都置为失效

@ -7,7 +7,7 @@ class SubjectsController < ApplicationController
:search_members, :add_subject_members, :statistics, :shixun_report, :school_report,
:up_member_position, :down_member_position, :update_team_title]
before_action :require_admin, only: [:copy_subject]
before_action :shixun_marker, only: [:new, :create, :add_shixun_to_stage]
before_action :shixun_marker, only: [:add_shixun_to_stage]
include ApplicationHelper
@ -456,6 +456,25 @@ class SubjectsController < ApplicationController
end
end
def statistics_new
# data = Subjects::DataStatisticService.new(@subject)
# Rails.logger.info("study_count: #{data.study_count}")
# Rails.logger.info("course_study_count: #{ data.course_study_count}")
# Rails.logger.info("passed_count: #{data.passed_count}")
# Rails.logger.info("course_used_count: #{data.course_used_count}")
# Rails.logger.info("school_used_count: #{data.school_used_count}")
# data_1 = Subjects::CourseUsedInfoService.call(@subject)
# Rails.logger.info("study_count: #{data_1}")
# data_2 = Subjects::ShixunUsedInfoService.call(@subject)
# Rails.logger.info("study_count: #{data_2}")
data_3 = Subjects::UserUsedInfoService.call(@subject)
Rails.logger.info("study_count: #{data_3}")
render_ok()
end
def shixun_report
end

@ -29,7 +29,7 @@ class TaskBanksController < ApplicationController
end
def bank_admin
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin_or_business?
end
def gtask_bank_params

@ -66,9 +66,9 @@ class Users::QuestionBanksController < Users::BaseController
def check_user_permission!
if params[:type] == 'publicly'
normal_status(-2,"未通过职业认证") unless User.current.admin? || User.current.certification_teacher?
normal_status(-2,"未通过职业认证") unless User.current.admin_or_business? || User.current.certification_teacher?
else
render_forbidden unless User.current.admin? || User.current.is_teacher?
render_forbidden unless User.current.admin_or_business? || User.current.is_teacher?
end
end
end

@ -39,7 +39,7 @@ class Weapps::CoursesController < Weapps::BaseController
@page = (params[:page] || 1).to_i
@limit = (params[:limit] || 20).to_i
search = params[:search].present? ? params[:search].strip : ""
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582
if @course.try(:id) != 1309 || current_user.admin_or_business? || current_user.try(:id) == 15582
@teacher_list = @course.course_members.joins(:user).where("course_members.role in (1, 2, 3)")
else
@teacher_list = @course.course_members.joins(:user).where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id}
@ -203,6 +203,6 @@ class Weapps::CoursesController < Weapps::BaseController
def set_course
@course = Course.find_by!(id: params[:id])
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin?
tip_exception(404, "") if @course.is_delete == 1 && !current_user.admin_or_business?
end
end

@ -47,9 +47,10 @@ module ExportHelper
user_name = user.real_name
user_mail = user.mail
user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--"
user_grade = user.grade
user_school = user.school_name
user_course_group = u.course_group_name
user_info_array = [user_name,user_login,user_mail,user_stu_id,user_school,user_course_group] #用户的信息集合
user_info_array = [user_name,user_login,user_mail,user_stu_id,user_grade,user_school,user_course_group] #用户的信息集合
user_work_scores = []
#学生总成绩
@ -150,7 +151,7 @@ module ExportHelper
course_user_score_title = "学生总成绩"
score_title_cells = shixun_titles + common_titles + group_titles + task_titles + exercise_titles
score_title_counts = [shixun_titles.count,common_titles.count,group_titles.count,task_titles.count,exercise_titles.count]
score_cell_head = %w(序号 真实姓名 登录名 邮箱 学号 学校 分班 个人总成绩) + score_title_cells
score_cell_head = %w(序号 真实姓名 登录名 邮箱 学号 金币 学校 分班 个人总成绩) + score_title_cells
@course_user_scores = [course_user_score_title,score_cell_head,score_title_counts,total_user_score_array]
#作业的全部集合

@ -28,6 +28,9 @@ class Challenge < ApplicationRecord
scope :fields_for_list, -> { select([:id, :subject, :st, :score, :position, :shixun_id]) }
validates :task_pass, length: { maximum: 10000 }
after_commit :create_diff_record
def next_challenge

@ -3,6 +3,8 @@ class ChallengeAnswer < ApplicationRecord
belongs_to :challenge
has_many :game_answers, :dependent => :destroy
validates :contents, length: { maximum: 5000 }
def view_answer_time(user_id)
game_answers.where(user_id: user_id).last&.view_time
end

@ -3,4 +3,7 @@ class ChallengeChoose < ApplicationRecord
belongs_to :challenge, optional: true
has_many :challenge_tags, :dependent => :destroy
has_many :challenge_questions, dependent: :destroy
validates :subject, length: { maximum: 1000 }
end

@ -1,3 +1,6 @@
class ChallengeQuestion < ApplicationRecord
belongs_to :challenge_choose
validates :option_name, length: { maximum: 500 }
end

@ -33,6 +33,8 @@ class Competition < ApplicationRecord
has_many :competition_prizes, dependent: :destroy
has_many :competition_prize_users, dependent: :destroy
validates :introduction, length: { maximum: 500 }
before_save :set_laboratory
after_create :create_competition_modules

@ -5,4 +5,6 @@ class CompetitionModuleMdContent < ApplicationRecord
# validates :name, presence: true
validates :content, presence: true
validates :content, length: { maximum: 10000 }
end

@ -251,7 +251,7 @@ class Course < ApplicationRecord
member = course_member(user.id)
group_ids = if member.present?
member.teacher_course_groups.size > 0 ? member.teacher_course_groups.pluck(:course_group_id) : course_groups.pluck(:id)
elsif user.admin?
elsif user.admin_or_business?
course_groups.pluck(:id)
else
[]

@ -13,6 +13,8 @@ class Discuss < ApplicationRecord
belongs_to :challenge, optional: true
validate :validate_sensitive_string
validates :content, length: { maximum: 1000 }
after_create :send_tiding
scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) }

@ -20,6 +20,7 @@ class Exercise < ApplicationRecord
where("exercise_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
validates :exercise_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
validates :exercise_description, length: { maximum: 100 }
after_create :create_exercise_list

@ -11,4 +11,6 @@ class ExerciseAnswer < ApplicationRecord
scope :exercise_answer_is_right, -> {where("score > ?",0.0)} #判断答案是否正确根据分数总和大于0
scope :score_reviewed, lambda {where("score >= ?",0.0)} #是否评分,用于判断主观题的
validates :answer_text, length: { maximum: 5000 }
end

@ -6,4 +6,6 @@ class ExerciseAnswerComment < ApplicationRecord
belongs_to :exercise_answer, optional: true
scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)}
validates :comment, length: { maximum: 100 }
end

@ -4,4 +4,7 @@ class ExerciseBankChoice < ApplicationRecord
scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
validates :choice_text, length: { maximum: 500 }
end

@ -11,6 +11,8 @@ class ExerciseBankQuestion < ApplicationRecord
scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
validates :question_title, length: { maximum: 1000 }
def question_type_name
case self.question_type
when 0

@ -3,4 +3,7 @@ class ExerciseBankStandardAnswer < ApplicationRecord
belongs_to :exercise_bank_choice
#attr_accessible :answer_text
scope :standard_by_ids, lambda { |s| where(exercise_bank_choice_id: s) }
validates :answer_text, length: { maximum: 5000 }
end

@ -7,4 +7,6 @@ class ExerciseChoice < ApplicationRecord
scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
validates :choice_text, length: { maximum: 500 }
end

@ -16,6 +16,8 @@ class ExerciseQuestion < ApplicationRecord
scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
validates :question_title, length: { maximum: 1000 }
def question_type_name
case self.question_type

@ -6,5 +6,5 @@ class ExerciseStandardAnswer < ApplicationRecord
scope :find_standard_answer_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
scope :standard_by_ids, lambda { |s| where(exercise_choice_id: s) }
validates :answer_text, length: { maximum: 5000 }
end

@ -55,7 +55,7 @@ class GraduationWork < ApplicationRecord
end
def delete_atta atta
last_score = graduation_work_scores.where.not(score: nil).last
last_score = graduation_work_scores.last
(atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on)
end

@ -5,5 +5,5 @@ class GraduationWorkScore < ApplicationRecord
belongs_to :graduation_task
has_many :attachments, as: :container, dependent: :destroy
validates :comment, length: { maximum: 2000 }
validates :comment, length: { maximum: 1000 }
end

@ -9,4 +9,6 @@ class GtaskBank < ApplicationRecord
scope :myself, ->(user_id) { where(user_id: user_id)}
scope :is_public, -> { where(:is_public => true) }
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 5000 }
end

@ -7,4 +7,11 @@ class GtopicBank < ApplicationRecord
has_many :graduation_topics, dependent: :nullify
scope :myself, ->(user_id) { where(user_id: user_id)}
# 课题名称和描述字段长度限制
validates :name, length: { maximum: 60,
too_long: "60 characters is the maximum allowed" }
validates :description, length: { maximum: 5000,
too_long: "5000 characters is the maximum allowed" }
end

@ -3,6 +3,7 @@ class Hack < ApplicationRecord
# diffcult: 难度 1简单2中等 3困难
# 编程题
validates_length_of :name, maximum: 60
validates_length_of :description, maximum: 5000
validates :description, presence: { message: "描述不能为空" }
validates :name, presence: { message: "名称不能为空" }
# 测试集

@ -1,4 +1,6 @@
class HackSet < ApplicationRecord
validates_length_of :input, maximum: 500
validates_length_of :output, maximum: 500
validates :input, presence: { message: "测试集输入不能为空" }
validates :output, presence: { message: "测试集输出不能为空" }
validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同"

@ -10,4 +10,7 @@ class HomeworkBank < ApplicationRecord
scope :is_public, -> { where(is_public: true)}
scope :myself, ->(user_id) { where(user_id: user_id)}
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 15000 }
validates :reference_answer, length: { maximum: 15000 }
end

@ -24,7 +24,9 @@ class JournalsForMessage < ApplicationRecord
# "m_reply_count", # 留言的回复数量
# "m_reply_id" , # 回复某留言的留言id(a留言回复了b留言这是b留言的id)
# "is_comprehensive_evaluation", # 1 教师评论、2 匿评、3 留言
# "hidden", 隐藏
# "hidden", 隐藏、
validates :notes, length: { maximum: 1000 }
after_create :send_tiding

@ -13,6 +13,7 @@ class Library < ApplicationRecord
has_one :praise_tread_cache, foreign_key: :object_id
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
validates :content, length: { maximum: 5000 }
validates :uuid, presence: true, uniqueness: true

@ -27,6 +27,8 @@ class Memo < ApplicationRecord
scope :hot, -> { order("all_replies_count desc, updated_at desc") }
scope :posts, -> { where(root_id: nil, forum_id: [3, 5]) }
validates :content, length: { maximum: 10000 }
after_create :send_tiding
# 帖子的回复
@ -39,6 +41,13 @@ class Memo < ApplicationRecord
Memo.where(parent_id: id).includes(:author).reorder("created_at asc")
end
# 主贴的名称
def main_subject
memo = Memo.find_by(root_id: id)
Rails.logger.info("###############memo: #{memo&.subject}")
memo ? memo.subject : subject
end
private
def send_tiding

@ -39,6 +39,12 @@ class Message < ApplicationRecord
message_detail.update_attributes(content: content)
end
# 主贴的名称
def main_subject
Rails.logger.info("##########parent: #{parent&.subject}")
parent.present? ? parent.subject : subject
end
def copy_attachments_to_new_message(new_message, user)
attachments.each do |attach|
new_message.attachments << Attachment.new(attach.attributes.except("id").merge(

@ -1,4 +1,5 @@
class MessageDetail < ApplicationRecord
belongs_to :message, :touch => true
validates :content, length: { maximum: 5000 }
end

@ -5,6 +5,7 @@ class Myshixun < ApplicationRecord
has_one :shixun_modify, :dependent => :destroy
belongs_to :user
belongs_to :user_extension, foreign_key: :user_id
belongs_to :shixun, counter_cache: true
has_one :last_executable_task, -> { where(status: [0, 1]).reorder(created_at: :asc) }, class_name: 'Game'
@ -21,7 +22,7 @@ class Myshixun < ApplicationRecord
end
def output_times
games.pluck(:evaluate_count).sum.to_i
games.map(&:evaluate_count).sum.to_i
end
def repo_path

@ -25,6 +25,7 @@ class Poll < ApplicationRecord
where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
validates :polls_name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
validates :polls_description, length: { maximum: 100 }
after_create :create_polls_list

@ -8,4 +8,6 @@ class PollAnswer < ApplicationRecord
scope :find_answer_by_custom, lambda {|k,v| where("#{k}":v)} #根据传入的参数查找问题
scope :left_answer_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
validates :answer_text, length: { maximum: 500 }
end

@ -9,6 +9,8 @@ class PollQuestion < ApplicationRecord
scope :ques_necessary, -> {where("is_necessary = ?",1)}
scope :insert_question, lambda {|k| where("question_number > ?",k)}
validates :question_title, length: { maximum: 1000 }
def question_type_name
case self.question_type
when 1

@ -8,4 +8,7 @@ class PollVote < ApplicationRecord
scope :find_current_vote,lambda {|k,v| where("#{k}": v)}
scope :find_vote_text,-> {where("vote_text IS NOT NULL")}
validates :vote_text, length: { maximum: 5000 }
end

@ -30,6 +30,8 @@ class Shixun < ApplicationRecord
has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire
has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
has_many :homework_commons, through: :homework_commons_shixuns
has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun'
#实训的关卡
@ -59,6 +61,9 @@ class Shixun < ApplicationRecord
# Jupyter数据集,附件
has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy
# 试卷的实训题
has_many :exercise_questions
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{keyword}%", "%#{keyword}%") }

@ -4,6 +4,8 @@ class ShixunInfo < ApplicationRecord
validates_length_of :fork_reason, maximum: 60
after_commit :create_diff_record
validates :description, length: { maximum: 5000 }
private
def create_diff_record

@ -2,4 +2,6 @@ class ShixunWorkComment < ApplicationRecord
belongs_to :student_work
belongs_to :user
belongs_to :challenge, optional: true
validates :comment, length: { maximum: 500 }
validates :hidden_comment, length: { maximum: 500 }
end

@ -7,5 +7,5 @@ class Stage < ApplicationRecord
has_many :shixuns, :through => :stage_shixuns
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 300 }
validates :description, length: { maximum: 1000 }
end

@ -105,7 +105,7 @@ class StudentWork < ApplicationRecord
end
def delete_atta atta
last_score = student_works_scores.where.not(score: nil).last
last_score = student_works_scores.last
(atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on)
end

@ -7,7 +7,7 @@ class StudentWorksScore < ApplicationRecord
has_many :tidings, as: :container, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy
validates :comment, length: { maximum: 2000 }
validates :comment, length: { maximum: 1000 }
scope :shixun_comment, lambda { where(is_ultimate: 0) }
@ -17,7 +17,7 @@ class StudentWorksScore < ApplicationRecord
end
def allow_delete current_user
(self.is_invalid || self.score.nil?) && (current_user == self.user || current_user.admin?)
(self.is_invalid || self.score.nil?) && (current_user == self.user || current_user.admin_or_business?)
end
# 匿评分

@ -25,6 +25,11 @@ class Subject < ApplicationRecord
has_many :courses, -> { where("is_delete = 0").order("courses.created_at ASC") }
has_many :laboratory_subjects, dependent: :destroy
# 学习统计
has_one :subject_record, dependent: :destroy
has_many :subject_course_records, dependent: :destroy
has_many :subject_shixun_infos, dependent: :destroy
has_many :subject_user_infos, dependent: :destroy
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 8000 }

@ -0,0 +1,3 @@
class SubjectCourseRecord < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectRecord < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectShixunInfo < ApplicationRecord
belongs_to :subject
end

@ -0,0 +1,3 @@
class SubjectUserInfo < ApplicationRecord
belongs_to :subject
end

@ -1,3 +1,7 @@
class TestSet < ApplicationRecord
# match_rule: 匹配规则: full 完全匹配, last 末尾匹配
#
validates :input, length: { maximum: 5000 }
validates :input, length: { maximum: 5000 }
end

@ -43,6 +43,7 @@ class User < ApplicationRecord
has_many :shixun_members, :dependent => :destroy
has_many :shixuns, :through => :shixun_members
has_many :myshixuns, :dependent => :destroy
has_many :games, :dependent => :destroy
has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训
has_many :course_messages
has_many :courses, foreign_key: 'tea_id', dependent: :destroy

@ -58,7 +58,7 @@ class DiscussesService
praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin?
)
# 发送手机通知
Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员')
# Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员')
rescue Exception => e
raise(e.message)
end

@ -0,0 +1,40 @@
class Subjects::CourseUsedInfoService < ApplicationService
attr_reader :subject
def initialize(subject)
@subject = subject
@shixun_ids = subject.shixuns.pluck(:id)
end
def call
return if subject.blank?
homework_commons =
HomeworkCommon.joins(:homework_commons_shixun)
.where(homework_type: %i[practice])
.where(homework_commons_shixuns: {shixun_id: @shixun_ids})
course_ids = homework_commons.pluck(:course_id)
homework_common_ids = homework_commons.pluck("homework_commons.id")
schools = School.joins(:courses).where(courses: {id: course_ids}).group("schools.id").select("schools.*, count(courses.id) course_count")
# name将该课程使用到课堂的单位
# course_count: 将该课程使用到课堂的数量
# student_count: 课堂的学生总数(去掉重复)
# choice_shixun_num: 选用该课程实训的个数(去重)
# choice_shixun_frequency: 选用该课程实训的次数
course_info = []
schools.map do |school|
name = school.name
course_count = school.course_count
student_count = school.courses.joins(:course_members).where(course_members: {role: 4, course_id: course_ids}).size
shixun_ids = school.courses.joins(homework_commons: :homework_commons_shixun)
.where(homework_commons: {id: homework_common_ids})
.pluck("homework_commons_shixuns.shixun_id")
choice_shixun_frequency = shixun_ids.size
choice_shixun_num = shixun_ids.uniq.size
course_info << {school_id: school.id, school_name: name, course_count: course_count, student_count: student_count,
choice_shixun_num: choice_shixun_num, choice_shixun_frequency: choice_shixun_frequency}
end
course_info
end
end

@ -0,0 +1,72 @@
class Subjects::DataStatisticService < ApplicationService
attr_reader :subject
def initialize(subject)
@subject = subject
@shixuns = subject.shixuns
@shixun_ids = @shixuns.pluck(:id)
end
# 学习总人数:
# 文案解释:学习该课程的全部人数(学习总人数=课堂学习人数+自主学习人数)
# 开发备注只要点击该课程的任何一个实训生成了tpi都算一个学习人数去重一个人数计算1次
def study_count
@shixuns.joins(:myshixuns).pluck("myshixuns.user_id").uniq.size
end
# 课堂学习人数:
# 文案解释:通过课堂学习该课程的人数
# 开发备注只要通过课堂进入并点击了实训生成了tpi则算一个可以学习人数去重一个人数计算1次
def course_study_count
# 实训作业
sw_user_ids = StudentWork.where.not(myshixun_id: 0).joins(homework_common: :homework_commons_shixun)
.where(homework_commons_shixuns: {shixun_id: @shixun_ids}).pluck("student_works.user_id")
# 试卷的实训题
esa_user_ids = ExerciseShixunAnswer.joins(exercise_shixun_challenge: :shixun)
.where(shixuns: {id: @shixun_ids}).pluck("exercise_shixun_answers.user_id")
(sw_user_ids + esa_user_ids).uniq.size
end
# 自主学习人数:
# 文案解释:通过自主学习该课程的人数
# 开发备注非课程进入生成了实训的tpi去重。一个人数计算1次
def initiative_study
study_count - course_study_count
end
# 通关总人数:
# 文案解释:
# 通关该课程所有实训的人数去重。一个人数计算1次
def passed_count
@shixuns.includes(:myshixuns).where(myshixuns: {status: 1}).pluck("myshixuns.user_id").uniq.size
end
# 使用课堂数:
# 文案解释:使用该课程的课堂数量
# 开发备注课堂加入该课程的实训到自己课堂则算一个使用课堂数。去重一个课堂计算1次
def course_used_count
hc_course_ids =
HomeworkCommon.joins(:homework_commons_shixun)
.where(homework_type: %i[practice])
.where(homework_commons_shixuns: {shixun_id: @shixun_ids}).pluck("homework_commons.course_id").uniq
ex_course_ids =
Exercise.joins(:exercise_questions)
.where(exercise_questions: {question_type: 5, shixun_id: @shixun_ids}).pluck("exercises.course_id").uniq
(hc_course_ids + ex_course_ids).uniq.size
end
# 使用单位数:
# 文案解释:使用该课程的单位数量(包括自主学习者所在单位)
# 开发备注:凡事该单位有使用该课程的实训(自主学习+课堂使用)都算;(去重,一个单位计算一次)
def school_used_count
school_ids.size
end
private
def school_ids
@shixuns.joins(myshixuns: :user_extension).pluck("user_extensions.school_id").uniq
end
end

@ -0,0 +1,30 @@
class Subjects::ShixunUsedInfoService < ApplicationService
attr_reader :subject, :stages
def initialize(subject)
@subject = subject
@stages = subject.stages.includes(shixuns: [myshixuns: :games, homework_commons_shixuns: [homework_common: :course]])
end
def call
shixun_infos = []
stages.each do |stage|
position = stage.position
stage.shixuns.each_with_index do |shixun, index|
stage = "#{position}-#{index+1}"
name = shixun.name
challenge_count = shixun.challenges_count
course_count = shixun.homework_commons.map{|hc| hc.course_id}.uniq.size
school_count = shixun.homework_commons.map{|hc| hc.course&.school_id}.uniq.size
used_count = shixun.myshixuns_count
passed_count = shixun.myshixuns.select{|m| m.status == 1}.size
evaluate_count = shixun.myshixuns.map{|m| m.output_times }.sum
passed_ave_time = passed_count > 0 ? shixun.myshixuns.map{|m| m.total_cost_time}.sum : 0
shixun_infos << {stage: stage, name: name, challenge_count: challenge_count, course_count: course_count,
school_count: school_count, used_count: used_count, passed_count: passed_count,
evaluate_count: evaluate_count, passed_ave_time: passed_ave_time, shixun_id: shixun.id}
end
end
shixun_infos
end
end

@ -0,0 +1,28 @@
class Subjects::UserUsedInfoService < ApplicationService
attr_reader :subject, :shixun_ids
def initialize(subject)
@subject = subject
@shixun_ids = subject.shixuns.pluck(:id)
end
def call
users_info = []
users = User.includes(myshixuns: :games).where(myshixuns: {shixun_id: shixun_ids}, games: {status: 2})
users.each do |user|
myshixuns = user.myshixuns.select{|m| shixun_ids.include?(m.shixun_id)}
name = "#{user.lastname}#{user.firstname}"
passed_myshixun_count = myshixuns.select{|m| m.status == 1}.size
passed_games_count = myshixuns.map{|m| m.games.select{|g| g.status == 2}.size }.size
code_line_count = 0
evaluate_count = myshixuns.map{|m| m.output_times }.sum
cost_time = myshixuns.map{|m|m.total_cost_time }.sum
users_info << {user_id: user.id, name: name, passed_myshixun_count: passed_myshixun_count,
passed_games_count: passed_games_count, code_line_count: code_line_count,
evaluate_count: evaluate_count, cost_time: cost_time}
end
users_info
end
end

@ -178,20 +178,21 @@
<span class="fl font-bd">实训详情</span>
</p>
<%#= ApplicationController.helpers.javascript_include_tag "/codemirror/lib/codemirror", "/codemirror/mode/javascript/javascript", "/codemirror/addon/hint/show-hint", "/codemirror/addon/hint/javascript-hint", "/codemirror/addon/selection/active-line", "/codemirror/addon/lint/javascript-lint", "/codemirror/addon/lint/css-lint", "/codemirror/addon/lint/lint", "/codemirror/addon/lint/json-lint", "/editormd/lib/codemirror/addon/lint/css-lint" %>
<% @games.each_with_index do |game, index| %>
<% @challenges.each_with_index do |challenge, index| %>
<% game = @games.select{|game| game.challenge_id == challenge.id}.first if @games %>
<div class="shixun_detail_con padding15 bor-top-greyE">
<p class="clearfix">
<span class="panel-inner-icon mr15 fl mt5">
<% if game.challenge.st == 1 %>
<% if challenge.st == 1 %>
<i class="fa fa-th-list font-16 color_white" data-tip-down="选择题任务"></i>
<% else %>
<i class="fa fa-code font-16 color_white" data-tip-down="编程题任务"></i>
<% end %>
</span>
<span class="fl mt3"><span class="font-bd mr15">第<%= index+1 %>关</span><%= game.challenge.subject %></span>
<span class="fl mt3"><span class="font-bd mr15">第<%= index+1 %>关</span><%= challenge.subject %></span>
</p>
<div style="margin-left: 32px;" class="mt15">
<% if game.outputs.present? %>
<% if game.present? && game.outputs.present? %>
<table class="edu-pop-table edu-txt-center table-line thback" cellpadding="0" cellspacing="0">
<thead>
<th width="10%">评测次数</th>
@ -209,7 +210,7 @@
</tbody>
</table>
<% end %>
<% if game.try(:lastest_code).present? && game.challenge.st == 0 %>
<% if game.present? && game.try(:lastest_code).present? && challenge.st == 0 %>
<div class="bor-grey-e mt15">
<p class="clearfix pt5 pb5 pl15 pr15 back-f6-grey">
<span class="fl">最近通过的代码</span>
@ -240,129 +241,129 @@
window.onload = function() {
console.debug("window.onload");
<% @games.map(&:id).each do |game_id| %>
<% if @games.present? %>
<% @games.map(&:id).each do |game_id| %>
var ele = document.getElementById("content_show_<%= game_id %>");
if (ele) {
var ide = CodeMirror.fromTextArea(ele, {
lineNumbers: true,
theme: "default",
// extraKeys: {"Ctrl-Q": "autocomplete"}, // 快捷键
indentUnit: 4, //代码缩进为一个tab的距离
matchBrackets: true,
autoRefresh: true,
smartIndent: true,//智能换行
styleActiveLine: true,
lineWrapping: true,
lint: true,
readOnly: "nocursor"
});
var ide = CodeMirror.fromTextArea(ele, {
lineNumbers: true,
theme: "default",
// extraKeys: {"Ctrl-Q": "autocomplete"}, // 快捷键
indentUnit: 4, //代码缩进为一个tab的距离
matchBrackets: true,
autoRefresh: true,
smartIndent: true,//智能换行
styleActiveLine: true,
lineWrapping: true,
lint: true,
readOnly: "nocursor"
});
ide.setSize("auto", ide.lineCount() * 18);
ide.setSize("auto", ide.lineCount() * 18);
}
<% end %>
<% end %>
// 基于准备好的dom初始化echarts实例
if(document.getElementById('shixun_skill_chart')){
var effChart = echarts.init(document.getElementById('shixun_skill_chart'));
// 指定图表的配置项和数据
var option = {
grid: {
left: '3%',
right: '9%',
bottom: '3%',
containLabel: true
},
tooltip : {},
xAxis : [
{
type : 'value',
name: '学生序号',
scale:true,
axisLabel : {
formatter: ' '
},
axisTick:{
show:false
},
splitLine: {
show: false
}
}
],
yAxis : [
{
type : 'value',
name : '工作效率',
scale:true,
axisLabel : {
formatter: '{value} '
},
splitLine: {
show: false
}
}
],
series : [
{
name:'',
type:'scatter',
data: <%= @echart_data[:efficiency_list] %>,
itemStyle:{
normal:{color:'#2e65ad'}
},
markArea: {
silent: true,
itemStyle: {
normal: {
color: 'transparent',
borderWidth: 1,
borderType: 'dashed'
}
}
},
markPoint : {
data : [
{
name: 'daiao',
xAxis:<%= @myself_eff[0] %>,
yAxis:<%= @myself_eff[1] %>
}
],
itemStyle: {
normal:{
color:'#c23531'
}
}
},
markLine : {
lineStyle: {
normal: {
type: 'solid',
color:'#c23531'
}
},
data : [
{type : 'average', name: '中位值'}
]
}
},
{
name:'二班',
type:'scatter',
data: [<%= @myself_eff %>],
itemStyle:{
color:'#c23531'
}
}
]
};
// 使用刚指定的配置项和数据显示图表
effChart.setOption(option);
console.debug(<%= @myself_consume %>);
}
// 基于准备好的dom初始化echarts实例
if(document.getElementById('shixun_skill_chart')){
var effChart = echarts.init(document.getElementById('shixun_skill_chart'));
// 指定图表的配置项和数据
var option = {
grid: {
left: '3%',
right: '9%',
bottom: '3%',
containLabel: true
},
tooltip : {},
xAxis : [
{
type : 'value',
name: '学生序号',
scale:true,
axisLabel : {
formatter: ' '
},
axisTick:{
show:false
},
splitLine: {
show: false
}
}
],
yAxis : [
{
type : 'value',
name : '工作效率',
scale:true,
axisLabel : {
formatter: '{value} '
},
splitLine: {
show: false
}
}
],
series : [
{
name:'',
type:'scatter',
data: <%= @echart_data[:efficiency_list] %>,
itemStyle:{
normal:{color:'#2e65ad'}
},
markArea: {
silent: true,
itemStyle: {
normal: {
color: 'transparent',
borderWidth: 1,
borderType: 'dashed'
}
}
},
markPoint : {
data : [
{
name: 'daiao',
xAxis:<%= @myself_eff[0] %>,
yAxis:<%= @myself_eff[1] %>
}
],
itemStyle: {
normal:{
color:'#c23531'
}
}
},
markLine : {
lineStyle: {
normal: {
type: 'solid',
color:'#c23531'
}
},
data : [
{type : 'average', name: '中位值'}
]
}
},
{
name:'二班',
type:'scatter',
data: [<%= @myself_eff %>],
itemStyle:{
color:'#c23531'
}
}
]
};
// 使用刚指定的配置项和数据显示图表
effChart.setOption(option);
console.debug(<%= @myself_consume %>);
}
if(document.getElementById('shixun_skill_chart')) {
if(document.getElementById('shixun_overall_ablility_chart')) {
var ablChart = echarts.init(document.getElementById('shixun_overall_ablility_chart'));
var dataBJ = <%= @echart_data[:consume_list] %>;
var schema = [
@ -477,6 +478,8 @@
// 使用刚指定的配置项和数据显示图表。
ablChart.setOption(option1);
}
<% end %>
}
</script>
</html>

@ -23,20 +23,21 @@
<%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
</div>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '输入关键字搜索') %>
<div class="">
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
</div>
<div class="d-flex mt-3">
<div class="form-group">
<div class="form-group flex-1">
<label for="status">fork原因</label>
<% fork_status_options = [['全部', ''], ["全部fork实训", "Fork"], ["实训内容升级", 'Shixun'], ["课堂教学使用", 'Course'],["实践课程使用",'Subject'],["其他原因",'Other']] %>
<%= select_tag(:fork_status, options_for_select(fork_status_options), class: 'form-control') %>
</div>
<%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with': '搜索中...') %>
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
<div class="flex-1">
<%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with': '搜索中...') %>
<%= link_to "清除", admins_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
</div>
<a href="javascript:void(0)" class="btn btn-primary" id="shixuns-export" data-disable-with = '导出中...'>导出</a>
</div>
</div>
<% end %>

@ -2,7 +2,7 @@ if @bank.container_type == "Exercise"
json.exercise do
json.extract! @bank, :id, :name, :description, :is_public
end
json.authorize @bank.user_id == current_user.id || current_user.admin?
json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.partial! "exercises/exercise_scores"
@ -21,7 +21,7 @@ else
json.poll do
json.extract! @bank, :id, :name, :description, :is_public
end
json.authorize @bank.user_id == current_user.id || current_user.admin?
json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.question_types do
json.q_counts @poll_questions_count

@ -1,7 +1,7 @@
json.partial! "public_navigation", locals: {graduation: @task, course: @course}
json.description @task.description
json.user_id @task.user_id
json.authorize @task.user_id == current_user.id || current_user.admin?
json.authorize @task.user_id == current_user.id || current_user.admin_or_business?
# 附件
json.attachments @attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}

@ -15,7 +15,7 @@ json.comment_scores @comment_scores do |score|
json.score score.score
json.content score.comment
json.is_invalid score.is_invalid
json.delete (@current_user == score.user || @current_user.admin?) && (score.is_invalid || score.score.nil?)
json.delete (@current_user == score.user || @current_user.admin_or_business?) && (score.is_invalid || score.score.nil?)
json.attachments score.attachments do |atta|
json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false}
end

@ -1,6 +1,6 @@
json.(@bank, :id, :name, :description, :is_public, :topic_type, :topic_source, :topic_property_first, :topic_property_second,
:source_unit, :topic_repeat, :province, :city)
json.authorize @bank.user_id == current_user.id || current_user.admin?
json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.attachment_list @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}

@ -1,5 +1,5 @@
json.(@bank, :id, :name, :description, :homework_type, :is_public, :min_num, :max_num, :base_on_project, :reference_answer)
json.authorize @bank.user_id == current_user.id || current_user.admin?
json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}

@ -21,7 +21,7 @@ json.shixun_list do
json.pic url_to_avatar(obj)
json.content highlights
json.level level_to_s(obj.trainee)
json.subjects obj.subjects.uniq do |subject|
json.subjects obj.subjects.visible.unhidden.uniq do |subject|
json.(subject, :id, :name)
end
end

@ -11,7 +11,7 @@ json.update_user_name @is_evaluation ? "匿名" : @work.update_user.try(:real_na
json.update_atta @homework.late_duration && @is_author
json.attachments @attachments do |atta|
json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false, }
json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false }
end
unless @is_evaluation

@ -1,6 +1,6 @@
json.(@bank, :id, :name, :description, :task_type, :is_public)
# 附件
json.authorize @bank.user_id == current_user.id || current_user.admin?
json.authorize @bank.user_id == current_user.id || current_user.admin_or_business?
json.attachments @bank_attachments do |attachment|
json.partial! "attachments/attachment_simple", locals: {attachment: attachment}
end

@ -14,5 +14,5 @@ json.question_banks @question_banks do |question_bank|
json.course_list_name question_bank.course_list&.name
json.updated_at question_bank.updated_at
json.solve_count @solve_count_map.fetch(question_bank.id, 0)
json.authorize question_bank.user_id == current_user.id || current_user.admin?
json.authorize question_bank.user_id == current_user.id || current_user.admin_or_business?
end

@ -407,6 +407,7 @@ Rails.application.routes.draw do
get 'cancel_publish'
get 'cancel_has_publish'
get 'statistics'
get 'statistics_new'
get 'shixun_report'
get 'school_report'
post 'update_attr'

@ -0,0 +1,14 @@
class CreateSubjectRecords < ActiveRecord::Migration[5.2]
def change
create_table :subject_records do |t|
t.references :subject, unique: true
t.integer :study_count, default: 0
t.integer :course_study_count, default: 0
t.integer :initiative_study, default: 0
t.integer :passed_count, default: 0
t.integer :course_used_count, default: 0
t.integer :school_used_count, default: 0
t.timestamps
end
end
end

@ -0,0 +1,16 @@
class CreateSubjectCourseRecords < ActiveRecord::Migration[5.2]
def change
create_table :subject_course_records do |t|
t.references :subject
t.references :school
t.string :school_name
t.integer :course_count, default: 0
t.integer :student_count, default: 0
t.integer :choice_shixun_num, default: 0
t.integer :choice_shixun_frequency, default: 0
t.timestamps
end
add_index :subject_course_records, [:school_id, :subject_id], unique: true, name: "couse_and_school_index"
end
end

@ -0,0 +1,21 @@
class CreateSubjectShixunInfos < ActiveRecord::Migration[5.2]
def change
create_table :subject_shixun_infos do |t|
t.references :subject
t.references :shixun
t.string :stage
t.string :shixun_name
t.integer :challenge_count, default: 0
t.integer :course_count, default: 0
t.integer :school_count, default: 0
t.integer :used_count, default: 0
t.integer :passed_count, default: 0
t.integer :evaluate_count, default: 0
t.integer :passed_ave_time, default: 0
t.timestamps
end
add_index :subject_shixun_infos, [:shixun_id, :subject_id], unique: true
end
end

@ -0,0 +1,18 @@
class CreateSubjectUserInfos < ActiveRecord::Migration[5.2]
def change
create_table :subject_user_infos do |t|
t.references :user
t.references :subject
t.string :username
t.integer :passed_myshixun_count, default: 0
t.integer :passed_games_count, default: 0
t.integer :code_line_count, default: 0
t.integer :evaluate_count, default: 0
t.integer :cost_time, default: 0
t.timestamps
end
add_index :subject_user_infos, [:user_id, :subject_id], unique: true
end
end

@ -0,0 +1,11 @@
class AddUniqIndexToEvaluationDistribution < ActiveRecord::Migration[5.2]
def change
sql = %Q(delete from student_works_evaluation_distributions where (user_id, student_work_id) in
(select * from (select user_id, student_work_id from student_works_evaluation_distributions group by user_id, student_work_id having count(*) > 1) a)
and id not in (select * from (select min(id) from student_works_evaluation_distributions group by user_id, student_work_id having count(*) > 1 order by id) b))
ActiveRecord::Base.connection.execute sql
add_index :student_works_evaluation_distributions, [:student_work_id, :user_id], name: "index_on_student_work_id_and_user_id", unique: true
remove_index :student_works_evaluation_distributions, :user_id
end
end

@ -0,0 +1,5 @@
class ModifyMyshixunIdForStudentWorks < ActiveRecord::Migration[5.2]
def change
StudentWork.where(myshixun_id: nil).update_all(myshixun_id: 0)
end
end

@ -0,0 +1,111 @@
desc "统计实践课程的学习统计数据"
namespace :subjects do
task data_statistic: :environment do
puts("---------------------data_statistic_begin")
Rails.logger.info("---------------------data_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each do |subject|
puts("---------------------data_statistic: #{subject.id}")
Rails.logger.info("---------------------data_statistic: #{subject.id}")
sr = SubjectRecord.find_or_create_by!(subject_id: subject.id)
data = Subjects::DataStatisticService.new(subject)
study_count = data.study_count
# 总人数没有变化的话,不同课堂之类的变化了
course_study_count = (study_count == sr.study_count ? sr.course_study_count : data.course_study_count)
passed_count = (study_count == sr.study_count ? sr.passed_count : data.passed_count)
course_used_count = (study_count == sr.study_count ? sr.course_used_count : data.course_used_count)
school_used_count = (study_count == sr.study_count ? sr.school_used_count : data.school_used_count)
update_params = {
study_count: study_count,
course_study_count: course_study_count,
initiative_study: (study_count - course_study_count),
passed_count: passed_count,
course_used_count: course_used_count,
school_used_count: school_used_count
}
sr.update_attributes!(update_params)
end
puts("---------------------data_statistic_end")
Rails.logger.info("---------------------data_statistic_end")
end
task course_info_statistic: :environment do
puts("---------------------course_info_statistic_begin")
Rails.logger.info("---------------------course_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each do |subject|
puts("---------------------course_info_statistic: #{subject.id}")
Rails.logger.info("---------------------course_info_statistic: #{subject.id}")
data = Subjects::CourseUsedInfoService.call(subject)
data.each do |key|
scr = SubjectCourseRecord.find_or_create_by!(school_id: key[:school_id], subject_id: subject.id)
update_params = {
school_name: key[:school_name],
course_count: key[:course_count],
student_count: key[:student_count],
choice_shixun_num: key[:choice_shixun_num],
choice_shixun_frequency: key[:choice_shixun_frequency]
}
scr.update_attributes(update_params)
end
end
puts("---------------------course_info_statistic_end")
Rails.logger.info("---------------------course_info_statistic_end")
end
task shixun_info_statistic: :environment do
puts("---------------------shixun_info_statistic_begin")
Rails.logger.info("---------------------shixun_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each(batch_size: 100) do |subject|
puts("---------------------shixun_info_statistic: #{subject.id}")
Rails.logger.info("---------------------shixun_info_statistic: #{subject.id}")
data = Subjects::ShixunUsedInfoService.call(subject)
data.each do |key|
ssi = SubjectShixunInfo.find_or_create_by!(shixun_id: key[:shixun_id], subject_id: subject.id)
update_params = {
stage: key[:stage],
shixun_name: key[:name],
challenge_count: key[:challenge_count],
course_count: key[:course_count],
school_count: key[:school_count],
used_count: key[:used_count],
passed_count: key[:passed_count],
evaluate_count: key[:evaluate_count],
passed_ave_time: key[:passed_ave_time]
}
ssi.update_attributes(update_params)
end
end
puts("---------------------shixun_info_statistic_end")
Rails.logger.info("---------------------shixun_info_statistic_end")
end
task user_info_statistic: :environment do
puts("---------------------user_info_statistic_begin")
Rails.logger.info("---------------------user_info_statistic_begin")
subjects = Subject.where(status: 2)
subjects.find_each(batch_size: 100) do |subject|
puts("---------------------user_info_statistic: #{subject.id}")
data = Subjects::UserUsedInfoService.call(subject)
data.each do |key|
sui = SubjectUserInfo.find_or_create_by!(user_id: key[:user_id], subject_id: subject.id)
update_params = {
username: key[:name],
passed_myshixun_count: key[:passed_myshixun_count],
passed_games_count: key[:passed_games_count],
code_line_count: key[:code_line_count],
evaluate_count: key[:evaluate_count],
cost_time: key[:cost_time]
}
sui.update_attributes(update_params)
end
end
puts("---------------------user_info_statistic_end")
Rails.logger.info("---------------------user_info_statistic_end")
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

@ -3474,10 +3474,7 @@ a.singlepublishtwo{
margin-bottom: 0 !important;
}
/*.ant-notification{*/
/*width: auto !important;*/
/*max-width: 600px !important;*/
/*}*/
.markdown-body {
@ -3502,3 +3499,7 @@ a.singlepublishtwo{
text-shadow: none !important;
box-shadow: none !important;
}
.ant-notification{
z-index: 10001 !important;
}

@ -7,6 +7,18 @@
<!-- width=device-width, initial-scale=1 , shrink-to-fit=no -->
<!-- <meta name="viewport" content=""> -->
<meta name=”Keywords” Content=”EduCoder,信息技术实践教学,精品课程网,慕课MOOC″>
<meta name=”Keywords” Content=”实践课程,项目实战,java实训,python实战,人工智能技术,后端开发学习,移动开发入门″>
<meta name=”Keywords” Content=”翻转课堂,高效课堂创建,教学模式″>
<meta name=”Keywords” Content=”实训项目,python教程,C语言入门,java书,php后端开发,app前端开发,数据库技术″>
<meta name=”Keywords” Content=”在线竞赛,计算机应用大赛,编程大赛,大学生计算机设计大赛,全国高校绿色计算机大赛″>
<meta name=”Description” Content=”EduCoder是信息技术类实践教学平台。EduCoder涵盖了计算机、大数据、云计算、人工智能、软件工程、物联网等专业课程。超10000个实训案例及22000个技能评测点建立学、练、评、测一体化实验环境。”>
<meta name=”Description” Content=”EduCoder实践课程旨在于通过企业级实战实训案例帮助众多程序员提升各项业务能力。解决学生、学员、企业员工等程序设计能力、算法设计能力、问题求解能力、应用开发能力、系统运维能力等。”>
<meta name=”Description” Content=”EduCoder翻转课堂教学模式颠覆了传统教学模式让教师与学生的关系由“权威”变成了“伙伴”。将学习的主动权转交给学生使学生可个性化化学学生的学习主体得到了彰显。”>
<meta name=”Description” Content=”EduCoder实训项目为单个知识点关卡实践训练帮助学生巩固单一弱点强化学习。 >
<meta name=”Description” Content=”EduCoder实践教学平台各类大赛为进一步提高各类学生综合运用高级语言程序设计能力培养创新意识和实践探索精神发掘优秀软件人才。 >
<meta name="theme-color" content="#000000">
<!--<meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />-->
<!--<meta http-equiv="pragma" content="no-cache" />-->

@ -49,7 +49,7 @@ if (isDev) {
if(timestamp&&checkSubmitFlg===false){
$.ajax({url:proxy,async:false,success:function(data){
if(data.status===0){
timestamp=data.message;
timestamp=data.data.t;
}
}})
checkSubmitFlg=true
@ -59,7 +59,7 @@ if (isDev) {
}else if(checkSubmitFlg===false){
$.ajax({url:proxy,async:false,success:function(data){
if(data.status===0){
timestamp=data.message;
timestamp=data.data.t;
}
}})
checkSubmitFlg=true
@ -127,7 +127,7 @@ export function initAxiosInterceptors(props) {
if (window.location.port === "3007") {
// let timestamp=railsgettimes(proxy);
// console.log(timestamp)
railsgettimes(`${proxy}/api/main/first_stamp.json`);
railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
let newopens=md5(opens+timestamp)
config.url = `${proxy}${url}`;
if (config.url.indexOf('?') == -1) {
@ -137,7 +137,7 @@ export function initAxiosInterceptors(props) {
}
} else {
// 加api前缀
railsgettimes(`/api/main/first_stamp.json`);
railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
let newopens=md5(opens+timestamp)
config.url = url;
if (config.url.indexOf('?') == -1) {

@ -0,0 +1,5 @@
import md5 from 'md5';
export function setmiyah(logins){
const opens ="79e33abd4b6588941ab7622aed1e67e8";
return md5(opens+logins);
}

@ -81,7 +81,7 @@ function railsgettimess(proxy) {
if(checkSubmitFlgs===false){
$.ajax({url:proxy,async:false,success:function(data){
if(data.status===0){
newtimestamp=data.message;
newtimestamp=data.data.t;
}
}})
checkSubmitFlgs=true
@ -92,7 +92,7 @@ function railsgettimess(proxy) {
}
export function Railsgettimes() {
railsgettimess(`${getUrl()}/api/main/first_stamp.json`);
railsgettimess(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
}
export function getUploadActionUrl(path, goTest) {

@ -5,6 +5,7 @@
export { getImageUrl as getImageUrl, getRandomNumber as getRandomNumber,getUrl as getUrl, publicSearchs as publicSearchs,getRandomcode as getRandomcode,getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl,getUploadActionUrltwo as getUploadActionUrltwo ,getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST ,htmlEncode as htmlEncode } from './UrlTool';
export {setmiyah as setmiyah} from './Component';
export { default as queryString } from './UrlTool2';
export { SnackbarHOC as SnackbarHOC } from './SnackbarHOC';

@ -4,35 +4,32 @@
* @Github:
* @Date: 2020-01-06 09:02:29
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-06 16:04:46
* @LastEditTime : 2020-01-09 15:00:13
*/
import Quill from 'quill';
let Inline = Quill.import('blots/inline');
class FillBlot extends Inline {
// let Inline = Quill.import('blots/inline');
const BlockEmbed = Quill.import('blots/embed');
class FillBlot extends BlockEmbed {
static create (value) {
const node = super.cerate();
node.classList.add('icon icon-bianji2');
node.setAttribute('data-fill', 'fill');
node.addEventListener('DOMNodeRemoved', function () {
alert(123);
}, false);
const node = super.cerate(value);
// node.classList.add('icon icon-bianji2');
// node.setAttribute('data-fill', 'fill');
console.log('编辑器值===》》》》》', value);
node.setAttribute('data_index', value.data_index);
node.nodeValue = value.text;
return node;
}
static value (node) {
return {
dataSet: node.getAttribute('data-fill'),
onDOMNodeRemoved: () => {
alert('123456');
}
// dataSet: node.getAttribute('data-fill'),
data_index: node.getAttribute('data_index')
}
}
}
FillBlot.blotName = "fill";
FillBlot.blotName = "fill-blot";
FillBlot.tagName = "span";
export default FillBlot;

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

Loading…
Cancel
Save