diff --git a/lib/ImportExport/OPML.php b/lib/ImportExport/OPML.php index a45d4e1a..5c633b4b 100644 --- a/lib/ImportExport/OPML.php +++ b/lib/ImportExport/OPML.php @@ -38,9 +38,9 @@ class OPML { // start a transaction for atomic rollback $tr = Arsse::$db->begin(); // get current state of database - $foldersDb = iterator_to_array(Arsse::$db->folderList(Arsse::$user->id)); - $feedsDb = iterator_to_array(Arsse::$db->subscriptionList(Arsse::$user->id)); - $tagsDb = iterator_to_array(Arsse::$db->tagList(Arsse::$user->id)); + $foldersDb = iterator_to_array(Arsse::$db->folderList($user)); + $feedsDb = iterator_to_array(Arsse::$db->subscriptionList($user)); + $tagsDb = iterator_to_array(Arsse::$db->tagList($user)); // reconcile folders $folderMap = [0 => 0]; foreach ($folders as $id => $f) { @@ -54,7 +54,7 @@ class OPML { } if (!isset($folderMap[$id])) { // if no existing folder exists, add one - $folderMap[$id] = Arsse::$db->folderAdd(Arsse::$user->id, ['name' => $f['name'], 'parent' -> $parent]); + $folderMap[$id] = Arsse::$db->folderAdd($user, ['name' => $f['name'], 'parent' -> $parent]); } } // process newsfeed subscriptions @@ -74,11 +74,11 @@ class OPML { } if (!$found) { // if no subscription exists, add one - $feedMap[$f['id']] = Arsse::$db->subscriptionAdd(Arsse::$user->id, $f['url']); + $feedMap[$f['id']] = Arsse::$db->subscriptionAdd($user, $f['url']); } if (!$found || $replace) { // set the subscription's properties, if this is a new feed or we're doing a full replacement - Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, $feedMap[$f['id']], ['title' => $title, 'folder' => $folder]); + Arsse::$db->subscriptionPropertiesSet($user, $feedMap[$f['id']], ['title' => $title, 'folder' => $folder]); // compile the set of used tags, if this is a new feed or we're doing a full replacement foreach ($f['tags'] as $t) { if (!strlen(trim($t))) { @@ -106,29 +106,29 @@ class OPML { } if (!$found) { // add the tag if it wasn't found - Arsse::$db->tagAdd(Arsse::$user->id, ['name' => $tag]); + Arsse::$db->tagAdd($user, ['name' => $tag]); } - Arsse::$db->tagSubscriptionsSet(Arsse::$user->id, $tag, $subs, $mode, true); + Arsse::$db->tagSubscriptionsSet($user, $tag, $subs, $mode, true); } // finally, if we're performing a replacement, delete any subscriptions, folders, or tags which were not present in the import if ($replace) { foreach (array_diff(array_column($feedsDb, "id"), $feedMap) as $id) { try { - Arsse::$db->subscriptionRemove(Arsse::$user->id, $id); + Arsse::$db->subscriptionRemove($user, $id); } catch (InputException $e) { // ignore errors } } foreach (array_diff(array_column($foldersDb, "id"), $folderMap) as $id) { try { - Arsse::$db->folderRemove(Arsse::$user->id, $id); + Arsse::$db->folderRemove($user, $id); } catch (InputException $e) { // ignore errors } } foreach (array_diff(array_column($tagsDb, "name"), array_keys($tagMap)) as $id) { try { - Arsse::$db->tagRemove(Arsse::$user->id, $id, true); + Arsse::$db->tagRemove($user, $id, true); } catch (InputException $e) { // ignore errors } @@ -287,7 +287,7 @@ class OPML { return true; } - public function imortFile(string $file, string $user, bool $flat = false, bool $replace): bool { + public function importFile(string $file, string $user, bool $flat = false, bool $replace): bool { $data = @file_get_contents($file); if ($data === false) { // if it fails throw an exception diff --git a/tests/cases/ImportExport/TestOPMLFile.php b/tests/cases/ImportExport/TestOPMLFile.php index 37b9e61d..35147ef8 100644 --- a/tests/cases/ImportExport/TestOPMLFile.php +++ b/tests/cases/ImportExport/TestOPMLFile.php @@ -21,16 +21,20 @@ class TestOPMLFile extends \JKingWeb\Arsse\Test\AbstractTest { // create a mock OPML processor with stubbed underlying import/export routines $this->opml = \Phake::partialMock(OPML::class); \Phake::when($this->opml)->export->thenReturn("OPML_FILE"); + \Phake::when($this->opml)->import->thenReturn(true); $this->vfs = vfsStream::setup("root", null, [ 'exportGoodFile' => "", 'exportGoodDir' => [], 'exportBadFile' => "", 'exportBadDir' => [], + 'importGoodFile' => "", + 'importBadFile' => "", ]); $this->path = $this->vfs->url()."/"; // make the "bad" entries inaccessible chmod($this->path."exportBadFile", 0000); chmod($this->path."exportBadDir", 0000); + chmod($this->path."importBadFile", 0000); } public function tearDown() { @@ -78,4 +82,50 @@ class TestOPMLFile extends \JKingWeb\Arsse\Test\AbstractTest { ["exportBadDir/file", "jane.doe@example.com", false, $createException], ]; } + + /** @dataProvider provideFileImports */ + public function testImportFromOpmlFile(string $file, string $user, bool $flat, bool $replace, $exp) { + $path = $this->path.$file; + try { + if ($exp instanceof \JKingWeb\Arsse\AbstractException) { + $this->assertException($exp); + $this->opml->importFile($path, $user, $flat, $replace); + } else { + $this->assertSame($exp, $this->opml->importFile($path, $user, $flat, $replace)); + } + } finally { + \Phake::verify($this->opml, \Phake::times((int) ($exp === true)))->import($user, "", $flat, $replace); + } + } + + public function provideFileImports() { + $missingException = new Exception("fileMissing"); + $permissionException = new Exception("fileUnreadable"); + return [ + ["importGoodFile", "john.doe@example.com", true, true, true], + ["importBadFile", "john.doe@example.com", true, true, $permissionException], + ["importNonFile", "john.doe@example.com", true, true, $missingException], + ["importGoodFile", "john.doe@example.com", true, false, true], + ["importBadFile", "john.doe@example.com", true, false, $permissionException], + ["importNonFile", "john.doe@example.com", true, false, $missingException], + ["importGoodFile", "john.doe@example.com", false, true, true], + ["importBadFile", "john.doe@example.com", false, true, $permissionException], + ["importNonFile", "john.doe@example.com", false, true, $missingException], + ["importGoodFile", "john.doe@example.com", false, false, true], + ["importBadFile", "john.doe@example.com", false, false, $permissionException], + ["importNonFile", "john.doe@example.com", false, false, $missingException], + ["importGoodFile", "jane.doe@example.com", true, true, true], + ["importBadFile", "jane.doe@example.com", true, true, $permissionException], + ["importNonFile", "jane.doe@example.com", true, true, $missingException], + ["importGoodFile", "jane.doe@example.com", true, false, true], + ["importBadFile", "jane.doe@example.com", true, false, $permissionException], + ["importNonFile", "jane.doe@example.com", true, false, $missingException], + ["importGoodFile", "jane.doe@example.com", false, true, true], + ["importBadFile", "jane.doe@example.com", false, true, $permissionException], + ["importNonFile", "jane.doe@example.com", false, true, $missingException], + ["importGoodFile", "jane.doe@example.com", false, false, true], + ["importBadFile", "jane.doe@example.com", false, false, $permissionException], + ["importNonFile", "jane.doe@example.com", false, false, $missingException], + ]; + } }