diff --git a/lib/Cron/DeleteCron.php b/lib/Cron/DeleteCron.php index 97854181f..6b762881c 100644 --- a/lib/Cron/DeleteCron.php +++ b/lib/Cron/DeleteCron.php @@ -13,6 +13,7 @@ use OCA\Deck\Db\CardMapper; use OCA\Deck\Db\StackMapper; use OCA\Deck\InvalidAttachmentType; use OCA\Deck\Service\AttachmentService; +use OCA\Deck\Sharing\DeckShareProvider; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJob; use OCP\BackgroundJob\TimedJob; @@ -29,14 +30,25 @@ class DeleteCron extends TimedJob { private $attachmentMapper; /** @var StackMapper */ private $stackMapper; + /** @var DeckShareProvider */ + private $deckShareProvider; - public function __construct(ITimeFactory $time, BoardMapper $boardMapper, CardMapper $cardMapper, AttachmentService $attachmentService, AttachmentMapper $attachmentMapper, StackMapper $stackMapper) { + public function __construct( + ITimeFactory $time, + BoardMapper $boardMapper, + CardMapper $cardMapper, + AttachmentService $attachmentService, + AttachmentMapper $attachmentMapper, + StackMapper $stackMapper, + DeckShareProvider $deckShareProvider, + ) { parent::__construct($time); $this->boardMapper = $boardMapper; $this->cardMapper = $cardMapper; $this->attachmentService = $attachmentService; $this->attachmentMapper = $attachmentMapper; $this->stackMapper = $stackMapper; + $this->deckShareProvider = $deckShareProvider; $this->setInterval(60 * 60 * 24); $this->setTimeSensitivity(IJob::TIME_INSENSITIVE); @@ -69,6 +81,12 @@ class DeleteCron extends TimedJob { $this->attachmentMapper->delete($attachment); } + // Delete orphaned attachment shares + $shares = $this->deckShareProvider->getOrphanedAttachmentShares(); + foreach ($shares as $share) { + $this->deckShareProvider->delete($share); + } + $stacks = $this->stackMapper->findToDelete(); foreach ($stacks as $stack) { $this->stackMapper->delete($stack); diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php index 64a0f5a1b..abec4e0ca 100644 --- a/lib/Db/CardMapper.php +++ b/lib/Db/CardMapper.php @@ -644,4 +644,16 @@ class CardMapper extends QBMapper implements IPermissionMapper { $result->closeCursor(); } + + public function getAllCardIds(): array { + $qb = $this->db->getQueryBuilder(); + $qb->select('id') + ->from('deck_cards'); + $result = $qb->executeQuery(); + $ids = []; + while ($row = $result->fetch()) { + $ids[] = (int)$row['id']; + } + return $ids; + } } diff --git a/lib/Sharing/DeckShareProvider.php b/lib/Sharing/DeckShareProvider.php index be5eb88af..8b39646aa 100644 --- a/lib/Sharing/DeckShareProvider.php +++ b/lib/Sharing/DeckShareProvider.php @@ -1045,4 +1045,21 @@ class DeckShareProvider implements \OCP\Share\IShareProvider { } $cursor->closeCursor(); } + + public function getOrphanedAttachmentShares(): array { + $allCardIds = $this->cardMapper->getAllCardIds(); + $qb = $this->dbConnection->getQueryBuilder(); + $qb->select('*') + ->from('share', 's') + ->where($qb->expr()->eq('s.share_type', $qb->createNamedParameter(IShare::TYPE_DECK))) + ->andWhere($qb->expr()->notIn('s.share_with', $qb->createNamedParameter($allCardIds, IQueryBuilder::PARAM_STR_ARRAY))); + + $cursor = $qb->execute(); + $shares = []; + while ($data = $cursor->fetch()) { + $shares[] = $this->createShareObject($data); + } + + return $shares; + } } diff --git a/tests/unit/Cron/DeleteCronTest.php b/tests/unit/Cron/DeleteCronTest.php index 1ed5f4472..751145023 100644 --- a/tests/unit/Cron/DeleteCronTest.php +++ b/tests/unit/Cron/DeleteCronTest.php @@ -34,6 +34,7 @@ use OCA\Deck\Db\StackMapper; use OCA\Deck\InvalidAttachmentType; use OCA\Deck\Service\AttachmentService; use OCA\Deck\Service\IAttachmentService; +use OCA\Deck\Sharing\DeckShareProvider; use OCP\AppFramework\Utility\ITimeFactory; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; @@ -52,6 +53,8 @@ class DeleteCronTest extends TestCase { private $attachmentMapper; /** @var StackMapper|MockObject */ private $stackMapper; + /** @var DeckShareProvider */ + private $deckShareProvider; /** @var DeleteCron */ protected $deleteCron; @@ -63,7 +66,16 @@ class DeleteCronTest extends TestCase { $this->attachmentService = $this->createMock(AttachmentService::class); $this->attachmentMapper = $this->createMock(AttachmentMapper::class); $this->stackMapper = $this->createMock(StackMapper::class); - $this->deleteCron = new DeleteCron($this->timeFactory, $this->boardMapper, $this->cardMapper, $this->attachmentService, $this->attachmentMapper, $this->stackMapper); + $this->deckShareProvider = $this->createMock(DeckShareProvider::class); + $this->deleteCron = new DeleteCron( + $this->timeFactory, + $this->boardMapper, + $this->cardMapper, + $this->attachmentService, + $this->attachmentMapper, + $this->stackMapper, + $this->deckShareProvider, + ); } protected function getBoard($id) {