|
|
|
@@ -1,2 +1,391 @@ |
|
|
|
# root_id:nil => 主贴; 有值 => 主帖的ID(值为帖子的ID) |
|
|
|
# parent_id: 回复(对这个id的回复) |
|
|
|
# sticky 顶置 1 |
|
|
|
# is_fine 是否加精,默认为false |
|
|
|
# hidden 是否隐藏 |
|
|
|
|
|
|
|
require 'elasticsearch/model' |
|
|
|
class Memo < ApplicationRecord |
|
|
|
|
|
|
|
include Redmine::SafeAttributes |
|
|
|
include UserScoreHelper |
|
|
|
include ApplicationHelper |
|
|
|
include Elasticsearch::Model |
|
|
|
#敏感词过滤 |
|
|
|
include DunCheckAble |
|
|
|
has_many :forums, :through => :memo_forums |
|
|
|
belongs_to :forum_section, counter_cache: true |
|
|
|
has_many :memo_forums, :dependent => :destroy |
|
|
|
has_many :visit_actions, as: :visitable, dependent: :destroy |
|
|
|
#用户是否禁言 |
|
|
|
has_many :banned_forums |
|
|
|
has_many_kindeditor_assets :assets, :dependent => :destroy |
|
|
|
has_many :tidings, :as => :container , :dependent => :destroy |
|
|
|
belongs_to :author, :class_name => "User", :foreign_key => 'author_id' |
|
|
|
validates_presence_of :author_id, :subject,:content |
|
|
|
# 若是主题帖,则内容可以是空 |
|
|
|
#validates :content, presence: true, if: Proc.new{|o| !o.parent_id.nil? } |
|
|
|
validates_length_of :subject, maximum: 50 |
|
|
|
|
|
|
|
validate :cannot_reply_to_locked_topic, :on => :create |
|
|
|
|
|
|
|
scope :total_replies, ->{where("hidden = false and root_id is not null")} |
|
|
|
|
|
|
|
# 创意征集方式 0-默认,1-申请, ps. 删除后,该帖子即删除, 拒绝后,该帖子状态将为初始状态 |
|
|
|
as_enum :memo_destroy_status, %i{common apply_destroy}, :column => 'destroy_status' |
|
|
|
acts_as_watchable |
|
|
|
#elasticsearch kaminari init |
|
|
|
Kaminari::Hooks.init |
|
|
|
Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari |
|
|
|
settings index: { |
|
|
|
number_of_shards: 5 , |
|
|
|
analysis: { |
|
|
|
char_filter: { |
|
|
|
and_filter: { |
|
|
|
type: "mapping", |
|
|
|
mappings: [ "&=> and "] |
|
|
|
} |
|
|
|
}, |
|
|
|
analyzer: { |
|
|
|
my_analyzer: { |
|
|
|
type: 'custom', |
|
|
|
tokenizer: 'standard', |
|
|
|
filter: ['classic'], |
|
|
|
char_filter: ['html_strip'] |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} do |
|
|
|
mappings dynamic: 'false' do |
|
|
|
indexes :subject, analyzer: 'smartcn',index_options: 'offsets'#, char_filter: 'html_strip' |
|
|
|
indexes :content, analyzer:'my_analyzer',index_options: 'offsets',search_analyzer: 'smartcn' |
|
|
|
indexes :updated_at,index:"not_analyzed" ,type:'date' |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
acts_as_tree :counter_cache => :replies_count, :order => "#{Memo.table_name}.created_at ASC", dependent: :destroy |
|
|
|
acts_as_attachable |
|
|
|
has_many :user_score_details, :class_name => 'UserScoreDetails',:as => :score_changeable_obj |
|
|
|
has_many :praise_tread, as: :praise_tread_object, dependent: :destroy |
|
|
|
has_one :praise_tread_cache, as: :object, dependent: :destroy |
|
|
|
|
|
|
|
# 消息 |
|
|
|
has_many :memo_messages, :class_name =>'MemoMessage', :dependent => :destroy |
|
|
|
# end |
|
|
|
belongs_to :last_reply, :class_name => 'Memo', :foreign_key => 'last_reply_id' |
|
|
|
# acts_as_searchable :column => ['subject', 'content'], |
|
|
|
# #:include => { :forum => :p} |
|
|
|
# #:project_key => "#{Forum.table_name}.project_id" |
|
|
|
# :date_column => "#{table_name}.created_at" |
|
|
|
#acts_as_event :title => Proc.new {|o| "#{o.forum.name}: #{o.subject}"}, |
|
|
|
#:datetime => :updated_at, |
|
|
|
# :datetime => :created_at, |
|
|
|
#:description => :content, |
|
|
|
#:author => :author, |
|
|
|
#:type => Proc.new {|o| o.parent_id.nil? ? 'Memo' : 'Reply'}, |
|
|
|
#:url => Proc.new {|o| {:controller => 'memos', :action => 'show', :forum_id => o.forum_id}.merge(o.parent_id.nil? ? {:id => o.id} : {:id => o.parent_id, :r => o.id, :anchor => "reply-#{o.id}"})} |
|
|
|
acts_as_activity_provider :author_key => :author_id, |
|
|
|
:func => 'memos', |
|
|
|
:timestamp => 'created_at' |
|
|
|
# :find_options => {:type => 'memos'} |
|
|
|
# acts_as_watchable |
|
|
|
|
|
|
|
safe_attributes "author_id", |
|
|
|
"subject", |
|
|
|
"content", |
|
|
|
"last_memo_id", |
|
|
|
"lock", |
|
|
|
"sticky", |
|
|
|
"parent_id", |
|
|
|
"replies_count", |
|
|
|
"root_id", |
|
|
|
"language" |
|
|
|
|
|
|
|
# after_create :add_author_as_watcher, :reset_counters!, :send_tiding |
|
|
|
# after_create :add_author_as_watcher #浏览记录 |
|
|
|
after_update |
|
|
|
# after_destroy :reset_counters!,:delete_kindeditor_assets #,:down_user_score -- 公共区发帖暂不计入得分, |
|
|
|
# after_create :send_notification |
|
|
|
# after_save :plusParentAndForum |
|
|
|
# after_destroy :minusParentAndForum |
|
|
|
#before_save :be_user_score |
|
|
|
# scope :visible, lambda { |*args| |
|
|
|
# includes(:forum => ).where() |
|
|
|
# } |
|
|
|
scope :indexable,lambda { |
|
|
|
where('parent_id is null') |
|
|
|
} |
|
|
|
scope :visible, lambda{where(hidden: false)} |
|
|
|
scope :hidden_memos, lambda{where(hidden: true)} |
|
|
|
scope :field_for_list, lambda{ |
|
|
|
select([:id, :subject,:destroy_status, :author_id, :sticky, :published_at, :language, :reward, :replies_count,:is_fine, :viewed_count, :praises_count,:forum_section_id, :tag_id, :is_original]) |
|
|
|
} |
|
|
|
scope :field_for_recommend, lambda{select([:id, :subject, :replies_count, :language])} |
|
|
|
scope :user_posts, ->(user_id){where(root_id: nil, author_id: user_id)} |
|
|
|
scope :user_replies, ->(user_id){where("root_id is not null and author_id = ?", user_id)} |
|
|
|
scope :memo_replies, ->(id){where(:root_id => id)} |
|
|
|
scope :hot, lambda{order("replies_count desc")} |
|
|
|
scope :posts, lambda{ where(root_id: nil) } |
|
|
|
scope :recommend_memos, lambda{ where(is_fine: true) } |
|
|
|
scope :in_week, lambda{ where("published_at >= ?",7.days.ago ) } |
|
|
|
scope :related_search_name, -> (name) {ransack(subject_cont: "#{name}").result(distinct: true)} |
|
|
|
|
|
|
|
scope :order_index, -> (sort_params) {reorder("sticky desc, is_fine desc, #{sort_params} desc")} |
|
|
|
|
|
|
|
def self.search_by_time(time_type, start_time, end_time) |
|
|
|
where("#{time_type} between ? and ?",start_time.present? ? start_time.to_time : Time.now, end_time.present? ? end_time.to_time.end_of_day : Time.now) |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def self.search(query) |
|
|
|
__elasticsearch__.search( |
|
|
|
{ |
|
|
|
query: { |
|
|
|
multi_match: { |
|
|
|
query: query, |
|
|
|
type:"most_fields", |
|
|
|
operator: "or", |
|
|
|
fields: ['subject','content^0.5'] |
|
|
|
} |
|
|
|
}, |
|
|
|
sort: { |
|
|
|
_score:{order: "desc" }, |
|
|
|
updated_at:{order: "desc" } |
|
|
|
}, |
|
|
|
highlight: { |
|
|
|
pre_tags: ['<span class="c_red">'], |
|
|
|
post_tags: ['</span>'], |
|
|
|
fields: { |
|
|
|
subject: {}, |
|
|
|
content: {} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
end |
|
|
|
|
|
|
|
def memo_parent |
|
|
|
Memo.find(parent_id) |
|
|
|
end |
|
|
|
|
|
|
|
def last_reply_memo(show_hidden_memo) |
|
|
|
memo_children = self.children |
|
|
|
if !show_hidden_memo |
|
|
|
memo_children = memo_children.visible |
|
|
|
end |
|
|
|
memo_children&.reorder("created_at desc")&.first |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def reply_for_memo |
|
|
|
Memo.where(:parent_id => self.id) |
|
|
|
end |
|
|
|
|
|
|
|
def all_replies |
|
|
|
Memo.where(:root_id => self.id) |
|
|
|
end |
|
|
|
|
|
|
|
#未审核发布的帖子数 |
|
|
|
def uncheck_memo_count |
|
|
|
self&.reply_for_memo&.where(hidden: true).size |
|
|
|
end |
|
|
|
|
|
|
|
def can_see_reply_count(user) |
|
|
|
memo_replies_count = self.replies_count |
|
|
|
unless user.try(:admin?) |
|
|
|
uncheck_memos_count = self.uncheck_memo_count #全部未审核的 |
|
|
|
user_uncheck_memos_count = self&.reply_for_memo&.where("hidden = true and author_id = ?", user.id)&.size #当前用户发布的,且未审核的 |
|
|
|
memo_replies_count = memo_replies_count - uncheck_memos_count + user_uncheck_memos_count |
|
|
|
end |
|
|
|
memo_replies_count |
|
|
|
end |
|
|
|
|
|
|
|
def self.hottest_five_memos |
|
|
|
order("replies_count desc, praises_count desc, viewed_count desc").limit(8).select([:id,:subject]) |
|
|
|
end |
|
|
|
|
|
|
|
def self.recommend_five_memos |
|
|
|
recommend_memos.order("updated_at desc").limit(8).select([:id,:subject]) |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
def send_mail |
|
|
|
# Mailer.run.forum_message_added(self) if Setting.notified_events.include?('forum_message_added') |
|
|
|
end |
|
|
|
|
|
|
|
def creator_user |
|
|
|
self.author |
|
|
|
end |
|
|
|
|
|
|
|
def created_time |
|
|
|
self.created_on |
|
|
|
end |
|
|
|
|
|
|
|
def content_detail |
|
|
|
self.content |
|
|
|
end |
|
|
|
|
|
|
|
# 公共贴吧消息记录 |
|
|
|
# 原则:新帖子给超级管理员发消息 |
|
|
|
def send_tiding |
|
|
|
if self.parent_id.present? |
|
|
|
# self.tidings << Tiding.new(:user_id => self.parent.author_id, :trigger_user_id => self.author_id, :parent_container_id => self.root_id, :parent_container_type => "Memo", |
|
|
|
# :belong_container_id => self.forum_id, :belong_container_type => "Forum", :viewed => 0, :tiding_type => "Comment") |
|
|
|
else |
|
|
|
self.tidings << Tiding.new(:user_id => 1, :trigger_user_id => self.author_id, :parent_container_id => self.id, :parent_container_type => "Memo", :viewed => 0, :tiding_type => "Comment") |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
def cannot_reply_to_locked_topic |
|
|
|
errors.add :base, l(:label_memo_locked) if root.locked? && self != root |
|
|
|
end |
|
|
|
|
|
|
|
# def update_memos_forum |
|
|
|
# if forum_id_changed? |
|
|
|
# Message.update_all({:board_id => board_id}, ["id = ? OR parent_id = ?", root.id, root.id ]) |
|
|
|
# Forum.reset_counters!(forum_id_was) |
|
|
|
# Forum.reset_counters!(forum_id) |
|
|
|
# end |
|
|
|
# end |
|
|
|
|
|
|
|
def reset_counters! |
|
|
|
if parent && parent.id |
|
|
|
parent.update_attribute(:last_reply_id, parent.children.maximum(:id)) |
|
|
|
end |
|
|
|
if root |
|
|
|
root.update_attribute(:last_reply_id, Memo.where(:root_id => root.id).maximum(:id)) unless root.destroyed? |
|
|
|
end |
|
|
|
forum.reset_counters! |
|
|
|
end |
|
|
|
|
|
|
|
def sticky? |
|
|
|
sticky == 1 |
|
|
|
end |
|
|
|
|
|
|
|
def replies |
|
|
|
Memo.where("parent_id = ?", id) |
|
|
|
end |
|
|
|
|
|
|
|
def locked? |
|
|
|
self.lock |
|
|
|
end |
|
|
|
|
|
|
|
def editable_by? user |
|
|
|
# user && user.logged? || (self.author == usr && usr.allowed_to?(:edit_own_messages, project)) |
|
|
|
user.admin? || self.author == user |
|
|
|
end |
|
|
|
|
|
|
|
def destroyable_by? user |
|
|
|
(user && self.author == user) || user.admin? || self.forum.creator == user || Memo.find(self.root_id).author == user |
|
|
|
#self.author == user || user.admin? |
|
|
|
end |
|
|
|
|
|
|
|
def deleted_attach_able_by? user |
|
|
|
(user && user.logged? && (self.author == user) ) || user.admin? |
|
|
|
end |
|
|
|
|
|
|
|
def meno_tag_name |
|
|
|
tag_id.to_i == 1 ? "交流" : "求助" |
|
|
|
end |
|
|
|
|
|
|
|
def update_attachments(attachment_ids) |
|
|
|
Attachment.where(id: attachment_ids).update_all(container_id: id, container_type: "Memo") |
|
|
|
end |
|
|
|
|
|
|
|
private |
|
|
|
|
|
|
|
def add_author_as_watcher |
|
|
|
Watcher.create(:watchable => self.root, :user => author) |
|
|
|
end |
|
|
|
|
|
|
|
def send_notification |
|
|
|
# if Setting.notified_events.include?('message_posted') |
|
|
|
# Mailer.run.message_posted(self) |
|
|
|
# end |
|
|
|
end |
|
|
|
|
|
|
|
# def update_reply_count |
|
|
|
# if self.root_id |
|
|
|
# self.root.increment!(:replies_count) |
|
|
|
# end |
|
|
|
# end |
|
|
|
|
|
|
|
def plusParentAndForum |
|
|
|
@forum = Forum.find(self.forum_id) |
|
|
|
@forum.memo_count = @forum.memo_count.to_int + 1 |
|
|
|
@forum.last_memo_id = self.id |
|
|
|
if self.parent_id |
|
|
|
@parent_memo = Memo.find_by_id(self.parent_id) |
|
|
|
@parent_memo.last_reply_id = self |
|
|
|
@parent_memo.replies_count = @parent_memo.replies_count.to_int + 1 |
|
|
|
@parent_memo.save |
|
|
|
else |
|
|
|
@forum.topic_count = @forum.topic_count.to_int + 1 |
|
|
|
end |
|
|
|
@forum.save |
|
|
|
end |
|
|
|
|
|
|
|
def minusParentAndForum |
|
|
|
@forum = Forum.find(self.forum_id) |
|
|
|
@forum.memo_count = @forum.memo_count.to_int - 1 |
|
|
|
@forum.memo_count = 0 if @forum.memo_count.to_int < 0 |
|
|
|
# @forum.last_memo_id = Memo.reorder('created_at ASC').find_all_by_forum_id(self.forum_id).last.id |
|
|
|
if self.parent_id |
|
|
|
@parent_memo = Memo.find_by_id(self.parent_id) |
|
|
|
# @parent_memo.last_reply_id = Memo.reorder('created_at ASC').find_all_by_parent_id(self.parent_id).last.id |
|
|
|
@parent_memo.replies_count = @parent_memo.replies_count.to_int - 1 |
|
|
|
@parent_memo.replies_count = 0 if @parent_memo.replies_count.to_int < 0 |
|
|
|
@parent_memo.save |
|
|
|
else |
|
|
|
@forum.topic_count = @forum.topic_count.to_int - 1 |
|
|
|
@forum.topic_count = 0 if @forum.topic_count.to_int < 0 |
|
|
|
end |
|
|
|
@forum.save |
|
|
|
end |
|
|
|
|
|
|
|
#更新用户分数 -by zjc |
|
|
|
def be_user_score |
|
|
|
#新建memo且无parent的为发帖 |
|
|
|
if self.parent_id.nil? |
|
|
|
UserScore.joint(:post_message, User.current,nil,self ,{ memo_id: self.id }) |
|
|
|
update_memo_number(User.current,1) |
|
|
|
|
|
|
|
#新建memo且有parent的为回帖 |
|
|
|
elsif !self.parent_id.nil? |
|
|
|
UserScore.joint(:reply_posting, User.current,self.parent.author,self, { memo_id: self.id }) |
|
|
|
update_replay_for_memo(User.current,1) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
#被删除时更新用户分数 |
|
|
|
def down_user_score |
|
|
|
update_memo_number(User.current,1) |
|
|
|
update_replay_for_memo(User.current,1) |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
# Time 2015-03-26 15:20:24 |
|
|
|
# Author lizanle |
|
|
|
# Description 从硬盘上删除资源 |
|
|
|
def delete_kindeditor_assets |
|
|
|
delete_kindeditor_assets_from_disk self.id,OwnerTypeHelper::MEMO |
|
|
|
end |
|
|
|
|
|
|
|
def create_memo_ealasticsearch_index |
|
|
|
if self.parent_id.nil? |
|
|
|
self.__elasticsearch__.index_document |
|
|
|
end |
|
|
|
end |
|
|
|
def update_memo_ealasticsearch_index |
|
|
|
if self.parent_id.nil? |
|
|
|
self.__elasticsearch__.update_document |
|
|
|
end |
|
|
|
end |
|
|
|
def delete_memo_ealasticsearch_index |
|
|
|
if self.parent_id.nil? |
|
|
|
self.__elasticsearch__.delete_document |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
end |