1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-06-27 16:36:00 +00:00

refuse requests for deletions records that are too old

This commit is contained in:
Martin Chaine 2025-06-03 18:45:01 +02:00
parent e08c10af5d
commit 1883ff1380
No known key found for this signature in database
GPG key ID: 2D04DFDC89D53FDE
2 changed files with 62 additions and 5 deletions

View file

@ -7,8 +7,10 @@ use Hateoas\Representation\Factory\PagerfantaFactory;
use OpenApi\Attributes as OA;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\GoneHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Wallabag\Entity\EntryDeletion;
use Wallabag\Helper\EntryDeletionExpirationConfig;
use Wallabag\Repository\EntryDeletionRepository;
use Wallabag\OpenApi\Attribute as WOA;
@ -36,26 +38,63 @@ class EntryDeletionRestController extends WallabagRestController
responses: [
new OA\Response(
response: 200,
description: 'Returned when successful',
description: 'Returned when successful.',
content: new WOA\PagerFanta\JsonContent(EntryDeletion::class)
),
new OA\Response(
response: 410,
description: 'Returned when the since date is before the cutoff date.',
content: new OA\JsonContent(
type: 'object',
properties: [
'message' => new OA\Property(type: 'string'),
]
),
headers: [
new OA\Header(
header: 'X-Wallabag-Entry-Deletion-Cutoff',
description: 'The furthest cutoff timestamp possible for entry deletions.',
schema: new OA\Schema(type: 'integer')
),
]
)
]
)]
#[IsGranted('LIST_ENTRIES')]
public function getEntryDeletionsAction(Request $request, EntryDeletionRepository $entryDeletionRepository)
{
public function getEntryDeletionsAction(
Request $request,
EntryDeletionRepository $entryDeletionRepository,
EntryDeletionExpirationConfig $expirationConfig
) {
$this->validateAuthentication();
$userId = $this->getUser()->getId();
$page = $request->query->get('page', 1);
$perPage = $request->query->get('perPage', 100);
$order = $request->query->get('order', 'desc');
$since = $request->query->get('since');
$since = (int)$request->query->get('since', 0);
if (!\in_array($order, ['asc', 'desc'], true)) {
$order = 'desc';
}
if (0 < $since) {
$cutoff = $expirationConfig->getCutoffDate()->getTimestamp();
if ($since < $cutoff) {
// Using a JSON response rather than a GoneHttpException to preserve the error message in production
return $this->json(
[
'message' => "The requested since date ({$since}) is before the data retention cutoff date ({$cutoff}).\n"
. "You can get the cutoff date programmatically from the X-Wallabag-Entry-Deletion-Cutoff header.",
],
410,
headers: [
'X-Wallabag-Entry-Deletion-Cutoff' => $cutoff,
]
);
}
}
$pager = $entryDeletionRepository->findEntryDeletions($userId, $since, $order);
$pager->setMaxPerPage($perPage);
$pager->setCurrentPage($page);

View file

@ -33,7 +33,6 @@ class EntryDeletionRestControllerTest extends WallabagApiTestCase
public function testGetEntryDeletionsSince()
{
// Test date range filter - get deletions from last 2 days
$since = (new \DateTime('-2 days'))->getTimestamp();
$this->client->request('GET', "/api/entry-deletions?since={$since}");
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
@ -41,4 +40,23 @@ class EntryDeletionRestControllerTest extends WallabagApiTestCase
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertGreaterThanOrEqual(1, \count($content['_embedded']['items']));
}
public function testGetEntryDeletionsWithSinceBeforeCutoffDate()
{
$sinceBeforeCutoff = (new \DateTime('-410 days'))->getTimestamp();
$this->client->request('GET', "/api/entry-deletions?since={$sinceBeforeCutoff}");
$this->assertSame(410, $this->client->getResponse()->getStatusCode());
$content = $this->client->getResponse()->getContent();
$this->assertStringContainsString('The requested since date', $content);
$this->assertStringContainsString('is before the data retention cutoff date', $content);
$this->assertStringContainsString('X-Wallabag-Entry-Deletion-Cutoff', $content);
$response = $this->client->getResponse();
$this->assertTrue($response->headers->has('X-Wallabag-Entry-Deletion-Cutoff'));
$cutoffTimestamp = $response->headers->get('X-Wallabag-Entry-Deletion-Cutoff');
$this->assertIsNumeric($cutoffTimestamp);
$this->assertGreaterThan($sinceBeforeCutoff, (int) $cutoffTimestamp);
}
}