Merge remote-tracking branch 'origin/main' into feature/084
This commit is contained in:
@@ -48,9 +48,12 @@ class PostsController < ApplicationController
|
||||
|
||||
viewed = current_user&.viewed?(post) || false
|
||||
|
||||
render json: (post
|
||||
.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
|
||||
.merge(related: post.related(limit: 20), viewed:))
|
||||
json = post.as_json
|
||||
json['tags'] = build_tag_tree_for(post.tags)
|
||||
json['related'] = post.related(limit: 20)
|
||||
json['viewed'] = viewed
|
||||
|
||||
render json:
|
||||
end
|
||||
|
||||
# POST /posts
|
||||
@@ -73,7 +76,9 @@ class PostsController < ApplicationController
|
||||
post.thumbnail.attach(thumbnail)
|
||||
if post.save
|
||||
post.resized_thumbnail!
|
||||
sync_post_tags!(post, Tag.normalise_tags(tag_names))
|
||||
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] } }),
|
||||
status: :created
|
||||
else
|
||||
@@ -107,11 +112,13 @@ class PostsController < ApplicationController
|
||||
|
||||
post = Post.find(params[:id].to_i)
|
||||
if post.update(title:, original_created_from:, original_created_before:)
|
||||
sync_post_tags!(post,
|
||||
(post.tags.where(category: 'nico').to_a +
|
||||
Tag.normalise_tags(tag_names)))
|
||||
render json: post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
|
||||
status: :ok
|
||||
tags = post.tags.where(category: 'nico').to_a +
|
||||
Tag.normalise_tags(tag_names, with_tagme: false)
|
||||
tags = Tag.expand_parent_tags(tags)
|
||||
sync_post_tags!(post, tags)
|
||||
json = post.as_json
|
||||
json['tags'] = build_tag_tree_for(post.tags)
|
||||
render json:, status: :ok
|
||||
else
|
||||
render json: post.errors, status: :unprocessable_entity
|
||||
end
|
||||
@@ -168,4 +175,46 @@ class PostsController < ApplicationController
|
||||
pt.discard_by!(current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def build_tag_tree_for tags
|
||||
tags = tags.to_a
|
||||
tag_ids = tags.map(&:id)
|
||||
|
||||
implications = TagImplication.where(parent_tag_id: tag_ids, tag_id: tag_ids)
|
||||
|
||||
children_ids_by_parent = Hash.new { |h, k| h[k] = [] }
|
||||
implications.each do |imp|
|
||||
children_ids_by_parent[imp.parent_tag_id] << imp.tag_id
|
||||
end
|
||||
|
||||
child_ids = children_ids_by_parent.values.flatten.uniq
|
||||
|
||||
root_ids = tag_ids - child_ids
|
||||
|
||||
tags_by_id = tags.index_by(&:id)
|
||||
|
||||
memo = { }
|
||||
|
||||
build_node = -> tag_id, path do
|
||||
tag = tags_by_id[tag_id]
|
||||
return nil unless tag
|
||||
|
||||
if path.include?(tag_id)
|
||||
return tag.as_json(only: [:id, :name, :category, :post_count]).merge(children: [])
|
||||
end
|
||||
|
||||
if memo.key?(tag_id)
|
||||
return memo[tag_id]
|
||||
end
|
||||
|
||||
new_path = path + [tag_id]
|
||||
child_ids = children_ids_by_parent[tag_id] || []
|
||||
|
||||
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:)
|
||||
end
|
||||
|
||||
root_ids.filter_map { |id| build_node.call(id, []) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,12 +6,15 @@ class UsersController < ApplicationController
|
||||
end
|
||||
|
||||
def verify
|
||||
ip_bin = IPAddr.new(request.remote_ip).hton
|
||||
ip_address = IpAddress.find_or_create_by!(ip_address: ip_bin)
|
||||
|
||||
user = User.find_by(inheritance_code: params[:code])
|
||||
render json: if user
|
||||
{ valid: true, user: user.slice(:id, :name, :inheritance_code, :role) }
|
||||
else
|
||||
{ valid: false }
|
||||
end
|
||||
return render json: { valid: false } unless user
|
||||
|
||||
UserIp.find_or_create_by!(user:, ip_address:)
|
||||
|
||||
render json: { valid: true, user: user.slice(:id, :name, :inheritance_code, :role) }
|
||||
end
|
||||
|
||||
def renew
|
||||
|
||||
@@ -13,6 +13,14 @@ class Tag < ApplicationRecord
|
||||
dependent: :destroy
|
||||
has_many :linked_nico_tags, through: :reversed_nico_tag_relations, source: :nico_tag
|
||||
|
||||
has_many :tag_implications, foreign_key: :parent_tag_id, dependent: :destroy
|
||||
has_many :children, through: :tag_implications, source: :tag
|
||||
|
||||
has_many :reversed_tag_implications, class_name: 'TagImplication',
|
||||
foreign_key: :tag_id,
|
||||
dependent: :destroy
|
||||
has_many :parents, through: :reversed_tag_implications, source: :parent_tag
|
||||
|
||||
enum :category, { deerjikist: 'deerjikist',
|
||||
meme: 'meme',
|
||||
character: 'character',
|
||||
@@ -59,10 +67,33 @@ class Tag < ApplicationRecord
|
||||
end
|
||||
end
|
||||
end
|
||||
tags << Tag.tagme if with_tagme && tags.size < 20 && tags.none?(Tag.tagme)
|
||||
tags << Tag.tagme if with_tagme && tags.size < 10 && tags.none?(Tag.tagme)
|
||||
tags.uniq
|
||||
end
|
||||
|
||||
def self.expand_parent_tags tags
|
||||
return [] if tags.blank?
|
||||
|
||||
seen = Set.new
|
||||
result = []
|
||||
stack = tags.compact.dup
|
||||
|
||||
until stack.empty?
|
||||
tag = stack.pop
|
||||
next unless tag
|
||||
|
||||
tag.parents.each do |parent|
|
||||
next if seen.include?(parent.id)
|
||||
|
||||
seen << parent.id
|
||||
result << parent
|
||||
stack << parent
|
||||
end
|
||||
end
|
||||
|
||||
(result + tags).uniq { |t| t.id }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nico_tag_name_must_start_with_nico
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
class TagImplication < ApplicationRecord
|
||||
belongs_to :tag, class_name: 'Tag'
|
||||
belongs_to :parent_tag, class_name: 'Tag'
|
||||
|
||||
validates :tag_id, presence: true, uniqueness: { scope: :parent_tag_id }
|
||||
validates :parent_tag_id, presence: true
|
||||
|
||||
validate :parent_tag_mustnt_be_itself
|
||||
|
||||
private
|
||||
|
||||
def parent_tag_mustnt_be_itself
|
||||
if parent_tag == tag
|
||||
errors.add :parent_tag_id, '親タグは子タグと同一であってはなりません.'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,6 @@ class User < ApplicationRecord
|
||||
|
||||
has_many :posts
|
||||
has_many :settings
|
||||
has_many :ip_addresses
|
||||
has_many :user_ips, dependent: :destroy
|
||||
has_many :ip_addresses, through: :user_ips
|
||||
has_many :user_post_views, dependent: :destroy
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class CreateTagImplications < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
create_table :tag_implications do |t|
|
||||
t.references :tag, null: false, foreign_key: { to_table: :tags }
|
||||
t.references :parent_tag, null: false, foreign_key: { to_table: :tags }
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class RenameIpAdressColumnToIpAddresses < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
rename_column :ip_addresses, :ip_adress, :ip_address
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
class AddUniqueIndexToTagImplications < ActiveRecord::Migration[8.0]
|
||||
def up
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
ti1
|
||||
FROM
|
||||
tag_implications ti1
|
||||
INNER JOIN
|
||||
tag_implications ti2
|
||||
ON
|
||||
ti1.tag_id = ti2.tag_id
|
||||
AND ti1.parent_tag_id = ti2.parent_tag_id
|
||||
AND ti1.id > ti2.id
|
||||
;
|
||||
SQL
|
||||
|
||||
add_index :tag_implications, [:tag_id, :parent_tag_id],
|
||||
unique: true,
|
||||
name: 'index_tag_implications_on_tag_id_and_parent_tag_id'
|
||||
end
|
||||
|
||||
def down
|
||||
# NOTE: 重複削除は復元されなぃ.
|
||||
remove_index :tag_implications,
|
||||
name: 'index_tag_implications_on_tag_id_and_parent_tag_id'
|
||||
end
|
||||
end
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace :nico do
|
||||
desc 'ニコタグ連携'
|
||||
task link: :environment do
|
||||
Post.find_each do |post|
|
||||
tags = post.tags.where(category: 'nico')
|
||||
tags.each do |tag|
|
||||
post.tags.concat(tag.linked_tags) if tag.linked_tags.present?
|
||||
end
|
||||
post.tags = post.tags.to_a.uniq
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user