Merge remote-tracking branch 'origin/main' into feature/111

This commit is contained in:
2026-01-17 08:41:38 +09:00
52 changed files with 1797 additions and 318 deletions
@@ -1,20 +0,0 @@
class IpAddressesController < ApplicationController
def index
@ip_addresses = IpAddress.all
render json: @ip_addresses
end
def show
render json: @ip_address
end
def create
end
def update
end
def destroy
end
end
@@ -1,16 +0,0 @@
class NicoTagRelationController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
@@ -1,9 +1,13 @@
class NicoTagsController < ApplicationController
TAG_JSON = { only: [:id, :category, :post_count], methods: [:name, :has_wiki] }.freeze
def index
limit = (params[:limit] || 20).to_i
cursor = params[:cursor].presence
q = Tag.nico_tags.includes(:linked_tags).order(updated_at: :desc)
q = Tag.nico_tags
.includes(:tag_name, linked_tags: :tag_name)
.order(updated_at: :desc)
q = q.where('tags.updated_at < ?', Time.iso8601(cursor)) if cursor
tags = q.limit(limit + 1)
@@ -15,7 +19,9 @@ class NicoTagsController < ApplicationController
end
render json: { tags: tags.map { |tag|
tag.as_json(include: :linked_tags)
tag.as_json(TAG_JSON).merge(linked_tags: tag.linked_tags.map { |lt|
lt.as_json(TAG_JSON)
})
}, next_cursor: }
end
@@ -30,12 +36,11 @@ class NicoTagsController < ApplicationController
linked_tag_names = params[:tags].to_s.split(' ')
linked_tags = Tag.normalise_tags(linked_tag_names, with_tagme: false)
return head :bad_request if linked_tags.filter { |t| t.category == 'nico' }.present?
return head :bad_request if linked_tags.any? { |t| t.category == 'nico' }
tag.linked_tags = linked_tags
tag.updated_at = Time.now
tag.save!
render json: tag.linked_tags, status: :ok
render json: tag.linked_tags.map { |t| t.as_json(TAG_JSON) }, status: :ok
end
end
@@ -1,16 +0,0 @@
class PostTagsController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
+30 -29
View File
@@ -1,7 +1,6 @@
class PostsController < ApplicationController
Event = Struct.new(:post, :tag, :user, :change_type, :timestamp, keyword_init: true)
# GET /posts
def index
page = (params[:page].presence || 1).to_i
limit = (params[:limit].presence || 20).to_i
@@ -18,7 +17,7 @@ class PostsController < ApplicationController
'posts.created_at)'
q =
filtered_posts
.preload(:tags)
.preload(tags: :tag_name)
.with_attached_thumbnail
.select("posts.*, #{ sort_sql } AS sort_ts")
.order(Arel.sql("#{ sort_sql } DESC"))
@@ -36,7 +35,8 @@ class PostsController < ApplicationController
end
render json: { posts: posts.map { |post|
post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }).tap do |json|
post.as_json(include: { tags: { only: [:id, :category, :post_count],
methods: [:name] } }).tap do |json|
json['thumbnail'] =
if post.thumbnail.attached?
rails_storage_proxy_url(post.thumbnail, only_path: false)
@@ -44,23 +44,27 @@ class PostsController < ApplicationController
nil
end
end
}, count: filtered_posts.count(:id), next_cursor: }
}, count: if filtered_posts.group_values.present?
filtered_posts.count.size
else
filtered_posts.count
end, next_cursor: }
end
def random
post = filtered_posts.order('RAND()').first
post = filtered_posts.preload(tags: :tag_name).order('RAND()').first
return head :not_found unless post
viewed = current_user&.viewed?(post) || false
render json: (post
.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
.as_json(include: { tags: { only: [:id, :category, :post_count],
methods: [:name] } })
.merge(viewed:))
end
# GET /posts/1
def show
post = Post.includes(:tags).find(params[:id])
post = Post.includes(tags: :tag_name).find(params[:id])
return head :not_found unless post
viewed = current_user&.viewed?(post) || false
@@ -73,7 +77,6 @@ class PostsController < ApplicationController
render json:
end
# POST /posts
def create
return head :unauthorized unless current_user
return head :forbidden unless current_user.member?
@@ -81,7 +84,7 @@ class PostsController < ApplicationController
# TODO: URL が正規のものがチェック,不正ならエラー
# TODO: URL は必須にする(タイトルは省略可).
# TODO: サイトに応じて thumbnail_base 設定
title = params[:title]
title = params[:title].presence
url = params[:url]
thumbnail = params[:thumbnail]
tag_names = params[:tags].to_s.split(' ')
@@ -96,7 +99,8 @@ class PostsController < ApplicationController
tags = Tag.normalise_tags(tag_names)
tags = Tag.expand_parent_tags(tags)
sync_post_tags!(post, tags)
render json: post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
render json: post.as_json(include: { tags: { only: [:id, :category, :post_count],
methods: [:name] } }),
status: :created
else
render json: { errors: post.errors.full_messages }, status: :unprocessable_entity
@@ -117,12 +121,11 @@ class PostsController < ApplicationController
head :no_content
end
# PATCH/PUT /posts/1
def update
return head :unauthorized unless current_user
return head :forbidden unless current_user.member?
title = params[:title]
title = params[:title].presence
tag_names = params[:tags].to_s.split(' ')
original_created_from = params[:original_created_from]
original_created_before = params[:original_created_before]
@@ -141,10 +144,6 @@ class PostsController < ApplicationController
end
end
# DELETE /posts/1
def destroy
end
def changes
id = params[:id]
page = (params[:page].presence || 1).to_i
@@ -157,13 +156,13 @@ class PostsController < ApplicationController
pts = PostTag.with_discarded
pts = pts.where(post_id: id) if id.present?
pts = pts.includes(:post, :tag, :created_user, :deleted_user)
pts = pts.includes(:post, { tag: :tag_name }, :created_user, :deleted_user)
events = []
pts.each do |pt|
events << Event.new(
post: pt.post,
tag: pt.tag,
tag: pt.tag.as_json(only: [:id, :category], methods: [:name]),
user: pt.created_user && { id: pt.created_user.id, name: pt.created_user.name },
change_type: 'add',
timestamp: pt.created_at)
@@ -171,7 +170,7 @@ class PostsController < ApplicationController
if pt.discarded_at
events << Event.new(
post: pt.post,
tag: pt.tag,
tag: pt.tag.as_json(only: [:id, :category], methods: [:name]),
user: pt.deleted_user && { id: pt.deleted_user.id, name: pt.deleted_user.name },
change_type: 'remove',
timestamp: pt.discarded_at)
@@ -186,7 +185,7 @@ class PostsController < ApplicationController
private
def filtered_posts
tag_names = params[:tags]&.split(' ')
tag_names = params[:tags].to_s.split(' ')
match_type = params[:match]
if tag_names.present?
filter_posts_by_tags(tag_names, match_type)
@@ -196,15 +195,15 @@ class PostsController < ApplicationController
end
def filter_posts_by_tags tag_names, match_type
posts = Post.joins(:tags)
posts = Post.joins(tags: :tag_name)
if match_type == 'any'
posts = posts.where(tags: { name: tag_names }).distinct
posts.where(tag_names: { name: tag_names }).distinct
else
tag_names.each do |tag|
posts = posts.where(id: Post.joins(:tags).where(tags: { name: tag }))
end
posts.where(tag_names: { name: tag_names })
.group('posts.id')
.having('COUNT(DISTINCT tag_names.id) = ?', tag_names.uniq.size)
end
posts.distinct
end
def sync_post_tags! post, desired_tags
@@ -255,7 +254,8 @@ class PostsController < ApplicationController
return nil unless tag
if path.include?(tag_id)
return tag.as_json(only: [:id, :name, :category, :post_count]).merge(children: [])
return tag.as_json(only: [:id, :category, :post_count],
methods: [:name]).merge(children: [])
end
if memo.key?(tag_id)
@@ -267,7 +267,8 @@ class PostsController < ApplicationController
children = child_ids.filter_map { |cid| build_node.(cid, new_path) }
memo[tag_id] = tag.as_json(only: [:id, :name, :category, :post_count]).merge(children:)
memo[tag_id] = tag.as_json(only: [:id, :category, :post_count],
methods: [:name]).merge(children:)
end
root_ids.filter_map { |id| build_node.call(id, []) }
@@ -1,16 +0,0 @@
class SettingsController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
@@ -1,16 +0,0 @@
class TagAliasesController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
+24 -23
View File
@@ -1,46 +1,47 @@
class TagsController < ApplicationController
def index
post_id = params[:post]
tags = if post_id.present?
Tag.joins(:posts).where(posts: { id: post_id })
else
Tag.all
end
render json: tags
tags =
if post_id.present?
Tag.joins(:posts).where(posts: { id: post_id })
else
Tag.all
end
render json: tags.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
end
def autocomplete
q = params[:q].to_s.strip
return render json: [] if q.blank?
tags = (Tag
.where('(category = ? AND name LIKE ?) OR name LIKE ?',
tags = (Tag.joins(:tag_name).includes(:tag_name)
.where('(tags.category = ? AND tag_names.name LIKE ?) OR tag_names.name LIKE ?',
'nico', "nico:#{ q }%", "#{ q }%")
.order('post_count DESC, name ASC')
.order(Arel.sql('post_count DESC, tag_names.name ASC'))
.limit(20))
render json: tags
render json: tags.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
end
def show
tag = Tag.find(params[:id])
render json: tag
end
def show_by_name
tag = Tag.find_by(name: params[:name])
tag = Tag.find_by(id: params[:id])
if tag
render json: tag
render json: tag.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
else
head :not_found
end
end
def create
end
def show_by_name
name = params[:name].to_s.strip
return head :bad_request if name.blank?
def update
end
def destroy
tag = Tag.joins(:tag_name).includes(:tag_name).find_by(tag_names: { name: })
if tag
render json: tag.as_json(only: [:id, :category, :post_count], methods: [:name, :has_wiki])
else
head :not_found
end
end
end
@@ -1,16 +0,0 @@
class UserIpsController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
@@ -1,16 +0,0 @@
class UserPostViewsController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
@@ -18,6 +18,8 @@ class UsersController < ApplicationController
end
def renew
return head :unauthorized unless current_user
user = current_user
user.inheritance_code = SecureRandom.uuid
user.save!
@@ -2,19 +2,25 @@ class WikiPagesController < ApplicationController
rescue_from Wiki::Commit::Conflict, with: :render_wiki_conflict
def index
render json: WikiPage.all
pages = WikiPage.all
render json: pages.as_json(methods: [:title])
end
def show
render_wiki_page_or_404 WikiPage.find(params[:id])
page = WikiPage.find_by(id: params[:id])
render_wiki_page_or_404 page
end
def show_by_title
render_wiki_page_or_404 WikiPage.find_by(title: params[:title])
title = params[:title].to_s.strip
page = WikiPage.joins(:tag_name)
.includes(:tag_name)
.find_by(tag_names: { name: title })
render_wiki_page_or_404 page
end
def exists
if WikiPage.exists?(params[:id])
if WikiPage.exists?(id: params[:id])
head :no_content
else
head :not_found
@@ -22,7 +28,8 @@ class WikiPagesController < ApplicationController
end
def exists_by_title
if WikiPage.exists?(title: params[:title])
title = params[:title].to_s.strip
if WikiPage.joins(:tag_name).exists?(tag_names: { name: title })
head :no_content
else
head :not_found
@@ -81,7 +88,7 @@ class WikiPagesController < ApplicationController
message = params[:message].presence
Wiki::Commit.content!(page:, body:, created_user: current_user, message:)
render json: page, status: :created
render json: page.as_json(methods: [:title]), status: :created
else
render json: { errors: page.errors.full_messages },
status: :unprocessable_entity
@@ -115,14 +122,14 @@ class WikiPagesController < ApplicationController
end
def search
title = params[:title]&.strip
title = params[:title].to_s.strip
q = WikiPage.all
q = WikiPage.joins(:tag_name).includes(:tag_name)
if title.present?
q = q.where('title LIKE ?', "%#{ WikiPage.sanitize_sql_like(title) }%")
q = q.where('tag_names.name LIKE ?', "%#{ WikiPage.sanitize_sql_like(title) }%")
end
render json: q.limit(20)
render json: q.limit(20).as_json(methods: [:title])
end
def changes
@@ -163,12 +170,14 @@ class WikiPagesController < ApplicationController
succ = page.succ_revision_id(revision_id)
updated_at = rev.created_at
return render json: page.as_json.merge(body:, revision_id:, pred:, succ:, updated_at:)
return render json: page.as_json(methods: [:title])
.merge(body:, revision_id:, pred:, succ:, updated_at:)
end
rev = page.current_revision
unless rev
return render json: page.as_json.merge(body: nil, revision_id: nil, pred: nil, succ: nil)
return render json: page.as_json(methods: [:title])
.merge(body: nil, revision_id: nil, pred: nil, succ: nil)
end
if rev.redirect?
@@ -183,7 +192,8 @@ class WikiPagesController < ApplicationController
succ = page.succ_revision_id(revision_id)
updated_at = rev.created_at
render json: page.as_json.merge(body:, revision_id:, pred:, succ:, updated_at:)
render json: page.as_json(methods: [:title])
.merge(body:, revision_id:, pred:, succ:, updated_at:)
end
def render_wiki_conflict err