From bf8fee14e3b6e33d4436686e3b339d91ab795401 Mon Sep 17 00:00:00 2001 From: thrillfall Date: Fri, 24 Feb 2023 20:48:53 +0100 Subject: [PATCH] delete conflicting episode action if current episode actions updates to same episode url --- lib/Core/EpisodeAction/EpisodeActionSaver.php | 23 ++++++ .../EpisodeAction/EpisodeActionRepository.php | 5 ++ ...tionSaverGuidBackwardCompatibilityTest.php | 77 +++++++++---------- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/lib/Core/EpisodeAction/EpisodeActionSaver.php b/lib/Core/EpisodeAction/EpisodeActionSaver.php index cfac4b9..12edc31 100644 --- a/lib/Core/EpisodeAction/EpisodeActionSaver.php +++ b/lib/Core/EpisodeAction/EpisodeActionSaver.php @@ -69,7 +69,17 @@ class EpisodeActionSaver $this->ensureGuidDoesNotGetNulledWithOldData($episodeActionToUpdate, $episodeActionEntity); + try { + return $this->episodeActionWriter->update($episodeActionEntity); + } catch (UniqueConstraintViolationException $uniqueConstraintViolationException) { + $this->deleteConflictingEpisodeAction($episodeActionEntity, $userId); + } catch (Exception $exception) { + if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + $this->deleteConflictingEpisodeAction($episodeActionEntity, $userId); + } + } return $this->episodeActionWriter->update($episodeActionEntity); + } private function ensureGuidDoesNotGetNulledWithOldData(EpisodeAction $episodeActionToUpdate, EpisodeActionEntity $episodeActionEntity): void @@ -115,4 +125,17 @@ class EpisodeActionSaver return $episodeAction; } + + /** + * @param EpisodeActionEntity $episodeActionEntity + * @param string $userId + * @return void + */ + private function deleteConflictingEpisodeAction(EpisodeActionEntity $episodeActionEntity, string $userId): void + { + $collidingEpisodeActionId = $this->episodeActionRepository->findByEpisodeUrl($episodeActionEntity->getGuid(), $userId)->getId(); + if ($collidingEpisodeActionId !== $episodeActionEntity->getId()) { + $this->episodeActionRepository->deleteEpisodeActionByEpisodeUrl($episodeActionEntity->getGuid(), $userId); + } + } } diff --git a/lib/Db/EpisodeAction/EpisodeActionRepository.php b/lib/Db/EpisodeAction/EpisodeActionRepository.php index ff60e8b..e159e2a 100644 --- a/lib/Db/EpisodeAction/EpisodeActionRepository.php +++ b/lib/Db/EpisodeAction/EpisodeActionRepository.php @@ -52,6 +52,11 @@ class EpisodeActionRepository { ); } + public function deleteEpisodeActionByEpisodeUrl(string $episodeUrl, string $userId) : void { + $episodeAction = $this->episodeActionMapper->findByEpisodeUrl($episodeUrl, $userId); + $this->episodeActionMapper->delete($episodeAction); + } + private function mapEntityToEpisodeAction(EpisodeActionEntity $episodeActionEntity): EpisodeAction { return new EpisodeAction( diff --git a/tests/Integration/EpisodeActionSaverGuidBackwardCompatibilityTest.php b/tests/Integration/EpisodeActionSaverGuidBackwardCompatibilityTest.php index 99b903b..47ad971 100644 --- a/tests/Integration/EpisodeActionSaverGuidBackwardCompatibilityTest.php +++ b/tests/Integration/EpisodeActionSaverGuidBackwardCompatibilityTest.php @@ -14,39 +14,40 @@ use Test\TestCase; class EpisodeActionSaverGuidBackwardCompatibilityTest extends TestCase { - private const USER_ID_0 = "testuser0"; + private const USER_ID_0 = "testuser0"; - private \OCP\AppFramework\IAppContainer $container; + private \OCP\AppFramework\IAppContainer $container; - public function setUp(): void { - parent::setUp(); - $app = new App('gpoddersync'); - $this->container = $app->getContainer(); - } + public function setUp(): void + { + parent::setUp(); + $app = new App('gpoddersync'); + $this->container = $app->getContainer(); + } - public function testUpdateWithoutGuidDoesNotNullGuid() : void - { - /** @var EpisodeActionSaver $episodeActionSaver */ - $episodeActionSaver = $this->container->get(EpisodeActionSaver::class); + public function testUpdateWithoutGuidDoesNotNullGuid(): void + { + /** @var EpisodeActionSaver $episodeActionSaver */ + $episodeActionSaver = $this->container->get(EpisodeActionSaver::class); - $episodeUrl = uniqid("test_https://dts.podtrac.com/redirect.mp3/chrt.fm/track"); - $guid = uniqid("test_gid://art19-episode-locator/V0/Ktd"); + $episodeUrl = uniqid("test_https://dts.podtrac.com/redirect.mp3/chrt.fm/track"); + $guid = uniqid("test_gid://art19-episode-locator/V0/Ktd"); - $savedEpisodeActionEntity = $episodeActionSaver->saveEpisodeActions( - [["podcast" => 'https://rss.art19.com/dr-death-s3-miracle-man', "episode" => $episodeUrl, "guid" => $guid, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 47, "position" => 54, "total" => 2252]], - self::USER_ID_0 - )[0]; + $savedEpisodeActionEntity = $episodeActionSaver->saveEpisodeActions( + [["podcast" => 'https://rss.art19.com/dr-death-s3-miracle-man', "episode" => $episodeUrl, "guid" => $guid, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 47, "position" => 54, "total" => 2252]], + self::USER_ID_0 + )[0]; - $savedEpisodeActionEntityWithoutGuidFromOldDevice = $episodeActionSaver->saveEpisodeActions( - [["podcast" => 'https://rss.art19.com/dr-death-s3-miracle-man', "episode" => $episodeUrl, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 47, "position" => 54, "total" => 2252]], - self::USER_ID_0 - )[0]; + $savedEpisodeActionEntityWithoutGuidFromOldDevice = $episodeActionSaver->saveEpisodeActions( + [["podcast" => 'https://rss.art19.com/dr-death-s3-miracle-man', "episode" => $episodeUrl, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 47, "position" => 54, "total" => 2252]], + self::USER_ID_0 + )[0]; - self::assertSame($savedEpisodeActionEntity->getId(), $savedEpisodeActionEntityWithoutGuidFromOldDevice->getId()); - self::assertNotNull($savedEpisodeActionEntityWithoutGuidFromOldDevice->getGuid()); - } + self::assertSame($savedEpisodeActionEntity->getId(), $savedEpisodeActionEntityWithoutGuidFromOldDevice->getId()); + self::assertNotNull($savedEpisodeActionEntityWithoutGuidFromOldDevice->getGuid()); + } - public function testDoNotFailToUpdateEpisodeActionByGuidIfThereIsAnotherWithTheSameValueForEpisodeUrl() : void + public function testDoNotFailToUpdateEpisodeActionByGuidIfThereIsAnotherWithTheSameValueForEpisodeUrl(): void { //arrange /** @var EpisodeActionSaver $episodeActionSaver */ @@ -63,13 +64,13 @@ class EpisodeActionSaverGuidBackwardCompatibilityTest extends TestCase )[0]; $episodeActionSaver->saveEpisodeActions( - [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $url, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], + [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $url, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], self::USER_ID_0 )[0]; //act $episodeActionSaver->saveEpisodeActions( - [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $url, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], + [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $url, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], self::USER_ID_0 )[0]; @@ -78,19 +79,15 @@ class EpisodeActionSaverGuidBackwardCompatibilityTest extends TestCase $episodeActionRepository = $this->container->get(EpisodeActionRepository::class); $this->assertSame(100, $episodeActionRepository->findByGuid($urlWithParameter, self::USER_ID_0)->getPosition()); - try { - //act - $episodeActionSaver->saveEpisodeActions( - [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $urlWithParameter, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], - self::USER_ID_0 - )[0]; - - $this->assertSame(1,2); - - } catch (\Exception $exception) { - $this->assertStringContainsString("SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry", $exception->getMessage()); - $this->assertStringContainsString("for key 'gpodder_episode_user_id'", $exception->getMessage()); - } + //act + $episodeActionSaver->saveEpisodeActions( + [["podcast" => $podcastUrl, "episode" => $urlWithParameter, "guid" => $urlWithParameter, "action" => "PLAY", "timestamp" => "2021-08-22T23:58:56", "started" => 35, "position" => 100, "total" => 2252]], + self::USER_ID_0 + )[0]; + //assert + /** @var EpisodeActionRepository $episodeActionRepository */ + $episodeActionRepository = $this->container->get(EpisodeActionRepository::class); + $this->assertSame(100, $episodeActionRepository->findByGuid($urlWithParameter, self::USER_ID_0)->getPosition()); } }