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

dev_forum
杨树林 5 years ago
commit 6903658524

@ -8,7 +8,7 @@ class CourseSecondCategoriesController < ApplicationController
tip_exception("毕设子目录不能重命名") if @category.category_type == "graduation"
tip_exception("名称不能为空") if params[:name].blank?
tip_exception("已存在同名子目录") if @course_module.course_second_categories.exists?(name: params[:name].strip)
@category.update_attributes(name: params[:name].strip)
@category.update_attributes!(name: params[:name].strip)
normal_status(0, "更新成功")
end

@ -906,7 +906,6 @@ class CoursesController < ApplicationController
CourseAddStudentCreateWorksJob.perform_later(course.id, [current_user.id])
StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id)
logger.info("#####################{course.id}")
end
end
@ -927,14 +926,18 @@ class CoursesController < ApplicationController
role = course_message.content == 2 ? '7' : '9' # 7:老师 9:助教
ApplyTeacherRoleJoinCourseNotifyJob.perform_later(current_user.id, course.id, role)
teacher_role = 1
message = "#{course_message.content == 2 ? '教师' : '助教'}申请已提交,请等待审核"
end
end
end
if current_user.student_of_course?(course) || current_user.teacher_of_course?(course)
render json: { status: 0, message: "成功", course_id: course.id}
if teacher_role && current_user.student_of_course?(course)
render json: { status: 0, message: message, course_id: course.id}
elsif current_user.student_of_course?(course)
render json: { status: 0, message: "加入成功", course_id: course.id}
else
normal_status("申请已提交,请等待审核")
normal_status(message)
end
rescue => e
uid_logger(e.message)

@ -513,6 +513,111 @@ class ShixunsController < ApplicationController
# 以前在开启挑战的时候检测实训是否更新更新则重置觉得应该放在TPI更好
# 中间需要一个过渡动画
# TODO: 第一次开启实训都会去判断是否是纯选择题类型,感觉做成在创建关卡的时候就判断该实训是否是纯选择题更加合适
# def shixun_exec
# if is_shixun_opening?
# tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
# end
# current_myshixun = @shixun.current_myshixun(current_user.id)
#
# min_challenges = @shixun.challenges.pluck(:id , :st)
#
# Rails.logger.info("11111111112#{current_myshixun.try(:id)}")
# Rails.logger.info("111111111102#{params[:reset] != 1}")
#
# # 因为读写分离有延迟所以如果是重置来的请求可以先跳过重置过来的params[:reset]为1
# if current_myshixun && params[:reset] != "1"
# games = current_myshixun.games
# # 如果TPM和TPI的管卡数不相等或者关卡顺序错了说明实训被极大的改动需要重置,实训发布前打过的实训都需要重置
# if is_shixun_reset?(games, min_challenges, current_myshixun)
# # 这里页面弹框要收到 当前用户myshixun的identifier.
# tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game")
# end
#
#
# if current_myshixun.repo_name.nil?
# g = Gitlab.client
# repo_name = g.project(current_myshixun.gpid).try(:path_with_namespace)
# current_myshixun.update_column(:repo_name, repo_name)
# end
#
#
# # 如果存在实训,则直接进入实训
# # 如果实训允许跳关传参params[:challenge_id]跳入具体的关卡
# @current_task =
# if params[:challenge_id]
# game = games.where(challenge_id: params[:challenge_id]).take
# if @shixun.task_pass || game.status != 3
# game
# else
# current_myshixun.current_task(games)
# end
# else
# current_myshixun.current_task(games)
# end
# else
# # 如果未创建关卡一定不能开启实训否则TPI没法找到当前的关卡
# if @shixun.challenges_count == 0
# tip_exception("开启实战前请先创建实训关卡")
# end
#
# # 判断实训是否全为选择题
# is_choice_type = (min_challenges.size == min_challenges.select{|challenge| challenge.last == 1}.count)
# if !is_choice_type
# commit = GitService.commits(repo_path: @repo_path).try(:first)
# uid_logger("First comit########{commit}")
# tip_exception("开启实战前请先在版本库中提交代码") if commit.blank?
# commit_id = commit["id"]
# end
#
# ActiveRecord::Base.transaction do
# begin
# cloud_bridge = edu_setting('cloud_bridge')
# myshixun_identifier = generate_identifier Myshixun, 10
# myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
# modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
# onclick_time: Time.now, commit_id: commit_id)
# uid_logger("myshixun_id is #{myshixun.id}")
#
#
# # 其它创建关卡等操作
# challenges = @shixun.challenges
# # 之所以增加user_id是为了方便统计查询性能
# game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at]
# Game.bulk_insert(*game_attrs) do |worker|
# base_attr = { myshixun_id: myshixun.id, user_id: myshixun.user_id }
# challenges.each_with_index do |challenge, index|
# status = (index == 0 ? 0 : 3)
# game_identifier = generate_identifier(Game, 12)
# worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now,
# identifier: game_identifier, modify_time: challenge.modify_time))
# end
# end
#
# # 如果实训是纯选择题则不需要去fork仓库以及中间层的相关操作了
# unless is_choice_type
# # fork仓库
# project_fork(myshixun, @repo_path, current_user.login)
#
# rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path )
# uid_logger("start openGameInstance")
# uri = "#{cloud_bridge}/bridge/game/openGameInstance"
# logger.info("end openGameInstance")
# params = {tpiID: "#{myshixun.id}", tpmGitURL:rep_url, tpiRepoName: myshixun.repo_name.split("/").last}
# uid_logger("openGameInstance params is #{params}")
# interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
# end
#
# @current_task = myshixun.current_task(myshixun.games)
# uid_logger("## shixun exec: myshixun id is #{myshixun.id}")
# rescue Exception => e
# uid_logger_error(e.message)
# tip_exception("实训云平台繁忙繁忙等级81")
# raise ActiveRecord::Rollback
# end
# end
# end
# end
def shixun_exec
if is_shixun_opening?
tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
@ -520,10 +625,6 @@ class ShixunsController < ApplicationController
current_myshixun = @shixun.current_myshixun(current_user.id)
min_challenges = @shixun.challenges.pluck(:id , :st)
Rails.logger.info("11111111112#{current_myshixun.try(:id)}")
Rails.logger.info("111111111102#{params[:reset] != 1}")
# 因为读写分离有延迟所以如果是重置来的请求可以先跳过重置过来的params[:reset]为1
if current_myshixun && params[:reset] != "1"
games = current_myshixun.games
@ -540,7 +641,6 @@ class ShixunsController < ApplicationController
current_myshixun.update_column(:repo_name, repo_name)
end
# 如果存在实训,则直接进入实训
# 如果实训允许跳关传参params[:challenge_id]跳入具体的关卡
@current_task =
@ -569,51 +669,54 @@ class ShixunsController < ApplicationController
commit_id = commit["id"]
end
ActiveRecord::Base.transaction do
begin
cloud_bridge = edu_setting('cloud_bridge')
myshixun_identifier = generate_identifier Myshixun, 10
myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id)
uid_logger("myshixun_id is #{myshixun.id}")
# 其它创建关卡等操作
challenges = @shixun.challenges
# 之所以增加user_id是为了方便统计查询性能
game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at]
Game.bulk_insert(*game_attrs) do |worker|
base_attr = { myshixun_id: myshixun.id, user_id: myshixun.user_id }
challenges.each_with_index do |challenge, index|
status = (index == 0 ? 0 : 3)
game_identifier = generate_identifier(Game, 12)
worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now,
identifier: game_identifier, modify_time: challenge.modify_time))
begin
ActiveRecord::Base.transaction do
begin
myshixun_identifier = generate_identifier Myshixun, 10
myshixun_params = {user_id: current_user.id, identifier: myshixun_identifier,
modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
onclick_time: Time.now, commit_id: commit_id}
@myshixun = @shixun.myshixuns.create!(myshixun_params)
# 其它创建关卡等操作
challenges = @shixun.challenges
# 之所以增加user_id是为了方便统计查询性能
game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at]
Game.bulk_insert(*game_attrs) do |worker|
base_attr = {myshixun_id: @myshixun.id, user_id: @myshixun.user_id}
challenges.each_with_index do |challenge, index|
status = (index == 0 ? 0 : 3)
game_identifier = generate_identifier(Game, 12)
worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now,
identifier: game_identifier, modify_time: challenge.modify_time))
end
end
@current_task = @myshixun.current_task(@myshixun.games)
rescue Exception => e
logger.error("------ActiveRecord::RecordInvalid: #{e.message}")
raise("ActiveRecord::RecordInvalid")
end
# 如果实训是纯选择题则不需要去fork仓库以及中间层的相关操作了
end
# 如果实训是纯选择题则不需要去fork仓库以及中间层的相关操作了
ActiveRecord::Base.transaction do
unless is_choice_type
# fork仓库
project_fork(myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path )
cloud_bridge = edu_setting('cloud_bridge')
project_fork(@myshixun, @repo_path, current_user.login)
rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
uid_logger("start openGameInstance")
uri = "#{cloud_bridge}/bridge/game/openGameInstance"
logger.info("end openGameInstance")
params = {tpiID: "#{myshixun.id}", tpmGitURL:rep_url, tpiRepoName: myshixun.repo_name.split("/").last}
params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
uid_logger("openGameInstance params is #{params}")
interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
end
@current_task = myshixun.current_task(myshixun.games)
uid_logger("## shixun exec: myshixun id is #{myshixun.id}")
rescue Exception => e
uid_logger_error(e.message)
tip_exception("实训云平台繁忙繁忙等级81")
raise ActiveRecord::Rollback
end
rescue Exception => e
if e.message != "ActiveRecord::RecordInvalid"
logger.error("##########project_fork error #{e.message}")
@current_task.destroy!
end
raise ActiveRecord::Rollback
end
end
end

@ -39,7 +39,7 @@ class StagesController < ApplicationController
def update
ActiveRecord::Base.transaction do
begin
@stage.update_attributes(stage_params)
@stage.update_attributes!(stage_params)
@stage.stage_shixuns.destroy_all
unless params[:shixun_id].blank?
params[:shixun_id].each do |shixun_id|
@ -50,7 +50,7 @@ class StagesController < ApplicationController
@subject.update_attributes(updated_at: Time.now)
rescue Exception => e
uid_logger_error(e.message)
tip_exception("章节更新失败")
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end

@ -207,7 +207,7 @@ class SubjectsController < ApplicationController
end
rescue Exception => e
uid_logger(e.message)
tip_exception("发送失败")
tip_exception(e.message)
raise ActiveRecord::Rollback
end
end

@ -6,6 +6,6 @@ class Stage < ApplicationRecord
has_many :stage_shixuns, -> { order("stage_shixuns.position ASC") }, dependent: :destroy
has_many :shixuns, :through => :stage_shixuns
validates :name, length: { maximum: 30 }
validates :name, length: { maximum: 60 }
validates :description, length: { maximum: 300 }
end

@ -102,7 +102,7 @@ class Cropper extends Component {
setTimeout(() => {
const image = document.getElementById(this.props.imageId || '__image');
this.cropper = new window.Cropper(image, this.options);
}, 1000)
}, 1200)
}
renew = (image) => {

@ -194,7 +194,7 @@ class UseBank extends Component{
display: -webkit-flex;
}
.setImgW .edu-nodata-img{
width:218px !important;
width: 170px !important;
}
.bankwidth{
width:24% !important;

@ -408,7 +408,7 @@ class Coursesleftnav extends Component{
this.setState({
Navmodalname:id===2?"新建分班":"添加目录",
Navtitles:id===2?"分班名称":"目录名称",
Navplaceholder:id===2?"示例分班最佳4个字符":"示例第一阶段最佳4个字符",
Navplaceholder:"请输入名称最大限制60个字符",
Navmodalnametype:true,
Navmodaltypename:id,
setnavid:setnavid,
@ -419,7 +419,7 @@ class Coursesleftnav extends Component{
this.setState({
Navmodalname:id===5?"分班重命名":"目录重命名",
Navtitles:id===5?"分班名称":"目录名称",
Navplaceholder:id===5?"示例分班最佳4个字符":"示例第一阶段最佳4个字符",
Navplaceholder:"请输入名称最大限制60个字符",
Navmodalnametype:true,
Navmodaltypename:id,
setnavid:setnavid,

@ -34,7 +34,7 @@ class AddcoursesNav extends Component{
{this.props.addnametab===2?
<div>
<div className={"fl mt5"}>目录名称</div>
<Input placeholder="示例:第一阶段"
<Input placeholder="请输入名称最大限制60个字符"
className={"inputNav greyInput fl mb40"}
maxLength="60"
style={{width:'450px'}}

@ -44,7 +44,7 @@ class ModalsRename extends Component{
className={"Navmodal"}
>
<div className={"fl mt5"}>{this.props.Navname}名称</div>
<Input placeholder={"示例:第一阶段"}
<Input placeholder={"请输入名称最大限制60个字符"}
className={"inputNav greyInput fl"}
maxLength="60"
style={{width:'450px'}}

@ -301,7 +301,7 @@ class CoursesNew extends Component {
if(value!=""){
this.props.form.setFieldsValue({
classroom:value,
course:value
// course:value
});
this.Searchvalue(value)
}
@ -311,7 +311,7 @@ class CoursesNew extends Component {
handleChange=(value)=>{
this.props.form.setFieldsValue({
course:value,
// course:value,
classroom:value
})
};
@ -320,7 +320,7 @@ class CoursesNew extends Component {
if(value!="") {
this.props.form.setFieldsValue({
school: value,
// school: value,
fetching: true,
});
@ -331,7 +331,7 @@ class CoursesNew extends Component {
handleChangeschools=(value)=>{
this.props.form.setFieldsValue({
school: value,
// school: value,
fetching: true,
});
}
@ -347,9 +347,9 @@ class CoursesNew extends Component {
};
getschool=(value)=>{
this.props.form.setFieldsValue({
school: value
})
// this.props.form.setFieldsValue({
// school: value
// })
let url="/schools/school_list.json";
axios.get(url,{
params: {
@ -359,7 +359,7 @@ class CoursesNew extends Component {
if (result.data.status===0) {
this.setState({
searchlistscholl: result.data.school_names,
school: value
// school: value
})
}
@ -367,9 +367,9 @@ class CoursesNew extends Component {
console.log(error)
})
}
showApplyForAddOrgModal = () => {
this.applyForAddOrgForm.setVisible(true)
}
showApplyForAddOrgModal = () => {
this.applyForAddOrgForm.setVisible(true)
}
render() {
let {datatime,school,searchlistscholl} = this.state;
const {getFieldDecorator} = this.props.form;

@ -36,13 +36,19 @@ class Index extends Component{
<div>
<Switch {...this.props}>
<Route path="/paths/:pathId/statistics" component = {Statistics} {...this.props} {...this.state}></Route>
<Route path="/paths/new" exact
render={(props)=>(<PathsNew {...this.props} {...this.state} {...props}/>)}
></Route>
<Route path="/paths/:pathId/edit" exact
render={(props)=>(<PathsNew {...this.props} {...this.state} {...props}/>)}
></Route>
<Route path="/paths/:pathId" exact component = {PathsDetail} {...this.props} {...this.state}></Route>
<Route path="/paths/:pathId" exact
render={(props)=>(<PathsDetail {...this.props} {...this.state} {...props}/>)}
></Route>
{/*<Route path="/paths/:pathId" exact component = {PathsDetail} {...this.props} {...this.state}></Route>*/}
<Route exact path="/paths" exact component={ShixunPaths} {...this.props} {...this.state}></Route>
</Switch>
</div>

@ -314,6 +314,7 @@ class DetailCards extends Component{
showparagraphindex
}=this.state;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
return(
<div>
<Modals
@ -363,6 +364,19 @@ class DetailCards extends Component{
</div>
</Spin>
</Modal>
<style>
{
`
.lessonvalue{
max-width: 556px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
}
`
}
</style>
<div className="lesson-saved-list">
{
pathCardsList && pathCardsList.map((item,key)=>{
@ -374,7 +388,7 @@ class DetailCards extends Component{
<a className="fl ring-blue mr10 mt2">
<img src={getImageUrl("images/educoder/icon/charpter-white.svg")} className="fl ml3 mt3"/>
</a>
<span className="font-18 font-bd">{item.stage_name}</span>
<span className="font-18 font-bd lessonvalue" title={item.stage_name}>{item.stage_name}</span>
{
idsum===key&&pathCardsedittype===true?'':
@ -442,13 +456,13 @@ class DetailCards extends Component{
:<i className="iconfont icon-bofang progressRing-part font-18 mt10"></i>
}
</span>
<span className={line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className={this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className="subject_stage_shixun_index">{key+1}</span>-{index+1}&nbsp;&nbsp;{line.shixun_name}
</span>
</li>
{
line.shixun_status==="暂未公开"?
this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?
<li className="fr status_li"><span className="fr color204">暂未公开</span></li>
:
<li className={showparagraph===false?"none":"fr status_li"}>

@ -402,7 +402,7 @@ class DetailCardsEditAndAdd extends Component{
<div className="df mb30">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input maxLength="60" type="text" style={{width:'670px'}} className={stage_nametype===false?"input-100-45 greyInput":"input-100-45 greyInput bor-red"} name="stage_name" value={stage_names} onInput={this.updatastage_names} placeholder={"请输入第"+this.props.sum+"阶段名称"}/>
<input maxLength="60" type="text" style={{width:'670px'}} className={stage_nametype===false?"input-100-45 greyInput":"input-100-45 greyInput bor-red"} name="stage_name" value={stage_names} onInput={this.updatastage_names} placeholder={"请输入第"+this.props.sum+"阶段名称,最大限制60个字符"}/>
<div className={stage_nametype===true?"red":'none'}>名称不能为空</div>
</div>
<div style={{"width":"60px"}}><span className="color-orange fl mt8 none" id="stage_name_notice"><i className="iconfont icon-tishi font-14 mr3"></i></span></div>

@ -435,7 +435,7 @@ class DetailCardsEditAndEdit extends Component{
<div className="df mb30">
<span className="mr30 color-orange pt10">*</span>
<div className="flex1 mr20">
<input type="text" style={{width: '670px'}} className={stage_nametype===false?"input-100-45 greyInput":"input-100-45 greyInput bor-red"} name="stage_name" value={stage_name} onInput={this.updatastage_name} placeholder={"请输入第"+(this.props.keys+1)+"阶段名称"}/>
<input maxLength="60" type="text" style={{width: '670px'}} className={stage_nametype===false?"input-100-45 greyInput":"input-100-45 greyInput bor-red"} name="stage_name" value={stage_name} onInput={this.updatastage_name} placeholder={"请输入第"+(this.props.keys+1)+"阶段名称,最大限制60个字符"}/>
<div className={stage_nametype===true?"red":'none'}>名称不能为空</div>
</div>
<div style={{"width":"60px"}}><span className="color-orange fl mt8 none" id="stage_name_notice"><i className="iconfont icon-tishi font-14 mr3"></i></span></div>

@ -140,10 +140,13 @@ class PathDetailIndex extends Component{
let url="/paths/"+pathid+".json";
axios.get(url).then((result)=>{
if (result.data.status === 407 || result.data.status === 401) {
debugger
return;
}
if (result.data.status === 403) {
debugger
window.location.href = "/403";
return;
}
@ -165,9 +168,12 @@ class PathDetailIndex extends Component{
axios.get(url).then((result)=>{
// TODO 403 让后台返回status 403 比较好
if (result.data.status == 407 || result.data.status == 401) {
debugger
return;
}
if (result.data.status === 403 ) {
debugger
window.location.href = "/403";
return;
}

@ -106,10 +106,15 @@ class ChangeHeaderPicModal extends Component{
// {"status":0,"message":"success","avatar_url":"avatars/User/15739"}
if (response.data.status == 0) {
// this.props.getBasicInfo()
this.props.fetchUser()
// 头像更新后会触发AccountPage的DidUpdate然后会调用getBasicInfo
this.props.showNotification && this.props.showNotification("修改头像成功")
this.setVisible(false)
// https://www.trustie.net/issues/22461
if ( this.props.current_user.image_url.indexOf('avatars/User/b') != -1
|| this.props.current_user.image_url.indexOf('avatars/User/g') != -1 ) {
this.setTimeout(() => {
this.doAfterUpdated()
}, 1000)
} else {
this.doAfterUpdated();
}
}
})
.catch(function (error) {
@ -117,6 +122,12 @@ class ChangeHeaderPicModal extends Component{
});
});
}
doAfterUpdated = () => {
this.props.fetchUser()
// 头像更新后会触发AccountPage的DidUpdate然后会调用getBasicInfo
this.props.showNotification && this.props.showNotification("修改头像成功")
this.setVisible(false)
}
render(){
const { course_lists } = this.state

Loading…
Cancel
Save