class WikiPagesController < ApplicationController rescue_from Wiki::Commit::Conflict, with: :render_wiki_conflict def index render json: WikiPage.all end def show render_wiki_page_or_404 WikiPage.find(params[:id]) end def show_by_title render_wiki_page_or_404 WikiPage.find_by(title: params[:title]) end def exists if WikiPage.exists?(params[:id]) head :no_content else head :not_found end end def exists_by_title if WikiPage.exists?(title: params[:title]) head :no_content else head :not_found end end def diff id = params[:id] return head :bad_request if id.blank? from = params[:from].presence to = params[:to].presence page = WikiPage.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 head :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, 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.member? title = params[:title]&.strip body = params[:body].to_s return head :unprocessable_entity if title.blank? || body.blank? page = WikiPage.new(title:, 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:) render json: page, status: :created else render json: { errors: page.errors.full_messages }, status: :unprocessable_entity end end def update return head :unauthorized unless current_user return head :forbidden unless current_user.member? title = params[:title]&.strip body = params[:body].to_s return head :unprocessable_entity if title.blank? || body.blank? page = WikiPage.find(params[:id]) base_revision_id = page.current_revision.id if params[:title].present? && params[:title].strip != page.title return head :unprocessable_entity end message = params[:message].presence Wiki::Commit.content!(page:, body:, created_user: current_user, message:, base_revision_id:) head :ok end def search title = params[:title]&.strip q = WikiPage.all if title.present? q = q.where('title LIKE ?', "%#{ WikiPage.sanitize_sql_like(title) }%") end render json: q.limit(20) end def changes id = params[:id].presence q = WikiRevision.includes(:wiki_page, :created_user).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 }, 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 if params[:version].present? rev = page.wiki_revisions.find_by(id: params[:version]) 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) return render json: page.as_json.merge(body:, revision_id:, pred:, succ:) end rev = page.current_revision unless rev return render json: page.as_json.merge(body: nil, revision_id: nil, pred: nil, succ: nil) end 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) render json: page.as_json.merge(body:, revision_id:, pred:, succ:) end def render_wiki_conflict err render json: { error: 'conflict', message: err.message }, status: :conflict end end