@@ -57,3 +57,5 @@ gem "image_processing", "~> 1.14" | |||||
gem "nokogiri", "~> 1.18" | gem "nokogiri", "~> 1.18" | ||||
gem 'gollum' | gem 'gollum' | ||||
gem 'diff-lcs' |
@@ -88,6 +88,7 @@ GEM | |||||
connection_pool (2.5.3) | connection_pool (2.5.3) | ||||
crass (1.0.6) | crass (1.0.6) | ||||
date (3.4.1) | date (3.4.1) | ||||
diff-lcs (1.6.2) | |||||
dotenv (3.1.8) | dotenv (3.1.8) | ||||
drb (2.2.1) | drb (2.2.1) | ||||
ed25519 (1.4.0) | ed25519 (1.4.0) | ||||
@@ -412,6 +413,7 @@ PLATFORMS | |||||
DEPENDENCIES | DEPENDENCIES | ||||
bootsnap | bootsnap | ||||
brakeman | brakeman | ||||
diff-lcs | |||||
gollum | gollum | ||||
image_processing (~> 1.14) | image_processing (~> 1.14) | ||||
jwt | jwt | ||||
@@ -7,10 +7,51 @@ class WikiPagesController < ApplicationController | |||||
end | end | ||||
def show_by_title | def show_by_title | ||||
wiki_page = WikiPage.find_by(title: params[:title]) | |||||
title = params[:title] | |||||
version = params[:version].presence | |||||
wiki_page = WikiPage.find_by(title:) | |||||
return head :not_found unless wiki_page | return head :not_found unless wiki_page | ||||
render json: wiki_page.as_json.merge(body: wiki_page.body) | |||||
wiki_page.sha = version | |||||
body = wiki_page.body | |||||
sha = wiki_page.sha | |||||
pred = wiki_page.pred | |||||
succ = wiki_page.succ | |||||
render json: wiki_page.as_json.merge(body:, sha:, pred:, succ:) | |||||
end | |||||
def diff | |||||
id = params[:id] | |||||
from = params[:from] | |||||
to = params[:to].presence | |||||
return head :bad_request if id.blank? || from.blank? | |||||
wiki_page_from = WikiPage.find(id) | |||||
wiki_page_to = wiki_page_from.clone | |||||
wiki_page_from.sha = from | |||||
wiki_page_to.sha = to | |||||
diffs = Diff::LCS.sdiff(wiki_page_from.body, wiki_page_to.body) | |||||
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: wiki_page_from.id, | |||||
title: wiki_page_from.title, | |||||
older_sha: wiki_page_from.sha, | |||||
newer_sha: wiki_page_to.sha, | |||||
diff: diff_json } | |||||
end | end | ||||
def create | def create | ||||
@@ -57,8 +98,12 @@ class WikiPagesController < ApplicationController | |||||
render json: log.map { |commit| | render json: log.map { |commit| | ||||
wiki_page = WikiPage.find(commit.message.split(' ')[1].to_i) | wiki_page = WikiPage.find(commit.message.split(' ')[1].to_i) | ||||
wiki_page.sha = commit.id | |||||
user = User.find(commit.author.name.to_i) | user = User.find(commit.author.name.to_i) | ||||
{ sha: commit.id, | |||||
{ sha: wiki_page.sha, | |||||
pred: wiki_page.pred, | |||||
succ: wiki_page.succ, | |||||
wiki_page: wiki_page && { id: wiki_page.id, title: wiki_page.title }, | wiki_page: wiki_page && { id: wiki_page.id, title: wiki_page.title }, | ||||
user: user && { id: user.id, name: user.name }, | user: user && { id: user.id, name: user.name }, | ||||
change_type: commit.message.split(' ')[0].downcase[0...(-1)], | change_type: commit.message.split(' ')[0].downcase[0...(-1)], | ||||
@@ -8,14 +8,41 @@ class WikiPage < ApplicationRecord | |||||
validates :title, presence: true, length: { maximum: 255 }, uniqueness: true | validates :title, presence: true, length: { maximum: 255 }, uniqueness: true | ||||
def sha= val | |||||
if val.present? | |||||
@sha = val | |||||
@page = wiki.page("#{ id }.md", @sha) | |||||
else | |||||
@page = wiki.page("#{ id }.md") | |||||
@sha = @page.versions.first.id | |||||
end | |||||
vers = @page.versions | |||||
idx = vers.find_index { |ver| ver.id == @sha } | |||||
@pred = vers[idx + 1]&.id | |||||
@succ = idx.positive? ? vers[idx - 1].id : nil | |||||
@sha | |||||
end | |||||
def sha | |||||
@sha | |||||
end | |||||
def pred | |||||
@pred | |||||
end | |||||
def succ | |||||
@succ | |||||
end | |||||
def body | def body | ||||
page = wiki.page("#{ id }.md") | |||||
page&.raw_data | |||||
sha = nil unless @page | |||||
@page&.raw_data&.force_encoding('UTF-8') | |||||
end | end | ||||
def set_body content, user: | def set_body content, user: | ||||
commit_info = { name: user.id.to_s, | |||||
email: 'dummy@example.com' } | |||||
commit_info = { name: user.id.to_s, | |||||
email: 'dummy@example.com' } | |||||
page = wiki.page("#{ id }.md") | page = wiki.page("#{ id }.md") | ||||
if page | if page | ||||
commit_info[:message] = "Updated #{ id }" | commit_info[:message] = "Updated #{ id }" | ||||
@@ -7,6 +7,7 @@ Rails.application.routes.draw do | |||||
get 'wiki/title/:title', to: 'wiki_pages#show_by_title' | get 'wiki/title/:title', to: 'wiki_pages#show_by_title' | ||||
get 'wiki/search', to: 'wiki_pages#search' | get 'wiki/search', to: 'wiki_pages#search' | ||||
get 'wiki/changes', to: 'wiki_pages#changes' | get 'wiki/changes', to: 'wiki_pages#changes' | ||||
get 'wiki/:id/diff', to: 'wiki_pages#diff' | |||||
get 'wiki/:id', to: 'wiki_pages#show' | get 'wiki/:id', to: 'wiki_pages#show' | ||||
post 'wiki', to: 'wiki_pages#create' | post 'wiki', to: 'wiki_pages#create' | ||||
put 'wiki/:id', to: 'wiki_pages#update' | put 'wiki/:id', to: 'wiki_pages#update' | ||||