This commit is contained in:
@@ -238,21 +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,
|
||||
name_changed: name.present? && name != old_name)
|
||||
|
||||
record_tag_version!(
|
||||
tag,
|
||||
event_type: :update,
|
||||
created_by_user: current_user,
|
||||
name_changed:,
|
||||
wiki_page:)
|
||||
end
|
||||
|
||||
render json: TagRepr.base(tag.reload)
|
||||
@@ -277,6 +282,7 @@ class TagsController < ApplicationController
|
||||
|
||||
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?
|
||||
@@ -287,7 +293,8 @@ class TagsController < ApplicationController
|
||||
tag,
|
||||
event_type: :update,
|
||||
created_by_user: current_user,
|
||||
name_changed:)
|
||||
name_changed:,
|
||||
wiki_page:)
|
||||
end
|
||||
|
||||
render json: TagRepr.base(tag.reload)
|
||||
@@ -309,7 +316,7 @@ class TagsController < ApplicationController
|
||||
material: material.as_json&.merge(file:, content_type:))
|
||||
end
|
||||
|
||||
def record_tag_version! tag, event_type:, created_by_user:, name_changed: false
|
||||
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:)
|
||||
return
|
||||
@@ -319,10 +326,13 @@ class TagsController < ApplicationController
|
||||
|
||||
return unless name_changed
|
||||
|
||||
wiki_page = tag.tag_name.wiki_page
|
||||
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:)
|
||||
WikiVersionRecorder.record!(
|
||||
page: wiki_page,
|
||||
event_type: :update,
|
||||
created_by_user:)
|
||||
end
|
||||
|
||||
def update_aliases! tag, alias_names
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tag and wiki history integrity', type: :request do
|
||||
let(:member_user) { create(:user, role: 'member') }
|
||||
|
||||
def stub_current_user user
|
||||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user)
|
||||
end
|
||||
|
||||
def create_tag! name:, category: :general
|
||||
tag_name = TagName.create!(name:)
|
||||
Tag.create!(tag_name:, category:)
|
||||
end
|
||||
|
||||
def create_wiki_for_tag! tag:, body: 'wiki body', user: member_user
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: tag.tag_name,
|
||||
body:,
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
end
|
||||
|
||||
before do
|
||||
stub_current_user(member_user)
|
||||
end
|
||||
|
||||
describe 'PATCH /tags/:id' do
|
||||
it 'records wiki_version when tag name changes and tag has wiki' do
|
||||
tag = create_tag!(name: 'patch_tag_wiki_before')
|
||||
wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')
|
||||
|
||||
expect {
|
||||
patch "/tags/#{ tag.id }", params: {
|
||||
name: 'patch_tag_wiki_after',
|
||||
}
|
||||
}
|
||||
.to change(TagVersion, :count).by(2)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
tag.reload
|
||||
wiki_page.reload
|
||||
version = wiki_page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(tag.name).to eq('patch_tag_wiki_after')
|
||||
expect(wiki_page.title).to eq('patch_tag_wiki_after')
|
||||
|
||||
expect(version).to have_attributes(
|
||||
event_type: 'update',
|
||||
title: 'patch_tag_wiki_after',
|
||||
body: 'wiki body before',
|
||||
created_by_user_id: member_user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not record wiki_version when only category changes' do
|
||||
tag = create_tag!(name: 'patch_tag_category_only')
|
||||
wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')
|
||||
|
||||
before_wiki_versions = wiki_page.wiki_versions.count
|
||||
|
||||
expect {
|
||||
patch "/tags/#{ tag.id }", params: {
|
||||
category: 'meme',
|
||||
}
|
||||
}
|
||||
.to change(TagVersion, :count).by(2)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
tag.reload
|
||||
wiki_page.reload
|
||||
|
||||
expect(tag.name).to eq('patch_tag_category_only')
|
||||
expect(tag.category).to eq('meme')
|
||||
expect(wiki_page.wiki_versions.count).to eq(before_wiki_versions)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /tags/:id' do
|
||||
it 'records wiki_version when tag name changes and tag has wiki' do
|
||||
tag = create_tag!(name: 'put_tag_wiki_before')
|
||||
wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')
|
||||
|
||||
expect {
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
name: 'put_tag_wiki_after',
|
||||
category: 'general',
|
||||
aliases: '',
|
||||
parent_tags: '',
|
||||
}
|
||||
}
|
||||
.to change(TagVersion, :count).by(2)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
tag.reload
|
||||
wiki_page.reload
|
||||
version = wiki_page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(tag.name).to eq('put_tag_wiki_after')
|
||||
expect(wiki_page.title).to eq('put_tag_wiki_after')
|
||||
|
||||
expect(version).to have_attributes(
|
||||
event_type: 'update',
|
||||
title: 'put_tag_wiki_after',
|
||||
body: 'wiki body before',
|
||||
created_by_user_id: member_user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not record wiki_version when only category changes' do
|
||||
tag = create_tag!(name: 'put_tag_category_only')
|
||||
wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')
|
||||
|
||||
before_wiki_versions = wiki_page.wiki_versions.count
|
||||
|
||||
expect {
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
name: 'put_tag_category_only',
|
||||
category: 'meme',
|
||||
aliases: '',
|
||||
parent_tags: '',
|
||||
}
|
||||
}
|
||||
.to change(TagVersion, :count).by(2)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
tag.reload
|
||||
wiki_page.reload
|
||||
|
||||
expect(tag.name).to eq('put_tag_category_only')
|
||||
expect(tag.category).to eq('meme')
|
||||
expect(wiki_page.wiki_versions.count).to eq(before_wiki_versions)
|
||||
end
|
||||
|
||||
it 'does not record wiki_version when only aliases change' do
|
||||
tag = create_tag!(name: 'put_tag_alias_only')
|
||||
wiki_page = create_wiki_for_tag!(tag:, body: 'wiki body before')
|
||||
|
||||
before_wiki_versions = wiki_page.wiki_versions.count
|
||||
|
||||
expect {
|
||||
put "/tags/#{ tag.id }", params: {
|
||||
name: 'put_tag_alias_only',
|
||||
category: 'general',
|
||||
aliases: 'put_tag_alias_only_alias',
|
||||
parent_tags: '',
|
||||
}
|
||||
}
|
||||
.to change(TagVersion, :count).by(2)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(wiki_page.reload.wiki_versions.count).to eq(before_wiki_versions)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Wiki body search', type: :request do
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
it 'searches wiki pages by body text' do
|
||||
pending 'Wiki 本文検索実装時に有効化する'
|
||||
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: 'wiki_body_search_hit'),
|
||||
body: 'unique body keyword for wiki search',
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: 'wiki_body_search_miss'),
|
||||
body: 'ordinary body',
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
|
||||
get '/wiki/search', params: { body: 'unique body keyword' }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json.map { |page| page['title'] }).to include('wiki_body_search_hit')
|
||||
expect(json.map { |page| page['title'] }).not_to include('wiki_body_search_miss')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Wiki conflict handling', type: :request do
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
def auth_headers user
|
||||
{ 'X-Transfer-Code' => user.inheritance_code }
|
||||
end
|
||||
|
||||
it 'returns 409 when base_revision_id is stale' do
|
||||
page =
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: 'wiki_conflict_request'),
|
||||
body: 'first',
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
|
||||
stale_id = page.current_revision.id
|
||||
|
||||
Wiki::Commit.content!(
|
||||
page:,
|
||||
body: 'second',
|
||||
created_user: user,
|
||||
message: 'other edit',
|
||||
base_revision_id: stale_id)
|
||||
|
||||
put "/wiki/#{ page.id }",
|
||||
params: {
|
||||
title: 'wiki_conflict_request',
|
||||
body: 'third',
|
||||
message: 'stale',
|
||||
base_revision_id: stale_id,
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:conflict)
|
||||
|
||||
page.reload
|
||||
expect(page.body).to eq('second')
|
||||
expect(page.current_revision.message).to eq('other edit')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,196 @@
|
||||
require 'cgi'
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Wiki history integrity', type: :request do
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
def auth_headers user
|
||||
{ 'X-Transfer-Code' => user.inheritance_code }
|
||||
end
|
||||
|
||||
def create_wiki_page title:, body: 'body', message: 'init', user: self.user
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: title),
|
||||
body:,
|
||||
created_by_user: user,
|
||||
message:)
|
||||
end
|
||||
|
||||
describe 'POST /wiki' do
|
||||
it 'creates wiki_page, wiki_revision, and wiki_version atomically' do
|
||||
expect {
|
||||
post '/wiki',
|
||||
params: {
|
||||
title: 'wiki_history_create_atomic',
|
||||
body: "a\nb\nc",
|
||||
message: 'initial commit',
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.to change(WikiPage, :count).by(1)
|
||||
.and change(WikiRevision, :count).by(1)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
|
||||
page = WikiPage.find(json.fetch('id'))
|
||||
revision = page.current_revision
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(page.title).to eq('wiki_history_create_atomic')
|
||||
expect(page.body).to eq("a\nb\nc")
|
||||
|
||||
expect(revision).to be_content
|
||||
expect(revision.message).to eq('initial commit')
|
||||
expect(revision.lines_count).to eq(3)
|
||||
|
||||
expect(version).to have_attributes(
|
||||
version_no: 1,
|
||||
event_type: 'create',
|
||||
title: 'wiki_history_create_atomic',
|
||||
body: "a\nb\nc",
|
||||
reason: 'initial commit',
|
||||
created_by_user_id: user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns 422 and creates nothing when normalised body is blank' do
|
||||
expect {
|
||||
post '/wiki',
|
||||
params: {
|
||||
title: 'wiki_history_blank_body',
|
||||
body: "\r\n\r\n",
|
||||
message: 'blank',
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.not_to change(WikiPage, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(WikiPage.joins(:tag_name).where(tag_names: { name: 'wiki_history_blank_body' })).not_to exist
|
||||
end
|
||||
|
||||
it 'returns 422 and creates no partial page when title already exists' do
|
||||
create_wiki_page(title: 'wiki_history_duplicate_title', body: 'first')
|
||||
|
||||
expect {
|
||||
post '/wiki',
|
||||
params: {
|
||||
title: 'wiki_history_duplicate_title',
|
||||
body: 'second',
|
||||
message: 'duplicate',
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.not_to change(WikiPage, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(WikiPage.joins(:tag_name).where(tag_names: { name: 'wiki_history_duplicate_title' }).count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /wiki/:id' do
|
||||
it 'updates body and records wiki_revision and wiki_version' do
|
||||
page = create_wiki_page(title: 'wiki_history_update_body', body: 'before')
|
||||
current_id = page.current_revision.id
|
||||
|
||||
expect {
|
||||
put "/wiki/#{ page.id }",
|
||||
params: {
|
||||
title: 'wiki_history_update_body',
|
||||
body: 'after',
|
||||
message: 'edit body',
|
||||
base_revision_id: current_id,
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.to change(WikiRevision, :count).by(1)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
page.reload
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(page.title).to eq('wiki_history_update_body')
|
||||
expect(page.body).to eq('after')
|
||||
|
||||
expect(version).to have_attributes(
|
||||
event_type: 'update',
|
||||
title: 'wiki_history_update_body',
|
||||
body: 'after',
|
||||
reason: 'edit body',
|
||||
created_by_user_id: user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'renames title and records wiki_version with new title' do
|
||||
page = create_wiki_page(title: 'wiki_history_rename_before', body: 'before')
|
||||
current_id = page.current_revision.id
|
||||
|
||||
expect {
|
||||
put "/wiki/#{ page.id }",
|
||||
params: {
|
||||
title: 'wiki_history_rename_after',
|
||||
body: 'after',
|
||||
message: 'rename',
|
||||
base_revision_id: current_id,
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.to change(WikiRevision, :count).by(1)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
page.reload
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(page.title).to eq('wiki_history_rename_after')
|
||||
expect(page.body).to eq('after')
|
||||
|
||||
expect(version).to have_attributes(
|
||||
event_type: 'update',
|
||||
title: 'wiki_history_rename_after',
|
||||
body: 'after',
|
||||
reason: 'rename',
|
||||
created_by_user_id: user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not change title, body, revision, or version on stale base_revision_id' do
|
||||
page = create_wiki_page(title: 'wiki_history_conflict_page', body: 'first')
|
||||
stale_id = page.current_revision.id
|
||||
|
||||
Wiki::Commit.content!(
|
||||
page:,
|
||||
body: 'second',
|
||||
created_user: user,
|
||||
message: 'other edit',
|
||||
base_revision_id: stale_id)
|
||||
|
||||
page.reload
|
||||
current_title = page.title
|
||||
current_body = page.body
|
||||
revision_count = page.wiki_revisions.count
|
||||
version_count = page.wiki_versions.count
|
||||
|
||||
put "/wiki/#{ page.id }",
|
||||
params: {
|
||||
title: 'wiki_history_conflict_renamed',
|
||||
body: 'third',
|
||||
message: 'stale edit',
|
||||
base_revision_id: stale_id,
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:conflict)
|
||||
|
||||
page.reload
|
||||
expect(page.title).to eq(current_title)
|
||||
expect(page.body).to eq(current_body)
|
||||
expect(page.wiki_revisions.count).to eq(revision_count)
|
||||
expect(page.wiki_versions.count).to eq(version_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Wiki restore', type: :request do
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
def auth_headers user
|
||||
{ 'X-Transfer-Code' => user.inheritance_code }
|
||||
end
|
||||
|
||||
it 'restores wiki page to previous version' do
|
||||
pending 'Wiki 版巻き戻し API 実装時に有効化する'
|
||||
|
||||
page =
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: 'wiki_restore_page'),
|
||||
body: 'v1',
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
|
||||
v1 = page.wiki_versions.order(:version_no).last
|
||||
|
||||
Wiki::Commit.content!(
|
||||
page:,
|
||||
body: 'v2',
|
||||
created_user: user,
|
||||
message: 'edit',
|
||||
base_revision_id: page.current_revision.id)
|
||||
|
||||
post "/wiki/#{ page.id }/restore",
|
||||
params: { version_no: v1.version_no },
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(page.reload.body).to eq('v1')
|
||||
expect(page.wiki_versions.order(:version_no).last.event_type).to eq('restore')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Wiki title collision', type: :request do
|
||||
let!(:user) { create_member_user! }
|
||||
|
||||
def auth_headers user
|
||||
{ 'X-Transfer-Code' => user.inheritance_code }
|
||||
end
|
||||
|
||||
def create_wiki_page title:, body:
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: title),
|
||||
body:,
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
end
|
||||
|
||||
it 'returns 422 when renaming wiki title to existing title' do
|
||||
source = create_wiki_page(title: 'wiki_collision_source', body: 'source body')
|
||||
create_wiki_page(title: 'wiki_collision_target', body: 'target body')
|
||||
|
||||
source_revision_count = source.wiki_revisions.count
|
||||
source_version_count = source.wiki_versions.count
|
||||
old_title = source.title
|
||||
old_body = source.body
|
||||
|
||||
put "/wiki/#{ source.id }",
|
||||
params: {
|
||||
title: 'wiki_collision_target',
|
||||
body: 'new body',
|
||||
message: 'rename collision',
|
||||
base_revision_id: source.current_revision.id,
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
|
||||
source.reload
|
||||
|
||||
expect(source.title).to eq(old_title)
|
||||
expect(source.body).to eq(old_body)
|
||||
expect(source.wiki_revisions.count).to eq(source_revision_count)
|
||||
expect(source.wiki_versions.count).to eq(source_version_count)
|
||||
end
|
||||
|
||||
it 'returns 422 when creating wiki with existing title' do
|
||||
create_wiki_page(title: 'wiki_collision_create', body: 'already exists')
|
||||
|
||||
expect {
|
||||
post '/wiki',
|
||||
params: {
|
||||
title: 'wiki_collision_create',
|
||||
body: 'new body',
|
||||
message: 'duplicate create',
|
||||
},
|
||||
headers: auth_headers(user)
|
||||
}
|
||||
.not_to change(WikiPage, :count)
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,173 @@
|
||||
require 'digest'
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Wiki::Commit do
|
||||
let(:user) { create_member_user! }
|
||||
|
||||
def create_page title:, body: 'initial body'
|
||||
described_class.create_content!(
|
||||
tag_name: TagName.create!(name: title),
|
||||
body:,
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
end
|
||||
|
||||
describe '.create_content!' do
|
||||
it 'creates page, revision, and version with normalised body' do
|
||||
expect {
|
||||
described_class.create_content!(
|
||||
tag_name: TagName.create!(name: 'commit_integrity_create'),
|
||||
body: "a\r\nb\r\n\r\n",
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
}
|
||||
.to change(WikiPage, :count).by(1)
|
||||
.and change(WikiRevision, :count).by(1)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
page = WikiPage.joins(:tag_name).find_by!(tag_names: { name: 'commit_integrity_create' })
|
||||
revision = page.current_revision
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(page.body).to eq("a\nb")
|
||||
expect(revision.lines_count).to eq(2)
|
||||
expect(version.body).to eq("a\nb")
|
||||
expect(version.reason).to eq('init')
|
||||
end
|
||||
|
||||
it 'rejects body that becomes blank after normalisation' do
|
||||
tag_name = TagName.create!(name: 'commit_integrity_blank')
|
||||
|
||||
expect {
|
||||
described_class.create_content!(
|
||||
tag_name:,
|
||||
body: "\r\n\r\n",
|
||||
created_by_user: user,
|
||||
message: 'blank')
|
||||
}
|
||||
.to raise_error(ActiveRecord::RecordInvalid)
|
||||
|
||||
expect(WikiPage.where(tag_name:)).not_to exist
|
||||
end
|
||||
end
|
||||
|
||||
describe '.content!' do
|
||||
it 'updates page body, revision, and version' do
|
||||
page = create_page(title: 'commit_integrity_update', body: 'before')
|
||||
current_id = page.current_revision.id
|
||||
|
||||
expect {
|
||||
described_class.content!(
|
||||
page:,
|
||||
body: 'after',
|
||||
created_user: user,
|
||||
message: 'edit',
|
||||
base_revision_id: current_id)
|
||||
}
|
||||
.to change(WikiRevision, :count).by(1)
|
||||
.and change(WikiVersion, :count).by(1)
|
||||
|
||||
page.reload
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(page.body).to eq('after')
|
||||
expect(version.body).to eq('after')
|
||||
expect(version.reason).to eq('edit')
|
||||
end
|
||||
|
||||
it 'does not record tag_version on body-only wiki update' do
|
||||
tag_name = TagName.create!(name: 'commit_integrity_linked_tag')
|
||||
tag = Tag.create!(tag_name:, category: :general)
|
||||
|
||||
page =
|
||||
described_class.create_content!(
|
||||
tag_name:,
|
||||
body: 'before',
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
|
||||
TagVersionRecorder.record!(
|
||||
tag:,
|
||||
event_type: :create,
|
||||
created_by_user: user)
|
||||
|
||||
before_count = tag.reload.tag_versions.count
|
||||
|
||||
described_class.content!(
|
||||
page:,
|
||||
body: 'after',
|
||||
created_user: user,
|
||||
message: 'edit',
|
||||
base_revision_id: page.current_revision.id)
|
||||
|
||||
expect(tag.reload.tag_versions.count).to eq(before_count)
|
||||
end
|
||||
|
||||
it 'raises conflict and leaves page, revision, and version unchanged' do
|
||||
page = create_page(title: 'commit_integrity_conflict', body: 'first')
|
||||
stale_id = page.current_revision.id
|
||||
|
||||
described_class.content!(
|
||||
page:,
|
||||
body: 'second',
|
||||
created_user: user,
|
||||
message: 'second',
|
||||
base_revision_id: stale_id)
|
||||
|
||||
page.reload
|
||||
before_body = page.body
|
||||
before_revision_count = page.wiki_revisions.count
|
||||
before_version_count = page.wiki_versions.count
|
||||
|
||||
expect {
|
||||
described_class.content!(
|
||||
page:,
|
||||
body: 'third',
|
||||
created_user: user,
|
||||
message: 'stale',
|
||||
base_revision_id: stale_id)
|
||||
}
|
||||
.to raise_error(Wiki::Commit::Conflict)
|
||||
|
||||
page.reload
|
||||
expect(page.body).to eq(before_body)
|
||||
expect(page.wiki_revisions.count).to eq(before_revision_count)
|
||||
expect(page.wiki_versions.count).to eq(before_version_count)
|
||||
end
|
||||
|
||||
it 'deduplicates duplicated missing wiki lines' do
|
||||
page = create_page(title: 'commit_integrity_dedup', body: 'before')
|
||||
duplicated = 'commit_integrity_duplicate_line'
|
||||
|
||||
described_class.content!(
|
||||
page:,
|
||||
body: "#{ duplicated }\n#{ duplicated }",
|
||||
created_user: user,
|
||||
message: 'dedup',
|
||||
base_revision_id: page.current_revision.id)
|
||||
|
||||
revision = page.reload.current_revision
|
||||
|
||||
expect(WikiLine.where(body: duplicated).count).to eq(1)
|
||||
expect(revision.wiki_revision_lines.count).to eq(2)
|
||||
expect(revision.wiki_revision_lines.pluck(:wiki_line_id).uniq.size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.redirect!' do
|
||||
it 'raises because redirect revisions are deprecated' do
|
||||
page = create_page(title: 'commit_integrity_redirect_source', body: 'source')
|
||||
target = create_page(title: 'commit_integrity_redirect_target', body: 'target')
|
||||
|
||||
expect {
|
||||
described_class.redirect!(
|
||||
page:,
|
||||
redirect_page: target,
|
||||
created_user: user,
|
||||
message: 'redirect',
|
||||
base_revision_id: page.current_revision.id)
|
||||
}
|
||||
.to raise_error(RuntimeError, '廃止しました.')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,99 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe WikiVersionRecorder do
|
||||
let(:user) { create_member_user! }
|
||||
|
||||
def create_page title:, body: 'body'
|
||||
Wiki::Commit.create_content!(
|
||||
tag_name: TagName.create!(name: title),
|
||||
body:,
|
||||
created_by_user: user,
|
||||
message: 'init')
|
||||
end
|
||||
|
||||
describe '.record!' do
|
||||
it 'records title, body, reason, user, and version number' do
|
||||
page = create_page(title: 'wiki_version_recorder_basic', body: 'body')
|
||||
|
||||
expect {
|
||||
described_class.record!(
|
||||
page:,
|
||||
event_type: :update,
|
||||
reason: 'manual reason',
|
||||
created_by_user: user)
|
||||
}
|
||||
.to change { page.reload.wiki_versions.count }.by(1)
|
||||
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(version).to have_attributes(
|
||||
version_no: 2,
|
||||
event_type: 'update',
|
||||
title: 'wiki_version_recorder_basic',
|
||||
body: 'body',
|
||||
reason: 'manual reason',
|
||||
created_by_user_id: user.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not create duplicated update version for identical snapshot' do
|
||||
page = create_page(title: 'wiki_version_recorder_duplicate', body: 'body')
|
||||
|
||||
described_class.record!(
|
||||
page:,
|
||||
event_type: :update,
|
||||
reason: nil,
|
||||
created_by_user: user)
|
||||
|
||||
before_count = page.reload.wiki_versions.count
|
||||
|
||||
described_class.record!(
|
||||
page:,
|
||||
event_type: :update,
|
||||
reason: nil,
|
||||
created_by_user: user)
|
||||
|
||||
expect(page.reload.wiki_versions.count).to eq(before_count)
|
||||
end
|
||||
|
||||
it 'creates update version when title changes' do
|
||||
page = create_page(title: 'wiki_version_recorder_title_before', body: 'body')
|
||||
page.tag_name.update!(name: 'wiki_version_recorder_title_after')
|
||||
|
||||
expect {
|
||||
described_class.record!(
|
||||
page:,
|
||||
event_type: :update,
|
||||
reason: 'rename',
|
||||
created_by_user: user)
|
||||
}
|
||||
.to change { page.reload.wiki_versions.count }.by(1)
|
||||
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(version.title).to eq('wiki_version_recorder_title_after')
|
||||
expect(version.body).to eq('body')
|
||||
expect(version.reason).to eq('rename')
|
||||
end
|
||||
|
||||
it 'creates update version when body changes' do
|
||||
page = create_page(title: 'wiki_version_recorder_body', body: 'before')
|
||||
page.update!(body: 'after')
|
||||
|
||||
expect {
|
||||
described_class.record!(
|
||||
page:,
|
||||
event_type: :update,
|
||||
reason: 'body',
|
||||
created_by_user: user)
|
||||
}
|
||||
.to change { page.reload.wiki_versions.count }.by(1)
|
||||
|
||||
version = page.wiki_versions.order(:version_no).last
|
||||
|
||||
expect(version.title).to eq('wiki_version_recorder_body')
|
||||
expect(version.body).to eq('after')
|
||||
expect(version.reason).to eq('body')
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user