diff --git a/app/controllers/users/project_packages_controller.rb b/app/controllers/users/project_packages_controller.rb
new file mode 100644
index 000000000..edd6bd29b
--- /dev/null
+++ b/app/controllers/users/project_packages_controller.rb
@@ -0,0 +1,17 @@
+class Users::ProjectPackagesController < Users::BaseController
+
+ def index
+ packages = Users::ProjectPackageService.call(observed_user, query_params)
+
+ @count = packages.count
+ @packages = paginate(packages.includes(:project_package_category))
+
+ bidding_users = BiddingUser.where(project_package_id: @packages.map(&:id), user_id: observed_user.id)
+ bidding_users = bidding_users.group(:project_package_id).select(:project_package_id, :status)
+ @bidding_status_map = bidding_users.each_with_object({}) { |u, h| h[u.project_package_id] = u.status }
+ end
+
+ def query_params
+ params.permit(:category, :status, :sort_by, :sort_direction)
+ end
+end
\ No newline at end of file
diff --git a/app/models/project_package.rb b/app/models/project_package.rb
index fc541097a..219f60ca4 100644
--- a/app/models/project_package.rb
+++ b/app/models/project_package.rb
@@ -13,6 +13,9 @@ class ProjectPackage < ApplicationRecord
has_many :attachments, as: :container, dependent: :destroy
+ scope :visible, -> { where(status: %i[published bidding_ended bidding_finished]) }
+ scope :invisible, -> { where(status: %i[pending applying refused]) }
+
aasm(:status) do
state :pending, initiali: true
state :applying
diff --git a/app/models/user.rb b/app/models/user.rb
index 73036c73e..03c97b9f3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -123,6 +123,11 @@ class User < ApplicationRecord
has_many :user_interests, dependent: :delete_all
has_many :interests, through: :user_interests, source: :repertoire
+ # 众包
+ has_many :project_packages, foreign_key: :creator_id, dependent: :destroy
+ has_many :bidding_users, dependent: :destroy
+ has_many :bidden_project_packages, through: :bidding_users, source: :project_package
+
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
@@ -572,6 +577,10 @@ class User < ApplicationRecord
Attendance.find_by(user_id: id)&.next_gold || 60 # 基础50,连续签到+10
end
+ def admin_or_business?
+ admin? || business?
+ end
+
protected
def validate_password_length
# 管理员的初始密码是5位
diff --git a/app/services/users/project_package_service.rb b/app/services/users/project_package_service.rb
new file mode 100644
index 000000000..870cdc98e
--- /dev/null
+++ b/app/services/users/project_package_service.rb
@@ -0,0 +1,76 @@
+class Users::ProjectPackageService < ApplicationService
+ include CustomSortable
+
+ sort_columns :published_at, default_by: :published_at, default_direction: :desc
+
+ attr_reader :user, :params
+
+ def initialize(user, params)
+ @user = user
+ @params = params
+ end
+
+ def call
+ packages = category_scope_filter
+
+ packages = user_policy_filter(packages)
+
+ custom_sort(packages, :published_at, params[:sort_direction])
+ end
+
+ private
+
+ def category_scope_filter
+ case params[:category]
+ when 'bidden' then
+ user.bidden_project_packages
+ when 'manage' then
+ user.project_packages
+ else
+ ids = user.bidding_users.pluck(:project_package_id) + user.project_packages.pluck(:id)
+ ProjectPackage.where(id: ids)
+ end
+ end
+
+ def user_policy_filter(relations)
+ if self_or_admin?
+ status_filter(relations)
+ else
+ relations.visible
+ end
+ end
+
+ def status_filter(relations)
+ return relations unless self_or_admin?
+
+ case params[:category]
+ when 'bidden' then bidding_status_filter(relations)
+ when 'manage' then package_status_filter(relations)
+ else relations
+ end
+ end
+
+ def bidding_status_filter(relations)
+ case params[:status]
+ when 'bidding_lost' then
+ relations.where(bidding_users: { status: :bidding_lost })
+ when 'bidding_won' then
+ relations.where(bidding_users: { status: :bidding_won })
+ else
+ relations
+ end
+ end
+
+ def package_status_filter(relations)
+ case params[:status]
+ when 'unpublished' then relations.invisible
+ when 'bidding' then relations.where(status: :published)
+ when 'finished' then relations.where(status: %w[bidding_ended bidding_finished])
+ else relations
+ end
+ end
+
+ def self_or_admin?
+ User.current&.id == user.id || User.current&.admin_or_business?
+ end
+end
\ No newline at end of file
diff --git a/app/views/users/project_packages/index.json.jbuilder b/app/views/users/project_packages/index.json.jbuilder
new file mode 100644
index 000000000..a2574d558
--- /dev/null
+++ b/app/views/users/project_packages/index.json.jbuilder
@@ -0,0 +1,20 @@
+user = observed_user
+
+json.count @count
+json.project_packages do
+ json.array! @packages.each do |package|
+ json.extract! package, :id, :title, :status, :min_price, :max_price, :visit_count, :bidding_users_count
+
+ is_creator = user.id == package.creator_id
+ json.type is_creator ? 'manage' : 'bidden'
+ json.category_id package.project_package_category_id
+ json.category_name package.category_name
+
+ unless is_creator
+ json.bidden_status @bidding_status_map[package.id]
+ end
+
+ json.deadline_at package.display_deadline_at
+ json.published_at package.display_published_at
+ end
+end
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 16140e99c..bb5bc49cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -50,6 +50,7 @@ Rails.application.routes.draw do
resource :experience_records, only: [:show]
resource :grade_records, only: [:show]
resource :watch, only: [:create, :destroy]
+ resources :project_packages, only: [:index]
end
diff --git a/db/migrate/20190724013024_modify_final_score_for_games.rb b/db/migrate/20190724013024_modify_final_score_for_games.rb
new file mode 100644
index 000000000..e926cccd6
--- /dev/null
+++ b/db/migrate/20190724013024_modify_final_score_for_games.rb
@@ -0,0 +1,15 @@
+class ModifyFinalScoreForGames < ActiveRecord::Migration[5.2]
+ def change
+ grades = Grade.where(container_type: "Answer")
+ grades.each do |grade|
+ g = Game.find_by_id(grade.container_id)
+ if g.present?
+ if g.status == 2 && g.answer_open > 0 && g.final_score <= 0 && g.end_time < grade.created_at
+ g.update_column(:final_score, g.challenge.score)
+ elsif g.final_score < 0
+ g.update_column(:final_score, 0)
+ end
+ end
+ end
+ end
+end
diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js
index 7b9795e80..0abd707af 100644
--- a/public/react/config/webpack.config.prod.js
+++ b/public/react/config/webpack.config.prod.js
@@ -301,8 +301,8 @@ module.exports = {
},
warnings: false,
compress: {
- drop_debugger: true,
- drop_console: true
+ drop_debugger: false,
+ drop_console: false
}
}
}),
diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js
index 003ef5a9b..02d8c2be5 100644
--- a/public/react/src/AppConfig.js
+++ b/public/react/src/AppConfig.js
@@ -2,7 +2,7 @@ import React from "react";
import axios from 'axios';
import { requestProxy } from "./indexEduplus2RequestProxy";
-import { broadcastChannelOnmessage ,SetAppModel, isDev, queryString} from 'educoder';
+import { broadcastChannelOnmessage ,SetAppModel} from 'educoder';
import { notification } from 'antd';
import './index.css'
broadcastChannelOnmessage('refreshPage', () => {
@@ -18,19 +18,10 @@ function locationurl(list){
}
// TODO 开发期多个身份切换
-let debugType = ""
-if (isDev) {
- const _search = window.location.search;
- let parsed = {};
- if (_search) {
- parsed = queryString.parse(_search);
- }
- debugType = window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
- window.location.search.indexOf('debug=s') != -1 ? 'student' :
- window.location.search.indexOf('debug=a') != -1 ? 'admin' : parsed.debug || ''
-}
-
-window._debugType = debugType;
+const debugType =""
+// window.location.search.indexOf('debug=t') != -1 ? 'teacher' :
+// window.location.search.indexOf('debug=s') != -1 ? 'student' : 'admin'
+// window._debugType = debugType;
export function initAxiosInterceptors(props) {
// TODO 避免重复的请求 https://github.com/axios/axios#cancellation
@@ -121,7 +112,7 @@ export function initAxiosInterceptors(props) {
// https://github.com/axios/axios/issues/583
// message.info(response.data.message || '服务端返回status -1,请联系管理员。');
// props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
- if (window.location.pathname.startsWith('/tasks/')) {
+ if (window.location.pathname.startsWith('/tasks/')) {
props.showSnackbar( response.data.message || '服务器异常,请联系管理员。' )
} else {
notification.open({
@@ -136,7 +127,7 @@ export function initAxiosInterceptors(props) {
// description: response.data.message || '服务器异常,请联系管理员。',
// });
}
-
+
throw new axios.Cancel('Operation canceled by the user.');
}
// if(response.data.status === 401){
diff --git a/public/react/src/modules/courses/coursesPublic/Addcourses.js b/public/react/src/modules/courses/coursesPublic/Addcourses.js
index e8bd8b9cf..922c68650 100644
--- a/public/react/src/modules/courses/coursesPublic/Addcourses.js
+++ b/public/react/src/modules/courses/coursesPublic/Addcourses.js
@@ -147,6 +147,8 @@ class Addcourses extends Component{
if(Addcoursestype===true){
this.props.hideAddcoursestype();
+ }else{
+ window.location.href = "/";
}
}
diff --git a/public/react/src/modules/courses/new/CoursesNew.js b/public/react/src/modules/courses/new/CoursesNew.js
index c5d0009c1..1183b59e9 100644
--- a/public/react/src/modules/courses/new/CoursesNew.js
+++ b/public/react/src/modules/courses/new/CoursesNew.js
@@ -88,11 +88,11 @@ class CoursesNew extends Component {
}
componentDidUpdate(prevProps){
- if(prevProps.current_user!=this.props.current_user){
- if(this.props.current_user.user_identity==="学生"){
- window.location.href ="/403"
- }
- }
+ // if(prevProps.current_user!=this.props.current_user){
+ // if(this.props.current_user.user_identity==="学生"){
+ // window.location.href ="/403"
+ // }
+ // }
}
onChangeTimepublishs = (date, dateString) => {
if(dateString===""){
@@ -132,7 +132,7 @@ class CoursesNew extends Component {
e.preventDefault();
let coursesId = this.props.match.params.coursesId;
- let {is_public} = this.state
+ let {is_public,datatime} = this.state
// console.log(is_public)
if (coursesId != undefined) {
@@ -173,7 +173,7 @@ class CoursesNew extends Component {
// console.log('Received values of form: ', values);
- let {datatime} = this.state;
+
let url = "/courses/" + coursesId + ".json";
axios.put(url, {
course_list_name: values.course,
@@ -227,7 +227,7 @@ class CoursesNew extends Component {
// debugger
//新建
// console.log('Received values of form: ', values);
- let {datatime} = this.state;
+
let url = "/courses.json";
axios.post(url, {
course_list_name: values.course,
diff --git a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
index 5f41cdefb..61ed59d7b 100644
--- a/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
+++ b/public/react/src/modules/courses/shixunHomework/ShixunhomeWorkItem.js
@@ -382,7 +382,7 @@ class ShixunhomeWorkItem extends Component{
实训详情
{this.props.isAdminOrCreator()?this.editname(discussMessage.name,discussMessage.homework_id)} className={"btn colorblue ml20 font-16"}>重命名:""}
{/*