Browse Source

#317

feature/317
みてるぞ 1 week ago
parent
commit
5f0c1953ce
6 changed files with 319 additions and 99 deletions
  1. +14
    -3
      backend/app/controllers/wiki_pages_controller.rb
  2. +0
    -4
      backend/app/services/wiki/commit.rb
  3. +3
    -7
      backend/spec/requests/tag_versions_spec.rb
  4. +79
    -0
      backend/spec/requests/tags_spec.rb
  5. +177
    -69
      backend/spec/requests/wiki_spec.rb
  6. +46
    -16
      backend/spec/services/wiki/commit_spec.rb

+ 14
- 3
backend/app/controllers/wiki_pages_controller.rb View File

@@ -91,7 +91,7 @@ class WikiPagesController < ApplicationController
return head :unprocessable_entity if name.blank? || body.blank? return head :unprocessable_entity if name.blank? || body.blank?


tag_name = TagName.find_undiscard_or_create_by!(name:) tag_name = TagName.find_undiscard_or_create_by!(name:)
page = WikiPage.new(tag_name:, created_user: current_user, updated_user: current_user)
page = WikiPage.new(tag_name:, body:, created_user: current_user, updated_user: current_user)
if page.save if page.save
message = params[:message].presence message = params[:message].presence
Wiki::Commit.content!(page:, body:, created_user: current_user, message:) Wiki::Commit.content!(page:, body:, created_user: current_user, message:)
@@ -115,10 +115,16 @@ class WikiPagesController < ApplicationController
page = WikiPage.find(params[:id]) page = WikiPage.find(params[:id])
base_revision_id = page.current_revision.id base_revision_id = page.current_revision.id


if params[:title].present? && params[:title].strip != page.title
return head :unprocessable_entity
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 end


page.tag_name.update!(name: title) if title != old_title

message = params[:message].presence message = params[:message].presence
Wiki::Commit.content!(page:, Wiki::Commit.content!(page:,
body:, body:,
@@ -126,6 +132,11 @@ class WikiPagesController < ApplicationController
message:, message:,
base_revision_id:) base_revision_id:)


if tag && title != old_title
tag.reload
TagVersionRecorder.record!(tag:, event_type: :update, created_by_user: current_user)
end

head :ok head :ok
end end




+ 0
- 4
backend/app/services/wiki/commit.rb View File

@@ -79,10 +79,6 @@ module Wiki
event_type: @page.wiki_versions.exists? ? :update : :create, event_type: @page.wiki_versions.exists? ? :update : :create,
reason: message, reason: message,
created_by_user: @created_user) created_by_user: @created_user)
tag = @page.tag_name.tag
if tag&.tag_versions&.exists?
TagVersionRecorder.record!(tag:, event_type: :update, created_by_user: @created_user)
end


rev = WikiRevision.create!( rev = WikiRevision.create!(
wiki_page: @page, wiki_page: @page,


+ 3
- 7
backend/spec/requests/tag_versions_spec.rb View File

@@ -215,7 +215,7 @@ RSpec.describe 'TagVersions API', type: :request do
expect(versions.first['version_no']).to eq(2) expect(versions.first['version_no']).to eq(2)
end end


it 'includes tag versions created by wiki updates' do
it 'does not create tag versions by wiki updates when tag has no versions yet' do
wiki_tag_name = TagName.create!(name: 'tag_versions_from_wiki') wiki_tag_name = TagName.create!(name: 'tag_versions_from_wiki')
wiki_tag = Tag.create!(tag_name: wiki_tag_name, category: :general) wiki_tag = Tag.create!(tag_name: wiki_tag_name, category: :general)


@@ -236,12 +236,8 @@ RSpec.describe 'TagVersions API', type: :request do
get '/tags/versions', params: { id: wiki_tag.id } get '/tags/versions', params: { id: wiki_tag.id }


expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)

versions = json.fetch('versions')

expect(json.fetch('count')).to eq(2)
expect(versions.map { |v| v['event_type'] }).to eq(['update', 'create'])
expect(versions.map { |v| v['name']['current'] }.uniq).to eq(['tag_versions_from_wiki'])
expect(json.fetch('versions')).to eq([])
expect(json.fetch('count')).to eq(0)
end end
end end
end end

+ 79
- 0
backend/spec/requests/tags_spec.rb View File

@@ -472,6 +472,54 @@ RSpec.describe 'Tags API', type: :request do
expect(nico_tag.reload.category).to eq('nico') expect(nico_tag.reload.category).to eq('nico')
end end
end end

it 'PATCH で tag の name を変更すると対応する wiki version を作成する' do
wiki_page =
Wiki::Commit.create_content!(
tag_name: tag.tag_name,
body: 'wiki body before',
created_by_user: member_user,
message: 'init')

expect {
patch "/tags/#{ tag.id }", params: {
name: 'patch_wiki_renamed_tag',
}
}
.to change(TagVersion, :count).by(2)
.and change(WikiVersion, :count).by(1)

expect(response).to have_http_status(:ok)

version = wiki_page.reload.wiki_versions.order(:version_no).last

expect(version).to have_attributes(
event_type: 'update',
title: 'patch_wiki_renamed_tag',
body: 'wiki body before',
created_by_user_id: member_user.id
)
end

it 'tag の category だけを変更しても wiki version は作成しない' do
wiki_page =
Wiki::Commit.create_content!(
tag_name: tag.tag_name,
body: 'wiki body before',
created_by_user: member_user,
message: 'init')

before_count = wiki_page.reload.wiki_versions.count

expect {
patch "/tags/#{ tag.id }", params: {
category: 'meme',
}
}.to change(TagVersion, :count).by(2)

expect(response).to have_http_status(:ok)
expect(wiki_page.reload.wiki_versions.count).to eq(before_count)
end
end end


describe 'GET /tags/with-depth' do describe 'GET /tags/with-depth' do
@@ -976,5 +1024,36 @@ RSpec.describe 'Tags API', type: :request do
expect(TagImplication.where(tag:, parent_tag: child)).not_to exist expect(TagImplication.where(tag:, parent_tag: child)).not_to exist
end end
end end

it 'tag の name を変更すると対応する wiki version を作成する' do
wiki_page =
Wiki::Commit.create_content!(
tag_name: tag.tag_name,
body: 'wiki body before',
created_by_user: member_user,
message: 'init')

expect {
put "/tags/#{ tag.id }", params: {
name: 'put_wiki_renamed_tag',
category: 'general',
aliases: 'unko',
parent_tags: '',
}
}
.to change(TagVersion, :count).by(2)
.and change(WikiVersion, :count).by(1)

expect(response).to have_http_status(:ok)

version = wiki_page.reload.wiki_versions.order(:version_no).last

expect(version).to have_attributes(
event_type: 'update',
title: 'put_wiki_renamed_tag',
body: 'wiki body before',
created_by_user_id: member_user.id
)
end
end end
end end

+ 177
- 69
backend/spec/requests/wiki_spec.rb View File

@@ -4,18 +4,19 @@ require 'securerandom'




RSpec.describe 'Wiki API', type: :request do RSpec.describe 'Wiki API', type: :request do
def auth_headers(user)
{ 'X-Transfer-Code' => user.inheritance_code }
end

let!(:user) { create_member_user! } let!(:user) { create_member_user! }


let!(:tn) { TagName.create!(name: 'spec_wiki_title') } let!(:tn) { TagName.create!(name: 'spec_wiki_title') }
let!(:page) do let!(:page) do
WikiPage.create!(
tag_name: tn,
body: 'init',
created_user: user,
updated_user: user
).tap do |p|
Wiki::Commit.content!(page: p, body: 'init', created_user: user, message: 'init')
end
Wiki::Commit.create_content!(
tag_name: tn,
body: 'init',
created_by_user: user,
message: 'init')
end end


describe 'GET /wiki' do describe 'GET /wiki' do
@@ -42,11 +43,12 @@ RSpec.describe 'Wiki API', type: :request do
context 'when wiki page exists' do context 'when wiki page exists' do
it 'returns wiki page with title' do it 'returns wiki page with title' do
request request

expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)


expect(json).to include( expect(json).to include(
'id' => page.id,
'title' => 'spec_wiki_title')
'id' => page.id,
'title' => 'spec_wiki_title')
end end
end end


@@ -55,6 +57,7 @@ RSpec.describe 'Wiki API', type: :request do


it 'returns 404' do it 'returns 404' do
request request

expect(response).to have_http_status(:not_found) expect(response).to have_http_status(:not_found)
end end
end end
@@ -106,7 +109,13 @@ RSpec.describe 'Wiki API', type: :request do
.and change(WikiRevision, :count).by(1) .and change(WikiRevision, :count).by(1)
.and change(WikiVersion, :count).by(1) .and change(WikiVersion, :count).by(1)


version = page.wiki_versions.order(:version_no).last
expect(response).to have_http_status(:created)

page_id = json.fetch('id')
expect(json.fetch('title')).to eq('TestPage')

created_page = WikiPage.find(page_id)
version = created_page.wiki_versions.order(:version_no).last


expect(version).to have_attributes( expect(version).to have_attributes(
version_no: 1, version_no: 1,
@@ -116,24 +125,16 @@ RSpec.describe 'Wiki API', type: :request do
created_by_user_id: member.id created_by_user_id: member.id
) )


expect(response).to have_http_status(:created)

page_id = json.fetch('id')
expect(json.fetch('title')).to eq('TestPage')

page = WikiPage.find(page_id)
rev = page.current_revision
rev = created_page.current_revision
expect(rev).to be_present expect(rev).to be_present
expect(rev).to be_content expect(rev).to be_content
expect(rev.message).to eq('init') expect(rev.message).to eq('init')


# body が復元できること
expect(page.body).to eq("a\nb\nc")
expect(created_page.body).to eq("a\nb\nc")


# 行数とリレーションの整合
expect(rev.lines_count).to eq(3) expect(rev.lines_count).to eq(3)
expect(rev.wiki_revision_lines.order(:position).pluck(:position)).to eq([0, 1, 2]) expect(rev.wiki_revision_lines.order(:position).pluck(:position)).to eq([0, 1, 2])
expect(rev.wiki_lines.pluck(:body)).to match_array(%w[a b c])
expect(rev.wiki_lines.pluck(:body)).to match_array(['a', 'b', 'c'])
end end


it 'reuses existing WikiLine rows by sha256' do it 'reuses existing WikiLine rows by sha256' do
@@ -166,8 +167,8 @@ RSpec.describe 'Wiki API', type: :request do


expect(rev.lines_count).to eq(2) expect(rev.lines_count).to eq(2)
expect(WikiLine.where(body: duplicated).count).to eq(1) expect(WikiLine.where(body: duplicated).count).to eq(1)
expect(rev.wiki_lines.where(body: duplicated).count).to eq(1)
expect(rev.wiki_revision_lines.count).to eq(2) expect(rev.wiki_revision_lines.count).to eq(2)
expect(rev.wiki_revision_lines.pluck(:wiki_line_id).uniq.size).to eq(1)
end end


it 'normalises CRLF and strips trailing newlines' do it 'normalises CRLF and strips trailing newlines' do
@@ -230,14 +231,6 @@ RSpec.describe 'Wiki API', type: :request do
headers: auth_headers(member) headers: auth_headers(member)
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
end end

it 'returns 422 when title mismatched (if you forbid rename here)' do
put "/wiki/#{page.id}",
params: { title: 'OtherTitle', body: 'x' },
headers: auth_headers(member)
# 君の controller 例だと title 変更は 422 にしてた
expect(response).to have_http_status(:unprocessable_entity)
end
end end


context 'when success' do context 'when success' do
@@ -271,29 +264,29 @@ RSpec.describe 'Wiki API', type: :request do
expect(rev.base_revision_id).to eq(current_id) expect(rev.base_revision_id).to eq(current_id)
end end


it 'wiki page に対応する tag があれば tag version も作成する' do
linked_tag_name = TagName.create!(name: 'wiki_linked_tag_for_version')
it 'wiki body だけを変更しても tag version は作成しない' do
linked_tag_name = TagName.create!(name: 'wiki_body_only_tag')
linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general) linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general)
linked_page = WikiPage.create!(
tag_name: linked_tag_name,
body: 'before',
created_user: member,
updated_user: member
)


Wiki::Commit.content!(
page: linked_page,
body: 'before',
created_user: member,
message: 'init'
)
TagVersionRecorder.record!(
tag: linked_tag,
event_type: :create,
created_by_user: member)

linked_page =
Wiki::Commit.create_content!(
tag_name: linked_tag_name,
body: 'before',
created_by_user: member,
message: 'init')


current_id = linked_page.wiki_revisions.maximum(:id)
current_id = linked_page.current_revision.id
before_count = linked_tag.reload.tag_versions.count


expect { expect {
put "/wiki/#{ linked_page.id }", put "/wiki/#{ linked_page.id }",
params: { params: {
title: 'wiki_linked_tag_for_version',
title: 'wiki_body_only_tag',
body: 'after', body: 'after',
message: 'edit', message: 'edit',
base_revision_id: current_id, base_revision_id: current_id,
@@ -302,15 +295,9 @@ RSpec.describe 'Wiki API', type: :request do
} }
.to change(WikiRevision, :count).by(1) .to change(WikiRevision, :count).by(1)
.and change(WikiVersion, :count).by(1) .and change(WikiVersion, :count).by(1)
.and change { linked_tag.reload.tag_versions.count }.by(1)


expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)

version = linked_tag.reload.tag_versions.order(:version_no).last

expect(version.event_type).to eq('update')
expect(version.name).to eq('wiki_linked_tag_for_version')
expect(version.created_by_user_id).to eq(member.id)
expect(linked_tag.reload.tag_versions.count).to eq(before_count)
end end
end end


@@ -362,14 +349,17 @@ RSpec.describe 'Wiki API', type: :request do


describe 'GET /wiki/search' do describe 'GET /wiki/search' do
before do before do
# 追加で検索ヒット用
TagName.create!(name: 'spec_wiki_title_2')
WikiPage.create!(tag_name: TagName.find_by!(name: 'spec_wiki_title_2'), body: 'init',
created_user: user, updated_user: user)
Wiki::Commit.create_content!(
tag_name: TagName.create!(name: 'spec_wiki_title_2'),
body: 'search body 2',
created_by_user: user,
message: 'init')


TagName.create!(name: 'unrelated_title')
WikiPage.create!(tag_name: TagName.find_by!(name: 'unrelated_title'), body: 'init',
created_user: user, updated_user: user)
Wiki::Commit.create_content!(
tag_name: TagName.create!(name: 'unrelated_title'),
body: 'unrelated body',
created_by_user: user,
message: 'init')
end end


it 'returns up to 20 pages filtered by title like' do it 'returns up to 20 pages filtered by title like' do
@@ -379,7 +369,9 @@ RSpec.describe 'Wiki API', type: :request do
expect(json).to be_an(Array) expect(json).to be_an(Array)


titles = json.map { |p| p['title'] } titles = json.map { |p| p['title'] }
expect(titles).to include('spec_wiki_title', 'spec_wiki_title_2')

expect(titles).to include('spec_wiki_title')
expect(titles).to include('spec_wiki_title_2')
expect(titles).not_to include('unrelated_title') expect(titles).not_to include('unrelated_title')
end end


@@ -430,7 +422,12 @@ RSpec.describe 'Wiki API', type: :request do
it 'returns empty array when page has no revisions and filtered by id' do it 'returns empty array when page has no revisions and filtered by id' do
# 別ページを作って revision 無し # 別ページを作って revision 無し
tn2 = TagName.create!(name: 'spec_no_rev') tn2 = TagName.create!(name: 'spec_no_rev')
p2 = WikiPage.create!(tag_name: tn2, body: 'init', created_user: user, updated_user: user)
# 異常データ: revision 無し WikiPage を直接作る
p2 = WikiPage.create!(
tag_name: tn2,
body: 'init',
created_user: user,
updated_user: user)


get "/wiki/changes?id=#{p2.id}" get "/wiki/changes?id=#{p2.id}"
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
@@ -504,12 +501,12 @@ RSpec.describe 'Wiki API', type: :request do
describe 'Wiki::Commit.redirect!' do describe 'Wiki::Commit.redirect!' do
it 'raises because redirect revisions are deprecated' do it 'raises because redirect revisions are deprecated' do
target_tag_name = TagName.create!(name: 'redirect_deprecated_target') target_tag_name = TagName.create!(name: 'redirect_deprecated_target')
target = WikiPage.create!(
tag_name: target_tag_name,
body: 'target',
created_user: user,
updated_user: user
)
target =
Wiki::Commit.create_content!(
tag_name: target_tag_name,
body: 'target',
created_by_user: user,
message: 'init')


expect { expect {
Wiki::Commit.redirect!( Wiki::Commit.redirect!(
@@ -522,4 +519,115 @@ RSpec.describe 'Wiki API', type: :request do
}.to raise_error(RuntimeError, '廃止しました.') }.to raise_error(RuntimeError, '廃止しました.')
end end
end end

it 'wiki title を変更すると対応する tag の version を作成する' do
linked_tag_name = TagName.create!(name: 'wiki_linked_tag_for_version')
linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general)

linked_page =
Wiki::Commit.create_content!(
tag_name: linked_tag_name,
body: 'before',
created_by_user: user,
message: 'init')

current_id = linked_page.current_revision.id

expect {
put "/wiki/#{ linked_page.id }",
params: {
title: 'wiki_linked_tag_for_version_renamed',
body: 'after',
message: 'edit',
base_revision_id: current_id,
},
headers: auth_headers(member)
}
.to change(WikiRevision, :count).by(1)
.and change(WikiVersion, :count).by(1)
.and change { linked_tag.reload.tag_versions.count }.by(2)

expect(response).to have_http_status(:ok)

linked_tag.reload
expect(linked_tag.name).to eq('wiki_linked_tag_for_version_renamed')

versions = linked_tag.tag_versions.order(:version_no)

expect(versions.first.event_type).to eq('create')
expect(versions.first.name).to eq('wiki_linked_tag_for_version')

expect(versions.second.event_type).to eq('update')
expect(versions.second.name).to eq('wiki_linked_tag_for_version_renamed')
end

it 'wiki body だけを変更しても tag version は作成しない' do
linked_tag_name = TagName.create!(name: 'wiki_body_only_tag')
linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general)

linked_page =
Wiki::Commit.create_content!(
tag_name: linked_tag_name,
body: 'before',
created_by_user: user,
message: 'init')

current_id = linked_page.current_revision.id

expect {
put "/wiki/#{ linked_page.id }",
params: {
title: 'wiki_body_only_tag',
body: 'after',
message: 'edit',
base_revision_id: current_id,
},
headers: auth_headers(member)
}
.to change(WikiRevision, :count).by(1)
.and change(WikiVersion, :count).by(1)

expect(linked_tag.reload.tag_versions.count).to eq(0)
end

it 'wiki title を変更すると対応する tag の version を作成する' do
linked_tag_name = TagName.create!(name: 'wiki_linked_tag_for_version')
linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general)

linked_page =
Wiki::Commit.create_content!(
tag_name: linked_tag_name,
body: 'before',
created_by_user: user,
message: 'init')

current_id = linked_page.current_revision.id

expect {
put "/wiki/#{ linked_page.id }",
params: {
title: 'wiki_linked_tag_for_version_renamed',
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)
.and change { linked_tag.reload.tag_versions.count }.by(2)

expect(response).to have_http_status(:ok)

linked_tag.reload
expect(linked_tag.name).to eq('wiki_linked_tag_for_version_renamed')

versions = linked_tag.tag_versions.order(:version_no)

expect(versions.first.event_type).to eq('create')
expect(versions.first.name).to eq('wiki_linked_tag_for_version')

expect(versions.second.event_type).to eq('update')
expect(versions.second.name).to eq('wiki_linked_tag_for_version_renamed')
end
end end

+ 46
- 16
backend/spec/services/wiki/commit_spec.rb View File

@@ -79,26 +79,56 @@ RSpec.describe Wiki::Commit do
}.to raise_error(Wiki::Commit::Conflict) }.to raise_error(Wiki::Commit::Conflict)
end end


it 'records tag version when page has corresponding tag' do
tag_name = TagName.create!(name: 'commit_linked_tag')
it 'does not record tag version when corresponding tag has no versions' do
tag_name = TagName.create!(name: 'commit_linked_tag_without_versions')
tag = Tag.create!(tag_name:, category: :general) tag = Tag.create!(tag_name:, category: :general)
page = WikiPage.create!(
tag_name:,
body: '',
created_user: user,
updated_user: user
)

page =
described_class.create_content!(
tag_name:,
body: 'before',
created_by_user: user,
message: 'init')

expect(tag.reload.tag_versions.count).to eq(0)

current_revision_id = page.current_revision.id


expect { expect {
described_class.content!( described_class.content!(
page:,
body: 'body',
created_user: user,
message: 'init'
)
}
.to change(WikiVersion, :count).by(1)
.and change { tag.reload.tag_versions.count }.by(1)
page:,
body: 'after',
created_user: user,
message: 'edit',
base_revision_id: current_revision_id)
}.to change(WikiVersion, :count).by(1)

expect(tag.reload.tag_versions.count).to eq(0)
end

it 'does not record tag version when corresponding tag has no versions' do
tag_name = TagName.create!(name: 'commit_linked_tag_without_versions')
tag = Tag.create!(tag_name:, category: :general)

page =
described_class.create_content!(
tag_name:,
body: 'before',
created_by_user: user,
message: 'init')

current_revision_id = page.current_revision.id

expect {
described_class.content!(
page:,
body: 'after',
created_user: user,
message: 'edit',
base_revision_id: current_revision_id)
}.to change(WikiVersion, :count).by(1)

expect(tag.reload.tag_versions.count).to eq(0)
end end
end end




Loading…
Cancel
Save