#317 #317 #317 #317 #317 #317 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #333
This commit was merged in pull request #333.
This commit is contained in:
@@ -238,18 +238,26 @@ class TagsController < ApplicationController
|
||||
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)
|
||||
|
||||
old_name = tag.name
|
||||
name_changed = name != old_name
|
||||
wiki_page = tag.tag_name.wiki_page if name_changed
|
||||
|
||||
tag.update!(category:)
|
||||
tag.tag_name.update!(name:)
|
||||
|
||||
alias_names << old_name if name != old_name
|
||||
alias_names << old_name if name_changed
|
||||
alias_names.delete(name)
|
||||
|
||||
update_aliases!(tag, alias_names)
|
||||
update_parent_tags!(tag, parent_names)
|
||||
|
||||
tag.reload
|
||||
record_tag_version!(tag, event_type: :update, created_by_user: current_user)
|
||||
|
||||
record_tag_version!(
|
||||
tag,
|
||||
event_type: :update,
|
||||
created_by_user: current_user,
|
||||
name_changed:,
|
||||
wiki_page:)
|
||||
end
|
||||
|
||||
render json: TagRepr.base(tag.reload)
|
||||
@@ -272,10 +280,21 @@ class TagsController < ApplicationController
|
||||
ApplicationRecord.transaction do
|
||||
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)
|
||||
|
||||
old_name = tag.name
|
||||
name_changed = name.present? && name != old_name
|
||||
wiki_page = tag.tag_name.wiki_page if name_changed
|
||||
|
||||
tag.tag_name.update!(name:) if name.present?
|
||||
tag.update!(category:) if category.present?
|
||||
|
||||
record_tag_version!(tag, event_type: :update, created_by_user: current_user)
|
||||
tag.reload
|
||||
|
||||
record_tag_version!(
|
||||
tag,
|
||||
event_type: :update,
|
||||
created_by_user: current_user,
|
||||
name_changed:,
|
||||
wiki_page:)
|
||||
end
|
||||
|
||||
render json: TagRepr.base(tag.reload)
|
||||
@@ -297,12 +316,23 @@ class TagsController < ApplicationController
|
||||
material: material.as_json&.merge(file:, content_type:))
|
||||
end
|
||||
|
||||
def record_tag_version! tag, event_type:, created_by_user:
|
||||
def record_tag_version! tag, event_type:, created_by_user:, name_changed: false, wiki_page: nil
|
||||
if tag.nico?
|
||||
NicoTagVersionRecorder.record!(tag:, event_type:, created_by_user:)
|
||||
else
|
||||
TagVersionRecorder.record!(tag:, event_type:, created_by_user:)
|
||||
return
|
||||
end
|
||||
|
||||
TagVersionRecorder.record!(tag:, event_type:, created_by_user:)
|
||||
|
||||
return unless name_changed
|
||||
|
||||
wiki_page ||= tag.tag_name.wiki_page
|
||||
return unless wiki_page&.wiki_versions&.exists?
|
||||
|
||||
WikiVersionRecorder.record!(
|
||||
page: wiki_page,
|
||||
event_type: :update,
|
||||
created_by_user:)
|
||||
end
|
||||
|
||||
def update_aliases! tag, alias_names
|
||||
|
||||
@@ -85,22 +85,24 @@ class WikiPagesController < ApplicationController
|
||||
return head :unauthorized unless current_user
|
||||
return head :forbidden unless current_user.gte_member?
|
||||
|
||||
name = params[:title]&.strip
|
||||
title = params[:title].to_s.strip
|
||||
body = params[:body].to_s
|
||||
message = params[:message].presence
|
||||
|
||||
return head :unprocessable_entity if name.blank? || body.blank?
|
||||
return head :unprocessable_entity if title.blank? || body.blank?
|
||||
|
||||
tag_name = TagName.find_undiscard_or_create_by!(name:)
|
||||
page = WikiPage.new(tag_name:, created_user: current_user, updated_user: current_user)
|
||||
if page.save
|
||||
message = params[:message].presence
|
||||
Wiki::Commit.content!(page:, body:, created_user: current_user, message:)
|
||||
tag_name = TagName.find_undiscard_or_create_by!(name: title)
|
||||
|
||||
render json: WikiPageRepr.base(page), status: :created
|
||||
else
|
||||
render json: { errors: page.errors.full_messages },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
page =
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name:,
|
||||
body:,
|
||||
created_by_user: current_user,
|
||||
message:)
|
||||
|
||||
render json: WikiPageRepr.base(page), status: :created
|
||||
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
|
||||
head :unprocessable_entity
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -113,19 +115,34 @@ class WikiPagesController < ApplicationController
|
||||
return head :unprocessable_entity if title.blank? || body.blank?
|
||||
|
||||
page = WikiPage.find(params[:id])
|
||||
base_revision_id = page.current_revision.id
|
||||
base_revision_id = params[:base_revision_id].presence
|
||||
|
||||
if params[:title].present? && params[:title].strip != page.title
|
||||
return head :unprocessable_entity
|
||||
ApplicationRecord.transaction do
|
||||
page.lock!
|
||||
|
||||
old_title = page.title
|
||||
|
||||
tag = Tag.find_by(tag_name_id: page.tag_name_id)
|
||||
|
||||
if tag && title != old_title
|
||||
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)
|
||||
end
|
||||
|
||||
page.tag_name.update!(name: title) if title != old_title
|
||||
|
||||
message = params[:message].presence
|
||||
Wiki::Commit.content!(page:,
|
||||
body:,
|
||||
created_user: current_user,
|
||||
message:,
|
||||
base_revision_id:)
|
||||
|
||||
if tag && title != old_title
|
||||
tag.reload
|
||||
TagVersionRecorder.record!(tag:, event_type: :update, created_by_user: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
message = params[:message].presence
|
||||
Wiki::Commit.content!(page:,
|
||||
body:,
|
||||
created_user: current_user,
|
||||
message:,
|
||||
base_revision_id:)
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
||||
|
||||
@@ -2,5 +2,6 @@ class IpAddress < ApplicationRecord
|
||||
validates :ip_address, presence: true, length: { maximum: 16 }
|
||||
validates :banned, inclusion: { in: [true, false] }
|
||||
|
||||
has_many :users
|
||||
has_many :user_ips, dependent: :destroy
|
||||
has_many :users, through: :user_ips
|
||||
end
|
||||
|
||||
@@ -13,8 +13,11 @@ class WikiPage < ApplicationRecord
|
||||
foreign_key: :redirect_page_id,
|
||||
dependent: :nullify
|
||||
|
||||
has_many :wiki_versions
|
||||
|
||||
belongs_to :tag_name
|
||||
validates :tag_name, presence: true
|
||||
validates :body, presence: true
|
||||
|
||||
def title = tag_name.name
|
||||
|
||||
@@ -24,11 +27,6 @@ class WikiPage < ApplicationRecord
|
||||
|
||||
def current_revision = wiki_revisions.order(id: :desc).first
|
||||
|
||||
def body
|
||||
rev = current_revision
|
||||
rev.body if rev&.content?
|
||||
end
|
||||
|
||||
def resolve_redirect limit: 10
|
||||
page = self
|
||||
visited = Set.new
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class WikiVersion < ApplicationRecord
|
||||
include VersionRecord
|
||||
|
||||
belongs_to :wiki_page
|
||||
|
||||
validates :title, presence: true
|
||||
validates :body, presence: true
|
||||
end
|
||||
@@ -7,6 +7,31 @@ module Wiki
|
||||
;
|
||||
end
|
||||
|
||||
def self.create_content! tag_name:, body:, created_by_user:, message: nil
|
||||
normalised = normalise_body(body)
|
||||
|
||||
page = WikiPage.new(tag_name:,
|
||||
body: normalised,
|
||||
created_user: created_by_user,
|
||||
updated_user: created_by_user)
|
||||
|
||||
if normalised.blank?
|
||||
page.errors.add(:body, :blank)
|
||||
raise ActiveRecord::RecordInvalid, page
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
page.save!
|
||||
|
||||
new(page:, created_user: created_by_user).content!(
|
||||
body: normalised,
|
||||
message:,
|
||||
base_revision_id: nil)
|
||||
|
||||
page
|
||||
end
|
||||
end
|
||||
|
||||
def self.content! page:, body:, created_user:, message: nil, base_revision_id: nil
|
||||
new(page:, created_user:).content!(body:, message:, base_revision_id:)
|
||||
end
|
||||
@@ -21,7 +46,12 @@ module Wiki
|
||||
end
|
||||
|
||||
def content! body:, message:, base_revision_id:
|
||||
normalised = normalise_body(body)
|
||||
normalised = self.class.normalise_body(body)
|
||||
if normalised.blank?
|
||||
@page.errors.add(:body, :blank)
|
||||
raise ActiveRecord::RecordInvalid, @page
|
||||
end
|
||||
|
||||
lines = split_lines(normalised)
|
||||
|
||||
line_shas = lines.map { |line| Digest::SHA256.hexdigest(line) }
|
||||
@@ -37,10 +67,19 @@ module Wiki
|
||||
current_id = @page.wiki_revisions.maximum(:id)
|
||||
if current_id && current_id != base_revision_id.to_i
|
||||
raise Conflict,
|
||||
"競合が発生してゐます(現在の Id.:#{ current_id },ベース Id.:#{ base_revision_id })."
|
||||
"競合が発生してゐます" +
|
||||
"(現在の Id.:#{ current_id },ベース Id.:#{ base_revision_id })."
|
||||
end
|
||||
end
|
||||
|
||||
@page.update!(body: normalised)
|
||||
|
||||
WikiVersionRecorder.record!(
|
||||
page: @page,
|
||||
event_type: @page.wiki_versions.exists? ? :update : :create,
|
||||
reason: message,
|
||||
created_by_user: @created_user)
|
||||
|
||||
rev = WikiRevision.create!(
|
||||
wiki_page: @page,
|
||||
base_revision_id:,
|
||||
@@ -54,65 +93,45 @@ module Wiki
|
||||
rows = line_ids.each_with_index.map do |line_id, pos|
|
||||
{ wiki_revision_id: rev.id, wiki_line_id: line_id, position: pos }
|
||||
end
|
||||
WikiRevisionLine.insert_all!(rows)
|
||||
WikiRevisionLine.insert_all!(rows) if rows.any?
|
||||
|
||||
rev
|
||||
end
|
||||
end
|
||||
|
||||
def redirect! redirect_page:, message:, base_revision_id:
|
||||
ActiveRecord::Base.transaction do
|
||||
@page.lock!
|
||||
def redirect!(redirect_page:, message:, base_revision_id:) = raise '廃止しました.'
|
||||
|
||||
if base_revision_id.present?
|
||||
current_id = @page.wiki_revisions.maximum(:id)
|
||||
if current_id && current_id != base_revision_id.to_i
|
||||
raise Conflict,
|
||||
"競合が発生してゐます(現在の Id.:#{ current_id },ベース Id.:#{ base_revision_id })."
|
||||
end
|
||||
end
|
||||
|
||||
WikiRevision.create!(
|
||||
wiki_page: @page,
|
||||
base_revision_id:,
|
||||
created_user: @created_user,
|
||||
kind: :redirect,
|
||||
redirect_page:,
|
||||
message:,
|
||||
lines_count: 0,
|
||||
tree_sha256: nil)
|
||||
end
|
||||
def self.normalise_body body
|
||||
s = body.to_s
|
||||
s.gsub!(/\r\n?/, "\n")
|
||||
s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '🖕')
|
||||
s.gsub(/\n+$/, '')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalise_body body
|
||||
s = body.to_s
|
||||
s.gsub!("\r\n", "\n")
|
||||
s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '🖕')
|
||||
end
|
||||
|
||||
def split_lines body
|
||||
body.split("\n")
|
||||
end
|
||||
def split_lines(body) = body.split("\n")
|
||||
|
||||
def upsert_lines! lines, line_shas
|
||||
now = Time.current
|
||||
|
||||
id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h
|
||||
|
||||
missing_rows = []
|
||||
missing_by_sha = { }
|
||||
|
||||
line_shas.each_with_index do |sha, i|
|
||||
next if id_by_sha.key?(sha)
|
||||
next if missing_by_sha.key?(sha)
|
||||
|
||||
missing_rows << { sha256: sha,
|
||||
body: lines[i],
|
||||
created_at: now,
|
||||
updated_at: now }
|
||||
missing_by_sha[sha] = {
|
||||
sha256: sha,
|
||||
body: lines[i],
|
||||
created_at: now,
|
||||
updated_at: now }
|
||||
end
|
||||
|
||||
if missing_rows.any?
|
||||
WikiLine.upsert_all(missing_rows)
|
||||
if missing_by_sha.any?
|
||||
WikiLine.upsert_all(missing_by_sha.values)
|
||||
id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class WikiVersionRecorder < VersionRecorder
|
||||
def self.record! page:, event_type:, reason: nil, created_by_user:
|
||||
new(page:, event_type:, reason:, created_by_user:).record!
|
||||
end
|
||||
|
||||
def initialize page:, event_type:, reason: nil, created_by_user:
|
||||
@reason = reason
|
||||
super(record: page, event_type:, created_by_user:)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def version_class = WikiVersion
|
||||
def version_association = :wiki_versions
|
||||
def record_key = :wiki_page
|
||||
|
||||
def snapshot_attributes = {
|
||||
title: @record.title,
|
||||
body: @record.body,
|
||||
reason: @reason }
|
||||
end
|
||||
Reference in New Issue
Block a user