ぼざクリ タグ広場 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.
 
 
 
 
 
 

172 lines
5.0 KiB

  1. class PostsController < ApplicationController
  2. # GET /posts
  3. def index
  4. limit = params[:limit].presence&.to_i
  5. cursor = params[:cursor].presence
  6. created_at = ('COALESCE(posts.original_created_before - INTERVAL 1 SECOND,' +
  7. 'posts.original_created_from,' +
  8. 'posts.created_at)')
  9. q = filtered_posts.order(Arel.sql("#{ created_at } DESC"))
  10. q = q.where("#{ created_at } < ?", Time.iso8601(cursor)) if cursor
  11. posts = limit ? q.limit(limit + 1) : q
  12. next_cursor = nil
  13. if limit && posts.size > limit
  14. next_cursor = posts.last.created_at.iso8601(6)
  15. posts = posts.first(limit)
  16. end
  17. render json: { posts: posts.map { |post|
  18. post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }).tap do |json|
  19. json['thumbnail'] =
  20. if post.thumbnail.attached?
  21. rails_storage_proxy_url(post.thumbnail, only_path: false)
  22. else
  23. nil
  24. end
  25. end
  26. }, next_cursor: }
  27. end
  28. def random
  29. post = filtered_posts.order('RAND()').first
  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, :post_count] } })
  34. .merge(viewed:))
  35. end
  36. # GET /posts/1
  37. def show
  38. post = Post.includes(:tags).find(params[:id])
  39. return head :not_found unless post
  40. viewed = current_user&.viewed?(post) || false
  41. render json: (post
  42. .as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
  43. .merge(related: post.related(limit: 20), viewed:))
  44. end
  45. # POST /posts
  46. def create
  47. return head :unauthorized unless current_user
  48. return head :forbidden unless current_user.member?
  49. # TODO: URL が正規のものがチェック,不正ならエラー
  50. # TODO: URL は必須にする(タイトルは省略可).
  51. # TODO: サイトに応じて thumbnail_base 設定
  52. title = params[:title]
  53. url = params[:url]
  54. thumbnail = params[:thumbnail]
  55. tag_names = params[:tags].to_s.split(' ')
  56. original_created_from = params[:original_created_from]
  57. original_created_before = params[:original_created_before]
  58. post = Post.new(title:, url:, thumbnail_base: '', uploaded_user: current_user,
  59. original_created_from:, original_created_before:)
  60. post.thumbnail.attach(thumbnail)
  61. if post.save
  62. post.resized_thumbnail!
  63. sync_post_tags!(post, Tag.normalise_tags(tag_names))
  64. render json: post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
  65. status: :created
  66. else
  67. render json: { errors: post.errors.full_messages }, status: :unprocessable_entity
  68. end
  69. end
  70. def viewed
  71. return head :unauthorized unless current_user
  72. current_user.viewed_posts << Post.find(params[:id])
  73. head :no_content
  74. end
  75. def unviewed
  76. return head :unauthorized unless current_user
  77. current_user.viewed_posts.delete(Post.find(params[:id]))
  78. head :no_content
  79. end
  80. # PATCH/PUT /posts/1
  81. def update
  82. return head :unauthorized unless current_user
  83. return head :forbidden unless current_user.member?
  84. title = params[:title]
  85. tag_names = params[:tags].to_s.split(' ')
  86. original_created_from = params[:original_created_from]
  87. original_created_before = params[:original_created_before]
  88. post = Post.find(params[:id].to_i)
  89. if post.update(title:, original_created_from:, original_created_before:)
  90. sync_post_tags!(post,
  91. (post.tags.where(category: 'nico').to_a +
  92. Tag.normalise_tags(tag_names)))
  93. render json: post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
  94. status: :ok
  95. else
  96. render json: post.errors, status: :unprocessable_entity
  97. end
  98. end
  99. # DELETE /posts/1
  100. def destroy
  101. end
  102. private
  103. def filtered_posts
  104. tag_names = params[:tags]&.split(' ')
  105. match_type = params[:match]
  106. if tag_names.present?
  107. filter_posts_by_tags(tag_names, match_type)
  108. else
  109. Post.all
  110. end
  111. end
  112. def filter_posts_by_tags tag_names, match_type
  113. posts = Post.joins(:tags)
  114. if match_type == 'any'
  115. posts = posts.where(tags: { name: tag_names }).distinct
  116. else
  117. tag_names.each do |tag|
  118. posts = posts.where(id: Post.joins(:tags).where(tags: { name: tag }))
  119. end
  120. end
  121. posts.distinct
  122. end
  123. def sync_post_tags! post, desired_tags
  124. desired_tags.each do |t|
  125. t.save! if t.new_record?
  126. end
  127. desired_ids = desired_tags.map(&:id).to_set
  128. current_ids = post.tags.pluck(:id).to_set
  129. to_add = desired_ids - current_ids
  130. to_remove = current_ids - desired_ids
  131. Tag.where(id: to_add).find_each do |tag|
  132. begin
  133. PostTag.create!(post:, tag:, created_user: current_user)
  134. rescue ActiveRecord::RecordNotUnique
  135. ;
  136. end
  137. end
  138. PostTag.where(post_id: post.id, tag_id: to_remove.to_a).kept.find_each do |pt|
  139. pt.discard_by!(current_user)
  140. end
  141. end
  142. end