Browse Source

#317

feature/317
みてるぞ 1 week ago
parent
commit
d2eb69d3b0
6 changed files with 151 additions and 197 deletions
  1. +25
    -9
      backend/app/controllers/tags_controller.rb
  2. +35
    -29
      backend/app/controllers/wiki_pages_controller.rb
  3. +10
    -7
      backend/app/services/wiki/commit.rb
  4. +1
    -1
      backend/app/services/wiki_version_recorder.rb
  5. +64
    -64
      backend/spec/requests/tags_spec.rb
  6. +16
    -87
      backend/spec/requests/wiki_spec.rb

+ 25
- 9
backend/app/controllers/tags_controller.rb View File

@@ -249,7 +249,10 @@ class TagsController < ApplicationController
update_parent_tags!(tag, parent_names) update_parent_tags!(tag, parent_names)


tag.reload 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: name.present? && name != old_name)
end end


render json: TagRepr.base(tag.reload) render json: TagRepr.base(tag.reload)
@@ -272,10 +275,19 @@ class TagsController < ApplicationController
ApplicationRecord.transaction do ApplicationRecord.transaction do
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user) TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)


old_name = tag.name
name_changed = name.present? && name != old_name

tag.tag_name.update!(name:) if name.present? tag.tag_name.update!(name:) if name.present?
tag.update!(category:) if category.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:)
end end


render json: TagRepr.base(tag.reload) render json: TagRepr.base(tag.reload)
@@ -297,16 +309,20 @@ class TagsController < ApplicationController
material: material.as_json&.merge(file:, content_type:)) material: material.as_json&.merge(file:, content_type:))
end end


def record_tag_version! tag, event_type:, created_by_user:
def record_tag_version! tag, event_type:, created_by_user:, name_changed: false
if tag.nico? if tag.nico?
NicoTagVersionRecorder.record!(tag:, event_type:, created_by_user:) NicoTagVersionRecorder.record!(tag:, event_type:, created_by_user:)
else
TagVersionRecorder.record!(tag:, event_type:, created_by_user:)
wiki_page = tag.tag_name.wiki_page
if wiki_page&.wiki_versions&.exists?
WikiVersionRecorder.record!(page: wiki_page, event_type: :update, created_by_user:)
end
return
end 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 end


def update_aliases! tag, alias_names def update_aliases! tag, alias_names


+ 35
- 29
backend/app/controllers/wiki_pages_controller.rb View File

@@ -85,22 +85,24 @@ class WikiPagesController < ApplicationController
return head :unauthorized unless current_user return head :unauthorized unless current_user
return head :forbidden unless current_user.gte_member? return head :forbidden unless current_user.gte_member?


name = params[:title]&.strip
title = params[:title].to_s.strip
body = params[:body].to_s 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:, body:, 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 end


def update def update
@@ -113,28 +115,32 @@ class WikiPagesController < ApplicationController
return head :unprocessable_entity if title.blank? || body.blank? return head :unprocessable_entity if title.blank? || body.blank?


page = WikiPage.find(params[:id]) page = WikiPage.find(params[:id])
base_revision_id = page.current_revision.id
base_revision_id = params[:base_revision_id].presence


old_title = page.title
ApplicationRecord.transaction do
page.lock!


tag = Tag.find_by(tag_name_id: page.tag_name_id)
old_title = page.title


if tag && title != old_title
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)
end
tag = Tag.find_by(tag_name_id: page.tag_name_id)


page.tag_name.update!(name: title) if title != old_title
if tag && title != old_title
TagVersioning.ensure_snapshot!(tag, created_by_user: current_user)
end


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)
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 end


head :ok head :ok


+ 10
- 7
backend/app/services/wiki/commit.rb View File

@@ -117,18 +117,21 @@ module Wiki


id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h 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| line_shas.each_with_index do |sha, i|
next if id_by_sha.key?(sha) 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 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 id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h
end end




+ 1
- 1
backend/app/services/wiki_version_recorder.rb View File

@@ -1,6 +1,6 @@
class WikiVersionRecorder < VersionRecorder class WikiVersionRecorder < VersionRecorder
def self.record! page:, event_type:, reason: nil, created_by_user: def self.record! page:, event_type:, reason: nil, created_by_user:
new(page:, event_type:, created_by_user:).record!
new(page:, event_type:, reason:, created_by_user:).record!
end end


def initialize page:, event_type:, reason: nil, created_by_user: def initialize page:, event_type:, reason: nil, created_by_user:


+ 64
- 64
backend/spec/requests/tags_spec.rb View File

@@ -471,54 +471,54 @@ RSpec.describe 'Tags API', type: :request do
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(nico_tag.reload.category).to eq('nico') expect(nico_tag.reload.category).to eq('nico')
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',
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)
.to change(TagVersion, :count).by(2)
.and change(WikiVersion, :count).by(1)


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


version = wiki_page.reload.wiki_versions.order(:version_no).last
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
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')
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
before_wiki_version_count = wiki_page.reload.wiki_versions.count


expect {
patch "/tags/#{ tag.id }", params: {
category: 'meme',
}
}.to change(TagVersion, :count).by(2)
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)
expect(response).to have_http_status(:ok)
expect(wiki_page.reload.wiki_versions.count).to eq(before_wiki_version_count)
end
end end
end end


@@ -1023,37 +1023,37 @@ 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


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')
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: '',
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)
.to change(TagVersion, :count).by(2)
.and change(WikiVersion, :count).by(1)


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


version = wiki_page.reload.wiki_versions.order(:version_no).last
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
)
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
end end

+ 16
- 87
backend/spec/requests/wiki_spec.rb View File

@@ -301,23 +301,22 @@ RSpec.describe 'Wiki API', type: :request do
end end
end end


# TODO: コンフリクト未実装のため,実装したらコメント外す.
# context 'when conflict' do
# it 'returns 409 when base_revision_id mismatches' do
# # 先に別ユーザ(同じ member でもOK)が 1 回更新して先頭を進める
# Wiki::Commit.content!(page: page, body: "zzz", created_user: member, message: 'other edit')
# page.reload

# stale_id = page.wiki_revisions.order(:id).first.id # わざと古い id
# put "/wiki/#{page.id}",
# params: { title: 'TestPage', body: 'x', base_revision_id: stale_id },
# headers: auth_headers(member)

# expect(response).to have_http_status(:conflict)
# json = JSON.parse(response.body)
# expect(json['error']).to eq('conflict')
# end
# end
context 'when conflict' do
it 'returns 409 when base_revision_id mismatches' do
# 先に別ユーザ(同じ member でもOK)が 1 回更新して先頭を進める
Wiki::Commit.content!(page: page, body: "zzz", created_user: member, message: 'other edit')
page.reload

stale_id = page.wiki_revisions.order(:id).first.id # わざと古い id
put "/wiki/#{page.id}",
params: { title: 'TestPage', body: 'x', base_revision_id: stale_id },
headers: auth_headers(member)

expect(response).to have_http_status(:conflict)
json = JSON.parse(response.body)
expect(json['error']).to eq('conflict')
end
end


context 'when page not found' do context 'when page not found' do
it 'returns 404' do it 'returns 404' do
@@ -520,76 +519,6 @@ RSpec.describe 'Wiki API', type: :request do
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 it 'wiki title を変更すると対応する tag の version を作成する' do
linked_tag_name = TagName.create!(name: 'wiki_linked_tag_for_version') linked_tag_name = TagName.create!(name: 'wiki_linked_tag_for_version')
linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general) linked_tag = Tag.create!(tag_name: linked_tag_name, category: :general)


Loading…
Cancel
Save