2016-07-28 22:54:33 +02:00
|
|
|
<?php
|
2020-06-17 15:55:31 +02:00
|
|
|
|
2018-12-04 00:13:42 +01:00
|
|
|
namespace Shaarli\Netscape;
|
2016-07-28 22:54:33 +02:00
|
|
|
|
2018-12-04 00:13:42 +01:00
|
|
|
use DateTime;
|
2020-09-26 14:18:01 +02:00
|
|
|
use malkusch\lock\mutex\NoMutex;
|
2020-06-17 19:08:02 +02:00
|
|
|
use Psr\Http\Message\UploadedFileInterface;
|
2020-01-17 21:34:12 +01:00
|
|
|
use Shaarli\Bookmark\Bookmark;
|
|
|
|
use Shaarli\Bookmark\BookmarkFileService;
|
2020-06-17 15:55:31 +02:00
|
|
|
use Shaarli\Bookmark\BookmarkFilter;
|
2017-03-10 18:49:53 +01:00
|
|
|
use Shaarli\Config\ConfigManager;
|
2018-12-02 23:24:58 +01:00
|
|
|
use Shaarli\History;
|
2021-01-20 15:59:00 +01:00
|
|
|
use Shaarli\Plugin\PluginManager;
|
2020-09-29 14:41:40 +02:00
|
|
|
use Shaarli\TestCase;
|
2020-06-17 19:08:02 +02:00
|
|
|
use Slim\Http\UploadedFile;
|
2016-07-28 22:54:33 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility function to load a file's metadata in a $_FILES-like array
|
|
|
|
*
|
|
|
|
* @param string $filename Basename of the file
|
|
|
|
*
|
2020-06-17 19:08:02 +02:00
|
|
|
* @return UploadedFileInterface Upload file in PSR-7 compatible object
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
function file2array($filename)
|
|
|
|
{
|
2020-06-17 19:08:02 +02:00
|
|
|
return new UploadedFile(
|
|
|
|
__DIR__ . '/input/' . $filename,
|
|
|
|
$filename,
|
|
|
|
null,
|
|
|
|
filesize(__DIR__ . '/input/' . $filename)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Netscape bookmark import
|
|
|
|
*/
|
2020-06-17 15:55:31 +02:00
|
|
|
class BookmarkImportTest extends TestCase
|
2016-07-28 22:54:33 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var string datastore to test write operations
|
|
|
|
*/
|
|
|
|
protected static $testDatastore = 'sandbox/datastore.php';
|
|
|
|
|
2017-01-16 12:31:08 +01:00
|
|
|
/**
|
|
|
|
* @var string History file path
|
|
|
|
*/
|
|
|
|
protected static $historyFilePath = 'sandbox/history.php';
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* @var BookmarkFileService private LinkDB instance
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
2020-01-17 21:34:12 +01:00
|
|
|
protected $bookmarkService = null;
|
2016-07-28 22:54:33 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string Dummy page cache
|
|
|
|
*/
|
|
|
|
protected $pagecache = 'tests';
|
|
|
|
|
2017-02-09 20:54:56 +01:00
|
|
|
/**
|
|
|
|
* @var ConfigManager instance.
|
|
|
|
*/
|
|
|
|
protected $conf;
|
|
|
|
|
2017-01-16 12:31:08 +01:00
|
|
|
/**
|
|
|
|
* @var History instance.
|
|
|
|
*/
|
|
|
|
protected $history;
|
|
|
|
|
2020-06-17 15:55:31 +02:00
|
|
|
/**
|
|
|
|
* @var NetscapeBookmarkUtils
|
|
|
|
*/
|
|
|
|
protected $netscapeBookmarkUtils;
|
|
|
|
|
2021-01-20 15:59:00 +01:00
|
|
|
/** @var PluginManager */
|
|
|
|
protected $pluginManager;
|
|
|
|
|
2016-11-28 16:17:25 +01:00
|
|
|
/**
|
|
|
|
* @var string Save the current timezone.
|
|
|
|
*/
|
|
|
|
protected static $defaultTimeZone;
|
|
|
|
|
2020-09-26 15:08:39 +02:00
|
|
|
public static function setUpBeforeClass(): void
|
2016-11-28 16:17:25 +01:00
|
|
|
{
|
|
|
|
self::$defaultTimeZone = date_default_timezone_get();
|
|
|
|
// Timezone without DST for test consistency
|
|
|
|
date_default_timezone_set('Africa/Nairobi');
|
|
|
|
}
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
/**
|
|
|
|
* Resets test data before each test
|
|
|
|
*/
|
2020-09-26 15:08:39 +02:00
|
|
|
protected function setUp(): void
|
2016-07-28 22:54:33 +02:00
|
|
|
{
|
2020-09-26 14:18:01 +02:00
|
|
|
$mutex = new NoMutex();
|
2016-07-28 22:54:33 +02:00
|
|
|
if (file_exists(self::$testDatastore)) {
|
|
|
|
unlink(self::$testDatastore);
|
|
|
|
}
|
|
|
|
// start with an empty datastore
|
|
|
|
file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
|
2020-01-17 21:34:12 +01:00
|
|
|
|
2017-02-09 20:54:56 +01:00
|
|
|
$this->conf = new ConfigManager('tests/utils/config/configJson');
|
|
|
|
$this->conf->set('resource.page_cache', $this->pagecache);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->conf->set('resource.datastore', self::$testDatastore);
|
2017-01-16 12:31:08 +01:00
|
|
|
$this->history = new History(self::$historyFilePath);
|
2021-01-20 15:59:00 +01:00
|
|
|
$this->pluginManager = new PluginManager($this->conf);
|
|
|
|
$this->bookmarkService = new BookmarkFileService(
|
|
|
|
$this->conf,
|
|
|
|
$this->pluginManager,
|
|
|
|
$this->history,
|
|
|
|
$mutex,
|
|
|
|
true
|
|
|
|
);
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
|
2017-01-16 12:31:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete history file.
|
|
|
|
*/
|
2020-09-26 15:08:39 +02:00
|
|
|
protected function tearDown(): void
|
2017-01-16 12:31:08 +01:00
|
|
|
{
|
|
|
|
@unlink(self::$historyFilePath);
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
2020-09-26 15:08:39 +02:00
|
|
|
public static function tearDownAfterClass(): void
|
2016-11-28 16:17:25 +01:00
|
|
|
{
|
|
|
|
date_default_timezone_set(self::$defaultTimeZone);
|
|
|
|
}
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
/**
|
|
|
|
* Attempt to import bookmarks from an empty file
|
|
|
|
*/
|
|
|
|
public function testImportEmptyData()
|
|
|
|
{
|
|
|
|
$files = file2array('empty.htm');
|
|
|
|
$this->assertEquals(
|
|
|
|
'File empty.htm (0 bytes) has an unknown file format.'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' Nothing was imported.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import(null, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(0, $this->bookmarkService->count());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to import bookmarks from a file with no Doctype
|
|
|
|
*/
|
|
|
|
public function testImportNoDoctype()
|
|
|
|
{
|
|
|
|
$files = file2array('no_doctype.htm');
|
|
|
|
$this->assertEquals(
|
|
|
|
'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import(null, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(0, $this->bookmarkService->count());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
2018-02-23 20:34:06 +01:00
|
|
|
/**
|
|
|
|
* Attempt to import bookmarks from a file with a lowercase Doctype
|
|
|
|
*/
|
|
|
|
public function testImportLowecaseDoctype()
|
|
|
|
{
|
|
|
|
$files = file2array('lowercase_doctype.htm');
|
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import(null, $files)
|
2018-02-23 20:34:06 +01:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
2018-02-23 20:34:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-12 23:22:15 +02:00
|
|
|
/**
|
|
|
|
* Ensure IE dumps are supported
|
|
|
|
*/
|
|
|
|
public function testImportInternetExplorerEncoding()
|
|
|
|
{
|
|
|
|
$files = file2array('internet_explorer_encoding.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 1 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import([], $files)
|
2016-08-12 23:22:15 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(1, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
2016-08-12 23:22:15 +02:00
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://hginit.com/');
|
|
|
|
$this->assertEquals(0, $bookmark->getId());
|
2016-08-12 23:22:15 +02:00
|
|
|
$this->assertEquals(
|
2020-01-17 21:34:12 +01:00
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160618_203944'),
|
|
|
|
$bookmark->getCreated()
|
2016-08-12 23:22:15 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals('Hg Init a Mercurial tutorial by Joel Spolsky', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://hginit.com/', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('La37cg', $bookmark->getShortUrl());
|
2016-08-12 23:22:15 +02:00
|
|
|
}
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
/**
|
|
|
|
* Import bookmarks nested in a folder hierarchy
|
|
|
|
*/
|
|
|
|
public function testImportNested()
|
|
|
|
{
|
|
|
|
$files = file2array('netscape_nested.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 8 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import([], $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(8, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1');
|
|
|
|
$this->assertEquals(0, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235541'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 1', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/1', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('tag1 tag2', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('KyDNKA', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1-1');
|
|
|
|
$this->assertEquals(1, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235542'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 1-1', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/1-1', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder1 tag1 tag2', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('T2LnXg', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/1-2');
|
|
|
|
$this->assertEquals(2, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235547'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 1-2', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/1-2', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder1 tag3 tag4', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('46SZxA', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2-1');
|
|
|
|
$this->assertEquals(3, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160202_202222'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 2-1', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/2-1', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('First link of the second section', $bookmark->getDescription());
|
|
|
|
$this->assertTrue($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder2', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('4UHOSw', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2-2');
|
|
|
|
$this->assertEquals(4, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160119_230227'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 2-2', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/2-2', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('Second link of the second section', $bookmark->getDescription());
|
|
|
|
$this->assertTrue($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder2', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('yfzwbw', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/3-1');
|
|
|
|
$this->assertEquals(5, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160202_202222'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 3-1', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/3-1', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder3 folder3-1 tag3', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('UwxIUQ', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/3-2');
|
|
|
|
$this->assertEquals(6, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160119_230227'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 3-2', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/3-2', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('folder3 folder3-1', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('p8dyZg', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://nest.ed/2');
|
|
|
|
$this->assertEquals(7, $bookmark->getId());
|
|
|
|
$this->assertEquals(
|
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160229_111541'),
|
|
|
|
$bookmark->getCreated()
|
|
|
|
);
|
|
|
|
$this->assertEquals('Nested 2', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://nest.ed/2', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('tag4', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('Gt3Uug', $bookmark->getShortUrl());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Import bookmarks with the default privacy setting (reuse from file)
|
|
|
|
*
|
|
|
|
* The $_POST array is not set.
|
|
|
|
*/
|
|
|
|
public function testImportDefaultPrivacyNoPost()
|
|
|
|
{
|
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import([], $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2016-11-28 16:17:25 +01:00
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(1, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
2016-07-28 22:54:33 +02:00
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
$bookmark = $this->bookmarkService->findByUrl('https://private.tld');
|
|
|
|
$this->assertEquals(0, $bookmark->getId());
|
2016-07-28 22:54:33 +02:00
|
|
|
$this->assertEquals(
|
2020-01-17 21:34:12 +01:00
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20001010_135536'),
|
|
|
|
$bookmark->getCreated()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals('Secret stuff', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('https://private.tld', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('Super-secret stuff you\'re not supposed to know about', $bookmark->getDescription());
|
|
|
|
$this->assertTrue($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('private secret', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('EokDtA', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://public.tld');
|
|
|
|
$this->assertEquals(1, $bookmark->getId());
|
2016-07-28 22:54:33 +02:00
|
|
|
$this->assertEquals(
|
2020-01-17 21:34:12 +01:00
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235548'),
|
|
|
|
$bookmark->getCreated()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals('Public stuff', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://public.tld', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('public hello world', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('Er9ddA', $bookmark->getShortUrl());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Import bookmarks with the default privacy setting (reuse from file)
|
|
|
|
*/
|
|
|
|
public function testImportKeepPrivacy()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'default'];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(1, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('https://private.tld');
|
|
|
|
$this->assertEquals(0, $bookmark->getId());
|
2016-07-28 22:54:33 +02:00
|
|
|
$this->assertEquals(
|
2020-01-17 21:34:12 +01:00
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20001010_135536'),
|
|
|
|
$bookmark->getCreated()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals('Secret stuff', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('https://private.tld', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('Super-secret stuff you\'re not supposed to know about', $bookmark->getDescription());
|
|
|
|
$this->assertTrue($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('private secret', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('EokDtA', $bookmark->getShortUrl());
|
|
|
|
|
|
|
|
$bookmark = $this->bookmarkService->findByUrl('http://public.tld');
|
|
|
|
$this->assertEquals(1, $bookmark->getId());
|
2016-07-28 22:54:33 +02:00
|
|
|
$this->assertEquals(
|
2020-01-17 21:34:12 +01:00
|
|
|
DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20160225_235548'),
|
|
|
|
$bookmark->getCreated()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals('Public stuff', $bookmark->getTitle());
|
|
|
|
$this->assertEquals('http://public.tld', $bookmark->getUrl());
|
|
|
|
$this->assertEquals('', $bookmark->getDescription());
|
|
|
|
$this->assertFalse($bookmark->isPrivate());
|
|
|
|
$this->assertEquals('public hello world', $bookmark->getTagsString());
|
|
|
|
$this->assertEquals('Er9ddA', $bookmark->getShortUrl());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* Import bookmarks as public
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
public function testImportAsPublic()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'public'];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertFalse($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertFalse($this->bookmarkService->get(1)->isPrivate());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* Import bookmarks as private
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
public function testImportAsPrivate()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'private'];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertTrue($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertTrue($this->bookmarkService->get(1)->isPrivate());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* Overwrite private bookmarks so they become public
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
public function testOverwriteAsPublic()
|
|
|
|
{
|
|
|
|
$files = file2array('netscape_basic.htm');
|
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
// import bookmarks as private
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'private'];
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertTrue($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertTrue($this->bookmarkService->get(1)->isPrivate());
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
// re-import as public, enable overwriting
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = [
|
2016-07-28 22:54:33 +02:00
|
|
|
'privacy' => 'public',
|
|
|
|
'overwrite' => 'true'
|
2021-04-05 09:39:34 +02:00
|
|
|
];
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertFalse($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertFalse($this->bookmarkService->get(1)->isPrivate());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* Overwrite public bookmarks so they become private
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
public function testOverwriteAsPrivate()
|
|
|
|
{
|
|
|
|
$files = file2array('netscape_basic.htm');
|
|
|
|
|
2020-01-17 21:34:12 +01:00
|
|
|
// import bookmarks as public
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'public'];
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertFalse($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertFalse($this->bookmarkService->get(1)->isPrivate());
|
2016-07-28 22:54:33 +02:00
|
|
|
|
|
|
|
// re-import as private, enable overwriting
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = [
|
2016-07-28 22:54:33 +02:00
|
|
|
'privacy' => 'private',
|
|
|
|
'overwrite' => 'true'
|
2021-04-05 09:39:34 +02:00
|
|
|
];
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 2 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertTrue($this->bookmarkService->get(0)->isPrivate());
|
|
|
|
$this->assertTrue($this->bookmarkService->get(1)->isPrivate());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-17 21:34:12 +01:00
|
|
|
* Attept to import the same bookmarks twice without enabling overwriting
|
2016-07-28 22:54:33 +02:00
|
|
|
*/
|
|
|
|
public function testSkipOverwrite()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'public'];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
2016-07-28 22:54:33 +02:00
|
|
|
|
|
|
|
// re-import as private, DO NOT enable overwriting
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = ['privacy' => 'private'];
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 0 bookmarks imported, 0 bookmarks overwritten, 2 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add user-specified tags to all imported bookmarks
|
|
|
|
*/
|
|
|
|
public function testSetDefaultTags()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = [
|
2016-07-28 22:54:33 +02:00
|
|
|
'privacy' => 'public',
|
2020-10-22 16:21:03 +02:00
|
|
|
'default_tags' => 'tag1 tag2 tag3'
|
2021-04-05 09:39:34 +02:00
|
|
|
];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertEquals('tag1 tag2 tag3 private secret', $this->bookmarkService->get(0)->getTagsString());
|
|
|
|
$this->assertEquals('tag1 tag2 tag3 public hello world', $this->bookmarkService->get(1)->getTagsString());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The user-specified tags contain characters to be escaped
|
|
|
|
*/
|
|
|
|
public function testSanitizeDefaultTags()
|
|
|
|
{
|
2021-04-05 09:39:34 +02:00
|
|
|
$post = [
|
2016-07-28 22:54:33 +02:00
|
|
|
'privacy' => 'public',
|
2020-10-22 16:21:03 +02:00
|
|
|
'default_tags' => 'tag1& tag2 "tag3"'
|
2021-04-05 09:39:34 +02:00
|
|
|
];
|
2016-07-28 22:54:33 +02:00
|
|
|
$files = file2array('netscape_basic.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
2016-07-28 22:54:33 +02:00
|
|
|
$this->assertEquals(
|
|
|
|
'tag1& tag2 "tag3" private secret',
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->bookmarkService->get(0)->getTagsString()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'tag1& tag2 "tag3" public hello world',
|
2020-01-17 21:34:12 +01:00
|
|
|
$this->bookmarkService->get(1)->getTagsString()
|
2016-07-28 22:54:33 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-10-22 16:21:03 +02:00
|
|
|
/**
|
|
|
|
* Add user-specified tags to all imported bookmarks
|
|
|
|
*/
|
|
|
|
public function testSetDefaultTagsWithCustomSeparator()
|
|
|
|
{
|
|
|
|
$separator = '@';
|
|
|
|
$this->conf->set('general.tags_separator', $separator);
|
|
|
|
$post = [
|
|
|
|
'privacy' => 'public',
|
|
|
|
'default_tags' => 'tag1@tag2@tag3@multiple words tag'
|
|
|
|
];
|
|
|
|
$files = file2array('netscape_basic.htm');
|
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
2020-10-22 16:21:03 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files)
|
|
|
|
);
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertEquals(
|
|
|
|
'tag1@tag2@tag3@multiple words tag@private@secret',
|
|
|
|
$this->bookmarkService->get(0)->getTagsString($separator)
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
['tag1', 'tag2', 'tag3', 'multiple words tag', 'private', 'secret'],
|
|
|
|
$this->bookmarkService->get(0)->getTags()
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'tag1@tag2@tag3@multiple words tag@public@hello@world',
|
|
|
|
$this->bookmarkService->get(1)->getTagsString($separator)
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
['tag1', 'tag2', 'tag3', 'multiple words tag', 'public', 'hello', 'world'],
|
|
|
|
$this->bookmarkService->get(1)->getTags()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-07-28 22:54:33 +02:00
|
|
|
/**
|
2016-11-28 16:17:25 +01:00
|
|
|
* Ensure each imported bookmark has a unique id
|
2016-07-28 22:54:33 +02:00
|
|
|
*
|
|
|
|
* See https://github.com/shaarli/Shaarli/issues/351
|
|
|
|
*/
|
|
|
|
public function testImportSameDate()
|
|
|
|
{
|
|
|
|
$files = file2array('same_date.htm');
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertStringMatchesFormat(
|
|
|
|
'File same_date.htm (453 bytes) was successfully processed in %d seconds:'
|
2021-04-05 09:39:34 +02:00
|
|
|
. ' 3 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
|
|
|
|
$this->netscapeBookmarkUtils->import([], $files)
|
2020-01-17 21:34:12 +01:00
|
|
|
);
|
|
|
|
$this->assertEquals(3, $this->bookmarkService->count());
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
|
|
|
$this->assertEquals(0, $this->bookmarkService->get(0)->getId());
|
|
|
|
$this->assertEquals(1, $this->bookmarkService->get(1)->getId());
|
|
|
|
$this->assertEquals(2, $this->bookmarkService->get(2)->getId());
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|
2017-01-16 12:31:08 +01:00
|
|
|
|
|
|
|
public function testImportCreateUpdateHistory()
|
|
|
|
{
|
|
|
|
$post = [
|
|
|
|
'privacy' => 'public',
|
|
|
|
'overwrite' => 'true',
|
|
|
|
];
|
|
|
|
$files = file2array('netscape_basic.htm');
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files);
|
2017-01-16 12:31:08 +01:00
|
|
|
$history = $this->history->getHistory();
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertEquals(1, count($history));
|
|
|
|
$this->assertEquals(History::IMPORT, $history[0]['event']);
|
|
|
|
$this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
|
2017-01-16 12:31:08 +01:00
|
|
|
|
|
|
|
// re-import as private, enable overwriting
|
2020-06-17 15:55:31 +02:00
|
|
|
$this->netscapeBookmarkUtils->import($post, $files);
|
2017-01-16 12:31:08 +01:00
|
|
|
$history = $this->history->getHistory();
|
2017-10-07 16:40:16 +02:00
|
|
|
$this->assertEquals(2, count($history));
|
|
|
|
$this->assertEquals(History::IMPORT, $history[0]['event']);
|
|
|
|
$this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
|
|
|
|
$this->assertEquals(History::IMPORT, $history[1]['event']);
|
|
|
|
$this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']);
|
2017-01-16 12:31:08 +01:00
|
|
|
}
|
2016-07-28 22:54:33 +02:00
|
|
|
}
|