Merge branch 'dev_aliyun' into dev_cxt

dev_cxt
cxt 5 years ago
commit e47c7aec0f

@ -106,3 +106,6 @@ gem 'omniauth-oauth2', '~> 1.6.0'
# global var
gem 'request_store'
# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'

@ -0,0 +1,124 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-disciplines-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-discipline-modal');
var $form = $modal.find('form.admin-create-discipline-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.val('');
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
$(".discipline-list-container").on("change", '.discipline-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/disciplines/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
// 导入学生
var $importDisciplineModal = $('.modal.admin-import-discipline-modal');
var $importDisciplineForm = $importDisciplineModal.find('form.admin-import-discipline-form');
$importDisciplineModal.on('show.bs.modal', function(){
resetFileInputFunc($importDisciplineModal.find('.upload-file-input'));
$importDisciplineModal.find('.file-names').html('选择文件');
$importDisciplineModal.find('.upload-file-input').trigger('click');
});
$importDisciplineModal.on('change', '.upload-file-input', function(e){
var file = $(this)[0].files[0];
$importDisciplineModal.find('.file-names').html(file ? file.name : '请选择文件');
});
var importDisciplineFormValid = function(){
if($importDisciplineForm.find('input[name="file"]').val() == undefined || $importDisciplineForm.find('input[name="file"]').val().length == 0){
$importDisciplineForm.find('.error').html('请选择文件');
return false;
}
return true;
};
var buildResultMessage = function(data){
var messageHtml = "<div>导入结果:成功" + data.success + "条,失败"+ data.fail.length + "条</div>";
return messageHtml;
};
$importDisciplineModal.on('click', '.submit-btn', function(){
$importDisciplineForm.find('.error').html('');
if (importDisciplineFormValid()) {
$('body').mLoading({ text: '正在导入...' });
$.ajax({
method: 'POST',
dataType: 'json',
url: '/admins/import_disciplines',
data: new FormData($importDisciplineForm[0]),
processData: false,
contentType: false,
success: function(data){
$('body').mLoading('destroy');
$importDisciplineModal.modal('hide');
showMessageModal(buildResultMessage(data), function(){
window.location.reload();
});
},
error: function(res){
$('body').mLoading('destroy');
var data = res.responseJSON;
$importDisciplineForm.find('.error').html(data.message);
}
});
}
});
}
});

@ -0,0 +1,22 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-examination-authentications-index-page').length > 0) {
var $searchFrom = $('.examination-authentication-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$('.batch-action-container').hide();
$searchFrom.find('.status-filter').show();
} else {
$('.batch-action-container').show();
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
}
});

@ -0,0 +1,22 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-item-authentications-index-page').length > 0) {
var $searchFrom = $('.item-authentication-list-form');
$searchFrom.find('select[name="status"]').val('pending');
$searchFrom.on('click', '.search-form-tab', function(){
var $link = $(this);
$searchFrom.find('input[name="keyword"]').val('');
$searchFrom.find('select[name="status"]').val('processed');
if($link.data('value') === 'processed'){
$('.batch-action-container').hide();
$searchFrom.find('.status-filter').show();
} else {
$('.batch-action-container').show();
$searchFrom.find('.status-filter').hide();
$searchFrom.find('select[name="status"]').val('pending');
}
});
}
});

@ -0,0 +1,31 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-discipline-modal', function(){
var $modal = $('.modal.admin-edit-discipline-modal');
var $form = $modal.find('form.admin-edit-discipline-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'discipline[name]': {
required: true,
maxlength: 20
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
});
});

@ -0,0 +1,31 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-sub-discipline-modal', function(){
var $modal = $('.modal.admin-edit-sub-discipline-modal');
var $form = $modal.find('form.admin-edit-sub-discipline-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'sub_discipline[name]': {
required: true,
maxlength: 20
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
});
});

@ -0,0 +1,31 @@
$(document).on('turbolinks:load', function() {
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-tag-discipline-modal', function(){
var $modal = $('.modal.admin-edit-tag-discipline-modal');
var $form = $modal.find('form.admin-edit-tag-discipline-form');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
'tag_discipline[name]': {
required: true,
maxlength: 20
}
}
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
var url = $form.attr('action');
if ($form.valid()) {
$.ajax({
method: 'PATCH',
dataType: 'script',
url: url,
data: $form.serialize()
});
}
});
});
});

@ -0,0 +1,65 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-sub-disciplines-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-sub-discipline-modal');
var $form = $modal.find('form.admin-create-sub-discipline-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.val('');
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
$(".sub-discipline-list-container").on("change", '.sub-discipline-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/sub_disciplines/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -0,0 +1,65 @@
$(document).on('turbolinks:load', function() {
if ($('body.admins-tag-disciplines-index-page').length > 0) {
// ============== 新建 ===============
var $modal = $('.modal.admin-create-tag-discipline-modal');
var $form = $modal.find('form.admin-create-tag-discipline-form');
var $nameInput = $form.find('input[name="name"]');
$form.validate({
errorElement: 'span',
errorClass: 'danger text-danger',
rules: {
name: {
required: true
}
}
});
// modal ready fire
$modal.on('show.bs.modal', function () {
$nameInput.val('');
});
$modal.on('click', '.submit-btn', function(){
$form.find('.error').html('');
if ($form.valid()) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$modal.modal('hide');
setTimeout(function(){
window.location.reload();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
}
});
}
});
$(".tag-discipline-list-container").on("change", '.tag-discipline-source-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
json[s_name] = s_value;
$.ajax({
url: "/admins/tag_disciplines/" + s_id,
type: "PUT",
dataType:'script',
data: json
});
});
}
});

@ -0,0 +1,2 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -0,0 +1,3 @@
// Place all the styles related to the edu_datas controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

@ -6,7 +6,6 @@ class Admins::BaseController < ApplicationController
layout 'admin'
skip_before_action :verify_authenticity_token
before_action :require_login, :require_admin!
after_action :rebind_event_if_ajax_render_partial

@ -1,4 +1,5 @@
class Admins::CustomersController < Admins::BaseController
# skip_before_action :check_sign
helper_method :current_partner
def index

@ -0,0 +1,49 @@
class Admins::DisciplinesController < Admins::BaseController
def index
@disciplines = Discipline.all
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if Discipline.where(name: name).exists?
Discipline.create!(name: name)
render_ok
end
def edit
@discipline = current_discipline
end
def update
if params[:discipline] && params[:discipline][:name].present?
name = params[:discipline][:name].to_s.strip
current_discipline.update_attributes!(name: name)
else
ActiveRecord::Base.transaction do
current_discipline.update_attributes!(setting_params)
current_discipline.sub_disciplines.each do |sub|
sub.tag_disciplines.each do |tag|
tag.update_attributes!(setting_params)
end
sub.update_attributes!(setting_params)
end
end
end
@disciplines = Discipline.all
end
def destroy
@discipline_id = params[:id]
current_discipline.destroy!
end
private
def current_discipline
@_current_discipline = Discipline.find params[:id]
end
def setting_params
params.permit(:shixun, :subject, :question)
end
end

@ -0,0 +1,30 @@
class Admins::ExaminationAuthenticationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc'
applies = Admins::ApplyItemBankQuery.call(params.merge(type: "ExaminationBank"))
@applies = paginate applies.preload(user: { user_extension: [:school, :department] })
end
def agree
ActiveRecord::Base.transaction do
exam = ExaminationBank.find current_apply.container_id
current_apply.update!(status: 1)
exam.update!(public: 0)
end
render_success_js
end
def refuse
current_apply.update!(status: 2)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyAction.find(params[:id])
end
end

@ -0,0 +1,10 @@
class Admins::ImportDisciplinesController < Admins::BaseController
def create
return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
result = Admins::ImportDisciplineService.call(params[:file].to_io)
render_ok(result)
rescue Admins::ImportDisciplineService::Error => ex
render_error(ex)
end
end

@ -0,0 +1,34 @@
class Admins::ItemAuthenticationsController < Admins::BaseController
def index
params[:status] ||= 'pending'
params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc'
applies = Admins::ApplyItemBankQuery.call(params.merge(type: "ItemBank"))
@applies = paginate applies.preload(user: { user_extension: [:school, :department] })
end
def show
@item = ItemBank.find current_apply.container_id
end
def agree
ActiveRecord::Base.transaction do
item = ItemBank.find current_apply.container_id
current_apply.update!(status: 1)
item.update!(public: 0)
end
render_success_js
end
def refuse
current_apply.update!(status: 2)
render_success_js
end
private
def current_apply
@_current_apply ||= ApplyAction.find(params[:id])
end
end

@ -0,0 +1,52 @@
class Admins::SubDisciplinesController < Admins::BaseController
def index
@discipline = current_discipline
@sub_disciplines = current_discipline.sub_disciplines
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if current_discipline.sub_disciplines.where(name: name).exists?
SubDiscipline.create!(name: name, discipline_id: current_discipline.id)
render_ok
end
def edit
@sub_discipline = current_sub_discipline
end
def update
if params[:sub_discipline] && params[:sub_discipline][:name].present?
name = params[:sub_discipline][:name].to_s.strip
current_sub_discipline.update_attributes!(name: name)
else
ActiveRecord::Base.transaction do
current_sub_discipline.update_attributes!(setting_params)
current_sub_discipline.tag_disciplines.each do |tag|
tag.update_attributes!(setting_params)
end
end
end
@sub_disciplines = current_sub_discipline.discipline&.sub_disciplines
end
def destroy
@sub_discipline_id = params[:id]
current_sub_discipline.destroy!
end
private
def current_sub_discipline
@_current_sub_discipline = SubDiscipline.find params[:id]
end
def current_discipline
@_current_discipline = Discipline.find params[:discipline_id]
end
def setting_params
params.permit(:shixun, :subject, :question)
end
end

@ -0,0 +1,47 @@
class Admins::TagDisciplinesController < Admins::BaseController
def index
@sub_discipline = current_sub_discipline
@tag_disciplines = current_sub_discipline.tag_disciplines
end
def create
name = params[:name].to_s.strip
return render_error('名称重复') if current_sub_discipline.tag_disciplines.where(name: name).exists?
TagDiscipline.create!(name: name, sub_discipline_id: current_sub_discipline.id, user_id: current_user.id)
render_ok
end
def edit
@tag_discipline = current_tag_discipline
end
def update
if params[:tag_discipline] && params[:tag_discipline][:name].present?
name = params[:tag_discipline][:name].to_s.strip
current_tag_discipline.update_attributes!(name: name)
else
current_tag_discipline.update_attributes!(setting_params)
end
@tag_disciplines = current_tag_discipline.sub_discipline&.tag_disciplines
end
def destroy
@tag_discipline_id = params[:id]
current_tag_discipline.destroy!
end
private
def current_sub_discipline
@_current_sub_discipline = SubDiscipline.find params[:sub_discipline_id]
end
def current_tag_discipline
@_current_tag_discipline = TagDiscipline.find params[:id]
end
def setting_params
params.permit(:shixun, :subject, :question)
end
end

@ -61,7 +61,7 @@ class Admins::UsersController < Admins::BaseController
private
def update_params
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id
params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker
mail phone location location_city school_id department_id admin business is_test
password professional_certification authentication])
end

@ -23,18 +23,23 @@ class ApplicationController < ActionController::Base
# 所有请求必须合法签名
def check_sign
Rails.logger.info("66666 #{params}")
if params[:client_key].present?
Rails.logger.info("111111 #{params[:client_key]}")
Rails.logger.info("00000 #{params[:timestamp]}")
tip_exception(501, "请求不合理") unless (Time.now.to_i - params[:timestamp].to_i).between?(0,5)
timestamp = params[:timestamp]
sign = Digest::MD5.hexdigest("#{OPENKEY}#{timestamp}")
Rails.logger.info("2222 #{sign}")
tip_exception(501, "请求不合理") if sign != params[:client_key]
else
tip_exception(501, "请求不合理")
end
# 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
end
# 全局配置参数
@ -43,6 +48,12 @@ class ApplicationController < ActionController::Base
EduSetting.get(name)
end
def shixun_marker
unless current_user.is_shixun_marker? || current_user.admin_or_business?
tip_exception(403, "..")
end
end
# 实训的访问权限
def shixun_access_allowed
if !current_user.shixun_permission(@shixun)
@ -273,10 +284,10 @@ class ApplicationController < ActionController::Base
end
def user_setup
# reacct静态资源加载不需要走这一步
return if params[:controller] == "main"
# # reacct静态资源加载不需要走这一步
#return if params[:controller] == "main"
# Find the current user
Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
User.current = find_current_user
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))

@ -5,6 +5,7 @@ class AttachmentsController < ApplicationController
before_action :require_login, :check_auth, except: [:show]
before_action :find_file, only: %i[show destroy]
before_action :attachment_candown, only: [:show]
skip_before_action :check_sign, only: [:show, :create]
include ApplicationHelper

@ -41,10 +41,21 @@ module GitHelper
# 更新文件代码
# content 文件内容message提交描述
def update_file_content(content, repo_path, path, mail, username, message)
#content = Base64.encode64(content)
GitService.update_file(repo_path: repo_path, file_path: path, message: message,
content: content, author_name: username, author_email: mail)
end
# 添加目录
def git_add_folder(folder_path, author_name, author_email, message)
GitService.add_tree(file_path: folder_path, message: message, author_name: author_name, author_email: author_email)
end
# 删除文件
def git_delete_file(file_path, author_name, author_email, message)
GitService.delete_file(file_path: file_path, message: message, author_name: author_name, author_email: author_email)
end
# 版本库Fork功能
def project_fork(container, original_rep_path, username)
raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank?

@ -10,6 +10,7 @@ class Cooperative::BaseController < ApplicationController
before_action :laboratory_exist!, :require_login, :require_cooperative_manager!
after_action :rebind_event_if_ajax_render_partial
skip_before_action :check_sign
helper_method :current_laboratory, :current_setting_or_default

@ -1,4 +1,6 @@
class DepartmentsController < ApplicationController
skip_before_action :check_sign
def for_option
render_ok(departments: current_school.departments.without_deleted.select(:id, :name).as_json)
end

@ -0,0 +1,6 @@
class DisciplinesController < ApplicationController
def index
end
end

@ -14,14 +14,14 @@ class DiscussesController < ApplicationController
@disscuss_count = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil).count
disscusses = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s,
:root_id => nil)
@discusses = disscusses.limit(LIMIT).joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id")
.select("discusses.*, games.identifier").includes(:user, :praise_treads).offset(offset)
@discusses = disscusses.joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id")
.select("discusses.*, games.identifier").includes(:user, :praise_treads).limit(LIMIT).offset(offset)
else
disscusses = Discuss.where("dis_id = :dis_id and dis_type = :dis_type and root_id is null and
(discusses.hidden = :hidden or discusses.user_id = :user_id)",
{dis_id: @container.id, dis_type: @container.class.to_s, hidden: false, user_id: current_user.id})
@disscuss_count = disscusses.count("discusses.id")
@discusses = disscusses.limit(LIMIT).includes(:user, :praise_treads).offset(offset)
@discusses = disscusses.includes(:user, :praise_treads).limit(LIMIT).offset(offset)
end
@current_user = current_user
@ -85,7 +85,7 @@ class DiscussesController < ApplicationController
:hidden => !current_user.admin?) # 管理员回复的能够显示
rescue Exception => e
uid_logger_error("create discuss failed : #{e.message}")
raise Educoder::TipException.new("评论异常")
raise Educoder::TipException.new("评论异常,原因:#{e.message}")
end
end
@ -97,7 +97,7 @@ class DiscussesController < ApplicationController
:dis_type => @discuss.dis_type, :position => @discuss.position)
rescue Exception => e
uid_logger_error("reply discuss failed : #{e.message}")
raise Educoder::TipException.new("回复评论异常")
raise Educoder::TipException.new("回复评论异常,原因: #{e.message}")
end
end

@ -3,10 +3,6 @@ class Ecs::HomesController < Ecs::BaseController
@school_managers = current_school.users
end
def first_stamp
render :json => { status: 0, message: Time.now.to_i }
end
private
def current_school

@ -0,0 +1,29 @@
class EduDatasController < ApplicationController
before_action :find_game
skip_before_action :user_setup
skip_before_action :setup_laboratory
# layout :false
include GitHelper
# params[:game_id]
def game
@shixun = @challenge.shixun
@shixun_env = @shixun.mirror_name
@shixun_tags = @challenge.challenge_tags.map(&:name)
end
def code_lines
path = @challenge.path
myshixun = @game.myshixun
# content = git_fle_content(myshixun.repo_path, path) || ""
@content = {"content":"#coding=utf-8\n\n#请在此处添加代码完成输出“Hello Python”,注意要区分大小写!\n###### Begin ######\n\n\n\n###### End ######\n\n"}
@content[:content].include?("Begin")
end
private
def find_game
game_id = params[:game_id]
@game = Game.find(game_id)
@challenge = @game.challenge
end
end

@ -1,7 +1,7 @@
class EduSettingsController < ApplicationController
before_action :require_admin
before_action :set_edu_setting, only: [:show, :edit, :update, :destroy]
skip_before_action :check_sign
# GET /edu_settings
# GET /edu_settings.json
def index

@ -0,0 +1,78 @@
class ExaminationBanksController < ApplicationController
include PaginateHelper
before_action :require_login
before_action :find_exam, except: [:index, :create]
before_action :edit_auth, only: [:update, :destroy, :set_public]
def index
exams = ExaminationBankQuery.call(params)
@exams_count = exams.size
@exams = paginate exams.includes(:user, :examination_items)
end
def show
@items = @exam.examination_items
@single_questions = @items.where(item_type: "SINGLE")
@multiple_questions = @items.where(item_type: "MULTIPLE")
@judgement_questions = @items.where(item_type: "JUDGMENT")
@program_questions = @items.where(item_type: "PROGRAM")
end
def create
ActiveRecord::Base.transaction do
exam = ExaminationBank.new(user: current_user)
# 保存试卷基础信息
exam = ExaminationBanks::SaveExaminationBankService.call(exam, form_params)
# 将试题篮中的试题发送到试卷,试卷的题目与试题独立
current_user.item_baskets.includes(:item_bank).each do |basket|
item = basket.item_bank
if item.present?
new_item = ExaminationItem.new
new_item.new_item(item, exam, basket.score, basket.position)
end
end
current_user.item_baskets.destroy_all
end
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def edit; end
def update
ExaminationBanks::SaveExaminationBankService.call(@exam, form_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def destroy
@exam.destroy!
render_ok
end
def set_public
tip_exception(-1, "该试卷已公开") if @exam.public?
tip_exception(-1, "请勿重复提交申请") if ApplyAction.where(container_id: @exam.id, container_type: "ExaminationBank").exists?
ApplyAction.create!(container_id: @exam.id, container_type: "ExaminationBank", user_id: current_user.id)
# @exam.update_attributes!(public: 1)
render_ok
end
private
def form_params
params.permit(:discipline_id, :sub_discipline_id, :difficulty, :name, :duration, tag_discipline_id: [])
end
def find_exam
@exam = ExaminationBank.find_by!(id: params[:id])
end
def edit_auth
current_user.admin_or_business? || @exam.user == current_user
end
end

@ -0,0 +1,84 @@
class ExaminationItemsController < ApplicationController
before_action :require_login
before_action :validate_score, only: [:set_score, :batch_set_score]
before_action :find_exam, only: [:create, :batch_set_score, :delete_item_type]
before_action :find_item, except: [:create, :batch_set_score, :delete_item_type]
before_action :edit_auth
def create
ExaminationItems::SaveItemService.call(current_user, create_params, @exam)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def destroy
ActiveRecord::Base.transaction do
@exam.examination_items.where(item_type: @item.item_type).where("position > #{@item.position}").update_all("position = position -1")
@item.destroy!
end
render_ok
end
def delete_item_type
items = @exam.examination_items.where(item_type: params[:item_type])
items.destroy_all
render_ok
end
def set_score
@item.update_attributes!(score: params[:score])
@questions_score = @exam.examination_items.where(item_type: @item.item_type).pluck(:score).sum
@all_score = @exam.examination_items.pluck(:score).sum
render_ok({questions_score: @questions_score, all_score: @all_score})
end
def batch_set_score
@exam.examination_items.where(item_type: params[:item_type]).update_all(score: params[:score])
@questions_score = @exam.examination_items.where(item_type: params[:item_type]).pluck(:score).sum
@all_score = @exam.examination_items.pluck(:score).sum
render_ok({questions_score: @questions_score, all_score: @all_score})
end
def adjust_position
same_items = @exam.examination_items.where(item_type: @item.item_type)
max_position = same_items.size
tip_exception("position超出范围") unless params[:position].present? && params[:position].to_i <= max_position && params[:position].to_i >= 1
ActiveRecord::Base.transaction do
if params[:position].to_i > @item.position
same_items.where("position > #{@item.position} and position <= #{params[:position].to_i}").update_all("position=position-1")
@item.update_attributes!(position: params[:position])
elsif params[:position].to_i < @item.position
same_items.where("position < #{@item.position} and position >= #{params[:position].to_i}").update_all("position=position+1")
@item.update_attributes!(position: params[:position])
else
return normal_status(-1, "排序无变化")
end
end
render_ok
end
private
def find_exam
@exam = ExaminationBank.find_by!(id: params[:exam_id])
end
def create_params
params.permit(item_ids: [])
end
def find_item
@item = ExaminationItem.find_by!(id: params[:id])
@exam = @item.examination_bank
end
def validate_score
tip_exception("分值不能为空") unless params[:score].present?
tip_exception("分值需大于0") unless params[:score].to_f > 0
end
def edit_auth
current_user.admin_or_business? || @exam.user == current_user
end
end

@ -962,8 +962,11 @@ class GamesController < ApplicationController
shixun = game.myshixun.shixun
shixun_tomcat = edu_setting('cloud_bridge')
service_host = edu_setting('vnc_url')
tpiGitURL = "#{edu_setting('git_address_domain')}/#{game.myshixun.repo_path}"
uri = "#{shixun_tomcat}/bridge/vnc/getvnc"
params = {tpiID: game.myshixun.id, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
params = {tpiID: game.myshixun.id, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}",
tpiGitURL: tpiGitURL}
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")

@ -1,5 +1,5 @@
class GitsController < ApplicationController
skip_before_action :check_sign
# 说明:
# 以下Git认证只针对新版gitGitlab的Git认证不走该控制器
# 思路:
@ -39,7 +39,7 @@ class GitsController < ApplicationController
# 用户是否对对象拥有权限
system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username)
# 如果用户名密码错误
if system_user && !system_user.check_password?(input_password)
if system_user.blank? || system_user && !system_user.check_password?(input_password)
uid_logger_error("git start: password is wrong")
result = false
else

@ -140,8 +140,8 @@ class GraduationTopicsController < ApplicationController
update_graduation_topic_status
# 拒绝后将该学生移动到未分班中
student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first
student_member.update_attributes(:course_group_id => 0) if student_member.present?
# student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first
# student_member.update_attributes(:course_group_id => 0) if student_member.present?
student_graduation_topic.tidings.update_all(:status => 1)
Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id,
@ -170,14 +170,15 @@ class GraduationTopicsController < ApplicationController
teacher_group = @course.teacher_course_groups.where(:user_id => @graduation_topic.tea_id, :id => params[:group_id]).first
unless teacher_group.present?
member = @course.course_members.where(:user_id => @graduation_topic.tea_id).first
tip_exception("分班名称不能为空") if params[:course_group_name].blank?
course_group = CourseGroup.create(:name => params[:course_group_name], :course_id => @course.id)
teacher_group = TeacherCourseGroup.create(:course_id => @course.id, :course_member_id => member.try(:id),
if params[:course_group_name].present?
course_group = CourseGroup.find_or_create_by!(:name => params[:course_group_name], :course_id => @course.id)
teacher_group = TeacherCourseGroup.find_or_create_by!(:course_id => @course.id, :course_member_id => member.try(:id),
:user_id => @graduation_topic.tea_id,
:course_group_id => course_group.try(:id))
end
student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first
student_member.update_attributes(:course_group_id => teacher_group.course_group_id) if student_member.present?
end
end
student_graduation_topic.tidings.update_all(:status => 1)
Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id,

@ -5,6 +5,7 @@ class HackUserLastestCodesController < ApplicationController
before_action :update_user_hack_status, only: [:code_debug, :code_submit]
before_action :require_auth_identity, only: [:add_notes]
before_action :require_manager_identity, only: [:show, :update_code, :restore_initial_code, :sync_code]
skip_before_action :check_sign, only: [:listen_result]
def show
@my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1

@ -43,16 +43,23 @@ class HacksController < ApplicationController
def create
begin
logger.info("##########{hack_params}")
tip_exception("一次只能增加50个测试集") if hack_sets_params.size > 50
tip_exception("一次只能增加50个知识点") if params[:tags].size > 50
hack = Hack.new(hack_params)
ActiveRecord::Base.transaction do
hack.user_id = current_user.id
hack.identifier = generate_identifier Hack, 8
tag_params = params[:tags].map{|tag| {tag_discipline_id: tag}}
ActiveRecord::Base.transaction do
hack.save!
# 创建测试集与代码
hack.hack_sets.create!(hack_sets_params)
# 新建知识点
hack.tag_discipline_containers.create!(tag_params) if tag_params.present?
hack_codes = hack.hack_codes.new(hack_code_params)
hack_codes.modify_time = Time.now
hack_codes.save!
new_item_params = item_params.merge(container: hack, item_type: 'PROGRAM', difficulty: params[:hack][:difficult], user_id: current_user.id)
ItemBank.create!(new_item_params)
end
render_ok({identifier: hack.identifier})
rescue Exception => e
@ -63,6 +70,10 @@ class HacksController < ApplicationController
def update
begin
# 知识点
tag_discipline_ids = @hack.tag_discipline_containers.pluck(:tag_discipline_id)
new_tag_ids = params[:tags].to_a - tag_discipline_ids
tag_params = new_tag_ids.map{|tag| {tag_discipline_id: tag}}
ActiveRecord::Base.transaction do
@hack.update_attributes!(hack_params)
set_ids = @hack.hack_sets.pluck(:id)
@ -73,6 +84,14 @@ class HacksController < ApplicationController
# 更新代码
code_params = params[:hack_codes][:code] != @hack.code ? hack_code_params.merge(modify_time: Time.now) : hack_code_params
@hack.hack_codes.first.update_attributes!(code_params)
@hack.tag_discipline_containers.create!(tag_params) if tag_params
@hack.tag_discipline_containers.where.not(tag_discipline_id: params[:tags]).destroy_all
# 更新题库相关记录
if @hack.item_bank.present?
update_item_params = item_params.merge({difficulty: params[:hack][:difficult]})
@hack.item_bank.update!(update_item_params)
end
end
render_ok
rescue Exception => e
@ -126,9 +145,11 @@ class HacksController < ApplicationController
@hacks = hacks.includes(:hack_sets).page(page).per(limit)
end
def edit;end
def edit;
end
def new;end
def new;
end
def destroy
begin
@ -147,6 +168,7 @@ class HacksController < ApplicationController
end
private
# 实名认证老师,管理员与运营人员权限
def require_teacher_identity
unless current_user.certification_teacher? || admin_or_business?
@ -166,7 +188,11 @@ class HacksController < ApplicationController
end
def hack_params
params.require(:hack).permit(:name, :description, :difficult, :category, :open_or_not, :time_limit, :score)
params.require(:hack).permit(:name, :description, :difficult, :open_or_not, :time_limit, :score, :sub_discipline_id)
end
def item_params
params.require(:hack).permit(:name, :sub_discipline_id)
end
def hack_sets_params

@ -194,7 +194,7 @@ class HomeworkCommonsController < ApplicationController
# TODO user_extension 如果修改 请调整
unless params[:search].blank?
@student_works = @student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ?
or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%")
or student_id like ?", "%#{params[:search].strip}%", "%#{params[:search].strip}%")
end
@work_count = @student_works.size
@ -214,7 +214,7 @@ class HomeworkCommonsController < ApplicationController
limit = params[:limit] || 20
@student_works = @student_works.page(page).per(limit)
if @homework.homework_type == "practice"
@student_works = @student_works.includes(:student_works_scores, user: :user_extension, myshixun: :games)
@student_works = @student_works.includes(:student_works_scores, :shixun_work_comments, user: :user_extension, myshixun: :games)
else
@student_works = @student_works.includes(:student_works_scores, :project, user: :user_extension)
end
@ -1377,13 +1377,13 @@ class HomeworkCommonsController < ApplicationController
tip_exception(-1, "作业还未发布,不能评阅") if @homework_detail_manual.comment_status == 0
tip_exception("请至少输入一个评阅") if params[:comment].blank? && params[:hidden_comment].blank?
ActiveRecord::Base.transaction do
work_ids = @homework.student_works.where(user_id: @course.teacher_group_user_ids(current_user.id)).pluck(:id)
work_ids = @homework.student_works.where(work_status: [1, 2], user_id: @course.teacher_group_user_ids(current_user.id)).pluck(:id)
has_comment_ids = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 0).pluck(:student_work_id)
batch_comment_works = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 1)
batch_comment_works.update_all(comment: params[:comment], hidden_comment: params[:hidden_comment])
work_ids = work_ids - has_comment_ids - batch_comment_works.pluck(:student_work_id)
@homework.student_works.where(work_status: 0, id: work_ids).update_all(work_status: 1, commit_time: @homework.end_time, update_time: Time.now, work_score: 0, final_score: 0)
HomeworkBatchCommentJob.perform_now(params[:comment], params[:hidden_comment], work_ids, @homework.id, current_user.id)
# @homework.student_works.where(work_status: 0, id: work_ids).update_all(work_status: 1, commit_time: @homework.end_time, update_time: Time.now, work_score: 0, final_score: 0)
HomeworkBatchCommentJob.perform_later(params[:comment], params[:hidden_comment], work_ids, @homework.id, current_user.id)
normal_status("评阅成功")
end
end

@ -1,14 +1,60 @@
class LibrariesController < ApplicationController
class ItemBanksController < ApplicationController
include PaginateHelper
before_action :require_login
before_action :find_item, except: [:index, :create]
before_action :edit_auth, only: [:update, :destroy, :set_public]
def index
default_sort('updated_at', 'desc')
@items = ItemBankQuery.call(params)
@items = paginate courses.includes(:school, :students, :attachments, :homework_commons, teacher: :user_extension)
items = ItemBankQuery.call(params)
@items_count = items.size
@items = paginate items.includes(:item_analysis, :user, :container)
@item_basket_ids = current_user.item_baskets.pluck(:item_bank_id)
end
def create
item = ItemBank.new(user: current_user)
ItemBanks::SaveItemService.call(item, form_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def edit
end
def update
ItemBanks::SaveItemService.call(@item, form_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def destroy
@item.destroy!
render_ok
end
def set_public
tip_exception(-1, "该试题已公开") if @item.public?
tip_exception(-1, "请勿重复提交申请") if ApplyAction.where(container_id: @item.id, container_type: 'ItemBank').exists?
ApplyAction.create!(container_id: @item.id, container_type: 'ItemBank', user_id: current_user.id)
# @item.update_attributes!(public: 1)
render_ok
end
private
def find_item
@item = ItemBank.find_by!(id: params[:id])
end
def edit_auth
current_user.admin_or_business? || @item.user == current_user
end
def form_params
params.permit(:discipline_id, :sub_discipline_id, :item_type, :difficulty, :name, :analysis, tag_discipline_id: [], choices: %i[choice_text is_answer])
end
end

@ -0,0 +1,90 @@
class ItemBasketsController < ApplicationController
before_action :require_login
before_action :validate_score, only: [:set_score, :batch_set_score]
helper_method :current_basket
def index
@item_baskets = current_user.item_baskets
@single_questions = @item_baskets.where(item_type: "SINGLE")
@multiple_questions = @item_baskets.where(item_type: "MULTIPLE")
@judgement_questions = @item_baskets.where(item_type: "JUDGMENT")
@program_questions = @item_baskets.where(item_type: "PROGRAM")
end
def basket_list
@single_questions_count = current_user.item_baskets.where(item_type: "SINGLE").count
@multiple_questions_count = current_user.item_baskets.where(item_type: "MULTIPLE").count
@judgement_questions_count = current_user.item_baskets.where(item_type: "JUDGMENT").count
@completion_questions_count = current_user.item_baskets.where(item_type: "COMPLETION").count
@subjective_questions_count = current_user.item_baskets.where(item_type: "SUBJECTIVE").count
@practical_questions_count = current_user.item_baskets.where(item_type: "PRACTICAL").count
@program_questions_count = current_user.item_baskets.where(item_type: "PROGRAM").count
end
def create
ItemBaskets::SaveItemBasketService.call(current_user, create_params)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
def destroy
item = current_user.item_baskets.find_by!(item_bank_id: params[:id])
ActiveRecord::Base.transaction do
current_user.item_baskets.where(item_type: item.item_type).where("position > #{item.position}").update_all("position = position -1")
item.destroy!
end
render_ok
end
def delete_item_type
baskets = ItemBasket.where(item_type: params[:item_type])
baskets.destroy_all
render_ok
end
def set_score
current_basket.update_attributes!(score: params[:score])
@questions_score = current_user.item_baskets.where(item_type: current_basket.item_type).pluck(:score).sum
@all_score = current_user.item_baskets.pluck(:score).sum
end
def batch_set_score
current_user.item_baskets.where(item_type: params[:item_type]).update_all(score: params[:score])
@questions_score = current_user.item_baskets.where(item_type: params[:item_type]).pluck(:score).sum
@all_score = current_user.item_baskets.pluck(:score).sum
end
def adjust_position
same_items = current_user.item_baskets.where(item_type: current_basket.item_type)
max_position = same_items.size
tip_exception("position超出范围") unless params[:position].present? && params[:position].to_i <= max_position && params[:position].to_i >= 1
ActiveRecord::Base.transaction do
if params[:position].to_i > current_basket.position
same_items.where("position > #{current_basket.position} and position <= #{params[:position].to_i}").update_all("position=position-1")
current_basket.update_attributes!(position: params[:position])
elsif params[:position].to_i < current_basket.position
same_items.where("position < #{current_basket.position} and position >= #{params[:position].to_i}").update_all("position=position+1")
current_basket.update_attributes!(position: params[:position])
else
return normal_status(-1, "排序无变化")
end
end
render_ok
end
private
def create_params
params.permit(item_ids: [])
end
def current_basket
@_current_basket = current_user.item_baskets.find_by!(id: params[:id])
end
def validate_score
tip_exception("分值不能为空") unless params[:score].present?
tip_exception("分值需大于0") unless params[:score].to_f > 0
end
end

@ -76,7 +76,7 @@ class JupytersController < ApplicationController
def active_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
jupyter_active_tpm(myshixun)
jupyter_active_tpi(myshixun)
render json: {status: 0}
end

@ -1,5 +1,11 @@
class MainController < ApplicationController
skip_before_action :check_sign
skip_before_action :user_setup
skip_before_action :setup_laboratory
def first_stamp
render :json => { status: 0, message: Time.now.to_i }
end
def index
render file: 'public/react/build/index.html', :layout => false

@ -216,10 +216,11 @@ class MyshixunsController < ApplicationController
old_time = Time.now.to_i
begin
shixun_tomcat = edu_setting('tomcat_webssh')
tpiGitURL = "#{edu_setting('git_address_domain')}/#{@myshixun.repo_path}"
uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo"
# 由于中间层采用混合云的方式因为local参数表示在有文件生成的实训是在本地生成还是在其他云端生成评测文件
local = @myshixun.shixun.challenges.where.not(show_type: -1).count == 0
params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: local,
params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: local, tpiGitURL: tpiGitURL,
containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))}
res = uri_post uri, params
if res && res['code'].to_i != 0

@ -1,4 +1,5 @@
class PartnersController < ApplicationController
skip_before_action :check_sign
include Base::PaginateHelper
include Admins::RenderHelper

@ -46,8 +46,8 @@ class PollsController < ApplicationController
@polls = member_show_polls.size > 0 ? member_show_polls.public_or_unset : []
else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷
# 已发布 当前用户班级分组的 试卷id
not_poll_ids = @course.poll_group_settings.poll_group_not_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id)
@polls = member_show_polls.where.not(id: not_poll_ids)
publish_poll_ids = @course.poll_group_settings.poll_group_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id)
@polls = member_show_polls.unified_setting.or(member_show_polls.where(id: publish_poll_ids))
end
else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁
@is_teacher_or = 0
@ -792,12 +792,12 @@ class PollsController < ApplicationController
if the_group_setting_status == 2
poll_group_params = {
:publish_time => the_group_setting.publish_time,
:end_time => poll_end_time
:end_time => poll_end_time < Time.now ? the_group_setting.end_time : poll_end_time
}
elsif the_group_setting_status == 3
poll_group_params = {
:publish_time => the_group_setting.publish_time,
:end_time => the_group_setting.end_time
:end_time => poll_end_time
}
end
the_group_setting.update_attributes(poll_group_params)

@ -1,4 +1,5 @@
class SchoolsController < ApplicationController
skip_before_action :check_sign
def school_list
schools = School.all
@ -14,7 +15,6 @@ class SchoolsController < ApplicationController
schools = School.all
keyword = params[:keyword].to_s.strip
schools = schools.where('name LIKE ?', "%#{keyword}%") if keyword
render_ok(schools: schools.select(:id, :name).as_json)
end

@ -18,12 +18,14 @@ class ShixunsController < ApplicationController
before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy,
:add_file, :jupyter_exec]
before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public,
:shixun_members_added, :change_manager, :collaborators_delete,
:cancel_apply_public, :cancel_publish, :add_collaborators, :add_file]
before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public, :upload_git_folder,
:shixun_members_added, :change_manager, :collaborators_delete, :upload_git_file,
:cancel_apply_public, :cancel_publish, :add_collaborators, :add_file, :delete_git_file]
before_action :portion_allowed, only: [:copy]
before_action :special_allowed, only: [:send_to_course, :search_user_courses]
before_action :shixun_marker, only: [:new, :create]
skip_before_action :check_sign, only: [:download_file]
## 获取课程列表
def index
@ -145,7 +147,7 @@ class ShixunsController < ApplicationController
## 实训详情
def show
# 当前用户开启的实训
can_fork = current_user.is_certification_teacher || current_user.admin?
can_fork = current_user.is_certification_teacher || current_user.admin_or_business?
unless can_fork
@can_fork = {can_fork: "已经职业认证的教师才能fork实训",
certi_url: "/account/certification"}
@ -884,6 +886,35 @@ class ShixunsController < ApplicationController
@content = update_file_content content, @repo_path, @path, author_email, author_name, "Edit by browser"
end
def upload_git_file
upload_file = params["file"]
uid_logger("#########################file_params####{params["#{params[:file]}"]}")
raise "未上传文件" unless upload_file
content = upload_file.tempfile.read
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:message] || "upload file by browser"
update_file_content(content, @repo_path, @path, author_email, author_name, message)
render_ok
end
# 上传目录
def upload_git_folder
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:message] || "upload folder by browser"
git_add_folder(@path, author_name, author_email, message)
render_ok
end
def delete_git_file
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:message] || "delete file by browser"
git_delete_file(@path, author_name, author_email, message)
render_ok
end
def add_collaborators
member_ids = "(" + @shixun.shixun_members.map(&:user_id).join(',') + ")"
user_name = "%#{params[:user_name].to_s.strip}%"
@ -900,7 +931,7 @@ class ShixunsController < ApplicationController
page = params[:page] || 1
limit = params[:limit] || 20
@user_count = @users.count
@users = @users.page(page).per(limit)
@users = @users.page(page).per(20)
end
@ -964,7 +995,7 @@ class ShixunsController < ApplicationController
@courses = @courses.where(id: current_laboratory.all_courses)
@course_count = @courses.count
@courses = @courses.page(page).per(limit)
@courses = @courses.page(page).per(10)
end
# 将实训发送到课程
@ -1151,4 +1182,5 @@ private
end
md5.hexdigest
end
end

@ -529,7 +529,7 @@ class StudentWorksController < ApplicationController
@echart_data = student_efficiency(@homework, @work)
@myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id }
@myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id }
filename_ = "#{@user&.student_id}_#{@user&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
filename_ = "#{@homework.course&.user_group_name(@work.user_id)}_#{@user&.student_id}_#{@user&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
filename = filename_.strip.tr("+/", "-_")
stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css)
if params[:export].present? && params[:export]

@ -7,6 +7,8 @@ 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]
include ApplicationHelper
include SubjectsHelper

@ -0,0 +1,9 @@
class TagDisciplinesController < ApplicationController
before_action :require_login
def create
sub_discipline = SubDiscipline.find_by!(id: params[:sub_discipline_id])
tag_discipline = TagDiscipline.create!(name: params[:name].to_s.strip, sub_discipline: sub_discipline, user_id: current_user.id)
render_ok({tag_discipline_id: tag_discipline.id})
end
end

@ -2,6 +2,7 @@ class UsersController < ApplicationController
before_action :load_user, only: [:show, :homepage_info]
before_action :check_user_exist, only: [:show, :homepage_info]
skip_before_action :check_sign, only: [:attachment_show]
# 检查是否更新
def system_update

@ -0,0 +1,15 @@
class ExaminationBanks::SaveExamForm
include ActiveModel::Model
attr_accessor :discipline_id, :sub_discipline_id, :difficulty, :name, :duration, :tag_discipline_id
validates :discipline_id, presence: true
validates :sub_discipline_id, presence: true
validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
validates :name, presence: true, length: { maximum: 60 }
validate :validate_duration
def validate_duration
raise '时长应为大于0的整数' if duration.present? && duration.to_i < 1
end
end

@ -0,0 +1,33 @@
class ItemBanks::SaveItemForm
include ActiveModel::Model
attr_accessor :discipline_id, :sub_discipline_id, :item_type, :difficulty, :name, :analysis, :tag_discipline_id, :choices
validates :discipline_id, presence: true
validates :sub_discipline_id, presence: true
validates :item_type, presence: true, inclusion: {in: %W(SINGLE MULTIPLE JUDGMENT COMPLETION SUBJECTIVE PRACTICAL PROGRAM)}
validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true }
validates :name, presence: true, length: { maximum: 1000 }
validates :analysis, length: { maximum: 1000 }
def validate!
super
return unless errors.blank?
choices.each { |item| SubForm.new(item).validate! } if %W(SINGLE MULTIPLE JUDGMENT).include?(item_type)
return unless errors.blank?
if [0, 2].include?(item_type) && choices.pluck(:is_answer).select{|item| item == 1}.length > 1
raise("正确答案只能有一个")
elsif item_type == 1 && choices.pluck(:is_answer).select{|item| item == 1}.length <= 1
raise("多选题至少有两个正确答案")
end
end
class SubForm
include ActiveModel::Model
attr_accessor :choice_text, :is_answer
validates :choice_text, presence: true, length: { maximum: 100 }
validates :is_answer, presence: true, inclusion: {in: 0..1}, numericality: { only_integer: true }
end
end

@ -0,0 +1,2 @@
module EduDatasHelper
end

@ -850,7 +850,7 @@ module ExportHelper
def make_zip_name(work, file_name="")
Rails.logger.info("######################file_name: #{file_name}")
# name = file_name === "" ? "" : (file_name[0, file_name.rindex('.')]+"_")
"#{work&.user&.student_id}_#{work&.user&.real_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
"#{work&.homework_common.course&.user_group_name(work.user_id)}_#{work&.user&.student_id}_#{work&.user&.real_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
end
def zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[])

@ -0,0 +1,16 @@
class Admins::ImportDisciplineExcel < BaseImportXlsx
DisciplineData = Struct.new(:discipline_name, :sub_discipline_name)
def read_each(&block)
sheet.each_row_streaming(pad_cells: true, offset: 2) do |row|
data = row.map(&method(:cell_value))[1..2]
block.call DisciplineData.new(*data)
end
end
private
def cell_value(obj)
obj&.cell_value
end
end

@ -16,7 +16,7 @@ class ApplyAction < ApplicationRecord
tidings.create(user_id: user_id, trigger_user_id: 0, status: 1, viewed: 0, tiding_type: 'System',
parent_container_id: container_id, parent_container_type: container_type,
belong_container_id: container_id, belong_container_type: 'User')
else
elsif %w(ApplyShixun ApplySubject TrialAuthorization).include?(container_type)
belong_container_type = if container_type == 'TrialAuthorization'
'User'
else

@ -81,6 +81,8 @@ class Course < ApplicationRecord
# 老版的members弃用 现用course_members
has_many :members
validate :validate_sensitive_string
scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) }
scope :ended, ->(is_end = true) { where(is_end: is_end) }
scope :processing, -> { where(is_end: false) }
@ -435,4 +437,8 @@ class Course < ApplicationRecord
self.laboratory = Laboratory.current if laboratory_id.blank?
end
def validate_sensitive_string
raise("课堂名称包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(name)
end
end

@ -2,13 +2,15 @@ class CourseGroup < ApplicationRecord
default_scope { order("course_groups.position ASC") }
belongs_to :course, counter_cache: true
has_many :course_members
has_many :exercise_group_settings,:dependent => :destroy
has_many :attachment_group_settings, :dependent => :destroy
has_many :homework_group_reviews, :dependent => :destroy
has_many :teacher_course_groups, :dependent => :destroy
has_many :homework_group_settings, :dependent => :destroy
scope :by_group_ids, lambda { |ids| where(id: ids)}
validates :name, length: { maximum: 60 }
validates_uniqueness_of :name, scope: :course_id, message: "不能创建相同名称的分班"
after_create :generate_invite_code

@ -6,4 +6,10 @@ class CourseList < ApplicationRecord
has_many :gtask_banks
has_many :gtopic_banks
belongs_to :user
validate :validate_sensitive_string
def validate_sensitive_string
raise("课程名称包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(name)
end
end

@ -0,0 +1,7 @@
class Discipline < ApplicationRecord
has_many :sub_disciplines, dependent: :destroy
has_many :shixun_sub_disciplines, -> { where("shixun = 1") }, class_name: "SubDiscipline"
has_many :subject_sub_disciplines, -> { where("subject = 1") }, class_name: "SubDiscipline"
has_many :question_sub_disciplines, -> { where("question = 1") }, class_name: "SubDiscipline"
end

@ -11,6 +11,8 @@ class Discuss < ApplicationRecord
belongs_to :dis, polymorphic: true
belongs_to :challenge, optional: true
validate :validate_sensitive_string
after_create :send_tiding
scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) }
@ -69,4 +71,8 @@ class Discuss < ApplicationRecord
}
tidings.create!(base_attrs.merge(user_id: send_user_id))
end
def validate_sensitive_string
raise("内容包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(content)
end
end

@ -0,0 +1,17 @@
class ExaminationBank < ApplicationRecord
belongs_to :user
belongs_to :sub_discipline
has_many :tag_discipline_containers, as: :container, dependent: :destroy
has_many :tag_disciplines, through: :tag_discipline_containers
has_many :examination_items, -> {order(position: :asc)}, dependent: :destroy
def question_count
examination_items.size
end
def total_score
examination_items.pluck(:score).sum
end
end

@ -0,0 +1,45 @@
class ExaminationItem < ApplicationRecord
enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 }
belongs_to :examination_bank, touch: true
belongs_to :item_bank, optional: true
has_many :examination_item_choices, dependent: :destroy
has_one :examination_item_analysis, dependent: :destroy
belongs_to :container, polymorphic: true, optional: true
def analysis
examination_item_analysis&.analysis
end
def item_choices
examination_item_choices
end
def public
0
end
def quotes
0
end
# 题库复制
def new_item item, exam, score, position
attributes = {examination_bank: exam, item_bank: item, name: item.name, item_type: item.item_type,
difficulty: item.difficulty, score: score, position: position}
self.update!(attributes)
item.increment!(:quotes)
if item.item_type == "PROGRAM"
new_hack = item.container.fork
self.update!(container: new_hack)
else
ExaminationItemAnalysis.create!(analysis: item.analysis, examination_item_id: self.id)
item.item_choices.each do |choice|
examination_item_choices << ExaminationItemChoice.new(choice_text: choice.choice_text, is_answer: choice.is_answer)
end
end
end
end

@ -0,0 +1,3 @@
class ExaminationItemAnalysis < ApplicationRecord
belongs_to :examination_item
end

@ -0,0 +1,3 @@
class ExaminationItemChoice < ApplicationRecord
belongs_to :examination_item
end

@ -15,8 +15,14 @@ class Hack < ApplicationRecord
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
# 消息
has_many :tidings, as: :container
# 知识点
has_many :tag_discipline_containers, as: :container, dependent: :destroy
belongs_to :user
belongs_to :sub_discipline
has_one :item_bank, as: :container, dependent: :destroy
has_one :examination_bank, as: :container, dependent: :destroy
scope :published, -> { where(status: 1) }
scope :unpublish, -> { where(status: 0) }
@ -51,4 +57,31 @@ class Hack < ApplicationRecord
user_id == user.id || user.admin_or_business?
end
# 复制fork
def fork
new_hack = Hack.new
new_hack.attributes = self.attributes.dup.except("id", "user_id", "status", "identifier", "comments_count", "praises_count",
"pass_num", "created_at", "updated_at", "hack_user_lastest_codes_count",
"open_or_not", "submit_num")
new_hack.user_id = User.current.id
new_hack.identifier = Util::UUID.generate_identifier(Hack, 8)
new_hack.fork_id = self.id
new_hack.save!
# 创建测试集与代码
hack_sets.each do |set|
new_hack.hack_sets.create!(input: set.input, output: set.output, position: set.position)
end
# 新建知识点
tag_discipline_containers.each do |tag|
new_hack.tag_discipline_containers.create!(tag_discipline_id: tag.tag_discipline_id)
end
hack_codes.each do |code|
new_hack.hack_codes.create!(code: code.code, language: code.language, modify_time: Time.now)
end
new_hack
end
end

@ -1,11 +1,52 @@
class ItemBank < ApplicationRecord
# difficulty: 1 简单 2 适中 3 困难
# item_type: 0 单选 1 多选 2 判断 3 填空 4 简答 5 实训 6 编程
enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 }
# item_type: 0 单选 1 多选 2 判断 3 填空 4 简答 5 实训 6 编程
belongs_to :user
belongs_to :sub_discipline, optional: true
has_one :item_analysis, dependent: :destroy
has_many :item_choices, dependent: :destroy
has_many :item_baskets, dependent: :destroy
has_many :tag_discipline_containers, as: :container, dependent: :destroy
has_many :tag_disciplines, through: :tag_discipline_containers
belongs_to :container, polymorphic: true, optional: true
def analysis
item_analysis&.analysis
end
def type_string
result = case item_type
when "SINGLE"
"单选题"
when "MULTIPLE"
"多选题"
when "JUDGMENT"
"判断题"
when "COMPLETION"
"填空题"
when "SUBJECTIVE"
"简答题"
when "PRACTICAL"
"实训题"
when "PROGRAM"
"编程题"
end
result
end
def difficulty_string
result = case difficulty
when 1
"简单"
when 2
"适中"
when 3
"困难"
end
result
end
end

@ -1,4 +1,14 @@
class ItemBasket < ApplicationRecord
enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 }
belongs_to :item_bank
belongs_to :user
def all_score
User.current.item_baskets.map(&:score).sum
end
def question_count
User.current.item_baskets.size
end
end

@ -16,6 +16,7 @@ class Memo < ApplicationRecord
has_many :children, foreign_key: :parent_id, class_name: 'Memo'
has_many :attachments, as: :container, dependent: :destroy
has_many :tidings, as: :container, dependent: :destroy
validate :validate_sensitive_string
scope :field_for_list, lambda{
select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id])
@ -54,4 +55,9 @@ class Memo < ApplicationRecord
self.tidings << Tiding.new(tiding_attr)
end
def validate_sensitive_string
raise("标题包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(subject)
raise("内容包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(content)
end
end

@ -19,6 +19,7 @@ class Poll < ApplicationRecord
scope :poll_by_ids, lambda { |ids| where(id: ids) unless ids.blank? }
scope :poll_by_status, lambda { |s| where(polls_status: s) unless s.blank? }
scope :poll_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)}
scope :unified_setting, -> { where("unified_setting = ?",true) }
scope :poll_search, lambda { |keywords|
where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?}
@ -103,7 +104,7 @@ class Poll < ApplicationRecord
if course.is_end
status = 4
else
if user.present? && user.student_of_course?(course)
if user.present? && user.course_identity(course) == Course::STUDENT
ex_time = get_poll_times(user.id,false)
pb_time = ex_time[:publish_time]
ed_time = ex_time[:end_time]

@ -0,0 +1,9 @@
class SubDiscipline < ApplicationRecord
belongs_to :discipline
has_many :tag_disciplines, dependent: :destroy
has_one :hack
has_many :shixun_tag_disciplines, -> { where("shixun = 1") }, class_name: "TagDiscipline"
has_many :subject_tag_disciplines, -> { where("subject = 1") }, class_name: "TagDiscipline"
has_many :question_tag_disciplines, -> { where("question = 1") }, class_name: "TagDiscipline"
end

@ -0,0 +1,11 @@
class TagDiscipline < ApplicationRecord
belongs_to :sub_discipline
belongs_to :user, optional: true
has_many :tag_discipline_containers, dependent: :destroy
validates_presence_of :name
def discipline
sub_discipline&.discipline
end
end

@ -0,0 +1,5 @@
class TagDisciplineContainer < ApplicationRecord
belongs_to :tag_discipline
belongs_to :container, polymorphic: true, optional: true
end

@ -8,6 +8,8 @@ class TeacherCourseGroup < ApplicationRecord
scope :find_teacher_group_ids, lambda { |ids| where(course_group_id: ids) unless ids.blank?}
scope :get_user_groups,lambda {|ids| where(user_id:ids)}
validates_uniqueness_of :course_group_id, scope: :course_member_id
def course_members
self.course_group.course_members
end

@ -153,6 +153,10 @@ class User < ApplicationRecord
has_many :hacks, dependent: :destroy
has_many :hack_user_lastest_codes, dependent: :destroy
# 题库
has_many :item_banks, dependent: :destroy
has_many :item_baskets, -> { order("item_baskets.position ASC") }, dependent: :destroy
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
@ -174,13 +178,8 @@ class User < ApplicationRecord
validates_uniqueness_of :phone, :if => Proc.new { |user| user.phone_changed? && user.phone.present? }, case_sensitive: false
validates_length_of :login, maximum: LOGIN_LENGTH_LIMIT
validates_length_of :mail, maximum: MAIL_LENGTH_LMIT
# validates_format_of :mail, with: VALID_EMAIL_REGEX, multiline: true
# validates_format_of :phone, with: VALID_PHONE_REGEX, multiline: true
validate :validate_sensitive_string
validate :validate_password_length
#validate :validate_ID_number
#validates_format_of :ID_number, with: VALID_NUMBER_REGEX, multiline: true, message: "身份证号格式不对"
# validates :nickname, presence: true, length: { maximum: 10 }
# validates :lastname, presence: true
# 删除自动登录的token一旦退出下次会提示需要登录
def delete_autologin_token(value)
@ -723,6 +722,11 @@ class User < ApplicationRecord
end
end
def validate_sensitive_string
raise("真实姓名包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(lastname)
raise("昵称包含敏感词汇,请重新输入") unless HarmoniousDictionary.clean?(nickname)
end
def set_laboratory
return unless new_record?

@ -0,0 +1,34 @@
class Admins::ApplyItemBankQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :updated_at, default_by: :updated_at, default_direction: :desc
def initialize(params)
@params = params
end
def call
applies = ApplyAction.where(container_type: params[:type].presence || "ItemBank")
status =
case params[:status]
when 'pending' then 0
when 'processed' then [1, 2]
when 'agreed' then 1
when 'refused' then 2
else 0
end
applies = applies.where(status: status) if status.present?
# 关键字模糊查询
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins(user: { user_extension: :school })
.where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,32 @@
class ExaminationBankQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :updated_at, default_by: :updated_at, default_direction: :desc, default_table: 'examination_banks'
def initialize(params)
@params = params
end
def call
if params[:public].to_i == 1
exams = ExaminationBank.where(public: 1)
elsif params[:public].to_i == 0
exams = ExaminationBank.where(user_id: User.current.id)
end
if params[:tag_discipline_id].present?
exams = exams.joins(:tag_discipline_containers).where(tag_discipline_containers: {tag_discipline_id: params[:tag_discipline_id]})
elsif params[:sub_discipline_id].present?
exams = exams.where(sub_discipline_id: params[:sub_discipline_id])
elsif params[:discipline_id].present?
exams = exams.joins(:sub_discipline).where(sub_disciplines: {discipline_id: params[:discipline_id]})
end
exams = exams.where(difficulty: params[:difficulty].to_i) if params[:difficulty].present?
exams = exams.where("name like ?", "%#{params[:keyword].strip}%") if params[:keyword].present?
custom_sort(exams, params[:sort_by], params[:sort_direction])
end
end

@ -0,0 +1,37 @@
class ItemBankQuery < ApplicationQuery
include CustomSortable
attr_reader :params
sort_columns :updated_at, default_by: :updated_at, default_direction: :desc, default_table: 'item_banks'
def initialize(params)
@params = params
end
def call
if params[:public].to_i == 1
items = ItemBank.where(public: 1)
elsif params[:public].to_i == 0
items = ItemBank.where(user_id: User.current.id)
end
if params[:tag_discipline_id].present?
items = items.joins(:tag_discipline_containers).where(tag_discipline_containers: {tag_discipline_id: params[:tag_discipline_id]})
elsif params[:sub_discipline_id].present?
items = items.where(sub_discipline_id: params[:sub_discipline_id])
elsif params[:discipline_id].present?
items = items.joins(:sub_discipline).where(sub_disciplines: {discipline_id: params[:discipline_id]})
end
if params[:oj_status].present? && params[:item_type] == "PROGRAM"
items = items.joins("join hacks on hacks.id=item_banks.container_id and item_banks.container_type='Hack'").where(hacks: {status: params[:oj_status]})
end
items = items.where(item_type: params[:item_type]) if params[:item_type].present?
items = items.where(difficulty: params[:difficulty].to_i) if params[:difficulty].present?
items = items.where("name like ?", "%#{params[:keyword].strip}%") if params[:keyword].present?
custom_sort(items, params[:sort_by], params[:sort_direction])
end
end

@ -10,7 +10,6 @@ class Admins::IdentityAuths::AgreeApplyService < ApplicationService
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(authentication: true)
RewardGradeService.call(user, container_id: user.id, container_type: 'Authentication', score: 500)
deal_tiding!

@ -0,0 +1,52 @@
class Admins::ImportDisciplineService < ApplicationService
Error = Class.new(StandardError)
attr_reader :file, :result
def initialize(file)
@file = file
@result = { success: 0, fail: [] }
end
def call
raise Error, '文件不存在' if file.blank?
excel = Admins::ImportDisciplineExcel.new(file)
excel.read_each(&method(:save_discipline))
result
rescue ApplicationImport::Error => ex
raise Error, ex.message
end
private
def save_discipline(data)
count = 0
discipline_name = data.discipline_name.to_s.strip
sub_discipline_name = data.sub_discipline_name.to_s.strip
return unless discipline_name.present?
discipline = Discipline.find_by(name: discipline_name)
if discipline.blank?
discipline = Discipline.create!(name: discipline_name)
count += 1
end
if sub_discipline_name.present?
sub_discipline = SubDiscipline.find_by(name: discipline_name, discipline: discipline)
if sub_discipline.blank?
SubDiscipline.create!(name: sub_discipline_name, discipline: discipline)
count += 1
end
end
result[:success] += count
rescue Exception => ex
fail_data = data.as_json
fail_data[:data] = fail_data.values.join(',')
fail_data[:message] = ex.message
result[:fail] << fail_data
end
end

@ -10,7 +10,7 @@ class Admins::ProfessionalAuths::AgreeApplyService < ApplicationService
ActiveRecord::Base.transaction do
apply.update!(status: 1)
user.update!(professional_certification: true)
user.update!(is_shixun_marker: true) if user.is_teacher?
RewardGradeService.call(user, container_id: user.id, container_type: 'Professional', score: 500)
deal_tiding!

@ -25,6 +25,7 @@ class Admins::UpdateUserService < ApplicationService
ActiveRecord::Base.transaction do
user.save!
user.user_extension.save!
user.update!(is_shixun_marker: true) if user.is_certification_teacher
update_gitlab_password if params[:password].present?
end
@ -36,7 +37,7 @@ class Admins::UpdateUserService < ApplicationService
def user_attributes
params.slice(*%i[lastname nickname mail phone admin business is_test
professional_certification authentication])
professional_certification authentication is_shixun_marker])
end
def user_extension_attributes

@ -0,0 +1,30 @@
class ExaminationBanks::SaveExaminationBankService < ApplicationService
attr_reader :exam, :params
def initialize(exam, params)
@exam = exam
@params = params
end
def call
ExaminationBanks::SaveExamForm.new(params).validate!
exam.name = params[:name].to_s.strip
exam.difficulty = params[:difficulty]
exam.duration = params[:duration].present? ? params[:duration].to_i : nil
exam.sub_discipline_id = params[:sub_discipline_id]
exam.save!
# 知识点的创建
new_tag_discipline_ids = params[:tag_discipline_id] || []
old_tag_discipline_ids = exam.tag_discipline_containers.pluck(:tag_discipline_id)
delete_tag_discipline_ids = old_tag_discipline_ids - new_tag_discipline_ids
create_tag_discipline_ids = new_tag_discipline_ids - old_tag_discipline_ids
exam.tag_discipline_containers.where(tag_discipline_id: delete_tag_discipline_ids).destroy_all
create_tag_discipline_ids.each do |tag_id|
exam.tag_discipline_containers << TagDisciplineContainer.new(tag_discipline_id: tag_id)
end
exam
end
end

@ -0,0 +1,50 @@
class ExaminationItems::SaveItemService < ApplicationService
attr_reader :user, :params, :exam
def initialize(user, params, exam)
@user = user
@params = params
@exam = exam
end
def call
raise("请选择试题") if params[:item_ids].blank?
# 只能选用公共题库或是自己的题库
items = ItemBank.where(public: 1).or(ItemBank.where(user_id: user.id))
# 已选到过试题篮的不重复选用
item_ids = params[:item_ids] - exam.examination_items.pluck(:item_bank_id)
items.where(id: item_ids).each do |item|
ActiveRecord::Base.transaction do
item_score = item_score item.item_type
item_position = item_position item.item_type
new_item = ExaminationItem.new
new_item.new_item(item, exam, item_score, item_position)
end
end
end
private
def item_score item_type
if exam.examination_items.where(item_type: item_type).last.present?
score = exam.examination_items.where(item_type: item_type).last.score
else
score =
case item_type
when "SINGLE", "MULTIPLE", "JUDGMENT"
5
when "PROGRAM"
10
else
5
end
end
score
end
def item_position item_type
exam.examination_items.where(item_type: item_type).last&.position.to_i + 1
end
end

@ -10,7 +10,7 @@ class ExportShixunReportService
end
def filename
@_filename ||= "#{work.user&.student_id}_#{work.user.real_name}_#{homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf".gsub(' ', '-').gsub('/', '_')
@_filename ||= "#{homework.course&.user_group_name(work.user_id)}_#{work.user&.student_id}_#{work.user.real_name}_#{homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf".gsub(' ', '-').gsub('/', '_')
end
def prepare_binding
@ -43,6 +43,7 @@ class ExportShixunReportService
@user = @work.user
@shixun = homework.shixuns.take
@games = @work.myshixun.games.includes(:challenge, :game_codes,:outputs) if @work.myshixun
@challenges = @shixun.challenges if @shixun
# 用户最大评测次数
@user_evaluate_count = @games.pluck(:evaluate_count).sum if @games

@ -2,16 +2,30 @@
#
# 文档在 https://www.showdoc.cc/127895880302646?page_id=1077512172693249
#
require 'faraday'
class GitService
class << self
['add_repository', 'fork_repository', 'delete_repository', 'file_tree', 'update_file', 'file_content', 'commits'].each do |method|
['add_repository', 'fork_repository', 'delete_repository', 'file_tree', 'update_file', 'file_content', 'commits',
'add_tree', 'delete_file', 'update_file_base64'].each do |method|
define_method method do |params|
post(method, params)
end
end
def make_new_multipar_file(full_file_path)
Faraday::FilePart.new(full_file_path, 'application/octet-stream')
end
#上传二进制文件
#参数构造形式
# {a: 'a', file: make_new_multipar_file('1.txt') }
def update_file_binary(params)
post_form('update_file', params)
end
private
def root_url
@ -24,6 +38,19 @@ class GitService
Rails.logger
end
def post_form(action,params)
conn = Faraday.new(root_url) do |f|
f.request :multipart
f.request :url_encoded
f.adapter :net_http
end
resp = conn.post("/api/#{action}", params)
body = resp.body
parse_return(body)
end
def post(action, params)
uri = URI.parse("#{root_url}/api/#{action}")
https = Net::HTTP.new(uri.host, uri.port)
@ -32,6 +59,11 @@ class GitService
req.body = params.to_json
res = https.request(req)
body = res.body
parse_return(body)
end
def parse_return(body)
logger.info("--uri_exec: .....res is #{body}")
content = JSON.parse(body)

@ -305,14 +305,21 @@ class HomeworksService
myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil
if work.work_status == 0
is_complete = myshixun_endtime && (myshixun_endtime < setting_time.end_time)
if is_complete || (myshixun.created_at < setting_time.end_time && (!homework.allow_late || setting_time.end_time >= Time.now))
# if work.work_status == 0
# if is_complete || (myshixun.created_at < setting_time.end_time && (!homework.allow_late || setting_time.end_time >= Time.now))
# work.work_status = 1
# elsif homework.allow_late && myshixun.created_at < homework.late_time
# work.work_status = 2
# end
# end
if !homework.allow_late || is_complete
work.work_status = 1
elsif homework.allow_late && myshixun.created_at < homework.late_time
elsif myshixun.created_at < homework.late_time
work.work_status = 2
end
end
if work.work_status != 0
if myshixun_endtime.present?

@ -0,0 +1,58 @@
class ItemBanks::SaveItemService < ApplicationService
attr_reader :item, :params
def initialize(item, params)
@item = item
@params = params
end
def call
new_record = item.new_record?
raise("不能更改题型") if !new_record && item.item_type != params[:item_type]
ItemBanks::SaveItemForm.new(params).validate!
ActiveRecord::Base.transaction do
item.item_type = params[:item_type] if new_record
item.difficulty = params[:difficulty]
item.sub_discipline_id = params[:sub_discipline_id]
item.name = params[:name].to_s.strip
item.save!
analysis = item.item_analysis || ItemAnalysis.new(item_bank_id: item.id)
analysis.analysis = params[:analysis].blank? ? nil : params[:analysis].strip
analysis.save
# 知识点的创建
new_tag_discipline_ids = params[:tag_discipline_id]
old_tag_discipline_ids = item.tag_discipline_containers.pluck(:tag_discipline_id)
delete_tag_discipline_ids = old_tag_discipline_ids - new_tag_discipline_ids
create_tag_discipline_ids = new_tag_discipline_ids - old_tag_discipline_ids
item.tag_discipline_containers.where(tag_discipline_id: delete_tag_discipline_ids).destroy_all
create_tag_discipline_ids.each do |tag_id|
item.tag_discipline_containers << TagDisciplineContainer.new(tag_discipline_id: tag_id)
end
# 选项的创建
if %W(SINGLE MULTIPLE JUDGMENT).include?(item.item_type)
old_choices = item.item_choices
new_choices = params[:choices]
new_choices.each_with_index do |choice, index|
choice_item = old_choices[index] || ItemChoice.new(item_bank_id: item.id)
choice_item.choice_text = choice[:choice_text]
choice_item.is_answer = choice[:is_answer]
choice_item.save!
end
if old_choices.length > new_choices.length
old_choices[new_choices.length..(old_choices.length-1)].each do |old_choice|
old_choice.destroy
end
end
end
end
item
end
end

@ -0,0 +1,47 @@
class ItemBaskets::SaveItemBasketService < ApplicationService
attr_reader :user, :params
def initialize(user, params)
@user = user
@params = params
end
def call
raise("请选择试题") if params[:item_ids].blank?
# 只能选用公共题库或是自己的题库
items = ItemBank.where(public: 1).or(ItemBank.where(user_id: user.id))
# 已选到过试题篮的不重复选用
item_ids = params[:item_ids] - user.item_baskets.pluck(:item_bank_id)
items.where(id: item_ids).each do |item|
new_item = ItemBasket.new(user_id: user.id, item_bank_id: item.id, item_type: item.item_type)
new_item.score = item_score item.item_type
new_item.position = item_position item.item_type
new_item.save!
end
end
private
def item_score item_type
if user.item_baskets.where(item_type: item_type).last.present?
score = user.item_baskets.where(item_type: item_type).last.score
else
score =
case item_type
when "SINGLE", "MULTIPLE", "JUDGMENT"
5
when "PROGRAM"
10
else
5
end
end
score
end
def item_position item_type
user.item_baskets.where(item_type: item_type).last&.position.to_i + 1
end
end

@ -8,7 +8,8 @@ module JupyterService
uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = "tpm#{shixun.id}"
mount = shixun.data_sets.present?
params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount,
gitUrl = "#{edu_setting('git_address_domain')}/#{shixun.repo_path}"
params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount, gitUrl: gitUrl,
:containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
logger.info "test_juypter: uri->#{uri}, params->#{params}"
@ -48,7 +49,13 @@ module JupyterService
tpiID = myshixun.id
mount = myshixun.shixun.data_sets.present?
params = {tpiID: tpiID, identifier: shixun.identifier, myshixunIdentifier: myshixun.identifier, needMount: mount,
gitUrl = "#{edu_setting('git_address_domain')}/#{myshixun.repo_path}"
params = { tpiID: tpiID,
identifier: shixun.identifier,
myshixunIdentifier: myshixun.identifier,
gitUrl: gitUrl,
needMount: mount,
:containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
res = uri_post uri, params

@ -30,6 +30,6 @@ class PrivateMessages::CreateService < ApplicationService
def validate!
raise Error, '内容不能为空' if content.blank?
raise Error, '内容太长' if content.size > 255
raise Error, '内容太长' if content.size > 500
end
end

@ -26,7 +26,14 @@ class CreateShixunService < ApplicationService
# 创建镜像
ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id)
# 创建主服务配置
ShixunServiceConfig.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id)
config_params =
if shixun.is_jupyter?
{shixun_id: shixun.id, mirror_repository_id: main_mirror.id, cpu_limit: 2,
memory_limit: 1024, lower_cpu_limit: 0.2, request_limit: 100}
else
{shixun_id: shixun.id, mirror_repository_id: main_mirror.id}
end
ShixunServiceConfig.create!(config_params)
# 创建子镜像相关数据(实训镜像关联表,子镜像服务配置)
sub_mirrors.each do |sub|
ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => sub.id)

@ -101,6 +101,7 @@
</table>
</div>
<% if @work.myshixun.present? %>
<div class="bor-grey-e mt20">
<p class="pt10 pb10 pl15 pr15 clearfix bor-bottom-greyE">
<span class="fl font-bd">图形统计</span>
@ -224,6 +225,7 @@
</div>
<% end %>
</div>
<% end %>
</div>
</body>
@ -261,6 +263,7 @@
// 基于准备好的dom初始化echarts实例
if(document.getElementById('shixun_skill_chart')){
var effChart = echarts.init(document.getElementById('shixun_skill_chart'));
// 指定图表的配置项和数据
var option = {
@ -357,6 +360,9 @@
// 使用刚指定的配置项和数据显示图表
effChart.setOption(option);
console.debug(<%= @myself_consume %>);
}
if(document.getElementById('shixun_skill_chart')) {
var ablChart = echarts.init(document.getElementById('shixun_overall_ablility_chart'));
var dataBJ = <%= @echart_data[:consume_list] %>;
var schema = [
@ -471,5 +477,6 @@
// 使用刚指定的配置项和数据显示图表。
ablChart.setOption(option1);
}
}
</script>
</html>

@ -0,0 +1,2 @@
$.notify({ message: '删除成功' });
$(".discipline-item-<%= @discipline_id %>").remove();

@ -0,0 +1,2 @@
$('.admin-modal-container').html("<%= j( render partial: 'admins/disciplines/shared/edit_discipline_modal', locals: { discipline: @discipline } ) %>");
$('.modal.admin-edit-discipline-modal').modal('show');

@ -0,0 +1,17 @@
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('课程方向', admins_disciplines_path) %>
<% end %>
<div class="box search-form-container discipline-list-form rig">
<div class="flex-1">
<%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-discipline-modal' } %>
</div>
<%= javascript_void_link '导入数据', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-import-discipline-modal'} %>
</div>
<div class="box admin-list-container discipline-list-container">
<%= render(partial: 'admins/disciplines/shared/list') %>
</div>
<%= render 'admins/disciplines/shared/create_discipline_modal' %>
<%= render partial: 'admins/disciplines/shared/import_discipline_modal' %>

@ -0,0 +1,28 @@
<div class="modal fade admin-create-discipline-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">新建课程方向</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-create-discipline-form" data-url="<%= admins_disciplines_path %>">
<div class="form-group d-flex">
<label for="new_mirror_id" class="col-form-label">名称:</label>
<div class="w-75 d-flex flex-column">
<%= text_field_tag(:name, nil, class: 'form-control', placeholder: '请输入名称') %>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,23 @@
<div class="modal fade admin-edit-discipline-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">编辑课程方向</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<%= simple_form_for([:admins, discipline], html: { class: 'admin-edit-discipline-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
<%= f.input :name, as: :string, label: '名称' %>
<div class="error text-danger"></div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,30 @@
<div class="modal fade admin-import-discipline-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">导入数据</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form class="admin-import-discipline-form" enctype="multipart/form-data">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">文件</span>
</div>
<div class="custom-file">
<input type="file" name="file" class="upload-file-input" id="import-discipline-input" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
<label class="custom-file-label file-names" for="import-discipline-input">选择文件</label>
</div>
</div>
<div class="error text-danger"></div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary submit-btn">确认</button>
</div>
</div>
</div>
</div>

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

Loading…
Cancel
Save