diff --git a/app/controllers/item_banks_controller.rb b/app/controllers/item_banks_controller.rb index 3ed8c76b8..767d3d61f 100644 --- a/app/controllers/item_banks_controller.rb +++ b/app/controllers/item_banks_controller.rb @@ -1,6 +1,8 @@ class ItemBanksController < ApplicationController include PaginateHelper before_action :require_login + before_action :find_item, except: [:index, :create] + before_action :edit_auth, only: [:update, :destroy, :set_public] def index items = ItemBankQuery.call(params) @@ -10,12 +12,46 @@ class ItemBanksController < ApplicationController def create item = ItemBank.new(user: current_user) - ItemBank::SaveItemService.call(item, form_params) + ItemBanks::SaveItemService.call(item, form_params) + render_ok + rescue ApplicationService::Error => ex + render_error(ex.message) + end + + def edit + + end + + def update + ItemBanks::SaveItemService.call(@item, form_params) + render_ok + rescue ApplicationService::Error => ex + render_error(ex.message) + end + + def destroy + @item.destroy! + render_ok + end + + def set_public + tip_exception(-1, "该试题已公开") if @item.public? + @item.update_attributes!(public: 1) + render_ok end private + + def find_item + @item = ItemBank.find_by!(id: params[:id]) + end + + def edit_auth + current_user.admin_or_business? || @item.user == current_user + end + def form_params - params.permit(:repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, tag_repertoire_id: [], choices: []) + params.permit(:repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, :analysis, tag_repertoire_id: [], choices: %i[choice_text is_answer]) end end \ No newline at end of file diff --git a/app/controllers/item_baskets_controller.rb b/app/controllers/item_baskets_controller.rb new file mode 100644 index 000000000..12d3f5617 --- /dev/null +++ b/app/controllers/item_baskets_controller.rb @@ -0,0 +1,30 @@ +class ItemBasketsController < ApplicationController + before_action :require_login + + def index + + end + + def create + ItemBaskets::SaveItemBasketService.call(current_user, create_params) + end + + def destroy + item = current_user.item_baskets.find_by!(item_bank_id: params[:id]) + ActiveRecord::Base.transaction do + current_user.item_baskets.where("item_type = #{item.item_type} and position > #{item.position}").update_all("position = position -1") + item.destroy! + end + render_ok + end + + def delete_item_type + # tip_exception() unless + end + + private + + def create_params + params.permit(item_ids: []) + end +end \ No newline at end of file diff --git a/app/forms/item_banks/save_item_form.rb b/app/forms/item_banks/save_item_form.rb index 6e59aa384..a323be7d4 100644 --- a/app/forms/item_banks/save_item_form.rb +++ b/app/forms/item_banks/save_item_form.rb @@ -1,13 +1,33 @@ -class ItemBank::SaveItemForm +class ItemBanks::SaveItemForm include ActiveModel::Model - attr_accessor :repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, :tag_repertoire_id, :choices + attr_accessor :repertoire_id, :sub_repertoire_id, :item_type, :difficulty, :name, :analysis, :tag_repertoire_id, :choices validates :repertoire_id, presence: true validates :sub_repertoire_id, presence: true - validates :item_type, presence: true - validates :difficulty, presence: true - validates :name, presence: true + validates :item_type, presence: true, inclusion: {in: 0..6}, numericality: { only_integer: true } + validates :difficulty, presence: true, inclusion: {in: 1..3}, numericality: { only_integer: true } + validates :name, presence: true, length: { maximum: 1000 } + validates :analysis, length: { maximum: 1000 } + def validate! + super + return unless errors.blank? + choices.each { |item| SubForm.new(item).validate! } if item_type < 3 + return unless errors.blank? + if [0, 2].include?(item_type) && choices.pluck(:is_answer).select{|item| item == 1}.length > 1 + raise("正确答案只能有一个") + elsif item_type == 1 && choices.pluck(:is_answer).select{|item| item == 1}.length <= 1 + raise("多选题至少有两个正确答案") + end + end + class SubForm + include ActiveModel::Model + + attr_accessor :choice_text, :is_answer + + validates :choice_text, presence: true, length: { maximum: 100 } + validates :is_answer, presence: true, inclusion: {in: 0..1}, numericality: { only_integer: true } + end end \ No newline at end of file diff --git a/app/models/item_bank.rb b/app/models/item_bank.rb index a7cf6c579..03e3fddb3 100644 --- a/app/models/item_bank.rb +++ b/app/models/item_bank.rb @@ -17,8 +17,9 @@ class ItemBank < ApplicationRecord has_many :item_choices, dependent: :destroy has_many :item_baskets, dependent: :destroy has_many :item_bank_tag_repertoires, dependent: :destroy + has_many :tag_repertoires, through: :item_bank_tag_repertoires - def analysisi + def analysis item_analysis&.analysis end end diff --git a/app/models/user.rb b/app/models/user.rb index a9b2f0b3a..d6c264e15 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -153,6 +153,10 @@ class User < ApplicationRecord has_many :hacks, dependent: :destroy has_many :hack_user_lastest_codes, dependent: :destroy + # 题库 + has_many :item_banks, dependent: :destroy + has_many :item_baskets, -> { order("item_baskets.position ASC") }, dependent: :destroy + # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } diff --git a/app/services/item_banks/save_item_service.rb b/app/services/item_banks/save_item_service.rb index ec9930aaa..2fc838c4c 100644 --- a/app/services/item_banks/save_item_service.rb +++ b/app/services/item_banks/save_item_service.rb @@ -1,4 +1,4 @@ -class ItemBank::SaveItemService < ApplicationService +class ItemBanks::SaveItemService < ApplicationService attr_reader :item, :params def initialize(item, params) @@ -7,7 +7,52 @@ class ItemBank::SaveItemService < ApplicationService end def call - Competitions::SaveTeamForm.new(params).validate! + new_record = item.new_record? + raise("不能更改题型") if !new_record && item.item_type != params[:item_type] + ItemBanks::SaveItemForm.new(params).validate! + ActiveRecord::Base.transaction do + item.item_type = params[:item_type] if new_record + item.difficulty = params[:difficulty] + item.sub_repertoire_id = params[:sub_repertoire_id] + item.name = params[:name].strip + item.save! + + analysis = item.item_analysis || ItemAnalysis.new(item_bank_id: item.id) + analysis.analysis = params[:analysis].blank? ? nil : params[:analysis].strip + analysis.save + + # 知识点的创建 + new_tag_repertoire_ids = params[:tag_repertoire_id] + old_tag_repertoire_ids = item.item_bank_tag_repertoires.pluck(:tag_repertoire_id) + delete_tag_repertoire_ids = old_tag_repertoire_ids - new_tag_repertoire_ids + create_tag_repertoire_ids = new_tag_repertoire_ids - old_tag_repertoire_ids + item.item_bank_tag_repertoires.where(tag_repertoire_id: delete_tag_repertoire_ids).destroy_all + create_tag_repertoire_ids.each do |tag_id| + item.item_bank_tag_repertoires << ItemBankTagRepertoire.new(tag_repertoire_id: tag_id) + end + + # 选项的创建 + if item.item_type < 3 + old_choices = item.item_choices + new_choices = params[:choices] + + new_choices.each_with_index do |choice, index| + choice_item = old_choices[index] || ItemChoice.new(item_bank_id: item.id) + choice_item.choice_text = choice[:choice_text] + choice_item.is_answer = choice[:is_answer] + choice_item.save! + end + + if old_choices.length > new_choices.length + old_choices[new_choices.length..(old_choices.length-1)].each do |old_choice| + old_choice.destroy + end + end + + end + end + + item end end \ No newline at end of file diff --git a/app/services/item_baskets/save_item_basket_service.rb b/app/services/item_baskets/save_item_basket_service.rb new file mode 100644 index 000000000..36ea46cb2 --- /dev/null +++ b/app/services/item_baskets/save_item_basket_service.rb @@ -0,0 +1,47 @@ +class ItemBaskets::SaveItemBasketService < ApplicationService + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + raise("请选择试题") if params[:item_ids].blank? + + # 只能选用公共题库或是自己的题库 + items = ItemBank.where(public: 1).or(ItemBank.where(user_id: user.id)) + + # 已选到过试题篮的不重复选用 + item_ids = params[:item_ids] - user.item_baskets.pluck(:item_bank_id) + items.where(id: item_ids).each do |item| + new_item = ItemBasket.new(user_id: user.id, item_bank_id: item.id, item_type: item.item_type) + new_item.score = item_score item.item_type + new_item.position = item_position item.item_type + new_item.save! + end + end + + private + + def item_score item_type + if user.item_baskets.where(item_type: item_type).last.present? + score = user.item_baskets.where(item_type: item_type).last.score + else + score = + case item_type + when 0, 1, 2 + 5 + when 6 + 10 + else + 5 + end + end + score + end + + def item_position item_type + user.item_baskets.where(item_type: item_type).last&.position.to_i + 1 + end +end \ No newline at end of file diff --git a/app/views/item_banks/edit.json.jbuilder b/app/views/item_banks/edit.json.jbuilder new file mode 100644 index 000000000..569a2cb86 --- /dev/null +++ b/app/views/item_banks/edit.json.jbuilder @@ -0,0 +1,15 @@ +json.repertoire do + json.(@item.sub_repertoire&.repertoire, :id, :name) +end +json.sub_repertoire do + json.(@item.sub_repertoire, :id, :name) +end +json.tag_repertoires @item.tag_repertoires do |tag| + json.(tag, :id, :name) +end +json.(@item, :id, :name, :item_type, :difficulty) +json.analysis @item.analysis +json.choices @item.item_choices do |choice| + json.choice_text choice.choice_text + json.is_answer choice.is_answer +end \ No newline at end of file diff --git a/app/views/item_banks/index.json.jbuilder b/app/views/item_banks/index.json.jbuilder index 991cf9592..5b965c362 100644 --- a/app/views/item_banks/index.json.jbuilder +++ b/app/views/item_banks/index.json.jbuilder @@ -1,6 +1,6 @@ json.items @items.each do |item| json.(item, :id, :name, :item_type, :difficulty, :public, :quotes) - json.analysisi item.analysisi + json.analysis item.analysis json.update_time item.updated_at&.strftime("%Y-%m-%d %H:%M") json.author do json.login item.user&.login diff --git a/config/routes.rb b/config/routes.rb index 0d2aba843..2ca65c8e2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -49,6 +49,12 @@ Rails.application.routes.draw do end resources :item_banks do + member do + post :set_public + end + end + + resources :item_baskets do end diff --git a/db/migrate/20191220084001_add_position_score_to_basket.rb b/db/migrate/20191220084001_add_position_score_to_basket.rb new file mode 100644 index 000000000..3f4057018 --- /dev/null +++ b/db/migrate/20191220084001_add_position_score_to_basket.rb @@ -0,0 +1,7 @@ +class AddPositionScoreToBasket < ActiveRecord::Migration[5.2] + def change + add_column :item_baskets, :position, :integer, default: 0 + add_column :item_baskets, :score, :float, default: 0 + add_column :item_baskets, :item_type, :integer, default: 0 + end +end