dev_jupyter
daiao 5 years ago
commit 0b0241727e

@ -49,6 +49,8 @@ gem 'rqrcode_png'
gem 'acts-as-taggable-on', '~> 6.0'
gem 'omniauth-cas'
group :development, :test do
gem 'rspec-rails', '~> 3.8'
end

@ -120,5 +120,19 @@ $(document).on('turbolinks:load', function() {
});
}
});
// ------------ 上移/下移 -------------
$('.discipline-list-container').on('click', ".move-action", function () {
var $doAction = $(this);
var disciplineId = $doAction.data('id');
var opr = $doAction.data('opr');
$.ajax({
url: '/admins/disciplines/' + disciplineId + '/adjust_position',
method: 'POST',
dataType: 'script',
data: {opr: opr}
});
});
}
});

@ -5,13 +5,13 @@ $(document).on('turbolinks:load', function() {
var $addMemberModal = $('.admin-add-salesman-channel-user-modal');
var $addMemberForm = $addMemberModal.find('.admin-add-salesman-channel-user-form');
var $memberSelect = $addMemberModal.find('.salesman-channel-user-select');
var $salesmanIdInput = $('.salesman-channel-list-form').find(".btn-primary");
var $form = $addMemberModal.find('form.admin-add-salesman-user-form');
// 搜索
var searchscForm = $(".saleman-channel-list-form .search-form");
$addMemberModal.on('show.bs.modal', function(event){
var $link = $(event.relatedTarget);
// var salesmanId = $link.data('salesman_id');
// $salesmanIdInput.val(salesmanId);
$addMemberModal.on('show.bs.modal', function(event){
$memberSelect.select2('val', ' ');
});
@ -48,27 +48,72 @@ $(document).on('turbolinks:load', function() {
// var salesmanId = $salesmanIdInput.val();
var memberIds = $memberSelect.val();
if (memberIds && memberIds.length > 0) {
var url = $form.data('url');
$.ajax({
method: 'POST',
dataType: 'json',
url: '/admins/salesman_channels/batch_add',
data: { salesman_id: $salesmanIdInput.data("salesman-id"), school_ids: memberIds },
url: url,
data: $form.serialize(),
success: function(){
$.notify({ message: '创建成功' });
$addMemberModal.modal('hide');
searchscForm.find('input[name="keyword"]').val('');
setTimeout(function(){
window.location.reload();
submitForm();
}, 500);
},
error: function(res){
var data = res.responseJSON;
$form.find('.error').html(data.message);
$addMemberForm.find('.error').html(data.message);
}
});
} else {
$addMemberModal.modal('hide');
}
});
// 清空
searchscForm.on('click', '.clear-btn', function () {
searchscForm.find('.start_date').val('');
searchscForm.find('.end_date').val('').trigger('change');
searchscForm.find('input[name="keyword"]').val('');
});
// 时间跨度
var baseOptions = {
autoclose: true,
language: 'zh-CN',
format: 'yyyy-mm-dd',
startDate: '2017-04-01'
};
var defineDateRangeSelect = function(element){
var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, baseOptions);
$(element).datepicker(options);
$(element).find('.start-date').datepicker().on('changeDate', function(e){
$(element).find('.end-date').datepicker('setStartDate', e.date);
});
};
defineDateRangeSelect('.grow-date-input-daterange');
// 区间搜索
searchscForm.on('click', ".search-btn", function(){
submitForm();
});
var submitForm = function(){
var url = searchscForm.data('search-form-url');
var form = searchscForm;
$.ajax({
url: url,
data: form.serialize(),
dataType: "script"
})
};
}
});

@ -58,7 +58,7 @@ $(document).on('turbolinks:load', function() {
$addMemberModal.modal('hide');
setTimeout(function(){
window.location.reload();
listForm();
}, 500);
},
error: function(res){
@ -70,5 +70,13 @@ $(document).on('turbolinks:load', function() {
$addMemberModal.modal('hide');
}
});
var listForm = function(){
$.ajax({
url: '/admins/salesman_customers?salesman_id='+ $salesmanIdInput.data("salesman-id"),
dataType: "script"
});
};
}
});

@ -72,5 +72,18 @@ $(document).on('turbolinks:load', function () {
data: json
});
});
// ------------ 上移/下移 -------------
$('.sub-discipline-list-container').on('click', ".move-action", function () {
var $doAction = $(this);
var objectId = $doAction.data('id');
var opr = $doAction.data('opr');
$.ajax({
url: '/admins/sub_disciplines/' + objectId + '/adjust_position',
method: 'POST',
dataType: 'script',
data: {opr: opr}
});
});
}
});

@ -29,6 +29,7 @@ $(document).on('turbolinks:load', function () {
}
});
$(".subject-setting-list-container").on("change", '.subject-setting-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();

@ -72,5 +72,19 @@ $(document).on('turbolinks:load', function () {
data: json
});
});
// ------------ 上移/下移 -------------
$('.tag-discipline-list-container').on('click', ".move-action", function () {
var $doAction = $(this);
var objectId = $doAction.data('id');
var opr = $doAction.data('opr');
$.ajax({
url: '/admins/tag_disciplines/' + objectId + '/adjust_position',
method: 'POST',
dataType: 'script',
data: {opr: opr}
});
});
}
});

@ -51,12 +51,12 @@ class AccountsController < ApplicationController
# todo user_extension
UserExtension.create!(user_id: @user.id)
# 注册完成手机号或邮箱想可以奖励500金币
RewardGradeService.call(
@user,
container_id: @user.id,
container_type: pre == 'p' ? 'Phone' : 'Mail',
score: 500
)
# RewardGradeService.call(
# @user,
# container_id: @user.id,
# container_type: pre == 'p' ? 'Phone' : 'Mail',
# score: 500
# )
# 注册时,记录是否是引流用户
ip = request.remote_ip
ua = UserAgent.find_by_ip(ip)

@ -7,7 +7,7 @@ class Admins::DisciplinesController < Admins::BaseController
def create
name = params[:name].to_s.strip
return render_error('名称重复') if Discipline.where(name: name).exists?
Discipline.create!(name: name)
Discipline.create!(name: name, position: Discipline.all.pluck(:position).max + 1)
render_ok
end
@ -39,7 +39,31 @@ class Admins::DisciplinesController < Admins::BaseController
def destroy
@discipline_id = params[:id]
current_discipline.destroy!
ActiveRecord::Base.transaction do
Discipline.where("position > #{current_discipline.position}").update_all("position=position-1")
current_discipline.destroy!
end
end
def adjust_position
max_position = Discipline.all.pluck(:position).max
opr = params[:opr] || "down"
if (params[:opr] == "up" && current_discipline.position == 1) || (params[:opr] == "down" && current_discipline.position == max_position)
@message = "超出范围"
else
ActiveRecord::Base.transaction do
if opr == "up"
Discipline.find_by("position = #{current_discipline.position - 1}")&.update!(position: current_discipline.position)
current_discipline.update!(position: current_discipline.position - 1)
else
Discipline.find_by("position = #{current_discipline.position + 1}")&.update!(position: current_discipline.position)
current_discipline.update!(position: current_discipline.position + 1)
end
end
end
@disciplines = Discipline.all
rescue Exception => e
@message = e.message
end
private

@ -2,7 +2,12 @@ class Admins::SalesmanChannelsController < Admins::BaseController
before_action :set_salesman
def index
@channels = SalesmanChannel.all
@channels = @salesman.salesman_channels
if params[:keyword].present?
@channels = @channels.joins(:school).where("schools.name like ?", "%#{params[:keyword]}%")
end
@start_time = params[:start_date]
@end_time = params[:end_date].blank? ? Time.now : params[:end_date]
end
def batch_add
@ -10,10 +15,12 @@ class Admins::SalesmanChannelsController < Admins::BaseController
school_ids = params[:school_ids] - channel_ids
school_ids.each do |school_id|
school = School.find_by(id: school_id)
next if school.blank?
next if school.blank? || @salesman.salesman_channels.where(school_id: school.id).exists?
@salesman.salesman_channels.create!(school_id: school.id)
end
render_ok
rescue Exception => ex
render_error(ex.message)
end
def destroy

@ -10,7 +10,7 @@ class Admins::SalesmanCustomersController < Admins::BaseController
user_ids = params[:user_ids] - customer_ids
user_ids.each do |user_id|
user = UserExtension.find_by(user_id: user_id)
next if user.blank?
next if user.blank? || @salesman.salesman_customers.where(user_id: user.user_id).exists?
@salesman.salesman_customers.create!(user_id: user.user_id, school_id: user.school_id)
end
render_ok

@ -18,7 +18,7 @@ class Admins::ShixunSettingsController < Admins::BaseController
task_pass: params[:task_pass].present? ? params[:task_pass] : false,
code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false,
vip: params[:vip].present? ? params[:vip] : false,
is_wechat_support: params[:is_wechat_support].present? ? params[:is_wechat_support] : false
no_subject: params[:no_subject].present? ? params[:no_subject] : false
}
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@ -135,6 +135,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,
:code_hidden,:vip,:page_no,:id, :is_wechat_support)
:code_hidden,:vip,:page_no,:id, :no_subject)
end
end

@ -9,7 +9,7 @@ class Admins::SubDisciplinesController < Admins::BaseController
name = params[:name].to_s.strip
return render_error('名称不能为空') if name.blank?
return render_error('名称重复') if current_discipline.sub_disciplines.where(name: name).exists?
SubDiscipline.create!(name: name, discipline_id: current_discipline.id)
SubDiscipline.create!(name: name, discipline_id: current_discipline.id, position: current_discipline.sub_disciplines.pluck(:position).max + 1)
render_ok
end
@ -38,9 +38,36 @@ class Admins::SubDisciplinesController < Admins::BaseController
def destroy
@sub_discipline_id = params[:id]
current_sub_discipline.destroy!
ActiveRecord::Base.transaction do
discipline = current_sub_discipline.discipline
discipline.sub_disciplines.where("position > #{current_sub_discipline.position}").update_all("position=position-1")
current_sub_discipline.destroy!
end
end
def adjust_position
discipline = current_sub_discipline.discipline
max_position = discipline.sub_disciplines.pluck(:position).max
opr = params[:opr] || "down"
if (params[:opr] == "up" && current_sub_discipline.position == 1) || (params[:opr] == "down" && current_sub_discipline.position == max_position)
@message = "超出范围"
else
ActiveRecord::Base.transaction do
if opr == "up"
discipline.sub_disciplines.find_by("position = #{current_sub_discipline.position - 1}")&.update!(position: current_sub_discipline.position)
current_sub_discipline.update!(position: current_sub_discipline.position - 1)
else
discipline.sub_disciplines.find_by("position = #{current_sub_discipline.position + 1}")&.update!(position: current_sub_discipline.position)
current_sub_discipline.update!(position: current_sub_discipline.position + 1)
end
end
end
@sub_disciplines = discipline&.sub_disciplines
rescue Exception => e
@message = e.message
end
private
def current_sub_discipline

@ -20,6 +20,11 @@ class Admins::SubjectSettingsController < Admins::BaseController
end
end
def update_mobile_show
subject = Subject.find(params[:subject_id])
subject.update_attributes(:show_mobile => params[:show_mobile])
end
private
def current_subject

@ -8,7 +8,8 @@ class Admins::TagDisciplinesController < Admins::BaseController
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)
TagDiscipline.create!(name: name, sub_discipline_id: current_sub_discipline.id, user_id: current_user.id,
position: current_sub_discipline.tag_disciplines.pluck(:position).max + 1)
render_ok
end
@ -32,9 +33,36 @@ class Admins::TagDisciplinesController < Admins::BaseController
def destroy
@tag_discipline_id = params[:id]
current_tag_discipline.destroy!
ActiveRecord::Base.transaction do
sub_discipline = current_tag_discipline.sub_discipline
sub_discipline.tag_disciplines.where("position > #{current_tag_discipline.position}").update_all("position=position-1")
current_tag_discipline.destroy!
end
end
def adjust_position
sub_discipline = current_tag_discipline.sub_discipline
max_position = sub_discipline.tag_disciplines.pluck(:position).max
opr = params[:opr] || "down"
if (params[:opr] == "up" && current_tag_discipline.position == 1) || (params[:opr] == "down" && current_tag_discipline.position == max_position)
@message = "超出范围"
else
ActiveRecord::Base.transaction do
if opr == "up"
sub_discipline.tag_disciplines.find_by("position = #{current_tag_discipline.position - 1}")&.update!(position: current_tag_discipline.position)
current_tag_discipline.update!(position: current_tag_discipline.position - 1)
else
sub_discipline.tag_disciplines.find_by("position = #{current_tag_discipline.position + 1}")&.update!(position: current_tag_discipline.position)
current_tag_discipline.update!(position: current_tag_discipline.position + 1)
end
end
end
@tag_disciplines = sub_discipline&.tag_disciplines
rescue Exception => e
@message = e.message
end
private
def current_sub_discipline

@ -1,13 +1,35 @@
class BindUsersController < ApplicationController
before_action :require_login
# before_action :require_login
def create
user = CreateBindUserService.call(current_user, create_params)
successful_authentication(user) if user.id != current_user.id
# user = CreateBindUserService.call(create_params)
#
if params[:type] == "qq"
begin
user = CreateBindUserService.call(current_user, create_params)
successful_authentication(user) if user.id != current_user.id
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
render_ok
rescue ApplicationService::Error => ex
render_error(ex.message)
end
else
begin
tip_exception '系统错误' if session[:unionid].blank?
bind_user = User.try_to_login(params[:username], params[:password])
tip_exception '用户名或者密码错误' if bind_user.blank?
tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
OpenUsers::Wechat.create!(user: bind_user, uid: session[:unionid])
successful_authentication(bind_user)
render_ok
rescue Exception => e
render_error(e.message)
end
end
end
def new_user

@ -6,11 +6,21 @@ module ControllerRescueHandler
Util.logger_error e
render json: {status: -1, message: e.message}
end
rescue_from ActiveRecord::StatementInvalid do |e|
Util.logger_error e
render json: {status: -1, message: "接口数据异常"}
end
rescue_from NoMethodError do |e|
Util.logger_error e
render json: {status: -1, message: "接口方法异常"}
end
rescue_from ActionController::UnknownFormat do |e|
render json: {status: -1, message: "接口调用非JSON格式"}
end
# rescue_from ActionView::MissingTemplate, with: :object_not_found
# rescue_from ActiveRecord::RecordNotFound, with: :object_not_found
rescue_from Educoder::TipException, with: :tip_show
@ -26,10 +36,6 @@ module ControllerRescueHandler
render_error(ex.record.errors.full_messages.join(','))
end
rescue_from ActionController::UnknownFormat do |e|
render json: {status: -1, message: "接口调用非JSON格式"}
end
# rescue_from RuntimeError do |ex|
# Util.logger_error "#######ex:#{ex}"
# render_error(ex.message)

@ -13,7 +13,7 @@ class CoursesController < ApplicationController
end
before_action :require_login, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups,
:left_banner, :top_banner, :informs, :online_learning, :course_groups]
:left_banner, :top_banner, :informs, :online_learning, :course_groups, :search_slim]
before_action :check_account, only: [:new, :create, :apply_to_join_course, :join_excellent_course]
before_action :check_auth, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups,
:left_banner, :top_banner, :apply_to_join_course, :exit_course, :course_groups]
@ -742,12 +742,15 @@ class CoursesController < ApplicationController
# 切换为教师
def switch_to_teacher
begin
course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1)
tip_exception("切换失败") unless course_member.STUDENT?
course_student = @course.students.find_by!(user_id: current_user.id, is_active: 1)
tip_exception("切换失败") unless course_student.present?
course_teacher = CourseMember.find_by!(user_id: current_user.id, role: %i[CREATOR PROFESSOR], course_id: @course.id)
course_member.update!(is_active: 0)
course_teacher.update!(is_active: 1)
ActiveRecord::Base.transaction do
course_student.destroy!
course_teacher.update!(is_active: 1)
CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功")
rescue => e
uid_logger_error(e.message)
@ -758,12 +761,15 @@ class CoursesController < ApplicationController
# 切换为助教
def switch_to_assistant
begin
course_member = @course.course_members.find_by!(user_id: current_user.id, is_active: 1)
tip_exception("切换失败") unless course_member.STUDENT?
course_student = @course.course_members.find_by!(user_id: current_user.id, is_active: 1)
tip_exception("切换失败") unless course_student.present?
course_teacher = CourseMember.find_by!(user_id: current_user.id, role: %i[ASSISTANT_PROFESSOR], course_id: @course.id)
course_member.update!(is_active: 0)
course_teacher.update!(is_active: 1)
ActiveRecord::Base.transaction do
course_student.destroy!
course_teacher.update!(is_active: 1)
CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [current_user.id])
end
normal_status(0, "切换成功")
rescue => e
uid_logger_error(e.message)

@ -1168,7 +1168,7 @@ class ExercisesController < ApplicationController
#班级的选择
if params[:exercise_group_id].present?
group_id = params[:exercise_group_id]
exercise_students = @course_all_members.course_find("course_group_id", group_id) #试卷所分班的全部人数
exercise_students = @course_all_members.course_find_by_ids("course_group_id", group_id) #试卷所分班的全部人数
user_ids = exercise_students.pluck(:user_id).reject(&:blank?)
@exercise_users_list = @exercise_users_list.exercise_commit_users(user_ids)
end

@ -524,11 +524,11 @@ class GamesController < ApplicationController
else
{updated_at: Time.now}
end
logger.info("#############myshixuns_update: ##{myshixuns_update}")
#logger.info("#############myshixuns_update: ##{myshixuns_update}")
@myshixun.update_attributes!(myshixuns_update)
gitUrl = repo_ip_url @myshixun.repo_path
logger.info("#############giturl: ##{gitUrl}")
#logger.info("#############giturl: ##{gitUrl}")
gitUrl = Base64.urlsafe_encode64(gitUrl)
shixun_tomcat = edu_setting('cloud_bridge')
@ -554,7 +554,7 @@ class GamesController < ApplicationController
testSet << test_cases
end
logger.info("##############testSet: #{testSet}")
#logger.info("##############testSet: #{testSet}")
testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank?
# 评测类型: 012 用于webssh的评测 3用于vnc
@ -581,7 +581,7 @@ class GamesController < ApplicationController
if secret_rep&.repo_name
secretGitUrl = repo_ip_url secret_rep.repo_path
br_params.merge!({secretGitUrl: Base64.urlsafe_encode64(secretGitUrl), secretDir: secret_rep.secret_dir_path})
logger.info("#######br_params:#{br_params}")
#logger.info("#######br_params:#{br_params}")
end
# 中间层交互
@ -691,7 +691,7 @@ class GamesController < ApplicationController
next_game: next_game&.identifier}
rescue Exception => e
uid_logger("choose build failed #{e.message}")
@result = [status: -1, contents: "#{e.message}"]
tip_exception(-1, e.message)
end
# 轮询获取状态
@ -700,10 +700,10 @@ class GamesController < ApplicationController
resubmit_identifier = @game.resubmit_identifier
# 如果没有超时并且正在评测中
# 判断评测中的状态有两种1、如果之前没有通关的只需判断status为1即可如果通过关则判断game的resubmit_identifier是否更新
uid_logger("################game_status: #{@game.status}")
uid_logger("################params[:resubmit]: #{params[:resubmit]}")
uid_logger("################resubmit_identifier: #{resubmit_identifier}")
uid_logger("################time_out: #{params[:time_out]}")
#uid_logger("################game_status: #{@game.status}")
#uid_logger("################params[:resubmit]: #{params[:resubmit]}")
#uid_logger("################resubmit_identifier: #{resubmit_identifier}")
#uid_logger("################time_out: #{params[:time_out]}")
sec_key = params[:sec_key]
if (params[:time_out] == "false") && ((params[:resubmit].blank? && @game.status == 1) || (params[:resubmit].present? &&
(params[:resubmit] != resubmit_identifier)))
@ -764,7 +764,7 @@ class GamesController < ApplicationController
end
end
uid_logger("game is #{@game.id}, record id is #{e_record.try(:id)}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
#uid_logger("game is #{@game.id}, record id is #{e_record.try(:id)}, time is**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
# 记录前端总耗时
record_consume_time = e_record.try(:pod_execute)
max_mem = e_record.try(:max_mem)
@ -850,7 +850,7 @@ class GamesController < ApplicationController
@allowed_hidden_testset = @identity < User::EDU_GAME_MANAGER || @game.test_sets_view #解锁的用户
if max_query_index > 0
uid_logger("max_query_index is #{max_query_index} game id is #{@game.id}, challenge_id is #{challenge.id}")
#uid_logger("max_query_index is #{max_query_index} game id is #{@game.id}, challenge_id is #{challenge.id}")
@qurey_test_sets = TestSet.find_by_sql("SELECT o.code, o.actual_output, o.out_put, o.result, o.test_set_position, o.ts_time, o.ts_mem,
o.query_index, t.is_public, t.input, t.output, o.compile_success FROM outputs o, games g, challenges c,
test_sets t where g.id=#{@game.id} and c.id=#{challenge.id} and o.query_index=#{max_query_index}

@ -876,10 +876,12 @@ class HomeworkCommonsController < ApplicationController
subjects = Subject.where(id: params[:subject_ids], status: 2).includes(stages: :shixuns).reorder("id desc")
@homework_ids = []
none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
# none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
course_module = @course.course_modules.find_by(module_type: "shixun_homework")
subjects.each do |subject|
shixun_ids = subject.shixuns.where(use_scope: 0).pluck(:id) +
subject.shixuns.joins(:shixun_schools).where("school_id = #{current_user.try(:school_id).to_i} and use_scope = 1").pluck(:id)
subject.stages.each do |stage|
@ -889,7 +891,7 @@ class HomeworkCommonsController < ApplicationController
course_module_id: course_module.id, position: course_module.course_second_categories.count + 1)
# 去掉不对当前用户的单位公开的实训,已发布的实训
stage.shixuns.no_jupyter.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun|
stage.shixuns.no_jupyter.where(id: shixun_ids).unhidden.each do |shixun|
homework = HomeworksService.new.create_homework shixun, @course, category, current_user
@homework_ids << homework.id
CreateStudentWorkJob.perform_later(homework.id)
@ -981,8 +983,8 @@ class HomeworkCommonsController < ApplicationController
end
homework.homework_detail_manual.update_attributes!(comment_status: 1)
if homework.course_acts.size == 0
homework.course_acts << CourseActivity.new(user_id: homework.user_id, course_id: homework.course_id)
if homework.course_act.blank?
homework.course_act << CourseActivity.new(user_id: homework.user_id, course_id: homework.course_id)
end
# 发消息
HomeworkCommonPushNotifyJob.perform_later(homework.id, tiding_group_ids)
@ -1043,7 +1045,7 @@ class HomeworkCommonsController < ApplicationController
def end_homework
tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0
time = Time.now.strftime("%Y-%m-%d %H:%M:%S")
time = Time.now
# 已发布且未截止的作业才能立即截止
@ -1084,7 +1086,7 @@ class HomeworkCommonsController < ApplicationController
homework.end_time = time
end
homework_detail_manual.update_attributes!(comment_status: 2) if homework.end_time <= time
# homework_detail_manual.update_attributes!(comment_status: 2) if homework.end_time <= time
# 实训作业的作品需要计算是否迟交
if homework.homework_type == "practice"

@ -20,11 +20,8 @@ class MainController < ApplicationController
uid_logger("main start is #{cookies[:_educoder_session]}")
end
if params[:path] && params[:path]&.include?("educoderh5") && params[:path].split("/").first == "educoderh5"
render file: 'public/h5build/index.html', :layout => false
# TODO: 这块之后需要整合到上面去或者架构重新变化统一跳转到index后再路由分发
elsif params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
# TODO: 这块之后需要整合者架构重新变化统一跳转到index后再路由分发
if params[:path] && params[:path]&.include?("h5educoderbuild") && params[:path].split("/").first == "h5educoderbuild"
render file: 'public/h5educoderbuild/index.html', :layout => false
else
render file: 'public/react/build/index.html', :layout => false

@ -91,7 +91,7 @@ class MyshixunsController < ApplicationController
ActiveRecord::Base.transaction do
begin
t1 = Time.now
uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}")
#uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}")
jsonTestDetails = JSON.parse(params[:jsonTestDetails])
timeCost = JSON.parse(params[:timeCost])
brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present?
@ -101,7 +101,7 @@ class MyshixunsController < ApplicationController
sec_key = jsonTestDetails['sec_key']
server_url = jsonTestDetails['showServer']
uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
#uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
resubmit = jsonTestDetails['resubmit']
outPut = tran_base64_decode64(jsonTestDetails['outPut'])
@ -267,7 +267,7 @@ class MyshixunsController < ApplicationController
@sec_key = generate_identifier(EvaluateRecord, 12)
record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id,
:identifier => @sec_key, :exec_time => exec_time)
uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
#uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
end
# 隐藏代码文件 和 VNC的都不需要走版本库
vnc = @myshixun.shixun&.vnc
@ -282,8 +282,6 @@ class MyshixunsController < ApplicationController
else
params[:content]
end
uid_logger_dubug("content_#{@myshixun.identifier}: #{content}")
uid_logger_dubug("###last_content_#{@myshixun.identifier}####{last_content}")
if content != last_content
@content_modified = 1
@ -291,9 +289,6 @@ class MyshixunsController < ApplicationController
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted"
uid_logger_dubug("112233#{author_name}")
uid_logger_dubug("112233#{author_email}")
uid_logger_dubug("daiao_debug_#{@myshixun.identifier}: #{@repo_path}: #{path}; #{message}; #{content}; ")
@content = GitService.update_file(repo_path: @repo_path,
file_path: path,
message: message,

@ -30,4 +30,22 @@ class Oauth::BaseController < ActionController::Base
@_default_yun_session = "#{request.subdomain.split('.').first}_user_id"
# @_default_yun_session = "#{current_laboratory.try(:identifier).split('.').first}_user_id"
end
def session_openid
session[:openid]
end
def set_session_openid(openid)
Rails.logger.info("[wechat] set session openid: #{openid}")
session[:openid] = openid
end
def session_unionid
session[:unionid]
end
def set_session_unionid(unionid)
Rails.logger.info("[wechat] set session unionid: #{unionid}")
session[:unionid] = unionid
end
end

@ -0,0 +1,13 @@
class Oauth::CasController < Oauth::BaseController
def create
user, is_new_user = Oauth::CreateORFindCasUserService.call(current_user, auth_hash)
successful_authentication(user)
redirect_to root_url
end
def auth_hash
JSON.parse(CGI.unescape(request.env['omniauth.auth'].extra.to_json))
end
end

@ -1,11 +1,32 @@
class Oauth::WechatController < Oauth::BaseController
def create
user, new_user = Oauth::CreateOrFindWechatAccountService.call(current_user ,params)
# user, new_user = Oauth::CreateOrFindWechatAccountService.call(current_user ,params)
successful_authentication(user)
begin
code = params['code'].to_s.strip
tip_exception("code不能为空") if code.blank?
new_user = false
render_ok(new_user: new_user)
rescue Oauth::CreateOrFindWechatAccountService::Error => ex
render_error(ex.message)
result = WechatOauth::Service.access_token(code)
result = WechatOauth::Service.user_info(result['access_token'], result['openid'])
# 存在该用户
open_user = OpenUsers::Wechat.find_by(uid: result['unionid'])
if open_user.present? && open_user.user.present?
successful_authentication(open_user.user)
else
if current_user.blank? || !current_user.logged?
new_user = true
set_session_openid(result['openid'])
set_session_unionid(result['unionid'])
else
OpenUsers::Wechat.create!(user: current_user, uid: result['unionid'])
end
end
render_ok(new_user: new_user)
rescue WechatOauth::Error => ex
render_error(ex.message)
end
end
end

@ -4,7 +4,8 @@ class TagDisciplinesController < ApplicationController
def create
sub_discipline = SubDiscipline.find_by!(id: params[:sub_discipline_id])
tip_exception("重复的知识点") if sub_discipline.tag_disciplines.exists?(name: params[:name].to_s.strip)
tag_discipline = TagDiscipline.create!(name: params[:name].to_s.strip, sub_discipline: sub_discipline, user_id: current_user.id)
tag_discipline = TagDiscipline.create!(name: params[:name].to_s.strip, sub_discipline: sub_discipline, user_id: current_user.id,
position: sub_discipline.tag_disciplines.pluck(:position).max + 1)
render_ok({tag_discipline_id: tag_discipline.id})
end
end

@ -6,7 +6,7 @@ class Weapps::ChallengesController < Weapps::BaseController
# 关卡有展示效果 || 选择题 || jupyter实训 || vnc || 隐藏代码窗口 || html+css实训
# @challenge.show_type != -1 || @challenge.st == 1 || @shixun.is_jupyter? || @shixun.vnc ||
# @shixun.hide_code? || (@shixun.small_mirror_name & ["Css", "Html", "Web"]).present?
play = @challenge.st == 1 || @shixun.is_jupyter? || @shixun.vnc ||
play = @shixun.is_jupyter? || @shixun.vnc ||
@shixun.hide_code? || (@shixun.small_mirror_name & ["Css", "Html", "Web"]).present?
if play

@ -6,6 +6,23 @@ class Weapps::CoursesController < Weapps::BaseController
before_action :teacher_allowed, only: [:edit, :update]
before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers]
def course_activities
@course = current_course
homework_commons = @course.homework_commons.where(homework_type: ["practice", "normal"]).homework_published
member = @course.course_members.find_by(user_id: current_user.id, is_active: 1)
if (@user_course_identity == Course::STUDENT && member.try(:course_group_id).to_i == 0) || @user_course_identity > Course::STUDENT
homework_commons = homework_commons.unified_setting
elsif @user_course_identity == Course::STUDENT
not_homework_ids = @course.homework_group_settings.none_published.where("course_group_id = #{member.try(:course_group_id)}").pluck(:homework_common_id)
homework_commons = homework_commons.where.not(id: not_homework_ids)
end
homework_ids = homework_commons.blank? ? "(-1)" : "(" + homework_commons.pluck(:id).join(",") + ")"
activities = @course.course_activities.where("course_act_type in ('Course', 'CourseMessage') or
(course_act_type = 'HomeworkCommon' and course_act_id in #{homework_ids})").order("id desc")
@activities = paginate activities.includes(:course_act, user: :user_extension)
end
def create
# return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher?
course = Course.new(tea_id: current_user.id)

@ -1,5 +1,4 @@
class Weapps::ShixunListsController < ApplicationController
before_action :require_login
def index
results = Weapps::ShixunSearchService.call(search_params, current_laboratory)

@ -1,5 +1,5 @@
class Weapps::SubjectsController < Weapps::BaseController
before_action :require_login
before_action :require_login, except: [:index, :show]
before_action :find_subject, except: [:index]
# 首页

@ -169,6 +169,7 @@ module ShixunsHelper
source_class_name << source if source.present?
end
end
logger.info("####source_class_name: #{source_class_name}")
script = if script.include?("sourceClassName") && script.include?("challengeProgramName")
script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{source_class_name.reject(&:blank?).join(" ")}\)")
else

@ -70,7 +70,9 @@ class Course < ApplicationRecord
# 课堂动态
has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
has_one :course_act, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
has_many :course_activities
has_many :tidings, as: :container, dependent: :destroy
# 开放课堂
@ -300,7 +302,7 @@ class Course < ApplicationRecord
#课程动态公共表记录
def act_as_course_activity
self.course_acts << CourseActivity.new(user_id: tea_id, course_id: id)
self.course_act << CourseActivity.new(user_id: tea_id, course_id: id)
end
# 当前老师分班下的所有学生

@ -4,9 +4,26 @@ class CourseActivity < ApplicationRecord
belongs_to :user
belongs_to :exercise
belongs_to :poll
belongs_to :course_message
belongs_to :homework_common
# after_create :add_course_lead
def container_name
case course_act_type
when "HomeworkCommon"
course_act&.name
when "Exercise"
course_act&.exercise_name
when "Poll"
course_act&.poll_name
when "Message"
course_act&.subject
else
""
end
end
# 发布新课导语
# 导语要放置在课程创建信息之后
def add_course_lead

@ -2,6 +2,7 @@ class CourseMessage < ApplicationRecord
enum status: { UNHANDLED: 0, PASSED: 1, REJECTED: 2 }
belongs_to :course
belongs_to :user
has_one :course_act, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
scope :find_by_course, ->(course) { where(course_id: course.id) }
scope :join_course_requests, -> { where(course_message_type: "JoinCourseRequest") }
@ -9,6 +10,8 @@ class CourseMessage < ApplicationRecord
scope :unhandled_join_course_requests_by_course, ->(course) { find_by_course(course).join_course_requests.unhandled }
after_create :act_as_course_activity
def pass!
update!(status: :PASSED)
send_deal_tiding(1)
@ -25,6 +28,11 @@ class CourseMessage < ApplicationRecord
private
#课程动态公共表记录
def act_as_course_activity
self.course_act << CourseActivity.new(user_id: course_message_id, course_id: course_id)
end
def send_deal_tiding deal_status
# 发送申请处理结果消息
Tiding.create!(

@ -1,5 +1,7 @@
class Discipline < ApplicationRecord
has_many :sub_disciplines, dependent: :destroy
default_scope { order(position: :asc) }
has_many :sub_disciplines, -> { order("sub_disciplines.position ASC") }, dependent: :destroy
has_many :shixun_sub_disciplines, -> { where("shixun = 1") }, class_name: "SubDiscipline"
has_many :subject_sub_disciplines, -> { where("subject = 1") }, class_name: "SubDiscipline"

@ -3,5 +3,5 @@ class ExaminationIntelligentSetting < ApplicationRecord
belongs_to :user
has_many :examination_type_settings, dependent: :destroy
has_many :tag_discipline_containers, as: :container, dependent: :destroy
has_many :item_baskets, dependent: :destroy
has_many :item_baskets, -> { order("item_baskets.position ASC") }, dependent: :destroy
end

@ -1,3 +1,4 @@
class HackCode < ApplicationRecord
# 编程题代码相关
belongs_to :hack
end

@ -28,7 +28,7 @@ class HomeworkCommon < ApplicationRecord
belongs_to :course_second_category, optional: true
# 课堂动态
has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
has_one :course_act, class_name: 'CourseActivity', as: :course_act, dependent: :destroy
has_many :tidings, as: :container, dependent: :destroy
# 实训作业的分班查重记录
has_many :homework_group_reviews, :dependent => :destroy

@ -0,0 +1,9 @@
class OpenUsers::Cas < OpenUser
def nickname
extra&.[]('nickname')
end
def en_type
'cas'
end
end

@ -6,20 +6,21 @@ class SalesmanChannel < ApplicationRecord
school.name
end
def teacher_count
UserExtension.where(school_id: school_id).where.not(identity: 1).count
def teacher_count(start_time, end_time)
UserExtension.where("identity = 0 and school_id = #{school_id} and created_at between '#{start_time}' and '#{end_time}'").count
# UserExtension.where(school_id: school_id).where(query).count
end
def student_count
UserExtension.where(school_id: school_id, identity: 1).count
def student_count(start_time, end_time)
UserExtension.where("identity = 1 and school_id = #{school_id} and created_at between '#{start_time}' and '#{end_time}'").count
end
def course_count
Course.where(school_id: school_id).count
def course_count(start_time, end_time)
Course.where("school_id = #{school_id} and courses.created_at between '#{start_time}' and '#{end_time}'").count
end
def shixuns_count
ShixunMember.joins("join user_extensions on user_extensions.user_id = shixun_members.user_id")
def shixuns_count(start_time, end_time)
ShixunMember.joins("join user_extensions on user_extensions.user_id = shixun_members.user_id and shixun_members.created_at between '#{start_time}' and '#{end_time}'")
.where(user_extensions: {school_id: school_id}).pluck(:shixun_id).uniq.count
end

@ -1,6 +1,6 @@
class SalesmanCustomer < ApplicationRecord
belongs_to :salesman, :touch => true, counter_cache: true
belongs_to :school
belongs_to :school, optional: true
belongs_to :user
def name
@ -8,7 +8,7 @@ class SalesmanCustomer < ApplicationRecord
end
def school_name
school.name
school&.name
end
def courses_count

@ -1,6 +1,6 @@
class SubDiscipline < ApplicationRecord
belongs_to :discipline
has_many :tag_disciplines, dependent: :destroy
has_many :tag_disciplines, -> { order("tag_disciplines.position ASC") }, dependent: :destroy
has_many :sub_discipline_containers, dependent: :destroy
has_one :hack

@ -41,6 +41,7 @@ class Subject < ApplicationRecord
scope :published, lambda{where(status: 1)}
scope :unhidden, lambda{where(hidden: 0)}
scope :publiced, lambda{ where(public: 2) }
scope :show_moblied, lambda{ where(show_mobile: true) }
after_create :send_tiding
def send_tiding

@ -51,7 +51,10 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip]
all_shixuns = all_shixuns.where(is_wechat_support: params[:is_wechat_support]) if params[:is_wechat_support]
if params[:no_subject]
shixun_ids = StageShixun.pluck(:shixun_id).uniq
all_shixuns = all_shixuns.published.where.not(id: shixun_ids)
end
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end

@ -18,9 +18,9 @@ class Admins::SubjectQuery < ApplicationQuery
status =
case params[:status].to_s.strip
when "editing" then {status: 0}
when "processed" then {status: 2, public: 0}
when "applying" then {status: 2, public: [0, 1]}
when "pending" then {public: 1}
when "publiced" then {public: 2}
when "published" then {public: 2}
end
subjects = subjects.where(status) if status

@ -19,17 +19,20 @@ class OptionalItemQuery < ApplicationQuery
end
if hacks.present?
items = ItemBank.where(container_id: hacks.pluck(:id), container_type: "Hack").or(ItemBank.where(id: items.pluck(:id)))
items = ItemBank.where(container_id: hacks.where(status: 1).pluck(:id), container_type: "Hack")
.or(ItemBank.where(id: items.pluck(:id)).where("item_type != '6'"))
end
# 来源
public = source.present? ? source.to_i : 1
public = public == 2 ? [0, 1] : public
items = items.where(public: public)
if public == 1
items = items.where(public: 1)
elsif public == 0
items = items.where(user_id: User.current.id)
end
# 难度
difficulty = difficulty ? difficulty.to_i : 1
items = items.where(difficulty: difficulty)
diff = difficulty ? difficulty.to_i : 1
items = items.where(difficulty: diff)
items
end
end

@ -8,7 +8,7 @@ class Weapps::SubjectQuery < ApplicationQuery
end
def call
subjects = @current_laboratory.subjects.unhidden.publiced
subjects = @current_laboratory.subjects.unhidden.publiced.show_moblied
# 课程体系的过滤
if params[:sub_discipline_id].present?

@ -29,14 +29,14 @@ class Admins::ImportDisciplineService < ApplicationService
return unless discipline_name.present?
discipline = Discipline.find_by(name: discipline_name)
if discipline.blank?
discipline = Discipline.create!(name: discipline_name)
discipline = Discipline.create!(name: discipline_name, position: Discipline.all.pluck(:position).max + 1)
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)
SubDiscipline.create!(name: sub_discipline_name, discipline: discipline, position: discipline.sub_disciplines.pluck(:position).max + 1)
count += 1
end
end

@ -17,6 +17,7 @@ class CreateBindUserService < ApplicationService
bind_user = User.try_to_login(params[:username], params[:password])
raise Error, '用户名或者密码错误' if bind_user.blank?
raise Error, '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
raise Error, '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
ActiveRecord::Base.transaction do

@ -133,8 +133,10 @@ class HomeworksService
# 计算实训作品学生的效率分
def update_student_eff_score homework
if homework.work_efficiency && homework.max_efficiency != 0
max_efficiency = homework.student_works.where("compelete_status != 0").pluck(:efficiency).max
homework.update_column("max_efficiency", max_efficiency)
homework.student_works.where("compelete_status != 0").each do |student_work|
eff_score = student_work.efficiency / homework.max_efficiency * homework.eff_score
eff_score = student_work.efficiency / max_efficiency * homework.eff_score
student_work.eff_score = format("%.2f", eff_score)
student_work.late_penalty = student_work.work_status == 1 ? 0 : homework.late_penalty
unless student_work.ultimate_score
@ -333,7 +335,10 @@ class HomeworksService
work.compelete_status = myshixun_endtime < setting_time.end_time ? 2 : 3
# 如果作业的最大效率值有变更则更新所有作品的效率分
homework.update_column("max_efficiency", work.efficiency) if homework.work_efficiency && homework.max_efficiency < work.efficiency
if homework.work_efficiency && homework.max_efficiency < work.efficiency
homework.max_efficiency = work.efficiency
homework.save(validate: false)
end
else
work.compelete_status = 1 # 未通关
end

@ -0,0 +1,31 @@
class Oauth::CreateORFindCasUserService < ApplicationService
def initialize(user, params)
@user = user
@params = params
end
def call
return [@user, false] if @user
open_user = OpenUsers::Cas.find_or_initialize_by(uid: @params['user']) do |u|
u.extra = @params
end
return [open_user.user, false] if open_user.persisted?
@user = User.new(login: User.generate_login('C'), type: 'User', status: User::STATUS_ACTIVE, nickname: @params['comsys_name'], lastname: @params['comsys_name'])
ActiveRecord::Base.transaction do
@user.save!
@user.create_user_extension!
open_user.user = @user
open_user.save!
Rails.cache.write(open_user.can_bind_cache_key, 1, expires_in: 1.hours)
end
[@user, true]
end
end

@ -18,18 +18,22 @@ class Oauth::CreateOrFindWechatAccountService < ApplicationService
# 存在该用户
open_user = OpenUsers::Wechat.find_by(uid: result['unionid'])
return [open_user.user, new_user] if open_user.present?
return [open_user.user, new_user] if open_user.present? && open_user.user.present?
if user.blank? || !user.logged?
new_user = true
# 新用户
login = User.generate_login('w')
# result['nickname'] = regix_emoji(result['nickname'])
@user = User.new(login: login, type: 'User', status: User::STATUS_ACTIVE)
#@user = User.new(login: login, nickname: result['nickname'], type: 'User', status: User::STATUS_ACTIVE)
# login = User.generate_login('w')
# result['nickname'] = regix_emoji(result['nickname'])
# @user = User.new(login: login, type: 'User', status: User::STATUS_ACTIVE)
# @user = User.new(login: login, nickname: result['nickname'], type: 'User', status: User::STATUS_ACTIVE)
set_session_openid(result['openid'])
set_session_unionid(result['unionid'])
else
OpenUsers::Wechat.create!(user: user, uid: result['unionid'])
end
=begin
ActiveRecord::Base.transaction do
if new_user
user.save!
@ -46,6 +50,7 @@ class Oauth::CreateOrFindWechatAccountService < ApplicationService
Rails.cache.write(new_open_user.can_bind_cache_key, 1, expires_in: 1.hours) if new_user # 方便后面进行账号绑定
end
=end
[user, new_user]
rescue WechatOauth::Error => ex

@ -73,9 +73,11 @@ class UpdateHomeworkPublishSettingService < ApplicationService
# 作业在"提交中"状态时
else
if homework.end_time > Time.now && homework.unified_setting
# 实训作业截止时间已过也可修改截止时间,其他作业暂不支持修改
if (homework.homework_type == "practice" || homework.end_time > Time.now) && homework.unified_setting
tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time].to_time <= Time.now
tip_exception("截止时间必须晚于发布时间") if params[:end_time].to_time <= homework.publish_time
# tip_exception("截止时间不能早于当前时间") if params[:end_time].to_time <= Time.now
tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
course.end_date.present? && params[:end_time].to_time > course.end_date.end_of_day
@ -93,19 +95,29 @@ class UpdateHomeworkPublishSettingService < ApplicationService
# 如果该发布规则 没有已发布的分班则需判断发布时间
tip_exception("发布时间不能早于等于当前时间") if setting[:publish_time].to_time <= Time.now && group_settings.group_published.count == 0
tip_exception("截止时间不能早于等于当前时间") if setting[:end_time].to_time <= Time.now && group_settings.none_end.count > 0
# tip_exception("截止时间不能早于等于当前时间") if setting[:end_time].to_time <= Time.now && group_settings.none_end.count > 0
tip_exception("截止时间不能早于发布时间") if setting[:publish_time].to_time > setting[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
course.end_date.present? && setting[:end_time].to_time > course.end_date.end_of_day
group_settings.none_published.update_all(publish_time: setting[:publish_time])
group_settings.none_end.update_all(end_time: setting[:end_time])
# 实训作业截止时间已过也可修改截止时间,其他作业暂不支持修改
if homework.homework_type == "practice"
group_settings.update_all(end_time: setting[:end_time])
else
group_settings.none_end.update_all(end_time: setting[:end_time])
end
end
homework.end_time = homework.max_group_end_time
end
end
if homework.end_time > Time.now && homework.homework_detail_manual.try(:comment_status) > 1
homework.homework_detail_manual.update_attributes!(comment_status: 1)
end
homework.save!
UpdateShixunWorkScoreJob.perform_later(homework.id)
HomeworkCommonPushNotifyJob.perform_later(homework.id, publish_group_ids) if send_tiding
end

@ -50,7 +50,7 @@ class Users::UpdateAccountService < ApplicationService
end
if first_full_reward
RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500)
# RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500)
if user.user_extension.teacher?
join_course(user.id,1309, 2)
# sms_notify_admin(user.lastname)

@ -3,7 +3,7 @@ class Videos::DispatchCallbackService < ApplicationService
def initialize(params)
@video = Video.find_by(uuid: params[:VideoId])
@params = params
@params = params``
end
def call

@ -4,17 +4,33 @@
<meta charset="utf-8">
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0-rc.1/katex.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/contrib/auto-render.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.getElementById('markdown_content'), {
displayMode: true,
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "$", right: "$", display: false}
]
});
function fix_frac_line(){
var win = window;
var frac_lines = document.getElementsByClassName("frac-line");
for (var i = 0; i < frac_lines.length; i++) {
var frac = frac_lines[i];
if (win.getComputedStyle) {
style = win.getComputedStyle(frac, '');
if (style['border-bottom-width'] == '0px') {
frac.style['border-bottom-width'] = '1px';
}
}
}
};
fix_frac_line();
})
</script>
</head>

@ -0,0 +1,5 @@
<% if @message.present? %>
$.notify({ message: "<%= @message %>" });
<% else %>
$(".discipline-list-container").html("<%= j(render :partial => 'admins/disciplines/shared/list') %>");
<% end %>

@ -1,3 +1,4 @@
<% max_position = @disciplines.pluck(:position).max %>
<table class="table table-hover text-center discipline-list-table">
<thead class="thead-light">
<tr>
@ -11,9 +12,9 @@
</thead>
<tbody>
<% if @disciplines.present? %>
<% @disciplines.each_with_index do |discipline, index| %>
<% @disciplines.each do |discipline| %>
<tr class="discipline-item discipline-item-<%= discipline.id %>">
<td><%= index + 1 %></td>
<td><%= discipline.position %></td>
<td class="text-left">
<span><%= link_to discipline.name, admins_sub_disciplines_path(discipline_id: discipline), :title => discipline.name %></span>
</td>
@ -21,6 +22,9 @@
<td><%= check_box_tag :shixun,!discipline.shixun,discipline.shixun,remote:true,data:{id:discipline.id},class:"discipline-source-form" %></td>
<td><%= check_box_tag :question,!discipline.question,discipline.question,remote:true,data:{id:discipline.id},class:"discipline-source-form" %></td>
<td>
<%= javascript_void_link('上移', class: 'move-action', data: { id: discipline.id, opr: "up" }, style: discipline.position == 1 ? 'display:none' : '') %>
<%= javascript_void_link('下移', class: 'move-action', data: { id: discipline.id, opr: "down" }, style: discipline.position == max_position ? 'display:none' : '') %>
<%= link_to '编辑', edit_admins_discipline_path(discipline), remote: true, class: 'action' %>
<%= delete_link '删除', admins_discipline_path(discipline, element: ".discipline-item-#{discipline.id}"), class: 'delete-discipline-action' %>
</td>

@ -1,4 +1,9 @@
<% is_processed = params[:status].to_s != 'pending' %>
<link rel="stylesheet" href="/quill/quill.snow.css"/>
<div id="editor" style="display: none">
</div>
<script src="/quill/quill.min.js"></script>
<table class="table table-hover text-center professional-authentication-list-table">
<thead class="thead-light">
<tr>
@ -30,11 +35,13 @@
</td>
<td><%= user.real_name %></td>
<td><%= raw [user.school_name.presence, user.department_name.presence].compact.join('<br/>') %></td>
<td>
<td class="text-left">
<% if item.item_type == "PROGRAM" %>
<%= link_to item.name, "/problems/#{item.container&.identifier}/edit", target: "_blank" %>
<%= link_to item.name, "/problems/#{item.container&.identifier}/edit", id: "item_name_#{index}", class: "d-inline-block text-truncate",
style: "max-width: 280px", target: "_blank", data: { toggle: 'tooltip', title: "#{item.name}"} %>
<% else %>
<%= link_to item.name, admins_item_authentication_path(apply), remote: true %>
<%= link_to item.name, admins_item_authentication_path(apply), remote: true, id: "item_name_#{index}", class: "d-inline-block text-truncate",
style: "max-width: 280px", data: { toggle: 'tooltip', title: "#{item.name}"} %>
<% end %>
</td>
<td><%= item.type_string %></td>
@ -57,4 +64,18 @@
</tbody>
</table>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
<script>
var quill = new Quill('#editor', {
theme: 'snow'
});
var content = "";
<% applies.each_with_index do |apply, index| %>
<% item = ItemBank.find apply.container_id %>
content = JSON.parse(<%= item.name %>);
quill.setContents(content);
$("#item_name_<%= index %>").html(quill.container.firstChild.innerHTML);
<% end %>
</script>

@ -2,12 +2,33 @@
<% add_admin_breadcrumb("#{@salesman.name}的渠道", admins_salesmans_path) %>
<% end %>
<div class="box search-form-container salesman-channel-list-form rig">
<div class="flex-1">
<%= javascript_void_link '新增渠道', class: 'btn btn-primary', data: {salesman_id: @salesman.id, toggle: 'modal', target: '.admin-add-salesman-channel-user-modal' } %>
<% define_admin_breadcrumbs do %>
<% add_admin_breadcrumb('数据变化报表', admins_school_statistics_path) %>
<% end %>
<div class="box search-form-container saleman-channel-list-form">
<form class="form-inline search-form d-flex" data-search-form-url="<%= admins_salesman_channels_path(salesman_id: @salesman.id) %>">
<div class="time-select">
<div class="form-group grow-date-container">
<div class="input-group input-daterange grow-date-input-daterange">
<%= text_field_tag :start_date, params[:start_date], class: 'form-control start-date mx-0', placeholder: '开始时间' %>
<div class="input-group-prepend"><span class="input-group-text">到</span></div>
<%= text_field_tag :end_date, params[:end_date], class: 'form-control end-date mx-0', placeholder: '结束时间' %>
</div>
</div>
</div>
<%= text_field_tag :keyword, params[:keyword], placeholder: 'ID/单位名称检索', class: 'form-control mx-3 search-input' %>
<%= javascript_void_link '搜索', class: 'btn btn-primary search-btn', target: '' %>
<input type="reset" class="btn btn-secondary clear-btn ml-3" value="清空"/>
</form>
<div class="flex-12">
<%= javascript_void_link '新增渠道', class: 'btn btn-primary', data: {toggle: 'modal', target: '.admin-add-salesman-channel-user-modal' } %>
</div>
</div>
<div class="box admin-list-container salesman-channel-list-container">
<%= render(partial: 'admins/salesman_channels/shared/list') %>
</div>

@ -0,0 +1 @@
$(".salesman-channel-list-container").html("<%= j(render partial: 'admins/salesman_channels/shared/list') %>")

@ -8,13 +8,12 @@
</button>
</div>
<div class="modal-body">
<form class="admin-add-salesman-user-form">
<%= hidden_field_tag(:salesman_id, nil) %>
<form class="admin-add-salesman-user-form" data-url="<%= batch_add_admins_salesman_channels_path(salesman_id: @salesman.id) %>">
<div class="form-group d-flex">
<label class="col-form-label">单位:</label>
<div class="d-flex flex-column-reverse w-75">
<select id="user_ids" name="user_ids" class="form-control salesman-channel-user-select"></select>
<select id="school_ids" name="school_ids[]" class="form-control salesman-channel-user-select"></select>
</div>
</div>

@ -19,16 +19,16 @@
<span><%= channel.school_name %></span>
</td>
<td class="text-left">
<span><%= channel.teacher_count %></span>
<span><%= channel.teacher_count(@start_time, @end_time) %></span>
</td>
<td class="text-left">
<span><%= channel.student_count %></span>
<span><%= channel.student_count(@start_time, @end_time) %></span>
</td>
<td>
<%= channel.course_count %>
<%= channel.course_count(@start_time, @end_time) %>
</td>
<td>
<%= channel.shixuns_count %>
<%= channel.shixuns_count(@start_time, @end_time) %>
</td>
<td>
<%= delete_link '删除', admins_salesman_channel_path(channel, salesman_id: channel.salesman_id, element: ".salesman-channel-item-#{channel.id}"), class: 'delete-salesman-action' %>

@ -0,0 +1 @@
$(".salesman-customer-list-container").html("<%= j(render partial: 'admins/salesman_customers/shared/list') %>")

@ -2,9 +2,9 @@
<thead class="thead-light">
<tr>
<th width="6%">序号</th>
<th width="20%" class="text-left">名称</th>
<th width="30%" class="text-left">客户(点击数字客户列表)</th>
<th width="30%" class="text-left">渠道数(点击数字渠道列表)</th>
<th width="20%" class="text-left">业务员</th>
<th width="30%" class="text-left">重点跟踪客户(点击数字客户列表)</th>
<th width="30%" class="text-left">重点跟踪院校(点击数字渠道列表)</th>
<th width="14%">操作</th>
</tr>
</thead>

@ -88,14 +88,14 @@
</li>
<li>
<%= sidebar_item_group('#running_data', '运营数据', icon: 'bar-chart') do %>
<li><%= sidebar_item(admins_salesmans_path, '销售数据列表', icon: 'columns', controller: 'admins-salesman') %></li>
<%= sidebar_item_group('#running-data', '运营数据', icon: 'bar-chart') do %>
<li><%= sidebar_item(admins_salesmans_path, '销售数据列表', icon: 'columns', controller: 'admins-salesmans') %></li>
<% end %>
</li>
<li>
<%= sidebar_item_group('#other-submenu', '其他', icon: 'list-alt') do %>
<li><%= sidebar_item(admins_repertoires_path, '技术体系', icon: 'sitemap', controller: 'admins-repertoire') %></li>
<li><%= sidebar_item(admins_repertoires_path, '技术体系', icon: 'sitemap', controller: 'admins-repertoires') %></li>
<% end %>
</li>

@ -73,8 +73,8 @@
</div>
<div class="mr-5">
<label for="is_wechat_support">
<%= check_box_tag :is_wechat_support, !@sort_json[:is_wechat_support],@sort_json[:is_wechat_support], class:"shixun-settings-select" %>
<span class="only_view">只看小程序可用</span>
<%= check_box_tag :no_subject, !@sort_json[:no_subject],@sort_json[:no_subject], class:"shixun-settings-select" %>
<span class="only_view">已发布没关联课程</span>
</label>
</div>

@ -0,0 +1,5 @@
<% if @message.present? %>
$.notify({ message: "<%= @message %>" });
<% else %>
$(".sub-discipline-list-container").html("<%= j(render :partial => 'admins/sub_disciplines/shared/list') %>");
<% end %>

@ -1,3 +1,4 @@
<% max_position = @sub_disciplines.pluck(:position).max %>
<table class="table table-hover text-center sub-discipline-list-table">
<thead class="thead-light">
<tr>
@ -11,9 +12,9 @@
</thead>
<tbody>
<% if @sub_disciplines.present? %>
<% @sub_disciplines.each_with_index do |sub, index| %>
<% @sub_disciplines.each do |sub| %>
<tr class="sub-discipline-item sub-discipline-item-<%= sub.id %>">
<td><%= index + 1 %></td>
<td><%= sub.position %></td>
<td class="text-left">
<span><%= link_to sub.name, admins_tag_disciplines_path(sub_discipline_id: sub), :title => sub.name %></span>
</td>
@ -21,6 +22,9 @@
<td><%= check_box_tag :shixun,!sub.shixun,sub.shixun,disabled:!sub.discipline&.shixun,remote:true,data:{id:sub.id},class:"sub-discipline-source-form" %></td>
<td><%= check_box_tag :question,!sub.question,sub.question,disabled:!sub.discipline&.question,remote:true,data:{id:sub.id},class:"sub-discipline-source-form" %></td>
<td>
<%= javascript_void_link('上移', class: 'move-action', data: { id: sub.id, opr: "up" }, style: sub.position == 1 ? 'display:none' : '') %>
<%= javascript_void_link('下移', class: 'move-action', data: { id: sub.id, opr: "down" }, style: sub.position == max_position ? 'display:none' : '') %>
<%= link_to '编辑', edit_admins_sub_discipline_path(sub), remote: true, class: 'action' %>
<%= delete_link '删除', admins_sub_discipline_path(sub, element: ".sub-discipline-item-#{sub.id}"), class: 'delete-sub-discipline-action' %>
</td>

@ -6,7 +6,7 @@
<%= form_tag(admins_subject_settings_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
<div class="form-group mr-1">
<label for="status">状态:</label>
<% status_options = [['全部', ''], ['编辑中', 'pending'], ['审核中', 'applying'], ['已发布', 'published']] %>
<% status_options = [['全部', ''], ['编辑中', 'pending'], ['审核中', 'applying'], ['已公开', 'published']] %>
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
</div>

@ -1,14 +1,14 @@
<table class="table table-hover text-center subject-list-table">
<thead class="thead-light">
<tr>
<th width="4%">序号</th>
<th width="25%" class="text-left">名称</th>
<th width="12%">技术体系</th>
<th width="10%">等级体系</th>
<th width="5%">序号</th>
<th width="23%" class="text-left">名称</th>
<th width="10%">老版技术体系</th>
<th width="10%">状态</th>
<th width="25%">课程体系</th>
<th width="10%">封面</th>
<th width="8%">开课人数</th>
<th width="6%">操作</th>
<th width="5%">开课人数</th>
<th width="12%">操作</th>
</tr>
</thead>
<tbody>

@ -5,7 +5,7 @@
<span class="badge badge-pill badge-info excellent-badge" style="<%= subject.excellent? ? '' : 'display:none' %>">金课</span>
</td>
<td><%= display_text subject.repertoire&.name %></td>
<td><%= display_text subject.subject_level_system&.name %></td>
<td><%= display_text subject.public == 2 ? "已公开" : ((subject.public == 1 && subject.status == 2) ? "审核中" : "未发布") %></td>
<td>
<%= select_tag(:sub_disciplines, options_for_select(@sub_disciplines, subject.sub_disciplines.pluck(:id)),multiple:true,class:"form-control subject-setting-form",data:{id:subject.id},id:"tags-chosen-#{subject.id}") %>
</td>
@ -16,6 +16,8 @@
</td>
<td><%= subject.student_count %></td>
<td class="action-container">
<%= check_box_tag :show_mobile, !subject.show_mobile, subject.show_mobile, remote: true,
data: {id: subject.id, toggle: "tooltip", placement: "top"}, class: "subject-mobile-form mr10", title: "小程序端显示" %>
<%= link_to('编辑', edit_admins_subject_path(subject), remote: true, class: 'edit-action') %>
</td>
@ -24,4 +26,22 @@
multiple: true,
maximumSelectionLength: 3,
placeholder: '请选择课程体系'});
$(".action-container").on("change", '.subject-mobile-form', function () {
var s_id = $(this).attr("data-id");
var s_value = $(this).val();
var s_name = $(this).attr("name");
var json = {};
var s_index = $(this).parent("td").siblings(".shixun-line-no").text();
json[s_name] = s_value;
json["page_no"] = s_index;
$.ajax({
url: "/admins/subject_settings/update_mobile_show?subject_id=" + s_id,
type: "POST",
dataType:'script',
data: json
});
});
</script>

@ -0,0 +1,5 @@
<% if @message.present? %>
$.notify({ message: "<%= @message %>" });
<% else %>
$(".tag-discipline-list-container").html("<%= j(render :partial => 'admins/tag_disciplines/shared/list') %>");
<% end %>

@ -1,3 +1,4 @@
<% max_position = @tag_disciplines.pluck(:position).max %>
<table class="table table-hover text-center tag-discipline-list-table">
<thead class="thead-light">
<tr>
@ -12,9 +13,9 @@
</thead>
<tbody>
<% if @tag_disciplines.present? %>
<% @tag_disciplines.each_with_index do |tag, index| %>
<% @tag_disciplines.each do |tag| %>
<tr class="tag-discipline-item tag-discipline-item-<%= tag.id %>">
<td><%= index + 1 %></td>
<td><%= tag.position %></td>
<td class="text-left"><%= tag.name %></td>
<td>
<% if tag.user.present? %>
@ -36,6 +37,9 @@
<%= check_box_tag :question,!tag.question,tag.question,disabled:disabled,remote:true,data:{id:tag.id},class:"tag-discipline-source-form" %>
</td>
<td>
<%= javascript_void_link('上移', class: 'move-action', data: { id: tag.id, opr: "up" }, style: tag.position == 1 ? 'display:none' : '') %>
<%= javascript_void_link('下移', class: 'move-action', data: { id: tag.id, opr: "down" }, style: tag.position == max_position ? 'display:none' : '') %>
<%= link_to '编辑', edit_admins_tag_discipline_path(tag), remote: true, class: 'action' %>
<%= delete_link '删除', admins_tag_discipline_path(tag, element: ".tag-discipline-item-#{tag.id}"), class: 'delete-tag-discipline-action' %>
</td>

@ -0,0 +1,12 @@
json.activities @activities do |activity|
json.(activity, :course_act_id, :course_act_type)
json.author do
user = activity.user
json.name user.real_name
json.login user.login
json.img url_to_avatar(user)
end
json.created_at activity.created_at.strftime('%m-%d %H:%M:')
json.container_name activity.container_name
json.container_type activity.course_act_type == "HomeworkCommon" ? activity.course_act&.homework_type : ""
end

@ -29,6 +29,10 @@ module Educoderplus
# job
config.active_job.queue_adapter = :sidekiq
config.middleware.use OmniAuth::Builder do
provider :cas, url: 'https://urp.tfswufe.edu.cn/cas'
end
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'

@ -8,8 +8,8 @@ Rails.application.routes.draw do
get 'attachments/download/:id/:filename', to: 'attachments#show'
get 'auth/qq/callback', to: 'oauth/qq#create'
get 'auth/failure', to: 'oauth/base#auth_failure'
get 'auth/cas/callback', to: 'oauth/cas#create'
resources :edu_settings
scope '/api' do
@ -26,7 +26,7 @@ Rails.application.routes.draw do
put 'commons/unhidden', to: 'commons#unhidden'
delete 'commons/delete', to: 'commons#delete'
resources :jupyters do
resources :jupyters do
collection do
get :save_with_tpi
get :save_with_tpm
@ -42,7 +42,7 @@ Rails.application.routes.draw do
post :import_with_tpm
end
end
resources :memos do
member do
post :sticky_or_cancel
@ -1040,12 +1040,13 @@ Rails.application.routes.draw do
member do
get :shixun_homework_category
get :teachers
delete :delete_course_teachers
post :change_member_roles
get :students
delete :delete_course_students
get :course_groups
get :basic_info
get :course_activities
post :change_member_roles
delete :delete_course_teachers
delete :delete_course_students
end
collection do
@ -1328,7 +1329,9 @@ Rails.application.routes.draw do
post :drag, on: :collection
end
resources :subject_settings, only: [:index, :update]
resources :subject_settings, only: [:index, :update] do
post :update_mobile_show, on: :collection
end
resources :subjects, only: [:index, :edit, :update, :destroy] do
member do
@ -1353,9 +1356,15 @@ Rails.application.routes.draw do
resources :projects, only: [:index, :destroy]
resources :disciplines, only: [:index, :create, :edit, :update, :destroy]
resources :sub_disciplines, only: [:index, :create, :edit, :update, :destroy]
resources :tag_disciplines, only: [:index, :create, :edit, :update, :destroy]
resources :disciplines, only: [:index, :create, :edit, :update, :destroy] do
post :adjust_position, on: :member
end
resources :sub_disciplines, only: [:index, :create, :edit, :update, :destroy] do
post :adjust_position, on: :member
end
resources :tag_disciplines, only: [:index, :create, :edit, :update, :destroy] do
post :adjust_position, on: :member
end
resources :repertoires, only: [:index, :create, :edit, :update, :destroy]
resources :sub_repertoires, only: [:index, :create, :edit, :update, :destroy]

@ -0,0 +1,5 @@
class AddShowMoblieToSubjects < ActiveRecord::Migration[5.2]
def change
add_column :subjects, :show_mobile, :boolean, :default => false
end
end

@ -0,0 +1,8 @@
class SyncSubjectdsMobile < ActiveRecord::Migration[5.2]
def change
SubDisciplineContainer.find_each do |sc|
Subject.find(sc.container_id).update_column(:show_mobile, true)
end
end
end

@ -0,0 +1,7 @@
class AddPositionToDiscipline < ActiveRecord::Migration[5.2]
def change
add_column :disciplines, :position, :integer, default: 0
add_column :sub_disciplines, :position, :integer, default: 0
add_column :tag_disciplines, :position, :integer, default: 0
end
end

@ -0,0 +1,15 @@
class MigrateDisciplinePosition < ActiveRecord::Migration[5.2]
def change
Discipline.all.each_with_index do |discipline, i|
discipline.update_column("position", i + 1)
discipline.sub_disciplines.each_with_index do |sub, j|
sub.update_column("position", j + 1)
sub.tag_disciplines.each_with_index do |tag, k|
tag.update_column("position", k + 1)
end
end
end
end
end

@ -0,0 +1,10 @@
class AddUniqIndexToSalesmanChannel < ActiveRecord::Migration[5.2]
def change
sql = %Q(delete from salesman_channels where (salesman_id, school_id) in
(select * from (select salesman_id, school_id from salesman_channels group by salesman_id, school_id having count(*) > 1) a)
and id not in (select * from (select min(id) from salesman_channels group by salesman_id, school_id having count(*) > 1 order by id) b))
ActiveRecord::Base.connection.execute sql
add_index :salesman_channels, [:salesman_id, :school_id], unique: true
end
end

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

@ -0,0 +1,5 @@
class MigrateCourseMessageAct < ActiveRecord::Migration[5.2]
def change
CourseActivity.where(course_act_type: "JoinCourse").update_all(course_act_type: "CourseMessage")
end
end

@ -45,7 +45,7 @@ namespace :homework_publishtime do
end
end
homework.course_acts << CourseActivity.new(user_id: homework.user_id, course_id: homework.course_id) if !homework.course_acts.exists?
homework.course_act << CourseActivity.new(user_id: homework.user_id, course_id: homework.course_id) if !homework.course_act.present?
end
# 分组设置发布时间的作业
@ -66,7 +66,7 @@ namespace :homework_publishtime do
.where("homework_type = 4 and end_time <= '#{Time.now}'")
homework_commons.each do |homework|
# homework_challenge_settings = homework.homework_challenge_settings
homework.homework_detail_manual.update_column("comment_status", 2)
# homework.homework_detail_manual.update_column("comment_status", 2)
if homework.allow_late
if homework.unified_setting

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

Loading…
Cancel
Save