commit
0a47426f88
71 changed files with 2632 additions and 1021 deletions
|
@ -323,6 +323,7 @@ function format_date($date, $time = true, $intl = true)
|
||||||
IntlDateFormatter::LONG,
|
IntlDateFormatter::LONG,
|
||||||
$time ? IntlDateFormatter::LONG : IntlDateFormatter::NONE
|
$time ? IntlDateFormatter::LONG : IntlDateFormatter::NONE
|
||||||
);
|
);
|
||||||
|
$formatter->setTimeZone($date->getTimezone());
|
||||||
|
|
||||||
return $formatter->format($date);
|
return $formatter->format($date);
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,7 @@ protected function setLinkDb($conf)
|
||||||
{
|
{
|
||||||
$linkDb = new BookmarkFileService(
|
$linkDb = new BookmarkFileService(
|
||||||
$conf,
|
$conf,
|
||||||
|
$this->container->get('pluginManager'),
|
||||||
$this->container->get('history'),
|
$this->container->get('history'),
|
||||||
new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
|
new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
|
||||||
true
|
true
|
||||||
|
|
|
@ -36,13 +36,6 @@ class Links extends ApiController
|
||||||
public function getLinks($request, $response)
|
public function getLinks($request, $response)
|
||||||
{
|
{
|
||||||
$private = $request->getParam('visibility');
|
$private = $request->getParam('visibility');
|
||||||
$bookmarks = $this->bookmarkService->search(
|
|
||||||
[
|
|
||||||
'searchtags' => $request->getParam('searchtags', ''),
|
|
||||||
'searchterm' => $request->getParam('searchterm', ''),
|
|
||||||
],
|
|
||||||
$private
|
|
||||||
);
|
|
||||||
|
|
||||||
// Return bookmarks from the {offset}th link, starting from 0.
|
// Return bookmarks from the {offset}th link, starting from 0.
|
||||||
$offset = $request->getParam('offset');
|
$offset = $request->getParam('offset');
|
||||||
|
@ -50,9 +43,6 @@ public function getLinks($request, $response)
|
||||||
throw new ApiBadParametersException('Invalid offset');
|
throw new ApiBadParametersException('Invalid offset');
|
||||||
}
|
}
|
||||||
$offset = ! empty($offset) ? intval($offset) : 0;
|
$offset = ! empty($offset) ? intval($offset) : 0;
|
||||||
if ($offset > count($bookmarks)) {
|
|
||||||
return $response->withJson([], 200, $this->jsonStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// limit parameter is either a number of bookmarks or 'all' for everything.
|
// limit parameter is either a number of bookmarks or 'all' for everything.
|
||||||
$limit = $request->getParam('limit');
|
$limit = $request->getParam('limit');
|
||||||
|
@ -61,23 +51,33 @@ public function getLinks($request, $response)
|
||||||
} elseif (ctype_digit($limit)) {
|
} elseif (ctype_digit($limit)) {
|
||||||
$limit = intval($limit);
|
$limit = intval($limit);
|
||||||
} elseif ($limit === 'all') {
|
} elseif ($limit === 'all') {
|
||||||
$limit = count($bookmarks);
|
$limit = null;
|
||||||
} else {
|
} else {
|
||||||
throw new ApiBadParametersException('Invalid limit');
|
throw new ApiBadParametersException('Invalid limit');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$searchResult = $this->bookmarkService->search(
|
||||||
|
[
|
||||||
|
'searchtags' => $request->getParam('searchtags', ''),
|
||||||
|
'searchterm' => $request->getParam('searchterm', ''),
|
||||||
|
],
|
||||||
|
$private,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
'limit' => $limit,
|
||||||
|
'offset' => $offset,
|
||||||
|
'allowOutOfBounds' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
// 'environment' is set by Slim and encapsulate $_SERVER.
|
// 'environment' is set by Slim and encapsulate $_SERVER.
|
||||||
$indexUrl = index_url($this->ci['environment']);
|
$indexUrl = index_url($this->ci['environment']);
|
||||||
|
|
||||||
$out = [];
|
$out = [];
|
||||||
$index = 0;
|
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||||
foreach ($bookmarks as $bookmark) {
|
$out[] = ApiUtils::formatLink($bookmark, $indexUrl);
|
||||||
if (count($out) >= $limit) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($index++ >= $offset) {
|
|
||||||
$out[] = ApiUtils::formatLink($bookmark, $indexUrl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->withJson($out, 200, $this->jsonStyle);
|
return $response->withJson($out, 200, $this->jsonStyle);
|
||||||
|
|
|
@ -122,12 +122,12 @@ public function putTag($request, $response, $args)
|
||||||
throw new ApiBadParametersException('New tag name is required in the request body');
|
throw new ApiBadParametersException('New tag name is required in the request body');
|
||||||
}
|
}
|
||||||
|
|
||||||
$bookmarks = $this->bookmarkService->search(
|
$searchResult = $this->bookmarkService->search(
|
||||||
['searchtags' => $args['tagName']],
|
['searchtags' => $args['tagName']],
|
||||||
BookmarkFilter::$ALL,
|
BookmarkFilter::$ALL,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
foreach ($bookmarks as $bookmark) {
|
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||||
$bookmark->renameTag($args['tagName'], $data['name']);
|
$bookmark->renameTag($args['tagName'], $data['name']);
|
||||||
$this->bookmarkService->set($bookmark, false);
|
$this->bookmarkService->set($bookmark, false);
|
||||||
$this->history->updateLink($bookmark);
|
$this->history->updateLink($bookmark);
|
||||||
|
@ -157,12 +157,12 @@ public function deleteTag($request, $response, $args)
|
||||||
throw new ApiTagNotFoundException();
|
throw new ApiTagNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
$bookmarks = $this->bookmarkService->search(
|
$searchResult = $this->bookmarkService->search(
|
||||||
['searchtags' => $args['tagName']],
|
['searchtags' => $args['tagName']],
|
||||||
BookmarkFilter::$ALL,
|
BookmarkFilter::$ALL,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
foreach ($bookmarks as $bookmark) {
|
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||||
$bookmark->deleteTag($args['tagName']);
|
$bookmark->deleteTag($args['tagName']);
|
||||||
$this->bookmarkService->set($bookmark, false);
|
$this->bookmarkService->set($bookmark, false);
|
||||||
$this->history->updateLink($bookmark);
|
$this->history->updateLink($bookmark);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
use Shaarli\Legacy\LegacyLinkDB;
|
use Shaarli\Legacy\LegacyLinkDB;
|
||||||
use Shaarli\Legacy\LegacyUpdater;
|
use Shaarli\Legacy\LegacyUpdater;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\Render\PageCacheManager;
|
use Shaarli\Render\PageCacheManager;
|
||||||
use Shaarli\Updater\UpdaterUtils;
|
use Shaarli\Updater\UpdaterUtils;
|
||||||
|
|
||||||
|
@ -40,6 +41,9 @@ class BookmarkFileService implements BookmarkServiceInterface
|
||||||
/** @var ConfigManager instance */
|
/** @var ConfigManager instance */
|
||||||
protected $conf;
|
protected $conf;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/** @var History instance */
|
/** @var History instance */
|
||||||
protected $history;
|
protected $history;
|
||||||
|
|
||||||
|
@ -55,8 +59,13 @@ class BookmarkFileService implements BookmarkServiceInterface
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn)
|
public function __construct(
|
||||||
{
|
ConfigManager $conf,
|
||||||
|
PluginManager $pluginManager,
|
||||||
|
History $history,
|
||||||
|
Mutex $mutex,
|
||||||
|
bool $isLoggedIn
|
||||||
|
) {
|
||||||
$this->conf = $conf;
|
$this->conf = $conf;
|
||||||
$this->history = $history;
|
$this->history = $history;
|
||||||
$this->mutex = $mutex;
|
$this->mutex = $mutex;
|
||||||
|
@ -65,7 +74,7 @@ public function __construct(ConfigManager $conf, History $history, Mutex $mutex,
|
||||||
$this->isLoggedIn = $isLoggedIn;
|
$this->isLoggedIn = $isLoggedIn;
|
||||||
|
|
||||||
if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) {
|
if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) {
|
||||||
$this->bookmarks = [];
|
$this->bookmarks = new BookmarkArray();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$this->bookmarks = $this->bookmarksIO->read();
|
$this->bookmarks = $this->bookmarksIO->read();
|
||||||
|
@ -91,7 +100,8 @@ public function __construct(ConfigManager $conf, History $history, Mutex $mutex,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf);
|
$this->pluginManager = $pluginManager;
|
||||||
|
$this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf, $this->pluginManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,8 +139,9 @@ public function search(
|
||||||
string $visibility = null,
|
string $visibility = null,
|
||||||
bool $caseSensitive = false,
|
bool $caseSensitive = false,
|
||||||
bool $untaggedOnly = false,
|
bool $untaggedOnly = false,
|
||||||
bool $ignoreSticky = false
|
bool $ignoreSticky = false,
|
||||||
) {
|
array $pagination = []
|
||||||
|
): SearchResult {
|
||||||
if ($visibility === null) {
|
if ($visibility === null) {
|
||||||
$visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
|
$visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
|
||||||
}
|
}
|
||||||
|
@ -143,13 +154,20 @@ public function search(
|
||||||
$this->bookmarks->reorder('DESC', true);
|
$this->bookmarks->reorder('DESC', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->bookmarkFilter->filter(
|
$bookmarks = $this->bookmarkFilter->filter(
|
||||||
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
|
||||||
[$searchTags, $searchTerm],
|
[$searchTags, $searchTerm],
|
||||||
$caseSensitive,
|
$caseSensitive,
|
||||||
$visibility,
|
$visibility,
|
||||||
$untaggedOnly
|
$untaggedOnly
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return SearchResult::getSearchResult(
|
||||||
|
$bookmarks,
|
||||||
|
$pagination['offset'] ?? 0,
|
||||||
|
$pagination['limit'] ?? null,
|
||||||
|
$pagination['allowOutOfBounds'] ?? false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -282,7 +300,7 @@ public function exists(int $id, string $visibility = null): bool
|
||||||
*/
|
*/
|
||||||
public function count(string $visibility = null): int
|
public function count(string $visibility = null): int
|
||||||
{
|
{
|
||||||
return count($this->search([], $visibility));
|
return $this->search([], $visibility)->getResultCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,10 +323,10 @@ public function save(): void
|
||||||
*/
|
*/
|
||||||
public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array
|
public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array
|
||||||
{
|
{
|
||||||
$bookmarks = $this->search(['searchtags' => $filteringTags], $visibility);
|
$searchResult = $this->search(['searchtags' => $filteringTags], $visibility);
|
||||||
$tags = [];
|
$tags = [];
|
||||||
$caseMapping = [];
|
$caseMapping = [];
|
||||||
foreach ($bookmarks as $bookmark) {
|
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||||
foreach ($bookmark->getTags() as $tag) {
|
foreach ($bookmark->getTags() as $tag) {
|
||||||
if (
|
if (
|
||||||
empty($tag)
|
empty($tag)
|
||||||
|
@ -357,7 +375,7 @@ public function findByDate(
|
||||||
$previous = null;
|
$previous = null;
|
||||||
$next = null;
|
$next = null;
|
||||||
|
|
||||||
foreach ($this->search([], null, false, false, true) as $bookmark) {
|
foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
|
||||||
if ($to < $bookmark->getCreated()) {
|
if ($to < $bookmark->getCreated()) {
|
||||||
$next = $bookmark->getCreated();
|
$next = $bookmark->getCreated();
|
||||||
} elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) {
|
} elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) {
|
||||||
|
@ -378,7 +396,7 @@ public function findByDate(
|
||||||
*/
|
*/
|
||||||
public function getLatest(): ?Bookmark
|
public function getLatest(): ?Bookmark
|
||||||
{
|
{
|
||||||
foreach ($this->search([], null, false, false, true) as $bookmark) {
|
foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) {
|
||||||
return $bookmark;
|
return $bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
namespace Shaarli\Bookmark;
|
namespace Shaarli\Bookmark;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LinkFilter.
|
* Class LinkFilter.
|
||||||
|
@ -30,11 +30,6 @@ class BookmarkFilter
|
||||||
*/
|
*/
|
||||||
public static $FILTER_TAG = 'tags';
|
public static $FILTER_TAG = 'tags';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string filter by day.
|
|
||||||
*/
|
|
||||||
public static $FILTER_DAY = 'FILTER_DAY';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string filter by day.
|
* @var string filter by day.
|
||||||
*/
|
*/
|
||||||
|
@ -62,13 +57,17 @@ class BookmarkFilter
|
||||||
/** @var ConfigManager */
|
/** @var ConfigManager */
|
||||||
protected $conf;
|
protected $conf;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Bookmark[] $bookmarks initialization.
|
* @param Bookmark[] $bookmarks initialization.
|
||||||
*/
|
*/
|
||||||
public function __construct($bookmarks, ConfigManager $conf)
|
public function __construct($bookmarks, ConfigManager $conf, PluginManager $pluginManager)
|
||||||
{
|
{
|
||||||
$this->bookmarks = $bookmarks;
|
$this->bookmarks = $bookmarks;
|
||||||
$this->conf = $conf;
|
$this->conf = $conf;
|
||||||
|
$this->pluginManager = $pluginManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,12 +111,12 @@ public function filter(
|
||||||
$filtered = $this->bookmarks;
|
$filtered = $this->bookmarks;
|
||||||
}
|
}
|
||||||
if (!empty($request[0])) {
|
if (!empty($request[0])) {
|
||||||
$filtered = (new BookmarkFilter($filtered, $this->conf))
|
$filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager))
|
||||||
->filterTags($request[0], $casesensitive, $visibility)
|
->filterTags($request[0], $casesensitive, $visibility)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
if (!empty($request[1])) {
|
if (!empty($request[1])) {
|
||||||
$filtered = (new BookmarkFilter($filtered, $this->conf))
|
$filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager))
|
||||||
->filterFulltext($request[1], $visibility)
|
->filterFulltext($request[1], $visibility)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -130,8 +129,6 @@ public function filter(
|
||||||
} else {
|
} else {
|
||||||
return $this->filterTags($request, $casesensitive, $visibility);
|
return $this->filterTags($request, $casesensitive, $visibility);
|
||||||
}
|
}
|
||||||
case self::$FILTER_DAY:
|
|
||||||
return $this->filterDay($request, $visibility);
|
|
||||||
default:
|
default:
|
||||||
return $this->noFilter($visibility);
|
return $this->noFilter($visibility);
|
||||||
}
|
}
|
||||||
|
@ -146,13 +143,20 @@ public function filter(
|
||||||
*/
|
*/
|
||||||
private function noFilter(string $visibility = 'all')
|
private function noFilter(string $visibility = 'all')
|
||||||
{
|
{
|
||||||
if ($visibility === 'all') {
|
|
||||||
return $this->bookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
$out = [];
|
$out = [];
|
||||||
foreach ($this->bookmarks as $key => $value) {
|
foreach ($this->bookmarks as $key => $value) {
|
||||||
if ($value->isPrivate() && $visibility === 'private') {
|
if (
|
||||||
|
!$this->pluginManager->filterSearchEntry(
|
||||||
|
$value,
|
||||||
|
['source' => 'no_filter', 'visibility' => $visibility]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($visibility === 'all') {
|
||||||
|
$out[$key] = $value;
|
||||||
|
} elseif ($value->isPrivate() && $visibility === 'private') {
|
||||||
$out[$key] = $value;
|
$out[$key] = $value;
|
||||||
} elseif (!$value->isPrivate() && $visibility === 'public') {
|
} elseif (!$value->isPrivate() && $visibility === 'public') {
|
||||||
$out[$key] = $value;
|
$out[$key] = $value;
|
||||||
|
@ -233,18 +237,34 @@ private function filterFulltext(string $searchterms, string $visibility = 'all')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over every stored link.
|
// Iterate over every stored link.
|
||||||
foreach ($this->bookmarks as $id => $link) {
|
foreach ($this->bookmarks as $id => $bookmark) {
|
||||||
|
if (
|
||||||
|
!$this->pluginManager->filterSearchEntry(
|
||||||
|
$bookmark,
|
||||||
|
[
|
||||||
|
'source' => 'fulltext',
|
||||||
|
'searchterms' => $searchterms,
|
||||||
|
'andSearch' => $andSearch,
|
||||||
|
'exactSearch' => $exactSearch,
|
||||||
|
'excludeSearch' => $excludeSearch,
|
||||||
|
'visibility' => $visibility
|
||||||
|
]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore non private bookmarks when 'privatonly' is on.
|
// ignore non private bookmarks when 'privatonly' is on.
|
||||||
if ($visibility !== 'all') {
|
if ($visibility !== 'all') {
|
||||||
if (!$link->isPrivate() && $visibility === 'private') {
|
if (!$bookmark->isPrivate() && $visibility === 'private') {
|
||||||
continue;
|
continue;
|
||||||
} elseif ($link->isPrivate() && $visibility === 'public') {
|
} elseif ($bookmark->isPrivate() && $visibility === 'public') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$lengths = [];
|
$lengths = [];
|
||||||
$content = $this->buildFullTextSearchableLink($link, $lengths);
|
$content = $this->buildFullTextSearchableLink($bookmark, $lengths);
|
||||||
|
|
||||||
// Be optimistic
|
// Be optimistic
|
||||||
$found = true;
|
$found = true;
|
||||||
|
@ -270,68 +290,18 @@ private function filterFulltext(string $searchterms, string $visibility = 'all')
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($found !== false) {
|
if ($found !== false) {
|
||||||
$link->addAdditionalContentEntry(
|
$bookmark->addAdditionalContentEntry(
|
||||||
'search_highlight',
|
'search_highlight',
|
||||||
$this->postProcessFoundPositions($lengths, $foundPositions)
|
$this->postProcessFoundPositions($lengths, $foundPositions)
|
||||||
);
|
);
|
||||||
|
|
||||||
$filtered[$id] = $link;
|
$filtered[$id] = $bookmark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $filtered;
|
return $filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* generate a regex fragment out of a tag
|
|
||||||
*
|
|
||||||
* @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard
|
|
||||||
*
|
|
||||||
* @return string generated regex fragment
|
|
||||||
*/
|
|
||||||
protected function tag2regex(string $tag): string
|
|
||||||
{
|
|
||||||
$tagsSeparator = $this->conf->get('general.tags_separator', ' ');
|
|
||||||
$len = strlen($tag);
|
|
||||||
if (!$len || $tag === "-" || $tag === "*") {
|
|
||||||
// nothing to search, return empty regex
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
if ($tag[0] === "-") {
|
|
||||||
// query is negated
|
|
||||||
$i = 1; // use offset to start after '-' character
|
|
||||||
$regex = '(?!'; // create negative lookahead
|
|
||||||
} else {
|
|
||||||
$i = 0; // start at first character
|
|
||||||
$regex = '(?='; // use positive lookahead
|
|
||||||
}
|
|
||||||
// before tag may only be the separator or the beginning
|
|
||||||
$regex .= '.*(?:^|' . $tagsSeparator . ')';
|
|
||||||
// iterate over string, separating it into placeholder and content
|
|
||||||
for (; $i < $len; $i++) {
|
|
||||||
if ($tag[$i] === '*') {
|
|
||||||
// placeholder found
|
|
||||||
$regex .= '[^' . $tagsSeparator . ']*?';
|
|
||||||
} else {
|
|
||||||
// regular characters
|
|
||||||
$offset = strpos($tag, '*', $i);
|
|
||||||
if ($offset === false) {
|
|
||||||
// no placeholder found, set offset to end of string
|
|
||||||
$offset = $len;
|
|
||||||
}
|
|
||||||
// subtract one, as we want to get before the placeholder or end of string
|
|
||||||
$offset -= 1;
|
|
||||||
// we got a tag name that we want to search for. escape any regex characters to prevent conflicts.
|
|
||||||
$regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/');
|
|
||||||
// move $i on
|
|
||||||
$i = $offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// after the tag may only be the separator or the end
|
|
||||||
$regex .= '(?:$|' . $tagsSeparator . '))';
|
|
||||||
return $regex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of bookmarks associated with a given list of tags
|
* Returns the list of bookmarks associated with a given list of tags
|
||||||
*
|
*
|
||||||
|
@ -381,25 +351,39 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit
|
||||||
$filtered = [];
|
$filtered = [];
|
||||||
|
|
||||||
// iterate over each link
|
// iterate over each link
|
||||||
foreach ($this->bookmarks as $key => $link) {
|
foreach ($this->bookmarks as $key => $bookmark) {
|
||||||
|
if (
|
||||||
|
!$this->pluginManager->filterSearchEntry(
|
||||||
|
$bookmark,
|
||||||
|
[
|
||||||
|
'source' => 'tags',
|
||||||
|
'tags' => $tags,
|
||||||
|
'casesensitive' => $casesensitive,
|
||||||
|
'visibility' => $visibility
|
||||||
|
]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// check level of visibility
|
// check level of visibility
|
||||||
// ignore non private bookmarks when 'privateonly' is on.
|
// ignore non private bookmarks when 'privateonly' is on.
|
||||||
if ($visibility !== 'all') {
|
if ($visibility !== 'all') {
|
||||||
if (!$link->isPrivate() && $visibility === 'private') {
|
if (!$bookmark->isPrivate() && $visibility === 'private') {
|
||||||
continue;
|
continue;
|
||||||
} elseif ($link->isPrivate() && $visibility === 'public') {
|
} elseif ($bookmark->isPrivate() && $visibility === 'public') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// build search string, start with tags of current link
|
// build search string, start with tags of current link
|
||||||
$search = $link->getTagsString($tagsSeparator);
|
$search = $bookmark->getTagsString($tagsSeparator);
|
||||||
if (strlen(trim($link->getDescription())) && strpos($link->getDescription(), '#') !== false) {
|
if (strlen(trim($bookmark->getDescription())) && strpos($bookmark->getDescription(), '#') !== false) {
|
||||||
// description given and at least one possible tag found
|
// description given and at least one possible tag found
|
||||||
$descTags = [];
|
$descTags = [];
|
||||||
// find all tags in the form of #tag in the description
|
// find all tags in the form of #tag in the description
|
||||||
preg_match_all(
|
preg_match_all(
|
||||||
'/(?<![' . self::$HASHTAG_CHARS . '])#([' . self::$HASHTAG_CHARS . ']+?)\b/sm',
|
'/(?<![' . self::$HASHTAG_CHARS . '])#([' . self::$HASHTAG_CHARS . ']+?)\b/sm',
|
||||||
$link->getDescription(),
|
$bookmark->getDescription(),
|
||||||
$descTags
|
$descTags
|
||||||
);
|
);
|
||||||
if (count($descTags[1])) {
|
if (count($descTags[1])) {
|
||||||
|
@ -412,8 +396,9 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit
|
||||||
// this entry does _not_ match our regex
|
// this entry does _not_ match our regex
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$filtered[$key] = $link;
|
$filtered[$key] = $bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $filtered;
|
return $filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,55 +412,30 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit
|
||||||
public function filterUntagged(string $visibility)
|
public function filterUntagged(string $visibility)
|
||||||
{
|
{
|
||||||
$filtered = [];
|
$filtered = [];
|
||||||
foreach ($this->bookmarks as $key => $link) {
|
foreach ($this->bookmarks as $key => $bookmark) {
|
||||||
|
if (
|
||||||
|
!$this->pluginManager->filterSearchEntry(
|
||||||
|
$bookmark,
|
||||||
|
['source' => 'untagged', 'visibility' => $visibility]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($visibility !== 'all') {
|
if ($visibility !== 'all') {
|
||||||
if (!$link->isPrivate() && $visibility === 'private') {
|
if (!$bookmark->isPrivate() && $visibility === 'private') {
|
||||||
continue;
|
continue;
|
||||||
} elseif ($link->isPrivate() && $visibility === 'public') {
|
} elseif ($bookmark->isPrivate() && $visibility === 'public') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($link->getTags())) {
|
if (empty($bookmark->getTags())) {
|
||||||
$filtered[$key] = $link;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $filtered;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of articles for a given day, chronologically sorted
|
|
||||||
*
|
|
||||||
* Day must be in the form 'YYYYMMDD' (e.g. '20120125'), e.g.
|
|
||||||
* print_r($mydb->filterDay('20120125'));
|
|
||||||
*
|
|
||||||
* @param string $day day to filter.
|
|
||||||
* @param string $visibility return only all/private/public bookmarks.
|
|
||||||
|
|
||||||
* @return Bookmark[] all link matching given day.
|
|
||||||
*
|
|
||||||
* @throws Exception if date format is invalid.
|
|
||||||
*/
|
|
||||||
public function filterDay(string $day, string $visibility)
|
|
||||||
{
|
|
||||||
if (!checkDateFormat('Ymd', $day)) {
|
|
||||||
throw new Exception('Invalid date format');
|
|
||||||
}
|
|
||||||
|
|
||||||
$filtered = [];
|
|
||||||
foreach ($this->bookmarks as $key => $bookmark) {
|
|
||||||
if ($visibility === static::$PUBLIC && $bookmark->isPrivate()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($bookmark->getCreated()->format('Ymd') == $day) {
|
|
||||||
$filtered[$key] = $bookmark;
|
$filtered[$key] = $bookmark;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by date ASC
|
return $filtered;
|
||||||
return array_reverse($filtered, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -497,6 +457,56 @@ public static function tagsStrToArray(string $tags, bool $casesensitive): array
|
||||||
return preg_split('/\s+/', $tagsOut, -1, PREG_SPLIT_NO_EMPTY);
|
return preg_split('/\s+/', $tagsOut, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a regex fragment out of a tag
|
||||||
|
*
|
||||||
|
* @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard
|
||||||
|
*
|
||||||
|
* @return string generated regex fragment
|
||||||
|
*/
|
||||||
|
protected function tag2regex(string $tag): string
|
||||||
|
{
|
||||||
|
$tagsSeparator = $this->conf->get('general.tags_separator', ' ');
|
||||||
|
$len = strlen($tag);
|
||||||
|
if (!$len || $tag === "-" || $tag === "*") {
|
||||||
|
// nothing to search, return empty regex
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if ($tag[0] === "-") {
|
||||||
|
// query is negated
|
||||||
|
$i = 1; // use offset to start after '-' character
|
||||||
|
$regex = '(?!'; // create negative lookahead
|
||||||
|
} else {
|
||||||
|
$i = 0; // start at first character
|
||||||
|
$regex = '(?='; // use positive lookahead
|
||||||
|
}
|
||||||
|
// before tag may only be the separator or the beginning
|
||||||
|
$regex .= '.*(?:^|' . $tagsSeparator . ')';
|
||||||
|
// iterate over string, separating it into placeholder and content
|
||||||
|
for (; $i < $len; $i++) {
|
||||||
|
if ($tag[$i] === '*') {
|
||||||
|
// placeholder found
|
||||||
|
$regex .= '[^' . $tagsSeparator . ']*?';
|
||||||
|
} else {
|
||||||
|
// regular characters
|
||||||
|
$offset = strpos($tag, '*', $i);
|
||||||
|
if ($offset === false) {
|
||||||
|
// no placeholder found, set offset to end of string
|
||||||
|
$offset = $len;
|
||||||
|
}
|
||||||
|
// subtract one, as we want to get before the placeholder or end of string
|
||||||
|
$offset -= 1;
|
||||||
|
// we got a tag name that we want to search for. escape any regex characters to prevent conflicts.
|
||||||
|
$regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/');
|
||||||
|
// move $i on
|
||||||
|
$i = $offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// after the tag may only be the separator or the end
|
||||||
|
$regex .= '(?:$|' . $tagsSeparator . '))';
|
||||||
|
return $regex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method finalize the content of the foundPositions array,
|
* This method finalize the content of the foundPositions array,
|
||||||
* by associated all search results to their associated bookmark field,
|
* by associated all search results to their associated bookmark field,
|
||||||
|
|
|
@ -44,16 +44,18 @@ public function findByUrl(string $url): ?Bookmark;
|
||||||
* @param bool $caseSensitive
|
* @param bool $caseSensitive
|
||||||
* @param bool $untaggedOnly
|
* @param bool $untaggedOnly
|
||||||
* @param bool $ignoreSticky
|
* @param bool $ignoreSticky
|
||||||
|
* @param array $pagination This array can contain the following keys for pagination: limit, offset.
|
||||||
*
|
*
|
||||||
* @return Bookmark[]
|
* @return SearchResult
|
||||||
*/
|
*/
|
||||||
public function search(
|
public function search(
|
||||||
array $request = [],
|
array $request = [],
|
||||||
string $visibility = null,
|
string $visibility = null,
|
||||||
bool $caseSensitive = false,
|
bool $caseSensitive = false,
|
||||||
bool $untaggedOnly = false,
|
bool $untaggedOnly = false,
|
||||||
bool $ignoreSticky = false
|
bool $ignoreSticky = false,
|
||||||
);
|
array $pagination = []
|
||||||
|
): SearchResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a single bookmark by its ID.
|
* Get a single bookmark by its ID.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
|
use Shaarli\Formatter\BookmarkDefaultFormatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract title from an HTML document.
|
* Extract title from an HTML document.
|
||||||
|
@ -98,7 +99,18 @@ function html_extract_tag($tag, $html)
|
||||||
function text2clickable($text)
|
function text2clickable($text)
|
||||||
{
|
{
|
||||||
$regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[a-z0-9\(\)]/?)!si';
|
$regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[a-z0-9\(\)]/?)!si';
|
||||||
return preg_replace($regex, '<a href="$1">$1</a>', $text);
|
$format = function (array $match): string {
|
||||||
|
return '<a href="' .
|
||||||
|
str_replace(
|
||||||
|
BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN,
|
||||||
|
'',
|
||||||
|
str_replace(BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE, '', $match[1])
|
||||||
|
) .
|
||||||
|
'">' . $match[1] . '</a>'
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
return preg_replace_callback($regex, $format, $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,6 +123,9 @@ function text2clickable($text)
|
||||||
*/
|
*/
|
||||||
function hashtag_autolink($description, $indexUrl = '')
|
function hashtag_autolink($description, $indexUrl = '')
|
||||||
{
|
{
|
||||||
|
$tokens = '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN . ')' .
|
||||||
|
'(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE . ')'
|
||||||
|
;
|
||||||
/*
|
/*
|
||||||
* To support unicode: http://stackoverflow.com/a/35498078/1484919
|
* To support unicode: http://stackoverflow.com/a/35498078/1484919
|
||||||
* \p{Pc} - to match underscore
|
* \p{Pc} - to match underscore
|
||||||
|
@ -118,9 +133,20 @@ function hashtag_autolink($description, $indexUrl = '')
|
||||||
* \p{L} - letter from any language
|
* \p{L} - letter from any language
|
||||||
* \p{Mn} - any non marking space (accents, umlauts, etc)
|
* \p{Mn} - any non marking space (accents, umlauts, etc)
|
||||||
*/
|
*/
|
||||||
$regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui';
|
$regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}' . $tokens . ']+)/mui';
|
||||||
$replacement = '$1<a href="' . $indexUrl . './add-tag/$2" title="Hashtag $2">#$2</a>';
|
$format = function (array $match) use ($indexUrl): string {
|
||||||
return preg_replace($regex, $replacement, $description);
|
$cleanMatch = str_replace(
|
||||||
|
BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN,
|
||||||
|
'',
|
||||||
|
str_replace(BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE, '', $match[2])
|
||||||
|
);
|
||||||
|
return $match[1] . '<a href="' . $indexUrl . './add-tag/' . $cleanMatch . '"' .
|
||||||
|
' title="Hashtag ' . $cleanMatch . '">' .
|
||||||
|
'#' . $match[2] .
|
||||||
|
'</a>';
|
||||||
|
};
|
||||||
|
|
||||||
|
return preg_replace_callback($regex, $format, $description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
136
application/bookmark/SearchResult.php
Normal file
136
application/bookmark/SearchResult.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shaarli\Bookmark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read-only class used to represent search result, including pagination.
|
||||||
|
*/
|
||||||
|
class SearchResult
|
||||||
|
{
|
||||||
|
/** @var Bookmark[] List of result bookmarks with pagination applied */
|
||||||
|
protected $bookmarks;
|
||||||
|
|
||||||
|
/** @var int number of Bookmarks found, with pagination applied */
|
||||||
|
protected $resultCount;
|
||||||
|
|
||||||
|
/** @var int total number of result found */
|
||||||
|
protected $totalCount;
|
||||||
|
|
||||||
|
/** @var int pagination: limit number of result bookmarks */
|
||||||
|
protected $limit;
|
||||||
|
|
||||||
|
/** @var int pagination: offset to apply to complete result list */
|
||||||
|
protected $offset;
|
||||||
|
|
||||||
|
public function __construct(array $bookmarks, int $totalCount, int $offset, ?int $limit)
|
||||||
|
{
|
||||||
|
$this->bookmarks = $bookmarks;
|
||||||
|
$this->resultCount = count($bookmarks);
|
||||||
|
$this->totalCount = $totalCount;
|
||||||
|
$this->limit = $limit;
|
||||||
|
$this->offset = $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a SearchResult from provided full result set and pagination settings.
|
||||||
|
*
|
||||||
|
* @param Bookmark[] $bookmarks Full set of result which will be filtered
|
||||||
|
* @param int $offset Start recording results from $offset
|
||||||
|
* @param int|null $limit End recording results after $limit bookmarks is reached
|
||||||
|
* @param bool $allowOutOfBounds Set to false to display the last page if the offset is out of bound,
|
||||||
|
* return empty result set otherwise (default: false)
|
||||||
|
*
|
||||||
|
* @return SearchResult
|
||||||
|
*/
|
||||||
|
public static function getSearchResult(
|
||||||
|
$bookmarks,
|
||||||
|
int $offset = 0,
|
||||||
|
?int $limit = null,
|
||||||
|
bool $allowOutOfBounds = false
|
||||||
|
): self {
|
||||||
|
$totalCount = count($bookmarks);
|
||||||
|
if (!$allowOutOfBounds && $offset > $totalCount) {
|
||||||
|
$offset = $limit === null ? 0 : $limit * -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bookmarks instanceof BookmarkArray) {
|
||||||
|
$buffer = [];
|
||||||
|
foreach ($bookmarks as $key => $value) {
|
||||||
|
$buffer[$key] = $value;
|
||||||
|
}
|
||||||
|
$bookmarks = $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static(
|
||||||
|
array_slice($bookmarks, $offset, $limit, true),
|
||||||
|
$totalCount,
|
||||||
|
$offset,
|
||||||
|
$limit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return Bookmark[] List of result bookmarks with pagination applied */
|
||||||
|
public function getBookmarks(): array
|
||||||
|
{
|
||||||
|
return $this->bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int number of Bookmarks found, with pagination applied */
|
||||||
|
public function getResultCount(): int
|
||||||
|
{
|
||||||
|
return $this->resultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int total number of result found */
|
||||||
|
public function getTotalCount(): int
|
||||||
|
{
|
||||||
|
return $this->totalCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int pagination: limit number of result bookmarks */
|
||||||
|
public function getLimit(): ?int
|
||||||
|
{
|
||||||
|
return $this->limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int pagination: offset to apply to complete result list */
|
||||||
|
public function getOffset(): int
|
||||||
|
{
|
||||||
|
return $this->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int Current page of result set in complete results */
|
||||||
|
public function getPage(): int
|
||||||
|
{
|
||||||
|
if (empty($this->limit)) {
|
||||||
|
return $this->offset === 0 ? 1 : 2;
|
||||||
|
}
|
||||||
|
$base = $this->offset >= 0 ? $this->offset : $this->totalCount + $this->offset;
|
||||||
|
|
||||||
|
return (int) ceil($base / $this->limit) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return int Get the # of the last page */
|
||||||
|
public function getLastPage(): int
|
||||||
|
{
|
||||||
|
if (empty($this->limit)) {
|
||||||
|
return $this->offset === 0 ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) ceil($this->totalCount / $this->limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return bool Either the current page is the last one or not */
|
||||||
|
public function isLastPage(): bool
|
||||||
|
{
|
||||||
|
return $this->getPage() === $this->getLastPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return bool Either the current page is the first one or not */
|
||||||
|
public function isFirstPage(): bool
|
||||||
|
{
|
||||||
|
return $this->offset === 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,6 +95,7 @@ public function build(): ShaarliContainer
|
||||||
$container['bookmarkService'] = function (ShaarliContainer $container): BookmarkServiceInterface {
|
$container['bookmarkService'] = function (ShaarliContainer $container): BookmarkServiceInterface {
|
||||||
return new BookmarkFileService(
|
return new BookmarkFileService(
|
||||||
$container->conf,
|
$container->conf,
|
||||||
|
$container->pluginManager,
|
||||||
$container->history,
|
$container->history,
|
||||||
new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
|
new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
|
||||||
$container->loginManager->isLoggedIn()
|
$container->loginManager->isLoggedIn()
|
||||||
|
|
|
@ -102,22 +102,16 @@ public function buildData(string $feedType, ?array $userInput)
|
||||||
$userInput['searchtags'] = false;
|
$userInput['searchtags'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$limit = $this->getLimit($userInput);
|
||||||
|
|
||||||
// Optionally filter the results:
|
// Optionally filter the results:
|
||||||
$linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true);
|
$searchResult = $this->linkDB->search($userInput ?? [], null, false, false, true, ['limit' => $limit]);
|
||||||
|
|
||||||
$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);
|
|
||||||
|
|
||||||
// Can't use array_keys() because $link is a LinkDB instance and not a real array.
|
|
||||||
$keys = [];
|
|
||||||
foreach ($linksToDisplay as $key => $value) {
|
|
||||||
$keys[] = $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
$pageaddr = escape(index_url($this->serverInfo));
|
$pageaddr = escape(index_url($this->serverInfo));
|
||||||
$this->formatter->addContextData('index_url', $pageaddr);
|
$this->formatter->addContextData('index_url', $pageaddr);
|
||||||
$linkDisplayed = [];
|
$links = [];
|
||||||
for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) {
|
foreach ($searchResult->getBookmarks() as $key => $bookmark) {
|
||||||
$linkDisplayed[$keys[$i]] = $this->buildItem($feedType, $linksToDisplay[$keys[$i]], $pageaddr);
|
$links[$key] = $this->buildItem($feedType, $bookmark, $pageaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['language'] = $this->getTypeLanguage($feedType);
|
$data['language'] = $this->getTypeLanguage($feedType);
|
||||||
|
@ -128,7 +122,7 @@ public function buildData(string $feedType, ?array $userInput)
|
||||||
$data['self_link'] = $pageaddr . $requestUri;
|
$data['self_link'] = $pageaddr . $requestUri;
|
||||||
$data['index_url'] = $pageaddr;
|
$data['index_url'] = $pageaddr;
|
||||||
$data['usepermalinks'] = $this->usePermalinks === true;
|
$data['usepermalinks'] = $this->usePermalinks === true;
|
||||||
$data['links'] = $linkDisplayed;
|
$data['links'] = $links;
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@ -268,19 +262,18 @@ protected function getIsoDate(string $feedType, DateTime $date, $format = false)
|
||||||
* If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
|
* If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
|
||||||
* If 'nb' is set to 'all', display all filtered bookmarks (max parameter).
|
* If 'nb' is set to 'all', display all filtered bookmarks (max parameter).
|
||||||
*
|
*
|
||||||
* @param int $max maximum number of bookmarks to display.
|
|
||||||
* @param array $userInput $_GET.
|
* @param array $userInput $_GET.
|
||||||
*
|
*
|
||||||
* @return int number of bookmarks to display.
|
* @return int number of bookmarks to display.
|
||||||
*/
|
*/
|
||||||
protected function getNbLinks($max, ?array $userInput)
|
protected function getLimit(?array $userInput)
|
||||||
{
|
{
|
||||||
if (empty($userInput['nb'])) {
|
if (empty($userInput['nb'])) {
|
||||||
return self::$DEFAULT_NB_LINKS;
|
return self::$DEFAULT_NB_LINKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($userInput['nb'] == 'all') {
|
if ($userInput['nb'] == 'all') {
|
||||||
return $max;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$intNb = intval($userInput['nb']);
|
$intNb = intval($userInput['nb']);
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
*/
|
*/
|
||||||
class BookmarkDefaultFormatter extends BookmarkFormatter
|
class BookmarkDefaultFormatter extends BookmarkFormatter
|
||||||
{
|
{
|
||||||
protected const SEARCH_HIGHLIGHT_OPEN = '|@@HIGHLIGHT';
|
public const SEARCH_HIGHLIGHT_OPEN = '||O_HIGHLIGHT';
|
||||||
protected const SEARCH_HIGHLIGHT_CLOSE = 'HIGHLIGHT@@|';
|
public const SEARCH_HIGHLIGHT_CLOSE = '||C_HIGHLIGHT';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Shaarli\Formatter;
|
namespace Shaarli\Formatter;
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
|
use Shaarli\Formatter\Parsedown\ShaarliParsedownExtra;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BookmarkMarkdownExtraFormatter
|
* Class BookmarkMarkdownExtraFormatter
|
||||||
|
@ -18,7 +19,6 @@ class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter
|
||||||
public function __construct(ConfigManager $conf, bool $isLoggedIn)
|
public function __construct(ConfigManager $conf, bool $isLoggedIn)
|
||||||
{
|
{
|
||||||
parent::__construct($conf, $isLoggedIn);
|
parent::__construct($conf, $isLoggedIn);
|
||||||
|
$this->parsedown = new ShaarliParsedownExtra();
|
||||||
$this->parsedown = new \ParsedownExtra();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Shaarli\Formatter;
|
namespace Shaarli\Formatter;
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
|
use Shaarli\Formatter\Parsedown\ShaarliParsedown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BookmarkMarkdownFormatter
|
* Class BookmarkMarkdownFormatter
|
||||||
|
@ -42,7 +43,7 @@ public function __construct(ConfigManager $conf, bool $isLoggedIn)
|
||||||
{
|
{
|
||||||
parent::__construct($conf, $isLoggedIn);
|
parent::__construct($conf, $isLoggedIn);
|
||||||
|
|
||||||
$this->parsedown = new \Parsedown();
|
$this->parsedown = new ShaarliParsedown();
|
||||||
$this->escape = $conf->get('security.markdown_escape', true);
|
$this->escape = $conf->get('security.markdown_escape', true);
|
||||||
$this->allowedProtocols = $conf->get('security.allowed_protocols', []);
|
$this->allowedProtocols = $conf->get('security.allowed_protocols', []);
|
||||||
}
|
}
|
||||||
|
@ -128,6 +129,9 @@ function ($match) use ($allowedProtocols, $indexUrl) {
|
||||||
protected function formatHashTags($description)
|
protected function formatHashTags($description)
|
||||||
{
|
{
|
||||||
$indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : '';
|
$indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : '';
|
||||||
|
$tokens = '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN . ')' .
|
||||||
|
'(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE . ')'
|
||||||
|
;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To support unicode: http://stackoverflow.com/a/35498078/1484919
|
* To support unicode: http://stackoverflow.com/a/35498078/1484919
|
||||||
|
@ -136,8 +140,15 @@ protected function formatHashTags($description)
|
||||||
* \p{L} - letter from any language
|
* \p{L} - letter from any language
|
||||||
* \p{Mn} - any non marking space (accents, umlauts, etc)
|
* \p{Mn} - any non marking space (accents, umlauts, etc)
|
||||||
*/
|
*/
|
||||||
$regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui';
|
$regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}' . $tokens . ']+)/mui';
|
||||||
$replacement = '$1[#$2](' . $indexUrl . './add-tag/$2)';
|
$replacement = function (array $match) use ($indexUrl): string {
|
||||||
|
$cleanMatch = str_replace(
|
||||||
|
BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN,
|
||||||
|
'',
|
||||||
|
str_replace(BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE, '', $match[2])
|
||||||
|
);
|
||||||
|
return $match[1] . '[#' . $match[2] . '](' . $indexUrl . './add-tag/' . $cleanMatch . ')';
|
||||||
|
};
|
||||||
|
|
||||||
$descriptionLines = explode(PHP_EOL, $description);
|
$descriptionLines = explode(PHP_EOL, $description);
|
||||||
$descriptionOut = '';
|
$descriptionOut = '';
|
||||||
|
@ -156,7 +167,7 @@ protected function formatHashTags($description)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$codeBlockOn && !$codeLineOn) {
|
if (!$codeBlockOn && !$codeLineOn) {
|
||||||
$descriptionLine = preg_replace($regex, $replacement, $descriptionLine);
|
$descriptionLine = preg_replace_callback($regex, $replacement, $descriptionLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
$descriptionOut .= $descriptionLine;
|
$descriptionOut .= $descriptionLine;
|
||||||
|
|
15
application/formatter/Parsedown/ShaarliParsedown.php
Normal file
15
application/formatter/Parsedown/ShaarliParsedown.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shaarli\Formatter\Parsedown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsedown extension for Shaarli.
|
||||||
|
*
|
||||||
|
* Extension for both Parsedown and ParsedownExtra centralized in ShaarliParsedownTrait.
|
||||||
|
*/
|
||||||
|
class ShaarliParsedown extends \Parsedown
|
||||||
|
{
|
||||||
|
use ShaarliParsedownTrait;
|
||||||
|
}
|
15
application/formatter/Parsedown/ShaarliParsedownExtra.php
Normal file
15
application/formatter/Parsedown/ShaarliParsedownExtra.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shaarli\Formatter\Parsedown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParsedownExtra extension for Shaarli.
|
||||||
|
*
|
||||||
|
* Extension for both Parsedown and ParsedownExtra centralized in ShaarliParsedownTrait.
|
||||||
|
*/
|
||||||
|
class ShaarliParsedownExtra extends \ParsedownExtra
|
||||||
|
{
|
||||||
|
use ShaarliParsedownTrait;
|
||||||
|
}
|
81
application/formatter/Parsedown/ShaarliParsedownTrait.php
Normal file
81
application/formatter/Parsedown/ShaarliParsedownTrait.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shaarli\Formatter\Parsedown;
|
||||||
|
|
||||||
|
use Shaarli\Formatter\BookmarkDefaultFormatter as Formatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait used for Parsedown and ParsedownExtra extension.
|
||||||
|
*
|
||||||
|
* Extended:
|
||||||
|
* - Format links properly in search context
|
||||||
|
*/
|
||||||
|
trait ShaarliParsedownTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function inlineLink($excerpt)
|
||||||
|
{
|
||||||
|
return $this->shaarliFormatLink(parent::inlineLink($excerpt), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function inlineUrl($excerpt)
|
||||||
|
{
|
||||||
|
return $this->shaarliFormatLink(parent::inlineUrl($excerpt), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properly format markdown link:
|
||||||
|
* - remove highlight tags from HREF attribute
|
||||||
|
* - (optional) add highlight tags to link caption
|
||||||
|
*
|
||||||
|
* @param array|null $link Parsedown formatted link array.
|
||||||
|
* It can be empty.
|
||||||
|
* @param bool $fullWrap Add highlight tags the whole link caption
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
protected function shaarliFormatLink(?array $link, bool $fullWrap): ?array
|
||||||
|
{
|
||||||
|
// If open and clean search tokens are found in the link, process.
|
||||||
|
if (
|
||||||
|
is_array($link)
|
||||||
|
&& strpos($link['element']['attributes']['href'] ?? '', Formatter::SEARCH_HIGHLIGHT_OPEN) !== false
|
||||||
|
&& strpos($link['element']['attributes']['href'] ?? '', Formatter::SEARCH_HIGHLIGHT_CLOSE) !== false
|
||||||
|
) {
|
||||||
|
$link['element']['attributes']['href'] = $this->shaarliRemoveSearchTokens(
|
||||||
|
$link['element']['attributes']['href']
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($fullWrap) {
|
||||||
|
$link['element']['text'] = Formatter::SEARCH_HIGHLIGHT_OPEN .
|
||||||
|
$link['element']['text'] .
|
||||||
|
Formatter::SEARCH_HIGHLIGHT_CLOSE
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove open and close tags from provided string.
|
||||||
|
*
|
||||||
|
* @param string $entry input
|
||||||
|
*
|
||||||
|
* @return string Striped input
|
||||||
|
*/
|
||||||
|
protected function shaarliRemoveSearchTokens(string $entry): string
|
||||||
|
{
|
||||||
|
$entry = str_replace(Formatter::SEARCH_HIGHLIGHT_OPEN, '', $entry);
|
||||||
|
$entry = str_replace(Formatter::SEARCH_HIGHLIGHT_CLOSE, '', $entry);
|
||||||
|
|
||||||
|
return $entry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,9 +57,12 @@ public function save(Request $request, Response $response): Response
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this to bookmark service
|
// TODO: move this to bookmark service
|
||||||
$count = 0;
|
$searchResult = $this->container->bookmarkService->search(
|
||||||
$bookmarks = $this->container->bookmarkService->search(['searchtags' => $fromTag], BookmarkFilter::$ALL, true);
|
['searchtags' => $fromTag],
|
||||||
foreach ($bookmarks as $bookmark) {
|
BookmarkFilter::$ALL,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
foreach ($searchResult->getBookmarks() as $bookmark) {
|
||||||
if (false === $isDelete) {
|
if (false === $isDelete) {
|
||||||
$bookmark->renameTag($fromTag, $toTag);
|
$bookmark->renameTag($fromTag, $toTag);
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,11 +71,11 @@ public function save(Request $request, Response $response): Response
|
||||||
|
|
||||||
$this->container->bookmarkService->set($bookmark, false);
|
$this->container->bookmarkService->set($bookmark, false);
|
||||||
$this->container->history->updateLink($bookmark);
|
$this->container->history->updateLink($bookmark);
|
||||||
$count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->container->bookmarkService->save();
|
$this->container->bookmarkService->save();
|
||||||
|
|
||||||
|
$count = $searchResult->getResultCount();
|
||||||
if (true === $isDelete) {
|
if (true === $isDelete) {
|
||||||
$alert = sprintf(
|
$alert = sprintf(
|
||||||
t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count),
|
t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count),
|
||||||
|
|
|
@ -66,6 +66,10 @@ public function deleteBookmark(Request $request, Response $response): Response
|
||||||
return $response->write('<script>self.close();</script>');
|
return $response->write('<script>self.close();</script>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->getParam('source') === 'batch') {
|
||||||
|
return $response->withStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
// Don't redirect to permalink after deletion.
|
// Don't redirect to permalink after deletion.
|
||||||
return $this->redirectFromReferer($request, $response, ['shaare/']);
|
return $this->redirectFromReferer($request, $response, ['shaare/']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ThumbnailsController extends ShaarliAdminController
|
||||||
public function index(Request $request, Response $response): Response
|
public function index(Request $request, Response $response): Response
|
||||||
{
|
{
|
||||||
$ids = [];
|
$ids = [];
|
||||||
foreach ($this->container->bookmarkService->search() as $bookmark) {
|
foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||||
// A note or not HTTP(S)
|
// A note or not HTTP(S)
|
||||||
if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) {
|
if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -33,10 +33,10 @@ public function index(Request $request, Response $response): Response
|
||||||
|
|
||||||
$formatter = $this->container->formatterFactory->getFormatter();
|
$formatter = $this->container->formatterFactory->getFormatter();
|
||||||
$formatter->addContextData('base_path', $this->container->basePath);
|
$formatter->addContextData('base_path', $this->container->basePath);
|
||||||
|
$formatter->addContextData('index_url', index_url($this->container->environment));
|
||||||
|
|
||||||
$searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
|
$searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
|
||||||
$searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));
|
$searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));
|
||||||
;
|
|
||||||
|
|
||||||
// Filter bookmarks according search parameters.
|
// Filter bookmarks according search parameters.
|
||||||
$visibility = $this->container->sessionManager->getSessionParameter('visibility');
|
$visibility = $this->container->sessionManager->getSessionParameter('visibility');
|
||||||
|
@ -44,39 +44,26 @@ public function index(Request $request, Response $response): Response
|
||||||
'searchtags' => $searchTags,
|
'searchtags' => $searchTags,
|
||||||
'searchterm' => $searchTerm,
|
'searchterm' => $searchTerm,
|
||||||
];
|
];
|
||||||
$linksToDisplay = $this->container->bookmarkService->search(
|
|
||||||
|
// Select articles according to paging.
|
||||||
|
$page = (int) ($request->getParam('page') ?? 1);
|
||||||
|
$page = $page < 1 ? 1 : $page;
|
||||||
|
$linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
|
||||||
|
|
||||||
|
$searchResult = $this->container->bookmarkService->search(
|
||||||
$search,
|
$search,
|
||||||
$visibility,
|
$visibility,
|
||||||
false,
|
false,
|
||||||
!!$this->container->sessionManager->getSessionParameter('untaggedonly')
|
!!$this->container->sessionManager->getSessionParameter('untaggedonly'),
|
||||||
|
false,
|
||||||
|
['offset' => $linksPerPage * ($page - 1), 'limit' => $linksPerPage]
|
||||||
) ?? [];
|
) ?? [];
|
||||||
|
|
||||||
// ---- Handle paging.
|
|
||||||
$keys = [];
|
|
||||||
foreach ($linksToDisplay as $key => $value) {
|
|
||||||
$keys[] = $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
$linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20;
|
|
||||||
|
|
||||||
// Select articles according to paging.
|
|
||||||
$pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1;
|
|
||||||
$page = (int) $request->getParam('page') ?? 1;
|
|
||||||
$page = $page < 1 ? 1 : $page;
|
|
||||||
$page = $page > $pageCount ? $pageCount : $page;
|
|
||||||
|
|
||||||
// Start index.
|
|
||||||
$i = ($page - 1) * $linksPerPage;
|
|
||||||
$end = $i + $linksPerPage;
|
|
||||||
|
|
||||||
$linkDisp = [];
|
|
||||||
$save = false;
|
$save = false;
|
||||||
while ($i < $end && $i < count($keys)) {
|
$links = [];
|
||||||
$save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save;
|
foreach ($searchResult->getBookmarks() as $key => $bookmark) {
|
||||||
$link = $formatter->format($linksToDisplay[$keys[$i]]);
|
$save = $this->updateThumbnail($bookmark, false) || $save;
|
||||||
|
$links[$key] = $formatter->format($bookmark);
|
||||||
$linkDisp[$keys[$i]] = $link;
|
|
||||||
$i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($save) {
|
if ($save) {
|
||||||
|
@ -86,15 +73,10 @@ public function index(Request $request, Response $response): Response
|
||||||
// Compute paging navigation
|
// Compute paging navigation
|
||||||
$searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
|
$searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags);
|
||||||
$searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
|
$searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm);
|
||||||
|
$page = $searchResult->getPage();
|
||||||
|
|
||||||
$previous_page_url = '';
|
$previousPageUrl = !$searchResult->isLastPage() ? '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl : '';
|
||||||
if ($i !== count($keys)) {
|
$nextPageUrl = !$searchResult->isFirstPage() ? '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl : '';
|
||||||
$previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl;
|
|
||||||
}
|
|
||||||
$next_page_url = '';
|
|
||||||
if ($page > 1) {
|
|
||||||
$next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tagsSeparator = $this->container->conf->get('general.tags_separator', ' ');
|
$tagsSeparator = $this->container->conf->get('general.tags_separator', ' ');
|
||||||
$searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator));
|
$searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator));
|
||||||
|
@ -104,16 +86,16 @@ public function index(Request $request, Response $response): Response
|
||||||
$data = array_merge(
|
$data = array_merge(
|
||||||
$this->initializeTemplateVars(),
|
$this->initializeTemplateVars(),
|
||||||
[
|
[
|
||||||
'previous_page_url' => $previous_page_url,
|
'previous_page_url' => $previousPageUrl,
|
||||||
'next_page_url' => $next_page_url,
|
'next_page_url' => $nextPageUrl,
|
||||||
'page_current' => $page,
|
'page_current' => $page,
|
||||||
'page_max' => $pageCount,
|
'page_max' => $searchResult->getLastPage(),
|
||||||
'result_count' => count($linksToDisplay),
|
'result_count' => $searchResult->getTotalCount(),
|
||||||
'search_term' => escape($searchTerm),
|
'search_term' => escape($searchTerm),
|
||||||
'search_tags' => escape($searchTags),
|
'search_tags' => escape($searchTags),
|
||||||
'search_tags_url' => $searchTagsUrlEncoded,
|
'search_tags_url' => $searchTagsUrlEncoded,
|
||||||
'visibility' => $visibility,
|
'visibility' => $visibility,
|
||||||
'links' => $linkDisp,
|
'links' => $links,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -157,6 +139,7 @@ public function permalink(Request $request, Response $response, array $args): Re
|
||||||
|
|
||||||
$formatter = $this->container->formatterFactory->getFormatter();
|
$formatter = $this->container->formatterFactory->getFormatter();
|
||||||
$formatter->addContextData('base_path', $this->container->basePath);
|
$formatter->addContextData('base_path', $this->container->basePath);
|
||||||
|
$formatter->addContextData('index_url', index_url($this->container->environment));
|
||||||
|
|
||||||
$data = array_merge(
|
$data = array_merge(
|
||||||
$this->initializeTemplateVars(),
|
$this->initializeTemplateVars(),
|
||||||
|
|
|
@ -100,7 +100,7 @@ public function rss(Request $request, Response $response): Response
|
||||||
$days = [];
|
$days = [];
|
||||||
$format = DailyPageHelper::getFormatByType($type);
|
$format = DailyPageHelper::getFormatByType($type);
|
||||||
$length = DailyPageHelper::getRssLengthByType($type);
|
$length = DailyPageHelper::getRssLengthByType($type);
|
||||||
foreach ($this->container->bookmarkService->search() as $bookmark) {
|
foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||||
$day = $bookmark->getCreated()->format($format);
|
$day = $bookmark->getCreated()->format($format);
|
||||||
|
|
||||||
// Stop iterating after DAILY_RSS_NB_DAYS entries
|
// Stop iterating after DAILY_RSS_NB_DAYS entries
|
||||||
|
|
|
@ -30,19 +30,19 @@ public function index(Request $request, Response $response): Response
|
||||||
);
|
);
|
||||||
|
|
||||||
// Optionally filter the results:
|
// Optionally filter the results:
|
||||||
$links = $this->container->bookmarkService->search($request->getQueryParams());
|
$bookmarks = $this->container->bookmarkService->search($request->getQueryParams())->getBookmarks();
|
||||||
$linksToDisplay = [];
|
$links = [];
|
||||||
|
|
||||||
// Get only bookmarks which have a thumbnail.
|
// Get only bookmarks which have a thumbnail.
|
||||||
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
// Note: we do not retrieve thumbnails here, the request is too heavy.
|
||||||
$formatter = $this->container->formatterFactory->getFormatter('raw');
|
$formatter = $this->container->formatterFactory->getFormatter('raw');
|
||||||
foreach ($links as $key => $link) {
|
foreach ($bookmarks as $key => $bookmark) {
|
||||||
if (!empty($link->getThumbnail())) {
|
if (!empty($bookmark->getThumbnail())) {
|
||||||
$linksToDisplay[] = $formatter->format($link);
|
$links[] = $formatter->format($bookmark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = ['linksToDisplay' => $linksToDisplay];
|
$data = ['linksToDisplay' => $links];
|
||||||
$this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL);
|
$this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL);
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
|
|
|
@ -56,6 +56,10 @@ protected function assignAllView(array $data): self
|
||||||
|
|
||||||
protected function render(string $template): string
|
protected function render(string $template): string
|
||||||
{
|
{
|
||||||
|
// Legacy key that used to be injected by PluginManager
|
||||||
|
$this->assignView('_PAGE_', $template);
|
||||||
|
$this->assignView('template', $template);
|
||||||
|
|
||||||
$this->assignView('linkcount', $this->container->bookmarkService->count(BookmarkFilter::$ALL));
|
$this->assignView('linkcount', $this->container->bookmarkService->count(BookmarkFilter::$ALL));
|
||||||
$this->assignView('privateLinkcount', $this->container->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
$this->assignView('privateLinkcount', $this->container->bookmarkService->count(BookmarkFilter::$PRIVATE));
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ public static function getLatestGitVersionCode($url, $timeout = 2)
|
||||||
{
|
{
|
||||||
list($headers, $data) = get_http_response($url, $timeout);
|
list($headers, $data) = get_http_response($url, $timeout);
|
||||||
|
|
||||||
if (strpos($headers[0], '200 OK') === false) {
|
if (preg_match('#HTTP/[\d\.]+ 200(?: OK)?#', $headers[0]) !== 1) {
|
||||||
error_log('Failed to retrieve ' . $url);
|
error_log('Failed to retrieve ' . $url);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public function filterAndFormat(
|
||||||
}
|
}
|
||||||
|
|
||||||
$bookmarkLinks = [];
|
$bookmarkLinks = [];
|
||||||
foreach ($this->bookmarkService->search([], $selection) as $bookmark) {
|
foreach ($this->bookmarkService->search([], $selection)->getBookmarks() as $bookmark) {
|
||||||
$link = $formatter->format($bookmark);
|
$link = $formatter->format($bookmark);
|
||||||
$link['taglist'] = implode(',', $bookmark->getTags());
|
$link['taglist'] = implode(',', $bookmark->getTags());
|
||||||
if ($bookmark->isNote() && $prependNoteUrl) {
|
if ($bookmark->isNote() && $prependNoteUrl) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Shaarli\Plugin;
|
namespace Shaarli\Plugin;
|
||||||
|
|
||||||
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Plugin\Exception\PluginFileNotFoundException;
|
use Shaarli\Plugin\Exception\PluginFileNotFoundException;
|
||||||
use Shaarli\Plugin\Exception\PluginInvalidRouteException;
|
use Shaarli\Plugin\Exception\PluginInvalidRouteException;
|
||||||
|
@ -45,6 +46,9 @@ class PluginManager
|
||||||
*/
|
*/
|
||||||
protected $errors;
|
protected $errors;
|
||||||
|
|
||||||
|
/** @var callable[]|null Preloaded list of hook function for filterSearchEntry() */
|
||||||
|
protected $filterSearchEntryHooks = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugins subdirectory.
|
* Plugins subdirectory.
|
||||||
*
|
*
|
||||||
|
@ -273,6 +277,14 @@ public function getRegisteredRoutes(): array
|
||||||
return $this->registeredRoutes;
|
return $this->registeredRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array List of registered filter_search_entry hooks
|
||||||
|
*/
|
||||||
|
public function getFilterSearchEntryHooks(): ?array
|
||||||
|
{
|
||||||
|
return $this->filterSearchEntryHooks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the list of encountered errors.
|
* Return the list of encountered errors.
|
||||||
*
|
*
|
||||||
|
@ -283,6 +295,50 @@ public function getErrors()
|
||||||
return $this->errors;
|
return $this->errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply additional filter on every search result of BookmarkFilter calling plugins hooks.
|
||||||
|
*
|
||||||
|
* @param Bookmark $bookmark To check.
|
||||||
|
* @param array $context Additional info about search context, depends on the search source.
|
||||||
|
*
|
||||||
|
* @return bool True if the result must be kept in search results, false otherwise.
|
||||||
|
*/
|
||||||
|
public function filterSearchEntry(Bookmark $bookmark, array $context): bool
|
||||||
|
{
|
||||||
|
if ($this->filterSearchEntryHooks === null) {
|
||||||
|
$this->loadFilterSearchEntryHooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->filterSearchEntryHooks === []) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->filterSearchEntryHooks as $filterSearchEntryHook) {
|
||||||
|
if ($filterSearchEntryHook($bookmark, $context) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filterSearchEntry() method will be called for every search result,
|
||||||
|
* so for performances we preload existing functions to invoke them directly.
|
||||||
|
*/
|
||||||
|
protected function loadFilterSearchEntryHooks(): void
|
||||||
|
{
|
||||||
|
$this->filterSearchEntryHooks = [];
|
||||||
|
|
||||||
|
foreach ($this->loadedPlugins as $plugin) {
|
||||||
|
$hookFunction = $this->buildHookName('filter_search_entry', $plugin);
|
||||||
|
|
||||||
|
if (function_exists($hookFunction)) {
|
||||||
|
$this->filterSearchEntryHooks[] = $hookFunction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether provided input is valid to register a new route.
|
* Checks whether provided input is valid to register a new route.
|
||||||
* It must contain keys `method`, `route`, `callable` (all strings).
|
* It must contain keys `method`, `route`, `callable` (all strings).
|
||||||
|
|
|
@ -152,7 +152,7 @@ public function updateMethodMigrateExistingNotesUrl(): bool
|
||||||
{
|
{
|
||||||
$updated = false;
|
$updated = false;
|
||||||
|
|
||||||
foreach ($this->bookmarkService->search() as $bookmark) {
|
foreach ($this->bookmarkService->search()->getBookmarks() as $bookmark) {
|
||||||
if (
|
if (
|
||||||
$bookmark->isNote()
|
$bookmark->isNote()
|
||||||
&& startsWith($bookmark->getUrl(), '?')
|
&& startsWith($bookmark->getUrl(), '?')
|
||||||
|
|
|
@ -4,7 +4,11 @@ const sendBookmarkForm = (basePath, formElement) => {
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
[...inputs].forEach((input) => {
|
[...inputs].forEach((input) => {
|
||||||
formData.append(input.getAttribute('name'), input.value);
|
if (input.getAttribute('type') === 'checkbox') {
|
||||||
|
formData.append(input.getAttribute('name'), input.checked);
|
||||||
|
} else {
|
||||||
|
formData.append(input.getAttribute('name'), input.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -26,9 +30,9 @@ const sendBookmarkForm = (basePath, formElement) => {
|
||||||
const sendBookmarkDelete = (buttonElement, formElement) => (
|
const sendBookmarkDelete = (buttonElement, formElement) => (
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', buttonElement.href);
|
xhr.open('GET', `${buttonElement.href}&source=batch`);
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if (xhr.status !== 200) {
|
if (xhr.status !== 204) {
|
||||||
alert(`An error occurred. Return code: ${xhr.status}`);
|
alert(`An error occurred. Return code: ${xhr.status}`);
|
||||||
reject();
|
reject();
|
||||||
} else {
|
} else {
|
||||||
|
@ -100,7 +104,7 @@ const redirectIfEmptyBatch = (basePath, formElements, path) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(promises).then(() => {
|
Promise.all(promises).then(() => {
|
||||||
window.location.href = basePath || '/';
|
window.location.href = `${basePath}/`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
12
composer.lock
generated
12
composer.lock
generated
|
@ -8,16 +8,16 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "arthurhoaro/web-thumbnailer",
|
"name": "arthurhoaro/web-thumbnailer",
|
||||||
"version": "v2.0.3",
|
"version": "v2.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ArthurHoaro/web-thumbnailer.git",
|
"url": "https://github.com/ArthurHoaro/web-thumbnailer.git",
|
||||||
"reference": "39bfd4f3136d9e6096496b9720e877326cfe4775"
|
"reference": "7780ddc0f44fccdce6cddb86d1db0354810290d0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/39bfd4f3136d9e6096496b9720e877326cfe4775",
|
"url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/7780ddc0f44fccdce6cddb86d1db0354810290d0",
|
||||||
"reference": "39bfd4f3136d9e6096496b9720e877326cfe4775",
|
"reference": "7780ddc0f44fccdce6cddb86d1db0354810290d0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -53,9 +53,9 @@
|
||||||
"description": "PHP library which will retrieve a thumbnail for any given URL",
|
"description": "PHP library which will retrieve a thumbnail for any given URL",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/ArthurHoaro/web-thumbnailer/issues",
|
"issues": "https://github.com/ArthurHoaro/web-thumbnailer/issues",
|
||||||
"source": "https://github.com/ArthurHoaro/web-thumbnailer/tree/v2.0.3"
|
"source": "https://github.com/ArthurHoaro/web-thumbnailer/tree/v2.0.4"
|
||||||
},
|
},
|
||||||
"time": "2020-09-29T15:51:03+00:00"
|
"time": "2021-02-22T10:43:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "erusev/parsedown",
|
"name": "erusev/parsedown",
|
||||||
|
|
|
@ -194,7 +194,7 @@ $ docker logs -f <container-name-or-first-letters-of-id>
|
||||||
# delete unused images to free up disk space
|
# delete unused images to free up disk space
|
||||||
$ docker system prune --images
|
$ docker system prune --images
|
||||||
# delete unused volumes to free up disk space (CAUTION all data in unused volumes will be lost)
|
# delete unused volumes to free up disk space (CAUTION all data in unused volumes will be lost)
|
||||||
$ docker system prunt --volumes
|
$ docker system prune --volumes
|
||||||
# delete unused containers
|
# delete unused containers
|
||||||
$ docker system prune
|
$ docker system prune
|
||||||
```
|
```
|
||||||
|
|
|
@ -199,6 +199,8 @@ sudo nano /etc/apache2/sites-available/shaarli.mydomain.org.conf
|
||||||
Require all denied
|
Require all denied
|
||||||
</FilesMatch>
|
</FilesMatch>
|
||||||
|
|
||||||
|
DirectoryIndex index.php
|
||||||
|
|
||||||
<Files "index.php">
|
<Files "index.php">
|
||||||
Require all granted
|
Require all granted
|
||||||
</Files>
|
</Files>
|
||||||
|
|
|
@ -27,7 +27,6 @@ You should have the following tree view:
|
||||||
| |---| demo_plugin.php
|
| |---| demo_plugin.php
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Plugin initialization
|
### Plugin initialization
|
||||||
|
|
||||||
At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter.
|
At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter.
|
||||||
|
@ -209,6 +208,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha
|
||||||
| [save_link](#save_link) | Allow to alter the link being saved in the datastore. |
|
| [save_link](#save_link) | Allow to alter the link being saved in the datastore. |
|
||||||
| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |
|
| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |
|
||||||
| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
|
| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
|
||||||
|
| [filter_search_entry](#filter_search_entry) | Add custom filters to Shaarli search engine |
|
||||||
|
|
||||||
|
|
||||||
#### render_header
|
#### render_header
|
||||||
|
@ -565,6 +565,23 @@ the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
|
||||||
|
|
||||||
Also [special data](#special-data).
|
Also [special data](#special-data).
|
||||||
|
|
||||||
|
#### filter_search_entry
|
||||||
|
|
||||||
|
Triggered for *every* bookmark when Shaarli's BookmarkService method `search()` is used.
|
||||||
|
Any custom filter can be added to filter out bookmarks from search results.
|
||||||
|
|
||||||
|
The hook **must** return either:
|
||||||
|
- `true` to keep bookmark entry in search result set
|
||||||
|
- `false` to discard bookmark entry in result set
|
||||||
|
|
||||||
|
> Note: custom filters are called *before* default filters are applied.
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
- `Shaarli\Bookmark\Bookmark` object: entry to evaluate
|
||||||
|
- $context `array`: additional information provided depending on what search is currently used,
|
||||||
|
the user request, etc.
|
||||||
|
|
||||||
## Guide for template designers
|
## Guide for template designers
|
||||||
|
|
||||||
### Plugin administration
|
### Plugin administration
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@
|
||||||
* and check user status with _LOGGEDIN_.
|
* and check user status with _LOGGEDIN_.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Plugin\PluginManager;
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\Render\TemplatePage;
|
use Shaarli\Render\TemplatePage;
|
||||||
|
@ -263,6 +264,17 @@ function hook_demo_plugin_render_linklist($data)
|
||||||
}
|
}
|
||||||
$data['action_plugin'][] = $action;
|
$data['action_plugin'][] = $action;
|
||||||
|
|
||||||
|
// Action to trigger custom filter hiding bookmarks not containing 'e' letter in their description
|
||||||
|
$action = [
|
||||||
|
'attr' => [
|
||||||
|
'href' => '?e',
|
||||||
|
'title' => 'Hide bookmarks without "e" in their description.',
|
||||||
|
],
|
||||||
|
'html' => 'e',
|
||||||
|
'on' => isset($_GET['e'])
|
||||||
|
];
|
||||||
|
$data['action_plugin'][] = $action;
|
||||||
|
|
||||||
// link_plugin (for each link)
|
// link_plugin (for each link)
|
||||||
foreach ($data['links'] as &$value) {
|
foreach ($data['links'] as &$value) {
|
||||||
$value['link_plugin'][] = ' DEMO \o/';
|
$value['link_plugin'][] = ' DEMO \o/';
|
||||||
|
@ -486,6 +498,27 @@ function hook_demo_plugin_save_plugin_parameters($data)
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This hook is called when a search is performed, on every search entry.
|
||||||
|
* It allows to add custom filters, and filter out additional link.
|
||||||
|
*
|
||||||
|
* For exemple here, we hide all bookmarks not containing the letter 'e' in their description.
|
||||||
|
*
|
||||||
|
* @param Bookmark $bookmark Search entry. Note that this is a Bookmark object, and not a link array.
|
||||||
|
* It should NOT be altered.
|
||||||
|
* @param array $context Additional info on the search performed.
|
||||||
|
*
|
||||||
|
* @return bool True if the bookmark should be kept in the search result, false to discard it.
|
||||||
|
*/
|
||||||
|
function hook_demo_plugin_filter_search_entry(Bookmark $bookmark, array $context): bool
|
||||||
|
{
|
||||||
|
if (isset($_GET['e'])) {
|
||||||
|
return strpos($bookmark->getDescription(), 'e') !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is never called, but contains translation calls for GNU gettext extraction.
|
* This function is never called, but contains translation calls for GNU gettext extraction.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Shaarli\Plugin;
|
namespace Shaarli\Plugin;
|
||||||
|
|
||||||
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,4 +160,19 @@ public function testRegisteredRoutesInvalid(): void
|
||||||
$errors = $this->pluginManager->getErrors();
|
$errors = $this->pluginManager->getErrors();
|
||||||
static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors);
|
static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSearchFilterPlugin(): void
|
||||||
|
{
|
||||||
|
PluginManager::$PLUGINS_PATH = self::$pluginPath;
|
||||||
|
$this->pluginManager->load([self::$pluginName]);
|
||||||
|
|
||||||
|
static::assertNull($this->pluginManager->getFilterSearchEntryHooks());
|
||||||
|
|
||||||
|
static::assertTrue($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => true]));
|
||||||
|
|
||||||
|
static::assertCount(1, $this->pluginManager->getFilterSearchEntryHooks());
|
||||||
|
static::assertSame('hook_test_filter_search_entry', $this->pluginManager->getFilterSearchEntryHooks()[0]);
|
||||||
|
|
||||||
|
static::assertFalse($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => false]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -56,6 +57,7 @@ protected function setUp(): void
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['history'] = $history;
|
$this->container['history'] = $history;
|
||||||
|
$this->container['pluginManager'] = new PluginManager($this->conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
use Shaarli\Bookmark\BookmarkFileService;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
|
@ -55,12 +56,18 @@ protected function setUp(): void
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
$this->conf->set('resource.datastore', self::$testDatastore);
|
||||||
$this->refDB = new \ReferenceLinkDB();
|
$this->refDB = new \ReferenceLinkDB();
|
||||||
$this->refDB->write(self::$testDatastore);
|
$this->refDB->write(self::$testDatastore);
|
||||||
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
$history = new History('sandbox/history.php');
|
$history = new History('sandbox/history.php');
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
|
$this->container['db'] = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container['history'] = null;
|
$this->container['history'] = null;
|
||||||
|
|
||||||
$this->controller = new Info($this->container);
|
$this->controller = new Info($this->container);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
use Shaarli\Bookmark\BookmarkFileService;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -57,6 +58,9 @@ class DeleteLinkTest extends \Shaarli\TestCase
|
||||||
/** @var NoMutex */
|
/** @var NoMutex */
|
||||||
protected $mutex;
|
protected $mutex;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
* Before each test, instantiate a new Api with its config, plugins and bookmarks.
|
||||||
*/
|
*/
|
||||||
|
@ -70,7 +74,14 @@ protected function setUp(): void
|
||||||
$refHistory = new \ReferenceHistory();
|
$refHistory = new \ReferenceHistory();
|
||||||
$refHistory->write(self::$testHistory);
|
$refHistory->write(self::$testHistory);
|
||||||
$this->history = new History(self::$testHistory);
|
$this->history = new History(self::$testHistory);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
|
@ -105,7 +116,13 @@ public function testDeleteLinkValid()
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
$this->assertEquals(204, $response->getStatusCode());
|
||||||
$this->assertEmpty((string) $response->getBody());
|
$this->assertEmpty((string) $response->getBody());
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->assertFalse($this->bookmarkService->exists($id));
|
$this->assertFalse($this->bookmarkService->exists($id));
|
||||||
|
|
||||||
$historyEntry = $this->history->getHistory()[0];
|
$historyEntry = $this->history->getHistory()[0];
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
use Shaarli\Bookmark\BookmarkFileService;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -67,7 +68,14 @@ protected function setUp(): void
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
|
$pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->container['db'] = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container['history'] = null;
|
$this->container['history'] = null;
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
$this->controller = new Links($this->container);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\LinkDB;
|
use Shaarli\Bookmark\LinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -67,7 +68,14 @@ protected function setUp(): void
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
|
$pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->container['db'] = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container['history'] = null;
|
$this->container['history'] = null;
|
||||||
|
|
||||||
$this->controller = new Links($this->container);
|
$this->controller = new Links($this->container);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
use Shaarli\Bookmark\BookmarkFileService;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
|
@ -81,8 +82,14 @@ protected function setUp(): void
|
||||||
$refHistory = new \ReferenceHistory();
|
$refHistory = new \ReferenceHistory();
|
||||||
$refHistory->write(self::$testHistory);
|
$refHistory->write(self::$testHistory);
|
||||||
$this->history = new History(self::$testHistory);
|
$this->history = new History(self::$testHistory);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
|
$pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = $this->bookmarkService;
|
$this->container['db'] = $this->bookmarkService;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFileService;
|
use Shaarli\Bookmark\BookmarkFileService;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -73,8 +74,14 @@ protected function setUp(): void
|
||||||
$refHistory = new \ReferenceHistory();
|
$refHistory = new \ReferenceHistory();
|
||||||
$refHistory->write(self::$testHistory);
|
$refHistory->write(self::$testHistory);
|
||||||
$this->history = new History(self::$testHistory);
|
$this->history = new History(self::$testHistory);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
|
$pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = $this->bookmarkService;
|
$this->container['db'] = $this->bookmarkService;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use Shaarli\Bookmark\LinkDB;
|
use Shaarli\Bookmark\LinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -55,6 +56,9 @@ class DeleteTagTest extends \Shaarli\TestCase
|
||||||
*/
|
*/
|
||||||
protected $controller;
|
protected $controller;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/** @var NoMutex */
|
/** @var NoMutex */
|
||||||
protected $mutex;
|
protected $mutex;
|
||||||
|
|
||||||
|
@ -71,7 +75,14 @@ protected function setUp(): void
|
||||||
$refHistory = new \ReferenceHistory();
|
$refHistory = new \ReferenceHistory();
|
||||||
$refHistory->write(self::$testHistory);
|
$refHistory->write(self::$testHistory);
|
||||||
$this->history = new History(self::$testHistory);
|
$this->history = new History(self::$testHistory);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
|
@ -107,7 +118,13 @@ public function testDeleteTagValid()
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
$this->assertEquals(204, $response->getStatusCode());
|
||||||
$this->assertEmpty((string) $response->getBody());
|
$this->assertEmpty((string) $response->getBody());
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
||||||
$this->assertFalse(isset($tags[$tagName]));
|
$this->assertFalse(isset($tags[$tagName]));
|
||||||
|
|
||||||
|
@ -141,7 +158,13 @@ public function testDeleteTagCaseSensitivity()
|
||||||
$this->assertEquals(204, $response->getStatusCode());
|
$this->assertEquals(204, $response->getStatusCode());
|
||||||
$this->assertEmpty((string) $response->getBody());
|
$this->assertEmpty((string) $response->getBody());
|
||||||
|
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
$tags = $this->bookmarkService->bookmarksCountPerTag();
|
||||||
$this->assertFalse(isset($tags[$tagName]));
|
$this->assertFalse(isset($tags[$tagName]));
|
||||||
$this->assertTrue($tags[strtolower($tagName)] > 0);
|
$this->assertTrue($tags[strtolower($tagName)] > 0);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\LinkDB;
|
use Shaarli\Bookmark\LinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -46,6 +47,9 @@ class GetTagNameTest extends \Shaarli\TestCase
|
||||||
*/
|
*/
|
||||||
protected $controller;
|
protected $controller;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of JSON fields per link.
|
* Number of JSON fields per link.
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +69,14 @@ protected function setUp(): void
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->container['db'] = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container['history'] = null;
|
$this->container['history'] = null;
|
||||||
|
|
||||||
$this->controller = new Tags($this->container);
|
$this->controller = new Tags($this->container);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
use Shaarli\Bookmark\LinkDB;
|
use Shaarli\Bookmark\LinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -50,6 +51,9 @@ class GetTagsTest extends \Shaarli\TestCase
|
||||||
*/
|
*/
|
||||||
protected $controller;
|
protected $controller;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of JSON field per link.
|
* Number of JSON field per link.
|
||||||
*/
|
*/
|
||||||
|
@ -66,9 +70,14 @@ protected function setUp(): void
|
||||||
$this->refDB = new \ReferenceLinkDB();
|
$this->refDB = new \ReferenceLinkDB();
|
||||||
$this->refDB->write(self::$testDatastore);
|
$this->refDB->write(self::$testDatastore);
|
||||||
$history = new History('sandbox/history.php');
|
$history = new History('sandbox/history.php');
|
||||||
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
$this->container['db'] = $this->bookmarkService;
|
$this->container['db'] = $this->bookmarkService;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use Shaarli\Bookmark\LinkDB;
|
use Shaarli\Bookmark\LinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Environment;
|
use Slim\Http\Environment;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -55,6 +56,9 @@ class PutTagTest extends \Shaarli\TestCase
|
||||||
*/
|
*/
|
||||||
protected $controller;
|
protected $controller;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of JSON field per link.
|
* Number of JSON field per link.
|
||||||
*/
|
*/
|
||||||
|
@ -73,7 +77,14 @@ protected function setUp(): void
|
||||||
$refHistory = new \ReferenceHistory();
|
$refHistory = new \ReferenceHistory();
|
||||||
$refHistory->write(self::$testHistory);
|
$refHistory->write(self::$testHistory);
|
||||||
$this->history = new History(self::$testHistory);
|
$this->history = new History(self::$testHistory);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->container['conf'] = $this->conf;
|
$this->container['conf'] = $this->conf;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Formatter\BookmarkMarkdownFormatter;
|
use Shaarli\Formatter\BookmarkMarkdownFormatter;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +57,9 @@ class BookmarkFileServiceTest extends TestCase
|
||||||
/** @var NoMutex */
|
/** @var NoMutex */
|
||||||
protected $mutex;
|
protected $mutex;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates public and private LinkDBs with test data
|
* Instantiates public and private LinkDBs with test data
|
||||||
*
|
*
|
||||||
|
@ -93,8 +97,21 @@ protected function setUp(): void
|
||||||
$this->refDB = new \ReferenceLinkDB();
|
$this->refDB = new \ReferenceLinkDB();
|
||||||
$this->refDB->write(self::$testDatastore);
|
$this->refDB->write(self::$testDatastore);
|
||||||
$this->history = new History('sandbox/history.php');
|
$this->history = new History('sandbox/history.php');
|
||||||
$this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->publicLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,7 +128,13 @@ public function testDatabaseMigration()
|
||||||
$db = self::getMethod('migrate');
|
$db = self::getMethod('migrate');
|
||||||
$db->invokeArgs($this->privateLinkDB, []);
|
$db->invokeArgs($this->privateLinkDB, []);
|
||||||
|
|
||||||
$db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true);
|
$db = new \FakeBookmarkService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
|
$this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
|
||||||
$this->assertEquals($this->refDB->countLinks(), $db->count());
|
$this->assertEquals($this->refDB->countLinks(), $db->count());
|
||||||
}
|
}
|
||||||
|
@ -180,7 +203,13 @@ public function testAddFull()
|
||||||
$this->assertEquals($updated, $bookmark->getUpdated());
|
$this->assertEquals($updated, $bookmark->getUpdated());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new \FakeBookmarkService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(43);
|
$bookmark = $this->privateLinkDB->get(43);
|
||||||
$this->assertEquals(43, $bookmark->getId());
|
$this->assertEquals(43, $bookmark->getId());
|
||||||
|
@ -218,7 +247,13 @@ public function testAddMinimal()
|
||||||
$this->assertNull($bookmark->getUpdated());
|
$this->assertNull($bookmark->getUpdated());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(43);
|
$bookmark = $this->privateLinkDB->get(43);
|
||||||
$this->assertEquals(43, $bookmark->getId());
|
$this->assertEquals(43, $bookmark->getId());
|
||||||
|
@ -248,7 +283,13 @@ public function testAddMinimalNoWrite()
|
||||||
$this->assertEquals(43, $bookmark->getId());
|
$this->assertEquals(43, $bookmark->getId());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->privateLinkDB->get(43);
|
$this->privateLinkDB->get(43);
|
||||||
}
|
}
|
||||||
|
@ -309,7 +350,13 @@ public function testSetFull()
|
||||||
$this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
|
$this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(42);
|
$bookmark = $this->privateLinkDB->get(42);
|
||||||
$this->assertEquals(42, $bookmark->getId());
|
$this->assertEquals(42, $bookmark->getId());
|
||||||
|
@ -350,7 +397,13 @@ public function testSetMinimal()
|
||||||
$this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
|
$this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(42);
|
$bookmark = $this->privateLinkDB->get(42);
|
||||||
$this->assertEquals(42, $bookmark->getId());
|
$this->assertEquals(42, $bookmark->getId());
|
||||||
|
@ -383,7 +436,13 @@ public function testSetMinimalNoWrite()
|
||||||
$this->assertEquals($title, $bookmark->getTitle());
|
$this->assertEquals($title, $bookmark->getTitle());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(42);
|
$bookmark = $this->privateLinkDB->get(42);
|
||||||
$this->assertEquals(42, $bookmark->getId());
|
$this->assertEquals(42, $bookmark->getId());
|
||||||
|
@ -436,7 +495,13 @@ public function testAddOrSetNew()
|
||||||
$this->assertEquals(43, $bookmark->getId());
|
$this->assertEquals(43, $bookmark->getId());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(43);
|
$bookmark = $this->privateLinkDB->get(43);
|
||||||
$this->assertEquals(43, $bookmark->getId());
|
$this->assertEquals(43, $bookmark->getId());
|
||||||
|
@ -456,7 +521,13 @@ public function testAddOrSetExisting()
|
||||||
$this->assertEquals($title, $bookmark->getTitle());
|
$this->assertEquals($title, $bookmark->getTitle());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(42);
|
$bookmark = $this->privateLinkDB->get(42);
|
||||||
$this->assertEquals(42, $bookmark->getId());
|
$this->assertEquals(42, $bookmark->getId());
|
||||||
|
@ -488,7 +559,13 @@ public function testAddOrSetMinimalNoWrite()
|
||||||
$this->assertEquals($title, $bookmark->getTitle());
|
$this->assertEquals($title, $bookmark->getTitle());
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->privateLinkDB->get(42);
|
$bookmark = $this->privateLinkDB->get(42);
|
||||||
$this->assertEquals(42, $bookmark->getId());
|
$this->assertEquals(42, $bookmark->getId());
|
||||||
|
@ -514,7 +591,13 @@ public function testRemoveExisting()
|
||||||
$this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
|
$this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
|
||||||
|
|
||||||
// reload from file
|
// reload from file
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->privateLinkDB->get(42);
|
$this->privateLinkDB->get(42);
|
||||||
}
|
}
|
||||||
|
@ -607,7 +690,7 @@ public function testConstructDatastoreNotWriteable()
|
||||||
|
|
||||||
$conf = new ConfigManager('tests/utils/config/configJson');
|
$conf = new ConfigManager('tests/utils/config/configJson');
|
||||||
$conf->set('resource.datastore', 'null/store.db');
|
$conf->set('resource.datastore', 'null/store.db');
|
||||||
new BookmarkFileService($conf, $this->history, $this->mutex, true);
|
new BookmarkFileService($conf, $this->pluginManager, $this->history, $this->mutex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -617,7 +700,7 @@ public function testCheckDBNewLoggedIn()
|
||||||
{
|
{
|
||||||
unlink(self::$testDatastore);
|
unlink(self::$testDatastore);
|
||||||
$this->assertFileNotExists(self::$testDatastore);
|
$this->assertFileNotExists(self::$testDatastore);
|
||||||
new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
|
||||||
$this->assertFileExists(self::$testDatastore);
|
$this->assertFileExists(self::$testDatastore);
|
||||||
|
|
||||||
// ensure the correct data has been written
|
// ensure the correct data has been written
|
||||||
|
@ -631,7 +714,7 @@ public function testCheckDBNewLoggedOut()
|
||||||
{
|
{
|
||||||
unlink(self::$testDatastore);
|
unlink(self::$testDatastore);
|
||||||
$this->assertFileNotExists(self::$testDatastore);
|
$this->assertFileNotExists(self::$testDatastore);
|
||||||
$db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false);
|
$db = new \FakeBookmarkService($this->conf, $this->pluginManager, $this->history, $this->mutex, false);
|
||||||
$this->assertFileNotExists(self::$testDatastore);
|
$this->assertFileNotExists(self::$testDatastore);
|
||||||
$this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
|
$this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
|
||||||
$this->assertCount(0, $db->getBookmarks());
|
$this->assertCount(0, $db->getBookmarks());
|
||||||
|
@ -664,13 +747,13 @@ public function testReadPrivateDB()
|
||||||
*/
|
*/
|
||||||
public function testSave()
|
public function testSave()
|
||||||
{
|
{
|
||||||
$testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
|
||||||
$dbSize = $testDB->count();
|
$dbSize = $testDB->count();
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
$bookmark = new Bookmark();
|
||||||
$testDB->add($bookmark);
|
$testDB->add($bookmark);
|
||||||
|
|
||||||
$testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true);
|
||||||
$this->assertEquals($dbSize + 1, $testDB->count());
|
$this->assertEquals($dbSize + 1, $testDB->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,7 +763,7 @@ public function testSave()
|
||||||
public function testCountHiddenPublic()
|
public function testCountHiddenPublic()
|
||||||
{
|
{
|
||||||
$this->conf->set('privacy.hide_public_links', true);
|
$this->conf->set('privacy.hide_public_links', true);
|
||||||
$linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
|
$linkDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, false);
|
||||||
|
|
||||||
$this->assertEquals(0, $linkDB->count());
|
$this->assertEquals(0, $linkDB->count());
|
||||||
}
|
}
|
||||||
|
@ -807,7 +890,7 @@ public function testFilterString()
|
||||||
$request = ['searchtags' => $tags];
|
$request = ['searchtags' => $tags];
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
2,
|
2,
|
||||||
count($this->privateLinkDB->search($request, null, true))
|
count($this->privateLinkDB->search($request, null, true)->getBookmarks())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,7 +903,7 @@ public function testFilterArray()
|
||||||
$request = ['searchtags' => $tags];
|
$request = ['searchtags' => $tags];
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
2,
|
2,
|
||||||
count($this->privateLinkDB->search($request, null, true))
|
count($this->privateLinkDB->search($request, null, true)->getBookmarks())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,12 +917,12 @@ public function testHiddenTags()
|
||||||
$request = ['searchtags' => $tags];
|
$request = ['searchtags' => $tags];
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
1,
|
1,
|
||||||
count($this->privateLinkDB->search($request, 'all', true))
|
count($this->privateLinkDB->search($request, 'all', true)->getBookmarks())
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
0,
|
0,
|
||||||
count($this->publicLinkDB->search($request, 'public', true))
|
count($this->publicLinkDB->search($request, 'public', true)->getBookmarks())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +989,13 @@ public function testFilterHashWithPrivateKey()
|
||||||
$bookmark->addAdditionalContentEntry('private_key', $privateKey);
|
$bookmark->addAdditionalContentEntry('private_key', $privateKey);
|
||||||
$this->privateLinkDB->save();
|
$this->privateLinkDB->save();
|
||||||
|
|
||||||
$this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
|
$this->privateLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
false
|
||||||
|
);
|
||||||
$bookmark = $this->privateLinkDB->findByHash($hash, $privateKey);
|
$bookmark = $this->privateLinkDB->findByHash($hash, $privateKey);
|
||||||
|
|
||||||
static::assertSame(6, $bookmark->getId());
|
static::assertSame(6, $bookmark->getId());
|
||||||
|
@ -1152,7 +1241,13 @@ public function testGetLatestWithSticky(): void
|
||||||
public function testGetLatestEmptyDatastore(): void
|
public function testGetLatestEmptyDatastore(): void
|
||||||
{
|
{
|
||||||
unlink($this->conf->get('resource.datastore'));
|
unlink($this->conf->get('resource.datastore'));
|
||||||
$this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
|
$this->publicLinkDB = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
$bookmark = $this->publicLinkDB->getLatest();
|
$bookmark = $this->publicLinkDB->getLatest();
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
use ReferenceLinkDB;
|
use ReferenceLinkDB;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,19 +33,24 @@ class BookmarkFilterTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected static $bookmarkService;
|
protected static $bookmarkService;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected static $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate linkFilter with ReferenceLinkDB data.
|
* Instantiate linkFilter with ReferenceLinkDB data.
|
||||||
*/
|
*/
|
||||||
public static function setUpBeforeClass(): void
|
public static function setUpBeforeClass(): void
|
||||||
{
|
{
|
||||||
|
|
||||||
$mutex = new NoMutex();
|
$mutex = new NoMutex();
|
||||||
$conf = new ConfigManager('tests/utils/config/configJson');
|
$conf = new ConfigManager('tests/utils/config/configJson');
|
||||||
$conf->set('resource.datastore', self::$testDatastore);
|
$conf->set('resource.datastore', self::$testDatastore);
|
||||||
|
static::$pluginManager = new PluginManager($conf);
|
||||||
self::$refDB = new \ReferenceLinkDB();
|
self::$refDB = new \ReferenceLinkDB();
|
||||||
self::$refDB->write(self::$testDatastore);
|
self::$refDB->write(self::$testDatastore);
|
||||||
$history = new History('sandbox/history.php');
|
$history = new History('sandbox/history.php');
|
||||||
self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true);
|
self::$bookmarkService = new \FakeBookmarkService($conf, static::$pluginManager, $history, $mutex, true);
|
||||||
self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf);
|
self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf, static::$pluginManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -178,61 +184,6 @@ public function testFilterUnknownTag()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return bookmarks for a given day
|
|
||||||
*/
|
|
||||||
public function testFilterDay()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
4,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return bookmarks for a given day
|
|
||||||
*/
|
|
||||||
public function testFilterDayRestrictedVisibility(): void
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
3,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 404 - day not found
|
|
||||||
*/
|
|
||||||
public function testFilterUnknownDay()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
0,
|
|
||||||
count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '19700101'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use an invalid date format
|
|
||||||
*/
|
|
||||||
public function testFilterInvalidDayWithChars()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('/Invalid date format/');
|
|
||||||
|
|
||||||
self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use an invalid date format
|
|
||||||
*/
|
|
||||||
public function testFilterInvalidDayDigits()
|
|
||||||
{
|
|
||||||
$this->expectException(\Exception::class);
|
|
||||||
$this->expectExceptionMessageRegExp('/Invalid date format/');
|
|
||||||
|
|
||||||
self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a link entry with its hash
|
* Retrieve a link entry with its hash
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use malkusch\lock\mutex\NoMutex;
|
use malkusch\lock\mutex\NoMutex;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,6 +39,9 @@ class BookmarkInitializerTest extends TestCase
|
||||||
/** @var NoMutex */
|
/** @var NoMutex */
|
||||||
protected $mutex;
|
protected $mutex;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize an empty BookmarkFileService
|
* Initialize an empty BookmarkFileService
|
||||||
*/
|
*/
|
||||||
|
@ -51,8 +55,15 @@ public function setUp(): void
|
||||||
copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
|
copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
|
||||||
$this->conf = new ConfigManager(self::$testConf);
|
$this->conf = new ConfigManager(self::$testConf);
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
$this->conf->set('resource.datastore', self::$testDatastore);
|
||||||
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
$this->history = new History('sandbox/history.php');
|
$this->history = new History('sandbox/history.php');
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +75,13 @@ public function testInitializeNotEmptyDataStore(): void
|
||||||
{
|
{
|
||||||
$refDB = new \ReferenceLinkDB();
|
$refDB = new \ReferenceLinkDB();
|
||||||
$refDB->write(self::$testDatastore);
|
$refDB->write(self::$testDatastore);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
$this->initializer = new BookmarkInitializer($this->bookmarkService);
|
||||||
|
|
||||||
$this->initializer->initialize();
|
$this->initializer->initialize();
|
||||||
|
@ -95,7 +112,13 @@ public function testInitializeNotEmptyDataStore(): void
|
||||||
$this->bookmarkService->save();
|
$this->bookmarkService->save();
|
||||||
|
|
||||||
// Reload from file
|
// Reload from file
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
|
$this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
|
||||||
|
|
||||||
$bookmark = $this->bookmarkService->get(43);
|
$bookmark = $this->bookmarkService->get(43);
|
||||||
|
@ -126,7 +149,13 @@ public function testInitializeNotEmptyDataStore(): void
|
||||||
public function testInitializeNonExistentDataStore(): void
|
public function testInitializeNonExistentDataStore(): void
|
||||||
{
|
{
|
||||||
$this->conf->set('resource.datastore', static::$testDatastore . '_empty');
|
$this->conf->set('resource.datastore', static::$testDatastore . '_empty');
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$this->mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
$this->initializer->initialize();
|
$this->initializer->initialize();
|
||||||
|
|
||||||
|
|
125
tests/bookmark/SearchResultTest.php
Normal file
125
tests/bookmark/SearchResultTest.php
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shaarli\Bookmark;
|
||||||
|
|
||||||
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test SearchResult class.
|
||||||
|
*/
|
||||||
|
class SearchResultTest extends TestCase
|
||||||
|
{
|
||||||
|
/** Create a SearchResult without any pagination parameter. */
|
||||||
|
public function testResultNoParameters(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult($data = ['a', 'b', 'c', 'd', 'e', 'f']);
|
||||||
|
|
||||||
|
static::assertSame($data, $searchResult->getBookmarks());
|
||||||
|
static::assertSame(6, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(null, $searchResult->getLimit());
|
||||||
|
static::assertSame(0, $searchResult->getOffset());
|
||||||
|
static::assertSame(1, $searchResult->getPage());
|
||||||
|
static::assertSame(1, $searchResult->getLastPage());
|
||||||
|
static::assertTrue($searchResult->isFirstPage());
|
||||||
|
static::assertTrue($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with only an offset parameter */
|
||||||
|
public function testResultWithOffset(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2);
|
||||||
|
|
||||||
|
static::assertSame([2 => 'c', 3 => 'd', 4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(4, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(null, $searchResult->getLimit());
|
||||||
|
static::assertSame(2, $searchResult->getOffset());
|
||||||
|
static::assertSame(2, $searchResult->getPage());
|
||||||
|
static::assertSame(2, $searchResult->getLastPage());
|
||||||
|
static::assertFalse($searchResult->isFirstPage());
|
||||||
|
static::assertTrue($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with only a limit parameter */
|
||||||
|
public function testResultWithLimit(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 0, 2);
|
||||||
|
|
||||||
|
static::assertSame([0 => 'a', 1 => 'b'], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(2, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(2, $searchResult->getLimit());
|
||||||
|
static::assertSame(0, $searchResult->getOffset());
|
||||||
|
static::assertSame(1, $searchResult->getPage());
|
||||||
|
static::assertSame(3, $searchResult->getLastPage());
|
||||||
|
static::assertTrue($searchResult->isFirstPage());
|
||||||
|
static::assertFalse($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with offset and limit parameters */
|
||||||
|
public function testResultWithLimitAndOffset(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2, 2);
|
||||||
|
|
||||||
|
static::assertSame([2 => 'c', 3 => 'd'], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(2, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(2, $searchResult->getLimit());
|
||||||
|
static::assertSame(2, $searchResult->getOffset());
|
||||||
|
static::assertSame(2, $searchResult->getPage());
|
||||||
|
static::assertSame(3, $searchResult->getLastPage());
|
||||||
|
static::assertFalse($searchResult->isFirstPage());
|
||||||
|
static::assertFalse($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with offset and limit parameters displaying the last page */
|
||||||
|
public function testResultWithLimitAndOffsetLastPage(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 4, 2);
|
||||||
|
|
||||||
|
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(2, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(2, $searchResult->getLimit());
|
||||||
|
static::assertSame(4, $searchResult->getOffset());
|
||||||
|
static::assertSame(3, $searchResult->getPage());
|
||||||
|
static::assertSame(3, $searchResult->getLastPage());
|
||||||
|
static::assertFalse($searchResult->isFirstPage());
|
||||||
|
static::assertTrue($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with offset and limit parameters out of bound (display the last page) */
|
||||||
|
public function testResultWithLimitAndOffsetOutOfBounds(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2);
|
||||||
|
|
||||||
|
static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(2, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(2, $searchResult->getLimit());
|
||||||
|
static::assertSame(-2, $searchResult->getOffset());
|
||||||
|
static::assertSame(3, $searchResult->getPage());
|
||||||
|
static::assertSame(3, $searchResult->getLastPage());
|
||||||
|
static::assertFalse($searchResult->isFirstPage());
|
||||||
|
static::assertTrue($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a SearchResult with offset and limit parameters out of bound (no result) */
|
||||||
|
public function testResultWithLimitAndOffsetOutOfBoundsNoResult(): void
|
||||||
|
{
|
||||||
|
$searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2, true);
|
||||||
|
|
||||||
|
static::assertSame([], $searchResult->getBookmarks());
|
||||||
|
static::assertSame(0, $searchResult->getResultCount());
|
||||||
|
static::assertSame(6, $searchResult->getTotalCount());
|
||||||
|
static::assertSame(2, $searchResult->getLimit());
|
||||||
|
static::assertSame(12, $searchResult->getOffset());
|
||||||
|
static::assertSame(7, $searchResult->getPage());
|
||||||
|
static::assertSame(3, $searchResult->getLastPage());
|
||||||
|
static::assertFalse($searchResult->isFirstPage());
|
||||||
|
static::assertFalse($searchResult->isLastPage());
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
use Shaarli\Formatter\FormatterFactory;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,8 +56,15 @@ public static function setUpBeforeClass(): void
|
||||||
$refLinkDB->write(self::$testDatastore);
|
$refLinkDB->write(self::$testDatastore);
|
||||||
$history = new History('sandbox/history.php');
|
$history = new History('sandbox/history.php');
|
||||||
$factory = new FormatterFactory($conf, true);
|
$factory = new FormatterFactory($conf, true);
|
||||||
|
$pluginManager = new PluginManager($conf);
|
||||||
self::$formatter = $factory->getFormatter();
|
self::$formatter = $factory->getFormatter();
|
||||||
self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true);
|
self::$bookmarkService = new BookmarkFileService(
|
||||||
|
$conf,
|
||||||
|
$pluginManager,
|
||||||
|
$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
self::$serverInfo = array(
|
self::$serverInfo = array(
|
||||||
'HTTPS' => 'Off',
|
'HTTPS' => 'Off',
|
||||||
|
|
|
@ -211,13 +211,17 @@ public function testFormatDescriptionWithSearchHighlight(): void
|
||||||
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
$this->formatter = new BookmarkDefaultFormatter($this->conf, false);
|
||||||
|
|
||||||
$bookmark = new Bookmark();
|
$bookmark = new Bookmark();
|
||||||
$bookmark->setDescription('This guide extends and expands on PSR-1, the basic coding standard.');
|
$bookmark->setDescription(
|
||||||
|
'This guide extends and expands on PSR-1, the basic coding standard.' . PHP_EOL .
|
||||||
|
'https://www.php-fig.org/psr/psr-1/'
|
||||||
|
);
|
||||||
$bookmark->addAdditionalContentEntry(
|
$bookmark->addAdditionalContentEntry(
|
||||||
'search_highlight',
|
'search_highlight',
|
||||||
['description' => [
|
['description' => [
|
||||||
['start' => 0, 'end' => 10], // "This guide"
|
['start' => 0, 'end' => 10], // "This guide"
|
||||||
['start' => 45, 'end' => 50], // basic
|
['start' => 45, 'end' => 50], // basic
|
||||||
['start' => 58, 'end' => 67], // standard.
|
['start' => 58, 'end' => 67], // standard.
|
||||||
|
['start' => 84, 'end' => 87], // fig
|
||||||
]]
|
]]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -226,7 +230,10 @@ public function testFormatDescriptionWithSearchHighlight(): void
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'<span class="search-highlight">This guide</span> extends and expands on PSR-1, the ' .
|
'<span class="search-highlight">This guide</span> extends and expands on PSR-1, the ' .
|
||||||
'<span class="search-highlight">basic</span> coding ' .
|
'<span class="search-highlight">basic</span> coding ' .
|
||||||
'<span class="search-highlight">standard.</span>',
|
'<span class="search-highlight">standard.</span><br />' . PHP_EOL .
|
||||||
|
'<a href="https://www.php-fig.org/psr/psr-1/">' .
|
||||||
|
'https://www.php-<span class="search-highlight">fig</span>.org/psr/psr-1/' .
|
||||||
|
'</a>',
|
||||||
$link['description']
|
$link['description']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,49 @@ public function testFormatDescription()
|
||||||
$this->assertEquals($description, $link['description']);
|
$this->assertEquals($description, $link['description']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that the description is properly formatted by the default formatter.
|
||||||
|
*/
|
||||||
|
public function testFormatDescriptionWithSearchHighlight()
|
||||||
|
{
|
||||||
|
$description = 'This a <strong>description</strong>'. PHP_EOL;
|
||||||
|
$description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL;
|
||||||
|
$description .= 'Also, there is an #hashtag added'. PHP_EOL;
|
||||||
|
$description .= ' A N D KEEP SPACES ! '. PHP_EOL;
|
||||||
|
$description .= 'And [yet another link](https://other.domain.tld)'. PHP_EOL;
|
||||||
|
|
||||||
|
$bookmark = new Bookmark();
|
||||||
|
$bookmark->setDescription($description);
|
||||||
|
$bookmark->addAdditionalContentEntry(
|
||||||
|
'search_highlight',
|
||||||
|
['description' => [
|
||||||
|
['start' => 18, 'end' => 26], // cription
|
||||||
|
['start' => 49, 'end' => 52], // sub
|
||||||
|
['start' => 84, 'end' => 88], // hash
|
||||||
|
['start' => 118, 'end' => 123], // hasht
|
||||||
|
['start' => 203, 'end' => 215], // other.domain
|
||||||
|
]]
|
||||||
|
);
|
||||||
|
|
||||||
|
$link = $this->formatter->format($bookmark);
|
||||||
|
|
||||||
|
$description = '<div class="markdown"><p>';
|
||||||
|
$description .= 'This a <strong>des<span class="search-highlight">cription</span></strong><br />' .
|
||||||
|
PHP_EOL;
|
||||||
|
$url = 'https://sub.domain.tld?query=here&for=real#hash';
|
||||||
|
$highlighted = 'https://<span class="search-highlight">sub</span>.domain.tld';
|
||||||
|
$highlighted .= '?query=here&for=real#<span class="search-highlight">hash</span>';
|
||||||
|
$description .= 'text <a href="'. $url .'">'. $highlighted .'</a> more text<br />'. PHP_EOL;
|
||||||
|
$description .= 'Also, there is an <a href="./add-tag/hashtag">#<span class="search-highlight">hasht</span>' .
|
||||||
|
'ag</a> added<br />'. PHP_EOL;
|
||||||
|
$description .= 'A N D KEEP SPACES !<br />' . PHP_EOL;
|
||||||
|
$description .= 'And <a href="https://other.domain.tld">' .
|
||||||
|
'<span class="search-highlight">yet another link</span></a>';
|
||||||
|
$description .= '</p></div>';
|
||||||
|
|
||||||
|
$this->assertEquals($description, $link['description']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test formatting URL with an index_url set
|
* Test formatting URL with an index_url set
|
||||||
* It should prepend relative links.
|
* It should prepend relative links.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Bookmark\BookmarkFilter;
|
use Shaarli\Bookmark\BookmarkFilter;
|
||||||
|
use Shaarli\Bookmark\SearchResult;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Front\Exception\WrongTokenException;
|
use Shaarli\Front\Exception\WrongTokenException;
|
||||||
use Shaarli\Security\SessionManager;
|
use Shaarli\Security\SessionManager;
|
||||||
|
@ -100,11 +101,11 @@ public function testSaveRenameTagValid(): void
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
||||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): array {
|
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
||||||
$bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
$bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
||||||
$bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
$bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag');
|
||||||
|
|
||||||
return [$bookmark1, $bookmark2];
|
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
|
@ -153,11 +154,11 @@ public function testSaveDeleteTagValid(): void
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true)
|
||||||
->willReturnCallback(function () use ($bookmark1, $bookmark2): array {
|
->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult {
|
||||||
$bookmark1->expects(static::once())->method('deleteTag')->with('old-tag');
|
$bookmark1->expects(static::once())->method('deleteTag')->with('old-tag');
|
||||||
$bookmark2->expects(static::once())->method('deleteTag')->with('old-tag');
|
$bookmark2->expects(static::once())->method('deleteTag')->with('old-tag');
|
||||||
|
|
||||||
return [$bookmark1, $bookmark2];
|
return SearchResult::getSearchResult([$bookmark1, $bookmark2]);
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
|
|
|
@ -363,6 +363,7 @@ public function testDeleteBookmarkFromBookmarklet(): void
|
||||||
$this->container->bookmarkService->method('get')->with('123')->willReturn(
|
$this->container->bookmarkService->method('get')->with('123')->willReturn(
|
||||||
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
||||||
);
|
);
|
||||||
|
$this->container->bookmarkService->expects(static::once())->method('remove');
|
||||||
|
|
||||||
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
||||||
$this->container->formatterFactory
|
$this->container->formatterFactory
|
||||||
|
@ -379,6 +380,48 @@ public function testDeleteBookmarkFromBookmarklet(): void
|
||||||
$result = $this->controller->deleteBookmark($request, $response);
|
$result = $this->controller->deleteBookmark($request, $response);
|
||||||
|
|
||||||
static::assertSame(200, $result->getStatusCode());
|
static::assertSame(200, $result->getStatusCode());
|
||||||
static::assertSame('<script>self.close();</script>', (string) $result->getBody('location'));
|
static::assertSame('<script>self.close();</script>', (string) $result->getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete bookmark - from batch view
|
||||||
|
*/
|
||||||
|
public function testDeleteBookmarkFromBatch(): void
|
||||||
|
{
|
||||||
|
$parameters = [
|
||||||
|
'id' => '123',
|
||||||
|
'source' => 'batch',
|
||||||
|
];
|
||||||
|
|
||||||
|
$request = $this->createMock(Request::class);
|
||||||
|
$request
|
||||||
|
->method('getParam')
|
||||||
|
->willReturnCallback(function (string $key) use ($parameters): ?string {
|
||||||
|
return $parameters[$key] ?? null;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
$response = new Response();
|
||||||
|
|
||||||
|
$this->container->bookmarkService->method('get')->with('123')->willReturn(
|
||||||
|
(new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
|
||||||
|
);
|
||||||
|
$this->container->bookmarkService->expects(static::once())->method('remove');
|
||||||
|
|
||||||
|
$this->container->formatterFactory = $this->createMock(FormatterFactory::class);
|
||||||
|
$this->container->formatterFactory
|
||||||
|
->expects(static::once())
|
||||||
|
->method('getFormatter')
|
||||||
|
->willReturnCallback(function (): BookmarkFormatter {
|
||||||
|
$formatter = $this->createMock(BookmarkFormatter::class);
|
||||||
|
$formatter->method('format')->willReturn(['formatted']);
|
||||||
|
|
||||||
|
return $formatter;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
$result = $this->controller->deleteBookmark($request, $response);
|
||||||
|
|
||||||
|
static::assertSame(204, $result->getStatusCode());
|
||||||
|
static::assertEmpty((string) $result->getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
||||||
|
use Shaarli\Bookmark\SearchResult;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
use Shaarli\Thumbnailer;
|
use Shaarli\Thumbnailer;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -40,12 +41,12 @@ public function testIndex(): void
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->willReturn([
|
->willReturn(SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||||
(new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'),
|
(new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'),
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
(new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||||
(new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'),
|
(new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'),
|
||||||
])
|
]))
|
||||||
;
|
;
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
$result = $this->controller->index($request, $response);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
|
||||||
|
use Shaarli\Bookmark\SearchResult;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Security\LoginManager;
|
use Shaarli\Security\LoginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
@ -45,13 +46,15 @@ public function testIndexDefaultFirstPage(): void
|
||||||
['searchtags' => '', 'searchterm' => ''],
|
['searchtags' => '', 'searchterm' => ''],
|
||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
false,
|
||||||
|
['offset' => 0, 'limit' => 2]
|
||||||
)
|
)
|
||||||
->willReturn([
|
->willReturn(SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||||
]
|
], 0, 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->container->sessionManager
|
$this->container->sessionManager
|
||||||
|
@ -119,13 +122,15 @@ public function testIndexDefaultSecondPage(): void
|
||||||
['searchtags' => '', 'searchterm' => ''],
|
['searchtags' => '', 'searchterm' => ''],
|
||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
false,
|
||||||
|
['offset' => 2, 'limit' => 2]
|
||||||
)
|
)
|
||||||
->willReturn([
|
->willReturn(SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||||
])
|
], 2, 2))
|
||||||
;
|
;
|
||||||
|
|
||||||
$this->container->sessionManager
|
$this->container->sessionManager
|
||||||
|
@ -207,13 +212,15 @@ public function testIndexDefaultWithFilters(): void
|
||||||
['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
|
['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
|
||||||
'private',
|
'private',
|
||||||
false,
|
false,
|
||||||
true
|
true,
|
||||||
|
false,
|
||||||
|
['offset' => 0, 'limit' => 2]
|
||||||
)
|
)
|
||||||
->willReturn([
|
->willReturn(SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
(new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'),
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
(new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'),
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'),
|
||||||
])
|
], 0, 2))
|
||||||
;
|
;
|
||||||
|
|
||||||
$result = $this->controller->index($request, $response);
|
$result = $this->controller->index($request, $response);
|
||||||
|
@ -358,13 +365,13 @@ public function testThumbnailUpdateFromLinkList(): void
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->willReturn([
|
->willReturn(SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
|
(new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false),
|
||||||
$b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
|
$b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'),
|
||||||
(new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
|
(new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false),
|
||||||
$b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
|
$b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'),
|
||||||
(new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
|
(new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'),
|
||||||
])
|
]))
|
||||||
;
|
;
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
->expects(static::exactly(2))
|
->expects(static::exactly(2))
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
namespace Shaarli\Front\Controller\Visitor;
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
|
use Shaarli\Bookmark\SearchResult;
|
||||||
use Shaarli\Feed\CachedPage;
|
use Shaarli\Feed\CachedPage;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -347,13 +348,15 @@ public function testValidRssControllerInvokeDefault(): void
|
||||||
$request = $this->createMock(Request::class);
|
$request = $this->createMock(Request::class);
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||||
(new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
|
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||||
(new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'),
|
(new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
|
||||||
]);
|
(new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
$this->container->pageCacheManager
|
$this->container->pageCacheManager
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
|
@ -454,7 +457,9 @@ public function testValidRssControllerInvokeNoBookmark(): void
|
||||||
$request = $this->createMock(Request::class);
|
$request = $this->createMock(Request::class);
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]);
|
$this->container->bookmarkService
|
||||||
|
->expects(static::once())->method('search')
|
||||||
|
->willReturn(SearchResult::getSearchResult([]));
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
// Save RainTPL assigned variables
|
||||||
$assignedVariables = [];
|
$assignedVariables = [];
|
||||||
|
@ -613,11 +618,13 @@ public function testSimpleRssWeekly(): void
|
||||||
});
|
});
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||||
]);
|
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
// Save RainTPL assigned variables
|
||||||
$assignedVariables = [];
|
$assignedVariables = [];
|
||||||
|
@ -674,11 +681,13 @@ public function testSimpleRssMonthly(): void
|
||||||
});
|
});
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
|
||||||
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
|
$this->container->bookmarkService->expects(static::once())->method('search')->willReturn(
|
||||||
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
(new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
|
||||||
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
(new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
|
||||||
]);
|
(new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
// Save RainTPL assigned variables
|
// Save RainTPL assigned variables
|
||||||
$assignedVariables = [];
|
$assignedVariables = [];
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
namespace Shaarli\Front\Controller\Visitor;
|
namespace Shaarli\Front\Controller\Visitor;
|
||||||
|
|
||||||
use Shaarli\Bookmark\Bookmark;
|
use Shaarli\Bookmark\Bookmark;
|
||||||
|
use Shaarli\Bookmark\SearchResult;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\Front\Exception\ThumbnailsDisabledException;
|
use Shaarli\Front\Exception\ThumbnailsDisabledException;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
@ -50,17 +51,17 @@ public function testValidControllerInvokeDefault(): void
|
||||||
$this->container->bookmarkService
|
$this->container->bookmarkService
|
||||||
->expects(static::once())
|
->expects(static::once())
|
||||||
->method('search')
|
->method('search')
|
||||||
->willReturnCallback(function (array $parameters, ?string $visibility): array {
|
->willReturnCallback(function (array $parameters, ?string $visibility): SearchResult {
|
||||||
// Visibility is set through the container, not the call
|
// Visibility is set through the container, not the call
|
||||||
static::assertNull($visibility);
|
static::assertNull($visibility);
|
||||||
|
|
||||||
// No query parameters
|
// No query parameters
|
||||||
if (count($parameters) === 0) {
|
if (count($parameters) === 0) {
|
||||||
return [
|
return SearchResult::getSearchResult([
|
||||||
(new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'),
|
(new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'),
|
||||||
(new Bookmark())->setId(2)->setUrl('http://url2.tld'),
|
(new Bookmark())->setId(2)->setUrl('http://url2.tld'),
|
||||||
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'),
|
(new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'),
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
|
|
@ -93,6 +93,9 @@ public function testRender(): void
|
||||||
|
|
||||||
static::assertSame('templateName', $render);
|
static::assertSame('templateName', $render);
|
||||||
|
|
||||||
|
static::assertSame('templateName', $this->assignedValues['_PAGE_']);
|
||||||
|
static::assertSame('templateName', $this->assignedValues['template']);
|
||||||
|
|
||||||
static::assertSame(10, $this->assignedValues['linkcount']);
|
static::assertSame(10, $this->assignedValues['linkcount']);
|
||||||
static::assertSame(5, $this->assignedValues['privateLinkcount']);
|
static::assertSame(5, $this->assignedValues['privateLinkcount']);
|
||||||
static::assertSame(['error'], $this->assignedValues['plugin_errors']);
|
static::assertSame(['error'], $this->assignedValues['plugin_errors']);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use Shaarli\Formatter\BookmarkFormatter;
|
use Shaarli\Formatter\BookmarkFormatter;
|
||||||
use Shaarli\Formatter\FormatterFactory;
|
use Shaarli\Formatter\FormatterFactory;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
require_once 'tests/utils/ReferenceLinkDB.php';
|
require_once 'tests/utils/ReferenceLinkDB.php';
|
||||||
|
@ -47,6 +48,9 @@ class BookmarkExportTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected static $history;
|
protected static $history;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected static $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var NetscapeBookmarkUtils
|
* @var NetscapeBookmarkUtils
|
||||||
*/
|
*/
|
||||||
|
@ -63,7 +67,14 @@ public static function setUpBeforeClass(): void
|
||||||
static::$refDb = new \ReferenceLinkDB();
|
static::$refDb = new \ReferenceLinkDB();
|
||||||
static::$refDb->write(static::$testDatastore);
|
static::$refDb->write(static::$testDatastore);
|
||||||
static::$history = new History('sandbox/history.php');
|
static::$history = new History('sandbox/history.php');
|
||||||
static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true);
|
static::$pluginManager = new PluginManager(static::$conf);
|
||||||
|
static::$bookmarkService = new BookmarkFileService(
|
||||||
|
static::$conf,
|
||||||
|
static::$pluginManager,
|
||||||
|
static::$history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$factory = new FormatterFactory(static::$conf, true);
|
$factory = new FormatterFactory(static::$conf, true);
|
||||||
static::$formatter = $factory->getFormatter('raw');
|
static::$formatter = $factory->getFormatter('raw');
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkFilter;
|
use Shaarli\Bookmark\BookmarkFilter;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
use Slim\Http\UploadedFile;
|
use Slim\Http\UploadedFile;
|
||||||
|
|
||||||
|
@ -71,6 +72,9 @@ class BookmarkImportTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected $netscapeBookmarkUtils;
|
protected $netscapeBookmarkUtils;
|
||||||
|
|
||||||
|
/** @var PluginManager */
|
||||||
|
protected $pluginManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Save the current timezone.
|
* @var string Save the current timezone.
|
||||||
*/
|
*/
|
||||||
|
@ -99,7 +103,14 @@ protected function setUp(): void
|
||||||
$this->conf->set('resource.page_cache', $this->pagecache);
|
$this->conf->set('resource.page_cache', $this->pagecache);
|
||||||
$this->conf->set('resource.datastore', self::$testDatastore);
|
$this->conf->set('resource.datastore', self::$testDatastore);
|
||||||
$this->history = new History(self::$historyFilePath);
|
$this->history = new History(self::$historyFilePath);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
|
$this->pluginManager = new PluginManager($this->conf);
|
||||||
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->pluginManager,
|
||||||
|
$this->history,
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
|
$this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Shaarli\Bookmark\Bookmark;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for test.
|
* Hook for test.
|
||||||
*
|
*
|
||||||
|
@ -43,3 +45,8 @@ function test_register_routes(): array
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hook_test_filter_search_entry(Bookmark $bookmark, array $context): bool
|
||||||
|
{
|
||||||
|
return $context['_result'];
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
use Shaarli\Bookmark\BookmarkServiceInterface;
|
use Shaarli\Bookmark\BookmarkServiceInterface;
|
||||||
use Shaarli\Config\ConfigManager;
|
use Shaarli\Config\ConfigManager;
|
||||||
use Shaarli\History;
|
use Shaarli\History;
|
||||||
|
use Shaarli\Plugin\PluginManager;
|
||||||
use Shaarli\TestCase;
|
use Shaarli\TestCase;
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +52,13 @@ protected function setUp(): void
|
||||||
|
|
||||||
copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
|
copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
|
||||||
$this->conf = new ConfigManager(self::$configFile);
|
$this->conf = new ConfigManager(self::$configFile);
|
||||||
$this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true);
|
$this->bookmarkService = new BookmarkFileService(
|
||||||
|
$this->conf,
|
||||||
|
$this->createMock(PluginManager::class),
|
||||||
|
$this->createMock(History::class),
|
||||||
|
$mutex,
|
||||||
|
true
|
||||||
|
);
|
||||||
$this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
|
$this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loop="$links"}
|
{loop="$links"}
|
||||||
|
{$batchId=$key}
|
||||||
{include="editlink"}
|
{include="editlink"}
|
||||||
{/loop}
|
{/loop}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{$batchId=isset($batchId) ? $batchId : ''}
|
||||||
{if="empty($batch_mode)"}
|
{if="empty($batch_mode)"}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
{ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore}
|
{ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore}
|
||||||
{function="extract($value) ? '' : ''"}
|
{function="extract($value) ? '' : ''"}
|
||||||
{/if}
|
{/if}
|
||||||
<div id="editlinkform" class="edit-link-container" class="pure-g">
|
<div id="editlinkform{$batchId}" class="edit-link-container" class="pure-g">
|
||||||
<div class="pure-u-lg-1-5 pure-u-1-24"></div>
|
<div class="pure-u-lg-1-5 pure-u-1-24"></div>
|
||||||
<form method="post"
|
<form method="post"
|
||||||
name="linkform"
|
name="linkform"
|
||||||
|
@ -27,16 +28,16 @@ <h2 class="window-title">
|
||||||
{/if}
|
{/if}
|
||||||
{if="!$link_is_new"}<div class="created-date">{'Created:'|t} {$link.created|format_date}</div>{/if}
|
{if="!$link_is_new"}<div class="created-date">{'Created:'|t} {$link.created|format_date}</div>{/if}
|
||||||
<div>
|
<div>
|
||||||
<label for="lf_url">{'URL'|t}</label>
|
<label for="lf_url{$batchId}">{'URL'|t}</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" name="lf_url" id="lf_url" value="{$link.url}" class="lf_input">
|
<input type="text" name="lf_url" id="lf_url{$batchId}" value="{$link.url}" class="lf_input">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="lf_title">{'Title'|t}</label>
|
<label for="lf_title{$batchId}">{'Title'|t}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="{$asyncLoadClass}">
|
<div class="{$asyncLoadClass}">
|
||||||
<input type="text" name="lf_title" id="lf_title" value="{$link.title}"
|
<input type="text" name="lf_title" id="lf_title{$batchId}" value="{$link.title}"
|
||||||
class="lf_input {if="!$async_metadata"}autofocus{/if}"
|
class="lf_input {if="!$async_metadata"}autofocus{/if}"
|
||||||
>
|
>
|
||||||
<div class="icon-container">
|
<div class="icon-container">
|
||||||
|
@ -44,19 +45,19 @@ <h2 class="window-title">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="lf_description">{'Description'|t}</label>
|
<label for="lf_description{$batchId}">{'Description'|t}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
||||||
<textarea name="lf_description" id="lf_description" class="autofocus">{$link.description}</textarea>
|
<textarea name="lf_description" id="lf_description{$batchId}" class="autofocus">{$link.description}</textarea>
|
||||||
<div class="icon-container">
|
<div class="icon-container">
|
||||||
<i class="loader"></i>
|
<i class="loader"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="lf_tags">{'Tags'|t}</label>
|
<label for="lf_tags{$batchId}">{'Tags'|t}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
|
||||||
<input type="text" name="lf_tags" id="lf_tags" value="{$link.tags}" class="lf_input autofocus"
|
<input type="text" name="lf_tags" id="lf_tags{$batchId}" value="{$link.tags}" class="lf_input autofocus"
|
||||||
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" >
|
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" >
|
||||||
<div class="icon-container">
|
<div class="icon-container">
|
||||||
<i class="loader"></i>
|
<i class="loader"></i>
|
||||||
|
@ -64,11 +65,11 @@ <h2 class="window-title">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" name="lf_private" id="lf_private"
|
<input type="checkbox" name="lf_private" id="lf_private{$batchId}"
|
||||||
{if="$link.private === true"}
|
{if="$link.private === true"}
|
||||||
checked="checked"
|
checked="checked"
|
||||||
{/if}>
|
{/if}>
|
||||||
<label for="lf_private">{'Private'|t}</label>
|
<label for="lf_private{$batchId}">{'Private'|t}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{if="$formatter==='markdown'"}
|
{if="$formatter==='markdown'"}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
|
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
|
||||||
title="Shaarli search - {$shaarlititle}" />
|
title="Shaarli search - {$shaarlititle}" />
|
||||||
{if="! empty($links) && count($links) === 1"}
|
{if="$template === 'linklist' && ! empty($links) && count($links) === 1"}
|
||||||
{$link=reset($links)}
|
{$link=reset($links)}
|
||||||
<meta property="og:title" content="{$link.title}" />
|
<meta property="og:title" content="{$link.title}" />
|
||||||
<meta property="og:type" content="article" />
|
<meta property="og:type" content="article" />
|
||||||
|
|
|
@ -56,11 +56,11 @@ <h3 class="window-subtitle">{'General'|t}</h3>
|
||||||
|
|
||||||
{include="server.requirements"}
|
{include="server.requirements"}
|
||||||
|
|
||||||
<h3 class="window-subtitle">Version</h3>
|
<h3 class="window-subtitle">{'Version'|t}</h3>
|
||||||
|
|
||||||
<div class="pure-g server-row">
|
<div class="pure-g server-row">
|
||||||
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
||||||
<p>Current version</p>
|
<p>{'Current version'|t}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-lg-1-2 pure-u-1">
|
<div class="pure-u-lg-1-2 pure-u-1">
|
||||||
<p>{$current_version}</p>
|
<p>{$current_version}</p>
|
||||||
|
@ -69,7 +69,7 @@ <h3 class="window-subtitle">Version</h3>
|
||||||
|
|
||||||
<div class="pure-g server-row">
|
<div class="pure-g server-row">
|
||||||
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
||||||
<p>Latest release</p>
|
<p>{'Latest release'|t}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-lg-1-2 pure-u-1">
|
<div class="pure-u-lg-1-2 pure-u-1">
|
||||||
<p>
|
<p>
|
||||||
|
@ -80,11 +80,11 @@ <h3 class="window-subtitle">Version</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="window-subtitle">Thumbnails</h3>
|
<h3 class="window-subtitle">{'Thumbnails'|t}</h3>
|
||||||
|
|
||||||
<div class="pure-g server-row">
|
<div class="pure-g server-row">
|
||||||
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
<div class="pure-u-lg-1-2 pure-u-1 server-label">
|
||||||
<p>Thumbnails status</p>
|
<p>{'Thumbnails status'|t}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-lg-1-2 pure-u-1">
|
<div class="pure-u-lg-1-2 pure-u-1">
|
||||||
<p>
|
<p>
|
||||||
|
@ -107,17 +107,17 @@ <h3 class="window-subtitle">Thumbnails</h3>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<h3 class="window-subtitle">Cache</h3>
|
<h3 class="window-subtitle">{'Cache'|t}</h3>
|
||||||
|
|
||||||
<div class="center tools-item">
|
<div class="center tools-item">
|
||||||
<a href="{$base_path}/admin/clear-cache?type=main">
|
<a href="{$base_path}/admin/clear-cache?type=main">
|
||||||
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Clear main cache</span>
|
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Clear main cache'|t}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="center tools-item">
|
<div class="center tools-item">
|
||||||
<a href="{$base_path}/admin/clear-cache?type=thumbnails">
|
<a href="{$base_path}/admin/clear-cache?type=thumbnails">
|
||||||
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">Clear thumbnails cache</span>
|
<span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Clear thumbnails cache'|t}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
{if="is_file('data/user.css')"}<link type="text/css" rel="stylesheet" href="{$base_path}/data/user.css#" />{/if}
|
{if="is_file('data/user.css')"}<link type="text/css" rel="stylesheet" href="{$base_path}/data/user.css#" />{/if}
|
||||||
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
|
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
|
||||||
title="Shaarli search - {$shaarlititle|htmlspecialchars}" />
|
title="Shaarli search - {$shaarlititle|htmlspecialchars}" />
|
||||||
{if="! empty($links) && count($links) === 1"}
|
{if="$template === 'linklist' && ! empty($links) && count($links) === 1"}
|
||||||
{$link=reset($links)}
|
{$link=reset($links)}
|
||||||
<meta property="og:title" content="{$link.title}" />
|
<meta property="og:title" content="{$link.title}" />
|
||||||
<meta property="og:type" content="article" />
|
<meta property="og:type" content="article" />
|
||||||
|
|
38
yarn.lock
38
yarn.lock
|
@ -1369,10 +1369,10 @@ bluebird@^3.5.5:
|
||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||||
|
|
||||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0:
|
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
|
||||||
version "4.11.9"
|
version "4.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
|
||||||
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
|
integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
|
||||||
|
|
||||||
bn.js@^5.1.1:
|
bn.js@^5.1.1:
|
||||||
version "5.1.3"
|
version "5.1.3"
|
||||||
|
@ -1410,7 +1410,7 @@ braces@^3.0.1, braces@~3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
brorand@^1.0.1:
|
brorand@^1.0.1, brorand@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||||
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
||||||
|
@ -2130,17 +2130,17 @@ electron-to-chromium@^1.3.570:
|
||||||
integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg==
|
integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg==
|
||||||
|
|
||||||
elliptic@^6.5.3:
|
elliptic@^6.5.3:
|
||||||
version "6.5.3"
|
version "6.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
|
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
|
||||||
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
|
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
bn.js "^4.4.0"
|
bn.js "^4.11.9"
|
||||||
brorand "^1.0.1"
|
brorand "^1.1.0"
|
||||||
hash.js "^1.0.0"
|
hash.js "^1.0.0"
|
||||||
hmac-drbg "^1.0.0"
|
hmac-drbg "^1.0.1"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.4"
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.1"
|
||||||
minimalistic-crypto-utils "^1.0.0"
|
minimalistic-crypto-utils "^1.0.1"
|
||||||
|
|
||||||
emoji-regex@^7.0.1:
|
emoji-regex@^7.0.1:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
|
@ -2917,7 +2917,7 @@ he@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||||
|
|
||||||
hmac-drbg@^1.0.0:
|
hmac-drbg@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||||
integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
|
integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
|
||||||
|
@ -3714,7 +3714,7 @@ minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||||
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
||||||
|
|
||||||
minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
|
minimalistic-crypto-utils@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
|
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
|
||||||
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
|
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
|
||||||
|
@ -5980,9 +5980,9 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
|
||||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||||
|
|
||||||
y18n@^4.0.0:
|
y18n@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
|
||||||
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
|
integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
|
||||||
|
|
||||||
yallist@^3.0.2:
|
yallist@^3.0.2:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
|
|
Loading…
Reference in a new issue