| @@ -31,17 +31,20 @@ class WikiPagesController < ApplicationController | |||||
| def diff | def diff | ||||
| id = params[:id] | id = params[:id] | ||||
| from = params[:from] | |||||
| return head :bad_request if id.blank? | |||||
| from = params[:from].presence | |||||
| to = params[:to].presence | to = params[:to].presence | ||||
| return head :bad_request if id.blank? || from.blank? | |||||
| page = WikiPage.find(id) | page = WikiPage.find(id) | ||||
| from_rev = page.wiki_revisions.find(from) | |||||
| from_rev = from && page.wiki_revisions.find(from) | |||||
| to_rev = to ? page.wiki_revisions.find(to) : page.current_revision | to_rev = to ? page.wiki_revisions.find(to) : page.current_revision | ||||
| return head :unprocessable_entity if !(from_rev&.content?) || !(to_rev&.content?) | |||||
| 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) | |||||
| diffs = Diff::LCS.sdiff(from_rev&.body&.lines || [], to_rev.body.lines) | |||||
| diff_json = diffs.map { |change| | diff_json = diffs.map { |change| | ||||
| case change.action | case change.action | ||||
| when ?= | when ?= | ||||
| @@ -58,7 +61,7 @@ class WikiPagesController < ApplicationController | |||||
| render json: { wiki_page_id: page.id, | render json: { wiki_page_id: page.id, | ||||
| title: page.title, | title: page.title, | ||||
| older_revision_id: from_rev.id, | |||||
| older_revision_id: from_rev&.id, | |||||
| newer_revision_id: to_rev.id, | newer_revision_id: to_rev.id, | ||||
| diff: diff_json } | diff: diff_json } | ||||
| end | end | ||||
| @@ -8,7 +8,7 @@ class WikiLine < ApplicationRecord | |||||
| sha = Digest::SHA256.hexdigest(body) | sha = Digest::SHA256.hexdigest(body) | ||||
| now = Time.current | now = Time.current | ||||
| upsert({ sha256: sha, body:, created_at: now, updated_at: now }, unique_by: :sha256) | |||||
| upsert({ sha256: sha, body:, created_at: now, updated_at: now }) | |||||
| find_by!(sha256: sha) | find_by!(sha256: sha) | ||||
| end | end | ||||
| @@ -0,0 +1,73 @@ | |||||
| namespace :wiki do | |||||
| desc 'Wiki 移行' | |||||
| task migrate: :environment do | |||||
| require 'digest' | |||||
| require 'gollum-lib' | |||||
| wiki = Gollum::Wiki.new(Rails.root.join('wiki').to_s) | |||||
| WikiPage.where.missing(:wiki_revisions).find_each do |wiki_page| | |||||
| page = wiki.page("#{ wiki_page.id }.md") | |||||
| next unless page | |||||
| versions = page.versions | |||||
| next if versions.blank? | |||||
| base_revision_id = nil | |||||
| versions.reverse_each do |version| | |||||
| pg = wiki.page("#{ wiki_page.id }.md", version.id) | |||||
| raw = pg&.raw_data | |||||
| next unless raw | |||||
| lines = raw.force_encoding('UTF-8').split("\n") | |||||
| line_shas = lines.map { |l| Digest::SHA256.hexdigest(l) } | |||||
| tree_sha = Digest::SHA256.hexdigest(line_shas.join(',')) | |||||
| at = version.authored_date | |||||
| line_id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h | |||||
| missing_rows = [] | |||||
| line_shas.each_with_index do |sha, i| | |||||
| next if line_id_by_sha.key?(sha) | |||||
| missing_rows << { sha256: sha, | |||||
| body: lines[i], | |||||
| created_at: at, | |||||
| updated_at: at } | |||||
| end | |||||
| if missing_rows.any? | |||||
| WikiLine.upsert_all(missing_rows) | |||||
| line_id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h | |||||
| end | |||||
| line_ids = line_shas.map { |sha| line_id_by_sha.fetch(sha) } | |||||
| ActiveRecord::Base.transaction do | |||||
| wiki_page.lock! | |||||
| rev = WikiRevision.create!( | |||||
| wiki_page:, | |||||
| base_revision_id:, | |||||
| created_user_id: Integer(version.author.name) rescue 2, | |||||
| kind: :content, | |||||
| redirect_page_id: nil, | |||||
| message: nil, | |||||
| lines_count: lines.length, | |||||
| tree_sha256: tree_sha, | |||||
| created_at: at, | |||||
| updated_at: at) | |||||
| rows = line_ids.each_with_index.map do |line_id, pos| | |||||
| { wiki_revision_id: rev.id, | |||||
| wiki_line_id: line_id, | |||||
| position: pos } | |||||
| end | |||||
| WikiRevisionLine.insert_all!(rows) | |||||
| end | |||||
| base_revision_id = rev.id | |||||
| end | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -84,7 +84,7 @@ export type WikiPageDiff = { | |||||
| wikiPageId: number | wikiPageId: number | ||||
| title: string | title: string | ||||
| olderRevisionId: number | null | olderRevisionId: number | null | ||||
| newerRevisionId: number | null | |||||
| newerRevisionId: number | |||||
| diff: WikiPageDiffDiff[] } | diff: WikiPageDiffDiff[] } | ||||
| export type WikiPageDiffDiff = { | export type WikiPageDiffDiff = { | ||||