diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 72afb3342..c5d3082ba 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -32,7 +32,12 @@ class CommentsController < ApplicationController # 列表 def index - discusses = @hack.discusses.where(root_id: nil) + discusses = + if current_user.admin_or_business? + @hack.discusses.where(root_id: nil) + else + @hack.discusses.where(root_id: nil, hidden: false) + end @discusses_count = discusses.count @discusses= paginate discusses end @@ -45,8 +50,9 @@ class CommentsController < ApplicationController # 隐藏、取消隐藏 def hidden - if @hack.manager?(current_user) - @discuss.update_attribute(:hidden, params[:hidden] == "1") + if current_user.admin_or_business? + @discuss = @hack.discusses.where(id: params[:id]).first + @discuss.update_attribute(:hidden, params[:hidden].to_i == 1) sucess_status else Educoder::TipException(403, "..") diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index b7f6a30a2..7a0fb7635 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -98,12 +98,20 @@ class HacksController < ApplicationController # 发布功能 def publish @hack.update_attribute(:status, 1) + base_attrs = { + trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id, + } + @hack.tidings.create!(base_attrs) render_ok end # 取消发布 def cancel_publish @hack.update_attribute(:status, 0) + base_attrs = { + trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id + } + @hack.tidings.create!(base_attrs) render_ok end diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 190892730..940955e93 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -266,8 +266,20 @@ class ShixunsController < ApplicationController # 如果是jupyter,先创建一个目录,为了挂载(因为后续数据集,开启Pod后环境在没销毁前,你上传数据集是挂载不上目录的,因此要先创建目录,方便中间层挂载) if @new_shixun.is_jupyter? folder = EduSetting.get('shixun_folder') + raise "存储目录未定义" unless folder.present? path = "#{folder}/#{@new_shixun.identifier}" FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + # 复制数据集 + save_path = File.join(folder, @shixun.identifier) + @shixun.data_sets.each do |set| + new_date_set = Attachment.new + new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory") + new_date_set.container_id = @new_shixun.id + new_date_set.disk_directory = @new_shixun.identifier + new_date_set.save! + FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path) + end + end # 同步复制关卡 if @shixun.challenges.present? diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index c8f2f5f57..0009ab2a6 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -216,10 +216,10 @@ class SubjectsController < ApplicationController @shixun.update_column(:repo_name, repo_path.split(".")[0]) mirror_id = if @shixun.is_jupyter? - MirrorRepository.where("type_name like '%Jupyter%'").first&.id folder = EduSetting.get('shixun_folder') path = "#{folder}/#{identifier}" FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + MirrorRepository.where("type_name like '%Jupyter%'").first&.id else MirrorRepository.find_by(type_name: 'Python3.6')&.id end diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 130e7f4b8..ff198468a 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -250,6 +250,9 @@ module TidingDecorator when 'shixunPublish' then name = Shixun.find_by(id: parent_container_id)&.name || '---' I18n.t(locale_format(parent_container_type)) % [name, container.score] + when 'Hack' then + name = Hack.find_by(id: container_id)&.name || '---' + I18n.t(locale_format(parent_container_type)) % [name, container.score] else I18n.t(locale_format(parent_container_type)) % container.score end diff --git a/app/models/discuss.rb b/app/models/discuss.rb index 652ffea37..148d6518b 100644 --- a/app/models/discuss.rb +++ b/app/models/discuss.rb @@ -52,16 +52,19 @@ class Discuss < ApplicationRecord private def send_tiding + if dis_type == 'Shixun' + user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id + parent_container_type = 'Challenge' + challenge_id = challenge_id + elsif dis_type == 'Hack' + user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id + parent_container_type = 'Hack' + challenge_id = nil + end base_attrs = { - trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge', - belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment' + trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type, + belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment' } - user_id = - if dis_type == 'Shixun' - has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id - elsif dis_type == 'Hack' - has_parent? ? parent.user_id : Hack.find(dis_id).user_id - end tidings.create!(base_attrs.merge(user_id: user_id)) end end diff --git a/app/models/hack.rb b/app/models/hack.rb index 2e2ffb9e0..d1ec3932c 100644 --- a/app/models/hack.rb +++ b/app/models/hack.rb @@ -13,6 +13,8 @@ class Hack < ApplicationRecord has_many :discusses, as: :dis, dependent: :destroy # 点赞 has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + # 消息 + has_many :tidings, as: :container, dependent: :destroy belongs_to :user @@ -21,6 +23,8 @@ class Hack < ApplicationRecord scope :opening, -> {where(open_or_not: 1)} scope :mine, -> (author_id){ where(user_id: author_id) } + after_destroy :send_delete_tiding + def language if hack_codes.count == 1 hack_codes.first.language @@ -49,4 +53,12 @@ class Hack < ApplicationRecord user_id == user.id || user.admin_or_business? end + private + def send_delete_tiding + base_attrs = { + user_id: user_id, viewed: 0, tiding_type: 'Delete', trigger_user_id: current_user.id, content: "你删除了题目:#{name}" + } + tidings.create!(base_attrs) + end + end diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb index 58ec965b4..8e96b7d47 100644 --- a/app/models/praise_tread.rb +++ b/app/models/praise_tread.rb @@ -12,7 +12,7 @@ class PraiseTread < ApplicationRecord case self.praise_tread_object_type when "Memo","Message","Issue" self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") - when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask" + when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask", "Hack" self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") end end diff --git a/app/services/subjects/copy_subject_service.rb b/app/services/subjects/copy_subject_service.rb index f44191fda..4715a8bad 100644 --- a/app/services/subjects/copy_subject_service.rb +++ b/app/services/subjects/copy_subject_service.rb @@ -79,7 +79,7 @@ class Subjects::CopySubjectService < ApplicationService copy_shixun_service_configs_data!(shixun, to_shixun) copy_challenges_data!(shixun, to_shixun) copy_shixun_members_data!(to_shixun) - + copy_jupyter_data_sets(shixun, to_shixun) if shixun.is_jupyter? # 云上实验室 if laboratory laboratory.laboratory_shixuns.create(shixun: to_shixun) @@ -87,6 +87,25 @@ class Subjects::CopySubjectService < ApplicationService to_shixun end + # 复制jupyter的数据集 + def copy_jupyter_data_sets(shixun, to_shixun) + return unless shixun.is_jupyter? + folder = EduSetting.get('shixun_folder') + raise "存储目录未定义" unless folder.present? + path = "#{folder}/#{to_shixun.identifier}" + FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + # 复制数据集 + save_path = File.join(folder, shixun.identifier) + shixun.data_sets.each do |set| + new_date_set = Attachment.new + new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory") + new_date_set.container_id = to_shixun.id + new_date_set.disk_directory = to_shixun.identifier + new_date_set.save! + FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path) + end + end + # 创建实训长字段内容 def copy_shixun_info_data!(shixun, to_shixun) to_shixun_info = ShixunInfo.new diff --git a/app/views/comments/_discuss.json.jbuilder b/app/views/comments/_discuss.json.jbuilder index b634b20a8..55b27acdf 100644 --- a/app/views/comments/_discuss.json.jbuilder +++ b/app/views/comments/_discuss.json.jbuilder @@ -5,10 +5,12 @@ json.id discuss.id json.content content_safe(discuss.content) json.time time_from_now(discuss.created_at) json.hack_id discuss.dis_id +json.hidden discuss.hidden # 主贴和回复有一些不同点 if discuss.parent_id json.can_delete discuss.can_deleted?(current_user) else json.praise_count discuss.praises_count json.user_praise discuss.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0 + json.can_delete discuss.can_deleted?(current_user) && child.count == 0 end \ No newline at end of file diff --git a/app/views/comments/index.json.jbuilder b/app/views/comments/index.json.jbuilder index b176d00b9..bfdbdacbb 100644 --- a/app/views/comments/index.json.jbuilder +++ b/app/views/comments/index.json.jbuilder @@ -1,6 +1,6 @@ json.disscuss_count @discusses_count json.comments @discusses do |discuss| - json.partial! 'comments/discuss', locals: { discuss: discuss} + json.partial! 'comments/discuss', locals: { discuss: discuss, child: discuss.child_discuss(current_user)} json.children discuss.child_discuss(current_user) do |c_d| json.partial! 'comments/discuss', locals: { discuss: c_d } end diff --git a/app/views/hack_user_lastest_codes/result.json.jbuilder b/app/views/hack_user_lastest_codes/result.json.jbuilder index 2561d4ecd..d8f010cc3 100644 --- a/app/views/hack_user_lastest_codes/result.json.jbuilder +++ b/app/views/hack_user_lastest_codes/result.json.jbuilder @@ -1,5 +1,5 @@ json.status 0 -json.message "评测成功" +json.message "评测完成" json.data do json.(@result, :id, :status, :error_line, :error_msg, :input, :output, :execute_time, :execute_memory) diff --git a/app/views/hack_user_lastest_codes/show.json.jbuilder b/app/views/hack_user_lastest_codes/show.json.jbuilder index be700f112..098c24546 100644 --- a/app/views/hack_user_lastest_codes/show.json.jbuilder +++ b/app/views/hack_user_lastest_codes/show.json.jbuilder @@ -1,5 +1,5 @@ json.hack do - json.(@hack, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count) + json.(@hack, :id, :name, :difficult, :time_limit, :description, :score, :identifier, :status, :praises_count) json.language @hack.language json.username @hack.user.real_name json.code @my_hack.code @@ -7,6 +7,7 @@ json.hack do json.submit_count @hack.submit_num json.modify_code @modify json.comments_count @hack.discusses.count + json.user_praise @hack.praise_treads.select{|pt| pt.user_id == current_user.id}.length > 0 end json.test_case do @@ -16,5 +17,6 @@ end json.user do json.partial! 'users/user', user: current_user json.hack_manager @hack.manager?(current_user) + json.admin current_user.admin_or_business? end \ No newline at end of file diff --git a/app/views/shixuns/get_data_sets.json.jbuilder b/app/views/shixuns/get_data_sets.json.jbuilder index 20ced2acd..f800d1c32 100644 --- a/app/views/shixuns/get_data_sets.json.jbuilder +++ b/app/views/shixuns/get_data_sets.json.jbuilder @@ -5,7 +5,10 @@ json.data_sets do json.author set.author.real_name json.created_on set.created_on json.filesize number_to_human_size(set.filesize) - json.file_path "#{@absolute_folder}/#{set.relative_path_filename}" + # 这里需要去除shixunfiles目录后的标识;因为Jupyter代码里面会写死这样的路径,当实训fork后,这个版本库的路径无法修改,因此给用户展示的 + # 还是/data/shixunfiles/+文件名这种形式 + json.file_path "#{@absolute_folder}/#{set.relative_path_filename}".gsub("/#{@shixun.identifier}", "") end end -json.data_sets_count @data_count \ No newline at end of file +json.data_sets_count @data_count +json.folder_name @absolute_folder \ No newline at end of file diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml index f484efdc1..dc56ad345 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -118,6 +118,7 @@ Answer: true_end: "查看实训%s第%s关的参考答案消耗金币:%s金币" false_end: "查看实训的参考答案消耗金币:%s金币" + Hack_end: "完成题目解答:%s,获得金币奖励:%s金币" Game_end: "通过实训%s的第%s关获得金币奖励:%s金币" Memo_end: "发布的评论或者帖子获得平台奖励:%s金币" Discusses_end: "发布的评论获得金币奖励:%s金币" diff --git a/config/routes.rb b/config/routes.rb index de884f3c1..ad52ecdb2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -79,6 +79,8 @@ Rails.application.routes.draw do resources :comments do collection do post :reply + end + member do post :hidden end end diff --git a/public/react/public/css/css_min_all.css b/public/react/public/css/css_min_all.css index cf453ac21..431a4da8e 100755 --- a/public/react/public/css/css_min_all.css +++ b/public/react/public/css/css_min_all.css @@ -1883,9 +1883,8 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40 .newupload_nav li:last-child{ border-right: none;} .newupload_nav li a{font-size:12px; color:#444;} .newupload_nav_hover{ background: #3498db; } -.newupload_nav_nomal { } .newupload_nav_hover a{color: #fff !important; } - +.markdown-body { text-align: justify;word-break: break-all;} .bor-reds{ border:1px solid #FF0000!important; border-radius: 4px; @@ -1894,6 +1893,7 @@ a:hover.task_icons_close{background: url(../images/popup/sy_icons_close.png) -40 border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } + @charset "UTF-8"; /*! diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css index f628b1e5c..48386e675 100644 --- a/public/react/public/css/edu-all.css +++ b/public/react/public/css/edu-all.css @@ -2934,7 +2934,7 @@ a.singlepublishtwo{ padding: 40px !important; } .editormd-html-preview{ - width: 94% !important; + width: 100% !important; color: #323232 !important; } #homework_editorMd_description hr{ @@ -3478,3 +3478,9 @@ a.singlepublishtwo{ /*width: auto !important;*/ /*max-width: 600px !important;*/ /*}*/ + + +.markdown-body { + text-align: justify; + word-break: break-all; +} \ No newline at end of file diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 0356f25f1..c75389419 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -52,7 +52,7 @@ export function initAxiosInterceptors(props) { //proxy="http://47.96.87.25:48080" proxy="https://pre-newweb.educoder.net" proxy="https://test-newweb.educoder.net" - proxy="https://test-jupyterweb.educoder.net" + // proxy="https://test-jupyterweb.educoder.net" //proxy="http://192.168.2.63:3001" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; diff --git a/public/react/src/common/components/comment/CommentForm.js b/public/react/src/common/components/comment/CommentForm.js index 73e36cff9..7683e2dea 100644 --- a/public/react/src/common/components/comment/CommentForm.js +++ b/public/react/src/common/components/comment/CommentForm.js @@ -3,22 +3,24 @@ * @Author: tangjiang * @Github: * @Date: 2019-12-17 17:32:55 - * @LastEditors: tangjiang - * @LastEditTime: 2019-12-18 17:51:44 + * @LastEditors : tangjiang + * @LastEditTime : 2019-12-24 17:27:41 */ +import './index.scss'; import React, { useState } from 'react'; import { Form, Button, Input } from 'antd'; import QuillForEditor from '../../quillForEditor'; -import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html' +// import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html' +import {formatDelta} from './util'; const FormItem = Form.Item; function CommentForm (props) { const { - commentCtxChagne, onCancel, onSubmit, - form + form, + type } = props; const { getFieldDecorator } = form; @@ -34,22 +36,25 @@ function CommentForm (props) { // const { form: { getFieldDecorator } } = props; const [showQuill, setShowQuill] = useState(false); // 点击输入框 - const handleInputClick = () => { + const handleInputClick = (type) => { setShowQuill(true); } // 取消 const handleCancle = () => { setShowQuill(false); - onCancel && onCancel(); + setCtx(''); + props.form.resetFields(); + onCancel && onCancel(); } // 编辑器内容变化时 const handleContentChange = (content) => { + console.log('编辑器内容', content); setCtx(content); try { - const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert(); + // const _html = new QuillDeltaToHtmlConverter(content.ops, {}).convert(); // props.form.setFieldsValue({'comment': _html.replace(/<\/?[^>]*>/g, '')}); - props.form.setFieldsValue({'comment': _html}); + props.form.setFieldsValue({'comment': content}); } catch (error) { console.log(error); } @@ -63,13 +68,25 @@ function CommentForm (props) { const content = ctx; props.form.setFieldsValue({'comment': ''}); setCtx(''); - console.log(content); - onSubmit && onSubmit(content); + const _html = formatDelta(content.ops); + onSubmit && onSubmit(_html); } }); } + + const handleShowImage = (url) => { + alert(url); + } + + // const _clazz = type === 'bottom' ? 'comment_form_bottom_area' : 'comment_form_area'; + let _clazz; + if (type === 'bottom') { + _clazz = showQuill ? 'comment_form_bottom_area active' : 'comment_form_bottom_area'; + } else { + _clazz = 'comment_form_area'; + } return ( -