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