diff --git a/app/assets/javascripts/forums.js b/app/assets/javascripts/forums.js deleted file mode 100644 index dee720fac..000000000 --- a/app/assets/javascripts/forums.js +++ /dev/null @@ -1,2 +0,0 @@ -// Place all the behaviors and hooks related to the matching controller here. -// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/forums.scss b/app/assets/stylesheets/forums.scss deleted file mode 100644 index fafd631e1..000000000 --- a/app/assets/stylesheets/forums.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the forums controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index d1357d43f..e60e37bce 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -160,7 +160,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 +200,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 +212,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 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c76ca51a7..7aa89dbd7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -64,10 +64,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) @@ -241,14 +241,17 @@ class ApplicationController < ActionController::Base 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 diff --git a/app/controllers/discusses_controller.rb b/app/controllers/discusses_controller.rb index 3b987be51..6a270f619 100644 --- a/app/controllers/discusses_controller.rb +++ b/app/controllers/discusses_controller.rb @@ -1,7 +1,7 @@ class DiscussesController < ApplicationController LIMIT = 10 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] def index page = params[:page].to_i @@ -28,6 +28,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]). diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb deleted file mode 100644 index 82573fdd0..000000000 --- a/app/controllers/forums_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class ForumsController < ApplicationController -end diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index f7906ecda..603a59920 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -336,7 +336,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 diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb index 869d787db..66adcc46b 100644 --- a/app/controllers/memos_controller.rb +++ b/app/controllers/memos_controller.rb @@ -1,5 +1,9 @@ class MemosController < ApplicationController - before_action :set_memo, only: [:show, :edit, :update, :destroy] + before_action :require_login, except: [:show, :index] + 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 :is_admin, only: [:sticky_or_cancel, :hidden] include ApplicationHelper # GET /memos @@ -8,27 +12,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 +39,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 +69,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 = "帖子创建成功!" + normal_status("帖子创建成功") 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 +115,88 @@ 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) + normal_status("更新成功") + rescue Exception => e + tip_exception("更新失败,原因:#{e}") + raise ActiveRecord::Rollback end + end + + def reply + tip_exception("parent_id不能为空") if params[:parent_id].blank? + tip_exception("content不能为空") if params[:content].blank? - # Never trust parameters from the scary internet, only allow the white list through. - def memo_params - params.fetch(:memo, {}) + 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.increment!(:all_replies_count) + normal_status("回复成功") + 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 + + def is_admin + tip_exception(403, "无权限操作") unless 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[:tags].blank? + end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index c9ed6c597..672477790 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 26effd12e..fca143623 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -408,18 +408,16 @@ class ShixunsController < ApplicationController @shixun.update_attributes(shixun_params) @shixun.shixun_info.update_attributes(shixun_info_params) @shixun.shixun_schools.delete_all - if params[:scope_partment].present? && params[:user_scope].to_i == 1 + logger.info("##########scope_partment:###{params[:scope_partment]}") + # 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 diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index bc5b0a607..396c0900e 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -222,7 +222,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 diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb index fd138a182..969aca320 100644 --- a/app/controllers/users/base_controller.rb +++ b/app/controllers/users/base_controller.rb @@ -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 diff --git a/app/controllers/users/private_message_details_controller.rb b/app/controllers/users/private_message_details_controller.rb index 486d23d7f..8e7b31212 100644 --- a/app/controllers/users/private_message_details_controller.rb +++ b/app/controllers/users/private_message_details_controller.rb @@ -3,11 +3,13 @@ class Users::PrivateMessageDetailsController < Users::BaseController 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 diff --git a/app/controllers/users/projects_controller.rb b/app/controllers/users/projects_controller.rb index 863b99b37..07f4d5cac 100644 --- a/app/controllers/users/projects_controller.rb +++ b/app/controllers/users/projects_controller.rb @@ -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 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5df86ef54..7e9fd652b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -329,6 +329,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(/ */, '') + 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 diff --git a/app/helpers/forums_helper.rb b/app/helpers/forums_helper.rb deleted file mode 100644 index 2e531fd46..000000000 --- a/app/helpers/forums_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ForumsHelper -end diff --git a/app/models/discuss.rb b/app/models/discuss.rb index 2d9c00110..a50b18a6f 100644 --- a/app/models/discuss.rb +++ b/app/models/discuss.rb @@ -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 diff --git a/app/models/memo.rb b/app/models/memo.rb index 4dc153c81..d09251358 100644 --- a/app/models/memo.rb +++ b/app/models/memo.rb @@ -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]) diff --git a/app/models/user.rb b/app/models/user.rb index ed9d70c00..b453f9998 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -440,7 +440,7 @@ class User < ApplicationRecord end def manager_of_memo?(memo) - id == memo.author_id || admin? + id == memo.author_id || admin? || business? end # 是否是项目管理者 diff --git a/app/services/discusses_service.rb b/app/services/discusses_service.rb index 91fa523c9..81ac1eb33 100644 --- a/app/services/discusses_service.rb +++ b/app/services/discusses_service.rb @@ -58,7 +58,7 @@ class DiscussesService praise_count: 0, position: params[:position], challenge_id: params[:challenge_id], hidden: !current_user.admin? ) # 发送手机通知 - Trustie::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员') + Educoder::Sms.send(mobile:'18173242757', send_type:'discuss', name:'管理员') rescue Exception => e raise(e.message) end @@ -148,30 +148,6 @@ class DiscussesService @discuss = Discuss.select([:id, :hidden, :reward, :dis_type, :dis_id, :position, :challenge_id, :root_id]).find(id) end - protected - def memo_list memos - memos.map do |m| - user = User.find(m.user_id) - praise_count = m.praise_tread.where(:praise_or_tread => 1).count - replies_count = Discuss.where(:root_id => m.id).count - shixun_tag = m.dis.tag_repertoires.map(&:name) - m.attributes.dup.except("user_id", "dis_id", "dis_type", "root_id").merge({ - subject: (message_content m.content), - username: user.show_name, - login: user.login, - praise_count: praise_count, - replies_count: replies_count, - image_url: url_to_avatar(user), - shixun_tag: shixun_tag, - tpm_url: "/shixuns/#{m.dis.identifier}/shixun_discuss" - }) - end - end - - def format_for_current_user current_user - {username: current_user.show_name, login: current_user.login, user_id: current_user.id, image_url: url_to_avatar(current_user), admin: current_user.admin?} - end - def recommends hot_shixuns = Shixun.field_for_recommend.published.order("myshixuns_count desc").limit(2) newest_shixuns = Shixun.field_for_recommend.published.order("created_at desc").limit(2) @@ -185,6 +161,30 @@ class DiscussesService return recommend_shixuns end + def memo_list memos + memos.map do |m| + user = m.user + # praise_count = m.praise_treads.select{|pt| pt.praise_or_tread == 1}.count + replies_count = m.child_discuss_count + shixun_tag = m.dis.tag_repertoires.map(&:name) + m.attributes.dup.except("user_id", "dis_id", "dis_type", "root_id", "praise_count", "content").merge({ + subject: (message_content m.content), + username: user.full_name, + login: user.login, + replies_count: replies_count, + image_url: url_to_avatar(user), + shixun_tag: shixun_tag, + tpm_url: "/shixuns/#{m.dis.identifier}/shixun_discuss" + }) + end + end + + protected + + def format_for_current_user current_user + {username: current_user.show_name, login: current_user.login, user_id: current_user.id, image_url: url_to_avatar(current_user), admin: current_user.admin?} + end + # 将数据库对象转换成哈希对象 def object_to_hash objects objects.map{|o| o.attributes.dup} diff --git a/app/services/private_messages/create_service.rb b/app/services/private_messages/create_service.rb index 560f1a540..88f3a084f 100644 --- a/app/services/private_messages/create_service.rb +++ b/app/services/private_messages/create_service.rb @@ -3,7 +3,7 @@ class PrivateMessages::CreateService < ApplicationService attr_reader :sender, :receiver, :params - def initialize(sender, receiver, **params) + def initialize(sender, receiver, params) @sender = sender @receiver = receiver @params = params diff --git a/app/services/projects/apply_join_service.rb b/app/services/projects/apply_join_service.rb index a177de930..d14b3dc52 100644 --- a/app/services/projects/apply_join_service.rb +++ b/app/services/projects/apply_join_service.rb @@ -22,7 +22,7 @@ class Projects::ApplyJoinService < ApplicationService apply.forge_activities.find_or_create_by!(user: user, project: project) - notify_project_manager! + notify_project_manager!(apply) end # notify_project_owner @@ -47,10 +47,13 @@ class Projects::ApplyJoinService < ApplicationService end end - def notify_project_manager! + def notify_project_manager!(apply) columns = %i[user_id applied_id applied_type status viewed applied_user_id role project_id created_at updated_at] AppliedMessage.bulk_insert(*columns) do |worker| - base_attr = { status: false, viewed: false, applied_user_id: user.id, role: role_value, project_id: project.id } + base_attr = { + applied_id: apply.id, applied_type: 'AppliedProject', status: false, viewed: false, + applied_user_id: user.id, role: role_value, project_id: project.id + } project.manager_members.each do |manager| worker.add(base_attr.merge(user_id: manager.user_id)) diff --git a/app/services/search_shixun_service.rb b/app/services/search_shixun_service.rb deleted file mode 100644 index 2e77e82d8..000000000 --- a/app/services/search_shixun_service.rb +++ /dev/null @@ -1,96 +0,0 @@ -class SearchShixunService < ApplicationService - include ElasticsearchAble - - attr_reader :user, :params - - def initialize(user, params) - @user = user - @params = params - end - - def call - Shixun.search(keyword, - fields: search_fields, - where: where_clauses, - order: order_clauses, - includes: includes_clauses, - page: page, - per_page: per_page) - end - - private - - def tag_filter_shixun_ids - return [] if params[:tag_level].to_i == 0 || params[:tag_id].blank? - - case params[:tag_level].to_i - when 1 then - Repertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires) - .pluck('shixun_tag_repertoires.shixun_id') - when 2 then - SubRepertoire.find(params[:tag_id]).tag_repertoires.joins(:shixun_tag_repertoires) - .pluck('shixun_tag_repertoires.shixun_id') - when 3 then - TagRepertoire.find(params[:tag_id]).shixun_tag_repertoires.pluck(:shixun_id) - else - [] - end - end - - def user_filter_shixun_ids - return [] if params[:order_by] != 'mine' - - user.shixun_members.pluck(:shixun_id) + user.myshixuns.pluck(:shixun_id) - end - - def keyword - params[:keyword].to_s.strip.presence || '*' - end - - def search_fields - %w(name^10 author_name challenge_names description challenge_tag_names) - end - - def where_clauses - hash = {} - - ids = user_filter_shixun_ids + tag_filter_shixun_ids - hash[:id] = ids if ids.present? - - if params[:order_by] == 'mine' - hash[:status] = { not: -1 } - else - hash.merge!(hidden: false, status: 2) - end - - unless params[:status].to_i.zero? - params[:status] = [0, 1] if params[:status].to_i == 1 - hash[:status] = params[:status] - end - - hash[:trainee] = params[:diff].to_i unless params[:diff].to_i.zero? - - hash - end - - def includes_clauses - [] - end - - def order_clauses - hash = { _score: :desc } - publish_order = { type: 'number', order: :desc, script: 'doc["status"].value=="2" ? 1 : 0' } - - sort = params[:sort].to_s.strip == 'asc' ? 'asc' : 'desc' - clauses = - case params[:order_by].presence - when 'new' then { _script: publish_order, created_at: sort } - when 'hot' then { _script: publish_order, myshixuns_count: sort } - when 'mine' then { created_at: sort } - else { _script: publish_order, publish_time: sort } - end - hash.merge!(clauses) - - hash - end -end \ No newline at end of file diff --git a/app/services/users/update_account_service.rb b/app/services/users/update_account_service.rb index d603cec8c..c8ba6da61 100644 --- a/app/services/users/update_account_service.rb +++ b/app/services/users/update_account_service.rb @@ -51,6 +51,8 @@ class Users::UpdateAccountService < ApplicationService if first_full_reward RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500) + + sms_notify_admin(user.lastname) if user.user_extension.teacher? end user @@ -65,4 +67,10 @@ class Users::UpdateAccountService < ApplicationService def user_extension_attributes params.slice(*%i[location location_city identity student_id technical_title school_id department_id]) end + + def sms_notify_admin name + Educoder::Sms.send(mobile:'17680641960', send_type:'teacher_register', name: name, user_name:'管理员') + rescue => ex + Util.logger_error(ex) + end end \ No newline at end of file diff --git a/app/views/discusses/forum_discusses.json.jbuilder b/app/views/discusses/forum_discusses.json.jbuilder new file mode 100644 index 000000000..3b1aefd89 --- /dev/null +++ b/app/views/discusses/forum_discusses.json.jbuilder @@ -0,0 +1,27 @@ +json.memo_list @memos +# do |memo| +# json.(memo, :id, :updated_at, :reward) +# json.subject message_content(memo.content) +# json.praise_count memo.praises_count +# json.replies_count memo.child_discuss_count +# json.shixun_tag memo.dis.tag_repertoires.map(&:name) +# json.username memo.user.full_name +# json.login memo.user.login +# json.image_url url_to_avatar(memo.user) +# json.tpm_url "/shixuns/#{memo.dis.identifier}/shixun_discuss" +# end + +json.memo_count @memo_count + +json.hot_memos do + json.array! @hot_memos do |hm| + json.(hm, :id, :subject, :language, :forum_id) + json.replies_count hm.all_replies_count + # json.praise_count hm.praise_tread.praise_count + json.tag hm.tag_repertoires.map(&:name) + end +end + +json.hot_tags @hot_tags + +json.recommend_shixuns @recommend_shixuns \ No newline at end of file diff --git a/app/views/discusses/reward_code.json.jbuilder b/app/views/discusses/reward_code.json.jbuilder index e5e0e9152..e2a98192b 100644 --- a/app/views/discusses/reward_code.json.jbuilder +++ b/app/views/discusses/reward_code.json.jbuilder @@ -1 +1,2 @@ +json.status 0 json.code @code \ No newline at end of file diff --git a/app/views/games/picture_display.json.jbuilder b/app/views/games/picture_display.json.jbuilder index b43efa57e..770f0d71b 100644 --- a/app/views/games/picture_display.json.jbuilder +++ b/app/views/games/picture_display.json.jbuilder @@ -25,29 +25,28 @@ elsif @type == "txt" elsif @type =="qrcode" json.qrcode_str @qrcode_str elsif @type == "mp3" || @type == "mp4" - if @type == "mp4" - json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378171/123.mp4"}] - json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378172/456.mp4"}] - json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378173/789.mp4"}] - else - json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378174/58099.mp3"}] - json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] - json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] - end - - # json.orignal_file do - # json.array! @orignal_picture do |file| - # json.file_url attachment_show_users_path(:file_name => file, :path => @original_path) - # end - # end - # json.user_file do - # json.array! @user_picture do |file| - # json.file_url attachment_show_users_path(:file_name => file, :path => @user_path, :time => Time.now.to_i) - # end - # end - # json.answer_file do - # json.array! @answer_picture do |file| - # json.file_url attachment_show_users_path(:file_name => file, :path => @answer_path) - # end + # if @type == "mp4" + # json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378171/123.mp4"}] + # json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378172/456.mp4"}] + # json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378173/789.mp4"}] + # else + # json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378174/58099.mp3"}] + # json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] + # json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] # end + json.orignal_file do + json.array! @orignal_picture do |file| + json.file_url attachment_show_users_path(:file_name => file, :path => @original_path) + end + end + json.user_file do + json.array! @user_picture do |file| + json.file_url attachment_show_users_path(:file_name => file, :path => @user_path, :time => Time.now.to_i) + end + end + json.answer_file do + json.array! @answer_picture do |file| + json.file_url attachment_show_users_path(:file_name => file, :path => @answer_path) + end + end end \ No newline at end of file diff --git a/app/views/graduation_topics/_graduation_comments.json.jbuilder b/app/views/graduation_topics/_graduation_comments.json.jbuilder index 1d49d450f..ee9ed7529 100644 --- a/app/views/graduation_topics/_graduation_comments.json.jbuilder +++ b/app/views/graduation_topics/_graduation_comments.json.jbuilder @@ -10,7 +10,7 @@ json.hidden message.hidden if message.m_parent_id json.can_delete message.can_delete(identity) else - json.praise_count message.praise_treads.liker.count - json.user_praise message.praise_treads.user_liker(current_user).count + json.praise_count message.praise_treads.select{|pt| pt.praise_or_tread == 1}.count + json.user_praise message.praise_treads.select{|pt| pt.praise_or_tread == 1 && user_id == current_user.id}.count json.child_message_count message.m_reply_count end diff --git a/app/views/memos/_memo.json.jbuilder b/app/views/memos/_memo.json.jbuilder index 22adba5fc..bc3744d1f 100644 --- a/app/views/memos/_memo.json.jbuilder +++ b/app/views/memos/_memo.json.jbuilder @@ -1,8 +1,14 @@ -json.(memo, :id, :subject, :is_md, :content, :sticky, :reward, :viewed_count) - -json.tag memo.tag_repertoires.map(&:name) -json.time memo.created_at -json.replies_count memo.all_replies_count -json.attachments_list [] -json.user_praise memo.praise_tread.user_liker(@user.try(:id)) ? true : false -json.memo_praise_count = memo.praise_tread.liker.count +json.memo do + json.id memo.id + json.subject memo.subject + json.is_md memo.is_md + json.content memo.content + json.sticky memo.sticky + json.reward memo.reward + json.viewed_count memo.viewed_count + json.tag memo.tag_repertoires.map(&:name) + json.time memo.created_at + json.replies_count memo.all_replies_count + json.user_praise memo.praise_treads.user_liker(@user.try(:id)) ? true : false + json.memo_praise_count memo.praise_treads.liker.count +end diff --git a/app/views/memos/_memo_list.json.jbuilder b/app/views/memos/_memo_list.json.jbuilder index 8da056e92..1f45070a1 100644 --- a/app/views/memos/_memo_list.json.jbuilder +++ b/app/views/memos/_memo_list.json.jbuilder @@ -1,7 +1,7 @@ json.(memo, :id, :subject, :author_id, :sticky, :updated_at, :language, :reward, :all_replies_count, :viewed_count, :forum_id) -json.praise_count memo.praise_tread.praise_count +json.praise_count memo.praise_treads.liker.count json.replies_count memo.all_replies_count json.tag memo.tag_repertoires.map(&:name) json.user_name memo.author.full_name diff --git a/app/views/memos/_replies_list.json.jbuilder b/app/views/memos/_replies_list.json.jbuilder index 3dae61813..9ec6976c2 100644 --- a/app/views/memos/_replies_list.json.jbuilder +++ b/app/views/memos/_replies_list.json.jbuilder @@ -7,10 +7,10 @@ json.username memo.author.full_name json.reward memo.reward json.hidden memo.hidden json.permission @user.manager_of_memo?(memo) -json.praise_count memo.praise_tread.liker.count -json.user_praise memo.praise_tread.select{|pt| pt.user_id == @user.id}.length > 0 +json.praise_count memo.praise_treads.select{|pt| pt.praise_or_tread == 1}.count +json.user_praise memo.praise_treads.select{|pt| pt.praise_or_tread == 1 && pt.user_id == @user.id}.length > 0 json.user_login memo.author.login -json.admin @user.admin +json.admin @user.admin? || @user.business? json.children do json.array! memo.children_of_reply do |child| diff --git a/app/views/memos/edit.json.jbuilder b/app/views/memos/edit.json.jbuilder new file mode 100644 index 000000000..f3d3f3724 --- /dev/null +++ b/app/views/memos/edit.json.jbuilder @@ -0,0 +1,7 @@ +json.(@memo, :subject, :content, :forum_id) +json.memo_tags @memo_tags +json.attachments @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end +json.tag_list @tag_list +json.forums forum_list diff --git a/app/views/memos/index.json.jbuilder b/app/views/memos/index.json.jbuilder index 8a90e374a..e004f7ea7 100644 --- a/app/views/memos/index.json.jbuilder +++ b/app/views/memos/index.json.jbuilder @@ -8,22 +8,30 @@ # tidding_count: 消息数 # # -json.memo_list do - json.array! @memos do |memo| - json.partial! "memos/memo_list", locals: {memo: memo} - end +json.memo_list @memos do |memo| + json.(memo, :id, :subject, :sticky, + :updated_at, :language, :reward, + :viewed_count, :forum_id) + json.praise_count memo.praise_treads.select{|pt| pt.praise_or_tread == 1}.count + json.replies_count memo.all_replies_count + json.tag memo.tag_repertoires.map(&:name) + json.user_name memo.author.full_name + json.login memo.author.login + json.image_url url_to_avatar(memo.author) end json.memo_count @memos_count json.hot_memos do json.array! @hot_memos do |hm| - json.(hm, :id, :subject, :language, :forum_id, :all_replies_count) + json.(hm, :id, :subject, :language, :forum_id) json.replies_count hm.all_replies_count - json.praise_count hm.praise_tread.praise_count + # json.praise_count hm.praise_tread.praise_count json.tag hm.tag_repertoires.map(&:name) end end json.hot_tags @tags_info.map{|o| o.attributes.dup.except("cnt", "id")} +json.recommend_shixuns @recommend_shixuns + diff --git a/app/views/memos/more_reply.json.jbuilder b/app/views/memos/more_reply.json.jbuilder new file mode 100644 index 000000000..af1a9f1ac --- /dev/null +++ b/app/views/memos/more_reply.json.jbuilder @@ -0,0 +1,7 @@ +json.memo_replies do + json.array! @memos do |memo| + json.partial! "memos/replies_list", memo: memo + end +end + +json.memos_count @memos_count \ No newline at end of file diff --git a/app/views/memos/new.json.jbuilder b/app/views/memos/new.json.jbuilder index 47c023ea0..c35066023 100644 --- a/app/views/memos/new.json.jbuilder +++ b/app/views/memos/new.json.jbuilder @@ -1,3 +1,2 @@ json.tag_list @tag_list -json.forums @csrf_token - +json.forums forum_list \ No newline at end of file diff --git a/app/views/memos/show.json.jbuilder b/app/views/memos/show.json.jbuilder index 7acd6ba4a..1f7840983 100644 --- a/app/views/memos/show.json.jbuilder +++ b/app/views/memos/show.json.jbuilder @@ -1,5 +1,9 @@ json.partial! "memos/memo", memo: @memo +json.attachments_list @attachments do |attachment| + json.partial! "attachments/attachment_simple", locals: {attachment: attachment} +end + json.memo_replies do json.array! @memos do |memo| json.partial! "memos/replies_list", memo: memo @@ -9,10 +13,11 @@ end json.author_info do json.username @memo.author.full_name # TODO watched_by 插件没法用,等把lib文件载入后在打开代码 - #json.watched @memo.author.watched_by?(@user) + json.watched @user.watched?(@memo.author) json.image_url url_to_avatar(@memo.author) json.identity @memo.author.identity json.login @memo.author.login json.user_id @memo.author.id end +json.recommend_shixuns @recommend_shixuns \ No newline at end of file diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index d12b950f9..fc2eca762 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -1,4 +1,5 @@ json.username @user.full_name +json.real_name @user.real_name json.login @user.login json.user_id @user.id json.image_url url_to_avatar(@user) diff --git a/app/views/users/private_message_details/show.json.jbuilder b/app/views/users/private_message_details/show.json.jbuilder index 065767fb4..17d1a5e38 100644 --- a/app/views/users/private_message_details/show.json.jbuilder +++ b/app/views/users/private_message_details/show.json.jbuilder @@ -1,9 +1,13 @@ json.count @count +json.target do + json.partial! 'users/user_simple', user: target_user +end json.messages do json.array! @messages.each do |message| json.extract! message, :id, :user_id, :receiver_id, :sender_id, :content json.send_time message.display_send_time + json.send_day message.send_time.strftime('%Y-%m-%d') json.sender do json.partial! 'users/user_simple', user: message.sender end diff --git a/app/views/projects/search.json.jbuilder b/app/views/users/projects/search.json.jbuilder similarity index 100% rename from app/views/projects/search.json.jbuilder rename to app/views/users/projects/search.json.jbuilder diff --git a/config/routes.rb b/config/routes.rb index 2f9eed61b..79542817f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,7 +20,18 @@ Rails.application.routes.draw do put 'commons/unhidden', to: 'commons#unhidden' delete 'commons/delete', to: 'commons#delete' - resources :memos + resources :memos do + member do + post :sticky_or_cancel + post :hidden + get :more_reply + end + + collection do + post :reply + end + end + resources :tem_tests # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html # @@ -75,7 +86,7 @@ Rails.application.routes.draw do get :system_update resource :trial_apply, only: [:create] - resources :projects, only: [] do + resources :projects, module: :users, only: [] do get :search, on: :collection end @@ -222,6 +233,7 @@ Rails.application.routes.draw do resources :discusses do collection do get :new_message + get :forum_discusses end member do @@ -703,7 +715,7 @@ Rails.application.routes.draw do resources :libraries, only: [:index, :show, :create, :update, :destroy] scope module: :projects do - resources :applied_projects, only: [:create] + resources :project_applies, only: [:create] end end diff --git a/lib/educoder/sms.rb b/lib/educoder/sms.rb index 7fa1c0edb..a98ebf493 100644 --- a/lib/educoder/sms.rb +++ b/lib/educoder/sms.rb @@ -21,7 +21,7 @@ module Educoder def self.notify_admin(opt) opt[:name] = '管理员' - opt[:mobile] = ENV['NOTIFY_ADMIN_PHONE'] || EduSetting.get('notify_admin_phone') || '17680641960' + opt[:mobile] = ENV['NOTIFY_ADMIN_PHONE'] || EduSetting.get('notify_admin_phone') || '18711085785' send(opt) end @@ -39,25 +39,22 @@ module Educoder params['text'] = "【Edu实训】" + code + "(手机验证码),有效期为10分钟。如非本人操作,请忽略。" elsif send_type == 'competition_start' params['text'] = "【Edu实训】亲爱的#{user_name},你参与的#{name}将于#{result}开始,请及时参赛" - Rails.logger.info "#{params['text']}" + elsif send_type == "teacher_register" + params['mobile'] = EduSetting.get('teacher_register_phone') || '17680641960' + params['text'] = "【Edu实训】亲爱的#{user_name},有新的老师#{name}注册啦,请尽快处理" elsif send_type == 'subject_authorization' || send_type == 'shixun_authorization' params['text'] = "【Edu实训】亲爱的#{user_name},您提交的#{name}#{send_type=='subject_authorization'?'实训路径':'实训'}发布申请#{result},请登录平台查看详情" - Rails.logger.info "#{params['text']}" elsif send_type == 'authentication_pro' || send_type == 'authentication'|| send_type == 'trial_authorization' || send_type == 'project_info' params['text'] = "【Edu实训】亲爱的#{user_name},您提交的#{send_type == 'authentication_pro'?'职业认证':(send_type == 'authentication'? '实名认证' : (send_type == 'project_info'?'加入申请':'试用申请' ))}#{result},请登录平台查看详情" - Rails.logger.info "#{params['text']}" elsif send_type == "apply_pro_certification" || send_type == "apply_auth" params['text'] = "【Edu实训】亲爱的#{name},有新的#{send_type == 'apply_pro_certification'?'职业':'实名'}认证申请,请尽快处理" - Rails.logger.info "#{params['text']}" elsif send_type == "publish_subject" ||send_type == "publish_shixun"|| send_type == "user_apply_auth" || send_type == "discuss" + params['mobile'] = EduSetting.get('subject_shixun_notify_phone') || '18711011226' if send_type == "publish_subject" || send_type == "publish_shixun" params['text'] = "【Edu实训】亲爱的#{name},有新的#{send_type == 'publish_subject'?'实训路径':(send_type == 'publish_shixun' ? '实训' : (send_type == 'discuss' ? '实训评论':'试用'))}申请发布,请尽快处理" - Rails.logger.info "#{params['text']}" elsif send_type == 'join_course_multi_role' params['text'] = "【Edu实训】亲爱的#{user_name},您的课堂#{name}有助教或者教师申请加入,请尽快审核" - Rails.logger.info "#{params['text']}" elsif send_type == 'applied_project_info' params['text'] = "【Edu实训】亲爱的#{user_name},您的项目#{name}有成员申请加入,请尽快审核" - Rails.logger.info "#{params['text']}" end http = Net::HTTP.new(send_tpl_sms_uri.host, send_tpl_sms_uri.port) diff --git a/public/images/educoder/path.png b/public/images/educoder/path.png index d8b6f1715..d3d816012 100644 Binary files a/public/images/educoder/path.png and b/public/images/educoder/path.png differ diff --git a/public/javascripts/media/clappr-playback-rate-plugin.min.js b/public/javascripts/media/clappr-playback-rate-plugin.min.js new file mode 100644 index 000000000..8bbcbfaca --- /dev/null +++ b/public/javascripts/media/clappr-playback-rate-plugin.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("clappr")):"function"==typeof define&&define.amd?define("clappr-playback-rate-plugin",["clappr"],e):"object"==typeof exports?exports["clappr-playback-rate-plugin"]=e(require("clappr")):t["clappr-playback-rate-plugin"]=e(t.clappr)}("undefined"!=typeof self?self:this,function(t){return function(t){function e(n){if(a[n])return a[n].exports;var o=a[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var a={};return e.m=t,e.c=a,e.d=function(t,a,n){e.o(t,a)||Object.defineProperty(t,a,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var a=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(a,"a",a),a},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,a){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function r(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var i=a(1),l=(a.n(i),a(2)),c=a.n(l),s=a(3),u=a.n(s),p=function(){function t(t,e){for(var a=0;a\n <%= title %>\n\n\n'},function(t,e,a){e=t.exports=a(4)(void 0),e.push([t.i,".media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] {\n float: right;\n margin-top: 5px;\n position: relative; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] button.media-control-button.media-control-icon {\n font-family: Roboto,\"Open Sans\",Arial,sans-serif;\n -webkit-font-smoothing: antialiased;\n font-size: 12px;\n cursor: pointer;\n padding: 10px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] button.media-control-button.media-control-icon:hover {\n color: #c9c9c9; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] button.media-control-button.media-control-icon.changing {\n -webkit-animation: pulse 0.5s infinite alternate; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] > ul {\n display: none;\n list-style-type: none;\n position: absolute;\n bottom: 25px;\n border: 1px solid black;\n border-radius: 4px;\n background-color: rgba(0, 0, 0, 0.7); }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li {\n position: relative;\n font-size: 12px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li[data-title] {\n padding: 5px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li a {\n color: #aaa;\n padding: 2px 10px 2px 15px;\n display: block;\n text-decoration: none; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li a.active {\n background-color: black;\n font-weight: bold;\n color: #fff; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li a.active:before {\n content: '\\2713';\n position: absolute;\n top: 2px;\n left: 4px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .playback_rate[data-playback-rate-select] li a:hover {\n color: #fff;\n text-decoration: none; }\n\n@-webkit-keyframes pulse {\n 0% {\n color: #fff; }\n 50% {\n color: #ff0101; }\n 100% {\n color: #B80000; } }\n",""])},function(t,e){function a(t,e){var a=t[1]||"",o=t[3];if(!o)return a;if(e&&"function"==typeof btoa){var r=n(o);return[a].concat(o.sources.map(function(t){return"/*# sourceURL="+o.sourceRoot+t+" */"})).concat([r]).join("\n")}return[a].join("\n")}function n(t){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(t))))+" */"}t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=a(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n}).join("")},e.i=function(t,a){"string"==typeof t&&(t=[[null,t,""]]);for(var n={},o=0;o0&&e._renderPlugin()})})}},{key:"removeThumbnail",value:function(t){var e=this,n=t.constructor===Array?t:[t];return this._onThumbsLoaded.then(function(){var t=!0,o=!1;return n.forEach(function(n){var i=e._thumbs.some(function(t,o){return t.src===n&&(e._thumbs.splice(o,1),e._getOptions().backdropHeight&&(e._$backdropCarouselImgs[o].remove(),e._$backdropCarouselImgs.splice(o,1)),!0)});i?o=!0:t=!1}),o&&e._renderPlugin(),c.Promise.resolve(t)})}},{key:"_init",value:function(){this._thumbsLoaded&&(this._$backdropCarouselImgs=[],this._createElements(),this._loadBackdrop(),this._renderPlugin())}},{key:"_getOptions",value:function(){if(!("scrubThumbnails"in this.core.options))throw"'scrubThumbnails property missing from options object.";return this.core.options.scrubThumbnails}},{key:"_appendElToMediaControl",value:function(){this.core.mediaControl.$el.find(".media-control-background").first().after(this.el)}},{key:"_onMouseMove",value:function(t){this._calculateHoverPosition(t),this._show=!0,this._renderPlugin()}},{key:"_onMouseLeave",value:function(){this._show=!1,this._renderPlugin()}},{key:"_calculateHoverPosition",value:function(t){var e=t.pageX-this.core.mediaControl.$seekBarContainer.offset().left;this._hoverPosition=Math.min(1,Math.max(e/this.core.mediaControl.$seekBarContainer.width(),0))}},{key:"_buildThumbsFromOptions",value:function(){var t=this,e=this._getOptions().thumbs,n=e.map(function(e){return t._addThumbFromSrc(e)});return c.Promise.all(n)}},{key:"_addThumbFromSrc",value:function(t){var e=this;return new c.Promise(function(e,n){var o=new Image;o.onload=function(){e(o)},o.onerror=n,o.src=t.url}).then(function(n){var o=t.time,i=null;e._thumbs.some(function(t,e){return o0?e._thumbs[i-1]:null;u&&(u.duration=o-u.time);var s=r?r.time-t.time:null,a=n.width,c=n.height,l={imageW:a,imageH:c,x:t.x||0,y:t.y||0,w:t.w||a,h:t.h||c,url:t.url,time:o,duration:s,src:t};return e._thumbs.splice(i,0,l),l})}},{key:"_buildImg",value:function(t,e){var n=e/t.h,o=(0,a.$)("").addClass("thumbnail-img").attr("src",t.url),i=(0,a.$)("
").addClass("thumbnail-container");return i.css("width",t.w*n),i.css("height",e),o.css({height:t.imageH*n,left:-1*t.x*n,top:-1*t.y*n}),i.append(o),i}},{key:"_loadBackdrop",value:function(){if(this._getOptions().backdropHeight)for(var t=this._$carousel,e=0;e=0;n--){var o=e[n];if(o.time<=t)return n}return 0}},{key:"_renderPlugin",value:function(){this._thumbsLoaded&&(this._show&&this._thumbs.length>0?(this.$el.removeClass("hidden"),this._updateCarousel(),this._updateSpotlightThumb()):this.$el.addClass("hidden"))}},{key:"_createElements",value:function(){this.$el.html(this.template({backdropHeight:this._getOptions().backdropHeight,spotlightHeight:this._getOptions().spotlightHeight})),this.$el.append(a.Styler.getStyleFor(d["default"])),this._$spotlight=this.$el.find(".spotlight"),this._$backdrop=this.$el.find(".backdrop"),this._$carousel=this._$backdrop.find(".carousel"),this.$el.addClass("hidden"),this._appendElToMediaControl()}}]),e}(a.UICorePlugin);e["default"]=p,t.exports=e["default"]},function(t,e,n){(function(t,o){"use strict";function i(t,e){this._id=t,this._clearFn=e}var r=n(4).nextTick,u=Function.prototype.apply,s=Array.prototype.slice,a={},c=0;e.setTimeout=function(){return new i(u.call(setTimeout,window,arguments),clearTimeout)},e.setInterval=function(){return new i(u.call(setInterval,window,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(window,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},e.setImmediate="function"==typeof t?t:function(t){var n=c++,o=!(arguments.length<2)&&s.call(arguments,1);return a[n]=!0,r(function(){a[n]&&(o?t.apply(null,o):t.call(null),e.clearImmediate(n))}),n},e.clearImmediate="function"==typeof o?o:function(t){delete a[t]}}).call(e,n(1).setImmediate,n(1).clearImmediate)},function(t,e){"use strict";t.exports=function(){var t=[];return t.toString=function(){for(var t=[],e=0;e1)for(var n=1;n")},M.garbage=function(t){this.options.recycleVideo&&"VIDEO"===t[0].tagName.toUpperCase()&&(t.children().remove(),D.push(t))},M);function M(){(0,s.default)(this,M)}x.options={recycleVideo:!1};var N=e.DoubleEventHandler=(F.prototype.handle=function(t,e,r){var i=!(2]*>/,Xe=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Ye=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Ze=/^(?:body|html)$/i,$e=/([A-Z])/g,_e=["val","css","html","text","data","width","height","offset"],bf=Se.createElement("table"),cf=Se.createElement("tr"),df={tr:Se.createElement("tbody"),tbody:bf,thead:bf,tfoot:bf,td:cf,th:cf,"*":Se.createElement("div")},ef=/complete|loaded|interactive/,ff=/^[\w-]*$/,hf=(gf={}).toString,jf={},mf=Se.createElement("div"),nf={tabindex:"tabIndex",readonly:"readOnly",for:"htmlFor",class:"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},of=Array.isArray||function(t){return t instanceof Array},jf.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var r=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(r)return r.call(t,e);var i,n=t.parentNode,a=!n;return a&&(n=mf).appendChild(t),i=~jf.qsa(n,e).indexOf(t),a&&mf.removeChild(t),i},kf=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},lf=function(r){return Qe.call(r,function(t,e){return r.indexOf(t)==e})},jf.fragment=function(t,e,r){var i,n,a;return Xe.test(t)&&(i=Me(Se.createElement(RegExp.$1))),i||(t.replace&&(t=t.replace(Ye,"<$1>")),e===Ke&&(e=We.test(t)&&RegExp.$1),e in df||(e="*"),(a=df[e]).innerHTML=""+t,i=Me.each(Re.call(a.childNodes),function(){a.removeChild(this)})),uf(r)&&(n=Me(i),Me.each(r,function(t,e){-1<_e.indexOf(t)?n[t](e):n.attr(t,e)})),i},jf.Z=function(t,e){return new Df(t,e)},jf.isZ=function(t){return t instanceof jf.Z},jf.init=function(t,e){var r;if(!t)return jf.Z();if("string"==typeof t)if("<"==(t=t.trim())[0]&&We.test(t))r=jf.fragment(t,RegExp.$1,e),t=null;else{if(e!==Ke)return Me(e).find(t);r=jf.qsa(Se,t)}else{if(qf(t))return Me(Se).ready(t);if(jf.isZ(t))return t;if(of(t))r=function(t){return Qe.call(t,function(t){return null!=t})}(t);else if(tf(t))r=[t],t=null;else if(We.test(t))r=jf.fragment(t.trim(),RegExp.$1,e),t=null;else{if(e!==Ke)return Me(e).find(t);r=jf.qsa(Se,t)}}return jf.Z(r,t)},(Me=function(t,e){return jf.init(t,e)}).extend=function(e){var r,t=Re.call(arguments,1);return"boolean"==typeof e&&(r=e,e=t.shift()),t.forEach(function(t){!function t(e,r,i){for(Le in r)i&&(uf(r[Le])||of(r[Le]))?(uf(r[Le])&&!uf(e[Le])&&(e[Le]={}),of(r[Le])&&!of(e[Le])&&(e[Le]=[]),t(e[Le],r[Le],i)):r[Le]!==Ke&&(e[Le]=r[Le])}(e,t,r)}),e},jf.qsa=function(t,e){var r,i="#"==e[0],n=!i&&"."==e[0],a=i||n?e.slice(1):e,o=ff.test(a);return t.getElementById&&o&&i?(r=t.getElementById(a))?[r]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:Re.call(o&&!i&&t.getElementsByClassName?n?t.getElementsByClassName(a):t.getElementsByTagName(e):t.querySelectorAll(e))},Me.contains=Se.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},Me.type=pf,Me.isFunction=qf,Me.isWindow=rf,Me.isArray=of,Me.isPlainObject=uf,Me.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},Me.isNumeric=function(t){var e=Number(t),r=typeof t;return null!=t&&"boolean"!=r&&("string"!=r||t.length)&&!isNaN(e)&&isFinite(e)||!1},Me.inArray=function(t,e,r){return Oe.indexOf.call(e,t,r)},Me.camelCase=kf,Me.trim=function(t){return null==t?"":String.prototype.trim.call(t)},Me.uuid=0,Me.support={},Me.expr={},Me.noop=function(){},Me.map=function(t,e){var r,i,n,a=[];if(vf(t))for(i=0;i)<[^<]*)*<\/script>/gi,Ok=/^(?:text|application)\/javascript/i,Pk=/^(?:text|application)\/xml/i,Qk="application/json",Rk="text/html",Sk=/^\s*$/,Tk=Kk.createElement("a");function Vk(t,e,r,i){if(t.global)return function(t,e,r){var i=Ik.Event(e);return Ik(t).trigger(i,r),!i.isDefaultPrevented()}(e||Kk,r,i)}function Yk(t,e){var r=e.context;if(!1===e.beforeSend.call(r,t,e)||!1===Vk(e,r,"ajaxBeforeSend",[t,e]))return!1;Vk(e,r,"ajaxSend",[t,e])}function Zk(t,e,r,i){var n=r.context,a="success";r.success.call(n,t,a,e),i&&i.resolveWith(n,[t,a,e]),Vk(r,n,"ajaxSuccess",[e,r,t]),_k(a,e,r)}function $k(t,e,r,i,n){var a=i.context;i.error.call(a,r,e,t),n&&n.rejectWith(a,[r,e,t]),Vk(i,a,"ajaxError",[r,i,t||e]),_k(e,r,i)}function _k(t,e,r){var i=r.context;r.complete.call(i,e,t),Vk(r,i,"ajaxComplete",[e,r]),function(t){t.global&&!--Ik.active&&Vk(t,null,"ajaxStop")}(r)}function bl(){}function dl(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function fl(t,e,r,i){return Ik.isFunction(e)&&(i=r,r=e,e=void 0),Ik.isFunction(r)||(i=r,r=void 0),{url:t,data:e,success:r,dataType:i}}Tk.href=window.location.href,Ik.active=0,Ik.ajaxJSONP=function(r,i){if(!("type"in r))return Ik.ajax(r);function t(t){Ik(s).triggerHandler("error",t||"abort")}var n,a,e=r.jsonpCallback,o=(Ik.isFunction(e)?e():e)||"Zepto"+Jk++,s=Kk.createElement("script"),l=window[o],u={abort:t};return i&&i.promise(u),Ik(s).on("load error",function(t,e){clearTimeout(a),Ik(s).off().remove(),"error"!=t.type&&n?Zk(n[0],u,r,i):$k(null,e||"error",u,r,i),window[o]=l,n&&Ik.isFunction(l)&&l(n[0]),l=n=void 0}),!1===Yk(u,r)?t("abort"):(window[o]=function(){n=arguments},s.src=r.url.replace(/\?(.+)=\?/,"?$1="+o),Kk.head.appendChild(s),0").html(t.replace(Nk,"")).find(i):t),s&&s.apply(n,arguments)},Ik.ajax(o),this};var gl=encodeURIComponent;Ik.param=function(t,e){var r=[];return r.add=function(t,e){Ik.isFunction(e)&&(e=e()),null==e&&(e=""),this.push(gl(t)+"="+gl(e))},function r(i,t,n,a){var o,s=Ik.isArray(t),l=Ik.isPlainObject(t);Ik.each(t,function(t,e){o=Ik.type(e),a&&(t=n?a:a+"["+(l||"object"==o||"array"==o?t:"")+"]"),!a&&s?i.add(e.name,e.value):"array"==o||!n&&"object"==o?r(i,e,n,t):i.add(t,e)})}(r,t,e),r.join("&").replace(/%20/g,"+")}}(Je),(_m=Je).Callbacks=function(i){i=_m.extend({},i);var e,r,n,a,o,s,l=[],u=!i.once&&[],d=function(t){for(e=i.memory&&t,r=!0,s=a||0,a=0,o=l.length,n=!0;l&&s/,Sq="Zepto"+ +new Date,Lq.qsa=function(a,o){return Tq(o,function(t,r,i){try{var e;!t&&r?t="*":Rq.test(t)&&(e=Kq(a).addClass(Sq),t="."+Sq+" "+t);var n=Mq(a,t)}catch(t){throw console.error("error performing selector: %o",o),t}finally{e&&e.removeClass(Sq)}return r?Lq.uniq(Kq.map(n,function(t,e){return r.call(t,e,n,i)})):n})},Lq.matches=function(i,t){return Tq(t,function(t,e,r){return(!t||Nq(i,t))&&(!e||e.call(i,null,r)===i)})},He.exports=Je},function(t,e,r){"use strict";Object.defineProperty(e,"__esModule",{value:!0});function n(t){return null===t?"":(""+t).replace(o,function(t){return a[t]})}function i(a,t){var e,r=new RegExp([(l.escape||u).source,(l.interpolate||u).source,(l.evaluate||u).source].join("|")+"|$","g"),o=0,s="__p+='";a.replace(r,function(t,e,r,i,n){return s+=a.slice(o,n).replace(c,function(t){return"\\"+d[t]}),e&&(s+="'+\n((__t=("+e+"))==null?'':escapeExpr(__t))+\n'"),r&&(s+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(s+="';\n"+i+"\n__p+='"),o=n+t.length,t}),s+="';\n",l.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n//# sourceURL=/microtemplates/source["+f+++"]";try{e=new Function(l.variable||"obj","escapeExpr",s)}catch(t){throw t.source=s,t}if(t)return e(t,n);function i(t){return e.call(this,t,n)}return i.source="function("+(l.variable||"obj")+"){\n"+s+"}",i}var l={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},u=/(.)^/,d={"'":"'","\\":"\\","\r":"r","\n":"n","\t":"t","\u2028":"u2028","\u2029":"u2029"},c=/\\|'|\r|\n|\t|\u2028|\u2029/g,a={"&":"&","<":"<",">":">",'"':""","'":"'"},o=new RegExp("[&<>\"']","g"),f=0;i.settings=l,e.default=i,t.exports=e.default},function(t,e){t.exports=function(r){var o=[];return o.toString=function(){return this.map(function(t){var e=function(t,e){var r=t[1]||"",i=t[3];if(!i)return r;if(e&&"function"==typeof btoa){var n=function(t){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(t))))+" */"}(i),a=i.sources.map(function(t){return"/*# sourceURL="+i.sourceRoot+t+" */"});return[r].concat(a).concat([n]).join("\n")}return[r].join("\n")}(t,r);return t[2]?"@media "+t[2]+"{"+e+"}":e}).join("")},o.i=function(t,e){"string"==typeof t&&(t=[[null,t,""]]);for(var r={},i=0;i=e.length?{value:void 0,done:!0}:(t=i(e,r),this._i+=t.length,{value:t,done:!1})})},function(t,e){t.exports=!0},function(t,e,i){function n(){}var a=i(21),o=i(116),s=i(51),l=i(49)("IE_PROTO"),u="prototype",d=function(){var t,e=i(67)("iframe"),r=s.length;for(e.style.display="none",i(117).appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write("