ぼざクリ タグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

153 lines
4.1 KiB

  1. require 'open-uri'
  2. require 'nokogiri'
  3. class PostsController < ApplicationController
  4. # GET /posts
  5. def index
  6. limit = (params[:limit] || 20).to_i
  7. cursor = params[:cursor].presence
  8. q = filtered_posts.order(created_at: :desc)
  9. q = q.where('posts.created_at < ?', Time.iso8601(cursor)) if cursor
  10. posts = q.limit(limit + 1)
  11. next_cursor = nil
  12. if posts.size > limit
  13. next_cursor = posts.last.created_at.iso8601(6)
  14. posts = posts.first(limit)
  15. end
  16. render json: { posts: posts.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
  17. next_cursor: }
  18. end
  19. def random
  20. post = filtered_posts.order('RAND()').first
  21. return head :not_found unless post
  22. viewed = current_user&.viewed?(post) || false
  23. render json: (post
  24. .as_json(include: { tags: { only: [:id, :name, :category] } })
  25. .merge(viewed: viewed))
  26. end
  27. # GET /posts/1
  28. def show
  29. post = Post.includes(:tags).find(params[:id])
  30. return head :not_found unless post
  31. viewed = current_user&.viewed?(post) || false
  32. render json: (post
  33. .as_json(include: { tags: { only: [:id, :name, :category] } })
  34. .merge(viewed: viewed))
  35. end
  36. # POST /posts
  37. def create
  38. return head :unauthorized unless current_user
  39. return head :forbidden unless current_user.member?
  40. # TODO: URL が正規のものがチェック,不正ならエラー
  41. # TODO: title、URL は必須にする.
  42. # TODO: サイトに応じて thumbnail_base 設定
  43. title = params[:title]
  44. url = params[:url]
  45. thumbnail = params[:thumbnail]
  46. tag_names = params[:tags].to_s.split(' ')
  47. post = Post.new(title:, url:, thumbnail_base: '', uploaded_user: current_user)
  48. post.thumbnail.attach(thumbnail)
  49. if post.save
  50. post.resized_thumbnail!
  51. post.tags = normalise_tags(tags_names)
  52. render json: post.as_json(include: { tags: { only: [:id, :name, :category] } }),
  53. status: :created
  54. else
  55. render json: { errors: post.errors.full_messages }, status: :unprocessable_entity
  56. end
  57. end
  58. def viewed
  59. return head :unauthorized unless current_user
  60. current_user.viewed_posts << Post.find(params[:id])
  61. head :no_content
  62. end
  63. def unviewed
  64. return head :unauthorized unless current_user
  65. current_user.viewed_posts.delete(Post.find(params[:id]))
  66. head :no_content
  67. end
  68. # PATCH/PUT /posts/1
  69. def update
  70. return head :unauthorized unless current_user
  71. return head :forbidden unless current_user.member?
  72. title = params[:title]
  73. tag_names = params[:tags].to_s.split(' ')
  74. post = Post.find(params[:id].to_i)
  75. tags = post.tags.where(category: 'nico').to_a + normalise_tags(tag_names)
  76. if post.update(title:, tags:)
  77. render json: post.as_json(include: { tags: { only: [:id, :name, :category] } }),
  78. status: :created
  79. else
  80. render json: post.errors, status: :unprocessable_entity
  81. end
  82. end
  83. # DELETE /posts/1
  84. def destroy
  85. end
  86. private
  87. CATEGORY_PREFIXES = {
  88. 'gen:' => 'general',
  89. 'djk:' => 'deerjikist',
  90. 'meme:' => 'meme',
  91. 'chr:' => 'character',
  92. 'mtr:' => 'material',
  93. 'meta:' => 'meta' }.freeze
  94. def filtered_posts
  95. tag_names = params[:tags]&.split(' ')
  96. match_type = params[:match]
  97. tag_names.present? ? filter_posts_by_tags(tag_names, match_type) : Post.all
  98. end
  99. def filter_posts_by_tags tag_names, match_type
  100. posts = Post.joins(:tags)
  101. if match_type == 'any'
  102. posts = posts.where(tags: { name: tag_names }).distinct
  103. else
  104. tag_names.each do |tag|
  105. posts = posts.where(id: Post.joins(:tags).where(tags: { name: tag }))
  106. end
  107. end
  108. posts.distinct
  109. end
  110. def normalise_tags tag_names
  111. tags = tag_names.map do |name|
  112. pf, cat = CATEGORY_PREFIXES.find { |p, _| name.start_with?(p) } || ['', nil]
  113. name.delete_prefix!(pf)
  114. Tag.find_or_initialize_by(name:).tap do |tag|
  115. if cat && tag.category != cat
  116. tag.category = cat
  117. tag.save!
  118. end
  119. end
  120. end
  121. tags << Tag.tagme if tags.size < 20 && tags.none?(Tag.tagme)
  122. tags.uniq
  123. end
  124. end