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

dev_forum
jingquan huang 6 years ago
commit 493e07e455

@ -148,6 +148,10 @@ class ApplicationController < ActionController::Base
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,6 +6,6 @@ class Competitions::BaseController < ApplicationController
helper_method :current_competition
def current_competition
@_current_competition ||= Competition.find_by!(identifier: params[:competition_id].presence || params[:id])
@_current_competition ||= Competition.find_by!(identifier: params[:competition_id])
end
end

@ -0,0 +1,28 @@
class Competitions::CompetitionModulesController < Competitions::BaseController
skip_before_action :require_login, only: [:index, :show]
before_action :require_business, only: [:update]
def index
@modules = current_competition.unhidden_competition_modules.order(position: :asc)
end
def show
@module = current_module
end
def update
md = current_module.competition_module_md_content || current_module.build_competition_module_md_content
md.name = params[:md_name]
md.content = params[:md_content]
md.save!
render_ok
end
private
def current_module
@_current_module ||= current_competition.unhidden_competition_modules.find(params[:id])
end
end

@ -0,0 +1,70 @@
class Competitions::CompetitionTeamsController < Competitions::BaseController
def index
admin_or_business? ? all_competition_teams : user_competition_teams
end
def create
if current_competition.personal? # 个人赛报名
Competitions::CreatePersonalTeamService.call(current_competition, current_user)
else
team = current_competition.competition_teams.new(user: current_user)
Competitions::SaveTeamService.call(team, save_params)
end
render_ok
rescue Competitions::CreatePersonalTeamService::Error => ex
render_error(ex.message)
end
def update
team = current_competition.competition_teams.where(user: current_user).find(params[:id])
Competitions::SaveTeamService.call(team, save_params)
render_ok
end
def join
Competitions::JoinTeamService.call(current_competition, current_user, params)
render_ok
rescue Competitions::JoinTeamService::Error => ex
render_error(ex.message)
end
def leave
team = current_competition.competition_teams.find(params[:id])
member = team.team_members.find_by(user_id: current_user.id)
return render_error('您不是该战队的成员') if member.blank?
if member.user_id == team.user_id
team.destroy! # 队长退出,战队解散
else
member.destroy!
end
render_ok
end
private
def all_competition_teams
teams = current_competition.competition_teams
keyword = params[:keyword].to_s.strip
if keyword.present?
teams = teams.joins(users: { user_extension: :school }).where('schools.name LIKE ?', "%#{keyword}%")
end
@count = teams.count
@teams = paginate(teams.includes(:user, users: :user_extension))
end
def user_competition_teams
teams = current_competition.competition_teams
teams = teams.joins(:team_members).where(team_members: { user_id: current_user.id })
@teams = teams.includes(:user, users: :user_extension).to_a
@count = @teams.size
end
def save_params
params.permit(:name, teacher_ids: [], member_ids: [])
end
end

@ -29,4 +29,10 @@ class Competitions::CompetitionsController < Competitions::BaseController
return
end
end
private
def current_competition
@_current_competition ||= Competition.find_by!(identifier: params[:id])
end
end

@ -0,0 +1,22 @@
class Competitions::StudentsController < Competitions::BaseController
def index
keyword = params[:keyword].to_s.strip
if keyword.blank?
@students = []
return
end
students = User.joins(:user_extension).where(status: 1, user_extensions: { identity: 1 })
students = students.where.not(id: params[:student_ids]) if params[:student_ids].present?
students = students.where('LOWER(CONCAT(lastname, firstname, login, nickname)) LIKE ?', "%#{keyword}%")
@students = students.includes(user_extension: :school).limit(20)
# 队员多次报名限制
if current_competition.member_multiple_limited?
ids = @students.map(&:id)
members = current_competition.team_members.where(user_id: ids)
members = members.where.not(competition_team_id: params[:team_id]) if params[:team_id].present?
@enrolled_map = members.group(:user_id).count
end
end
end

@ -0,0 +1,22 @@
class Competitions::TeachersController < Competitions::BaseController
def index
keyword = params[:keyword].to_s.strip
if keyword.blank?
@teachers = []
return
end
teachers = User.joins(:user_extension).where(status: 1, user_extensions: { identity: 0 })
teachers = teachers.where.not(id: params[:teacher_ids]) if params[:teacher_ids].present?
teachers = teachers.where('LOWER(CONCAT(lastname, firstname, login, nickname)) LIKE ?', "%#{keyword}%")
@teachers = teachers.includes(user_extension: :school).limit(10)
# 老师多次报名限制
if current_competition.teacher_multiple_limited?
ids = @teachers.map(&:id)
members = current_competition.team_members.where(user_id: ids)
members = members.where.not(competition_team_id: params[:team_id]) if params[:team_id].present?
@enrolled_map = members.group(:user_id).count
end
end
end

@ -1373,7 +1373,6 @@ class CoursesController < ApplicationController
count_2 = common_homeworks.size
count_3 = group_homeworks.size
count_4 = tasks.size
count_5 = exercises.size
#实训作业
shixun_homeworks.each_with_index do |s,index|
all_student_works = s.score_student_works #该实训题的全部用户回答

@ -511,7 +511,6 @@ class ExercisesController < ApplicationController
else
exercise_end_time = t[:end_time].to_time
end
# exercise_end_time = t[:end_time].present? ? t[:end_time].to_time : nil
exercise_group = exercise_groups.find_in_exercise_group("course_group_id",course_id) #判断该分班是否存在
if exercise_group.present? && (exercise_group.first.publish_time < Time.now) && (exercise_publish_time != exercise_group.first.publish_time)
error_count += 1

@ -36,7 +36,7 @@ class MyshixunsController < ApplicationController
StudentWork.where(:myshixun_id => @myshixun.id).update_all(:myshixun_id => 0, :work_status => 0)
# 实训在申请发布前,是否玩过实训,如果玩过需要更改记录,防止二次重置
shixun_mod = ShixunModify.exists?(:shixun_id => @shixun.id, :myshixun_id => @myshixun.id, :status => 1)
shixun_mod = ShixunModify.where(:shixun_id => @shixun.id, :myshixun_id => @myshixun.id, :status => 1).take
shixun_mod.update_column(:status, 0) if shixun_mod
rescue Exception => e
uid_logger_error("myshixun reset failed #{e}")

@ -813,7 +813,7 @@ private
# 实训是否需要重置
def is_shixun_reset?(games, min_challenges, current_myshixun)
# 用户在申请发布之前,是否玩过实训
# 用户在申请发布之前,是否玩过实训 TODO: 重置的字段应该迁移到myshixuns表比较合适
modify_shixun = ShixunModify.exists?(:myshixun_id => current_myshixun.id, :shixun_id => @shixun.id, :status => 1)
games.size != min_challenges.size ||
games.map(&:challenge_id) != min_challenges.map{|challenge| challenge.first} ||

@ -0,0 +1,98 @@
class Competitions::SaveTeamForm
include ActiveModel::Model
attr_accessor :competition, :team, :creator
attr_accessor :name, :teacher_ids, :member_ids
validates :name, presence: true
validate :check_creator_enrollable
def check_creator_enrollable
return unless check_creator_identity_enrollable
check_creator_multiple_enrollable
end
validate :check_teachers_enrollable
def check_teachers_enrollable
if competition.teacher_enroll_forbidden? && teacher_ids.present?
errors.add(:teacher_ids, :enroll_forbidden)
return
end
self.teacher_ids = teacher_ids.map(&:to_i)
all_teachers = creator.is_teacher? ? teacher_ids + [creator.id] : teacher_ids
all_teachers.uniq!
if all_teachers.size < competition.teacher_staff.minimum || all_teachers.size > competition.teacher_staff.maximum
errors.add(:teacher_ids, :invalid_count, minimum: competition.teacher_staff.minimum, maximum: competition.teacher_staff.maximum)
return
end
# 老师可多次报名,不检查
return unless competition.teacher_multiple_limited?
# 存在已报名老师
enrolled_teacher_members = competition.team_members.where(user_id: all_teachers)
.where.not(competition_team_id: team.id).includes(:user)
if enrolled_teacher_members.present?
errors.add(:teacher_ids, :enrolled, names: enrolled_teacher_members.map { |m| m.user.real_name }.join(''))
return
end
end
validate :check_members_enrollable
def check_members_enrollable
if competition.member_enroll_forbidden? && member_ids.present?
errors.add(:member_ids, :enroll_forbidden)
return
end
self.member_ids = member_ids.map(&:to_i)
all_members = creator.is_teacher? ? member_ids : member_ids + [creator.id]
all_members.uniq!
if all_members.size < competition.member_staff.minimum || all_members.size > competition.member_staff.maximum
errors.add(:member_ids, :invalid_count, minimum: competition.member_staff.minimum, maximum: competition.member_staff.maximum)
return
end
# 成员可多次报名,不检查
return unless competition.member_multiple_limited?
# 存在已报名成员
enrolled_members = competition.team_members.where(user_id: all_members)
.where.not(competition_team_id: team.id).includes(:user)
if enrolled_members.present?
errors.add(:member_ids, :enrolled, names: enrolled_members.map { |m| m.user.real_name }.join(''))
return
end
end
private
# 竞赛是否限制了职业
def check_creator_identity_enrollable
if user.is_teacher? && competition.teacher_enroll_forbidden?
errors.add(:creator, :teacher_enroll_forbidden)
return false
elsif !user.is_teacher? && competition.member_enroll_forbidden?
errors.add(:creator, :member_enroll_forbidden)
return false
end
true
end
# 创建者是否能多次报名
def check_creator_multiple_enrollable
return unless competition.enrolled?(user)
if (user.is_teacher? && competition.teacher_multiple_limited?) || (!user.is_teacher? && competition.member_multiple_limited?)
errors.add(:creator, :enrolled)
return false
end
true
end
end

@ -1,10 +1,15 @@
class Competition < ApplicationRecord
has_many :competition_modules, dependent: :destroy
has_many :unhidden_competition_modules, -> { where(hidden: false) }, class_name: 'CompetitionModule'
has_many :competition_stages, dependent: :destroy
has_many :competition_stage_sections, dependent: :destroy
has_one :current_stage_section, -> { where('end_time > NOW()') }, class_name: 'CompetitionStageSection'
has_many :competition_teams, dependent: :destroy
has_many :team_members, dependent: :destroy
has_many :competition_staffs, dependent: :destroy
has_one :teacher_staff, -> { where(category: :teacher) }, class_name: 'CompetitionStaff'
has_one :member_staff, -> { where.not(category: :teacher) }, class_name: 'CompetitionStaff'
@ -18,6 +23,11 @@ class Competition < ApplicationRecord
status?
end
# 是否为个人赛
def personal?
competition_staffs.maximum(:maximum) == 1
end
# 报名是否结束
def enroll_ended?
enroll_end_time.blank? || enroll_end_time < Time.now
@ -28,6 +38,26 @@ class Competition < ApplicationRecord
team_members.exists?(user_id: user.id)
end
# 是否禁止教师报名
def teacher_enroll_forbidden?
teacher_staff.blank? || teacher_staff.maximum.zero?
end
# 是否禁止学生报名
def member_enroll_forbidden?
member_staff.blank? || member_staff.maximum.zero?
end
# 老师是否能多次报名
def teacher_multiple_limited?
teacher_staff.mutiple_limited?
end
# 队员是否能多次报名
def member_multiple_limited?
member_staff.mutiple_limited?
end
private
def create_competition_modules

@ -2,4 +2,7 @@ class CompetitionModuleMdContent < ApplicationRecord
belongs_to :competition_module
has_many :attachments, as: :container, dependent: :destroy
validates :name, presence: true
validates :content, presence: true
end

@ -1,8 +1,33 @@
class CompetitionTeam < ApplicationRecord
CODE_CHARS = %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).freeze
belongs_to :user
belongs_to :competition
has_many :team_members, dependent: :destroy
has_many :users, through: :team_members, source: :user
has_many :members, -> { without_teachers }, class_name: 'TeamMember'
has_many :teachers, -> { only_teachers }, class_name: 'TeamMember'
def group_team_type?
team_type.zero?
end
def personal_team_type?
team_type == 1
end
def en_team_type
group_team_type? ? 'group' : 'personal'
end
def generate_invite_code
code = CODE_CHARS.sample(6).join
while self.class.exists?(invite_code: code)
code = CODE_CHARS.sample(6).join
end
self.code = code
code
end
end

@ -74,15 +74,15 @@ class Exercise < ApplicationRecord
# 根据是否统一发布获取作业的作品列表
def all_works
ex_users = unified_setting ? exercise_users :
ex_users = self.unified_setting ? exercise_users :
exercise_users.joins("join course_members on exercise_users.user_id=course_members.user_id").
where(course_members: {course_group_id: published_settings.pluck(:course_group_id)})
end
# 分班权限的老师可见的作品列表
def all_exercise_users user_id
def all_exercise_users(user_id)
# member = course.course_member(user_id)
teacher_course_groups = course.teacher_course_groups.get_user_groups(user_id)
teacher_course_groups = course.teacher_course_groups.where(user_id:user_id)
ex_users = self.all_works
# 有分班权限的统计管理的分班且已发布的学生情况
if teacher_course_groups.exists?
@ -154,11 +154,11 @@ class Exercise < ApplicationRecord
update_column("exercise_status",3)
end
else
ex_group_setting = exercise_group_settings
# ex_group_setting = exercise_group_settings
user_group = course.students.where(user_id:user_id).select(:course_group_id)
if user_group.exists?
user_group_id = user_group.first&.course_group_id
user_ex_group_setting = ex_group_setting.where(course_group_id:user_group_id).select(:publish_time,:end_time)
user_ex_group_setting = exercise_group_settings.where(course_group_id:user_group_id).select(:publish_time,:end_time)
pb_time = user_ex_group_setting.first&.publish_time
en_time = user_ex_group_setting.first&.end_time
else

@ -61,7 +61,7 @@ class Game < ApplicationRecord
if self.status == 2 # 通关了则取实际得分,没通关则取总分
gold = (shixun_status <= 1) ? 0 : self.final_score.to_i
# 只要过关了查看了答案经验值就是0通关前查看了答案金final_score为负数
experience = (shixun_status <= 1 || self.final_score.to_i < 0) ? 0 : challenge.score.to_i
experience = (shixun_status <= 1 || self.final_score.to_i < 0) ? 0 : challenge.final_score.to_i
else
gold = challenge.score.to_i
experience = gold

@ -5,4 +5,12 @@ class TeamMember < ApplicationRecord
scope :only_teachers, -> { where(is_teacher: true) }
scope :without_teachers, -> { where(is_teacher: false) }
def creator?
role == 1
end
def en_role
is_teacher? ? 'teacher' : 'member'
end
end

@ -0,0 +1,27 @@
class Competitions::CreatePersonalTeamService < ApplicationService
Error = Class.new(StandardError)
attr_reader :competition, :user
def initialize(competition, user)
@competition = competition
@user = user
end
def call
raise Error, '个人赛才能报名' unless competition.personal?
is_teacher = user.is_teacher?
raise Error, '本竞赛的参赛者限定为:学生' if is_teacher && competition.teacher_enroll_forbidden?
raise Error, '本竞赛的参赛者限定为:教师' if !is_teacher && competition.member_enroll_forbidden?
enrolled = competition.competition_teams.exists?(user_id: user.id)
multiple_limited = (is_teacher && competition.teacher_multiple_limited?) || (!is_teacher && competition.member_multiple_limited?)
raise Error, '您已报名该竞赛' if enrolled && multiple_limited
ActiveRecord::Base.transaction do
team = competition.competition_teams.create!(name: user.show_name, user_id: user.id)
team.team_members.create!(competition_id: competition, user_id: user.id, role: 1, is_teacher: is_teacher)
end
end
end

@ -0,0 +1,35 @@
class Competitions::JoinTeamService < ApplicationService
Error = Class.new(StandardError)
attr_reader :competition, :user, :params
def initialize(competition, user, params)
@competition = competition
@user = user
@params = params
end
def call
invite_code = params[:invite_code].to_s.strip
raise Error, '战队邀请码不能为空' if invite_code.blank?
is_teacher = user.is_teacher?
raise Error, '本竞赛的参赛者限定为:学生' if is_teacher && competition.teacher_enroll_forbidden?
raise Error, '本竞赛的参赛者限定为:教师' if !is_teacher && competition.member_enroll_forbidden?
team = competition.competition_teams.find_by(invite_code: invite_code)
raise Error, '战队邀请码无效' if team.blank?
raise Error, '您已加入该战队' if team.team_members.exists?(user_id: user.id)
enrolled = competition.team_members.exists?(user_id: user.id)
if enrolled && (is_teacher && competition.teacher_multiple_limited?) || (!is_teacher && competition.member_multiple_limited?)
raise Error, '您已加入其它战队'
end
raise Error, '该战队教师人数已满' if is_teacher && team.teachers.count == competition.teacher_staff.maximum
raise Error, '该战队队员人数已满' if !is_teacher && team.members.count == competition.member_staff.maximum
role = is_teacher ? 3 : 2
team.team_members.create!(competition_id: competition.id, user_id: user, role: role, is_teacher: is_teacher)
end
end

@ -0,0 +1,71 @@
class Competitions::SaveTeamService < ApplicationService
attr_reader :competition, :team, :creator, :params
TEAM_MEMBER_ATTRIBUTES = %i[competition_id competition_team_id user_id role is_teacher created_at updated_at]
def initialize(team, params)
@team = team
@competition = team.competition
@creator = team.user
@params = params
end
def call
Competitions::SaveTeamForm.new(form_params).validate!
new_record = team.new_record?
is_teacher = team.user.is_teacher?
ActiveRecord::Base.transaction do
team.generate_invite_code if new_record
team.team_type = 1 # 组队竞赛
team.name = params[:name].to_s.strip
team.save!
# 创建者
team.team_members.create!(user_id: creator.id, competition_id: competition.id, role: 1, is_teacher: is_teacher) if new_record
update_teacher_team_members!
update_member_team_members!
end
end
private
def update_teacher_team_members!
teacher_ids = Array.wrap(params[:teacher_ids]).map(:to_i)
old_teacher_ids = team.team_members.where(role: 3).pluck(:user_id)
destroy_teacher_ids = old_teacher_ids - teacher_ids
team.team_members.where(role: 3).where(user_id: destroy_teacher_ids).delete_all
new_teacher_ids = teacher_ids - old_teacher_ids
TeamMember.bulk_insert(*TEAM_MEMBER_ATTRIBUTES) do |worker|
base_attr = { competition_id: competition.id, competition_team_id: team.id, role: 3, is_teacher: true }
new_teacher_ids.each do |teacher_id|
next if teacher_id == creator.id
worker.add(base_attr.merge(user_id: teacher_id))
end
end
end
def update_member_team_members!
member_ids = Array.wrap(params[:member_ids]).map(:to_i)
old_member_ids = team.team_members.where(role: 2).pluck(:user_id)
destroy_member_ids = old_member_ids - member_ids
team.team_members.where(role: 2).where(user_id: destroy_member_ids).delete_all
new_member_ids = member_ids - old_member_ids
TeamMember.bulk_insert(*TEAM_MEMBER_ATTRIBUTES) do |worker|
base_attr = { competition_id: competition.id, competition_team_id: team.id, role: 2, is_teacher: false }
new_member_ids.each do |member_id|
next if member_id == creator.id
worker.add(base_attr.merge(user_id: member_id))
end
end
end
def form_params
params.merge(competition: competition, team: team, creator: creator)
end
end

@ -0,0 +1,7 @@
json.modules do
json.array! @modules.each do |m|
json.extract! m, :id, :name, :position, :url
end
end
json.count @modules.size

@ -0,0 +1,8 @@
json.extract! @module, :id, :name, :position, :url, :md_edit
md = @module.competition_module_md_content
if md.present?
json.md_name md.name
json.md_content md.content
json.created_at md.created_at.strftime('%Y-%m-%d %H:%M:%S')
end

@ -0,0 +1,23 @@
json.count @count
json.competition_teams do
json.array! @teams.each do |team|
json.extract! team, :id, :name, :invite_code
json.team_type team.en_team_type
json.school_name team.user.school_name
json.manage_permission current_user.id == team.user_id
json.creator do
json.partial! 'users/user_simple', user: team.user
json.role team.team_members.find(&:creator?).en_role
end
json.team_members do
json.array! team.team_members.each do |member|
json.partial! 'users/user_simple', user: member.user
json.user_id member.user_id
json.role member.en_role
end
end
end
end

@ -0,0 +1,9 @@
json.teachers do
json.array! @students.each do |student|
json.id student.id
json.name student.full_name
json.student_id student.student_id
json.school_name student.school_name
json.enrollable !current_competition.member_multiple_limited? || !@enrolled_map.key?(student.id)
end
end

@ -0,0 +1,9 @@
json.teachers do
json.array! @teachers.each do |teacher|
json.id teacher.id
json.name teacher.full_name
json.identity teacher.identity
json.school_name teacher.school_name
json.enrollable !current_competition.teacher_multiple_limited? || !@enrolled_map.key?(teacher.id)
end
end

@ -0,0 +1,8 @@
'zh-CN':
activerecord:
models:
competition_module_md_content: ''
attributes:
competition_module_md_content:
name: '标题'
content: '内容'

@ -0,0 +1,25 @@
'zh-CN':
activemodel:
attributes:
competitions/save_team_form:
competition: ''
name: '战队名称'
creator: ''
teacher_ids: ''
member_ids: ''
errors:
models:
competitions/save_team_form:
attributes:
creator:
teacher_enroll_forbidden: "本竞赛的参赛者限定为:学生"
member_enroll_forbidden: "本竞赛的参赛者限定为:教师"
teacher_ids:
enroll_forbidden: "本竞赛的参赛者限定为:学生"
invalid_count: "教师数量应为%{minimum}~%{maximum}人"
enrolled: "教师 ${names} 已加入其它战队了"
member_ids:
enroll_forbidden: "本竞赛的参赛者限定为:教师"
invalid_count: "队员数量应为%{minimum}~%{maximum}人"
enrolled: "队员 ${names} 已加入其它战队了"

@ -672,9 +672,14 @@ Rails.application.routes.draw do
scope module: :competitions do
resources :competitions, only: [:index, :show] do
resources :competition_modules, only: [:index, :show]
resources :competition_modules, only: [:index, :show, :update]
resource :competition_staff
resources :competition_teams, only: [:index, :show]
resources :competition_teams, only: [:index, :show] do
post :join, on: :collection
post :leave, on: :member
end
resources :teachers, only: [:index]
resources :students, only: [:index]
end
end
end

Loading…
Cancel
Save