This commit is contained in:
@@ -127,17 +127,20 @@ class PostsController < ApplicationController
|
||||
post = Post.new(title:, url:, thumbnail_base: nil, uploaded_user: current_user,
|
||||
original_created_from:, original_created_before:)
|
||||
post.thumbnail.attach(thumbnail)
|
||||
if post.save
|
||||
post.resized_thumbnail!
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
post.save!
|
||||
tags = Tag.normalise_tags(tag_names)
|
||||
tags = Tag.expand_parent_tags(tags)
|
||||
sync_post_tags!(post, tags)
|
||||
post.resized_thumbnail!
|
||||
PostVersionRecorder.record!(post:, event_type: :create, created_by_user: current_user)
|
||||
end
|
||||
|
||||
post.reload
|
||||
render json: PostRepr.base(post), status: :created
|
||||
else
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
render json: { errors: post.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
rescue Tag::NicoTagNormalisationError
|
||||
head :bad_request
|
||||
end
|
||||
@@ -166,19 +169,22 @@ class PostsController < ApplicationController
|
||||
original_created_before = params[:original_created_before]
|
||||
|
||||
post = Post.find(params[:id].to_i)
|
||||
if post.update(title:, original_created_from:, original_created_before:)
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
post.update!(title:, original_created_from:, original_created_before:)
|
||||
tags = post.tags.where(category: 'nico').to_a +
|
||||
Tag.normalise_tags(tag_names, with_tagme: false)
|
||||
tags = Tag.expand_parent_tags(tags)
|
||||
sync_post_tags!(post, tags)
|
||||
PostVersionRecorder.record!(post:, event_type: :update, created_by_user: current_user)
|
||||
end
|
||||
|
||||
post.reload
|
||||
json = post.as_json
|
||||
json['tags'] = build_tag_tree_for(post.tags)
|
||||
render json:, status: :ok
|
||||
else
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
render json: post.errors, status: :unprocessable_entity
|
||||
end
|
||||
rescue Tag::NicoTagNormalisationError
|
||||
head :bad_request
|
||||
end
|
||||
|
||||
@@ -11,6 +11,7 @@ class Post < ApplicationRecord
|
||||
|
||||
has_many :user_post_views, dependent: :delete_all
|
||||
has_many :post_similarities, dependent: :delete_all
|
||||
has_many :post_versions
|
||||
|
||||
has_one_attached :thumbnail
|
||||
|
||||
@@ -30,6 +31,8 @@ class Post < ApplicationRecord
|
||||
super(options).merge(thumbnail: nil)
|
||||
end
|
||||
|
||||
def snapshot_tag_names = tags.joins(:tag_name).order('tag_names.name').pluck('tag_names.name')
|
||||
|
||||
def related limit: nil
|
||||
ids = post_similarities.order(cos: :desc)
|
||||
ids = ids.limit(limit) if limit
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
class PostVersion < ApplicationRecord
|
||||
before_update do
|
||||
raise ActiveRecord::ReadOnlyRecord, '版は更新できません.'
|
||||
end
|
||||
|
||||
before_destroy do
|
||||
raise ActiveRecord::ReadOnlyRecord, '版は削除できません.'
|
||||
end
|
||||
|
||||
belongs_to :post
|
||||
belongs_to :parent, class_name: 'Post', optional: true
|
||||
belongs_to :created_by_user, class_name: 'User', optional: true
|
||||
|
||||
enum :event_type, create: 'create', update: 'update', discard: 'discard', restore: 'restore'
|
||||
|
||||
validates :version_no, presence: true, numerically: { only_integer: true, greater_than: 0 }
|
||||
validates :event_type, presence: true, inclusion: { in: event_types.keys }
|
||||
validates :url, presence: true
|
||||
|
||||
validate :validate_original_created_range
|
||||
|
||||
scope :chronological, -> { order(:version_no, :id) }
|
||||
|
||||
private
|
||||
|
||||
def validate_original_created_range
|
||||
f = original_created_from
|
||||
b = original_created_before
|
||||
return if f.blank? || b.blank?
|
||||
|
||||
if f >= b
|
||||
errors.add :original_created_before, 'オリジナルの作成日時の順番がをかしぃです.'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,6 @@
|
||||
require 'set'
|
||||
|
||||
|
||||
class Tag < ApplicationRecord
|
||||
include MyDiscard
|
||||
|
||||
@@ -150,6 +153,8 @@ class Tag < ApplicationRecord
|
||||
def self.merge_tags! target_tag, source_tags
|
||||
target_tag => Tag
|
||||
|
||||
affected_post_ids = Set.new
|
||||
|
||||
Tag.transaction do
|
||||
Array(source_tags).compact.uniq.each do |source_tag|
|
||||
source_tag => Tag
|
||||
@@ -158,6 +163,7 @@ class Tag < ApplicationRecord
|
||||
|
||||
source_tag.post_tags.kept.find_each do |source_pt|
|
||||
post_id = source_pt.post_id
|
||||
affected_post_ids << post_id
|
||||
source_pt.discard_by!(nil)
|
||||
unless PostTag.kept.exists?(post_id:, tag: target_tag)
|
||||
PostTag.create!(post_id:, tag: target_tag)
|
||||
@@ -180,6 +186,10 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
Post.where(id: affected_post_ids.to_a).find_each do |post|
|
||||
PostVersionRecorder.record!(post:, event_type: :update, created_by_user: nil)
|
||||
end
|
||||
|
||||
# 投稿件数を再集計
|
||||
target_tag.update_columns(post_count: PostTag.kept.where(tag: target_tag).count)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
class PostVersionRecorder
|
||||
def self.record! post:, event_type:, created_by_user:
|
||||
new(post:, event_type:, created_by_user:).record!
|
||||
end
|
||||
|
||||
def initialize post:, event_type:, created_user:
|
||||
@post = post
|
||||
@event_type = event_type
|
||||
@created_by_user = created_by_user
|
||||
end
|
||||
|
||||
def record!
|
||||
@post.with_lock do
|
||||
latest = @post.post_versions.order(version_no: :desc).first
|
||||
attrs = snapshot_attributes
|
||||
|
||||
return latest if @event_type == :update && latest && same_snapshot?(latest, attrs)
|
||||
|
||||
PostVersion.create!(
|
||||
post: @post,
|
||||
version_no: (latest&.version_no || 0) + 1,
|
||||
event_type: @event_type,
|
||||
title: attrs[:title],
|
||||
url: attrs[:url],
|
||||
thumbnail_base: attrs[:thumbnail_base],
|
||||
tags: attrs[:url],
|
||||
parent: attrs[:parent],
|
||||
original_created_from: attrs[:original_created_from],
|
||||
original_created_before: attrs[:original_created_before],
|
||||
created_at: Time.current,
|
||||
created_by_user: @created_by_user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def snapshot_attributes
|
||||
{ title: @post.title,
|
||||
url: @post.url,
|
||||
thumbnail_base: @post.thumbnail_base,
|
||||
tags: @post.snapshot_tag_names.join(' '),
|
||||
parent: @post.parent,
|
||||
original_created_from: @post.original_created_from,
|
||||
original_created_before: @post.original_created_before }
|
||||
end
|
||||
|
||||
def same_snapshot? version, attrs
|
||||
true &&
|
||||
version.title == attrs[:title] &&
|
||||
version.url == attrs[:url] &&
|
||||
version.thumbnail_base == attrs[:thumbnail_base] &&
|
||||
version.tags == attrs[:tags] &&
|
||||
version.parent_id == attrs[:parent]&.id &&
|
||||
version.original_created_from == attrs[:original_created_from] &&
|
||||
version.original_created_before == attrs[:original_created_before]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,80 @@
|
||||
class CreatePostVersions < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
create_table :post_versions do |t|
|
||||
t.references :post, null: false, foreign_key: true
|
||||
t.integer :version_no, null: false
|
||||
t.string :event_type, null: false
|
||||
t.string :title
|
||||
t.string :url, limit: 768, null: false
|
||||
t.string :thumbnail_base, limit: 2000
|
||||
t.text :tags, null: false
|
||||
t.references :parent, foreign_key: { to_table: :posts }
|
||||
t.datetime :original_created_from
|
||||
t.datetime :original_created_before
|
||||
t.datetime :created_at, null: false
|
||||
t.references :created_by_user, foreign_key: { to_table: :users }
|
||||
|
||||
t.index [:post_id, :version_no], unique: true
|
||||
t.check_constraint 'version_no > 0'
|
||||
t.check_constraint "event_type IN ('create', 'update', 'discard', 'restore')"
|
||||
end
|
||||
|
||||
reversible do |dir|
|
||||
dir.up do
|
||||
execute <<~SQL
|
||||
INSERT INTO
|
||||
post_versions(
|
||||
post_id
|
||||
, version_no
|
||||
, event_type
|
||||
, title
|
||||
, url
|
||||
, thumbnail_base
|
||||
, tags
|
||||
, parent_id
|
||||
, original_created_from
|
||||
, original_created_before
|
||||
, created_at
|
||||
, created_by_user_id)
|
||||
SELECT
|
||||
posts.id
|
||||
, 1
|
||||
, 'create'
|
||||
, posts.title
|
||||
, posts.url
|
||||
, posts.thumbnail_base
|
||||
, COALESCE(tag_snapshots.tags, '')
|
||||
, posts.parent_id
|
||||
, posts.original_created_from
|
||||
, posts.original_created_before
|
||||
, posts.created_at
|
||||
, posts.uploaded_user_id
|
||||
FROM
|
||||
posts
|
||||
LEFT JOIN
|
||||
(
|
||||
SELECT
|
||||
post_tags.post_id
|
||||
, GROUP_CONCAT(tag_names.name ORDER BY tag_names.name SEPARATOR ' ') AS tags
|
||||
FROM
|
||||
post_tags
|
||||
INNER JOIN
|
||||
tags
|
||||
ON
|
||||
tags.id = post_tags.tag_id
|
||||
INNER JOIN
|
||||
tag_names
|
||||
ON
|
||||
tag_names.id = tags.tag_name_id
|
||||
WHERE
|
||||
post_tags.discarded_at IS NULL
|
||||
GROUP BY
|
||||
post_tags.post_id
|
||||
) tag_snapshots
|
||||
ON
|
||||
tag_snapshots.post_id = posts.id
|
||||
SQL
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -61,6 +61,9 @@ namespace :nico do
|
||||
original_created_from = original_created_at&.change(sec: 0)
|
||||
original_created_before = original_created_from&.+(1.minute)
|
||||
|
||||
post_created = false
|
||||
post_changed = false
|
||||
|
||||
if post
|
||||
attrs = { title:, original_created_from:, original_created_before: }
|
||||
|
||||
@@ -76,11 +79,13 @@ namespace :nico do
|
||||
end
|
||||
|
||||
post.assign_attributes(attrs)
|
||||
if post.changed?
|
||||
post_changed = post.changed?
|
||||
if post_changed
|
||||
post.save!
|
||||
post.resized_thumbnail! if post.thumbnail.attached?
|
||||
end
|
||||
else
|
||||
post_created = true
|
||||
url = "https://www.nicovideo.jp/watch/#{ code }"
|
||||
thumbnail_base = fetch_thumbnail.(url) rescue nil
|
||||
post = Post.new(title:, url:, thumbnail_base:, uploaded_user: nil,
|
||||
@@ -140,6 +145,12 @@ namespace :nico do
|
||||
desired_all_tag_ids.uniq!
|
||||
|
||||
sync_post_tags!(post, desired_all_tag_ids, current_tag_ids: kept_tag_ids)
|
||||
|
||||
if post_created
|
||||
PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil)
|
||||
elsif post_changed || kept_tag_ids != desired_all_tag_ids.to_set
|
||||
PostVersionRecorder.record!(post:, event_type: :update, created_by_user: nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user