diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 47349e219..324e5bde3 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -32,8 +32,11 @@ class AccountsController < ApplicationController end uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) - return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip - return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + # todo 上线前请删除万能验证码"513231" + if code != "513231" + return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip + return normal_status(-2, "验证码已失效") if !verifi_code&.effective? + end code = generate_identifier User, 8 login = pre + code diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9fd7dc0b5..cc1fc167e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,571 +1,563 @@ -require 'oauth2' - -class ApplicationController < ActionController::Base - include CodeExample - include RenderExpand - include RenderHelper - include ControllerRescueHandler - include GitHelper - include LoggerHelper - - protect_from_forgery prepend: true, unless: -> { request.format.json? } - - before_action :user_setup - #before_action :check_account - - DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) - - helper_method :current_user - - # 全局配置参数 - # 返回name对应的value - def edu_setting(name) - EduSetting.get(name) - end - - # 实训的访问权限 - def shixun_access_allowed - if !current_user.shixun_permission(@shixun) - tip_exception(403, "..") - end - end - - def admin_or_business? - User.current.admin? || User.current.business? - end - - # 访问课堂时没权限直接弹加入课堂的弹框 :409 - def user_course_identity - @user_course_identity = current_user.course_identity(@course) - if @user_course_identity > Course::STUDENT && @course.is_public == 0 - tip_exception(409, "您没有权限进入") - end - uid_logger("###############user_course_identity:#{@user_course_identity}") - end - - - # 判断用户的邮箱或者手机是否可用 - # params[:type] 1: 注册;2:忘记密码 - def check_mail_and_phone_valid login, type - unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || - login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ - tip_exception(-2, "请输入正确的手机号或邮箱") - end - # 考虑到安全参数问题,多一次查询,去掉Union - user = User.where(phone: login).first || User.where(mail: login).first - if type.to_i == 1 && !user.nil? - tip_exception(-2, "该手机号码或邮箱已被注册") - elsif type.to_i == 2 && user.nil? - tip_exception(-2, "该手机号码或邮箱未注册") - end - sucess_status - end - - # 发送及记录激活码 - # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 - # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 - def check_verification_code(code, send_type, value) - case send_type - when 1, 2, 4 - # 手机类型的发送 - sigle_para = {phone: value} - status = Educoder::Sms.send(mobile: value, code: code) - tip_exception(-2, code_msg(status)) if status != 0 - when 8, 3, 5 - # 邮箱类型的发送 - sigle_para = {email: value} - begin - UserMailer.register_email(value, code).deliver_now - # Mailer.run.email_register(code, value) - rescue Exception => e - logger_error(e) - tip_exception(-2,"邮件发送失败,请稍后重试") - end - end - ver_params = {code_type: send_type, code: code}.merge(sigle_para) - VerificationCode.create!(ver_params) - end - - def code_msg status - case status - when 0 - "验证码已经发送到您的手机,请注意查收" - when 8 - "同一手机号30秒内重复提交相同的内容" - when 9 - "同一手机号5分钟内重复提交相同的内容超过3次" - when 22 - "1小时内同一手机号发送次数超过限制" - when 33 - "验证码发送次数超过频率" - when 43 - "一天内同一手机号发送次数超过限制" - end - end - - def find_course - return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? - @course = Course.find(params[:course_id]) - rescue Exception => e - tip_exception(e.message) - end - - def course_manager - return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR - end - - def find_board - return normal_status(2, "缺少board_id参数") if params[:board_id].blank? - @board = Board.find(params[:board_id]) - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - - def validate_type(object_type) - normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) - end - - def set_pagination - @page = params[:page] || 1 - @page_size = params[:page_size] || 15 - end - - # 课堂教师权限 - def teacher_allowed - logger.info("#####identity: #{current_user.course_identity(@course)}") - unless current_user.course_identity(@course) < Course::STUDENT - normal_status(403, "") - end - end - - # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) - def teacher_or_admin_allowed - unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR - normal_status(403, "") - end - end - - def require_admin - normal_status(403, "") unless User.current.admin? - end - - def require_business - normal_status(403, "") unless admin_or_business? - end - - # 前端会捕捉401,弹登录弹框 - # 未授权的捕捉407,弹试用申请弹框 - def require_login - #6.13 -hs - tip_exception(401, "..") unless User.current.logged? - end - - # 异常提醒 - def tip_exception(status = -1, message) - raise Educoder::TipException.new(status, message) - end - - def missing_template - tip_exception(404, "...") - end - - # 弹框提醒 - def tip_show_exception(status = -2, message) - raise Educoder::TipException.new(status, message) - end - - def normal_status(status = 0, message) - case status - when 403 - message = "您没有权限进行该操作" - when 404 - message = "您访问的页面不存在或已被删除" - end - render :json => { status: status, message: message } - end - - # 系统全局认证 - def check_auth - day_cer = UserDayCertification.find_by(user_id: current_user.id) - # 如果注册超过24小时则需要完善资料及授权 - if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 - if !current_user.profile_completed? - info_url = '/account/profile' - tip_exception(402, info_url) - elsif current_user.certification != 1 - if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - tip_exception(408, "您的试用申请正在审核中,请耐心等待") - end - tip_exception(407, "系统未授权") - end - end - - - # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) - # tip_exception(408, "您的试用申请正在审核中,请耐心等待") - # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # if !current_user.profile_completed? - # info_url = '/account/profile' - # tip_exception(402, info_url) - # elsif current_user.certification != 1 - # day_cer = UserDayCertification.find_by(user_id: current_user.id) - # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 - # end - # end - end - - def start_user_session(user) - session[:user_id] = user.id - session[:ctime] = Time.now.utc.to_i - session[:atime] = Time.now.utc.to_i - end - - def user_setup - # reacct静态资源加载不需要走这一步 - return if params[:controller] == "main" - # Find the current user - User.current = find_current_user - uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) - - if !User.current.logged? && Rails.env.development? - User.current = User.find 12 - end - - # User.current = User.find 81403 - - if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 - User.current = User.find 81403 - elsif params[:debug] == 'student' - User.current = User.find 8686 - elsif params[:debug] == 'admin' - User.current = User.find 1 - elsif params[:debug] - User.current = User.find_by_login params[:debug] - end - end - - # Sets the logged in user - def logged_user=(user) - reset_session - if user && user.is_a?(User) - User.current = user - start_user_session(user) - else - User.current = User.anonymous - end - end - - # Returns the current user or nil if no user is logged in - # and starts a session if needed - def find_current_user - uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") - if session[:user_id] - # existing session - (User.active.find(session[:user_id]) rescue nil) - elsif autologin_user = try_to_autologin - autologin_user - elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? - # RSS key authentication does not start a session - User.find_by_rss_key(params[:key]) - end - end - - def autologin_cookie_name - edu_setting('autologin_cookie_name').presence || 'autologin' - end - - def try_to_autologin - if cookies[autologin_cookie_name] - # auto-login feature starts a new session - user = User.try_to_autologin(cookies[autologin_cookie_name]) - if user - start_user_session(user) - end - user - end - end - - def api_request? - %w(xml json).include? params[:format] - end - - def current_user - User.current - end - - ## 默认输出json - def render_json - respond_to do |format| - format.json - end - end - - ## 输出错误信息 - def error_status(message = nil) - @status = -1 - @message = message - end - - # 实训等对应的仓库地址 - def repo_ip_url(repo_path) - "#{edu_setting('git_address_ip')}/#{repo_path}" - end - - def repo_url(repo_path) - "#{edu_setting('git_address_domain')}/#{repo_path}" - end - - # 通关后,把最后一次成功的代码存到数据库 - # type 0 创始内容, 1 最新内容 - def game_passed_code(path, myshixun, game_id) - return if myshixun.shixun.hide_code - file_content = git_fle_content myshixun.repo_path, path - unless file_content.present? - raise("获取文件代码异常") - end - game_code = GameCode.where(:game_id => game_id, :path => path).first - if game_code.nil? - GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path) - else - game_code.update_attributes!(:new_code => file_content) - end - end - - # Post请求 - def uri_post(uri, params) - begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") - uri = URI.parse(URI.encode(uri.strip)) - res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") - JSON.parse(res) - rescue Exception => e - uid_logger("--uri_exec: exception #{e.message}") - raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") - end - end - - # 处理返回非0就报错的请求 - def interface_post(uri, params, status, message) - begin - uid_logger("--uri_exec: params is #{params}, url is #{uri}") - uri = URI.parse(URI.encode(uri.strip)) - res = Net::HTTP.post_form(uri, params).body - logger.info("--uri_exec: .....res is #{res}") - res = JSON.parse(res) - if (res && res['code'] != 0) - tip_exception(status, message) - else - res - end - rescue Exception => e - uid_logger("--uri_exec: exception #{e.message}") - raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") - end - end - - # 适用与已经用url_safe编码后,回调字符串形式 - def tran_base64_decode64(str) - s_size = str.size % 4 - if s_size != 0 - str += "=" * (4 - s_size) - end - if str.blank? - str - else - Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") - end - end - - def sucess_status(message = 'success') - render :json => { status: 1, message: message } - end - - # 随机生成字符 - def generate_identifier(container, num) - code = DCODES.sample(num).join - if container == User - while container.exists?(login: code) do - code = DCODES.sample(num).join - end - else - while container.exists?(identifier: code) do - code = DCODES.sample(num).join - end - end - code - end - - - # 实训主类别列表,自带描述 - def shixun_main_type - list = [] - mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror - mirrors.try(:each) do |mirror| - list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} - end - list - end - - # 小类别列表 - def shixun_small_type - list = [] - mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror - mirrors.try(:each) do |mirror| - list << {id: mirror.id, type_name: mirror.type_name} - end - list - end - - def container_limit(mirror_repositories) - container = [] - mirror_repositories.each do |mr| - if mr.name.present? - container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"} - end - end - container.to_json - end - - # 实训中间层pod配置 - def shixun_container_limit shixun - container = [] - shixun.shixun_service_configs.each do |config| - mirror = config.mirror_repository - if mirror.name.present? - container << {:image => mirror.name, - :cpuLimit => config.cpu_limit, - :cpuRequest => config.lower_cpu_limit, - :memoryLimit => "#{config.memory_limit}M", - :memoryRequest => "#{config.request_limit}M", - :resourceLimit => "#{config.resource_limit}K", - :type => mirror.try(:main_type) == "1" ? "main" : "sub"} - end - end - container.to_json - end - - # 毕设任务列表的赛选 - def course_work(task, **option) - logger.info("#############{option}") - course = task.course - work_list = task.graduation_works.includes(user: [:user_extension]) - # 教师评阅搜索 0: 未评, 1 已评 - if option[:teacher_comment] - graduation_work_ids = GraduationWorkScore.where(graduation_work_id: work_list.map(&:id)).pluck(:graduation_work_id) - if option[:teacher_comment].zero? - work_list = work_list.where.not(id: graduation_work_ids) - elsif option[:teacher_comment] == 1 - work_list = work_list.where(id: graduation_work_ids).where.not(work_status: 0) - end - end - - # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 - if option[:task_status] - work_list = work_list.where(work_status: option[:task_status]) - end - - # 分班情况 - if option[:course_group] - group_user_ids = course.course_members.where(course_group_id: option[:course_group]).pluck(:user_id) - # 有分组只可能是老师身份查看列表 - work_list = work_list.where(user_id: group_user_ids) - end - - # 只看我的交叉评阅 - if option[:cross_comment] - graduation_work_id = task.graduation_work_comment_assignations.where(:user_id => current_user.id) - .pluck(:graduation_work_id).uniq if task.graduation_work_comment_assignations - work_list = work_list.where(id: graduation_work_id) - end - - # 输入姓名和学号搜索 - # TODO user_extension 如果修改 请调整 - if option[:search] - work_list = work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? - or student_id like ?", "%#{option[:search]}%", "%#{option[:search]}%") - end - - # 排序 - rorder = option[:order] || "updated_at" - b_order = option[:b_order] || "desc" - if rorder == "created_at" || rorder == "work_score" - work_list = work_list.order("graduation_works.#{rorder} #{b_order}") - elsif rorder == "student_id" - work_list = work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") - end - work_list - end - - def strip_html(text, len=0, endss="...") - ss = "" - if !text.nil? && text.length>0 - ss=text.gsub(/<\/?.*?>/, '').strip - ss = ss.gsub(/ */, '') - ss = ss.gsub(/\r\n/,'') #新增 - ss = ss.gsub(/\n/,'') #新增 - if len > 0 && ss.length > len - ss = ss[0, len] + endss - elsif len > 0 && ss.length <= len - ss = ss - #ss = truncate(ss, :length => len) - end - end - ss - end - - # Returns a string that can be used as filename value in Content-Disposition header - def filename_for_content_disposition(name) - request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name - end - - def format_time(time) - time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M") - end - - # 获取Oauth Client - def get_client(site) - client_id = Rails.configuration.educoder['client_id'] - client_secret = Rails.configuration.educoder['client_secret'] - - OAuth2::Client.new(client_id, client_secret, site: site) - end - - def paginate(relation) - limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i - page = params[:page].to_i.zero? ? 1 : params[:page].to_i - offset = (page - 1) * limit - - if relation.is_a?(Array) - relation[offset, limit] - else - relation.limit(limit).offset(offset) - end - end - - def strf_time(time) - time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") - end - - def logger_error(error) - Rails.logger.error(error.message) - error.backtrace.each { |msg| Rails.logger.error(msg) } - end - - private - def object_not_found - uid_logger("Missing template or cant't find record, responding with 404") - render json: {message: "您访问的页面不存在或已被删除", status: 404} - false - end - - def tip_show(exception) - uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") - render json: exception.tip_json - end - - def render_parameter_missing - render json: { status: -1, message: '参数缺失' } - end -end +require 'oauth2' + +class ApplicationController < ActionController::Base + include CodeExample + include RenderExpand + include RenderHelper + include ControllerRescueHandler + include GitHelper + include LoggerHelper + + protect_from_forgery prepend: true, unless: -> { request.format.json? } + + before_action :user_setup + #before_action :check_account + + DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + + helper_method :current_user + + # 全局配置参数 + # 返回name对应的value + def edu_setting(name) + EduSetting.get(name) + end + + # 实训的访问权限 + def shixun_access_allowed + if !current_user.shixun_permission(@shixun) + tip_exception(403, "..") + end + end + + def admin_or_business? + User.current.admin? || User.current.business? + end + + # 访问课堂时没权限直接弹加入课堂的弹框 :409 + def user_course_identity + @user_course_identity = current_user.course_identity(@course) + if @user_course_identity > Course::STUDENT && @course.is_public == 0 + tip_exception(409, "您没有权限进入") + end + uid_logger("###############user_course_identity:#{@user_course_identity}") + end + + + # 判断用户的邮箱或者手机是否可用 + # params[:type] 1: 注册;2:忘记密码 + def check_mail_and_phone_valid login, type + unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ || + login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/ + tip_exception(-2, "请输入正确的手机号或邮箱") + end + # 考虑到安全参数问题,多一次查询,去掉Union + user = User.where(phone: login).first || User.where(mail: login).first + if type.to_i == 1 && !user.nil? + tip_exception(-2, "该手机号码或邮箱已被注册") + elsif type.to_i == 2 && user.nil? + tip_exception(-2, "该手机号码或邮箱未注册") + end + sucess_status + end + + # 发送及记录激活码 + # 发送验证码:type 1:注册手机验证码 2:找回密码手机验证码 3:找回密码邮箱验证码 4:绑定手机 5:绑定邮箱 + # 6:手机验证码登录 7:邮箱验证码登录 8:邮箱注册验证码 + def check_verification_code(code, send_type, value) + case send_type + when 1, 2, 4 + # 手机类型的发送 + sigle_para = {phone: value} + status = Educoder::Sms.send(mobile: value, code: code) + tip_exception(-2, code_msg(status)) if status != 0 + when 8, 3, 5 + # 邮箱类型的发送 + sigle_para = {email: value} + begin + UserMailer.register_email(value, code).deliver_now + # Mailer.run.email_register(code, value) + rescue Exception => e + logger_error(e) + tip_exception(-2,"邮件发送失败,请稍后重试") + end + end + ver_params = {code_type: send_type, code: code}.merge(sigle_para) + VerificationCode.create!(ver_params) + end + + def code_msg status + case status + when 0 + "验证码已经发送到您的手机,请注意查收" + when 8 + "同一手机号30秒内重复提交相同的内容" + when 9 + "同一手机号5分钟内重复提交相同的内容超过3次" + when 22 + "1小时内同一手机号发送次数超过限制" + when 33 + "验证码发送次数超过频率" + when 43 + "一天内同一手机号发送次数超过限制" + end + end + + def find_course + return normal_status(2, '缺少course_id参数!') if params[:course_id].blank? + @course = Course.find(params[:course_id]) + rescue Exception => e + tip_exception(e.message) + end + + def course_manager + return normal_status(403, '只有课堂管理员才有权限') if @user_course_identity > Course::CREATOR + end + + def find_board + return normal_status(2, "缺少board_id参数") if params[:board_id].blank? + @board = Board.find(params[:board_id]) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def validate_type(object_type) + normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip) + end + + def set_pagination + @page = params[:page] || 1 + @page_size = params[:page_size] || 15 + end + + # 课堂教师权限 + def teacher_allowed + logger.info("#####identity: #{current_user.course_identity(@course)}") + unless current_user.course_identity(@course) < Course::STUDENT + normal_status(403, "") + end + end + + # 课堂教师、课堂管理员、超级管理员的权限(不包含助教) + def teacher_or_admin_allowed + unless current_user.course_identity(@course) < Course::ASSISTANT_PROFESSOR + normal_status(403, "") + end + end + + def require_admin + normal_status(403, "") unless User.current.admin? + end + + def require_business + normal_status(403, "") unless admin_or_business? + end + + # 前端会捕捉401,弹登录弹框 + # 未授权的捕捉407,弹试用申请弹框 + def require_login + #6.13 -hs + tip_exception(401, "..") unless User.current.logged? + end + + # 异常提醒 + def tip_exception(status = -1, message) + raise Educoder::TipException.new(status, message) + end + + def missing_template + tip_exception(404, "...") + end + + # 弹框提醒 + def tip_show_exception(status = -2, message) + raise Educoder::TipException.new(status, message) + end + + def normal_status(status = 0, message) + case status + when 403 + message = "您没有权限进行该操作" + when 404 + message = "您访问的页面不存在或已被删除" + end + render :json => { status: status, message: message } + end + + # 系统全局认证 + def check_auth + day_cer = UserDayCertification.find_by(user_id: current_user.id) + # 如果注册超过24小时则需要完善资料及授权 + if (Time.now.to_i - day_cer.try(:created_at).to_i) > 86400 + if !current_user.profile_completed? + info_url = '/account/profile' + tip_exception(402, info_url) + elsif current_user.certification != 1 + if current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + tip_exception(408, "您的试用申请正在审核中,请耐心等待") + end + tip_exception(407, "系统未授权") + end + end + + + # if current_user.certification != 1 && current_user.apply_actions.exists?(container_type: 'TrialAuthorization', status: 0) + # tip_exception(408, "您的试用申请正在审核中,请耐心等待") + # elsif (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # if !current_user.profile_completed? + # info_url = '/account/profile' + # tip_exception(402, info_url) + # elsif current_user.certification != 1 + # day_cer = UserDayCertification.find_by(user_id: current_user.id) + # tip_exception(407, "系统未授权") unless (Time.now.to_i - day_cer.try(:created_at).to_i) < 86400 + # end + # end + end + + def start_user_session(user) + session[:user_id] = user.id + session[:ctime] = Time.now.utc.to_i + session[:atime] = Time.now.utc.to_i + end + + def user_setup + # reacct静态资源加载不需要走这一步 + return if params[:controller] == "main" + # Find the current user + User.current = find_current_user + uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + + if !User.current.logged? && Rails.env.development? + User.current = User.find 12 + end + + # User.current = User.find 81403 + end + + # Sets the logged in user + def logged_user=(user) + reset_session + if user && user.is_a?(User) + User.current = user + start_user_session(user) + else + User.current = User.anonymous + end + end + + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + uid_logger("user setup start: session[:user_id] is #{session[:user_id]}") + if session[:user_id] + # existing session + (User.active.find(session[:user_id]) rescue nil) + elsif autologin_user = try_to_autologin + autologin_user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + User.find_by_rss_key(params[:key]) + end + end + + def autologin_cookie_name + edu_setting('autologin_cookie_name').presence || 'autologin' + end + + def try_to_autologin + if cookies[autologin_cookie_name] + # auto-login feature starts a new session + user = User.try_to_autologin(cookies[autologin_cookie_name]) + if user + start_user_session(user) + end + user + end + end + + def api_request? + %w(xml json).include? params[:format] + end + + def current_user + User.current + end + + ## 默认输出json + def render_json + respond_to do |format| + format.json + end + end + + ## 输出错误信息 + def error_status(message = nil) + @status = -1 + @message = message + end + + # 实训等对应的仓库地址 + def repo_ip_url(repo_path) + "#{edu_setting('git_address_ip')}/#{repo_path}" + end + + def repo_url(repo_path) + "#{edu_setting('git_address_domain')}/#{repo_path}" + end + + # 通关后,把最后一次成功的代码存到数据库 + # type 0 创始内容, 1 最新内容 + def game_passed_code(path, myshixun, game_id) + # 如果代码窗口是隐藏的,则不用保存代码 + return if myshixun.shixun.hide_code + file_content = git_fle_content myshixun.repo_path, path + unless file_content.present? + raise("获取文件代码异常") + end + logger.info("#######game_id:#{game_id}, file_content:#{file_content}") + game_code = GameCode.where(:game_id => game_id, :path => path).first + if game_code.nil? + GameCode.create!(:game_id => game_id, :new_code => file_content, :path => path) + else + game_code.update_attributes!(:new_code => file_content) + end + end + + # Post请求 + def uri_post(uri, params) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + JSON.parse(res) + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # 处理返回非0就报错的请求 + def interface_post(uri, params, status, message) + begin + uid_logger("--uri_exec: params is #{params}, url is #{uri}") + uri = URI.parse(URI.encode(uri.strip)) + res = Net::HTTP.post_form(uri, params).body + logger.info("--uri_exec: .....res is #{res}") + res = JSON.parse(res) + if (res && res['code'] != 0) + tip_exception(status, message) + else + res + end + rescue Exception => e + uid_logger("--uri_exec: exception #{e.message}") + raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + end + end + + # 适用与已经用url_safe编码后,回调字符串形式 + def tran_base64_decode64(str) + s_size = str.size % 4 + if s_size != 0 + str += "=" * (4 - s_size) + end + if str.blank? + str + else + Base64.decode64(str.tr("-_", "+/")).force_encoding("utf-8") + end + end + + def sucess_status(message = 'success') + render :json => { status: 1, message: message } + end + + # 随机生成字符 + def generate_identifier(container, num) + code = DCODES.sample(num).join + if container == User + while container.exists?(login: code) do + code = DCODES.sample(num).join + end + else + while container.exists?(identifier: code) do + code = DCODES.sample(num).join + end + end + code + end + + + # 实训主类别列表,自带描述 + def shixun_main_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} + end + list + end + + # 小类别列表 + def shixun_small_type + list = [] + mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror + mirrors.try(:each) do |mirror| + list << {id: mirror.id, type_name: mirror.type_name} + end + list + end + + def container_limit(mirror_repositories) + container = [] + mirror_repositories.each do |mr| + if mr.name.present? + container << {:image => mr.name, :cpuLimit => mr.cpu_limit, :memoryLimit => "#{mr.memory_limit}M", :type => mr.try(:main_type) == "1" ? "main" : "sub"} + end + end + container.to_json + end + + # 实训中间层pod配置 + def shixun_container_limit shixun + container = [] + shixun.shixun_service_configs.each do |config| + mirror = config.mirror_repository + if mirror.name.present? + container << {:image => mirror.name, + :cpuLimit => config.cpu_limit, + :cpuRequest => config.lower_cpu_limit, + :memoryLimit => "#{config.memory_limit}M", + :memoryRequest => "#{config.request_limit}M", + :resourceLimit => "#{config.resource_limit}K", + :type => mirror.try(:main_type) == "1" ? "main" : "sub"} + end + end + container.to_json + end + + # 毕设任务列表的赛选 + def course_work(task, **option) + logger.info("#############{option}") + course = task.course + work_list = task.graduation_works.includes(user: [:user_extension]) + # 教师评阅搜索 0: 未评, 1 已评 + if option[:teacher_comment] + graduation_work_ids = GraduationWorkScore.where(graduation_work_id: work_list.map(&:id)).pluck(:graduation_work_id) + if option[:teacher_comment].zero? + work_list = work_list.where.not(id: graduation_work_ids) + elsif option[:teacher_comment] == 1 + work_list = work_list.where(id: graduation_work_ids).where.not(work_status: 0) + end + end + + # 作品状态 0: 未提交, 1 按时提交, 2 延迟提交 + if option[:task_status] + work_list = work_list.where(work_status: option[:task_status]) + end + + # 分班情况 + if option[:course_group] + group_user_ids = course.course_members.where(course_group_id: option[:course_group]).pluck(:user_id) + # 有分组只可能是老师身份查看列表 + work_list = work_list.where(user_id: group_user_ids) + end + + # 只看我的交叉评阅 + if option[:cross_comment] + graduation_work_id = task.graduation_work_comment_assignations.where(:user_id => current_user.id) + .pluck(:graduation_work_id).uniq if task.graduation_work_comment_assignations + work_list = work_list.where(id: graduation_work_id) + end + + # 输入姓名和学号搜索 + # TODO user_extension 如果修改 请调整 + if option[:search] + work_list = work_list.joins(user: :user_extension).where("concat(lastname, firstname) like ? + or student_id like ?", "%#{option[:search]}%", "%#{option[:search]}%") + end + + # 排序 + rorder = option[:order] || "updated_at" + b_order = option[:b_order] || "desc" + if rorder == "created_at" || rorder == "work_score" + work_list = work_list.order("graduation_works.#{rorder} #{b_order}") + elsif rorder == "student_id" + work_list = work_list.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") + end + work_list + end + + def strip_html(text, len=0, endss="...") + ss = "" + if !text.nil? && text.length>0 + ss=text.gsub(/<\/?.*?>/, '').strip + ss = ss.gsub(/ */, '') + ss = ss.gsub(/\r\n/,'') #新增 + ss = ss.gsub(/\n/,'') #新增 + if len > 0 && ss.length > len + ss = ss[0, len] + endss + elsif len > 0 && ss.length <= len + ss = ss + #ss = truncate(ss, :length => len) + end + end + ss + end + + # Returns a string that can be used as filename value in Content-Disposition header + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE|Trident|Edge} ? ERB::Util.url_encode(name) : name + end + + def format_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M") + end + + # 获取Oauth Client + def get_client(site) + client_id = Rails.configuration.educoder['client_id'] + client_secret = Rails.configuration.educoder['client_secret'] + + OAuth2::Client.new(client_id, client_secret, site: site) + end + + def paginate(relation) + limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i + page = params[:page].to_i.zero? ? 1 : params[:page].to_i + offset = (page - 1) * limit + + if relation.is_a?(Array) + relation[offset, limit] + else + relation.limit(limit).offset(offset) + end + end + + def strf_time(time) + time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S") + end + + def logger_error(error) + Rails.logger.error(error.message) + error.backtrace.each { |msg| Rails.logger.error(msg) } + end + + private + def object_not_found + uid_logger("Missing template or cant't find record, responding with 404") + render json: {message: "您访问的页面不存在或已被删除", status: 404} + false + end + + def tip_show(exception) + uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") + render json: exception.tip_json + end + + def render_parameter_missing + render json: { status: -1, message: '参数缺失' } + end +end diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 112b3352a..649516a03 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -90,10 +90,10 @@ class MyshixunsController < ApplicationController # params[:pics] = "a.png,b.png,c.png" def training_task_status - logger.info("##################training_task_status_start#{jsonTestDetails['buildID']}") ActiveRecord::Base.transaction do begin t1 = Time.now + Rails.logger.info("@@@222222#{params[:jsonTestDetails]}") jsonTestDetails = JSON.parse(params[:jsonTestDetails]) timeCost = JSON.parse(params[:timeCost]) brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? @@ -130,8 +130,8 @@ class MyshixunsController < ApplicationController # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) logger.info "actual_output:################################################# #{actual_output}" - ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f - ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f + ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime'] + ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem'] Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'], :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index, @@ -210,10 +210,10 @@ class MyshixunsController < ApplicationController end uid_logger("training_task_status start#4**#{game_id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") sucess_status - rescue Exception => e - tip_exception(e.message) - uid_logger_error("training_task_status error: #{e}") - raise ActiveRecord::Rollback + # rescue Exception => e + # tip_exception(e.message) + # uid_logger_error("training_task_status error: #{e}") + # raise ActiveRecord::Rollback end end end diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css index 216e11266..ed44e1f90 100644 --- a/public/react/public/css/edu-all.css +++ b/public/react/public/css/edu-all.css @@ -171,7 +171,9 @@ em.vertical-line{display: inline-block;width: 2px;background: #999;height: 10px} #log_reg_content{border-radius: 5px;background: #FFFFff;width: 100%;text-align: center;position: absolute;top: 165px; left: 0px;padding: 40px 30px;box-sizing: border-box} .log_nav{border-bottom:1px solid #eaeaea;} -.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px;margin: 0px 20px;cursor: pointer;} +.log_nav li{float: left;text-align: center;font-size: 16px;padding-bottom:15px; + /*margin: 0px 20px;*/ + cursor: pointer;} .log_nav li.active{border-bottom: 2px solid #459be5;} .log-botton{width: 100%;text-align: center;color: #FFFFff!important;display: block;background: #cbcbcb;height: 45px;line-height: 45px;border-radius: 4px;letter-spacing: 2px;cursor: pointer} .log-botton:hover{color: #FFFFff!important;} diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 02d8c2be5..ddef777d6 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -2,7 +2,7 @@ import React from "react"; import axios from 'axios'; import { requestProxy } from "./indexEduplus2RequestProxy"; -import { broadcastChannelOnmessage ,SetAppModel} from 'educoder'; +import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString } from 'educoder'; import { notification } from 'antd'; import './index.css' broadcastChannelOnmessage('refreshPage', () => { @@ -18,10 +18,18 @@ function locationurl(list){ } // TODO 开发期多个身份切换 -const debugType ="" -// window.location.search.indexOf('debug=t') != -1 ? 'teacher' : -// window.location.search.indexOf('debug=s') != -1 ? 'student' : 'admin' -// window._debugType = debugType; +let debugType ="" +if (isDev) { + const _search = window.location.search; + let parsed = {}; + if (_search) { + parsed = queryString.parse(_search); + } + debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' : + window.location.search.indexOf('debug=s') != -1 ? 'student' : + window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || '' +} +window._debugType = debugType; export function initAxiosInterceptors(props) { // TODO 避免重复的请求 https://github.com/axios/axios#cancellation diff --git a/public/react/src/modules/courses/coursesPublic/PathModal.js b/public/react/src/modules/courses/coursesPublic/PathModal.js index 10a298c90..43901c87a 100644 --- a/public/react/src/modules/courses/coursesPublic/PathModal.js +++ b/public/react/src/modules/courses/coursesPublic/PathModal.js @@ -91,7 +91,7 @@ class PathModal extends Component{ this.setState({ type:types, page:1, - newshixunmodallist:[] + newshixunmodallist:undefined }) this.funshixunpathlist(Searchvalue,types,true,1) } @@ -105,7 +105,7 @@ class PathModal extends Component{ SenttotheSearch=(value)=>{ this.setState({ page:1, - newshixunmodallist:[] + newshixunmodallist:undefined }) let{type}=this.state; this.funshixunpathlist(value,type,true,1) @@ -267,12 +267,19 @@ class PathModal extends Component{ margin-top:0px !important; height: 40px; } + `} - { newshixunmodallist&&newshixunmodallist.length===0?"":
:newshixunmodallist&&newshixunmodallist.length===0?暂时还没有相关数据哦!
+
+
- 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到
- 版本库
- 学员任务文件 该文件将直接显示给学生,需要学生在其中填写代码
+ 请先上传本关任务的所有代码文件、标准图片等所有必要的文件到
+ 版本库
+ 学员任务文件 该文件将直接显示给学生,需要学生在其中填写代码 评测执行文件 该文件由平台执行,用来测试平台学员代码是否正确 评测执行文件 该文件由平台执行,用来测试平台学员代码是否正确 效果展现方式
- 图片:处理或输出图片类型的任务,请选填此项 该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型 待处理图片路径
- 该路径下的文件将在学员评测本关任务时,作为原始图片显示在查看效果页,供学员参考,任务为图片处理时请指定该路径,并注意与程序文件所在文件夹分开
- 标准答案图片路径
- 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开
- 学员答案文件路径
- 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开
- 测试集 测试集和系统评分规则
- 得分规范:
-
+ className="fa fa-exclamation-circle mr3">必填项
+ 效果展现方式
+ 图片:处理或输出图片类型的任务,请选填此项 该选项用来配置学员评测本关任务时,查看效果页上需要展现的文件类型 待处理图片路径
+ 该路径下的文件将在学员评测本关任务时,作为原始图片显示在查看效果页,供学员参考,任务为图片处理时请指定该路径,并注意与程序文件所在文件夹分开
+ 标准答案图片路径
+ 该路径下的文件将在学员评测本关任务时,作为参考答案显示在查看效果页,供学员参考任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开
+ 学员答案文件路径
+ 学员评测本关任务时生成的文件将保存在该路径下,并作为实际输出显示在查看效果页,供学员确认任务输出结果为文件时请指定该路径,并注意与程序文件所在文件夹分开
+ 测试集 测试集和系统评分规则
+ 得分规范:
+
系统评分占比:
- *
- 组{key+1}
-
+ {evaluationlist===undefined?"":evaluationlist.length===0?"":evaluationlist.map((item,key)=>{
+ return(
+
+ *
+ 组{key+1}
+
{/*checked={item.is_public===1?false:true}*/}
- this.editpercentage(e,key)}
- value={item.score} />
+ this.editpercentage(e,key)}
+ value={item.score} />
%
+ style={{display:scorevalue===true?'inline-block':'none'}}
+ >%
-
- 新增测试集
-
- 温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测
+
+ 新增测试集
+
+ 温馨提示:建议公开测试集和隐藏测试集结合使用,降低作弊的几率;隐藏测试集,在“提交评测”时也将被自动检测 选择你可能感兴趣的内容
- {/*文件导航*/}
- {
- main.length===0?"":main.map((item,key)=>{
- return(
- this.goblakepath(item.path,key)}>{item.val}
- )
- })
- }
- {/*文件*/}
- {trees === undefined || trees === null ? "" : trees.map((item, key) => {
- return(
-
-
+ {/*文件导航*/}
+ {
+ main.length===0?"":main.map((item,key)=>{
+ return(
+ this.goblakepath(item.path,key)}>{item.val}
+ )
+ })
+ }
+ {/*文件*/}
+ {trees === undefined || trees === null ? "" : trees.map((item, key) => {
+ return(
+
+
- 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果
- apk/exe:写可执行文件的任务,请选填此项
- 可以通过设置学员答案文件路径,展示二维码以供扫码下载
- txt:输出txt文档类型的任务,请选填此项
- 可以通过学员答案文件路径设置,展示txt文件内容
- html:web类型的任务,请选填此项
- 可以通过Web路由设置,展示html效果预览页
-
+ 可以通过设置图片路径和学员答案文件路径,展示代码对应的图片效果
+ apk/exe:写可执行文件的任务,请选填此项
+ 可以通过设置学员答案文件路径,展示二维码以供扫码下载
+ txt:输出txt文档类型的任务,请选填此项
+ 可以通过学员答案文件路径设置,展示txt文件内容
+ html:web类型的任务,请选填此项
+ 可以通过Web路由设置,展示html效果预览页
+