mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
Add export-to-file wrapper for OPML
This commit is contained in:
parent
35e79d53a9
commit
deea294f8a
7 changed files with 128 additions and 0 deletions
|
@ -86,6 +86,8 @@ abstract class AbstractException extends \Exception {
|
|||
"Feed/Exception.xmlEntity" => 10512,
|
||||
"Feed/Exception.subscriptionNotFound" => 10521,
|
||||
"Feed/Exception.unsupportedFeedFormat" => 10522,
|
||||
"ImportExport/Exception.fileUnwritable" => 10604,
|
||||
"ImportExport/Exception.fileUncreatable" => 10605,
|
||||
];
|
||||
|
||||
public function __construct(string $msgID = "", $vars = null, \Throwable $e = null) {
|
||||
|
|
10
lib/ImportExport/Exception.php
Normal file
10
lib/ImportExport/Exception.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/** @license MIT
|
||||
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||
* See LICENSE and AUTHORS files for details */
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse\ImportExport;
|
||||
|
||||
class Exception extends \JKingWeb\Arsse\AbstractException {
|
||||
}
|
|
@ -7,9 +7,13 @@ declare(strict_types=1);
|
|||
namespace JKingWeb\Arsse\ImportExport;
|
||||
|
||||
use JKingWeb\Arsse\Arsse;
|
||||
use JKingWeb\Arsse\User\Exception as UserException;
|
||||
|
||||
class OPML {
|
||||
public function export(string $user, bool $flat = false): string {
|
||||
if (!Arsse::$user->exists($user)) {
|
||||
throw new UserException("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
|
||||
}
|
||||
$tags = [];
|
||||
$folders = [];
|
||||
$parents = [0 => null];
|
||||
|
@ -68,4 +72,14 @@ class OPML {
|
|||
// return the serialization
|
||||
return $document->saveXML();
|
||||
}
|
||||
|
||||
public function exportFile(string $file, string $user, bool $flat = false): bool {
|
||||
$data = $this->export($user, $flat);
|
||||
if (!@file_put_contents($file, $data)) {
|
||||
// if it fails throw an exception
|
||||
$err = file_exists($file) ? "fileUnwritable" : "fileUncreatable";
|
||||
throw new Exception($err, ['file' => $file, 'format' => str_replace(__NAMESPACE__."\\", "", __CLASS__)]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,4 +155,14 @@ return [
|
|||
'Exception.JKingWeb/Arsse/Feed/Exception.xmlEntity' => 'Refused to parse feed "{url}" because it contains an XXE attack',
|
||||
'Exception.JKingWeb/Arsse/Feed/Exception.subscriptionNotFound' => 'Unable to find a feed at location "{url}"',
|
||||
'Exception.JKingWeb/Arsse/Feed/Exception.unsupportedFeedFormat' => 'Feed "{url}" is of an unsupported format',
|
||||
'Exception.JKingWeb/Arsse/ImportExport/Exception.fileUncreatable' =>
|
||||
'Insufficient permissions to write {type, select,
|
||||
OPML {OPML}
|
||||
other {"{type}"}
|
||||
} export to file "{file}"',
|
||||
'Exception.JKingWeb/Arsse/ImportExport/Exception.fileUnwritable' =>
|
||||
'Insufficient permissions to write {type, select,
|
||||
OPML {OPML}
|
||||
other {"{type}"}
|
||||
} export to existing file "{file}"',
|
||||
];
|
||||
|
|
|
@ -79,7 +79,10 @@ OPML_EXPORT_SERIALIZATION;
|
|||
OPML_EXPORT_SERIALIZATION;
|
||||
|
||||
public function setUp() {
|
||||
self::clearData();
|
||||
Arsse::$db = \Phake::mock(\JKingWeb\Arsse\Database::class);
|
||||
Arsse::$user = \Phake::mock(\JKingWeb\Arsse\User::class);
|
||||
\Phake::when(Arsse::$user)->exists->thenReturn(true);
|
||||
}
|
||||
|
||||
public function testExportToOpml() {
|
||||
|
@ -95,4 +98,10 @@ OPML_EXPORT_SERIALIZATION;
|
|||
\Phake::when(Arsse::$db)->tagSummarize("john.doe@example.com")->thenReturn(new Result($this->tags));
|
||||
$this->assertXmlStringEqualsXmlString($this->serializationFlat, (new OPML)->export("john.doe@example.com", true));
|
||||
}
|
||||
|
||||
public function testExportToOpmlAMissingUser() {
|
||||
\Phake::when(Arsse::$user)->exists->thenReturn(false);
|
||||
$this->assertException("doesNotExist", "User");
|
||||
(new OPML)->export("john.doe@example.com");
|
||||
}
|
||||
}
|
||||
|
|
82
tests/cases/ImportExport/TestOPMLFile.php
Normal file
82
tests/cases/ImportExport/TestOPMLFile.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/** @license MIT
|
||||
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||
* See LICENSE and AUTHORS files for details */
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse\TestCase\ImportExport;
|
||||
|
||||
use JKingWeb\Arsse\ImportExport\OPML;
|
||||
use JKingWeb\Arsse\ImportExport\Exception;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
|
||||
/** @covers \JKingWeb\Arsse\ImportExport\OPML<extended> */
|
||||
class TestOPMLFile extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
protected $vfs;
|
||||
protected $path;
|
||||
protected $opml;
|
||||
|
||||
public function setUp() {
|
||||
self::clearData();
|
||||
// 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");
|
||||
$this->vfs = vfsStream::setup("root", null, [
|
||||
'exportGoodFile' => "",
|
||||
'exportGoodDir' => [],
|
||||
'exportBadFile' => "",
|
||||
'exportBadDir' => [],
|
||||
]);
|
||||
$this->path = $this->vfs->url()."/";
|
||||
// make the "bad" entries inaccessible
|
||||
chmod($this->path."exportBadFile", 0000);
|
||||
chmod($this->path."exportBadDir", 0000);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
$this->path = null;
|
||||
$this->vfs = null;
|
||||
$this->opml = null;
|
||||
self::clearData();
|
||||
}
|
||||
|
||||
/** @dataProvider provideFileExports */
|
||||
public function testExportOpmlToAFile(string $file, string $user, bool $flat, $exp) {
|
||||
$path = $this->path.$file;
|
||||
try {
|
||||
if ($exp instanceof \JKingWeb\Arsse\AbstractException) {
|
||||
$this->assertException($exp);
|
||||
$this->opml->exportFile($path, $user, $flat);
|
||||
} else {
|
||||
$this->assertSame($exp, $this->opml->exportFile($path, $user, $flat));
|
||||
$this->assertSame("OPML_FILE", $this->vfs->getChild($file)->getContent());
|
||||
}
|
||||
} finally {
|
||||
\Phake::verify($this->opml)->export($user, $flat);
|
||||
}
|
||||
}
|
||||
|
||||
public function provideFileExports() {
|
||||
$createException = new Exception("fileUncreatable");
|
||||
$writeException = new Exception("fileUnwritable");
|
||||
return [
|
||||
["exportGoodFile", "john.doe@example.com", true, true],
|
||||
["exportGoodFile", "john.doe@example.com", false, true],
|
||||
["exportGoodFile", "jane.doe@example.com", true, true],
|
||||
["exportGoodFile", "jane.doe@example.com", false, true],
|
||||
["exportGoodDir/file", "john.doe@example.com", true, true],
|
||||
["exportGoodDir/file", "john.doe@example.com", false, true],
|
||||
["exportGoodDir/file", "jane.doe@example.com", true, true],
|
||||
["exportGoodDir/file", "jane.doe@example.com", false, true],
|
||||
["exportBadFile", "john.doe@example.com", true, $writeException],
|
||||
["exportBadFile", "john.doe@example.com", false, $writeException],
|
||||
["exportBadFile", "jane.doe@example.com", true, $writeException],
|
||||
["exportBadFile", "jane.doe@example.com", false, $writeException],
|
||||
["exportBadDir/file", "john.doe@example.com", true, $createException],
|
||||
["exportBadDir/file", "john.doe@example.com", false, $createException],
|
||||
["exportBadDir/file", "jane.doe@example.com", true, $createException],
|
||||
["exportBadDir/file", "jane.doe@example.com", false, $createException],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -115,6 +115,7 @@
|
|||
</testsuite>
|
||||
<testsuite name="Import/Export">
|
||||
<file>cases/ImportExport/TestOPML.php</file>
|
||||
<file>cases/ImportExport/TestOPMLFile.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
|
Loading…
Reference in a new issue