summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSean Molenaar <sean@seanmolenaar.eu>2020-10-04 20:45:33 +0200
committerBenjamin Brahmer <info@b-brahmer.de>2020-11-03 19:58:37 +0100
commit10e8c28feaf6d858948285a291231f651ef74728 (patch)
tree5c48216dc1ce6a6dd8f292d489bb4a7d03cb5595 /lib
parent361cfa55b7302b29e158647060085550b9a3dfe1 (diff)
Add migration with foreign keys
Closes #829 Signed-off-by: Sean Molenaar <sean@seanmolenaar.eu>
Diffstat (limited to 'lib')
-rw-r--r--lib/Command/Config/FeedAdd.php24
-rw-r--r--lib/Command/Config/FolderAdd.php10
-rw-r--r--lib/Command/Config/FolderDelete.php4
-rw-r--r--lib/Controller/FeedApiController.php21
-rw-r--r--lib/Controller/FeedController.php32
-rw-r--r--lib/Controller/FolderApiController.php27
-rw-r--r--lib/Controller/FolderController.php39
-rw-r--r--lib/Controller/UserApiController.php74
-rw-r--r--lib/Db/Feed.php12
-rw-r--r--lib/Db/FeedMapper.php4
-rw-r--r--lib/Db/FeedMapperV2.php18
-rw-r--r--lib/Db/Folder.php2
-rw-r--r--lib/Db/FolderMapperV2.php1
-rw-r--r--lib/Db/ItemMapper.php22
-rw-r--r--lib/Migration/Version150005Date20201009192341.php98
-rw-r--r--lib/Service/FeedService.php26
-rw-r--r--lib/Service/FeedServiceV2.php8
-rw-r--r--lib/Service/FolderService.php18
-rw-r--r--lib/Service/FolderServiceV2.php2
-rw-r--r--lib/Service/ItemService.php44
-rw-r--r--lib/Utility/OPMLExporter.php2
21 files changed, 299 insertions, 189 deletions
diff --git a/lib/Command/Config/FeedAdd.php b/lib/Command/Config/FeedAdd.php
index 3c4820437..86121ad06 100644
--- a/lib/Command/Config/FeedAdd.php
+++ b/lib/Command/Config/FeedAdd.php
@@ -2,6 +2,8 @@
declare(strict_types=1);
namespace OCA\News\Command\Config;
+use OCA\News\Service\Exceptions\ServiceConflictException;
+use OCA\News\Service\Exceptions\ServiceNotFoundException;
use OCA\News\Service\FeedServiceV2;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -56,13 +58,31 @@ class FeedAdd extends Command
{
$user = $input->getArgument('user-id');
$url = $input->getArgument('feed');
- $folder = (int) $input->getOption('folder') ?? 0;
+ $folder = $input->getOption('folder');
$title = $input->getOption('title');
$full_text = (bool) $input->getOption('full-text');
$username = $input->getOption('username');
$password = $input->getOption('password');
- $feed = $this->feedService->create($user, $url, $folder, $full_text, $title, $username, $password);
+ if ($folder !== null) {
+ $folder = intval($folder);
+ }
+
+ try {
+ $feed = $this->feedService->create(
+ $user,
+ $url,
+ $folder,
+ $full_text,
+ $title,
+ $username,
+ $password
+ );
+ } catch (ServiceNotFoundException|ServiceConflictException $e) {
+ $output->write($e->getMessage());
+ return 1;
+ }
+
$this->feedService->fetch($feed);
$output->writeln(json_encode($feed->toAPI(), JSON_PRETTY_PRINT));
diff --git a/lib/Command/Config/FolderAdd.php b/lib/Command/Config/FolderAdd.php
index 257cf2dd6..03ad72535 100644
--- a/lib/Command/Config/FolderAdd.php
+++ b/lib/Command/Config/FolderAdd.php
@@ -47,9 +47,13 @@ class FolderAdd extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $user = $input->getArgument('user-id');
- $name = $input->getArgument('name');
- $parent = (int) $input->getOption('parent') ?? 0;
+ $user = $input->getArgument('user-id');
+ $name = $input->getArgument('name');
+ $parent = $input->getOption('parent');
+
+ if ($parent !== null) {
+ $parent = intval($parent);
+ }
$this->folderService->create($user, $name, $parent);
diff --git a/lib/Command/Config/FolderDelete.php b/lib/Command/Config/FolderDelete.php
index bf7608b02..397eda999 100644
--- a/lib/Command/Config/FolderDelete.php
+++ b/lib/Command/Config/FolderDelete.php
@@ -50,11 +50,11 @@ class FolderDelete extends Command
$user = $input->getArgument('user-id');
$id = $input->getArgument('folder-id');
- if ($id === '0') {
+ if ($id === null) {
throw new ServiceException('Can not remove root folder!');
}
- $this->folderService->delete($user, $id);
+ $this->folderService->delete($user, intval($id));
return 0;
}
diff --git a/lib/Controller/FeedApiController.php b/lib/Controller/FeedApiController.php
index cb3d5e645..2c96bbc6e 100644
--- a/lib/Controller/FeedApiController.php
+++ b/lib/Controller/FeedApiController.php
@@ -27,6 +27,7 @@ use \OCP\AppFramework\Http;
use \OCA\News\Service\FeedService;
use \OCA\News\Service\ItemService;
use Psr\Log\LoggerInterface;
+use function GuzzleHttp\Psr7\uri_for;
class FeedApiController extends ApiController
{
@@ -99,13 +100,17 @@ class FeedApiController extends ApiController
* @NoCSRFRequired
* @CORS
*
- * @param string $url
- * @param int $folderId
+ * @param string $url
+ * @param int|null $folderId
*
* @return array|mixed|JSONResponse
*/
- public function create(string $url, int $folderId = 0)
+ public function create(string $url, ?int $folderId = null)
{
+ if ($folderId === 0) {
+ $folderId = null;
+ }
+
try {
$this->feedService->purgeDeleted($this->getUserId(), false);
@@ -169,13 +174,17 @@ class FeedApiController extends ApiController
* @NoCSRFRequired
* @CORS
*
- * @param int $feedId
- * @param int $folderId
+ * @param int $feedId
+ * @param int|null $folderId
*
* @return array|JSONResponse
*/
- public function move(int $feedId, int $folderId)
+ public function move(int $feedId, ?int $folderId)
{
+ if ($folderId === 0) {
+ $folderId = null;
+ }
+
try {
$this->feedService->patch(
$feedId,
diff --git a/lib/Controller/FeedController.php b/lib/Controller/FeedController.php
index c09096bd9..78df7be0c 100644
--- a/lib/Controller/FeedController.php
+++ b/lib/Controller/FeedController.php
@@ -105,6 +105,9 @@ class FeedController extends Controller
// check if feed or folder exists
try {
if ($feedType === FeedType::FOLDER) {
+ if ($feedId === 0) {
+ $feedId = null;
+ }
$this->folderService->find($this->userId, $feedId);
} elseif ($feedType === FeedType::FEED) {
$this->feedService->find($this->userId, $feedId);
@@ -131,20 +134,23 @@ class FeedController extends Controller
* @NoAdminRequired
*
* @param string $url
- * @param int $parentFolderId
- * @param string $title
- * @param string $user
- * @param string $password
+ * @param int|null $parentFolderId
+ * @param string|null $title
+ * @param string|null $user
+ * @param string|null $password
*
* @return array|JSONResponse
*/
public function create(
string $url,
- int $parentFolderId,
+ ?int $parentFolderId,
?string $title = null,
?string $user = null,
?string $password = null
) {
+ if ($parentFolderId === 0) {
+ $parentFolderId = null;
+ }
try {
// we need to purge deleted feeds if a feed is created to
// prevent already exists exceptions
@@ -290,13 +296,13 @@ class FeedController extends Controller
/**
* @NoAdminRequired
*
- * @param int $feedId
- * @param bool $pinned
- * @param bool $fullTextEnabled
- * @param int $updateMode
- * @param int $ordering
- * @param int $folderId
- * @param string $title
+ * @param int $feedId
+ * @param bool $pinned
+ * @param bool $fullTextEnabled
+ * @param int|null $updateMode
+ * @param int|null $ordering
+ * @param int|null $folderId
+ * @param string|null $title
*
* @return array|JSONResponse
*/
@@ -315,7 +321,7 @@ class FeedController extends Controller
'updateMode' => $updateMode,
'ordering' => $ordering,
'title' => $title,
- 'folderId' => $folderId
+ 'folderId' => $folderId === 0 ? null : $folderId
];
$diff = array_filter(
diff --git a/lib/Controller/FolderApiController.php b/lib/Controller/FolderApiController.php
index 1f79d7cf9..691c67139 100644
--- a/lib/Controller/FolderApiController.php
+++ b/lib/Controller/FolderApiController.php
@@ -90,12 +90,16 @@ class FolderApiController extends ApiController
* @NoCSRFRequired
* @CORS
*
- * @param int $folderId
+ * @param int|null $folderId
*
* @return array|JSONResponse
*/
- public function delete(int $folderId)
+ public function delete(?int $folderId)
{
+ if (empty($folderId)) {
+ return new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
try {
$this->folderService->delete($folderId, $this->getUserId());
} catch (ServiceNotFoundException $ex) {
@@ -111,13 +115,17 @@ class FolderApiController extends ApiController
* @NoCSRFRequired
* @CORS
*
- * @param int $folderId
- * @param string $name
+ * @param int|null $folderId
+ * @param string $name
*
* @return array|JSONResponse
*/
- public function update(int $folderId, string $name)
+ public function update(?int $folderId, string $name)
{
+ if (empty($folderId)) {
+ return new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
try {
$this->folderService->rename($folderId, $name, $this->getUserId());
} catch (ServiceValidationException $ex) {
@@ -137,11 +145,14 @@ class FolderApiController extends ApiController
* @NoCSRFRequired
* @CORS
*
- * @param int $folderId
- * @param int $newestItemId
+ * @param int|null $folderId
+ * @param int $newestItemId
*/
- public function read(int $folderId, int $newestItemId): void
+ public function read(?int $folderId, int $newestItemId): void
{
+ if ($folderId === 0) {
+ $folderId = null;
+ }
$this->itemService->readFolder($folderId, $newestItemId, $this->getUserId());
}
}
diff --git a/lib/Controller/FolderController.php b/lib/Controller/FolderController.php
index d19726963..09900f5b2 100644
--- a/lib/Controller/FolderController.php
+++ b/lib/Controller/FolderController.php
@@ -64,13 +64,15 @@ class FolderController extends Controller
/**
* @NoAdminRequired
*
- * @param int $folderId
- * @param bool $open
+ * @param int|null $folderId
+ * @param bool $open
*
* @return array|JSONResponse
*/
- public function open(int $folderId, bool $open)
+ public function open(?int $folderId, bool $open)
{
+ $folderId = $folderId === 0 ? null : $folderId;
+
try {
$this->folderService->open($folderId, $open, $this->userId);
} catch (ServiceException $ex) {
@@ -108,12 +110,15 @@ class FolderController extends Controller
/**
* @NoAdminRequired
*
- * @param int $folderId
+ * @param int|null $folderId
*
* @return array|JSONResponse
*/
- public function delete(int $folderId)
+ public function delete(?int $folderId)
{
+ if (empty($folderId)) {
+ return new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ }
try {
$this->folderService->markDeleted($folderId, $this->userId);
} catch (ServiceNotFoundException $ex) {
@@ -127,13 +132,16 @@ class FolderController extends Controller
/**
* @NoAdminRequired
*
- * @param string $folderName
- * @param int $folderId
+ * @param string $folderName
+ * @param int|null $folderId
*
* @return array|JSONResponse
*/
- public function rename(string $folderName, int $folderId)
+ public function rename(string $folderName, ?int $folderId)
{
+ if (empty($folderId)) {
+ return new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ }
try {
$folder = $this->folderService->rename(
$folderId,
@@ -154,12 +162,15 @@ class FolderController extends Controller
/**
* @NoAdminRequired
*
- * @param int $folderId
- * @param int $highestItemId
+ * @param int|null $folderId
+ * @param int $highestItemId
+ *
* @return array
*/
- public function read(int $folderId, int $highestItemId): array
+ public function read(?int $folderId, int $highestItemId): array
{
+ $folderId = $folderId === 0 ? null : $folderId;
+
$this->itemService->readFolder(
$folderId,
$highestItemId,
@@ -173,12 +184,14 @@ class FolderController extends Controller
/**
* @NoAdminRequired
*
- * @param int $folderId
+ * @param int|null $folderId
*
* @return array|JSONResponse
*/
- public function restore(int $folderId)
+ public function restore(?int $folderId)
{
+ $folderId = $folderId === 0 ? null : $folderId;
+
try {
$this->folderService->unmarkDeleted($folderId, $this->userId);
} catch (ServiceNotFoundException $ex) {
diff --git a/lib/Controller/UserApiController.php b/lib/Controller/UserApiController.php
deleted file mode 100644
index b644ba1f0..000000000
--- a/lib/Controller/UserApiController.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-/**
- * Nextcloud - News
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author Alessandro Cosentino <cosenal@gmail.com>
- * @author Bernhard Posselt <dev@bernhard-posselt.com>
- * @author David Guillot <david@guillot.me>
- * @copyright 2012 Alessandro Cosentino
- * @copyright 2012-2014 Bernhard Posselt
- * @copyright 2018 David Guillot
- */
-
-namespace OCA\News\Controller;
-
-use \OCP\IRequest;
-use \OCP\IUserSession;
-use \OCP\IURLGenerator;
-use \OCP\Files\IRootFolder;
-use \OCP\AppFramework\Http;
-
-class UserApiController extends ApiController
-{
-
- private $rootFolder;
-
- public function __construct(
- string $appName,
- IRequest $request,
- IUserSession $userSession,
- IRootFolder $rootFolder
- ) {
- parent::__construct($appName, $request, $userSession);
- $this->rootFolder = $rootFolder;
- }
-
- /**
- * @NoAdminRequired
- * @NoCSRFRequired
- * @CORS
- */
- public function index(): array
- {
- $user = $this->getUser();
-
- // find the avatar
- $jpgAvatar = '/' . $user->getUID() . '/avatar.jpg';
- $pngAvatar = '/' . $user->getUID() . '/avatar.png';
- $avatar = null;
-
- if ($this->rootFolder->nodeExists($jpgAvatar)) {
- $file = $this->rootFolder->get($jpgAvatar);
- $avatar = [
- 'data' => base64_encode($file->getContent()),
- 'mime' => 'image/jpeg'
- ];
- } elseif ($this->rootFolder->nodeExists($pngAvatar)) {
- $file = $this->rootFolder->get($pngAvatar);
- $avatar = [
- 'data' => base64_encode($file->getContent()),
- 'mime' => 'image/png'
- ];
- }
-
- return [
- 'userId' => $user->getUID(),
- 'displayName' => $user->getDisplayName(),
- 'lastLoginTimestamp' => $user->getLastLogin(),
- 'avatar' => $avatar
- ];
- }
-}
diff --git a/lib/Db/Feed.php b/lib/Db/Feed.php
index 852de4c78..473912acc 100644
--- a/lib/Db/Feed.php
+++ b/lib/Db/Feed.php
@@ -37,7 +37,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
protected $faviconLink = null;
/** @var int|null */
protected $added = 0;
- /** @var int */
+ /** @var int|null */
protected $folderId;
/** @var int */
protected $unreadCount;
@@ -152,9 +152,9 @@ class Feed extends Entity implements IAPI, \JsonSerializable
}
/**
- * @return int
+ * @return int|null
*/
- public function getFolderId(): int
+ public function getFolderId(): ?int
{
return $this->folderId;
}
@@ -416,9 +416,11 @@ class Feed extends Entity implements IAPI, \JsonSerializable
}
/**
- * @param int $folderId
+ * @param int|null $folderId
+ *
+ * @return Feed
*/
- public function setFolderId(int $folderId): Feed
+ public function setFolderId(?int $folderId): Feed
{
if ($this->folderId !== $folderId) {
$this->folderId = $folderId;
diff --git a/lib/Db/FeedMapper.php b/lib/Db/FeedMapper.php
index 867ba982d..193cf1f5d 100644
--- a/lib/Db/FeedMapper.php
+++ b/lib/Db/FeedMapper.php
@@ -77,7 +77,7 @@ class FeedMapper extends NewsMapper
// think twice when changing this
'AND `items`.`unread` = ? ' .
'WHERE `feeds`.`user_id` = ? ' .
- 'AND (`feeds`.`folder_id` = 0 ' .
+ 'AND (`feeds`.`folder_id` IS NULL ' .
'OR `folders`.`deleted_at` = 0 ' .
') ' .
'AND `feeds`.`deleted_at` = 0 ' .
@@ -106,7 +106,7 @@ class FeedMapper extends NewsMapper
// POSSIBLE SQL INJECTION RISK WHEN MODIFIED WITHOUT THOUGHT.
// think twice when changing this
'AND `items`.`unread` = ? ' .
- 'WHERE (`feeds`.`folder_id` = 0 ' .
+ 'WHERE (`feeds`.`folder_id` IS NULL ' .
'OR `folders`.`deleted_at` = 0 ' .
') ' .
'AND `feeds`.`deleted_at` = 0 ' .
diff --git a/lib/Db/FeedMapperV2.php b/lib/Db/FeedMapperV2.php
index a7edecd88..05b272112 100644
--- a/lib/Db/FeedMapperV2.php
+++ b/lib/Db/FeedMapperV2.php
@@ -43,6 +43,7 @@ class FeedMapperV2 extends NewsMapperV2
* Find all feeds for a user.
*
* @param string $userId The user identifier
+ * @param array $params Filter parameters
*
* @return Entity[]
*/
@@ -62,7 +63,7 @@ class FeedMapperV2 extends NewsMapperV2
* Find all feeds for a user.
*
* @param string $userId The user identifier
- * @param int $id The feed identifier
+ * @param int $id The feed identifier
*
* @return Entity
*
@@ -124,17 +125,22 @@ class FeedMapperV2 extends NewsMapperV2
/**
* Find all feeds in a folder
*
- * @param int $id ID of the folder
+ * @param int|null $id ID of the folder
*
* @return Feed[]
*/
- public function findAllFromFolder(int $id): array
+ public function findAllFromFolder(?int $id): array
{
$builder = $this->db->getQueryBuilder();
$builder->addSelect('*')
- ->from($this->tableName)
- ->where('folder_id = :folder_id')
- ->setParameter(':folder_id', $id);
+ ->from($this->tableName);
+
+ if (is_null($id)) {
+ $builder->where('folder_id IS NULL');
+ } else {
+ $builder->where('folder_id = :folder_id')
+ ->setParameter(':folder_id', $id);
+ }
return $this->findEntities($builder);
}
diff --git a/lib/Db/Folder.php b/lib/Db/Folder.php
index 2efd65e96..d452bb7d4 100644
--- a/lib/Db/Folder.php
+++ b/lib/Db/Folder.php
@@ -141,7 +141,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
return $this;
}
- public function setParentId(int $parentId = 0): self
+ public function setParentId(?int $parentId = null): self
{
if ($this->parentId !== $parentId) {
$this->parentId = $parentId;
diff --git a/lib/Db/FolderMapperV2.php b/lib/Db/FolderMapperV2.php
index 7d0536607..913bd9d70 100644
--- a/lib/Db/FolderMapperV2.php
+++ b/lib/Db/FolderMapperV2.php
@@ -41,6 +41,7 @@ class FolderMapperV2 extends NewsMapperV2
* Find all feeds for a user.
*
* @param string $userId The user identifier
+ * @param array $params Filter parameters
*
* @return Entity[]
*/
diff --git a/lib/Db/ItemMapper.php b/lib/Db/ItemMapper.php
index 270919b44..65c6e0b15 100644
--- a/lib/Db/ItemMapper.php
+++ b/lib/Db/ItemMapper.php
@@ -55,7 +55,7 @@ class ItemMapper extends NewsMapper
$prependTo .
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
'ON `folders`.`id` = `feeds`.`folder_id` ' .
- 'WHERE `feeds`.`folder_id` = 0 ' .
+ 'WHERE `feeds`.`folder_id` IS NULL ' .
'OR `folders`.`deleted_at` = 0 ' .
'ORDER BY `items`.`id` ' . $ordering;
}
@@ -125,7 +125,7 @@ class ItemMapper extends NewsMapper
'AND `items`.`starred` = ? ' .
'LEFT OUTER JOIN `*PREFIX*news_folders` `folders` ' .
'ON `folders`.`id` = `feeds`.`folder_id` ' .
- 'WHERE `feeds`.`folder_id` = 0 ' .
+ 'WHERE `feeds`.`folder_id` IS NULL ' .
'OR `folders`.`deleted_at` = 0';
$params = [$userId, true];
@@ -151,14 +151,15 @@ class ItemMapper extends NewsMapper
}
- public function readFolder($folderId, $highestItemId, $time, $userId)
+ public function readFolder(?int $folderId, $highestItemId, $time, $userId)
{
+ $folderWhere = is_null($folderId) ? 'IS' : '=';
$sql = 'UPDATE `*PREFIX*news_items` ' .
'SET unread = ? ' .
', `last_modified` = ? ' .
'WHERE `feed_id` IN (' .
'SELECT `id` FROM `*PREFIX*news_feeds` ' .
- 'WHERE `folder_id` = ? ' .
+ "WHERE `folder_id` ${folderWhere} ? " .
'AND `user_id` = ? ' .
') ' .
'AND `id` <= ?';
@@ -207,11 +208,12 @@ class ItemMapper extends NewsMapper
}
- public function findAllNewFolder($id, $updatedSince, $showAll, $userId)
+ public function findAllNewFolder(?int $id, $updatedSince, $showAll, $userId)
{
$sql = $this->buildStatusQueryPart($showAll);
- $sql .= 'AND `feeds`.`folder_id` = ? ' .
+ $folderWhere = is_null($id) ? 'IS' : '=';
+ $sql .= "AND `feeds`.`folder_id` ${$folderWhere} ? " .
'AND `items`.`last_modified` >= ? ';
$sql = $this->makeSelectQuery($sql);
$params = [$userId, $id, $updatedSince];
@@ -270,7 +272,7 @@ class ItemMapper extends NewsMapper
public function findAllFolder(
- $id,
+ ?int $id,
$limit,
$offset,
$showAll,
@@ -285,10 +287,10 @@ class ItemMapper extends NewsMapper
$sql = $this->buildStatusQueryPart($showAll);
$sql .= $this->buildSearchQueryPart($search);
- $sql .= 'AND `feeds`.`folder_id` = ? ';
+ $folderWhere = is_null($id) ? 'IS' : '=';
+ $sql .= "AND `feeds`.`folder_id` ${folderWhere} ? ";
if ($offset !== 0) {
- $sql .= 'AND `items`.`id` ' .
- $this->getOperator($oldestFirst) . ' ? ';
+ $sql .= 'AND `items`.`id` ' . $this->getOperator($oldestFirst) . ' ? ';
$params[] = $offset;
}
$sql = $this->makeSelectQuery($sql, $oldestFirst, $search);
diff --git a/lib/Migration/Version150005Date20201009192341.php b/lib/Migration/Version150005Date20201009192341.php
new file mode 100644
index 000000000..937d3f50b
--- /dev/null
+++ b/lib/Migration/Version150005Date20201009192341.php
@@ -0,0 +1,98 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\News\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Auto-generated migration step: Please modify to your needs!
+ */
+class Version150005Date20201009192341 extends SimpleMigrationStep {
+
+ protected $connection;
+
+ public function __construct(IDBConnection $connection)
+ {
+ $this->connection = $connection;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
+ $qb = $this->connection->getQueryBuilder();
+
+ $qb->update('news_feeds')
+ ->set('folder_id', $qb->createPositionalParameter(null, IQueryBuilder::PARAM_NULL))
+ ->where('folder_id = 0')
+ ->execute();
+
+ $feed_name = $this->connection->getQueryBuilder()->getTableName('news_feeds');
+ $folder_name = $this->connection->getQueryBuilder()->getTableName('news_folders');
+
+ $items_query = "DELETE FROM ${feed_name} WHERE ${feed_name}.`folder_id` NOT IN (SELECT DISTINCT id FROM ${folder_name}) AND ${feed_name}.`folder_id` IS NOT NULL";
+ $this->connection->executeQuery($items_query);
+
+ $item_name = $this->connection->getQueryBuilder()->getTableName('news_items');
+ $feed_name = $this->connection->getQueryBuilder()->getTableName('news_feeds');
+
+ $items_query = "DELETE FROM ${item_name} WHERE ${item_name}.`feed_id` NOT IN (SELECT DISTINCT id FROM ${feed_name})";
+ $this->connection->executeQuery($items_query);
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ if ($schema->hasTable('news_items') &&
+ !$schema->getTable('news_items')->hasForeignKey('feed')) {
+
+ $schema->getTable('news_items')
+ ->addForeignKeyConstraint(
+ $schema->getTable('news_feeds')->getName(),
+ ['feed_id'],
+ ['id'],
+ ['onDelete' => 'CASCADE'],
+ 'feed'
+ );
+ }
+
+ if ($schema->hasTable('news_feeds') &&
+ !$schema->getTable('news_feeds')->hasForeignKey('folder')) {
+
+ $schema->getTable('news_feeds')
+ ->addForeignKeyConstraint(
+ $schema->getTable('news_folders')->getName(),
+ ['folder_id'],
+ ['id'],
+ ['onDelete' => 'CASCADE'],
+ 'folder'
+ );
+ }
+
+ return $schema;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
+ }
+}
diff --git a/lib/Service/FeedService.php b/lib/Service/FeedService.php
index ab9c18219..c671a035c 100644
--- a/lib/Service/FeedService.php
+++ b/lib/Service/FeedService.php
@@ -103,21 +103,27 @@ class FeedService extends Service
/**
* Creates a new feed
*
- * @param string $feedUrl the url to the feed
- * @param int $folderId the folder where it should be put into, 0 for root
+ * @param string $feedUrl the url to the feed
+ * @param int|null $folderId the folder where it should be put into, null for root
* folder
- * @param string $userId for which user the feed should be created
- * @param string $title if given, this is used for the opml feed title
- * @param string $user if given, basic auth is set for this feed
- * @param string $password if given, basic auth is set for this
+ * @param string $userId for which user the feed should be created
+ * @param string|null $title if given, this is used for the opml feed title
+ * @param string|null $user if given, basic auth is set for this feed
+ * @param string|null $password if given, basic auth is set for this
* feed. Ignored if user is null or an empty string
*
+ * @return Feed the newly created feed
* @throws ServiceConflictException if the feed exists already
* @throws ServiceNotFoundException if the url points to an invalid feed
- * @return Feed the newly created feed
*/
- public function create($feedUrl, $folderId, $userId, $title = null, $user = null, $password =