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

dev_winse
SylorHuang 6 years ago
commit 3f3b755611

1
.gitignore vendored

@ -46,6 +46,7 @@
/config/secrets.yml
/config/redis.yml
/config/elasticsearch.yml
/config/aliyun_vod.yml
public/upload.html
/config/configuration.yml

@ -0,0 +1,529 @@
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import {LocaleProvider} from 'antd'
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
import axios from 'axios';
import '@icedesign/base/dist/ICEDesignBase.css';
import '@icedesign/base/index.scss';
import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl';
import Trialapplicationysl from './modules/login/Trialapplicationysl';
import Trialapplicationreview from './modules/user/Trialapplicationreview';
import Addcourses from "./modules/courses/coursesPublic/Addcourses";
import AccountProfile from"./modules/user/AccountProfile";
import Trialapplication from './modules/login/Trialapplication'
import NotFoundPage from './NotFoundPage'
import Loading from './Loading'
import Loadable from 'react-loadable';
import moment from 'moment'
import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles';
// import './AppConfig'
import history from './history';
import {SnackbarHOC} from 'educoder'
import {initAxiosInterceptors} from './AppConfig'
// tpi需要这个来加载css
import {TPMIndexHOC} from './modules/tpm/TPMIndexHOC';
const theme = createMuiTheme({
palette: {
primary: {
main: '#4CACFF',
contrastText: 'rgba(255, 255, 255, 0.87)'
},
secondary: {main: '#4CACFF'}, // #11cb5f This is just green.A700 as hex.
},
});
//
// const Trialapplication= Loadable({
// loader: () =>import('./modules/login/Trialapplication'),
// loading:Loading,
// })
//登入
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
const TestIndex = Loadable({
loader: () => import('./modules/test'),
loading: Loading,
})
const IndexWrapperComponent = Loadable({
loader: () => import('./modules/page/IndexWrapper'),
loading: Loading,
})
const CommentComponent = Loadable({
loader: () => import('./modules/comment/CommentContainer'),
loading: Loading,
})
const TestMaterialDesignComponent = Loadable({
loader: () => import('./modules/test/md/TestMaterialDesign'),
loading: Loading,
})
const TestCodeMirrorComponent = Loadable({
loader: () => import('./modules/test/codemirror/TestCodeMirror'),
loading: Loading,
})
const TestComponent = Loadable({
loader: () => import('./modules/test/TestRC'),
loading: Loading,
})
const TestUrlQueryComponent = Loadable({
loader: () => import('./modules/test/urlquery/TestUrlQuery'),
loading: Loading,
})
const TPMIndexComponent = Loadable({
loader: () => import('./modules/tpm/TPMIndex'),
loading: Loading,
})
const TPMShixunsIndexComponent = Loadable({
loader: () => import('./modules/tpm/shixuns/ShixunsIndex'),
loading: Loading,
})
//实训课程(原实训路径)
const ShixunPaths = Loadable({
loader: () => import('./modules/paths/Index'),
loading: Loading,
})
//在线课堂
const CoursesIndex = Loadable({
loader: () => import('./modules/courses/Index'),
loading: Loading,
})
const SearchPage = Loadable({
loader: () => import('./search/SearchPage'),
loading: Loading,
})
//教学案例
const MoopCases = Loadable({
loader: () => import('./modules/moop_cases/index'),
loading: Loading,
})
// 课堂讨论
// const BoardIndex = Loadable({
// loader: () => import('./modules/courses/boards/BoardIndex'),
// loading:Loading,
// })
// //课堂普通作业&分组作业
// const CoursesWorkIndex = Loadable({
// loader: () => import('./modules/courses/busyWork/Index'),
// loading:Loading,
// })
//
// const TPMShixunchildIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/ShixunChildIndex'),
// loading: Loading,
// })
// const TPMshixunfork_listIndexComponent = Loadable({
// loader: () => import('./modules/tpm/shixunchild/Shixunfork_list'),
// loading: Loading,
// })
const ForumsIndexComponent = Loadable({
loader: () => import('./modules/forums/ForumsIndex'),
loading: Loading,
})
// trustie plus forum
// const TPForumsIndexComponent = Loadable({
// loader: () => import('./modules/tp-forums/TPForumsIndex'),
// loading: Loading,
// })
// const TestPageComponent = Loadable({
// loader: () => import('./modules/page/Index'),
// loading: Loading,
// })
//新建实训
const Newshixuns = Loadable({
loader: () => import('./modules/tpm/newshixuns/Newshixuns'),
loading: Loading,
})
//实训首页
const ShixunsHome = Loadable({
loader: () => import('./modules/home/shixunsHome'),
loading: Loading,
})
const CompatibilityPageLoadable = Loadable({
loader: () => import('./modules/common/CompatibilityPage'),
loading: Loading,
})
//403页面
const Shixunauthority = Loadable({
loader: () => import('./modules/403/Shixunauthority'),
loading: Loading,
})
//404页面
const Shixunnopage = Loadable({
loader: () => import('./modules/404/Shixunnopage'),
loading: Loading,
})
//500页面
const http500 = Loadable({
loader: () => import('./modules/500/http500'),
loading: Loading,
})
// 登录注册
const LoginRegisterPage = Loadable({
loader: () => import('./modules/user/LoginRegisterPage'),
loading: Loading,
})
const AccountPage = Loadable({
loader: () => import('./modules/user/AccountPage'),
loading: Loading,
})
// 个人主页
const UsersInfo = Loadable({
loader: () => import('./modules/user/usersInfo/Infos'),
loading: Loading,
})
// 兴趣页面
const Interestpage = Loadable({
loader: () => import('./modules/login/EducoderInteresse'),
loading: Loading,
})
//众包创新
const ProjectPackages=Loadable({
loader: () => import('./modules/projectPackages/ProjectPackageIndex'),
loading: Loading,
})
class App extends Component {
constructor(props) {
super(props)
// this.state = {
// isRenders:false,
// }
}
componentDidMount() {
// force an update if the URL changes
history.listen(() => {
this.forceUpdate()
const $ = window.$
// https://www.trustie.net/issues/21919 可能会有问题
$("html").animate({ scrollTop: $('html').scrollTop() - 0 })
});
initAxiosInterceptors(this.props)
//
// axios.interceptors.response.use((response) => {
// // console.log("response"+response);
// if(response!=undefined)
// // console.log("response"+response.data.statu);
// if (response&&response.data.status === 407) {
// this.setState({
// isRenders: true,
// })
// }
// return response;
// }, (error) => {
// //TODO 这里如果样式变了会出现css不加载的情况
// });
}
//修改登录方法
Modifyloginvalue=()=>{
this.setState({
isRender:false,
})
}
render() {
return (
<LocaleProvider locale={zhCN}>
<MuiThemeProvider theme={theme}>
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={()=>this.Modifyloginvalue()}></LoginDialog>
<Notcompletedysl {...this.props} {...this.state}></Notcompletedysl>
<Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl>
<Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview>
<Addcourses {...this.props} {...this.state}/>
<AccountProfile {...this.props} {...this.state}/>
{/*{*/}
{/* isRender === true?*/}
{/* <LoginDialog></LoginDialog> : ""*/}
{/*}*/}
{/*{*/}
{/* isRenders === true?*/}
{/*<Trialapplication></Trialapplication>*/}
{/*:""*/}
{/*}*/}
<Router>
<Switch>
{/*<Route path="/login" component={LoginRegisterPage}/>*/}
{/*众包创新*/}
<Route path={"/crowdsourcings"} component={ProjectPackages}/>
{/*认证*/}
<Route path="/account" component={AccountPage}/>
{/*403*/}
<Route path="/403" component={Shixunauthority}/>
<Route path="/500" component={http500}/>
{/*404*/}
<Route path="/nopage" component={Shixunnopage}/>
<Route path="/compatibility" component={CompatibilityPageLoadable}/>
<Route
path="/login" component={EducoderLogin}
/>
<Route
path="/register" component={EducoderLogin}
/>
<Route path="/users/:username"
render={
(props) => (<UsersInfo {...this.props} {...props} {...this.state} />)
}></Route>
{/*<Route*/}
{/* path="/trialapplication" component={Trialapplication}*/}
{/*/>*/}
<Route
path="/changepassword" component={EducoderLogin}
/>
<Route
path="/interesse" component={Interestpage}
/>
<Route path="/shixuns/new" component={Newshixuns}>
</Route>
<Route path="/tasks/:stageId" component={IndexWrapperComponent}/>
<Route path="/shixuns/:shixunId" component={TPMIndexComponent}>
</Route>
{/*列表页*/}
<Route path="/shixuns" component={TPMShixunsIndexComponent}/>
{/* <Route path="/shixunchild" component={TPMShixunchildIndexComponent}>
</Route>
<Route path="/fork_list" component={TPMshixunfork_listIndexComponent}>
</Route> */}
{/*<Route path="/forums" component={ForumsIndexComponent}>*/}
{/*</Route>*/}
{/*实训课程(原实训路径)*/}
<Route path="/paths" component={ShixunPaths}></Route>
<Route path="/search"
render={
(props)=>(<SearchPage {...this.props} {...props} {...this.state}></SearchPage>)
}
></Route>
{/*课堂*/}
<Route path="/courses" component={CoursesIndex} {...this.props}></Route>
{/* 课堂讨论 */}
{/* <Route path="/board" component = {BoardIndex} {...this.props}></Route> */}
{/* <Route path="/tpforums" component={TPForumsIndexComponent}>
</Route> */}
{/* <Route path="/myshixuns/:shixunId/stages/:stageId" component={Index}/> */}
{/* 兴趣页面*/}
{/*<Route path="/interest" component={Interestpage}/>*/}
<Route path="/comment" component={CommentComponent}/>
<Route path="/testMaterial" component={TestMaterialDesignComponent}/>
<Route path="/test" component={TestIndex}/>
<Route path="/testCodeMirror" component={TestCodeMirrorComponent}/>
<Route path="/testRCComponent" component={TestComponent}/>
<Route path="/testUrlQuery" component={TestUrlQueryComponent}/>
{/* 教学案例 */}
<Route path="/moop_cases"render={
(props) => (<MoopCases {...this.props} {...props} {...this.state} />)
}/>
{/* <Route component={NotFoundPage}/> */}
{/*列表页*/}
{/*<Route component={TPMShixunsIndexComponent}/>*/}
{/*首页*/}
<Route exact path="/" component={ShixunsHome}/>
<Route component={Shixunnopage}/>
{/*<Route component={ShixunsHome}/>*/}
</Switch>
</Router>
</MuiThemeProvider>
</LocaleProvider>
);
}
}
// moment国际化设置为中文
moment.defineLocale('zh-cn', {
months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
longDateFormat: {
LT: 'Ah点mm分',
LTS: 'Ah点m分s秒',
L: 'YYYY-MM-DD',
LL: 'YYYY年MMMD日',
LLL: 'YYYY年MMMD日Ah点mm分',
LLLL: 'YYYY年MMMD日ddddAh点mm分',
l: 'YYYY-MM-DD',
ll: 'YYYY年MMMD日',
lll: 'YYYY年MMMD日Ah点mm分',
llll: 'YYYY年MMMD日ddddAh点mm分'
},
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
meridiemHour: function (hour, meridiem) {
if (hour === 12) {
hour = 0;
}
if (meridiem === '凌晨' || meridiem === '早上' ||
meridiem === '上午') {
return hour;
} else if (meridiem === '下午' || meridiem === '晚上') {
return hour + 12;
} else {
// '中午'
return hour >= 11 ? hour : hour + 12;
}
},
meridiem: function (hour, minute, isLower) {
var hm = hour * 100 + minute;
if (hm < 600) {
return '凌晨';
} else if (hm < 900) {
return '早上';
} else if (hm < 1130) {
return '上午';
} else if (hm < 1230) {
return '中午';
} else if (hm < 1800) {
return '下午';
} else {
return '晚上';
}
},
calendar: {
sameDay: function () {
return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';
},
nextDay: function () {
return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';
},
lastDay: function () {
return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';
},
nextWeek: function () {
var startOfWeek, prefix;
startOfWeek = moment().startOf('week');
prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]';
return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
},
lastWeek: function () {
var startOfWeek, prefix;
startOfWeek = moment().startOf('week');
prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]';
return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';
},
sameElse: 'LL'
},
ordinalParse: /\d{1,2}(日|月|周)/,
ordinal: function (number, period) {
switch (period) {
case 'd':
case 'D':
case 'DDD':
return number + '日';
case 'M':
return number + '月';
case 'w':
case 'W':
return number + '周';
default:
return number;
}
},
relativeTime: {
future: '%s内',
past: '%s前',
s: '几秒',
m: '1分钟',
mm: '%d分钟',
h: '1小时',
hh: '%d小时',
d: '1天',
dd: '%d天',
M: '1个月',
MM: '%d个月',
y: '1年',
yy: '%d年'
},
week: {
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
dow: 1, // Monday is the first day of the week.
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
export default SnackbarHOC()(App);

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

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

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

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

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

@ -81,8 +81,6 @@ class AccountsController < ApplicationController
return normal_status(-2, "错误的账号或密码")
end
@user.update_column(:last_login_on, Time.now)
successful_authentication(@user)
session[:user_id] = @user.id
@ -124,7 +122,7 @@ class AccountsController < ApplicationController
set_autologin_cookie(user)
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
user.update_column(:last_login_on, Time.now)
# 注册完成后有一天的试用申请(先去掉)
# UserDayCertification.create(user_id: user.id, status: 1)
end
@ -160,7 +158,7 @@ class AccountsController < ApplicationController
# 发送验证码
# params[:login] 手机号或者邮箱号
# params[:type]为事件通知类型 1用户注册注册 2忘记密码 3: 绑定手机 4: 绑定邮箱 # 如果有新的继续后面加
# params[:type]为事件通知类型 1用户注册注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验收手机号有效 # 如果有新的继续后面加
# 发送验证码send_type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9: 验收手机号有效
def get_verification_code
@ -200,7 +198,7 @@ class AccountsController < ApplicationController
session[:user_id] = nil
end
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱 # 如果有新的继续后面加
# type 事件类型 1用户注册 2忘记密码 3: 绑定手机 4: 绑定邮箱, 5: 验证手机号是否有效 # 如果有新的继续后面加
# login_type 1手机类型 2邮箱类型
def verify_type login_type, type
case type
@ -212,6 +210,8 @@ class AccountsController < ApplicationController
login_type == 1 ? 4 : tip_exception('请填写正确的手机号')
when 4
login_type == 1 ? tip_exception('请填写正确的邮箱') : 5
when 5
login_type == 1 ? 9 : tip_exception('请填写正确的手机号')
end
end

@ -39,6 +39,7 @@ class ApplicationController < ActionController::Base
@user_course_identity = current_user.course_identity(@course)
if @user_course_identity > Course::STUDENT && @course.is_public == 0
tip_exception(401, "..") unless User.current.logged?
check_account
tip_exception(409, "您没有权限进入")
end
uid_logger("###############user_course_identity:#{@user_course_identity}")
@ -64,10 +65,10 @@ class ApplicationController < ActionController::Base
# 发送及记录激活码
# 发送验证码type 1注册手机验证码 2找回密码手机验证码 3找回密码邮箱验证码 4绑定手机 5绑定邮箱
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码
# 6手机验证码登录 7邮箱验证码登录 8邮箱注册验证码 9验证手机号有效
def check_verification_code(code, send_type, value)
case send_type
when 1, 2, 4
when 1, 2, 4, 9
# 手机类型的发送
sigle_para = {phone: value}
status = Educoder::Sms.send(mobile: value, code: code)
@ -189,8 +190,8 @@ class ApplicationController < ActionController::Base
# 资料是否完善
def check_account
if !current_user.profile_completed?
info_url = '/account/profile'
tip_exception(402, info_url)
#info_url = '/account/profile'
tip_exception(402, nil)
end
end
@ -238,17 +239,20 @@ class ApplicationController < ActionController::Base
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 57703
end
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
end
# 测试版前端需求
if request.host == "47.96.87.25"
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
end
end
# User.current = User.find 81403
end
@ -350,7 +354,7 @@ class ApplicationController < ActionController::Base
logger.info("--uri_exec: .....res is #{res}")
JSON.parse(res)
rescue Exception => e
uid_logger("--uri_exec: exception #{e.message}")
uid_logger_error("--uri_exec: exception #{e.message}")
raise Educoder::TipException.new("实训平台繁忙繁忙等级84")
end
end
@ -563,6 +567,10 @@ class ApplicationController < ActionController::Base
time.blank? ? '' : time.strftime("%Y-%m-%d %H:%M:%S")
end
def strf_date(date)
date.blank? ? '' : date.strftime("%Y-%m-%d")
end
def logger_error(error)
Rails.logger.error(error.message)
error.backtrace.each { |msg| Rails.logger.error(msg) }

@ -9,8 +9,7 @@ class BiddingUsersController < ApplicationController
end
def win
package = current_user.project_packages.find(params[:project_package_id])
ProjectPackages::WinBiddingService.call(package, params)
ProjectPackages::WinBiddingService.call(current_package, current_user, params)
render_ok
rescue ProjectPackages::WinBiddingService::Error => ex
render_error(ex.message)

@ -0,0 +1,12 @@
class BlobController < ApplicationController
def new
commit unless @repository.empty?
end
def create
create_commit(Files::CreateService, success_path: after_create_path,
failure_view: :new,
failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
end
end

@ -0,0 +1,24 @@
class Callbacks::AliyunVodsController < Callbacks::BaseController
before_action :check_signature_valid!
def create
Videos::DispatchCallbackService.call(params)
render_ok
end
private
def check_signature_valid!
return if AliyunVod::Sign.verify?(header_signature, header_timestamp)
render_not_acceptable
end
def header_timestamp
request.headers['X-VOD-TIMESTAMP']
end
def header_signature
request.headers['X-VOD-SIGNATURE']
end
end

@ -0,0 +1,5 @@
class Callbacks::BaseController < ActionController::Base
include RenderHelper
skip_before_action :verify_authenticity_token
end

@ -1,5 +1,5 @@
class ChallengesController < ApplicationController
before_action :require_login, :check_auth
before_action :require_login, :check_auth, except: [:index]
before_action :find_shixun, only: [:new, :create, :index]
skip_before_action :verify_authenticity_token, only: [:create, :update, :create_choose_question, :crud_answer]
before_action :find_challenge, only: [:edit, :show, :update, :create_choose_question, :index_down, :index_up,
@ -151,10 +151,11 @@ class ChallengesController < ApplicationController
def index
uid_logger("identifier: #{params}")
@challenges = Challenge.fields_for_list.where(shixun_id: @shixun.id)
@challenges = @shixun.challenges.fields_for_list
@editable = @shixun.status == 0 # before_action有判断权限如果没发布则肯定是管理人员
@user = current_user
@shixun.increment!(:visits)
end
def show

@ -7,6 +7,10 @@ module RenderHelper
render json: { status: -1, message: message }
end
def render_not_acceptable(message = '请求已拒绝')
render json: { status: 406, message: message }
end
def render_not_found(message = I18n.t('error.record_not_found'))
render json: { status: 404, message: message }
# render status: 404, json: { errors: errors }

@ -13,7 +13,7 @@ class CoursesController < ApplicationController
before_action :require_login, except: [:index, :show, :students, :teachers, :board_list, :mine, :all_course_groups,
:left_banner, :top_banner]
before_action :check_account, only: [:new, :create, :apply_to_join_course]
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]
before_action :set_course, :user_course_identity, only: [:show, :update, :destroy, :settings, :set_invite_code_halt,
@ -25,12 +25,13 @@ class CoursesController < ApplicationController
:transfer_to_course_group, :delete_from_course, :search_users, :add_students_by_search,
:base_info, :get_historical_courses, :create_group_by_importing_file,
:attahcment_category_list,:export_member_scores_excel, :duplicate_course,
:switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course]
:switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course,
:informs, :update_informs, :join_excellent_course, :online_learning]
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate,
:transfer_to_course_group, :delete_from_course,
:search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :add_teacher]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file]
:set_course_group, :create_group_by_importing_file, :update_informs]
before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group,
:change_course_teacher, :export_member_scores_excel, :course_group_list,
:teacher_application_review, :apply_teachers, :delete_course_teacher]
@ -49,30 +50,12 @@ class CoursesController < ApplicationController
@user = current_user
# 根据分类查询课堂(全部,我的,最新,最热)
@order = params[:order].present? ? params[:order] : "all"
order_str = @order != "course_members_count" && @order != "created_at" ? "updated_at" : @order
# if @order == "all"
# @course = Course.where(is_delete: 0, is_hidden: 0).select("select c.name, c.id, s.name, u.login, ifnull(concat(u.lastname,u.firstname),
# u.login), s.name from courses c, users u, user_extensions ue, schools s where c.is_delete=0 and
# c.tea_id=u.id and u.id=ue.user_id and ue.school_id=s.id")
# @courses = Course.where(is_delete: 0, is_hidden: 0)
# .order("courses.id = 1309 desc, courses.created_at desc")
# @courses = Course.where(is_delete: 0, is_hidden: 0).select("courses.id, courses.tea_id, courses.name, courses.exercises_count, courses.polls_count,
# courses.is_public, courses.is_end, courses.visits, courses.course_members_count,courses.homework_commons_count,(SELECT MAX(created_at)
# FROM `course_activities` WHERE course_activities.course_id = courses.id) AS a")
# .order("courses.id = 1309 desc, a desc")
if @order == "mine"
tip_exception(401, "..") unless current_user.logged?
@courses = Course.joins(:course_members)
.where("is_delete = 0 AND is_hidden = 0 AND course_members.user_id = ?", @user.id).distinct
elsif @order == "created_at"
# REDO:Extension
@courses = Course.where(is_delete: 0, is_hidden: 0, is_end: 0).distinct
if @order == "visits"
order_str = "courses.id = 1309 DESC, courses.visits DESC"
@courses = Course.where(is_delete: 0, is_hidden: 0)
else
# REDO:Extension
@courses = Course.where(is_delete: 0, is_hidden: 0).distinct
order_str = "courses.id = 1309 DESC, courses.homepage_show DESC, courses.created_at desc"
@courses = Course.where(is_delete: 0, is_hidden: 0, is_end: 0)
end
# 根据搜索关键字进一步筛选
@ -92,7 +75,7 @@ class CoursesController < ApplicationController
.where("#{sql}", keyword: "%#{params[:search]}%").distinct
end
@courses_count = @courses.count("courses.id")
@courses = @courses.order("courses.id = 1309 DESC, courses.#{order_str} DESC")
@courses = @courses.order(order_str)
# 分页
page = params[:page] || 1
@ -135,13 +118,19 @@ class CoursesController < ApplicationController
authentication: params[:authentication], professional_certification: params[:professional_certification])
@course.tea_id = current_user.id
@course_list_name = params[:course_list_name].strip
@course_list = CourseList.find_by(name: @course_list_name)
if @course_list
@course.course_list_id = @course_list.id
if params[:subject_id].blank?
@course_list_name = params[:course_list_name].strip
@course_list = CourseList.find_by(name: @course_list_name)
if @course_list
@course.course_list_id = @course_list.id
else
new_course_list = CourseList.create!(name: @course_list_name, user_id: current_user.id, is_admin: 0)
@course.course_list_id = new_course_list.id
end
else
new_course_list = CourseList.create!(name: @course_list_name, user_id: current_user.id, is_admin: 0)
@course.course_list_id = new_course_list.id
@course.start_date = params[:start_date]
@course.subject_id = params[:subject_id]
@course.excellent = true
end
@course.is_end = @course.end_date.present? && @course.end_date < Date.today
@ -151,6 +140,13 @@ class CoursesController < ApplicationController
CourseInfo.create!(user_id: current_user.id, course_id: @course.id)
CourseMember.create!(course_id: @course.id, user_id: current_user.id, role: 1)
# 将实践课程的教学团队成员以教师身份加入课堂
if @course.subject
@course.subject.subject_members.where.not(user_id: current_user.id).each do |s_member|
CourseMember.create!(course_id: @course.id, user_id: s_member.user_id, role: 2)
end
end
course_module_types = params[:course_module_types]
@course.create_course_modules(course_module_types)
end
@ -169,7 +165,6 @@ class CoursesController < ApplicationController
begin
extra_params = Hash.new
extra_params[:school_id] = @school.id
extra_params[:is_public] = params[:is_public].present? ? params[:is_public] : 0
if @course.is_end && (course_params[:end_date].blank? || course_params[:end_date].to_date > Date.today)
extra_params[:is_end] = 0
@ -180,13 +175,18 @@ class CoursesController < ApplicationController
extra_params[:authentication] = params[:authentication]
extra_params[:professional_certification] = params[:professional_certification]
@course_list_name = params[:course_list_name].strip
@course_list = CourseList.find_by(name: @course_list_name)
if @course_list
extra_params[:course_list_id] = @course_list.id
if @course.subject
@course.start_date = params[:start_date]
else
new_course_list = CourseList.create(name: @course_list_name, user_id: current_user.id, is_admin: 0)
extra_params[:course_list_id] = new_course_list.id
extra_params[:is_public] = params[:is_public].present? ? params[:is_public] : 0
@course_list_name = params[:course_list_name].strip
@course_list = CourseList.find_by(name: @course_list_name)
if @course_list
extra_params[:course_list_id] = @course_list.id
else
new_course_list = CourseList.create(name: @course_list_name, user_id: current_user.id, is_admin: 0)
extra_params[:course_list_id] = new_course_list.id
end
end
@course.update_attributes!(course_params.merge(extra_params))
@ -201,6 +201,42 @@ class CoursesController < ApplicationController
end
end
def join_excellent_course
tip_exception("您已是课堂成员") if current_user.member_of_course?(@course)
tip_exception("请通过邀请码加入课堂") unless @course.excellent
tip_exception("该课堂已结束") if @course.is_end
begin
new_student = CourseMember.new(user_id: current_user.id, course_id: @course.id, role: 4)
new_student.save!
CourseAddStudentCreateWorksJob.perform_later(@course.id, [current_user.id])
StudentJoinCourseNotifyJob.perform_later(current_user.id, @course.id)
normal_status(0, "加入成功")
rescue => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end
def informs
end
def update_informs
tip_exception("公告内容不能为空") if params[:description].blank?
inform = @course.inform || Inform.new(container: @course)
inform.description = params[:description]
inform.save!
normal_status("更新成功")
end
def online_learning
@subject = @course.subject
@stages = @subject&.stages
@user = current_user
@start_learning = @user_course_identity == Course::STUDENT && @subject&.learning?(current_user.id)
end
def search_course_list
search = params[:search] ? "%#{params[:search].strip}%" : "%%"
@course_lists = CourseList.where("name like ?", "#{search}")
@ -234,6 +270,8 @@ class CoursesController < ApplicationController
def destroy
if @course.is_delete == 0
@course.delete!
Tiding.create!(user_id: @course.tea_id, trigger_user_id: 1, container_id: @course.id,
container_type: 'Course', tiding_type: 'Delete', extra: @course.name)
normal_status(0, "成功")
else
normal_status(-1, "课堂已删除,无需重复操作")
@ -296,7 +334,13 @@ class CoursesController < ApplicationController
@applications = CourseMessage.unhandled_join_course_requests_by_course(@course).
joins("join users on course_messages.course_message_id=users.id").
where("LOWER(concat(users.lastname, users.firstname)) LIKE ?", "%#{search_str}%")
@teacher_list_size = @course.teachers.size
if @course.try(:id) != 1309 || current_user.admin? || current_user.try(:id) == 15582
teacher_list = @course.course_members.where("course_members.role in (1, 2, 3)")
else
teacher_list = @course.course_members.where("(course_members.role in (1, 3) or (course_members.user_id = #{current_user.id}
and course_members.role = 2))")
end
@teacher_list_size = teacher_list.size
@applications_size = CourseMessage.unhandled_join_course_requests_by_course(@course).size
@is_admin = @user_course_identity < Course::PROFESSOR
end
@ -909,6 +953,7 @@ class CoursesController < ApplicationController
CourseAddStudentCreateWorksJob.perform_later(course.id, [current_user.id])
StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id)
end
student_role = 1
end
# 创建教师身份
@ -921,24 +966,33 @@ class CoursesController < ApplicationController
course_message = CourseMessage.new(course_id: course.id, user_id: course.tea_id, status: 0,
course_message_id: current_user.id, course_message_type: "JoinCourseRequest",
viewed: false)
course_message.content = 2 if params[:professor].present? && params[:professor].to_i == 1
course_message.content = 3 if params[:assistant_professor].present? && params[:assistant_professor].to_i == 1
if params[:professor].present? && params[:professor].to_i == 1
course_message.content = 2
role = 9
message = "教师申请已提交,请等待审核"
else
course_message.content = 3
role = 7
message = "助教申请已提交,请等待审核"
end
course_message.save!
role = course_message.content == 2 ? '7' : '9' # 7:助教 9:教师
# role = course_message.content == 2 ? '9' : '7' # 7:助教 9:教师
ApplyTeacherRoleJoinCourseNotifyJob.perform_later(current_user.id, course.id, role)
message = "#{course_message.content == 2 ? '助教' : '教师'}申请已提交,请等待审核"
# message = "#{course_message.content == 2 ? '教师' : '助教'}申请已提交,请等待审核"
else
message = "#{existing_course_message.content == 2 ? '助教' : '教师'}申请已提交,请等待审核"
message = "#{existing_course_message.content == '2' ? '教师' : '助教'}申请已提交,请等待审核"
end
else
message = "您已是课堂成员"
end
teacher_role = 1
end
if teacher_role && current_user.student_of_course?(course)
if teacher_role && student_role
render json: { status: 0, message: message, course_id: course.id}
elsif current_user.student_of_course?(course)
elsif student_role
render json: { status: 0, message: "加入成功", course_id: course.id}
else
normal_status(message)
@ -1075,14 +1129,31 @@ class CoursesController < ApplicationController
def validate_course_name
tip_exception("课堂名称不能为空!") if params[:course][:name].blank?
tip_exception("课程名称不能为空!") if params[:course_list_name].blank?
tip_exception("课堂名称应以课程名称开头命名") unless params[:course][:name].index(params[:course_list_name]) &&
if params[:subject_id].blank? || (@course && @course.subject.blank?)
tip_exception("课程名称不能为空!") if params[:course_list_name].blank?
tip_exception("课堂名称应以课程名称开头命名") unless params[:course][:name].index(params[:course_list_name]) &&
params[:course][:name].index(params[:course_list_name]) == 0
else
@subject = @course.present? ? @course.subject : Subject.find_by!(id: params[:subject_id])
tip_exception("开始时间不能为空") if params[:start_date].blank?
tip_exception("结束时间不能为空") if params[:end_date].blank?
tip_exception("结束时间必须晚于开始时间") if params[:end_date] <= params[:start_date]
tip_exception("开始时间和结束时间不能与往期开课时间重叠") if @course.nil? && @subject.max_course_end_date && params[:start_date] <= strf_date(@subject.max_course_end_date)
validate_start_end_date if @course.present?
tip_exception("开放课堂必须包含公告栏和在线学习模块") unless params[:course_module_types].include?("announcement") && params[:course_module_types].include?("online_learning")
end
tip_exception("课堂所属单位不能为空!") if params[:school].blank?
tip_exception("请至少添加一个课堂模块") if params[:course_module_types].blank?
@school = School.find_by!(name: params[:school].strip)
end
def validate_start_end_date
prev_course = @subject.courses.where("id < #{@course.id}").last
next_course = @subject.courses.where("id > #{@course.id}").first
tip_exception("开始时间和结束时间不能与其他期开课时间重叠") if prev_course && params[:start_date] <= strf_date(prev_course.end_date)
tip_exception("开始时间和结束时间不能与其他期开课时间重叠") if next_course && params[:end_date] >= strf_date(next_course.start_date)
end
# 超级管理员和课堂管理员的权限判断
def admin_allowed
unless @user_course_identity < Course::PROFESSOR
@ -1154,6 +1225,12 @@ class CoursesController < ApplicationController
#课堂的作业信息
shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业
shixun_titles = shixun_homeworks.pluck(:name) + ["总得分"]
# 更新实训作业成绩
shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework|
homework.update_homework_work_score
end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业

@ -1,7 +1,8 @@
class DiscussesController < ApplicationController
LIMIT = 10
before_action :require_login, only: [:create, :reply, :hidden, :reward_code, :plus, :destroy]
before_action :find_container, only: [:index, :hidden]
before_action :find_discuss, except: [:create, :index, :new_message, :reward_code]
before_action :find_discuss, except: [:create, :index, :new_message, :reward_code, :forum_discusses, :plus]
def index
page = params[:page].to_i
@ -28,6 +29,48 @@ class DiscussesController < ApplicationController
@current_user = current_user
end
def forum_discusses
page = params[:page] || 1
limit = params[:limit] || 15
offset = (page.to_i-1) * limit
search = params[:search]
tag = params[:tag_repertoire_id]
sql, sql1, sql2 = '', '', ''
sql1 =
unless search.blank?
"and d.content like '%#{search}%'"
end
sql2 =
if tag
shixun_ids = ShixunTagRepertoire.where(:tag_repertoire_id => tag).pluck(:shixun_id)
"and d.dis_id in(#{shixun_ids.join(",")})"
end
sql = "select d.id from discusses d join shixuns s on d.dis_id = s.id where s.status = 2 and s.hidden = false and d.root_id is null
and d.hidden = false #{sql1} #{sql2} order by d.created_at desc"
memo_ids = Discuss.find_by_sql(sql).pluck(:id)
@memo_count = memo_ids.size
memo_ids = memo_ids[offset, limit]
order_ids = memo_ids.size > 0 ? memo_ids.join(',') : -1
@memos = Discuss.where(id: memo_ids).order("field(id,#{order_ids})").includes(:praise_treads, dis: :tag_repertoires, user: :user_extension)
# @memos = memos.includes(:praise_treads, user: :user_extension).page(page).per(limit)
# 实训标签使用最多的9个
# @hot_tags = TagRepertoire.find_by_sql("select distinct(a.name), a.id from
# (select tr.id, tr.name, count(d.dis_id) cnt
# from tag_repertoires tr join (shixun_tag_repertoires str
# left join (shixuns s join discusses d on d.dis_id = s.id)
# on s.id = str.shixun_id) on tr.id = str.tag_repertoire_id
# group by d.dis_id order by cnt desc) a limit 9").map{|ht| ht.attributes.dup}
tag_id = ShixunTagRepertoire.joins(:shixun).order("myshixuns_count desc").pluck(:tag_repertoire_id).uniq.first(9)
@hot_tags = TagRepertoire.select([:id, :name]).where(id: tag_id).order("FIELD(id, #{tag_id.join(",")})").map{|ht| ht.attributes.dup} if tag_id
@memos = DiscussesService.new.memo_list @memos
@hot_memos = Memo.field_for_recommend.posts.hot.includes(:tag_repertoires).limit(4)
@recommend_shixuns = DiscussesService.new.recommends
end
def new_message
onclick_time = Myshixun.find(params[:myshixun_id]).try(:onclick_time)
ids = Discuss.where(user_id: User.current.id, dis_id: params[:container_id], dis_type: params[:container_type]).

@ -703,12 +703,14 @@ class ExercisesController < ApplicationController
end
if ex_status == 1 #如果试卷存在已发布的,或者是已截止的,那么则直接跳过
g_course = params[:group_ids] #表示是否传入分班参数,如果传入分班的参数,那么试卷的统一设置需修改
tiding_group_ids = g_course
if g_course
user_course_groups = @course.charge_group_ids(current_user)
if g_course.map(&:to_i).sort == user_course_groups.sort # 如果是设置为全部班级,则试卷不用分组,且试卷设定为统一设置,否则则分组设置
exercise.exercise_group_settings.destroy_all
ex_unified = true
e_time = ex_end_time
tiding_group_ids = []
else
ex_unified = false
g_course.each do |i|
@ -748,7 +750,7 @@ class ExercisesController < ApplicationController
if exercise.course_acts.size == 0
exercise.course_acts << CourseActivity.new(:user_id => exercise.user_id,:course_id => exercise.course_id)
end
ExercisePublishNotifyJob.perform_later(exercise.id, g_course)
ExercisePublishNotifyJob.perform_later(exercise.id, tiding_group_ids)
end
end
end
@ -1084,6 +1086,7 @@ class ExercisesController < ApplicationController
:subjective_score => subjective_score
}
@answer_committed_user.update_attributes(commit_option)
CommitExercsieNotifyJobJob.perform_later(@exercise.id, current_user.id)
normal_status(0,"试卷提交成功!")
end
rescue Exception => e

@ -17,8 +17,8 @@ class FilesController < ApplicationController
sort_type = params[:sort_type] || 'created_on' # created_on时间排序 downloads下载次数排序; quotes: 引用次数排序
course_second_category_id = params[:course_second_category_id] || 0 # 0: 为主目录, 其他为次目录id
@user = current_user
@attachments = @course.attachments.by_course_second_category_id(course_second_category_id)
.includes(attachment_group_settings: :course_group, author: [:user_extension, :course_members])
@attachments = course_second_category_id.to_i == 0 ? @course.attachments : @course.attachments.by_course_second_category_id(course_second_category_id)
@attachments = @attachments.includes(attachment_group_settings: :course_group, author: [:user_extension, :course_members])
.ordered(sort: sort.to_i, sort_type: sort_type.strip)
get_category(@course, course_second_category_id)

@ -1,2 +0,0 @@
class ForumsController < ApplicationController
end

@ -116,10 +116,11 @@ class GamesController < ApplicationController
@qrcode_str = Base64.encode64( qr.to_img.resize(400,400).to_s )
else
@type = "image"
#conv = Iconv.new("GBK", "utf-8")
@game_challenge = @game.challenge
type = @game_challenge.show_type
@type = shixun_show_type type
workspace_path = @game.try(:picture_path)
@answer_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.expect_picture_path}"
@user_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.picture_path}"
@ -466,13 +467,13 @@ class GamesController < ApplicationController
path = params[:path]
game_code = GameCode.where(:game_id => @game.try(:id), :path => path).first
if game_code.present?
content = game_code.try(:new_code)
@content = game_code.try(:new_code)
# @content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && content.present?
# content.gsub(/\t/, ' ')
# else
# content
# end
update_file_content(content, @myshixun.repo_path, path, current_user.git_mail, current_user.real_name, "game passed reset")
update_file_content(@content, @myshixun.repo_path, path, current_user.git_mail, current_user.real_name, "game passed reset")
else
tip_exception("代码重置失败,代码为空")
end
@ -493,17 +494,10 @@ class GamesController < ApplicationController
path = path.try(:strip)
uid_logger("--rep_content: path is #{path}")
begin
if @myshixun.repo_name.nil?
g = Gitlab.client
repo_name = g.project(@myshixun.gpid).path_with_namespace
@myshixun.update_column(:repo_name, repo_name)
@content = git_fle_content("#{repo_name}.git", path) || ""
else
@content = git_fle_content(@myshixun.repo_path, path) || ""
end
@content = git_fle_content(@myshixun.repo_path, path) || ""
rescue Exception => e
# 思路: 异常首先应该考虑去恢复
# retry为1表示已经轮训完成后还没有解决问题这个时候需要检测异常
if params[:retry].to_i == 1
begin
# 如果模板没有问题,则通过中间层检测实训仓库是否异常
@ -541,7 +535,7 @@ class GamesController < ApplicationController
end
end
end
# 有异常,版本库获取不到代码,前端轮训30S后调用retry == 1
# 有异常,版本库获取不到代码,前端轮训15S后调用retry == 1
tip_exception(0, e.message)
end
end

@ -255,29 +255,7 @@ class HomeworkCommonsController < ApplicationController
def update_score
tip_exception("作业还未发布,暂不能计算成绩") if @homework.publish_time.nil? || @homework.publish_time > Time.now
begin
if @homework.unified_setting
student_works = @homework.student_works
user_ids = @course.students.pluck(:user_id)
else
user_ids = @course.students.where(course_group_id: @homework.published_settings.pluck(:course_group_id)).pluck(:user_id)
student_works = @homework.student_works.where(user_id: user_ids)
end
student_works = student_works.includes(:challenge_work_scores)
challenge_settings = @homework.homework_challenge_settings
challenge_setting_ids = challenge_settings.pluck(:challenge_id)
myshixuns = Myshixun.where(shixun_id: @homework.homework_commons_shixun&.shixun_id, user_id: user_ids).includes(:games)
myshixuns.find_each(batch_size: 100) do |myshixun|
work = student_works.select{|work| work.user_id == myshixun.user_id}.first
if work && myshixun
games = myshixun.games.select{|game| challenge_setting_ids.include?(game.challenge_id)}
HomeworksService.new.update_myshixun_work_score work, myshixun, games, @homework, challenge_settings
end
end
HomeworksService.new.update_student_eff_score @homework if (@homework.allow_late && @homework.late_time < Time.now) ||
(!@homework.allow_late && @homework.end_time < Time.now)
@homework.update_attribute('calculation_time', Time.now)
@homework.update_homework_work_score
normal_status("更新成功")
rescue Exception => e
uid_logger(e.message)
@ -336,7 +314,7 @@ class HomeworkCommonsController < ApplicationController
@messages = @messages.parent_comment
end
@messages = @messages.page(@page).per(@limit).order("created_on desc")
@messages = @messages.includes(:praise_treads).page(@page).per(@limit).order("created_on desc")
end
def reference_answer
@ -1347,6 +1325,7 @@ class HomeworkCommonsController < ApplicationController
def group_list
@page = params[:page] || 1
@limit = params[:limit] || 10
@course_member_count = @course.course_groups.count
@course_groups = @course.course_groups.page(@page).per(@limit)
@ungroup_user_ids = @course.course_members.ungroup_students.pluck(:user_id)
end
@ -1357,7 +1336,7 @@ class HomeworkCommonsController < ApplicationController
shixun = @homework.shixuns.take
# 通过代码文件来判断语言
language = shixun.challenges.practice_type.pluck(:path).first
language = language.split("")[0].split(".")[1].downcase if language.present?
language = language.split("")[0].split(".").last.downcase if language.present?
user_lists = []
if language.present? && (language == "java" || language == "py")
user_ids = @course.course_members.where(course_group_id: params[:group_ids]).distinct(:user_id).pluck(:user_id)
@ -1480,7 +1459,8 @@ class HomeworkCommonsController < ApplicationController
if game_codes.count > 0
code_rate += game_codes.map(&:rate).sum / challenge.path.split("").length
end
target = game_codes.count > 0 ? game_codes[0].target_user_id : nil
logger.info("#####game_codes: #{game_codes}")
#target = game_codes.count > 0 ? game_codes[0].target_user_id : nil
# 作品完成时间
game = challenge.games.find_by(user_id: @user.id)
end_time = game.end_time
@ -1488,7 +1468,7 @@ class HomeworkCommonsController < ApplicationController
all_score = homework_challenge_settings.find_by(challenge_id: challenge.id).try(:score).to_f
final_score = @student_work.work_challenge_score game, all_score
# 抄袭用户
copy_user = User.find_by_id(game_codes[0].target_user_id)
copy_user = User.find_by_id(game_codes[0].try(:target_user_id))
copy_end_time = copy_user.games.find_by(challenge_id: challenge.id).try(:end_time) if copy_user.present?
# 代码部分
code_list = []
@ -1498,7 +1478,7 @@ class HomeworkCommonsController < ApplicationController
code_list << {path: path, origin_content: info.origin_content, target_content: info.target_content}
end
end
# TODO: 这里本来应该前端做的,但是现在页面已经刷不开了。
{code_rate: code_rate, copy_user_id: copy_user.try(:id), end_time: end_time, final_score: final_score,
all_score: all_score, copy_end_time: copy_end_time, copy_username: copy_user.try(:full_name),
username: game.user.full_name, code_list: code_list, subject: challenge.subject, position: challenge.position,

@ -2,7 +2,8 @@ class LibrariesController < ApplicationController
include PaginateHelper
before_action :require_login, :check_auth, except: %i[index show]
before_action :check_account, except: %i[index show]
after_action :increment_visit_count, only: [:show, :edit, :update]
helper_method :current_library, :library_manageable?
def index
@ -22,7 +23,7 @@ class LibrariesController < ApplicationController
end
@count = libraries.count
@libraries = paginate libraries.includes(:library_tags, :praise_tread_cache, user: :user_extension)
@libraries = paginate libraries.includes(:library_tags, user: :user_extension)
ids = @libraries.map(&:id)
@download_count_map = Attachment.where(container_type: 'Library', container_id: ids)
@ -38,7 +39,7 @@ class LibrariesController < ApplicationController
def create
library = current_user.libraries.new
Libraries::SaveService.call(library, current_user, save_params)
render_ok
render_ok({id: library.id})
rescue Libraries::SaveService::Error => ex
render_error(ex.message)
end
@ -47,7 +48,7 @@ class LibrariesController < ApplicationController
return render_forbidden unless library_manageable?(current_library)
Libraries::SaveService.call(current_library, current_user, save_params)
render_ok
render_ok({id: current_library.id})
rescue Libraries::SaveService::Error => ex
render_error(ex.message)
end
@ -80,6 +81,10 @@ class LibrariesController < ApplicationController
current_user&.id == library.user_id || admin_or_business?
end
def increment_visit_count
current_library.increment_visited_count! if current_library && current_library.id
end
def save_params
params.permit(:title, :content, :author_name, :author_school_name,
:cover_id, :publish, attachment_ids: [], tag_ids: [])

@ -1,5 +1,10 @@
class MemosController < ApplicationController
before_action :set_memo, only: [:show, :edit, :update, :destroy]
before_action :require_login, except: [:show, :index]
before_action :check_account, only: [:new, :create]
before_action :set_memo, only: [:show, :edit, :update, :destroy, :sticky_or_cancel, :hidden, :more_reply]
before_action :validate_memo_params, only: [:create, :update]
before_action :owner_or_admin, only: [:edit, :update, :destroy]
before_action :require_business, only: [:sticky_or_cancel, :hidden]
include ApplicationHelper
# GET /memos
@ -8,27 +13,21 @@ class MemosController < ApplicationController
@user = current_user
@memos = Memo.all
s_order = (params[:order] == "replies_count" ? "all_replies_count" : params[:order]) || "updated_at"
#@tidding_count = unviewed_tiddings(current_user) if current_user.present?
page = params[:page].to_i
# @tidding_count = unviewed_tiddings(current_user) if current_user.present?
page = params[:page] || 1
limit = params[:limit] || 15
search = params[:search]
offset = page * 15
forum_id = params[:forum]
user_id = params[:user_id]
if user_id == -1
user_id = current_user.try(:id)
end
tag_repertoire_id = params[:tag_repertoire_id]
sql =
if forum_id
search ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" :
!search.blank? ? "forum_id = #{forum_id} and root_id is null and subject like '%#{search}%'" :
"forum_id = #{forum_id} and root_id is null"
elsif search
user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null and subject like '%#{search}%'" :
"forum_id in(3, 5) and root_id is null and subject like '%#{search}%'"
elsif !search.blank?
"forum_id in(3, 5) and root_id is null and subject like '%#{search}%'"
else
user_id ? "author_id = #{user_id.to_i} and forum_id in(3, 5) and root_id is null" :
"forum_id in(3, 5) and root_id is null"
"forum_id in(3, 5) and root_id is null"
end
if tag_repertoire_id
@ -41,27 +40,27 @@ class MemosController < ApplicationController
sql += " and all_replies_count != 0"
end
memos = Memo.field_for_list.includes(:praise_tread, :author).where("#{sql}")
memos = Memo.field_for_list.where("#{sql}")
@memos_count = memos.length
@memos = memos.order("sticky = 1 desc, #{Memo.table_name}.#{s_order} desc").offset(offset).limit(15)
@my_memos_count = Memo.user_posts(current_user.try(:id)).count
@memos = memos.order("sticky = 1 desc, #{Memo.table_name}.#{s_order} desc").page(page).per(limit)
@memos = @memos.includes(:praise_treads, :tag_repertoires, author: :user_extension)
# @my_memos_count = Memo.user_posts(current_user.try(:id)).count
@tags_info = MemoTagRepertoire.find_by_sql("SELECT tag_repertoire_id, tr.name, count(*) cnt
FROM memo_tag_repertoires mtr join tag_repertoires tr on
tr.id = mtr.tag_repertoire_id group by tag_repertoire_id order by cnt desc,
tag_repertoire_id desc limit 9")
@hot_memos = Memo.field_for_recommend.posts.hot.limit(4)
@hot_memos = Memo.field_for_recommend.posts.hot.includes(:tag_repertoires).limit(4)
@recommend_shixuns = DiscussesService.new.recommends
end
# GET /memos/1
# GET /memos/1.json
def show
# tidding_count = unviewed_tiddings(current_user) if current_user
@user = current_user
# TODO 附件最后再做
# attachments_list =
@memo.update_column(:viewed_count, @memo.viewed_count+1)
@memos = @memo.reply_for_memo.includes(:praise_tread, :author).order("created_at desc").limit(10)
@memos = @memo.reply_for_memo.includes(:praise_treads, author: :user_extension).order("created_at desc").limit(10)
@attachments = @memo.attachments
@recommend_shixuns = DiscussesService.new.recommends
end
# GET /memos/new
@ -71,43 +70,44 @@ class MemosController < ApplicationController
# GET /memos/1/edit
def edit
@tag_list = TagRepertoire.field_for_list.order("name asc")
@memo_tags = @memo.tag_repertoires.field_for_list
@attachments = @memo.attachments
end
# POST /memos
# POST /memos.json
def create
ActiveRecord::Base.transaction do
begin
@memo = Memo.new(memo_params)
@memo.author = current_user
# TODO 保存附件
# @memo.save_attachments(params[:attachments]) if params[:attachments]
@memo.save!
Attachment.associate_container(params[:attachment_ids], @memo.id, @memo.class.name)
params[:tags].each do |tag|
MemoTagRepertoire.create(:memo_id => @memo.id, :tag_repertoire_id => tag)
MemoTagRepertoire.create!(memo_id: @memo.id, tag_repertoire_id: tag)
end
@status = 0
@message = "帖子创建成功!"
render :json => {memo_id: @memo.id, status: 0, message: "帖子创建成功"}
rescue Exception => e
@status = -1
@message = "帖子创建失败,原因:#{e}"
tip_exception("帖子创建失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
# PATCH/PUT /memos/1
# PATCH/PUT /memos/1.json
def update
respond_to do |format|
if @memo.update(memo_params)
format.html { redirect_to @memo, notice: 'Memo was successfully updated.' }
format.json { render :show, status: :ok, location: @memo }
else
format.html { render :edit }
format.json { render json: @memo.errors, status: :unprocessable_entity }
ActiveRecord::Base.transaction do
begin
@memo.update_attributes!(memo_params)
Attachment.associate_container(params[:attachment_ids], @memo.id, @memo.class.name)
@memo.memo_tag_repertoires.destroy_all
params[:tags].each do |tag|
MemoTagRepertoire.create!(memo_id: @memo.id, tag_repertoire_id: tag)
end
normal_status("帖子更新成功")
rescue Exception => e
tip_exception("帖子更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
@ -116,21 +116,83 @@ class MemosController < ApplicationController
# DELETE /memos/1.json
def destroy
@memo.destroy
respond_to do |format|
format.html { redirect_to memos_url, notice: 'Memo was successfully destroyed.' }
format.json { head :no_content }
normal_status("删除成功")
end
def sticky_or_cancel
tip_exception("只能对主贴进行置顶操作") unless @memo.parent_id.nil?
begin
@memo.update_attributes!(sticky: !@memo.sticky)
normal_status("更新成功")
rescue Exception => e
tip_exception("更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_memo
@memo = Memo.find(params[:id])
def hidden
tip_exception("不能对主贴进行隐藏操作") if @memo.parent_id.nil?
begin
@memo.update_attributes!(hidden: @memo.hidden == 0 ? 1 : 0)
normal_status("更新成功")
rescue Exception => e
tip_exception("更新失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def memo_params
params.fetch(:memo, {})
def reply
tip_exception("parent_id不能为空") if params[:parent_id].blank?
tip_exception("content不能为空") if params[:content].blank?
ActiveRecord::Base.transaction do
begin
memo = Memo.find_by!(id: params[:parent_id])
@reply = Memo.new
@reply.content = params[:content]
@reply.author = current_user
@reply.forum_id = memo.forum_id
@reply.subject = memo.subject
@reply.root_id = memo.root_id || memo.id
memo.children << @reply
m = Memo.find_by!(id: @reply.root_id)
m.update_attributes!(all_replies_count: m.all_replies_count + 1)
rescue Exception => e
tip_exception("回复失败,原因:#{e}")
raise ActiveRecord::Rollback
end
end
end
def more_reply
@user = current_user
page = params[:page] || 2
limit = params[:limit] || 10
offset = (page.to_i - 1) * limit
@memos_count = Memo.where(parent_id: @memo.id).count
@memos = Memo.limit(limit).where(parent_id: @memo.id).includes(:author, :praise_treads).order("created_at desc").offset(offset)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_memo
@memo = Memo.find(params[:id])
end
def owner_or_admin
tip_exception(403, "无权限操作") unless @memo.author == current_user || current_user.admin? || current_user.business?
end
# Never trust parameters from the scary internet, only allow the white list through.
def memo_params
params.require(:memo).permit(:subject, :content, :forum_id)
end
def validate_memo_params
tip_exception("话题名称不能为空") if params[:subject].blank?
tip_exception("话题内容不能为空") if params[:content].blank?
tip_exception("话题类型不能为空") if params[:forum_id].blank?
tip_exception("技术标签不能为空") if params[:forum_id].to_i == 5 && params[:tags].blank?
end
end

@ -23,24 +23,19 @@ class MyshixunsController < ApplicationController
begin
ActiveRecord::Base.transaction do
begin
@shixun = Shixun.select(:id, :identifier).find(@myshixun.shixun_id)
@myshixun.destroy
@shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id)
@myshixun.destroy!
StudentWork.where(:myshixun_id => @myshixun.id).update_all(:myshixun_id => 0, :work_status => 0)
# 实训在申请发布前,是否玩过实训,如果玩过需要更改记录,防止二次重置
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
logger.error("######reset_my_game_failed:#{e.message}")
raise("ActiveRecord::RecordInvalid")
end
end
# 删除版本库
GitService.delete_repository(repo_path: @repo_path)
GitService.delete_repository(repo_path: @repo_path) unless @shixun.is_choice_type?
rescue Exception => e
if e.message != "ActiveRecord::RecordInvalid"
logger.error("######delete_repository_error:#{e.message}")
logger.error("######delete_repository_error-:#{e.message}")
end
raise "delete_repository_error:#{e.message}"
end
@ -265,9 +260,10 @@ class MyshixunsController < ApplicationController
# params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
# 自动保存的时候evaluate为0点评测的时候为1
if params[:evaluate] == 1
exec_time = game.challenge.try(:exec_time)
@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)
:identifier => @sec_key, :exec_time => exec_time)
uid_logger("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
end
unless @hide_code

@ -919,6 +919,7 @@ class PollsController < ApplicationController
:end_at => Time.now
}
poll_user_current.update_attributes(poll_user_params)
CommitPollNotifyJobJob.perform_later(@poll.id, current_user.id)
normal_status(0, "问卷提交成功!")
end
## 需添加发送消息的接口,稍后添加

@ -1,7 +1,7 @@
class ProjectPackagesController < ApplicationController
include PaginateHelper
before_action :require_login, :check_auth, only: %i[create update destroy]
before_action :require_login, :check_auth, only: %i[show create update destroy]
helper_method :current_package, :package_manageable?

@ -1,10 +1,2 @@
class ProjectsController < ApplicationController
def search
query_params = { keyword: params[:keyword], category: 'manage' }
projects = Users::ProjectService.new(current_user, query_params).call
params[:limit] = params[:per_page].to_i.zero? ? 20 : params[:per_page].to_i
@count = projects.count
@projects = paginate projects
end
end

@ -2,10 +2,10 @@ class ShixunsController < ApplicationController
include ShixunsHelper
include ApplicationHelper
before_action :require_login, :check_auth, except: [:download_file, :index, :menus]
before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list,
:discusses, :collaborators, :fork_list, :propaedeutics]
before_action :check_account, only: [:new, :create, :shixun_exec]
before_action :check_auth, except: [:download_file, :index, :menus]
before_action :find_shixun, :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
:propaedeutics, :departments, :apply_shixun_mirror,
@ -164,7 +164,7 @@ class ShixunsController < ApplicationController
@new_shixun = Shixun.new
@new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star",
"homepage_show","repo_name", "myshixuns_count", "challenges_count",
"can_copy")
"can_copy", "created_at", "updated_at")
@new_shixun.user_id = User.current.id
@new_shixun.averge_star = 5
@new_shixun.identifier = generate_identifier Shixun, 8
@ -406,20 +406,19 @@ class ShixunsController < ApplicationController
end
end
@shixun.update_attributes(shixun_params)
logger.info("##########shixun_info_params: #{shixun_info_params}")
logger.info("##########params[:shixun_info][:evaluate_script]: #{params[:shixun_info][:evaluate_script]}")
@shixun.shixun_info.update_attributes(shixun_info_params)
@shixun.shixun_schools.delete_all
if params[:scope_partment].present? && params[:user_scope].to_i == 1
# scope_partment: 高校的名称
if params[:scope_partment].present?
arr = []
ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq
ids.each do |id|
arr << { :school_id => id, :shixun_id => @shixun.id }
end
ShixunSchool.create!(arr)
use_scope = 1
else
use_scope = 0
end
@shixun.update_attributes!(:use_scope => use_scope)
# 超级管理员和运营人员才能保存 中间层服务器pod信息的配置
if current_user.admin? || current_user.business?
@shixun.shixun_service_configs.destroy_all
@ -515,6 +514,103 @@ 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
# 如果存在实训,则直接进入实训
# 如果实训允许跳关传参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, repo_name: (is_choice_type ? "-1" : nil))
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')}")
@ -522,10 +618,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
@ -542,7 +634,6 @@ class ShixunsController < ApplicationController
# current_myshixun.update_column(:repo_name, repo_name)
# end
#
#
# # 如果存在实训,则直接进入实训
# # 如果实训允许跳关传参params[:challenge_id]跳入具体的关卡
# @current_task =
@ -571,159 +662,59 @@ 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
# logger.info("shixun_exec error: #{e.message}")
# if e.message != "ActiveRecord::RecordInvalid"
# logger.error("##########project_fork error #{e.message}")
# @myshixun.destroy!
# end
# raise "实训云平台繁忙繁忙等级81"
# end
# end
# end
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)
# 因为读写分离有延迟所以如果是重置来的请求可以先跳过重置过来的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
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
end
# 如果实训是纯选择题则不需要去fork仓库以及中间层的相关操作了
ActiveRecord::Base.transaction do
unless is_choice_type
# fork仓库
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}
uid_logger("openGameInstance params is #{params}")
interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
end
end
rescue Exception => e
logger.info("shixun_exec error: #{e.message}")
if e.message != "ActiveRecord::RecordInvalid"
logger.error("##########project_fork error #{e.message}")
@myshixun.destroy!
end
raise "实训云平台繁忙繁忙等级81"
end
end
end
# gameID 及实训ID
# status: 0 , 1 申请过, 2实训关卡路径未填 3 实训标签未填, 4 实训未创建关卡
def publish
@ -783,8 +774,8 @@ class ShixunsController < ApplicationController
school_name = "%#{params[:school_name].to_s.strip}%"
if user_name.present? || school_name.present?
@users = User.joins(user_extension: :school).where("users.id not in #{member_ids} AND users.status = 1 AND
(LOWER(users.lastname) LIKE ? or users.phone like ?) AND LOWER(schools.name) LIKE
?", user_name, user_name, school_name)
(LOWER(concat(users.lastname, users.firstname)) LIKE ? or users.phone like ?)
AND LOWER(schools.name) LIKE ?", user_name, user_name, school_name)
else
@users = User.none
end

@ -1,5 +1,5 @@
class StagesController < ApplicationController
before_action :require_login, :check_auth
before_action :require_login, :check_auth, except: [:index]
before_action :find_subject, only: [:create, :index]
before_action :find_stage, only: [:update, :destroy, :edit, :up_position, :down_position]
before_action :allowed, except: [:index]
@ -18,7 +18,7 @@ class StagesController < ApplicationController
@stage.position = @subject.stages.count + 1
@stage.save!
unless params[:shixun_id].blank?
shixuns = Shixun.where(id: params[:shixun_id])
shixuns = Shixun.where(id: params[:shixun_id]).order("field(id, #{params[:shixun_id].join(",")})")
shixuns.each do |shixun|
StageShixun.create!(stage_id: @stage.id, subject_id: @subject.id, shixun_id: shixun.id, position: @stage.stage_shixuns.count + 1)
end

@ -4,7 +4,7 @@ class StudentWorksController < ApplicationController
before_action :require_login, :check_auth
before_action :find_homework, only: [:new, :create, :search_member_list, :check_project, :relate_project,
:cancel_relate_project]
:cancel_relate_project, :delete_work]
before_action :find_work, only: [:shixun_work_report, :adjust_review_score, :shixun_work, :commit_des, :update_des,
:adjust_score, :show, :adjust_score, :supply_attachments, :revise_attachment,
:comment_list, :add_score, :add_score_reply, :destroy_score, :appeal_anonymous_score,
@ -15,12 +15,12 @@ class StudentWorksController < ApplicationController
before_action :teacher_allowed, only: [:adjust_score, :adjust_review_score, :deal_appeal_score]
before_action :course_student, only: [:new, :commit_des, :update_des, :create, :edit, :update, :search_member_list, :relate_project,
:cancel_relate_project, :relate_project]
:cancel_relate_project, :relate_project, :delete_work]
before_action :my_work, only: [:commit_des, :update_des, :edit, :update, :revise_attachment, :appeal_anonymous_score,
:cancel_appeal]
before_action :edit_duration, only: [:edit, :update]
before_action :edit_duration, only: [:edit, :update, :delete_work]
before_action :end_or_late, only: [:new, :create, :search_member_list, :commit_des, :update_des]
before_action :require_score_id, only: [:destroy_score, :add_score_reply, :appeal_anonymous_score, :deal_appeal_score, :cancel_appeal]
@ -60,6 +60,20 @@ class StudentWorksController < ApplicationController
@members = @members.page(page).per(limit).includes(:course_group, user: :user_extension)
end
def delete_work
begin
work = @homework.student_works.find_by!(user_id: params[:user_id])
work.update_attributes(description: nil, project_id: 0,
late_penalty: 0, work_status: 0,
commit_time: nil, update_time: nil, group_id: 0,
commit_user_id: nil, final_score: nil, work_score: nil, teacher_score: nil, teaching_asistant_score: nil)
normal_status("删除成功")
rescue Exception => e
uid_logger(e.message)
tip_exception(e.message)
end
end
def create
student_work = @homework.student_works.find_or_create_by(user_id: current_user.id)
@ -360,7 +374,7 @@ class StudentWorksController < ApplicationController
Tiding.create(user_id: @work.user_id, trigger_user_id: User.current.id, container_id: new_score.id,
container_type: "StudentWorksScore", parent_container_id: @work.id,
parent_container_type: "HomeworkCommon", belong_container_id: @homework.course_id,
belong_container_type: "Course", viewed: 0, tiding_type: "HomeworkCommon", extra: new_score.reviewer_role)
belong_container_type: "Course", viewed: 0, tiding_type: new_score.reviewer_role == 3 ? "System" : "HomeworkCommon", extra: new_score.reviewer_role)
case new_score.reviewer_role
when 1 #教师评分:最后一个教师评分为最终评分

@ -1,7 +1,7 @@
class SubjectsController < ApplicationController
before_action :require_login, :check_auth, except: [:index]
before_action :require_login, :check_auth, except: [:index, :show]
# before_action :check_auth, except: [:index]
before_action :check_account, only: [:new, :create]
before_action :check_account, except: [:index, :show]
before_action :find_subject, except: [:index, :create, :new, :append_to_stage]
before_action :allowed, only: [:update, :edit, :destroy, :publish, :cancel_publish, :cancel_has_publish,
:search_members, :add_subject_members, :statistics, :shixun_report, :school_report,
@ -25,13 +25,13 @@ class SubjectsController < ApplicationController
if reorder == "myshixun_count"
if select
@subjects = Subject.find_by_sql("SELECT subjects.id, subjects.user_id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status,
subjects.shixuns_count, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns
subjects.shixuns_count, subjects.excellent, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns
on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id where
subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%'
AND subjects.repertoire_id = #{select} GROUP BY subjects.id ORDER BY myshixun_member_count DESC")
else
@subjects = Subject.find_by_sql("SELECT subjects.id, subjects.user_id, subjects.name, subjects.stages_count, subjects.repertoire_id, subjects.status,
subjects.shixuns_count, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns
subjects.shixuns_count, subjects.excellent, sum(shixuns.myshixuns_count) AS myshixun_member_count FROM subjects join stage_shixuns
on stage_shixuns.subject_id = subjects.id join shixuns on shixuns.id = stage_shixuns.shixun_id where
subjects.hidden = 0 AND subjects.status = 2 AND subjects.name like '%#{search}%'
GROUP BY subjects.id ORDER BY myshixun_member_count DESC")
@ -81,6 +81,7 @@ class SubjectsController < ApplicationController
def show
@user = current_user
@is_creator = current_user.creator_of_subject?(@subject)
@is_manager = @user.manager_of_subject?(@subject)
# 合作团队
@members = @subject.subject_members.includes(:user)
@shixuns = @subject.shixuns.published.pluck(:id)
@ -222,7 +223,7 @@ class SubjectsController < ApplicationController
@subject.update_attributes(status: 1)
ApplyAction.create(container_type: "ApplySubject", container_id: @subject.id, user_id: current_user.id, status: 0)
begin
status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_subject' , name: '管理员')
status = Educoder::Sms.send(mobile: '18711011226', send_type:'publish_subject' , name: '管理员')
rescue => e
uid_logger_error("发送验证码出错: #{e}")
end
@ -281,7 +282,7 @@ class SubjectsController < ApplicationController
# 删除实训
# DELETE: /api/subejcts/:id/delete_member
def delete_member
tip_exception(403, "没权限操作") if !current_user.admin?
tip_exception(403, "没权限操作") unless current_user.manager_of_subject?(@subject)
tip_exception('用户id不能为空') if params[:user_id].blank?
user = @subject.subject_members.where(:user_id => params[:user_id], :role => 2).first
tip_exception("管理员用户不允许删除,或用户不存在") if user.blank?

@ -1,6 +1,7 @@
class TidingsController < ApplicationController
include PaginateHelper
before_action :require_login
after_action :update_onclick_time!, only: [:index]
def index

@ -0,0 +1,40 @@
class Users::BanksController < Users::BaseController
before_action :params_filter
def index
order = params[:order] || "updated_at"
sort = params[:sort] || "desc"
@banks = @object_type.classify.constantize.where(@object_filter)
@course_lists = CourseList.where(id: @banks.pluck(:course_list_id))
@banks = @banks.where(course_list_id: params[:tag_id]) unless params[:tag_id].blank?
@banks = @banks.order("#{order} #{sort}")
@banks_count = @banks.size
end
private
def params_filter
type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"]
tip_exception("object_type类型不正确") unless type.include?(params[:object_type])
# HomeworkBank 普通、分组作业题库ExerciseBank试卷、问卷题库GtaskBank毕设选题题库GtopicBank毕设任务题库
case params[:object_type]
when 'normal'
@object_type = "HomeworkBank"
@object_filter = "homework_type = 1" # 普通作业
when 'group'
@object_type = "HomeworkBank"
@object_filter = "homework_type = 3" # 分组作业
when 'poll'
@object_type = "ExerciseBank"
@object_filter = "container_type = 'Poll'" # 问卷
when 'exercise'
@object_type = "ExerciseBank"
@object_filter = "container_type = 'Exercise'" # 试卷
when 'gtask'
@object_type = "GtaskBank"
@object_filter = nil
when 'gtopic'
@object_type = "GtopicBank"
@object_filter = nil
end
end
end

@ -21,7 +21,7 @@ class Users::BaseController < ApplicationController
def private_user_resources!
require_login
return if current_user.admin? || observed_logged_user?
return if current_user.admin_or_business? || observed_logged_user?
render_forbidden
end
@ -43,7 +43,7 @@ class Users::BaseController < ApplicationController
page = page_value
per_page = per_page_value
return Kaminari.paginate_array(objs).page(page).per(per_page) unless observed_logged_user? && opts[:special]
return Kaminari.paginate_array(objs).page(page).per(per_page) unless opts[:special] && observed_logged_user?
# note: 为实现第一页少一条记录,让前端放置新建入口
if page == 1

@ -1,13 +1,16 @@
class Users::PrivateMessageDetailsController < Users::BaseController
before_action :require_login
before_action :private_user_resources!
after_action :update_message_status, only: [:show]
helper_method :target_user
def show
messages = observed_user.private_messages.without_deleted.where(target: target_user)
@count = messages.count
@messages = messages.order(send_time: :asc).includes(sender: :user_extension)
@messages = paginate messages.order(send_time: :desc).includes(sender: :user_extension)
end
private

@ -1,4 +1,5 @@
class Users::PrivateMessagesController < Users::BaseController
before_action :require_login
before_action :private_user_resources!
after_action :update_onclick_time!, only: [:index]
@ -9,6 +10,8 @@ class Users::PrivateMessagesController < Users::BaseController
query = "SELECT subquery.*, COUNT(*) message_count FROM (#{subquery}) subquery "\
"GROUP BY subquery.target_id ORDER BY subquery.send_time desc LIMIT #{limit_value} OFFSET #{offset_value}"
@messages = PrivateMessage.select('*').from("(#{query}) AS query").includes(target: :user_extension)
observed_user.private_messages.only_unread.update_all(status: 1)
end
def create

@ -1,4 +1,6 @@
class Users::ProjectsController < Users::BaseController
skip_before_action :check_observed_user_exists!, only: [:search]
def index
projects = Users::ProjectService.new(observed_user, query_params).call
@ -6,6 +8,15 @@ class Users::ProjectsController < Users::BaseController
@projects = paginate(projects.includes(:project_score, owner: { user_extension: :school }), special: true)
end
def search
query_params = { keyword: params[:keyword], category: 'manage' }
projects = Users::ProjectService.new(current_user, query_params).call
params[:limit] = params[:per_page].to_i.zero? ? 20 : params[:per_page].to_i
@count = projects.count
@projects = paginate projects
end
private
def query_params

@ -0,0 +1,26 @@
class Users::VideoAuthsController < Users::BaseController
before_action :private_user_resources!
def create
result = Videos::CreateAuthService.call(observed_user, create_params)
render_ok(data: result)
rescue Videos::CreateAuthService::Error => ex
render_error(ex.message)
end
def update
video = observed_user.videos.find_by(uuid: params[:video_id])
return render_error('该视频凭证不存在') if video.blank?
result = AliyunVod::Service.refresh_upload_video(video.uuid)
render_ok(data: result)
rescue AliyunVod::Error => _
render_error('刷新上传凭证失败')
end
private
def create_params
params.permit(:title, :file_name, :file_size, :description, :cover_url)
end
end

@ -0,0 +1,60 @@
class Users::VideosController < Users::BaseController
before_action :private_user_resources!
helper_method :current_video
def index
videos = Users::VideoQuery.call(observed_user, search_params)
@count = videos.count
@videos = paginate videos
end
def update
return render_error('该状态下不能编辑视频信息') unless current_video.published?
current_video.update!(title: params[:title])
AliyunVod::Service.update_video_info(current_video.uuid, Title: current_video.title) rescue nil
end
def cancel
video = observed_user.videos.find_by(uuid: params[:video_id])
return render_not_found if video.blank?
return render_error('该状态下不能删除视频') unless video.pending?
video.destroy!
AliyunVod::Service.delete_video([video.uuid]) rescue nil
render_ok
end
def review
params[:status] = 'processing'
videos = Users::VideoQuery.call(observed_user, params)
@count = videos.count
@videos = paginate videos
end
def batch_publish
Videos::BatchPublishService.call(observed_user, batch_publish_params)
render_ok
rescue Videos::BatchPublishService::Error => ex
render_error(ex.message)
end
private
def current_video
@_current_video ||= observed_user.videos.find_by(id: params[:id])
end
def search_params
params.permit(:keyword, :sort_by, :sort_direction)
end
def batch_publish_params
params.permit(videos: %i[video_id title])
end
end

@ -1,5 +1,5 @@
module CourseDecorator
def can_visited?
is_public == 1 || User.current.admin? || User.current.member_of_course?(self)
is_public == 1 || User.current.admin_or_business? || User.current.member_of_course?(self)
end
end

@ -2,6 +2,9 @@ module TidingDecorator
def content
method_name = "#{container_type.underscore}_content"
respond_to?(method_name) ? send(method_name) : ''
rescue => ex
Util.logger_error(ex)
''
end
def how_long_time
@ -27,6 +30,7 @@ module TidingDecorator
end
def strip_html(text, len = 0, suffix = "...")
text = text.to_s
str = ""
if !text.nil? && text.length > 0
str = text.gsub(/<\/?.*?>/, '').strip
@ -43,13 +47,13 @@ module TidingDecorator
# ================ 各种类消息内容方法 ================
def apply_user_authentication_content
return if trigger_user_id.zero?
t_user = trigger_user || User.find(1)
if tiding_type == 'Apply'
str1, str2 = if container.auth_type == 1
[trigger_user.show_real_name, trigger_user.ID_number]
[t_user.show_real_name, t_user.ID_number]
elsif container.auth_type == 2
ue = trigger_user.user_extension
ue = t_user.user_extension
[[ue.school&.name, ue.department&.name].join('_'), ue.identity_text]
end
I18n.t(locale_format(tiding_type, container.auth_type)) % [str1, str2]
@ -93,7 +97,7 @@ module TidingDecorator
elsif status == 2
I18n.t(locale_format(tiding_type, "#{status}_#{extra.nil?}"), reason: extra) % [name, second_name]
else
I18n.t(locale_format(tiding_type, status)) % [name, second_name]
I18n.t(locale_format(tiding_type, status), reason: extra) % [name, second_name]
end
end
@ -102,9 +106,9 @@ module TidingDecorator
if tiding_type == 'Apply'
I18n.t(locale_format(tiding_type)) % name
elsif status == 2
I18n.t(locale_format(tiding_type, "#{status}_#{extra.nil?}"), reason: extra) % name
I18n.t(locale_format(tiding_type, "#{status}_#{extra.nil?}"), name: name, reason: extra)
else
I18n.t(locale_format(tiding_type, status)) % name
I18n.t(locale_format(tiding_type, status), name: name, reason: extra)
end
end
@ -123,7 +127,11 @@ module TidingDecorator
end
def course_content
I18n.t(locale_format) % container.name
if tiding_type == 'Delete'
I18n.t(locale_format(tiding_type)) % extra
else
I18n.t(locale_format) % container.name
end
end
def shixun_content
@ -261,16 +269,16 @@ module TidingDecorator
def journal_content
case tiding_type
when 'Mentioned' then
I18n.t(locale_format(tiding_type)) % message_content_helper(container.notes)
I18n.t(locale_format(tiding_type)) % message_content_helper(container&.notes)
when 'Comment' then
I18n.t(locale_format(tiding_type, container.parent.present?)) % message_content_helper(container.notes)
I18n.t(locale_format(tiding_type, container.parent.present?)) % message_content_helper(container&.notes)
else
I18n.t(locale_format) % container.issue.subject
I18n.t(locale_format) % container&.issue&.subject
end
end
def issue_content
I18n.t(locale_format) % container.subject
I18n.t(locale_format) % container&.subject
end
def pull_request_content
@ -291,15 +299,15 @@ module TidingDecorator
end
def poll_content
I18n.t(locale_format(parent_container_type)) % container.polls_name
I18n.t(locale_format(parent_container_type)) % container&.polls_name
end
def exercise_content
I18n.t(locale_format(parent_container_type)) % container.exercise_name
I18n.t(locale_format(parent_container_type)) % container&.exercise_name
end
def student_graduation_topic_content
I18n.t(locale_format) % container.graduation_topic.try(:name)
I18n.t(locale_format) % container&.graduation_topic.try(:name)
end
def deal_student_topic_select_content
@ -307,27 +315,27 @@ module TidingDecorator
end
def graduation_task_content
I18n.t(locale_format(parent_container_type)) % container.name
I18n.t(locale_format(parent_container_type)) % container&.name
end
def graduation_work_content
I18n.t(locale_format(extra.nil?)) % container.graduation_task.try(:name)
I18n.t(locale_format(extra.nil?)) % container&.graduation_task.try(:name)
end
def graduation_work_score_content
I18n.t(locale_format) % container.graduation_work.graduation_task.try(:name)
I18n.t(locale_format) % container&.graduation_work&.graduation_task.try(:name)
end
def homework_common_content
I18n.t(locale_format(parent_container_type), name: container.name, reason: extra)
I18n.t(locale_format(parent_container_type), name: container&.name, reason: extra)
end
def student_work_content
I18n.t(locale_format(extra.nil?)) % container.homework_common.try(:name)
I18n.t(locale_format(extra.nil?)) % container&.homework_common.try(:name)
end
def student_works_score_content
I18n.t(locale_format(extra)) % container.student_work.homework_common.try(:name)
I18n.t(locale_format(extra)) % container&.student_work&.homework_common.try(:name)
end
def challenge_work_score_content
@ -364,4 +372,12 @@ module TidingDecorator
I18n.t(locale_format(tiding_type)) % [container.try(:title) || extra]
end
end
def video_content
if tiding_type == 'System'
I18n.t(locale_format(tiding_type, status), reason: extra) % container.try(:title)
else
I18n.t(locale_format(tiding_type)) % [container.try(:title) || extra]
end
end
end

@ -0,0 +1,5 @@
module VideoDecorator
extend ApplicationDecorator
display_time_method :published_at, :created_at, :updated_at
end

@ -5,8 +5,8 @@ class Users::UpdateAccountForm
attr_accessor :nickname, :name, :show_realname, :gender, :location, :location_city,
:identity, :student_id, :technical_title, :school_id, :department_id
validates :nickname, presence: true
validates :name, presence: true
validates :nickname, presence: true, length: { maximum: 20 }
validates :name, presence: true, length: { maximum: 10 }
validates :gender, presence: true, numericality: { only_integer: true }, inclusion: { in: [0, 1] }
validates :location, presence: true
validates :location_city, presence: true

@ -62,15 +62,18 @@ module ApplicationHelper
# shixun开启挑战对应的行为名及url
def task_operation_url current_myshixun, shixun
url = "/shixuns/#{shixun.identifier}/shixun_exec"
name =
if current_myshixun.blank?
shixun.status == 0 ? "模拟实战" : "开启挑战"
elsif current_myshixun.status == 1
"查看实战"
if current_myshixun.blank?
name = shixun.status == 0 ? "模拟实战" : "开启挑战"
url = "/shixuns/#{shixun.identifier}/shixun_exec"
else
identifier = current_myshixun.current_task(current_myshixun.games).try(:identifier)
if current_myshixun.status == 1
name = "查看实战"
else
"继续挑战"
name = "继续挑战"
end
url = identifier
end
[name, url]
end
@ -329,6 +332,23 @@ module ApplicationHelper
content
end
def strip_html(text, len=0, endss="...")
ss = ""
if !text.nil? && text.length>0
ss=text.gsub(/<\/?.*?>/, '').strip
ss = ss.gsub(/&nbsp;*/, '')
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
def strip_export_title(content)
con_ = ""
if content.length > 0

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

@ -28,6 +28,10 @@ module CoursesHelper
def module_url mod, course
return nil if mod.blank? or course.blank?
case mod.module_type
when "announcement"
"/courses/#{course.id}/informs"
when "online_learning"
"/courses/#{course.id}/online_learning"
when "shixun_homework"
"/courses/#{course.id}/shixun_homeworks/#{mod.id}"
when "common_homework"
@ -194,7 +198,7 @@ module CoursesHelper
# 获取课堂的资源数
def get_attachment_count(course, category_id)
course.attachments.where(course_second_category_id: category_id).size
category_id.to_i == 0 ? course.attachments.size : course.attachments.where(course_second_category_id: category_id).size
end
# 获取课堂的作业数
@ -261,4 +265,10 @@ module CoursesHelper
group_info
end
def last_subject_shixun user_id, subject
myshixun = Myshixun.where(user_id: user_id, shixun_id: subject&.shixuns).order("updated_at desc").first
return "" unless myshixun
stage_shixun = subject&.stage_shixuns.where(shixun_id: myshixun.shixun_id).take
progress = stage_shixun&.position.to_s + "-" + stage_shixun&.position.to_s + " " + myshixun.shixun&.name
end
end

@ -146,8 +146,8 @@ module ExportHelper
w_6 = "--"
end
w_7 = w.work_status == 0 ? '--' : myshixun.try(:passed_count).to_s+"/"+shixun.challenges_count.to_s
w_8 = myshixun ? myshixun.try(:passed_time) == "--" ? "--" : format_time(myshixun.try(:passed_time)) : "--" # 通关时间
w_9 = myshixun ? (myshixun.try(:passed_count) > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时
w_8 = myshixun ? myshixun.try(:passed_time).to_s == "--" ? "--" : format_time(myshixun.try(:passed_time)) : "--" # 通关时间
w_9 = myshixun ? (myshixun.try(:passed_count).to_i > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时
w_10 = myshixun ? myshixun.output_times : 0 #评测次数
w_11 = myshixun ? myshixun.total_score : "--" #获得经验值
w_12 = w.final_score.present? ? w.final_score : 0
@ -543,7 +543,7 @@ module ExportHelper
end
def format_sheet_name name
name = name.gsub(":", "-")
name = name.gsub(":", "-").gsub("/", "_")
end
def rename_same_file(name, index)

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

@ -6,7 +6,7 @@ module GamesHelper
end
# 获取目录下所有文件,返回一个文件名的数组 type是查看文件的类型image表示图片
# type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"]]
# type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"], [5, "mp3"], [6, "mp4"]]
def get_dir_filename(path, type, game_id)
answer_picture = []
return answer_picture unless File.directory?(path)
@ -39,6 +39,12 @@ module GamesHelper
end
f.close
@type = 'txt'
elsif extension == 'mp3' && type == 5
answer_picture << file
@type = 'mp3'
elsif extension == 'mp4' && type == 6
answer_picture << file
@type = 'mp4'
end
end
@ -51,4 +57,21 @@ module GamesHelper
"编译失败,请在测试结果中查看具体的错误信息" : test_set.try(:actual_output)
end
end
def shixun_show_type type
case type.to_i
when 1
"image"
when 2
"apk/exe"
when 3
"txt"
when 4
"html"
when 5
"mp3"
when 6
"mp4"
end
end
end

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

@ -2,7 +2,7 @@ module StagesHelper
# 章节实训的通关情况
def stage_myshixun_status shixun, user
myshixun = Myshixun.where(user_id: user.id, shixun_id: shixun.id).first
myshixun = Myshixun.where(user_id: user.id, shixun_id: shixun.id).take
myshixun.try(:status) == 1 ? 1 : 0
end

@ -103,6 +103,10 @@ module StudentWorksHelper
# 对结果进行排序
efficiency_list =
results.sort {|x, y| x[:efficiency] <=> y[:efficiency]}.each_with_index.map do |result, index|
if result[:user_id] == work.user.id
myself_eff = [index+1, result[:efficiency]]
myself_object = [result[:consume_time], result[:eff_score], result[:round_size]]
end
[index + 1, result[:efficiency], result[:user_id]]
end

@ -0,0 +1,2 @@
module Users::BanksHelper
end

@ -11,7 +11,7 @@ class ApplyTeacherRoleJoinCourseNotifyJob < ApplicationJob
belong_container_type tiding_type extra created_at updated_at]
same_attrs = {
trigger_user_id: user.id, container_id: course.id, container_type: 'JoinCourse',
trigger_user_id: user.id, container_id: course.id, container_type: 'JoinCourse', status: 0,
belong_container_id: course.id, belong_container_type: 'Course', tiding_type: 'Apply', extra: role
}
Tiding.bulk_insert(*attrs) do |worker|

@ -0,0 +1,23 @@
# 批量发布视频 消息任务
class BatchPublishVideoNotifyJob < ApplicationJob
queue_as :notify
def perform(user_id, video_ids)
user = User.find_by(id: user_id)
return if user.blank?
attrs = %i[user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
same_attrs = {
user_id: 1,
trigger_user_id: user.id,
container_type: 'Video',
tiding_type: 'Apply', status: 0
}
Tiding.bulk_insert(*attrs) do |worker|
user.videos.where(id: video_ids).each do |video|
worker.add same_attrs.merge(container_id: video.id)
end
end
end
end

@ -0,0 +1,26 @@
class CommitExercsieNotifyJobJob < ApplicationJob
queue_as :notify
def perform(exercise_id, user_id)
exercise = Exercise.find_by(id: exercise_id)
user = User.find_by(id: user_id)
return if [exercise, user].any?(&:blank?)
course = exercise.course
attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type tiding_type viewed status created_at updated_at]
same_attrs = {
trigger_user_id: user.id,
container_id: exercise.id, container_type: 'Exercise',
parent_container_id: exercise.id, parent_container_type: 'CommitExercise',
belong_container_id: course.id, belong_container_type: 'Course',
tiding_type: 'Exercise', viewed: 0, status: 0
}
Tiding.bulk_insert(*attrs) do |worker|
course.course_member(user).member_teachers.each do |teacher|
worker.add same_attrs.merge(user_id: teacher.user_id)
end
end
end
end

@ -0,0 +1,26 @@
class CommitPollNotifyJobJob < ApplicationJob
queue_as :notify
def perform(poll_id, user_id)
poll = Poll.find_by(id: poll_id)
user = User.find_by(id: user_id)
return if [poll, user].any?(&:blank?)
course = poll.course
attrs = %i[user_id trigger_user_id container_id container_type parent_container_id parent_container_type
belong_container_id belong_container_type tiding_type viewed status created_at updated_at]
same_attrs = {
trigger_user_id: user.id,
container_id: poll.id, container_type: 'Poll',
parent_container_id: poll.id, parent_container_type: 'CommitPoll',
belong_container_id: course.id, belong_container_type: 'Course',
tiding_type: 'Poll', viewed: 0, status: 0
}
Tiding.bulk_insert(*attrs) do |worker|
course.course_member(user).member_teachers.each do |teacher|
worker.add same_attrs.merge(user_id: teacher.user_id)
end
end
end
end

@ -0,0 +1,17 @@
# 获取阿里云视频信息
class GetAliyunVideoInfoJob < ApplicationJob
queue_as :default
def perform(vod_video_id)
video = Video.find_by(uuid: vod_video_id)
return if video.blank? || video.vod_uploading?
result = AliyunVod::Service.get_play_info(video.uuid)
cover_url = result.dig('VideoBase', 'CoverURL')
file_url = (result.dig('PlayInfoList', 'PlayInfo') || []).first&.[]('PlayURL')
video.cover_url = cover_url if cover_url.present? && video.cover_url.blank?
video.file_url = file_url if file_url.present?
video.save!
end
end

@ -19,11 +19,20 @@ class StudentWorkScoreAppealNotifyJob < ApplicationJob
belong_container_id: course.id, belong_container_type: 'Course',
tiding_type: 'HomeworkCommon', viewed: 0, status: 0
}
student_same_attrs = {
trigger_user_id: 0,
container_id: appeal.id, container_type: 'StudentWorksScoresAppeal',
parent_container_id: score.student_work_id, parent_container_type: 'StudentWork',
belong_container_id: course.id, belong_container_type: 'Course',
tiding_type: 'System', viewed: 0, status: 0
}
Tiding.bulk_insert(*attrs) do |worker|
course.course_member(user).member_teachers.each do |teacher|
worker.add same_attrs.merge(user_id: teacher.user_id)
end
worker.add same_attrs.merge(user_id: score.user_id)
worker.add student_same_attrs.merge(user_id: score.user_id)
end
end
end

@ -0,0 +1,5 @@
module AliyunVod
class << self
attr_accessor :access_key_id, :access_key_secret, :base_url, :cate_id, :callback_url, :signature_key
end
end

@ -0,0 +1,2 @@
class AliyunVod::Error < StandardError
end

@ -0,0 +1,8 @@
module AliyunVod::Service
extend AliyunVod::Service::Base
extend AliyunVod::Service::VideoUpload
extend AliyunVod::Service::VideoProcess
extend AliyunVod::Service::VideoManage
extend AliyunVod::Service::VideoPlay
end

@ -0,0 +1,46 @@
module AliyunVod::Service::Base
def request(method, params)
params = AliyunVod::Sign.format_params(params.compact) # 多层hash需要预先处理保证值为string
params[:Signature] = AliyunVod::Sign.generate(params, method: method.to_s.upcase)
Rails.logger.info("[AliyunVod] request => method: #{method}, params: #{params}")
response = Faraday.public_send(method, AliyunVod.base_url, params)
result = JSON.parse(response.body)
Rails.logger.info("[AliyunVod] response => status: #{response.status}, result: #{result}")
raise AliyunVod::Error, result['Code'] if response.status != 200
result
rescue => ex
::Util.logger_error(ex)
raise AliyunVod::Error, ex.message
end
def base_params
{
AccessKeyId: AliyunVod.access_key_id,
Format: 'JSON',
Version: '2017-03-21',
SignatureMethod: 'HMAC-SHA1',
SignatureVersion: '1.0',
SignatureNonce: signature_nonce,
Timestamp: timestamp,
UserData: user_data
}
end
def user_data
{ MessageCallback: { CallbackURL: AliyunVod.callback_url } }
end
def timestamp
Time.now.utc.iso8601
end
def signature_nonce
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
chars.sample(16).join('')
end
end

@ -0,0 +1,40 @@
# 视频管理
module AliyunVod::Service::VideoManage
# 修改视频信息
def update_video_info(video_id, **opts)
params = {
Action: 'UpdateVideoInfo',
VideoId: video_id
}.merge(base_params)
params = opts.merge(params)
result = request(:post, params)
result
end
# 获取视频信息
def get_video_info(video_id)
params = {
Action: 'GetVideoInfo',
VideoId: video_id
}.merge(base_params)
result = request(:post, params)
result
end
# 删除视频信息
def delete_video(video_ids)
params = {
Action: 'DeleteVideo',
VideoIds: video_ids.join(',')
}.merge(base_params)
result = request(:post, params)
result
end
end

@ -0,0 +1,17 @@
# 视频播放
module AliyunVod::Service::VideoPlay
# 获取视频播放地址
# https://help.aliyun.com/document_detail/56124.html?spm=a2c4g.11186623.6.715.4d7e2d52dU1CTK
def get_play_info(video_id, **opts)
params = {
Action: 'GetPlayInfo',
VideoId: video_id
}.merge(base_params)
params = opts.merge(params)
result = request(:post, params)
result
end
end

@ -0,0 +1,17 @@
# 视频处理
module AliyunVod::Service::VideoProcess
# 提交媒体截图作业
def submit_snapshot_job(video_id, **opts)
params = {
Action: 'SubmitSnapshotJob',
VideoId: video_id
}.merge(base_params)
params = opts.merge(params)
result = request(:post, params)
raise AliyunVod::Error, '提交媒体截图作业失败' if result['SnapshotJob'].blank?
result
end
end

@ -0,0 +1,37 @@
# 视频上传
module AliyunVod::Service::VideoUpload
# 获取视频上传地址和凭证
def create_upload_video(title, filename, **opts)
params = {
Action: 'CreateUploadVideo',
Title: title,
FileName: filename
}.merge(base_params)
# 分类
cate_id = AliyunVod.cate_id
params[:CateId] = cate_id if cate_id.present?
params = opts.merge(params)
result = request(:post, params)
raise AliyunVod::Error, '获取上传凭证失败' if result['UploadAddress'].blank?
result
end
# 刷新视频上传凭证
def refresh_upload_video(video_id)
params = {
Action: 'RefreshUploadVideo',
VideoId: video_id
}.merge(base_params)
result = request(:post, params)
raise AliyunVod::Error, '刷新上传凭证失败' if result['UploadAddress'].blank?
result
end
end

@ -0,0 +1,41 @@
module AliyunVod::Sign
# https://help.aliyun.com/document_detail/44434.html?spm=a2c4g.11186623.2.16.354c7853oqlhMb&/#SignatureNonce
def self.generate(params, **opts)
method = opts[:method] || 'POST'
key = opts[:key] || AliyunVod.access_key_secret + '&'
digest = OpenSSL::Digest.new('sha1')
str = params_to_string(params)
str = percent_encode(str)
str = "#{method}&%2F&#{str}"
Base64.encode64(OpenSSL::HMAC.digest(digest, key, str)).gsub(/\n/, '')
end
def self.verify?(signature, timestamp)
content = "#{AliyunVod.callback_url}|#{timestamp}|#{AliyunVod.signature_key}"
our_signature = Digest::MD5.hexdigest(content)
ActiveSupport::SecurityUtils.secure_compare(signature, our_signature)
end
def self.params_to_string(params)
params.sort.map { |k, v| "#{percent_encode(k)}=#{percent_encode(v)}" }.join('&')
end
def self.percent_encode(str)
return '' if str.blank?
CGI::escape(str.to_s).gsub(/\+/,'%20').gsub(/\*/,'%2A').gsub(/%7E/,'~')
end
def self.format_params(params)
params.each_with_object({}) do |arr, obj|
obj[arr[0]] = arr[1].is_a?(Hash) ? parse_hash_to_str(arr[1]) : arr[1]
end
end
def self.parse_hash_to_str(hash)
hash.each_with_object({}) do |h, obj|
obj[h[0]] = h[1].is_a?(Hash) ? parse_hash_to_str(h[1].clone) : h[1].to_s
end.to_json
end
end

@ -9,6 +9,7 @@ class ApplyAddSchool < ApplicationRecord
private
def send_notify
tidings.create!(user_id: 1, status: 0, trigger_user_id: user_id, belong_container: school, tiding_type: 'Apply')
Tiding.create!(user_id: 1, status: 0, container_id: id, container_type: 'ApplyAddSchools',
trigger_user_id: user_id, belong_container: school, tiding_type: 'Apply')
end
end

@ -3,8 +3,18 @@
class ApplyUserAuthentication < ApplicationRecord
belongs_to :user
has_many :tidings, :as => :container, :dependent => :destroy
scope :real_name_auth, -> { where(auth_type: 1) }
scope :professional_auth, -> { where(auth_type: 2) }
scope :processing, -> { where(status: 0) }
scope :passed, -> { where(status: 1) }
after_create :send_tiding
private
def send_tiding
self.tidings << Tiding.new(:user_id => '1', :status=> 0, :trigger_user_id => user_id, :belong_container_id => 1, :belong_container_type =>'User', :tiding_type => "Apply")
end
end

@ -5,7 +5,7 @@ class BiddingUser < ApplicationRecord
belongs_to :project_package, counter_cache: true
aasm(:status) do
state :pending, initiali: true
state :pending, initial: true
state :bidding_won
state :bidding_lost

@ -1,6 +1,6 @@
class Challenge < ApplicationRecord
# difficulty: 关卡难度: 1.简单 2.中等 3.困难
default_scope { order("challenges.position asc") }
# show_type: 效果展示:-1.无效果 1.图片 2.apk/exe 3.txt 4.html 5.mp3 6.mp4
belongs_to :shixun, :touch => true, counter_cache: true
belongs_to :user

@ -5,7 +5,11 @@ class Course < ApplicationRecord
belongs_to :teacher, class_name: 'User', foreign_key: :tea_id # 定义一个方法teacher该方法通过tea_id来调用User表
belongs_to :school, class_name: 'School', foreign_key: :school_id #定义一个方法school该方法通过school_id来调用School表
belongs_to :course_list
belongs_to :course_list, optional: true
# 所属实践课程
belongs_to :subject, optional: true
has_one :inform, as: :container, dependent: :destroy
has_many :course_infos, dependent: :destroy
# 课堂左侧导航栏的模块
@ -87,7 +91,7 @@ class Course < ApplicationRecord
NORMAL = 6 # 普通用户
Anonymous = 7 # 普未登录
validates :name, presence: true, length: { maximum: 30 }
validates :name, presence: true, length: { maximum: 60 }
after_create :create_board_sync, :act_as_course_activity, :send_tiding
@ -176,7 +180,7 @@ class Course < ApplicationRecord
end
def all_course_module_types
%w[activity shixun_homework common_homework group_homework graduation exercise poll attachment board course_group]
%w[activity announcement online_learning shixun_homework common_homework group_homework graduation exercise poll attachment board course_group]
end
def get_course_module_by_type(type)
@ -327,13 +331,15 @@ class Course < ApplicationRecord
#创建课程后,给该用户发送消息
def send_tiding
self.tidings << Tiding.new(user_id: tea_id, trigger_user_id: tea_id, belong_container_id: id,
self.tidings << Tiding.new(user_id: tea_id, trigger_user_id: 1, belong_container_id: id,
belong_container_type: 'Course', tiding_type: 'System')
end
def get_name_by_type(type)
case type
when 'activity' then '动态'
when 'announcement' then '公告栏'
when 'online_learning' then '在线学习'
when 'shixun_homework' then '实训作业'
when 'common_homework' then '普通作业'
when 'group_homework' then '分组作业'
@ -350,15 +356,17 @@ class Course < ApplicationRecord
def get_position_by_type(type)
case type
when 'activity' then 1
when 'shixun_homework' then 2
when 'common_homework' then 3
when 'group_homework' then 4
when 'graduation' then 5
when 'exercise' then 6
when 'poll' then 7
when 'attachment' then 8
when 'board' then 9
when 'course_group' then 10
when 'announcement' then 2
when 'online_learning' then 3
when 'shixun_homework' then 4
when 'common_homework' then 5
when 'group_homework' then 6
when 'graduation' then 7
when 'exercise' then 8
when 'poll' then 9
when 'attachment' then 10
when 'board' then 11
when 'course_group' then 12
else 100
end
end

@ -8,7 +8,7 @@ class CourseGroup < ApplicationRecord
has_many :homework_group_reviews, :dependent => :destroy
scope :by_group_ids, lambda { |ids| where(id: ids)}
validates :name, length: { maximum: 20 }
validates :name, length: { maximum: 60 }
after_create :generate_invite_code

@ -11,7 +11,7 @@ class CourseMessage < ApplicationRecord
def pass!
update!(status: :PASSED)
send_deal_tiding
send_deal_tiding(1)
end
def application_user
@ -20,16 +20,16 @@ class CourseMessage < ApplicationRecord
def reject!
update!(status: :REJECTED)
send_deal_tiding
send_deal_tiding(2)
end
private
def send_deal_tiding
def send_deal_tiding deal_status
# 发送申请处理结果消息
Tiding.create!(
user_id: user_id, trigger_user: User.current, container_id: course_id, container_type: 'DealCourse',
belong_container: course, extra: content.to_i == 2 ? '7' : '9', tiding_type: 'System', status: status == :PASSED ? 1 : 2
user_id: course_message_id, trigger_user_id: 1, container_id: course_id, container_type: 'DealCourse',
belong_container: course, extra: content.to_i == 2 ? '9' : '7', tiding_type: 'System', status: deal_status
)
# 将申请消息置为已处理
Tiding.where(trigger_user_id: user_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1)

@ -8,6 +8,7 @@ class Discuss < ApplicationRecord
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_many :tidings, as: :container, dependent: :destroy
has_one :praise_tread_cache, as: :object, dependent: :destroy
belongs_to :dis, polymorphic: true
belongs_to :challenge
after_create :send_tiding
@ -44,6 +45,10 @@ class Discuss < ApplicationRecord
Discuss.where(parent_id: self.id).includes(:user).reorder(created_at: :asc)
end
def child_discuss_count
Discuss.where(root_id: id).count
end
private
def send_tiding

@ -264,4 +264,30 @@ class HomeworkCommon < ApplicationRecord
def challenge_score challenge_id
homework_challenge_settings.find_by(challenge_id: challenge_id)&.score.to_f
end
def update_homework_work_score
if unified_setting
works = student_works
user_ids = course.students.pluck(:user_id)
else
user_ids = course.students.where(course_group_id: published_settings.pluck(:course_group_id)).pluck(:user_id)
works = student_works.where(user_id: user_ids)
end
works = works.includes(:challenge_work_scores)
challenge_settings = homework_challenge_settings
challenge_setting_ids = challenge_settings.pluck(:challenge_id)
myshixuns = Myshixun.where(shixun_id: homework_commons_shixun&.shixun_id, user_id: user_ids).includes(:games)
myshixuns.find_each(batch_size: 100) do |myshixun|
work = works.select{|work| work.user_id == myshixun.user_id}.first
if work && myshixun
games = myshixun.games.select{|game| challenge_setting_ids.include?(game.challenge_id)}
HomeworksService.new.update_myshixun_work_score work, myshixun, games, self, challenge_settings
end
end
HomeworksService.new.update_student_eff_score(self) if (allow_late && late_time < Time.now) ||
(!allow_late && end_time < Time.now)
update_attribute('calculation_time', Time.now)
end
end

@ -0,0 +1,3 @@
class Inform < ApplicationRecord
belongs_to :container, polymorphic: true, optional: true
end

@ -11,6 +11,7 @@ class JournalsForMessage < ApplicationRecord
scope :parent_comment, -> { where(m_parent_id: nil)}
scope :search_by_jour_type, lambda{|type,ids| where(jour_type:type,jour_id: ids)}
has_many :tidings, as: :container, dependent: :destroy
# "jour_type", # 留言所属类型
# "jour_id", # 留言所属类型的id
@ -25,6 +26,8 @@ class JournalsForMessage < ApplicationRecord
# "is_comprehensive_evaluation", # 1 教师评论、2 匿评、3 留言
# "hidden", 隐藏
after_create :send_tiding
# course_identity 课堂用户身份
def contents_show course_identity
@ -47,4 +50,29 @@ class JournalsForMessage < ApplicationRecord
JournalsForMessage.includes(:user).where(m_parent_id: self.id).page(page).per(limit).reorder("created_on asc")
end
def send_tiding
# 回复和@同一个人时:只发@的消息(因@的消息先创建)
case self.jour_type
# 用户留言当做私信处理 不发消息
when "Principal"
=begin
user_id = self.m_parent_id.present? ? JournalsForMessage.find(self.m_parent_id).user_id : self.jour_id
if user_id != self.user_id && !self.tidings.where(:user_id => user_id, :trigger_user_id => self.user_id, :tiding_type => "Mentioned").first.present?
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => user_id, :parent_container_id => self.jour_id, :parent_container_type => self.jour_type, :belong_container_id => self.jour_id, :belong_container_type => "User", :viewed => 0, :tiding_type => self.m_parent_id.present? ? "Comment" : "Journal")
end
=end
when "HomeworkCommon", "GraduationTopic"
user_id = self.m_parent_id.present? ? JournalsForMessage.find(self.m_parent_id).user_id : (self.jour_type == "HomeworkCommon" ? self.jour.user_id : self.jour.tea_id)
if user_id != self.user_id && !self.tidings.where(:user_id => user_id, :trigger_user_id => self.user_id, :tiding_type => "Mentioned").first.present?
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => user_id, :parent_container_id => self.jour_id, :parent_container_type => self.jour_type, :belong_container_id => self.jour.course_id, :belong_container_type => "Course", :viewed => 0, :tiding_type => "Comment")
end
when "StudentWorksScore"
course_id = self.jour.try(:student_work).try(:homework_common).try(:course_id)
user_id = self.m_parent_id.present? ? JournalsForMessage.find(self.m_parent_id).user_id : self.jour.user_id
if user_id != self.user_id && !self.tidings.where(:user_id => user_id, :trigger_user_id => self.user_id, :tiding_type => "Mentioned").first.present?
self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => user_id, :parent_container_id => self.jour_id, :parent_container_type => self.jour_type, :belong_container_id => course_id, :belong_container_type => "Course", :viewed => 0, :tiding_type => "Comment")
end
end
end
end

@ -10,11 +10,13 @@ class Library < ApplicationRecord
has_many :attachments, as: :container
has_one :praise_tread_cache, foreign_key: :object_id
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
validates :uuid, presence: true, uniqueness: true
aasm(:status) do
state :pending, initiali: true
state :pending, initial: true
state :processing
state :refused
state :published
@ -32,6 +34,10 @@ class Library < ApplicationRecord
end
end
def increment_visited_count!(num = 1)
increment_column!(:visited_count, num)
end
def generate_uuid
uuid = Util::UUID.time_uuid
while Library.exists?(uuid: uuid)
@ -40,4 +46,10 @@ class Library < ApplicationRecord
self.uuid = uuid
end
private
def increment_column!(column, num = 1)
self.class.connection.execute("update #{self.class.table_name} set #{column} = COALESCE(#{column}, 0) + #{num} where id = #{id}")
end
end

@ -4,7 +4,7 @@ class LibraryApply < ApplicationRecord
belongs_to :library
aasm(:status) do
state :pending, initiali: true
state :pending, initial: true
state :refused
state :agreed

@ -6,7 +6,7 @@ class Memo < ApplicationRecord
has_many :memo_tag_repertoires, dependent: :destroy
has_many :tag_repertoires, :through => :memo_tag_repertoires
has_many :praise_tread, as: :praise_tread_object, dependent: :destroy
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_one :praise_tread_cache, as: :object, dependent: :destroy
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
@ -14,6 +14,8 @@ class Memo < ApplicationRecord
has_many :descendants, foreign_key: :root_id, class_name: 'Memo'
has_many :children, foreign_key: :parent_id, class_name: 'Memo'
has_many :attachments, as: :container, dependent: :destroy
has_many :tidings, as: :container, dependent: :destroy
scope :field_for_list, lambda{
select([:id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id])

@ -82,7 +82,7 @@ class Myshixun < ApplicationRecord
# 通关时间
def passed_time
self.status == 1 ? self.games.map(&:end_time).max : "--"
self.status == 1 ? self.games.select{|game| game.status == 2}.map(&:end_time).max : "--"
end
# 耗时

@ -0,0 +1,3 @@
class Partner < ApplicationRecord
has_many :users
end

@ -17,7 +17,7 @@ class ProjectPackage < ApplicationRecord
scope :invisible, -> { where(status: %i[pending applying refused]) }
aasm(:status) do
state :pending, initiali: true
state :pending, initial: true
state :applying
state :refused
state :published

@ -4,7 +4,7 @@ class ProjectPackageApply < ApplicationRecord
belongs_to :project_package
aasm(:status) do
state :pending, initiali: true
state :pending, initial: true
state :refused
state :agreed

@ -21,8 +21,8 @@ module Searchable::Course
def to_searchable_json
{
id: id,
author_name: teacher.real_name,
author_school_name: teacher.school_name,
author_name: teacher&.real_name,
author_school_name: teacher&.school_name,
visits_count: visits,
members_count: members_count,
is_public: is_public == 1

@ -17,6 +17,7 @@ module Searchable::Dependents::User
# reindex subject
created_subjects.each(&:reindex)
subjects.each(&:reindex)
end
end
end

@ -27,6 +27,7 @@ module Searchable::Subject
{
author_name: user.real_name,
author_school_name: user.school_name,
member_user_names: users.map(&:real_name).join(' ')
}
end
@ -43,7 +44,8 @@ module Searchable::Subject
author_school_name: user.school_name,
visits_count: visits,
stage_count: stages_count,
stage_shixuns_count: stage_shixuns_count
stage_shixuns_count: stage_shixuns_count,
shixuns_count: shixuns_count
}
end

@ -5,7 +5,7 @@ class Shixun < ApplicationRecord
# hide_code 隐藏代码窗口
# code_hidden: 隐藏代码目录
# task_pass: 跳关
has_many :challenges, dependent: :destroy
has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy
has_many :challenge_tags, through: :challenges
has_many :myshixuns, :dependent => :destroy
has_many :shixun_members, dependent: :destroy
@ -38,6 +38,7 @@ class Shixun < ApplicationRecord
belongs_to :user
# 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy
has_many :tidings, as: :container, dependent: :destroy
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{keyword}%", "%#{keyword}%") }
@ -62,6 +63,8 @@ class Shixun < ApplicationRecord
scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) }
scope :find_by_ids,lambda{|k| where(id:k)}
after_create :send_tiding
# REDO: 
def propaedeutics
shixun_info.try(:propaedeutics)
@ -242,4 +245,15 @@ class Shixun < ApplicationRecord
def finished_challenges_count(user)
Game.joins(:myshixun).where(user_id: user.id, status: 2, myshixuns: { shixun_id: id }).count
end
def has_web_route?
self.mirror_name.include?('JavaWeb') || self.mirror_name.include?('PHP') && self.mirror_name.include?('Mysql') || self.mirror_name.include?('Web')
end
private
def send_tiding
self.tidings << Tiding.new(:user_id => user_id, :trigger_user_id => 1, :belong_container_id => id, :belong_container_type =>'Shixun', :tiding_type => "System", :viewed => 0)
end
end

@ -17,7 +17,12 @@ class StudentGraduationTopic < ApplicationRecord
scope :is_refused, -> {where(status: 2)}
scope :is_accepted, -> {where(status: 1)}
scope :is_accepting, -> {where(status: 0)}
after_create :send_tiding
def send_tiding
self.tidings << Tiding.new(:user_id => self.graduation_topic.tea_id, :trigger_user_id => self.user_id, :parent_container_id => self.graduation_topic_id, :parent_container_type => "GraduationTopic",
:belong_container_id => self.graduation_topic.course_id, :belong_container_type => "Course", :viewed => 0, :status => 0, :tiding_type => "GraduationTopic")
end
# 学生名称
def name

@ -123,10 +123,10 @@ class StudentWork < ApplicationRecord
# 更新作品成绩
def set_work_score
if work_status > 0 && homework_common && homework_common.homework_detail_manual && !self.ultimate_score
if work_status > 0 && homework_common && !self.ultimate_score
case homework_common.homework_type
when "normal", "group"
if !homework_common.homework_detail_manual.final_mode
if !homework_common&.homework_detail_manual&.final_mode
tea_ass_proportion = homework_common.homework_detail_manual.ta_proportion
tea_proportion = homework_common.homework_detail_manual.te_proportion
if self.teacher_score

@ -18,6 +18,9 @@ class Subject < ApplicationRecord
has_many :tidings, as: :container, dependent: :destroy
has_many :stages, -> { order("stages.position ASC") }, dependent: :destroy
# 开放课堂
has_many :courses, -> { order("courses.id ASC") }
validates :name, length: { maximum: 40 }
validates :description, length: { maximum: 5000 }
validates :learning_notes, length: { maximum: 500 }
@ -31,6 +34,11 @@ class Subject < ApplicationRecord
self.tidings << Tiding.new(user_id: self.user_id, trigger_user_id: self.user_id, belong_container_id: self.id, belong_container_type: 'Subject', tiding_type: "System", viewed: 0)
end
# 所有开课课堂的最大结束时间
def max_course_end_date
courses.pluck(:end_date).max
end
# 挑战过路径的成员数
def member_count
shixuns.pluck(:myshixuns_count).sum
@ -92,4 +100,8 @@ class Subject < ApplicationRecord
challenges = Challenge.where(shixun_id: shixuns.unhidden)
@tags = ChallengeTag.where(challenge_id: challenges).pluck(:name).uniq
end
def learning? user_id
Myshixun.where(user_id: user_id, shixun_id: shixuns).exists?
end
end

@ -9,16 +9,15 @@ class Tiding < ApplicationRecord
def identifier
value = nil
if Object.const_defined?(container_type)
value = container.try(:identifier)
end
if value.blank? && parent_container_type && Object.const_defined?(parent_container_type)
value = parent_container_type.try(:identifier)
value = container.try(:identifier) rescue nil
if value.blank? && parent_container_type
value = parent_container_type.try(:identifier) rescue nil
end
if value.blank? && belong_container_type && Object.const_defined?(belong_container_type)
value = belong_container.try(:identifier)
if value.blank? && belong_container_type
value = belong_container.try(:identifier) rescue nil
end
value

@ -60,8 +60,8 @@ class User < ApplicationRecord
has_many :games, :dependent => :destroy
has_many :created_subjects, foreign_key: :user_id, class_name: 'Subject'
has_many :subjects, :through => :subject_members
has_many :subject_members, :dependent => :destroy
has_many :subjects, :through => :subject_members
has_many :grades, :dependent => :destroy
has_many :experiences, :dependent => :destroy
has_many :student_works, :dependent => :destroy
@ -132,6 +132,15 @@ class User < ApplicationRecord
# 项目
has_many :applied_projects, dependent: :destroy
# 教学案例
has_many :libraries, dependent: :destroy
# 视频
has_many :videos, dependent: :destroy
# 客户管理
belongs_to :partner
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
@ -234,7 +243,7 @@ class User < ApplicationRecord
# 课堂的老师(创建者、老师、助教),不用考虑当前身份
def teacher_of_course_non_active?(course)
course.course_members.exists?(user_id: id, role: [1,2,3]) || admin? || business?
course.course_members.exists?(user_id: id, role: [1,2,3])
end
# 是否是教师,课堂管理员或者超级管理员
@ -257,9 +266,9 @@ class User < ApplicationRecord
course&.course_members.exists?(user_id: id)
end
# 实训路径管理员创建者或admin
# 实训路径管理员
def creator_of_subject?(subject)
subject.user_id == id || admin?
subject.user_id == id
end
# 实训路径合作者、admin
@ -372,6 +381,8 @@ class User < ApplicationRecord
@identity =
if admin?
User::EDU_ADMIN
elsif business?
User::EDU_BUSINESS
elsif creator_of_shixun?(shixun)
User::EDU_SHIXUN_MANAGER
elsif member_of_shixun?(shixun)
@ -440,7 +451,7 @@ class User < ApplicationRecord
end
def manager_of_memo?(memo)
id == memo.author_id || admin?
id == memo.author_id || admin? || business?
end
# 是否是项目管理者

@ -0,0 +1,36 @@
class Video < ApplicationRecord
include AASM
belongs_to :user
has_many :video_applies, dependent: :destroy
has_one :processing_video_apply, -> { where(status: :pending) }, class_name: 'VideoApply'
aasm(:status) do
state :pending, initial: true
state :processing
state :refused
state :published
event :apply_publish do
transitions from: :pending, to: :processing
end
event :refuse do
transitions from: :processing, to: :refused
end
event :publish do
transitions from: :processing, to: :published, guard: :vod_uploaded?
end
end
aasm(:vod_status, namespace: :vod) do
state :uploading, initial: true
state :uploaded
event :upload_success do
transitions from: :uploading, to: :uploaded
end
end
end

@ -0,0 +1,19 @@
class VideoApply < ApplicationRecord
include AASM
belongs_to :video
aasm(:status) do
state :pending, initial: true
state :refused
state :agreed
event :refuse do
transitions from: :pending, to: :refused
end
event :agree do
transitions from: :pending, to: :agreed
end
end
end

@ -0,0 +1,3 @@
class ApplicationQuery
include Callable
end

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

Loading…
Cancel
Save