Permanently delete deck cards marked as deleted after 5 min in a cron job

Limit deleted cards in one cron job run to 500

Converted spaces to tabs

Added missing import for CardMapper class

Added another missing import for CardMapper class

Fixed response object in findToDelete method + fixed 2 misspellings in API.md

Fixed invalid parameter type

Fix DeleteCronTest

Signed-off-by: Marcel Klehr <mklehr@gmx.net>

Fix lint errors

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
Michal Polacik
2021-08-27 23:26:25 +02:00
committed by Julius Härtl
parent 19f466fd4d
commit 8698e2ce3f
4 changed files with 49 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
The REST API provides access for authenticated users to their data inside the Deck app. To get a better understanding of Decks data models and their relations, please have a look at the [data structure](structure.md) documentation. The REST API provides access for authenticated users to their data inside the Deck app. To get a better understanding of Decks data models and their relations, please have a look at the [data structure](structure.md) documentation.
# Prequisited # Prerequisites
- All requests require a `OCS-APIRequest` HTTP header to be set to `true` and a `Content-Type` of `application/json`. - All requests require a `OCS-APIRequest` HTTP header to be set to `true` and a `Content-Type` of `application/json`.
- The API is located at https://nextcloud.local/index.php/apps/deck/api/v1.0 - The API is located at https://nextcloud.local/index.php/apps/deck/api/v1.0
@@ -9,7 +9,7 @@ The REST API provides access for authenticated users to their data inside the De
## Naming ## Naming
- Board is the the project like grouping of tasks that can be shared to different users and groups - Board is the project like grouping of tasks that can be shared to different users and groups
- Stack is the grouping of cards which is rendered in vertical columns in the UI - Stack is the grouping of cards which is rendered in vertical columns in the UI

View File

@@ -28,6 +28,7 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob; use OCP\BackgroundJob\TimedJob;
use OCA\Deck\Db\AttachmentMapper; use OCA\Deck\Db\AttachmentMapper;
use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\InvalidAttachmentType; use OCA\Deck\InvalidAttachmentType;
use OCA\Deck\Service\AttachmentService; use OCA\Deck\Service\AttachmentService;
use OCP\BackgroundJob\IJob; use OCP\BackgroundJob\IJob;
@@ -36,14 +37,17 @@ class DeleteCron extends TimedJob {
/** @var BoardMapper */ /** @var BoardMapper */
private $boardMapper; private $boardMapper;
/** @var CardMapper */
private $cardMapper;
/** @var AttachmentService */ /** @var AttachmentService */
private $attachmentService; private $attachmentService;
/** @var AttachmentMapper */ /** @var AttachmentMapper */
private $attachmentMapper; private $attachmentMapper;
public function __construct(ITimeFactory $time, BoardMapper $boardMapper, AttachmentService $attachmentService, AttachmentMapper $attachmentMapper) { public function __construct(ITimeFactory $time, BoardMapper $boardMapper, CardMapper $cardMapper, AttachmentService $attachmentService, AttachmentMapper $attachmentMapper) {
parent::__construct($time); parent::__construct($time);
$this->boardMapper = $boardMapper; $this->boardMapper = $boardMapper;
$this->cardMapper = $cardMapper;
$this->attachmentService = $attachmentService; $this->attachmentService = $attachmentService;
$this->attachmentMapper = $attachmentMapper; $this->attachmentMapper = $attachmentMapper;
@@ -61,6 +65,12 @@ class DeleteCron extends TimedJob {
$this->boardMapper->delete($board); $this->boardMapper->delete($board);
} }
$timeLimit = time() - (60 * 5); // 5 min buffer
$cards = $this->cardMapper->findToDelete($timeLimit, 500);
foreach ($cards as $card) {
$this->cardMapper->delete($card);
}
$attachments = $this->attachmentMapper->findToDelete(); $attachments = $this->attachmentMapper->findToDelete();
foreach ($attachments as $attachment) { foreach ($attachments as $attachment) {
try { try {

View File

@@ -177,6 +177,17 @@ class CardMapper extends QBMapper implements IPermissionMapper {
return $qb; return $qb;
} }
public function findToDelete($timeLimit, $limit = null) {
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'title', 'owner', 'archived', 'deleted_at', 'last_modified')
->from('deck_cards')
->where($qb->expr()->gt('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->lt('deleted_at', $qb->createNamedParameter($timeLimit, IQueryBuilder::PARAM_INT)))
->orderBy('deleted_at')
->setMaxResults($limit);
return $this->findEntities($qb);
}
public function findDeleted($boardId, $limit = null, $offset = null) { public function findDeleted($boardId, $limit = null, $offset = null) {
$qb = $this->queryCardsByBoard($boardId); $qb = $this->queryCardsByBoard($boardId);
$qb->andWhere($qb->expr()->neq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))) $qb->andWhere($qb->expr()->neq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))

View File

@@ -27,6 +27,8 @@ use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\AttachmentMapper; use OCA\Deck\Db\AttachmentMapper;
use OCA\Deck\Db\Board; use OCA\Deck\Db\Board;
use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper;
use OCA\Deck\InvalidAttachmentType; use OCA\Deck\InvalidAttachmentType;
use OCA\Deck\Service\AttachmentService; use OCA\Deck\Service\AttachmentService;
use OCA\Deck\Service\IAttachmentService; use OCA\Deck\Service\IAttachmentService;
@@ -40,7 +42,9 @@ class DeleteCronTest extends TestCase {
private $timeFactory; private $timeFactory;
/** @var BoardMapper|MockObject */ /** @var BoardMapper|MockObject */
protected $boardMapper; protected $boardMapper;
/** @var AttachmentService|MockObject */ /** @var CardMapper|\PHPUnit\Framework\MockObject\MockObject */
protected $cardMapper;
/** @var AttachmentService|\PHPUnit\Framework\MockObject\MockObject */
private $attachmentService; private $attachmentService;
/** @var AttachmentMapper|MockObject */ /** @var AttachmentMapper|MockObject */
private $attachmentMapper; private $attachmentMapper;
@@ -51,9 +55,10 @@ class DeleteCronTest extends TestCase {
parent::setUp(); parent::setUp();
$this->timeFactory = $this->createMock(ITimeFactory::class); $this->timeFactory = $this->createMock(ITimeFactory::class);
$this->boardMapper = $this->createMock(BoardMapper::class); $this->boardMapper = $this->createMock(BoardMapper::class);
$this->cardMapper = $this->createMock(CardMapper::class);
$this->attachmentService = $this->createMock(AttachmentService::class); $this->attachmentService = $this->createMock(AttachmentService::class);
$this->attachmentMapper = $this->createMock(AttachmentMapper::class); $this->attachmentMapper = $this->createMock(AttachmentMapper::class);
$this->deleteCron = new DeleteCron($this->timeFactory, $this->boardMapper, $this->attachmentService, $this->attachmentMapper); $this->deleteCron = new DeleteCron($this->timeFactory, $this->boardMapper, $this->cardMapper, $this->attachmentService, $this->attachmentMapper);
} }
protected function getBoard($id) { protected function getBoard($id) {
@@ -62,6 +67,12 @@ class DeleteCronTest extends TestCase {
return $board; return $board;
} }
protected function getCard($id) {
$card = new Card();
$card->setId($id);
return $card;
}
public function testDeleteCron() { public function testDeleteCron() {
$boards = [ $boards = [
$this->getBoard(1), $this->getBoard(1),
@@ -81,6 +92,14 @@ class DeleteCronTest extends TestCase {
[$boards[3]] [$boards[3]]
); );
$cards = [ $this->getCard(10) ];
$this->cardMapper->expects($this->once())
->method('findToDelete')
->willReturn($cards);
$this->cardMapper->expects($this->once())
->method('delete')
->with($cards[0]);
$attachment = new Attachment(); $attachment = new Attachment();
$attachment->setType('deck_file'); $attachment->setType('deck_file');
$this->attachmentMapper->expects($this->once()) $this->attachmentMapper->expects($this->once())
@@ -107,6 +126,10 @@ class DeleteCronTest extends TestCase {
->method('findToDelete') ->method('findToDelete')
->willReturn($boards); ->willReturn($boards);
$this->cardMapper->expects($this->once())
->method('findToDelete')
->willReturn([]);
$attachment = new Attachment(); $attachment = new Attachment();
$attachment->setType('deck_file_invalid'); $attachment->setType('deck_file_invalid');
$this->attachmentMapper->expects($this->once()) $this->attachmentMapper->expects($this->once())