2
0
mirror of https://github.com/moebooru/moebooru synced 2025-08-22 01:47:48 +00:00
moebooru/app/models/forum_post.rb
2025-01-12 23:51:24 +09:00

181 lines
3.9 KiB
Ruby

class ForumPost < ApplicationRecord
LATEST_CACHE_KEY = 'forum_posts_latest_v4'
belongs_to :creator, class_name: "User", foreign_key: :creator_id
belongs_to :updater, class_name: "User", foreign_key: :last_updated_by
after_create :initialize_last_updated_by
after_create :clear_cache
before_validation :validate_title
validates_length_of :body, minimum: 1, message: "You need to enter a body"
module LockMethods
module ClassMethods
def lock!(id)
# Run raw SQL to skip the lock check
execute_sql("UPDATE forum_posts SET is_locked = TRUE WHERE id = ?", id)
end
def unlock!(id)
# Run raw SQL to skip the lock check
execute_sql("UPDATE forum_posts SET is_locked = FALSE WHERE id = ?", id)
end
end
def self.included(m)
m.extend(ClassMethods)
m.before_validation :validate_lock
end
def validate_lock
if root.is_locked?
errors.add(:base, "Thread is locked")
throw :abort
end
true
end
end
module StickyMethods
module ClassMethods
def stick!(id)
# Run raw SQL to skip the lock check
execute_sql("UPDATE forum_posts SET is_sticky = TRUE WHERE id = ?", id)
end
def unstick!(id)
# Run raw SQL to skip the lock check
execute_sql("UPDATE forum_posts SET is_sticky = FALSE WHERE id = ?", id)
end
end
def self.included(m)
m.extend(ClassMethods)
end
end
module ParentMethods
def self.included(m)
m.after_create :update_parent_on_create
m.before_destroy :update_parent_on_destroy
m.has_many :children, lambda { order "id" }, class_name: "ForumPost", foreign_key: :parent_id
m.belongs_to :parent, class_name: "ForumPost", foreign_key: :parent_id
end
def update_parent_on_destroy
unless is_parent?
p = parent
p.update(response_count: p.response_count - 1)
end
end
def update_parent_on_create
unless is_parent?
p = parent
p.update(updated_at: updated_at, response_count: p.response_count + 1, last_updated_by: creator_id)
end
end
def is_parent?
parent_id.nil?
end
def root
if is_parent?
self
else
parent
end
end
def root_id
if is_parent?
id
else
parent_id
end
end
end
module ApiMethods
def api_attributes
{
body: body,
creator: author,
creator_id: creator_id,
id: id,
parent_id: parent_id,
title: title,
updated_at: updated_at,
pages: pages
}
end
def as_json(*params)
api_attributes.as_json(*params)
end
def to_xml(options = {})
api_attributes.to_xml(options.reverse_merge(root: "forum_post"))
end
end
include LockMethods
include StickyMethods
include ParentMethods
include ApiMethods
def self.updated?(user)
conds = []
conds += [ "creator_id <> %d" % [ user.id ] ] unless user.is_anonymous?
newest_topic = ForumPost.where(conds).order(id: :desc).select(:created_at).take
return false if newest_topic.nil?
newest_topic.created_at > user.last_forum_topic_read_at
end
def validate_title
if is_parent?
if title.blank?
errors.add :title, "missing"
throw :abort
end
if title !~ /\S/
errors.add :title, "missing"
throw :abort
end
end
true
end
def initialize_last_updated_by
if is_parent?
update(last_updated_by: creator_id)
end
end
def clear_cache
Rails.cache.delete LATEST_CACHE_KEY
end
def last_updater
updater.name
rescue
CONFIG["default_guest_name"]
end
def author
creator.name
end
def pages
((response_count == 0 ? 1 : response_count) / 30.0).ceil
end
def self.latest
where(parent_id: nil).reorder(updated_at: :desc).paginate(page: 1, per_page: 10)
end
end