|
5 | 5 | namespace App\Controller\Api\Post; |
6 | 6 |
|
7 | 7 | use App\Controller\Traits\PrivateContentTrait; |
| 8 | +use App\DTO\ContentResponseDto; |
8 | 9 | use App\DTO\PostResponseDto; |
9 | 10 | use App\Entity\Magazine; |
10 | 11 | use App\Entity\Post; |
| 12 | +use App\Entity\PostComment; |
11 | 13 | use App\Entity\User; |
12 | 14 | use App\Event\Post\PostHasBeenSeenEvent; |
13 | 15 | use App\Factory\PostFactory; |
@@ -308,7 +310,6 @@ public function collection( |
308 | 310 | #[IsGranted('ROLE_OAUTH2_READ')] |
309 | 311 | public function subscribed( |
310 | 312 | ContentRepository $repository, |
311 | | - PostFactory $factory, |
312 | 313 | RateLimiterFactoryInterface $apiReadLimiter, |
313 | 314 | RateLimiterFactoryInterface $anonymousApiReadLimiter, |
314 | 315 | SymfonySecurity $security, |
@@ -344,7 +345,155 @@ public function subscribed( |
344 | 345 | try { |
345 | 346 | \assert($value instanceof Post); |
346 | 347 | $this->handlePrivateContent($value); |
347 | | - array_push($dtos, $this->serializePost($factory->createDto($value), $this->tagLinkRepository->getTagsOfContent($value))); |
| 348 | + $dtos[] = $this->serializePost($this->postFactory->createDto($value), $this->tagLinkRepository->getTagsOfContent($value)); |
| 349 | + } catch (\Exception $e) { |
| 350 | + continue; |
| 351 | + } |
| 352 | + } |
| 353 | + |
| 354 | + return new JsonResponse( |
| 355 | + $this->serializePaginated($dtos, $posts), |
| 356 | + headers: $headers |
| 357 | + ); |
| 358 | + } |
| 359 | + |
| 360 | + #[OA\Response( |
| 361 | + response: 200, |
| 362 | + description: 'A paginated list of posts from user\'s subscribed magazines', |
| 363 | + content: new OA\JsonContent( |
| 364 | + type: 'object', |
| 365 | + properties: [ |
| 366 | + new OA\Property( |
| 367 | + property: 'items', |
| 368 | + type: 'array', |
| 369 | + items: new OA\Items(ref: new Model(type: ContentResponseDto::class)) |
| 370 | + ), |
| 371 | + new OA\Property( |
| 372 | + property: 'pagination', |
| 373 | + ref: new Model(type: PaginationSchema::class) |
| 374 | + ), |
| 375 | + ] |
| 376 | + ), |
| 377 | + headers: [ |
| 378 | + new OA\Header(header: 'X-RateLimit-Remaining', schema: new OA\Schema(type: 'integer'), description: 'Number of requests left until you will be rate limited'), |
| 379 | + new OA\Header(header: 'X-RateLimit-Retry-After', schema: new OA\Schema(type: 'integer'), description: 'Unix timestamp to retry the request after'), |
| 380 | + new OA\Header(header: 'X-RateLimit-Limit', schema: new OA\Schema(type: 'integer'), description: 'Number of requests available'), |
| 381 | + ] |
| 382 | + )] |
| 383 | + #[OA\Response( |
| 384 | + response: 401, |
| 385 | + description: 'Permission denied due to missing or expired token', |
| 386 | + content: new OA\JsonContent(ref: new Model(type: \App\Schema\Errors\UnauthorizedErrorSchema::class)) |
| 387 | + )] |
| 388 | + #[OA\Response( |
| 389 | + response: 429, |
| 390 | + description: 'You are being rate limited', |
| 391 | + content: new OA\JsonContent(ref: new Model(type: \App\Schema\Errors\TooManyRequestsErrorSchema::class)), |
| 392 | + headers: [ |
| 393 | + new OA\Header(header: 'X-RateLimit-Remaining', schema: new OA\Schema(type: 'integer'), description: 'Number of requests left until you will be rate limited'), |
| 394 | + new OA\Header(header: 'X-RateLimit-Retry-After', schema: new OA\Schema(type: 'integer'), description: 'Unix timestamp to retry the request after'), |
| 395 | + new OA\Header(header: 'X-RateLimit-Limit', schema: new OA\Schema(type: 'integer'), description: 'Number of requests available'), |
| 396 | + ] |
| 397 | + )] |
| 398 | + #[OA\Parameter( |
| 399 | + name: 'p', |
| 400 | + description: 'Page of posts to retrieve', |
| 401 | + in: 'query', |
| 402 | + schema: new OA\Schema(type: 'integer', default: 1, minimum: 1) |
| 403 | + )] |
| 404 | + #[OA\Parameter( |
| 405 | + name: 'perPage', |
| 406 | + description: 'Number of posts to retrieve per page', |
| 407 | + in: 'query', |
| 408 | + schema: new OA\Schema(type: 'integer', default: PostRepository::PER_PAGE, minimum: self::MIN_PER_PAGE, maximum: self::MAX_PER_PAGE) |
| 409 | + )] |
| 410 | + #[OA\Parameter( |
| 411 | + name: 'sort', |
| 412 | + description: 'Sort method to use when retrieving posts', |
| 413 | + in: 'query', |
| 414 | + schema: new OA\Schema(type: 'string', default: Criteria::SORT_HOT, enum: Criteria::SORT_OPTIONS) |
| 415 | + )] |
| 416 | + #[OA\Parameter( |
| 417 | + name: 'time', |
| 418 | + description: 'Max age of retrieved posts', |
| 419 | + in: 'query', |
| 420 | + schema: new OA\Schema(type: 'string', default: Criteria::TIME_ALL, enum: Criteria::TIME_ROUTES_EN) |
| 421 | + )] |
| 422 | + #[OA\Parameter( |
| 423 | + name: 'lang[]', |
| 424 | + description: 'Language(s) of posts to return', |
| 425 | + in: 'query', |
| 426 | + explode: true, |
| 427 | + allowReserved: true, |
| 428 | + schema: new OA\Schema( |
| 429 | + type: 'array', |
| 430 | + items: new OA\Items(type: 'string', default: null, minLength: 2, maxLength: 3) |
| 431 | + ) |
| 432 | + )] |
| 433 | + #[OA\Parameter( |
| 434 | + name: 'usePreferredLangs', |
| 435 | + description: 'Filter by a user\'s preferred languages? (Requires authentication and takes precedence over lang[])', |
| 436 | + in: 'query', |
| 437 | + schema: new OA\Schema(type: 'boolean', default: false), |
| 438 | + )] |
| 439 | + #[OA\Parameter( |
| 440 | + name: 'federation', |
| 441 | + description: 'What type of federated entries to retrieve', |
| 442 | + in: 'query', |
| 443 | + schema: new OA\Schema(type: 'string', default: Criteria::AP_ALL, enum: Criteria::AP_OPTIONS) |
| 444 | + )] |
| 445 | + #[OA\Parameter( |
| 446 | + name: 'includeBoosts', |
| 447 | + description: 'if true then boosted content from followed users are included', |
| 448 | + in: 'query', |
| 449 | + schema: new OA\Schema(type: 'boolean', default: false) |
| 450 | + )] |
| 451 | + #[OA\Tag(name: 'post')] |
| 452 | + #[Security(name: 'oauth2', scopes: ['read'])] |
| 453 | + #[IsGranted('ROLE_OAUTH2_READ')] |
| 454 | + public function subscribedWithBoosts( |
| 455 | + ContentRepository $repository, |
| 456 | + RateLimiterFactoryInterface $apiReadLimiter, |
| 457 | + RateLimiterFactoryInterface $anonymousApiReadLimiter, |
| 458 | + SymfonySecurity $security, |
| 459 | + SqlHelpers $sqlHelpers, |
| 460 | + #[MapQueryParameter] ?int $p, |
| 461 | + #[MapQueryParameter] ?int $perPage, |
| 462 | + #[MapQueryParameter] ?string $sort, |
| 463 | + #[MapQueryParameter] ?string $time, |
| 464 | + #[MapQueryParameter] ?string $federation, |
| 465 | + ): JsonResponse { |
| 466 | + $headers = $this->rateLimit($apiReadLimiter, $anonymousApiReadLimiter); |
| 467 | + |
| 468 | + $criteria = new PostPageView($p ?? 1, $security); |
| 469 | + $criteria->sortOption = $sort ?? Criteria::SORT_HOT; |
| 470 | + $criteria->time = $criteria->resolveTime($time ?? Criteria::TIME_ALL); |
| 471 | + $criteria->perPage = self::constrainPerPage($perPage ?? ContentRepository::PER_PAGE); |
| 472 | + $criteria->setFederation($federation ?? Criteria::AP_ALL); |
| 473 | + |
| 474 | + $criteria->subscribed = true; |
| 475 | + $criteria->includeBoosts = true; |
| 476 | + $criteria->setContent(Criteria::CONTENT_MICROBLOG); |
| 477 | + |
| 478 | + $this->handleLanguageCriteria($criteria); |
| 479 | + |
| 480 | + $user = $this->getUserOrThrow(); |
| 481 | + $criteria->fetchCachedItems($sqlHelpers, $user); |
| 482 | + |
| 483 | + $posts = $repository->findByCriteria($criteria); |
| 484 | + |
| 485 | + $dtos = []; |
| 486 | + foreach ($posts->getCurrentPageResults() as $value) { |
| 487 | + try { |
| 488 | + if ($value instanceof Post) { |
| 489 | + $this->handlePrivateContent($value); |
| 490 | + $dtos[] = new ContentResponseDto(post: $this->serializePost($this->postFactory->createDto($value), $this->tagLinkRepository->getTagsOfContent($value))); |
| 491 | + } elseif ($value instanceof PostComment) { |
| 492 | + $this->handlePrivateContent($value); |
| 493 | + $dtos[] = new ContentResponseDto(postComment: $this->serializePostComment($this->postCommentFactory->createDto($value), $this->tagLinkRepository->getTagsOfContent($value))); |
| 494 | + } else { |
| 495 | + throw new \AssertionError('got unexpected type '.\get_class($value)); |
| 496 | + } |
348 | 497 | } catch (\Exception $e) { |
349 | 498 | continue; |
350 | 499 | } |
|
0 commit comments