aboutsummaryrefslogtreecommitdiff
path: root/p/api
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2018-09-29 20:47:17 +0200
committerGravatar GitHub <noreply@github.com> 2018-09-29 20:47:17 +0200
commit8ee8a573f1f7e9cc45f9b3c46627d15670f14f3a (patch)
tree14200758ab43e4031f60b46b8c6e9018b43e53af /p/api
parent3ae1b57c9d2e23157be54e8fe9865b85872ff9e7 (diff)
Custom labels (#2027)
* First draft of custom tags https://github.com/FreshRSS/FreshRSS/issues/928 https://github.com/FreshRSS/FreshRSS/issues/1367 * SMALLINT to BIGINT for id_entry And uppercase SQL types * Fix layout for unreads * Start UI menu * Change menu order * Clean database helpers https://github.com/FreshRSS/FreshRSS/pull/2027#discussion_r217971535 * Travis rules do not understand PostgreSQL constants Grrr * Tag controller + UI * Add column attributes to tags * Use only favicon for now, for label * Fix styling for different themes * Constant for maximum InnoDB index length in Unicode https://github.com/FreshRSS/FreshRSS/pull/2027#discussion_r219052200 (I would have personnally prefered keeping the readability of a real value instead of a constant, in this case of many SQL fields) * Use FreshRSS_Factory::createCategoryDao * Add view of all articles containing any tag * Fix search in tags * Mark as read tags * Partial auto-update unread tags * More auto update tag unreads * Add tag deletion * Do not purge tagged articles * Minor comment * Fix SQLite and UI bug * Google Reader API support for user tags Add SQL check that tag names must be distinct from category names * whitespace * Add missing API for EasyRSS * Compatibility SQLite Problematic parentheses * Add SQL DISTINCT for cases with multiple tags * Fix for PostgreSQL PostgreSQL needs some additional type hint to avoid "could not determine data type of parameter $1" http://www.postgresql-archive.org/Could-not-determine-data-type-of-parameter-1-tp2171092p2171094.html
Diffstat (limited to 'p/api')
-rw-r--r--p/api/fever.php4
-rw-r--r--p/api/greader.php167
2 files changed, 147 insertions, 24 deletions
diff --git a/p/api/fever.php b/p/api/fever.php
index abbade768..bf38dc662 100644
--- a/p/api/fever.php
+++ b/p/api/fever.php
@@ -312,7 +312,7 @@ class FeverAPI
{
$groups = array();
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$categories = $categoryDAO->listCategories(false, false);
/** @var FreshRSS_Category $category */
@@ -457,7 +457,7 @@ class FeverAPI
}
if (isset($_REQUEST['group_ids'])) {
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$group_ids = explode(',', $_REQUEST['group_ids']);
foreach ($group_ids as $id) {
/** @var FreshRSS_Category $category */
diff --git a/p/api/greader.php b/p/api/greader.php
index f5b84f7a1..27362082e 100644
--- a/p/api/greader.php
+++ b/p/api/greader.php
@@ -42,6 +42,12 @@ if (PHP_INT_SIZE < 8) { //32-bit
}
}
+if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ define('JSON_OPTIONS', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+} else {
+ define('JSON_OPTIONS', 0);
+}
+
function headerVariable($headerName, $varName) {
$header = '';
$upName = 'HTTP_' . strtoupper($headerName);
@@ -234,7 +240,7 @@ function userInfo() { //https://github.com/theoldreader/api#user-info
'userName' => $user,
'userProfileId' => $user,
'userEmail' => FreshRSS_Context::$user_conf->mail_login,
- )));
+ ), JSON_OPTIONS));
}
function tagList() {
@@ -254,10 +260,24 @@ function tagList() {
$tags[] = array(
'id' => 'user/-/label/' . $cName,
//'sortid' => $cName,
+ 'type' => 'folder', //Inoreader
);
}
- echo json_encode(array('tags' => $tags)), "\n";
+ unset($res);
+
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $labels = $tagDAO->listTags(true);
+ foreach ($labels as $label) {
+ $tags[] = array(
+ 'id' => 'user/-/label/' . $label->name(),
+ //'sortid' => $cName,
+ 'type' => 'tag', //Inoreader
+ 'unread_count' => $label->nbUnread(),
+ );
+ }
+
+ echo json_encode(array('tags' => $tags), JSON_OPTIONS), "\n";
exit();
}
@@ -293,7 +313,7 @@ function subscriptionList() {
);
}
- echo json_encode(array('subscriptions' => $subscriptions)), "\n";
+ echo json_encode(array('subscriptions' => $subscriptions), JSON_OPTIONS), "\n";
exit();
}
@@ -310,7 +330,7 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = '
$addCatId = 0;
$categoryDAO = null;
if ($add != '' || $remove != '') {
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
}
$c_name = '';
if ($add != '' && strpos($add, 'user/') === 0) { //user/-/label/Example ; user/username/label/Example
@@ -391,13 +411,13 @@ function quickadd($url) {
exit(json_encode(array(
'numResults' => 1,
'streamId' => $feed->id(),
- )));
+ ), JSON_OPTIONS));
} catch (Exception $e) {
Minz_Log::error('quickadd error: ' . $e->getMessage(), API_LOG);
die(json_encode(array(
'numResults' => 0,
'error' => $e->getMessage(),
- )));
+ ), JSON_OPTIONS));
}
}
@@ -407,7 +427,7 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl
$totalUnreads = 0;
$totalLastUpdate = 0;
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
foreach ($categoryDAO->listCategories(true, true) as $cat) {
$catLastUpdate = 0;
foreach ($cat->feeds() as $feed) {
@@ -432,6 +452,14 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl
}
}
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ foreach ($tagDAO->listTags(true) as $label) {
+ $unreadcounts[] = array(
+ 'id' => 'user/-/label/' . $label->name(),
+ 'count' => $label->nbUnread(),
+ );
+ }
+
$unreadcounts[] = array(
'id' => 'user/-/state/com.google/reading-list',
'count' => $totalUnreads,
@@ -441,13 +469,21 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl
echo json_encode(array(
'max' => $totalUnreads,
'unreadcounts' => $unreadcounts,
- )), "\n";
+ ), JSON_OPTIONS), "\n";
exit();
}
function entriesToArray($entries) {
+ if (empty($entries)) {
+ return array();
+ }
$feedDAO = FreshRSS_Factory::createFeedDao();
$arrayFeedCategoryNames = $feedDAO->arrayFeedCategoryNames();
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $entryIdsTagNames = $tagDAO->getEntryIdsTagNames($entries);
+ if ($entryIdsTagNames == false) {
+ $entryIdsTagNames = array();
+ }
$items = array();
foreach ($entries as $entry) {
@@ -472,7 +508,6 @@ function entriesToArray($entries) {
'categories' => array(
'user/-/state/com.google/reading-list',
'user/-/label/' . $c_name,
- //TODO: Add other tags
),
'origin' => array(
'streamId' => 'feed/' . $f_id,
@@ -490,6 +525,10 @@ function entriesToArray($entries) {
if ($entry->isFavorite()) {
$item['categories'][] = 'user/-/state/com.google/starred';
}
+ $tagNames = isset($entryIdsTagNames['e_' . $entry->id()]) ? $entryIdsTagNames['e_' . $entry->id()] : array();
+ foreach ($tagNames as $tagName) {
+ $item['categories'][] = 'user/-/label/' . $tagName;
+ }
$items[] = $item;
}
return $items;
@@ -511,10 +550,22 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex
$type = 'f';
break;
case 'label':
- $type = 'c';
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$cat = $categoryDAO->searchByName($include_target);
- $include_target = $cat == null ? -1 : $cat->id();
+ if ($cat != null) {
+ $type = 'c';
+ $include_target = $cat->id();
+ } else {
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $tag = $tagDAO->searchByName($include_target);
+ if ($tag != null) {
+ $type = 't';
+ $include_target = $tag->id();
+ } else {
+ $type = 'A';
+ $include_target = -1;
+ }
+ }
break;
default:
$type = 'A';
@@ -559,7 +610,7 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex
}
}
- echo json_encode($response), "\n";
+ echo json_encode($response, JSON_OPTIONS), "\n";
exit();
}
@@ -579,9 +630,22 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude
} elseif (strpos($streamId, 'user/-/label/') === 0) {
$type = 'c';
$c_name = substr($streamId, 13);
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$cat = $categoryDAO->searchByName($c_name);
- $id = $cat == null ? -1 : $cat->id();
+ if ($cat != null) {
+ $type = 'c';
+ $id = $cat->id();
+ } else {
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $tag = $tagDAO->searchByName($c_name);
+ if ($tag != null) {
+ $type = 't';
+ $id = $tag->id();
+ } else {
+ $type = 'A';
+ $id = -1;
+ }
+ }
}
switch ($exclude_target) {
@@ -625,7 +689,7 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude
}
}
- echo json_encode($response), "\n";
+ echo json_encode($response, JSON_OPTIONS), "\n";
exit();
}
@@ -647,7 +711,7 @@ function streamContentsItems($e_ids, $order) {
'items' => $items,
);
- echo json_encode($response), "\n";
+ echo json_encode($response, JSON_OPTIONS), "\n";
exit();
}
@@ -657,6 +721,7 @@ function editTag($e_ids, $a, $r) {
}
$entryDAO = FreshRSS_Factory::createEntryDao();
+ $tagDAO = FreshRSS_Factory::createTagDao();
switch ($a) {
case 'user/-/state/com.google/read':
@@ -671,6 +736,30 @@ function editTag($e_ids, $a, $r) {
break;
case 'user/-/state/com.google/broadcast':
break;*/
+ default:
+ $tagName = '';
+ if (strpos($a, 'user/-/label/') === 0) {
+ $tagName = substr($a, 13);
+ } else {
+ $user = Minz_Session::param('currentUser', '_');
+ $prefix = 'user/' . $user . '/label/';
+ if (strpos($a, $prefix) === 0) {
+ $tagName = substr($a, strlen($prefix));
+ }
+ }
+ if ($tagName != '') {
+ $tag = $tagDAO->searchByName($tagName);
+ if ($tag == null) {
+ $tagDAO->addTag(array('name' => $tagName));
+ $tag = $tagDAO->searchByName($tagName);
+ }
+ if ($tag != null) {
+ foreach ($e_ids as $e_id) {
+ $tagDAO->tagEntry($tag->id(), $e_id, true);
+ }
+ }
+ }
+ break;
}
switch ($r) {
case 'user/-/state/com.google/read':
@@ -679,6 +768,17 @@ function editTag($e_ids, $a, $r) {
case 'user/-/state/com.google/starred':
$entryDAO->markFavorite($e_ids, false);
break;
+ default:
+ if (strpos($r, 'user/-/label/') === 0) {
+ $tagName = substr($r, 13);
+ $tag = $tagDAO->searchByName($tagName);
+ if ($tag != null) {
+ foreach ($e_ids as $e_id) {
+ $tagDAO->tagEntry($tag->id(), $e_id, false);
+ }
+ }
+ }
+ break;
}
exit('OK');
@@ -688,12 +788,20 @@ function renameTag($s, $dest) {
if ($s != '' && strpos($s, 'user/-/label/') === 0 &&
$dest != '' && strpos($dest, 'user/-/label/') === 0) {
$s = substr($s, 13);
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $dest = substr($dest, 13);
+
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$cat = $categoryDAO->searchByName($s);
if ($cat != null) {
- $dest = substr($dest, 13);
$categoryDAO->updateCategory($cat->id(), array('name' => $dest));
exit('OK');
+ } else {
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $tag = $tagDAO->searchByName($s);
+ if ($tag != null) {
+ $tagDAO->updateTag($tag->id(), array('name' => $dest));
+ exit('OK');
+ }
}
}
badRequest();
@@ -702,7 +810,7 @@ function renameTag($s, $dest) {
function disableTag($s) {
if ($s != '' && strpos($s, 'user/-/label/') === 0) {
$s = substr($s, 13);
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$cat = $categoryDAO->searchByName($s);
if ($cat != null) {
$feedDAO = FreshRSS_Factory::createFeedDao();
@@ -711,6 +819,13 @@ function disableTag($s) {
$categoryDAO->deleteCategory($cat->id());
}
exit('OK');
+ } else {
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $tag = $tagDAO->searchByName($s);
+ if ($tag != null) {
+ $tagDAO->deleteTag($tag->id());
+ exit('OK');
+ }
}
}
badRequest();
@@ -723,9 +838,17 @@ function markAllAsRead($streamId, $olderThanId) {
$entryDAO->markReadFeed($f_id, $olderThanId);
} elseif (strpos($streamId, 'user/-/label/') === 0) {
$c_name = substr($streamId, 13);
- $categoryDAO = new FreshRSS_CategoryDAO();
+ $categoryDAO = FreshRSS_Factory::createCategoryDao();
$cat = $categoryDAO->searchByName($c_name);
- $entryDAO->markReadCat($cat === null ? -1 : $cat->id(), $olderThanId);
+ if ($cat != null) {
+ $entryDAO->markReadCat($cat->id(), $olderThanId);
+ } else {
+ $tagDAO = FreshRSS_Factory::createTagDao();
+ $tag = $tagDAO->searchByName($c_name);
+ if ($tag != null) {
+ $entryDAO->markReadTag($tag->id(), $olderThanId);
+ }
+ }
} elseif ($streamId === 'user/-/state/com.google/reading-list') {
$entryDAO->markReadEntries($olderThanId, false, -1);
}