From 5bb80d1a3575e7a620c9b2ab97a66c8329abccbd Mon Sep 17 00:00:00 2001 From: miteruzo Date: Wed, 5 Aug 2026 03:24:01 +0900 Subject: [PATCH] #354 --- .../controllers/post_versions_controller.rb | 77 +++++++++---------- backend/app/controllers/posts_controller.rb | 5 +- backend/app/models/post.rb | 15 ++++ backend/app/services/post_version_recorder.rb | 1 + 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/backend/app/controllers/post_versions_controller.rb b/backend/app/controllers/post_versions_controller.rb index ae3d897..a04abf2 100644 --- a/backend/app/controllers/post_versions_controller.rb +++ b/backend/app/controllers/post_versions_controller.rb @@ -23,17 +23,19 @@ class PostVersionsController < ApplicationController prev.post_id = post_versions.post_id AND prev.version_no = post_versions.version_no - 1 SQL - .select('post_versions.*', 'prev.title AS prev_title', 'prev.url AS prev_url', - 'prev.thumbnail_base AS prev_thumbnail_base', 'prev.tags AS prev_tags', + .select('post_versions.*', + 'prev.title AS prev_title', + 'prev.url AS prev_url', + 'prev.thumbnail_base AS prev_thumbnail_base', + 'prev.tags_json AS prev_tags_json', 'prev.video_ms AS prev_video_ms', 'prev.original_created_from AS prev_original_created_from', 'prev.original_created_before AS prev_original_created_before') q = q.where('post_versions.post_id = ?', post_id) if post_id if tag_name escaped = ActiveRecord::Base.sanitize_sql_like(tag_name.name) - q = q.where(("CONCAT(' ', post_versions.tags, ' ') LIKE :kw " + - "OR CONCAT(' ', prev.tags, ' ') LIKE :kw"), - kw: "% #{ escaped } %") + q = q.where(("JSON_CONTAINTS(post_version.tags_json, JSON_OBJECT('id', :tag_id)) " + + "OR JSON_CONTAINS(prev.tags_json, JSON_OBJECT('id', :tag_id))"), tag_id:) end count = q.except(:select, :order, :limit, :offset).count @@ -47,56 +49,47 @@ class PostVersionsController < ApplicationController private + def tag_literal tag + sections = tag.fetch('sections', []).map do |sec| + begin_ms = sec.fetch('begin_ms') + end_ms = sec['end_ms'] + + "[#{ Post.ms_to_time(begin_ms) }-#{ end_ms ? Post.ms_to_time(end_ms) : '' }]" + end + + "#{ tag.fetch('name') }#{ sections.join }" + end + def serialise_versions rows user_ids = rows.map(&:created_by_user_id).compact.uniq users_by_id = User.where(id: user_ids).pluck(:id, :name).to_h rows.map do |row| - cur_tags = split_tags(row.tags) - prev_tags = split_tags(row.attributes['prev_tags']) + cur_tags = split_tags(row.tags_json.map { tag_literal(_1) }) + prev_tags = split_tags(row.attributes['prev_tags_json'].map { tag_literal(_1) }) - { - post_id: row.post_id, + { post_id: row.post_id, version_no: row.version_no, event_type: row.event_type, - title: { - current: row.title, - prev: row.attributes['prev_title'] - }, - url: { - current: row.url, - prev: row.attributes['prev_url'] - }, - thumbnail: { - current: nil, - prev: nil - }, - thumbnail_base: { - current: row.thumbnail_base, - prev: row.attributes['prev_thumbnail_base'] - }, - video_ms: { - current: row.video_ms, - prev: row.attributes['prev_video_ms'] - }, + title: { current: row.title, prev: row.attributes['prev_title'] }, + url: { current: row.url, prev: row.attributes['prev_url'] }, + thumbnail: { current: nil, prev: nil }, + thumbnail_base: { current: row.thumbnail_base, + prev: row.attributes['prev_thumbnail_base'] }, + video_ms: { current: row.video_ms, prev: row.attributes['prev_video_ms'] }, tags: build_version_tags(cur_tags, prev_tags), original_created_from: { - current: row.original_created_from&.iso8601, - prev: row.attributes['prev_original_created_from']&.iso8601 - }, + current: row.original_created_from&.iso8601, + prev: row.attributes['prev_original_created_from']&.iso8601 }, original_created_before: { - current: row.original_created_before&.iso8601, - prev: row.attributes['prev_original_created_before']&.iso8601 - }, + current: row.original_created_before&.iso8601, + prev: row.attributes['prev_original_created_before']&.iso8601 }, created_at: row.created_at.iso8601, created_by_user: - if row.created_by_user_id - { - id: row.created_by_user_id, - name: users_by_id[row.created_by_user_id] - } - end - } + if row.created_by_user_id + { id: row.created_by_user_id, + name: users_by_id[row.created_by_user_id] } + end } end end diff --git a/backend/app/controllers/posts_controller.rb b/backend/app/controllers/posts_controller.rb index fb3c61a..eec228b 100644 --- a/backend/app/controllers/posts_controller.rb +++ b/backend/app/controllers/posts_controller.rb @@ -699,7 +699,10 @@ class PostsController < ApplicationController end def editable_tag_names_from_version version - version.tags.to_s.split.reject { |name| name.downcase.start_with?('nico:') }.sort + version.tags_json + .reject { _1[:name].downcase.start_with?('nico:') } + .map { tag_literal(_1) } + .sort end def post_snapshot_from_record post diff --git a/backend/app/models/post.rb b/backend/app/models/post.rb index 4f5b09d..cde0929 100644 --- a/backend/app/models/post.rb +++ b/backend/app/models/post.rb @@ -137,6 +137,21 @@ class Post < ApplicationRecord end end + def snapshot_tags_json + post_tags + .kept + .joins(tag: :tag_name) + .includes(:sections, tag: :tag_name) + .order('tag_names.name') + .map do |pt| + { id: pt.tag.id, + version_no: pt.tag.version_no, + name: pt.tag.name, + category: pt.tag.category, + sections: pt.sections.map { { begin_ms: _1.begin_ms, end_ms: _1.end_ms } } } + end + end + def self.section_literal section end_ms = section.end_ms ? Post.ms_to_time(section.end_ms) : '' diff --git a/backend/app/services/post_version_recorder.rb b/backend/app/services/post_version_recorder.rb index 0726884..873770b 100644 --- a/backend/app/services/post_version_recorder.rb +++ b/backend/app/services/post_version_recorder.rb @@ -25,6 +25,7 @@ class PostVersionRecorder < VersionRecorder thumbnail_base: @record.thumbnail_base, video_ms: @record.video_ms, tags: @record.snapshot_tag_names.join(' '), + tags_json: @record.snapshot_tags_json, parent_post_ids: @record.snapshot_parent_post_ids.join(' '), original_created_from: @record.original_created_from, original_created_before: @record.original_created_before }