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

146 lines
4.4 KiB

  1. require 'open-uri'
  2. require 'nokogiri'
  3. class PostsController < ApplicationController
  4. # GET /posts
  5. def index
  6. limit = params[:limit].presence&.to_i
  7. cursor = params[:cursor].presence
  8. created_at = ('COALESCE(posts.original_created_before - INTERVAL 1 SECOND,' +
  9. 'posts.original_created_from,' +
  10. 'posts.created_at)')
  11. q = filtered_posts.order(Arel.sql("#{ created_at } DESC"))
  12. q = q.where("#{ created_at } < ?", Time.iso8601(cursor)) if cursor
  13. posts = limit ? q.limit(limit + 1) : q
  14. next_cursor = nil
  15. if limit && posts.size > limit
  16. next_cursor = posts.last.created_at.iso8601(6)
  17. posts = posts.first(limit)
  18. end
  19. render json: { posts: posts.map { |post|
  20. post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }).tap do |json|
  21. json['thumbnail'] =
  22. if post.thumbnail.attached?
  23. rails_storage_proxy_url(post.thumbnail, only_path: false)
  24. else
  25. nil
  26. end
  27. end
  28. }, next_cursor: }
  29. end
  30. def random
  31. post = filtered_posts.order('RAND()').first
  32. return head :not_found unless post
  33. viewed = current_user&.viewed?(post) || false
  34. render json: (post
  35. .as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
  36. .merge(viewed:))
  37. end
  38. # GET /posts/1
  39. def show
  40. post = Post.includes(:tags).find(params[:id])
  41. return head :not_found unless post
  42. viewed = current_user&.viewed?(post) || false
  43. render json: (post
  44. .as_json(include: { tags: { only: [:id, :name, :category, :post_count] } })
  45. .merge(related: post.related(limit: 20), viewed:))
  46. end
  47. # POST /posts
  48. def create
  49. return head :unauthorized unless current_user
  50. return head :forbidden unless current_user.member?
  51. # TODO: URL が正規のものがチェック,不正ならエラー
  52. # TODO: URL は必須にする(タイトルは省略可).
  53. # TODO: サイトに応じて thumbnail_base 設定
  54. title = params[:title]
  55. url = params[:url]
  56. thumbnail = params[:thumbnail]
  57. tag_names = params[:tags].to_s.split(' ')
  58. original_created_from = params[:original_created_from]
  59. original_created_before = params[:original_created_before]
  60. post = Post.new(title:, url:, thumbnail_base: '', uploaded_user: current_user,
  61. original_created_from:, original_created_before:)
  62. post.thumbnail.attach(thumbnail)
  63. if post.save
  64. post.resized_thumbnail!
  65. post.tags = Tag.normalise_tags(tag_names)
  66. render json: post.as_json(include: { tags: { only: [:id, :name, :category, :post_count] } }),
  67. status: :created
  68. else
  69. render json: { errors: post.errors.full_messages }, status: :unprocessable_entity
  70. end
  71. end
  72. def viewed
  73. return head :unauthorized unless current_user
  74. current_user.viewed_posts << Post.find(params[:id])
  75. head :no_content
  76. end
  77. def unviewed
  78. return head :unauthorized unless current_user
  79. current_user.viewed_posts.delete(Post.find(params[:id]))
  80. head :no_content
  81. end
  82. # PATCH/PUT /posts/1
  83. def update
  84. return head :unauthorized unless current_user
  85. return head :forbidden unless current_user.member?
  86. title = params[:title]
  87. tag_names = params[:tags].to_s.split(' ')
  88. original_created_from = params[:original_created_from]
  89. original_created_before = params[:original_created_before]
  90. post = Post.find(params[:id].to_i)
  91. tags = post.tags.where(category: 'nico').to_a + Tag.normalise_tags(tag_names)
  92. if post.update(title:, tags:, original_created_from:, original_created_before:)
  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. tag_names.present? ? filter_posts_by_tags(tag_names, match_type) : Post.all
  107. end
  108. def filter_posts_by_tags tag_names, match_type
  109. posts = Post.joins(:tags)
  110. if match_type == 'any'
  111. posts = posts.where(tags: { name: tag_names }).distinct
  112. else
  113. tag_names.each do |tag|
  114. posts = posts.where(id: Post.joins(:tags).where(tags: { name: tag }))
  115. end
  116. end
  117. posts.distinct
  118. end
  119. end