Browse Source

#19 ひとまづ表示のみ

#23
みてるぞ 1 month ago
parent
commit
39dce3a39f
11 changed files with 1355 additions and 206 deletions
  1. +16
    -8
      backend/app/controllers/wiki_pages_controller.rb
  2. +0
    -31
      backend/app/controllers/wiki_proxy_controller.rb
  3. +25
    -2
      backend/app/models/wiki_page.rb
  4. +8
    -59
      backend/config/routes.rb
  5. +1236
    -64
      frontend/package-lock.json
  6. +1
    -0
      frontend/package.json
  7. +2
    -2
      frontend/src/App.tsx
  8. +19
    -0
      frontend/src/components/WikiEditor/index.tsx
  9. +0
    -40
      frontend/src/pages/WikiEditPage.tsx
  10. +22
    -0
      frontend/src/pages/WikiPage.tsx
  11. +26
    -0
      frontend/src/pages/WikiShowPage.tsx

+ 16
- 8
backend/app/controllers/wiki_pages_controller.rb View File

@@ -1,16 +1,24 @@
class WikiPagesController < ApplicationController class WikiPagesController < ApplicationController
def index
end

def show def show
end

def create
p params
wiki_page = WikiPage.find_by(title: params[:title])
if wiki_page
render plain: wiki_page.markdown
else
head :not_found
end
end end


def update def update
end
return head :unauthorized unless current_user


def destroy
title = params[:title]
wiki_page = WikiPage.find_by(title: title)
unless wiki_page
wiki_page = WikiPage.new(title: title, created_user: current_user, updated_user: current_user)
end
wiki_page.markdown = params[:markdown]
wiki_page.save!
head :ok
end end
end end

+ 0
- 31
backend/app/controllers/wiki_proxy_controller.rb View File

@@ -1,31 +0,0 @@
require 'net/http'
require 'uri'


class WikiProxyController < ApplicationController
def edit
tag = params[:tag]
uri = "http://localhost:4567/gollum/edit/#{ URI.encode_www_form_component(tag) }"
begin
res = fetch_with_redirect(uri)
render html: res.body.html_safe, content_type: res.content_type
rescue => e
render plain: "Wiki システムとの通信に失敗しました:#{ e.message }", status: 502
end
end

private

def fetch_with_redirect uri_str, limit = 5
raise 'Too many redirects' if limit == 0

uri = URI.parse(uri_str)
res = Net::HTTP.get_response(uri)
if res.is_a? Net::HTTPRedirection
location = res['location']
fetch_with_redirect(location, limit - 1)
else
res
end
end
end

+ 25
- 2
backend/app/models/wiki_page.rb View File

@@ -1,11 +1,34 @@
require 'gollum-lib'


class WikiPage < ApplicationRecord class WikiPage < ApplicationRecord
WIKI_PATH = Rails.root.join('wiki').to_s

belongs_to :tag, optional: true belongs_to :tag, optional: true
belongs_to :created_user, class_name: 'User', foreign_key: 'created_user_id' belongs_to :created_user, class_name: 'User', foreign_key: 'created_user_id'
belongs_to :updated_user, class_name: 'User', foreign_key: 'updated_user_id' belongs_to :updated_user, class_name: 'User', foreign_key: 'updated_user_id'


validates :title, presence: true, length: { maximum: 255 }, uniqueness: true validates :title, presence: true, length: { maximum: 255 }, uniqueness: true


def gollum_path
"wiki/#{ title.parameterize }.md"
def markdown
wiki = Gollum::Wiki.new(WIKI_PATH)
page = wiki.page(title)
page&.raw_data
end

def markdown= content
wiki = Gollum::Wiki.new(WIKI_PATH)

page = wiki.page(title)

commit_info = { message: "Update #{ title }",
name: current_user.id,
email: 'dummy@example.com' }

if page
page.update(content, commit: commit_info)
else
wiki.write_page(title, :markdown, content, commit_info)
end
end end
end end

+ 8
- 59
backend/config/routes.rb View File

@@ -1,62 +1,4 @@
Rails.application.routes.draw do Rails.application.routes.draw do
get "wiki_pages/index"
get "wiki_pages/show"
get "wiki_pages/create"
get "wiki_pages/update"
get "wiki_pages/destroy"
get "users/index"
get "users/show"
get "users/create"
get "users/update"
get "users/destroy"
get "user_post_views/index"
get "user_post_views/show"
get "user_post_views/create"
get "user_post_views/update"
get "user_post_views/destroy"
get "user_ips/index"
get "user_ips/show"
get "user_ips/create"
get "user_ips/update"
get "user_ips/destroy"
get "tags/index"
get "tags/show"
get "tags/create"
get "tags/update"
get "tags/destroy"
get 'tags/autocomplete', to: 'tags#autocomplete'
get "tag_aliases/index"
get "tag_aliases/show"
get "tag_aliases/create"
get "tag_aliases/update"
get "tag_aliases/destroy"
get "settings/index"
get "settings/show"
get "settings/create"
get "settings/update"
get "settings/destroy"
get "post_tags/index"
get "post_tags/show"
get "post_tags/create"
get "post_tags/update"
get "post_tags/destroy"
post 'posts/:id/viewed', to: 'posts#viewed'
delete 'posts/:id/viewed', to: 'posts#unviewed'
get "nico_tag_relation/index"
get "nico_tag_relation/show"
get "nico_tag_relation/create"
get "nico_tag_relation/update"
get "nico_tag_relation/destroy"
get "ip_addresses/index"
get "ip_addresses/show"
get "ip_addresses/create"
get "ip_addresses/update"
get "ip_addresses/destroy"
get 'preview/title', to: 'preview#title'
get 'preview/thumbnail', to: 'preview#thumbnail'
get '/wiki/edit/:tag', to: 'wiki_proxy#edit'
root 'home#index'

resources :posts resources :posts
resources :ip_addresses resources :ip_addresses
resources :nico_tag_relations resources :nico_tag_relations
@@ -72,7 +14,14 @@ Rails.application.routes.draw do
get :me get :me
end end
end end
resources :wiki_pages

get 'tags/autocomplete', to: 'tags#autocomplete'
post 'posts/:id/viewed', to: 'posts#viewed'
delete 'posts/:id/viewed', to: 'posts#unviewed'
get 'preview/title', to: 'preview#title'
get 'preview/thumbnail', to: 'preview#thumbnail'
get 'wiki/*title', to: 'wiki_pages#show', format: false
post 'wiki/*title', to: 'wiki_pages#save', format: false


# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html




+ 1236
- 64
frontend/package-lock.json
File diff suppressed because it is too large
View File


+ 1
- 0
frontend/package.json View File

@@ -21,6 +21,7 @@
"marked": "^15.0.12", "marked": "^15.0.12",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-markdown": "^10.1.0",
"react-markdown-editor-lite": "^1.3.4", "react-markdown-editor-lite": "^1.3.4",
"react-router-dom": "^6.30.0", "react-router-dom": "^6.30.0",
"tailwind-merge": "^3.3.0" "tailwind-merge": "^3.3.0"


+ 2
- 2
frontend/src/App.tsx View File

@@ -7,7 +7,7 @@ import TagSidebar from './components/TagSidebar'
import PostPage from './pages/PostPage' import PostPage from './pages/PostPage'
import PostNewPage from './pages/PostNewPage' import PostNewPage from './pages/PostNewPage'
import PostDetailPage from './pages/PostDetailPage' import PostDetailPage from './pages/PostDetailPage'
import WikiEditPage from './pages/WikiEditPage'
import WikiShowPage from './pages/WikiShowPage'
import { API_BASE_URL } from './config' import { API_BASE_URL } from './config'
import axios from 'axios' import axios from 'axios'
import { Toaster } from '@/components/ui/toaster' import { Toaster } from '@/components/ui/toaster'
@@ -81,7 +81,7 @@ const App = () => {
<Route path="/posts/new" element={<PostNewPage />} /> <Route path="/posts/new" element={<PostNewPage />} />
<Route path="/posts/:id" element={<PostDetailPage posts={posts} setPosts={setPosts} />} /> <Route path="/posts/:id" element={<PostDetailPage posts={posts} setPosts={setPosts} />} />
<Route path="/tags/:tag" element={<TagPage />} /> <Route path="/tags/:tag" element={<TagPage />} />
<Route path="/wiki/:name" element={<WikiEditPage />} />
<Route path="/wiki/:name" element={<WikiShowPage />} />
</Routes> </Routes>
</main> </main>
</div> </div>


+ 19
- 0
frontend/src/components/WikiEditor/index.tsx View File

@@ -0,0 +1,19 @@
import MdEditor from 'react-markdown-editor-lite'
import 'react-markdown-editor-lite/lib/index.css'
import { marked } from 'marked'

type Props = { value: string
onChange: (text: string) => void
onSave: () => void }


const WikiEditor = ({ value, onChange, onSave }) => (
<div className="wiki-editor">
<MdEditor value={value}
style={{ height: '500px' }}
renderHTML={text => marked (text)} />
<button onClick={onSave}>保存</button>
</div>)


export default WikiEditor

+ 0
- 40
frontend/src/pages/WikiEditPage.tsx View File

@@ -1,40 +0,0 @@
import { useParams } from 'react-router-dom'
import { useEffect, useState } from 'react'
import axios from 'axios'


const WikiEditPage = () => {
const { name } = useParams<{ name: string }> ()

const [html, setHtml] = useState('')
const [loading, setLoading] = useState(true)

useEffect(() => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = '/wiki/custom.css' // Gollum の静的 CSS にアクセスできるようにしとく
document.head.appendChild(link)
return () => {
document.head.removeChild(link)
}
}, [])

useEffect(() => {
setLoading(true)
axios
.get(`/api/wiki/edit/${encodeURIComponent(name)}`, {
headers: { 'X-Transfer-Code': localStorage.getItem('user_code') || '' }
})
.then((res) => setHtml(res.data))
.finally(() => setLoading(false))
}, [name])

return loading ? (
<p>読み込み中...</p>
) : (
<div dangerouslySetInnerHTML={{ __html: html }} />
)
}


export default WikiEditPage

+ 22
- 0
frontend/src/pages/WikiPage.tsx View File

@@ -0,0 +1,22 @@
import axios from 'axios'
import { useState, useEffect } from 'react'
import WikiEditor from '@/components/WikiEditor'
import { API_BASE_URL } from '../config'


const WikiPage = () => {
const [text, setText] = useState ('')

useEffect (() => {
void (axios.get (`${ API_BASE_URL }/wiki/load`, { params: { page: 'xxx' } })
.then (res => setText (res.data.markdown)))
}, [])

const save = () => {
void (axios.post ('/api/wiki/save', { page: 'xxx',
markdown: text })
.catch (err => console.error ('保存失敗', err)))
}

return <WikiEditor value={text} onChange={setText} onSave={save} />
}

+ 26
- 0
frontend/src/pages/WikiShowPage.tsx View File

@@ -0,0 +1,26 @@
import { useParams } from 'react-router-dom'
import ReactMarkdown from 'react-markdown'
import { useEffect, useState } from 'react'
import axios from 'axios'
import { API_BASE_URL } from '@/config'


const WikiShowPage = () => {
const { name } = useParams ()

const [markdown, setMarkdown] = useState ('')

useEffect (() => {
void (axios.get (`${ API_BASE_URL }/wiki/${ encodeURIComponent (name) }`)
.then (res => setMarkdown (res.data))
.catch (() => setMarkdown ('# ページが存在しません')))
}, [name])

return (
<div className="prose mx-auto p-4">
<ReactMarkdown>{markdown}</ReactMarkdown>
</div>)
}


export default WikiShowPage

Loading…
Cancel
Save