Refactor stuff into services

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
Marcel Klehr 2019-10-22 22:01:09 +02:00
parent 0570fdc770
commit 8770351825
14 changed files with 367 additions and 49 deletions

View File

@ -9,6 +9,7 @@
"psr/http-client": "^0.2.0",
"rowbot/url": "^2.0",
"ext-pdo": "*",
"ext-json": "*"
}
"ext-json": "*",
"ext-libxml": "*"
}
}

View File

@ -38,18 +38,6 @@ class Bookmark extends Entity {
$this->addType('lastPreview', 'integer');
}
// todo
public function hashBookmark($userId, $bookmarkId, $fields) {
$bookmarkRecord = $this->findUniqueBookmark($bookmarkId, $userId);
$bookmark = [];
foreach ($fields as $field) {
if (isset($bookmarkRecord[$field])) {
$bookmark[$field] = $bookmarkRecord[$field];
}
}
return hash('sha256', json_encode($bookmark, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
public function markPreviewCreated() {
$this->setLastPreview(time());
}

View File

@ -1,7 +1,9 @@
<?php
namespace OCA\Bookmarks\Db;
use OCA\Bookmarks\UrlNormalizer;
use OCA\Bookmarks\Exception\AlreadyExistsError;
use OCA\Bookmarks\Exception\UrlParseError;
use OCA\Bookmarks\Service\UrlNormalizer;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
@ -9,6 +11,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\AppFramework\Db\QBMapper;
use Rowbot\URL\Exception\TypeError;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@ -291,10 +294,12 @@ class BookmarkMapper extends QBMapper {
/**
* @param Entity $entity
* @return Entity
* @throws UrlParseError
*/
public function update(Entity $entity) : Entity {
// normalize url
$entity->setUrl($this->urlNormalizer->normalize($entity->getUrl()));
$entity->setLastmodified(time());
$newEntity = parent::update($entity);
@ -310,11 +315,14 @@ class BookmarkMapper extends QBMapper {
/**
* @param Entity $entity
* @return Entity
* @throws \Exception
* @throws AlreadyExistsError
* @throws UrlParseError
*/
public function insert(Entity $entity) : Entity {
// normalize url
$entity->setUrl($this->urlNormalizer->normalize($entity->getUrl()));
if ($entity->getAdded() === null) $entity->setAdded(time());
$entity->setLastmodified(time());
$exists = true;
try {
@ -326,8 +334,7 @@ class BookmarkMapper extends QBMapper {
}
if ($exists) {
// TODO: Create a separate Exception for this!
throw new \Exception('A bookmark with this URL already exists');
throw new AlreadyExistsError('A bookmark with this URL already exists');
}
$newEntity = parent::insert($entity);
@ -342,6 +349,7 @@ class BookmarkMapper extends QBMapper {
* @param Entity $entity
* @return Entity
* @throws MultipleObjectsReturnedException
* @throws UrlParseError
*/
public function insertOrUpdate(Entity $entity) : Entity {
// normalize url
@ -374,19 +382,9 @@ class BookmarkMapper extends QBMapper {
$bookmark = [];
foreach ($fields as $field) {
if (isset($entity->{$field})) {
$bookmark[$field] = $entity->{$field};
$bookmark[$field] = $entity->{'get'.$field}();
}
}
return hash('sha256', json_encode($bookmark, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
/**
* @param Entity $entity
* @return Entity
*/
public function markPreviewCreated(Entity $entity) {
$entity->setLastPreview(time());
return $this->update($entity);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace OCA\Bookmarks\Exception;
class AlreadyExistsError extends Exception {
}

View File

@ -0,0 +1,9 @@
<?php
namespace OCA\Bookmarks\Exception;
class Exception extends \Exception {
}

View File

@ -0,0 +1,6 @@
<?php
namespace OCA\Bookmarks\Exception;
class UnauthorizedAccessError extends Exception {
}

View File

@ -0,0 +1,6 @@
<?php
namespace OCA\Bookmarks\Exception;
class UrlParseError extends \Exception {
}

View File

@ -2,7 +2,7 @@
/*
* (c) Pedro Rodrigues <relvas.rodrigues@gmail.com>
*/
namespace OCA\Bookmarks;
namespace OCA\Bookmarks\Service;
/**
* Bookmark parser

View File

@ -0,0 +1,128 @@
<?php
namespace OCA\Bookmarks\Service;
use OCA\Bookmarks\BookmarksParser;
use OCA\Bookmarks\Db\BookmarkMapper;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\TagMapper;
use OCA\Bookmarks\Exception\UnauthorizedAccessError;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\Util;
/**
* Class HtmlExporter
*
* @package OCA\Bookmarks\Service
*/
class HtmlExporter {
/**
* @var BookmarkMapper
*/
protected $bookmarkMapper;
/**
* @var FolderMapper
*/
protected $folderMapper;
/**
* @var TagMapper
*/
protected $tagMapper;
/** @var BookmarksParser */
private $bookmarksParser;
/**
* ImportService constructor.
*
* @param BookmarkMapper $bookmarkMapper
* @param FolderMapper $folderMapper
* @param TagMapper $tagMapper
*/
public function __construct(BookmarkMapper $bookmarkMapper, FolderMapper $folderMapper, TagMapper $tagMapper) {
$this->bookmarkMapper = $bookmarkMapper;
$this->folderMapper = $folderMapper;
$this->tagMapper = $tagMapper;
}
/**
* @param int $userId
* @param int $folderId
* @return string
* @throws UnauthorizedAccessError
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
*/
public function exportFolder(int $userId, int $folderId = -1): string {
$file = "<!DOCTYPE NETSCAPE-Bookmark-file-1>
<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">
<TITLE>Bookmarks</TITLE>";
$file .= $this->serializeFolder($userId, $folderId);
return $file;
}
/**
* @param int $userId
* @param int $id
* @return string
* @throws UnauthorizedAccessError
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
*/
protected function serializeFolder(int $userId, int $id): string {
if ($id !== -1) {
$folder = $this->folderMapper->find($id);
if ($folder->getUserId() !== $userId) {
throw new UnauthorizedAccessError();
}
$output = '<DT><h3>' . htmlspecialchars($folder['title']) . '</h3>' . "\n"
. '<DL><p>';
} else {
$output = '<H1>Bookmarks</h1>' . "\n"
. '<DL><p>';
}
$childBookmarks = $id !== -1 ? $this->bookmarkMapper->findByFolder($id) : $this->bookmarkMapper->findByRootFolder($userId);
foreach ($childBookmarks as $bookmark) {
// discards records with no URL. This should not happen but
// a database could have old entries
if ($bookmark->getUrl() === '') {
continue;
}
$tags = $this->tagMapper->findByBookmark($bookmark->getId());
$tags = Util::sanitizeHTML(implode(',', $tags));
$title = trim($bookmark->getTitle());
$url = Util::sanitizeHTML($bookmark->getUrl());
if ($title === '') {
$title = $url;
}
$title = Util::sanitizeHTML($title);
$description = Util::sanitizeHTML($bookmark->getDescription());
$output .= '<DT><A HREF="' . $url . '" TAGS="' . $tags . '" ADD_DATE="' . $bookmark['added'] . '">' . $title . '</A>' . "\n";
if (strlen($description) > 0) {
$output .= '<DD>' . $description . '</DD>';
}
$output .= "\n";
}
$childFolders = $this->folderMapper->findByParentFolder($id);
foreach ($childFolders as $childFolder) {
$output .= $this->serializeFolder($userId, $childFolder->getId());
}
$output .= '</p></DL>';
return $output;
}
}

View File

@ -0,0 +1,164 @@
<?php
namespace OCA\Bookmarks\Service;
use OCA\Bookmarks\BookmarksParser;
use OCA\Bookmarks\Db\Bookmark;
use OCA\Bookmarks\Db\BookmarkMapper;
use OCA\Bookmarks\Db\Folder;
use OCA\Bookmarks\Db\FolderMapper;
use OCA\Bookmarks\Db\TagMapper;
use OCA\Bookmarks\Exception\UnauthorizedAccessError;
use OCA\Bookmarks\Exception\UrlParseError;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
/**
* Class HtmlImporter
*
* @package OCA\Bookmarks\Service
*/
class HtmlImporter {
/**
* @var BookmarkMapper
*/
protected $bookmarkMapper;
/**
* @var FolderMapper
*/
protected $folderMapper;
/**
* @var TagMapper
*/
protected $tagMapper;
/** @var BookmarksParser */
private $bookmarksParser;
/**
* ImportService constructor.
*
* @param BookmarkMapper $bookmarkMapper
* @param FolderMapper $folderMapper
* @param TagMapper $tagMapper
* @param BookmarksParser $bookmarksParser
*/
public function __construct(BookmarkMapper $bookmarkMapper, FolderMapper $folderMapper, TagMapper $tagMapper, BookmarksParser $bookmarksParser) {
$this->bookmarkMapper = $bookmarkMapper;
$this->folderMapper = $folderMapper;
$this->tagMapper = $tagMapper;
$this->bookmarksParser = $bookmarksParser;
}
/**
* @brief Import Bookmarks from html formatted file
* @param int $userId
* @param string $file Content to import
* @param int $rootFolder
* @return array
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws UnauthorizedAccessError
*/
public function importFile(int $userId, string $file, int $rootFolder = -1) {
$content = file_get_contents($file);
return $this->import($userId, $content, $rootFolder);
}
/**
* @brief Import Bookmarks from html
* @param int $userId
* @param string $content
* @param int $rootFolder
* @return array
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws UnauthorizedAccessError
*/
public function import(int $userId, string $content, int $rootFolder = -1) {
$imported = [];
$errors = [];
if ($rootFolder !== -1) {
$folder = $this->folderMapper->find($rootFolder);
if ($folder->getUserId() !== $userId) {
throw new UnauthorizedAccessError('Not allowed to access folder '.$rootFolder);
}
}
$this->bookmarksParser->parse($content, false);
foreach ($this->bookmarksParser->currentFolder['children'] as $folder) {
$imported[] = $this->importFolder($userId, $folder, $rootFolder, $errors);
}
foreach ($this->bookmarksParser->currentFolder['bookmarks'] as $bookmark) {
try {
$bm = $this->importBookmark($userId, $rootFolder, $bookmark);
} catch (UrlParseError $e) {
$errors[] = 'Failed to parse URL: '.$bookmark['href'];
continue;
}
$imported[] = ['type' => 'bookmark', 'id' => $bm->getId(), 'title' => $bookmark['title'], 'url' => $bookmark['href']];
}
return ['imported' => $imported, 'errors' => $errors];
}
/**
* @param int $userId
* @param array $folderParams
* @param int $parentId
* @param array $errors
* @return array
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
*/
private function importFolder(int $userId, array $folderParams, int $parentId, &$errors = []) {
$folder = new Folder();
$folder->setUserId($userId);
$folder->setTitle($folderParams['title']);
$folder->setParentFolder($parentId);
$folder = $this->folderMapper->insert($folder);
$newFolder = ['type' => 'folder', 'id' => $folder->getId(), 'title' => $folder['title'], 'children' => []];
foreach ($folderParams['bookmarks'] as $bookmark) {
try {
$bm = $this->importBookmark($userId, $folder->getId(), $bookmark);
} catch (UrlParseError $e) {
$errors[] = 'Failed to parse URL: '.$bookmark['href'];
continue;
}
$newFolder['children'][] = ['type' => 'bookmark', 'id' => $bm->getId(), 'title' => $bookmark['title'], 'url' => $bookmark['href']];
}
foreach ($folder['children'] as $childFolder) {
$newFolder['children'][] = $this->importFolder($userId, $childFolder, $folder->getId(), $errors);
}
return $newFolder;
}
/**
* @param int $userId
* @param int $folderId
* @param array $bookmark
* @return Bookmark|Entity
* @throws DoesNotExistException
* @throws MultipleObjectsReturnedException
* @throws UrlParseError
*/
private function importBookmark(int $userId, int $folderId, array $bookmark) {
$bm = new Bookmark();
$bm->setUserId($userId);
$bm->setUrl($bookmark['href']);
$bm->setTitle($bookmark['title']);
$bm->setDescription($bookmark['title']);
if (isset($bookmark['add_date'])) $bm->setAdded($bookmark['add_date']->getTimestamp());
// insert bookmark
$bm = $this->bookmarkMapper->insertOrUpdate($bm);
// add to folder
$this->folderMapper->addToFolders($bm->getId(), [$folderId]);
// add tags
$this->tagMapper->addTo($bookmark['tags'], $bm->getId());
return $bm;
}
}

View File

@ -1,8 +1,7 @@
<?php
namespace OCA\Bookmarks;
namespace OCA\Bookmarks\Service;
use Marcelklehr\LinkPreview\Client as LinkPreview;
use Marcelklehr\LinkPreview\Exceptions\ConnectionErrorException;
use OCP\ILogger;
use OCP\IConfig;
use OCP\Http\Client\IClientService;
@ -49,8 +48,6 @@ class LinkExplorer {
$data = $preview->toArray();
$this->logger->debug('getImage for URL: '.$url.' '.var_export($data, true), ['app' => 'bookmarks']);
if (!isset($data)) {
return ['url' => $url];
}

View File

@ -0,0 +1,25 @@
<?php
namespace OCA\Bookmarks\Service;
use OCA\Bookmarks\Exception\UrlParseError;
use Rowbot\URL\Exception\TypeError;
use Rowbot\URL\URL;
class UrlNormalizer {
public function __construct() {
}
/**
* @param $urlString
* @return string
* @throws UrlParseError
*/
public function normalize($urlString) {
try {
$url = new URL($urlString);
} catch (TypeError $e) {
throw new UrlParseError();
}
return $url->href;
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace OCA\Bookmarks;
use Rowbot\URL\URL;
use Rowbot\URL\Exception\TypeError;
class UrlNormalizer {
public function __construct() {
}
public function normalize($urlString) {
$url = new URL($urlString);
return $url->href;
}
}

View File

@ -5,6 +5,7 @@ namespace OCA\Bookmarks\Tests;
use OCA\Bookmarks\Db;
use OCA\Bookmarks\Db\Bookmark;
use OCA\Bookmarks\Exception\UrlParseError;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
@ -45,6 +46,7 @@ class TagMapperTest extends TestCase {
* @param array $tags
* @param Bookmark $bookmark
* @throws MultipleObjectsReturnedException
* @throws UrlParseError
*/
public function testAddToAndFind(array $tags, Bookmark $bookmark) {
$bookmark->setUserId($this->userId);