323 行
10 KiB
Ruby
323 行
10 KiB
Ruby
class WikiPagesController < ApplicationController
|
|
rescue_from Wiki::Commit::Conflict, with: :render_wiki_conflict
|
|
|
|
def index
|
|
# 互換性のための化石リソース
|
|
# TODO: ヘルプおよびタグ・グループ追加後に,
|
|
# TODO: タグ説明とヘルプ、タグ・グループから取得する作りに変更する.
|
|
|
|
title = params[:title].to_s.strip
|
|
if title.blank?
|
|
tag_descriptions = TagDescription.where(language_code: :ja).map do |td|
|
|
{ id: td.id,
|
|
tag_name_id: td.tag.tag_name(:ja).id,
|
|
body: td.body,
|
|
created_user_id: td.created_by_user_id,
|
|
updated_user_id: td.updated_by_user_id,
|
|
created_at: td.created_at,
|
|
updated_at: td.updated_at,
|
|
discarded_at: nil,
|
|
version_no: td.version_no,
|
|
title: td.tag.name(:ja),
|
|
deprecated_at: td.tag.deprecated_at }
|
|
end
|
|
# TODO: ヘルプ移行したらここに追記
|
|
# TODO: タグ・グループ追加したらここに追記
|
|
|
|
# TODO: ヘルプ、タグ・グループ移行したらそれらもタイトルから除外に含める.
|
|
# てかこれ何順?
|
|
wiki_pages =
|
|
WikiPageRepr.base(WikiPage.joins(:tag_name).includes(tag_name: :tag))
|
|
.reject { |wp| tag_descriptions.any? { |td| td.title == wp.title } }
|
|
|
|
json = tag_descriptions + wiki_pages
|
|
|
|
return render json:
|
|
end
|
|
|
|
q =
|
|
TagDescription.joins(tag: :tag_names)
|
|
.where(language_code: :ja)
|
|
.where(tag: { tag_names: { language_code: :ja, primary_flg: true } })
|
|
.where('tag_names.name LIKE ?', "%#{ ApplicationRecord.sanitize_sql_like(title) }%")
|
|
tag_descriptions = q.limit(20).map do |td|
|
|
{ id: td.id,
|
|
tag_name_id: td.tag.tag_name(:ja).id,
|
|
body: td.body,
|
|
created_user_id: td.created_by_user_id,
|
|
updated_user_id: td.updated_by_user_id,
|
|
created_at: td.created_at,
|
|
updated_at: td.updated_at,
|
|
discarded_at: nil,
|
|
version_no: td.version_no,
|
|
title: td.tag.name(:ja),
|
|
deprecated_at: td.tag.deprecated_at }
|
|
end
|
|
|
|
q =
|
|
WikiPage.joins(:tag_name).includes(tag_name: :tag)
|
|
.where('tag_names.name LIKE ?', "%#{ WikiPage.sanitize_sql_like(title) }%")
|
|
# TODO: ヘルプ、タグ・グループ移行したらそれらもタイトルから除外に含める.
|
|
wiki_pages =
|
|
WikiPageRepr.base(q.limit(20))
|
|
.reject { |wp| tag_descriptions.any? { |td| td.title == wp.title } }
|
|
|
|
json = (tag_descriptions + wiki_pages)[...20]
|
|
|
|
render json:
|
|
end
|
|
|
|
def show
|
|
tag_description = TagDescription.find_by(id: params[:id])
|
|
|
|
if tag_description
|
|
rev =
|
|
if params[:version].present?
|
|
TagDescriptionVersion.find_by(id: params[:version])
|
|
else
|
|
TagDescriptionVersion.find_by(tag_id: tag_description.tag_id,
|
|
language_code: :ja,
|
|
version_no: tag_description.version_no)
|
|
end
|
|
|
|
if rev
|
|
body =
|
|
if rev.version_no == tag_description.version_no
|
|
tag_description.body
|
|
else
|
|
rev.body
|
|
end
|
|
revision_id = rev.id
|
|
pred = TagDescriptionVersion.find_by(tag_id: tag_description.tag_id,
|
|
language_code: :ja,
|
|
version_no: tag_description.version_no - 1)&.id
|
|
succ = TagDescriptionVersion.find_by(tag_id: tag_description.tag_id,
|
|
language_code: :ja,
|
|
version_no: tag_description.version_no + 1)&.id
|
|
updated_at =
|
|
if rev.version_no == tag_description.version_no
|
|
tag_description.updated_at
|
|
else
|
|
rev.created_at
|
|
end
|
|
|
|
json =
|
|
{ id: tag_description.id,
|
|
tag_name_id: tag_description.tag.tag_name(:ja).id,
|
|
body:,
|
|
created_user_id: tag_description.created_by_user_id,
|
|
updated_user_id: tag_description.updated_by_user_id,
|
|
created_at: tag_description.created_at,
|
|
updated_at:,
|
|
discarded_at: nil,
|
|
version_no: tag_description.version_no,
|
|
title: tag_description.tag.name(:ja),
|
|
deprecated_at: tag_description.tag.deprecated_at,
|
|
revision_id:,
|
|
pred:,
|
|
succ: }
|
|
|
|
return render json:
|
|
end
|
|
end
|
|
|
|
page = WikiPage.joins(:tag_name)
|
|
.includes(tag_name: :tag)
|
|
.find_by(id: params[:id])
|
|
|
|
render_wiki_page_or_404 page
|
|
end
|
|
|
|
def show_by_title
|
|
title = params[:title].to_s.strip
|
|
page = WikiPage.joins(:tag_name)
|
|
.includes(tag_name: :tag)
|
|
.find_by(tag_name: { name: title })
|
|
render_wiki_page_or_404 page
|
|
end
|
|
|
|
def exists
|
|
if WikiPage.exists?(id: params[:id])
|
|
head :no_content
|
|
else
|
|
head :not_found
|
|
end
|
|
end
|
|
|
|
def exists_by_title
|
|
title = params[:title].to_s.strip
|
|
if WikiPage.joins(:tag_name).exists?(tag_names: { name: title })
|
|
head :no_content
|
|
else
|
|
head :not_found
|
|
end
|
|
end
|
|
|
|
def diff
|
|
id = params[:id]
|
|
return render_bad_request('id は必須です.') if id.blank?
|
|
|
|
from = params[:from].presence
|
|
to = params[:to].presence
|
|
|
|
page = WikiPage.joins(:tag_name).includes(tag_name: :tag).find(id)
|
|
|
|
from_rev = from && page.wiki_revisions.find(from)
|
|
to_rev = to ? page.wiki_revisions.find(to) : page.current_revision
|
|
if ((from_rev && !(from_rev.content?)) || !(to_rev&.content?))
|
|
return render_unprocessable_entity('差分を表示できない版です.')
|
|
end
|
|
|
|
diffs = Diff::LCS.sdiff(from_rev&.body&.lines || [], to_rev.body.lines)
|
|
diff_json = diffs.map { |change|
|
|
case change.action
|
|
when ?=
|
|
{ type: 'context', content: change.old_element }
|
|
when ?!
|
|
[{ type: 'removed', content: change.old_element },
|
|
{ type: 'added', content: change.new_element }]
|
|
when ?+
|
|
{ type: 'added', content: change.new_element }
|
|
when ?-
|
|
{ type: 'removed', content: change.old_element }
|
|
end
|
|
}.flatten.compact
|
|
|
|
render json: { wiki_page_id: page.id,
|
|
title: page.title,
|
|
deprecated_at: page.deprecated_at,
|
|
older_revision_id: from_rev&.id,
|
|
newer_revision_id: to_rev.id,
|
|
diff: diff_json }
|
|
end
|
|
|
|
def create
|
|
return head :unauthorized unless current_user
|
|
return head :forbidden unless current_user.gte_member?
|
|
|
|
title = params[:title].to_s.strip
|
|
body = params[:body].to_s
|
|
message = params[:message].presence
|
|
|
|
return render_unprocessable_entity('タイトルは必須です.', field: :title) if title.blank?
|
|
return render_unprocessable_entity('本文は必須です.', field: :body) if body.blank?
|
|
|
|
tag_name = TagName.find_or_create_by!(language_code: 'ja', name: title) do |name|
|
|
name.script_code = 'Jpan'
|
|
name.primary_flg = true
|
|
name.auto_generated = false
|
|
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 => e
|
|
render_validation_error e.record
|
|
rescue ActiveRecord::RecordNotUnique
|
|
render_record_not_unique
|
|
end
|
|
|
|
def update
|
|
return head :unauthorized unless current_user
|
|
return head :forbidden unless current_user.gte_member?
|
|
|
|
title = params[:title]&.strip
|
|
body = params[:body].to_s
|
|
|
|
return render_unprocessable_entity('タイトルは必須です.', field: :title) if title.blank?
|
|
return render_unprocessable_entity('本文は必須です.', field: :body) if body.blank?
|
|
|
|
page = WikiPage.find(params[:id])
|
|
base_revision_id = params[:base_revision_id].presence
|
|
|
|
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
|
|
|
|
head :ok
|
|
end
|
|
|
|
def changes
|
|
id = params[:id].presence
|
|
q = WikiRevision.joins(wiki_page: :tag_name)
|
|
.includes(:created_user, wiki_page: { tag_name: :tag })
|
|
.order(id: :desc)
|
|
q = q.where(wiki_page_id: id) if id
|
|
|
|
render json: q.limit(200).map { |rev|
|
|
{ revision_id: rev.id,
|
|
pred: rev.base_revision_id,
|
|
succ: nil,
|
|
wiki_page: { id: rev.wiki_page_id,
|
|
title: rev.wiki_page.title,
|
|
deprecated_at: rev.wiki_page.deprecated_at },
|
|
user: rev.created_user && { id: rev.created_user.id, name: rev.created_user.name },
|
|
kind: rev.kind,
|
|
message: rev.message,
|
|
timestamp: rev.created_at }
|
|
}.compact
|
|
end
|
|
|
|
private
|
|
|
|
def render_wiki_page_or_404 page
|
|
return head :not_found unless page
|
|
|
|
rev = find_revision(page)
|
|
return head :not_found unless rev
|
|
|
|
if rev.redirect?
|
|
return (
|
|
redirect_to wiki_page_by_title_path(title: rev.redirect_page.title),
|
|
status: :moved_permanently)
|
|
end
|
|
|
|
body = rev.body
|
|
revision_id = rev.id
|
|
pred = page.pred_revision_id(revision_id)
|
|
succ = page.succ_revision_id(revision_id)
|
|
updated_at = rev.created_at
|
|
|
|
render json: WikiPageRepr.base(page).merge(body:, revision_id:, pred:, succ:, updated_at:)
|
|
end
|
|
|
|
def find_revision page
|
|
if params[:version].present?
|
|
page.wiki_revisions.find_by(id: params[:version])
|
|
else
|
|
page.current_revision
|
|
end
|
|
end
|
|
|
|
def render_wiki_conflict err
|
|
render json: { error: 'conflict', message: err.message }, status: :conflict
|
|
end
|
|
end
|