MeReactionController.php 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. <?php
  2. namespace App\Http\Controllers\V3;
  3. use App\Http\Controllers\Concerns\ResolvesCurrentUser;
  4. use App\Http\Controllers\Controller;
  5. use App\Http\Requests\V3\IndexMeReactionRequest;
  6. use App\Http\Requests\V3\StoreMeReactionRequest;
  7. use App\Http\Resources\V3\ReactionResource;
  8. use App\Http\Resources\V3\ReactionStatusResource;
  9. use App\Models\Reaction;
  10. use App\Services\V3\ReactionService;
  11. use Illuminate\Http\Request;
  12. /**
  13. * 当前登录用户自己的 reactions(点赞/收藏/书签/关注/下载记录)。
  14. *
  15. * 与 `/v3/reactions`(公共只读)分属两个控制器:这个控制器全线要求登录,
  16. * user_id 一律取当前登录用户,不接受客户端指定——替别人加关注是 target 的
  17. * 关注者管理,暂留在 v2,不属于这里。
  18. *
  19. * 取代 `POST /v2/like` 与 `DELETE /v2/like/{like}`。资源改名(v2 的 `like` →
  20. * v3 的 `reactions`)是根目录 CLAUDE.md「已登记的改名例外」里的唯一一条,
  21. * 底层仍是 `likes` 表。
  22. */
  23. class MeReactionController extends Controller
  24. {
  25. use ResolvesCurrentUser;
  26. public function __construct(private readonly ReactionService $reactions) {}
  27. /**
  28. * 列出我自己的 reactions
  29. *
  30. * @queryParam type string 操作类型。Enum: like,dislike,favorite,watch,bookmark,download
  31. * @queryParam target_type string target 的类型(task 任务、collection 文集、progress_chapter 书·章节、article 文章、terms 术语)。Enum: task,collection,progress_chapter,article,terms
  32. * @queryParam page integer 页码。Default: 1
  33. * @queryParam per_page integer 每页数量,最大 200。Default: 15
  34. */
  35. public function index(IndexMeReactionRequest $request)
  36. {
  37. $user = $this->currentUser($request);
  38. return ReactionResource::collection($this->reactions->listForUser(
  39. $user['user_uid'],
  40. $request->validated(),
  41. $request->integer('per_page', 15),
  42. ));
  43. }
  44. /**
  45. * 添加一条我自己的 reaction(幂等)
  46. *
  47. * 唯一键是 (type, target_id, user_id):重复提交不会产生第二条记录,返回同一条。
  48. * 首次创建返回 201,命中已存在的记录返回 200。
  49. *
  50. * 201 不是手写的状态码:Laravel 的 ResourceResponse::calculateStatus() 看模型的
  51. * wasRecentlyCreated,新建时自动给 201。这里不要改成固定 200——幂等端点区分
  52. * 「真的建了」与「早就有了」对调用方有用。
  53. *
  54. * @responseStatus 201 首次创建。响应体与 200 同形,区别只在这一条是本次新建的
  55. *
  56. * @bodyParam type string required 操作类型。Enum: like,dislike,favorite,watch,bookmark,download
  57. * @bodyParam target_id string required target 的 uuid
  58. * @bodyParam target_type string required target 的类型(task 任务、collection 文集、progress_chapter 书·章节、article 文章、terms 术语)。Enum: task,collection,progress_chapter,article,terms
  59. * @bodyParam context string 附加上下文,最长 128 字符
  60. */
  61. public function store(StoreMeReactionRequest $request)
  62. {
  63. $user = $this->currentUser($request);
  64. return new ReactionStatusResource(
  65. $this->reactions->add($user['user_uid'], $request->validated())
  66. );
  67. }
  68. /**
  69. * 删除我自己的 reaction
  70. *
  71. * 只能删自己那条(user_id 与当前用户不符返回 403)。
  72. *
  73. * @urlParam reaction string required reaction 的 uuid
  74. *
  75. * @responseStatus 403 只能删除自己的 reaction
  76. */
  77. public function destroy(Request $request, Reaction $reaction)
  78. {
  79. $user = $this->currentUser($request);
  80. return new ReactionStatusResource(
  81. $this->reactions->remove($reaction, $user['user_uid'])
  82. );
  83. }
  84. }