Include folder names directly in subscription list
This commit is contained in:
parent
ad094f5217
commit
3b2190ca10
4 changed files with 59 additions and 68 deletions
|
@ -796,19 +796,21 @@ class Database {
|
|||
"SELECT
|
||||
s.id as id,
|
||||
s.feed as feed,
|
||||
f.url,source,folder,pinned,err_count,err_msg,order_type,added,keep_rule,block_rule,f.etag,s.scrape,
|
||||
f.url,source,pinned,err_count,err_msg,order_type,added,keep_rule,block_rule,f.etag,s.scrape,
|
||||
f.updated as updated,
|
||||
f.modified as edited,
|
||||
s.modified as modified,
|
||||
f.next_fetch,
|
||||
i.id as icon_id,
|
||||
i.url as icon_url,
|
||||
t.top as top_folder,
|
||||
folder, t.top as top_folder, d.name as folder_name, dt.name as top_folder_name,
|
||||
coalesce(s.title, f.title) as title,
|
||||
coalesce((articles - hidden - marked), articles) as unread
|
||||
FROM arsse_subscriptions as s
|
||||
left join topmost as t on t.f_id = s.folder
|
||||
join arsse_feeds as f on f.id = s.feed
|
||||
left join topmost as t on t.f_id = s.folder
|
||||
left join arsse_folders as d on s.folder = d.id
|
||||
left join arsse_folders as dt on t.top = dt.id
|
||||
left join arsse_icons as i on i.id = f.icon
|
||||
left join (
|
||||
select
|
||||
|
|
|
@ -554,21 +554,30 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
return new EmptyResponse(204);
|
||||
}
|
||||
|
||||
protected function baseCategory(): array {
|
||||
// the root folder is always a category and is always ID 1
|
||||
// the specific formulation is verbose, so a function makes sense
|
||||
/** Returns a useful subset of user metadata
|
||||
*
|
||||
* The following keys are included:
|
||||
*
|
||||
* - "num": The user's numeric ID,
|
||||
* - "root": The effective name of the root folder
|
||||
*/
|
||||
protected function userMeta(string $user): array {
|
||||
$meta = Arsse::$user->propertiesGet(Arsse::$user->id, false);
|
||||
return ['id' => 1, 'title' => $meta['root_folder_name'] ?? Arsse::$lang->msg("API.Miniflux.DefaultCategoryName"), 'user_id' => $meta['num']];
|
||||
return [
|
||||
'num' => $meta['num'],
|
||||
'root' => $meta['root_folder_name'] ?? Arsse::$lang->msg("API.Miniflux.DefaultCategoryName")
|
||||
];
|
||||
}
|
||||
|
||||
protected function getCategories(): ResponseInterface {
|
||||
$out = [];
|
||||
// add the root folder as a category
|
||||
$out = [$this->baseCategory()];
|
||||
$num = $out[0]['user_id'];
|
||||
$meta = $this->userMeta(Arsse::$user->id);
|
||||
$out[] = ['id' => 1, 'title' => $meta['root'], 'user_id' => $meta['num']];
|
||||
// add other top folders as categories
|
||||
foreach (Arsse::$db->folderList(Arsse::$user->id, null, false) as $f) {
|
||||
// always add 1 to the ID since the root folder will always be 1 instead of 0.
|
||||
$out[] = ['id' => $f['id'] + 1, 'title' => $f['name'], 'user_id' => $num];
|
||||
$out[] = ['id' => $f['id'] + 1, 'title' => $f['name'], 'user_id' => $meta['num']];
|
||||
}
|
||||
return new Response($out);
|
||||
}
|
||||
|
@ -651,24 +660,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
return new EmptyResponse(204);
|
||||
}
|
||||
|
||||
protected function mapFolders(): array {
|
||||
$folders = [0 => $this->baseCategory()];
|
||||
$num = $folders[0]['user_id'];
|
||||
foreach (Arsse::$db->folderList(Arsse::$user->id, null, false) as $r) {
|
||||
$folders[(int) $r['id']] = [
|
||||
'id' => ((int) $r['id']) + 1,
|
||||
'title' => $r['name'],
|
||||
'user_id' => $num,
|
||||
];
|
||||
}
|
||||
return $folders;
|
||||
}
|
||||
|
||||
protected function transformFeed(array $sub, array $folders): array {
|
||||
protected function transformFeed(array $sub, int $uid, string $rootName): array {
|
||||
$url = new Uri($sub['url']);
|
||||
return [
|
||||
'id' => (int) $sub['id'],
|
||||
'user_id' => $folders[0]['user_id'],
|
||||
'user_id' => $uid,
|
||||
'feed_url' => (string) $url->withUserInfo(""),
|
||||
'site_url' => (string) $sub['source'],
|
||||
'title' => (string) $sub['title'],
|
||||
|
@ -689,19 +685,21 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
'disabled' => false,
|
||||
'ignore_http_cache' => false,
|
||||
'fetch_via_proxy' => false,
|
||||
'category' => $folders[(int) $sub['top_folder']],
|
||||
'category' => [
|
||||
'id' => (int) $sub['top_folder'] + 1,
|
||||
'title' => $sub['top_folder_name'] ?? $rootName,
|
||||
'user_id' => $uid,
|
||||
],
|
||||
'icon' => $sub['icon_id'] ? ['feed_id' => (int) $sub['id'], 'icon_id' => (int) $sub['icon_id']] : null,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getFeeds(): ResponseInterface {
|
||||
$tr = Arsse::$db->begin();
|
||||
// compile the list of folders; the feed list includes folder names
|
||||
$folders = $this->mapFolders();
|
||||
// next compile the list of feeds
|
||||
$out = [];
|
||||
$tr = Arsse::$db->begin();
|
||||
$meta = $this->userMeta(Arsse::$user->id);
|
||||
foreach (Arsse::$db->subscriptionList(Arsse::$user->id) as $r) {
|
||||
$out[] = $this->transformFeed($r, $folders);
|
||||
$out[] = $this->transformFeed($r, $meta['num'], $meta['root']);
|
||||
}
|
||||
return new Response($out);
|
||||
}
|
||||
|
@ -711,35 +709,30 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$folder = ((int) $path[1]) - 1;
|
||||
// unless the folder is root, list recursive
|
||||
$recursive = $folder > 0;
|
||||
$out = [];
|
||||
$tr = Arsse::$db->begin();
|
||||
// get the list of subscriptions, or bail\
|
||||
// get the list of subscriptions, or bail
|
||||
try {
|
||||
$subs = Arsse::$db->subscriptionList(Arsse::$user->id, $folder, $recursive)->getAll();
|
||||
$meta = $this->userMeta(Arsse::$user->id);
|
||||
foreach (Arsse::$db->subscriptionList(Arsse::$user->id, $folder, $recursive) as $r) {
|
||||
$out[] = $this->transformFeed($r, $meta['num'], $meta['root']);
|
||||
}
|
||||
} catch (ExceptionInput $e) {
|
||||
// the folder does not exist
|
||||
return new ErrorResponse("404", 404);
|
||||
}
|
||||
// compile the list of folders; the feed list includes folder names
|
||||
// NOTE: We compile the full list of folders in case someone has manually selected a non-top folder
|
||||
$folders = $this->mapFolders();
|
||||
// next compile the list of feeds
|
||||
$out = [];
|
||||
foreach ($subs as $r) {
|
||||
$out[] = $this->transformFeed($r, $folders);
|
||||
}
|
||||
return new Response($out);
|
||||
}
|
||||
|
||||
protected function getFeed(array $path): ResponseInterface {
|
||||
$tr = Arsse::$db->begin();
|
||||
$meta = $this->userMeta(Arsse::$user->id);
|
||||
try {
|
||||
$sub = Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]);
|
||||
return new Response($this->transformFeed($sub, $meta['num'], $meta['root']));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
}
|
||||
// compile the list of folders; the feed list includes folder names
|
||||
$folders = $this->mapFolders();
|
||||
return new Response($this->transformFeed($sub, $folders));
|
||||
}
|
||||
|
||||
protected function createFeed(array $data): ResponseInterface {
|
||||
|
|
|
@ -314,22 +314,26 @@ trait SeriesSubscription {
|
|||
public function testListSubscriptions(): void {
|
||||
$exp = [
|
||||
[
|
||||
'url' => "http://example.com/feed2",
|
||||
'title' => "eek",
|
||||
'folder' => null,
|
||||
'top_folder' => null,
|
||||
'unread' => 4,
|
||||
'pinned' => 1,
|
||||
'order_type' => 2,
|
||||
'url' => "http://example.com/feed2",
|
||||
'title' => "eek",
|
||||
'folder' => null,
|
||||
'top_folder' => null,
|
||||
'folder_name' => null,
|
||||
'top_folder_name' => null,
|
||||
'unread' => 4,
|
||||
'pinned' => 1,
|
||||
'order_type' => 2,
|
||||
],
|
||||
[
|
||||
'url' => "http://example.com/feed3",
|
||||
'title' => "Ook",
|
||||
'folder' => 2,
|
||||
'top_folder' => 1,
|
||||
'unread' => 2,
|
||||
'pinned' => 0,
|
||||
'order_type' => 1,
|
||||
'url' => "http://example.com/feed3",
|
||||
'title' => "Ook",
|
||||
'folder' => 2,
|
||||
'top_folder' => 1,
|
||||
'folder_name' => "Software",
|
||||
'top_folder_name' => "Technology",
|
||||
'unread' => 2,
|
||||
'pinned' => 0,
|
||||
'order_type' => 1,
|
||||
],
|
||||
];
|
||||
$this->assertResult($exp, Arsse::$db->subscriptionList($this->user));
|
||||
|
|
|
@ -67,8 +67,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
],
|
||||
];
|
||||
protected $feeds = [
|
||||
['id' => 1, 'feed' => 12, 'url' => "http://example.com/ook", 'title' => "Ook", 'source' => "http://example.com/", 'icon_id' => 47, 'icon_url' => "http://example.com/icon", 'folder' => 2112, 'top_folder' => 5, 'pinned' => 0, 'err_count' => 1, 'err_msg' => "Oopsie", 'order_type' => 0, 'keep_rule' => "this|that", 'block_rule' => "both", 'added' => "2020-12-21 21:12:00", 'updated' => "2021-01-05 13:51:32", 'edited' => "2021-01-01 00:00:00", 'modified' => "2020-11-30 04:08:52", 'next_fetch' => "2021-01-20 00:00:00", 'etag' => "OOKEEK", 'scrape' => 0, 'unread' => 42],
|
||||
['id' => 55, 'feed' => 12, 'url' => "http://j%20k:super%20secret@example.com/eek", 'title' => "Eek", 'source' => "http://example.com/", 'icon_id' => null, 'icon_url' => null, 'folder' => null, 'top_folder' => null, 'pinned' => 0, 'err_count' => 0, 'err_msg' => null, 'order_type' => 0, 'keep_rule' => null, 'block_rule' => null, 'added' => "2020-12-21 21:12:00", 'updated' => "2021-01-05 13:51:32", 'edited' => null, 'modified' => "2020-11-30 04:08:52", 'next_fetch' => null, 'etag' => null, 'scrape' => 1, 'unread' => 0],
|
||||
['id' => 1, 'feed' => 12, 'url' => "http://example.com/ook", 'title' => "Ook", 'source' => "http://example.com/", 'icon_id' => 47, 'icon_url' => "http://example.com/icon", 'folder' => 2112, 'top_folder' => 5, 'folder_name' => "Cat Eek", 'top_folder_name' => "Cat Ook", 'pinned' => 0, 'err_count' => 1, 'err_msg' => "Oopsie", 'order_type' => 0, 'keep_rule' => "this|that", 'block_rule' => "both", 'added' => "2020-12-21 21:12:00", 'updated' => "2021-01-05 13:51:32", 'edited' => "2021-01-01 00:00:00", 'modified' => "2020-11-30 04:08:52", 'next_fetch' => "2021-01-20 00:00:00", 'etag' => "OOKEEK", 'scrape' => 0, 'unread' => 42],
|
||||
['id' => 55, 'feed' => 12, 'url' => "http://j%20k:super%20secret@example.com/eek", 'title' => "Eek", 'source' => "http://example.com/", 'icon_id' => null, 'icon_url' => null, 'folder' => null, 'top_folder' => null, 'folder_name' => null, 'top_folder_name' => null, 'pinned' => 0, 'err_count' => 0, 'err_msg' => null, 'order_type' => 0, 'keep_rule' => null, 'block_rule' => null, 'added' => "2020-12-21 21:12:00", 'updated' => "2021-01-05 13:51:32", 'edited' => null, 'modified' => "2020-11-30 04:08:52", 'next_fetch' => null, 'etag' => null, 'scrape' => 1, 'unread' => 0],
|
||||
];
|
||||
protected $feedsOut = [
|
||||
['id' => 1, 'user_id' => 42, 'feed_url' => "http://example.com/ook", 'site_url' => "http://example.com/", 'title' => "Ook", 'checked_at' => "2021-01-05T13:51:32.000000Z", 'next_check_at' => "2021-01-20T00:00:00.000000Z", 'etag_header' => "OOKEEK", 'last_modified_header' => "Fri, 01 Jan 2021 00:00:00 GMT", 'parsing_error_message' => "Oopsie", 'parsing_error_count' => 1, 'scraper_rules' => "", 'rewrite_rules' => "", 'crawler' => false, 'blocklist_rules' => "both", 'keeplist_rules' => "this|that", 'user_agent' => "", 'username' => "", 'password' => "", 'disabled' => false, 'ignore_http_cache' => false, 'fetch_via_proxy' => false, 'category' => ['id' => 6, 'title' => "Cat Ook", 'user_id' => 42], 'icon' => ['feed_id' => 1,'icon_id' => 47]],
|
||||
|
@ -545,18 +545,12 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
}
|
||||
|
||||
public function testListFeeds(): void {
|
||||
\Phake::when(Arsse::$db)->folderList->thenReturn(new Result($this->v([
|
||||
['id' => 5, 'name' => "Cat Ook"],
|
||||
])));
|
||||
\Phake::when(Arsse::$db)->subscriptionList->thenReturn(new Result($this->v($this->feeds)));
|
||||
$exp = new Response($this->feedsOut);
|
||||
$this->assertMessage($exp, $this->req("GET", "/feeds"));
|
||||
}
|
||||
|
||||
public function testListFeedsOfACategory(): void {
|
||||
\Phake::when(Arsse::$db)->folderList->thenReturn(new Result($this->v([
|
||||
['id' => 5, 'name' => "Cat Ook"],
|
||||
])));
|
||||
\Phake::when(Arsse::$db)->subscriptionList->thenReturn(new Result($this->v($this->feeds)));
|
||||
$exp = new Response($this->feedsOut);
|
||||
$this->assertMessage($exp, $this->req("GET", "/categories/2112/feeds"));
|
||||
|
@ -564,7 +558,6 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
}
|
||||
|
||||
public function testListFeedsOfTheRootCategory(): void {
|
||||
\Phake::when(Arsse::$db)->folderList->thenReturn(new Result($this->v([['id' => 5, 'name' => "Cat Ook"],])));
|
||||
\Phake::when(Arsse::$db)->subscriptionList->thenReturn(new Result($this->v($this->feeds)));
|
||||
$exp = new Response($this->feedsOut);
|
||||
$this->assertMessage($exp, $this->req("GET", "/categories/1/feeds"));
|
||||
|
@ -580,7 +573,6 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function testGetAFeed(): void {
|
||||
\Phake::when(Arsse::$db)->subscriptionPropertiesGet->thenReturn($this->v($this->feeds[0]))->thenReturn($this->v($this->feeds[1]));
|
||||
\Phake::when(Arsse::$db)->folderList->thenReturn(new Result($this->v([['id' => 5, 'name' => "Cat Ook"],])));
|
||||
$this->assertMessage(new Response($this->feedsOut[0]), $this->req("GET", "/feeds/1"));
|
||||
\Phake::verify(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 1);
|
||||
$this->assertMessage(new Response($this->feedsOut[1]), $this->req("GET", "/feeds/55"));
|
||||
|
|
Loading…
Reference in a new issue