Add feed group feature
- each feed can have multiple groups assigned - group assignments are done on the add or edit feed page - groups are only visible on the unread page - groups are exported via the fever api - it's not possible do delete a group manually from the database (the group will be removed automatically, as soon as the last association of a group to a feed is removed) - if you try to create an already existing group, the existing group is used to prevent duplicates
This commit is contained in:
parent
e214785be7
commit
dd47b3f82e
@ -247,6 +247,38 @@ textarea.form-error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Feed group buttons */
|
||||
#grouplist span {
|
||||
float: left;
|
||||
opacity: 0.4;
|
||||
min-width: 4em;
|
||||
margin-right: 6px;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#grouplist input[type="text"] {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
#grouplist input[type="checkbox"] + span, #grouplist input[type="text"] {
|
||||
padding: 4px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#grouplist input[type="checkbox"]:checked + span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul#grouplist {
|
||||
float: left;
|
||||
}
|
||||
|
||||
ul#grouplist li {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
/* alerts */
|
||||
.alert, .panel {
|
||||
padding: 8px 35px 8px 14px;
|
||||
@ -287,7 +319,7 @@ textarea.form-error {
|
||||
}
|
||||
|
||||
/* buttons */
|
||||
.btn {
|
||||
.btn, #grouplist span {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
display: inline-block;
|
||||
|
@ -22,7 +22,8 @@
|
||||
"models/schema.php",
|
||||
"models/auto_update.php",
|
||||
"models/database.php",
|
||||
"models/remember_me.php"
|
||||
"models/remember_me.php",
|
||||
"models/group.php"
|
||||
],
|
||||
"classmap": [
|
||||
"vendor/fguillot/json-rpc/src/",
|
||||
|
@ -19,10 +19,16 @@ Router\get_action('edit-feed', function() {
|
||||
|
||||
$id = Request\int_param('feed_id');
|
||||
|
||||
$values = Model\Feed\get($id);
|
||||
$values += array(
|
||||
'feed_group_ids' => Model\Group\get_feed_group_ids($id)
|
||||
);
|
||||
|
||||
Response\html(Template\layout('edit_feed', array(
|
||||
'values' => Model\Feed\get($id),
|
||||
'values' => $values,
|
||||
'errors' => array(),
|
||||
'nb_unread_items' => Model\Item\count_by_status('unread'),
|
||||
'groups' => Model\Group\get_all(),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('Edit subscription')
|
||||
)));
|
||||
@ -32,7 +38,14 @@ Router\get_action('edit-feed', function() {
|
||||
Router\post_action('edit-feed', function() {
|
||||
|
||||
$values = Request\values();
|
||||
$values += array('enabled' => 0, 'download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
|
||||
$values += array(
|
||||
'enabled' => 0,
|
||||
'download_content' => 0,
|
||||
'rtl' => 0,
|
||||
'cloak_referrer' => 0,
|
||||
'feed_group_ids' => array(),
|
||||
'create_group' => ''
|
||||
);
|
||||
|
||||
list($valid, $errors) = Model\Feed\validate_modification($values);
|
||||
|
||||
@ -50,6 +63,7 @@ Router\post_action('edit-feed', function() {
|
||||
'values' => $values,
|
||||
'errors' => $errors,
|
||||
'nb_unread_items' => Model\Item\count_by_status('unread'),
|
||||
'groups' => Model\Group\get_all(),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('Edit subscription')
|
||||
)));
|
||||
@ -129,12 +143,19 @@ Router\get_action('feeds', function() {
|
||||
// Display form to add one feed
|
||||
Router\get_action('add', function() {
|
||||
|
||||
$values = array('download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
|
||||
$values = array(
|
||||
'download_content' => 0,
|
||||
'rtl' => 0,
|
||||
'cloak_referrer' => 0,
|
||||
'create_group' => '',
|
||||
'feed_group_ids' => array()
|
||||
);
|
||||
|
||||
Response\html(Template\layout('add', array(
|
||||
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
|
||||
'errors' => array(),
|
||||
'nb_unread_items' => Model\Item\count_by_status('unread'),
|
||||
'groups' => Model\Group\get_all(),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('New subscription')
|
||||
)));
|
||||
@ -158,10 +179,24 @@ Router\action('subscribe', function() {
|
||||
}
|
||||
}
|
||||
|
||||
$values += array('url' => trim($url), 'download_content' => 0, 'rtl' => 0, 'cloak_referrer' => 0);
|
||||
$values += array(
|
||||
'url' => trim($url),
|
||||
'download_content' => 0,
|
||||
'rtl' => 0,
|
||||
'cloak_referrer' => 0,
|
||||
'create_group' => '',
|
||||
'feed_group_ids' => array()
|
||||
);
|
||||
|
||||
try {
|
||||
$feed_id = Model\Feed\create($values['url'], $values['download_content'], $values['rtl'], $values['cloak_referrer']);
|
||||
$feed_id = Model\Feed\create(
|
||||
$values['url'],
|
||||
$values['download_content'],
|
||||
$values['rtl'],
|
||||
$values['cloak_referrer'],
|
||||
$values['feed_group_ids'],
|
||||
$values['create_group']
|
||||
);
|
||||
}
|
||||
catch (UnexpectedValueException $e) {
|
||||
$error_message = t('This subscription already exists.');
|
||||
@ -210,6 +245,7 @@ Router\action('subscribe', function() {
|
||||
Response\html(Template\layout('add', array(
|
||||
'values' => $values + array('csrf' => Model\Config\generate_csrf()),
|
||||
'nb_unread_items' => Model\Item\count_by_status('unread'),
|
||||
'groups' => Model\Group\get_all(),
|
||||
'menu' => 'feeds',
|
||||
'title' => t('Subscriptions')
|
||||
)));
|
||||
|
@ -12,6 +12,7 @@ Router\get_action('history', function() {
|
||||
$nb_items = Model\Item\count_by_status('read');
|
||||
$items = Model\Item\get_all_by_status(
|
||||
'read',
|
||||
null,
|
||||
$offset,
|
||||
Model\Config\get('items_per_page'),
|
||||
'updated',
|
||||
|
@ -14,11 +14,26 @@ Router\get_action('unread', function() {
|
||||
$order = Request\param('order', 'updated');
|
||||
$direction = Request\param('direction', Model\Config\get('items_sorting_direction'));
|
||||
$offset = Request\int_param('offset', 0);
|
||||
$items = Model\Item\get_all_by_status('unread', $offset, Model\Config\get('items_per_page'), $order, $direction);
|
||||
$nb_items = Model\Item\count_by_status('unread');
|
||||
$group_id = Request\int_param('group_id', null);
|
||||
$feed_ids = null;
|
||||
|
||||
if ($nb_items === 0) {
|
||||
if (!is_null($group_id)) {
|
||||
$feed_ids = Model\Group\get_feeds_by_group($group_id);
|
||||
}
|
||||
|
||||
$items = Model\Item\get_all_by_status(
|
||||
'unread',
|
||||
$feed_ids,
|
||||
$offset,
|
||||
Model\Config\get('items_per_page'),
|
||||
$order,
|
||||
$direction
|
||||
);
|
||||
|
||||
$nb_items = Model\Item\count_by_status('unread', $feed_ids);
|
||||
$nb_unread_items = Model\Item\count_by_status('unread');
|
||||
|
||||
if ($nb_unread_items === 0) {
|
||||
$action = Model\Config\get('redirect_nothing_to_read');
|
||||
Response\redirect('?action='.$action.'¬hing_to_read=1');
|
||||
}
|
||||
@ -29,13 +44,15 @@ Router\get_action('unread', function() {
|
||||
'order' => $order,
|
||||
'direction' => $direction,
|
||||
'display_mode' => Model\Config\get('items_display_mode'),
|
||||
'group_id' => $group_id,
|
||||
'items' => $items,
|
||||
'nb_items' => $nb_items,
|
||||
'nb_unread_items' => $nb_items,
|
||||
'nb_unread_items' => $nb_unread_items,
|
||||
'offset' => $offset,
|
||||
'items_per_page' => Model\Config\get('items_per_page'),
|
||||
'title' => 'Miniflux ('.$nb_items.')',
|
||||
'menu' => 'unread'
|
||||
'menu' => 'unread',
|
||||
'groups' => Model\Group\get_all()
|
||||
)));
|
||||
});
|
||||
|
||||
@ -146,10 +163,18 @@ Router\post_action('mark-item-unread', function() {
|
||||
Response\json(array('Ok'));
|
||||
});
|
||||
|
||||
// Mark all unread items as read
|
||||
// Mark unread items as read
|
||||
Router\get_action('mark-all-read', function() {
|
||||
|
||||
Model\Item\mark_all_as_read();
|
||||
$group_id = Request\int_param('group_id', null);
|
||||
|
||||
if (!is_null($group_id)) {
|
||||
Model\Item\mark_group_as_read($group_id);
|
||||
}
|
||||
else {
|
||||
Model\Item\mark_all_as_read();
|
||||
}
|
||||
|
||||
Response\redirect('?action=unread');
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
require '../common.php';
|
||||
|
||||
use Model\Feed;
|
||||
use Model\Group;
|
||||
use Model\Service;
|
||||
use PicoDb\Database;
|
||||
|
||||
@ -59,8 +60,16 @@ route('groups', function() {
|
||||
|
||||
if ($response['auth']) {
|
||||
|
||||
$response['groups'] = array();
|
||||
$response['groups'] = Group\get_all();
|
||||
$response['feeds_groups'] = array();
|
||||
$group_map = Group\get_map();
|
||||
|
||||
foreach ($group_map as $group_id => $feed_ids) {
|
||||
$response['feeds_groups'][] = array(
|
||||
'group_id' => $group_id,
|
||||
'feed_ids' => implode(',', $feed_ids)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
response($response);
|
||||
@ -89,6 +98,14 @@ route('feeds', function() {
|
||||
'last_updated_on_time' => $feed['last_checked'] ?: time(),
|
||||
);
|
||||
}
|
||||
|
||||
$group_map = Group\get_map();
|
||||
foreach ($group_map as $group_id => $feed_ids) {
|
||||
$response['feeds_groups'][] = array(
|
||||
'group_id' => $group_id,
|
||||
'feed_ids' => implode(',', $feed_ids)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
response($response);
|
||||
@ -286,11 +303,15 @@ route('write_groups', function() {
|
||||
$response = auth();
|
||||
|
||||
if ($response['auth']) {
|
||||
$db = Database::get('db')
|
||||
->table('items')
|
||||
->lte('updated', $_POST['before']);
|
||||
|
||||
Database::get('db')
|
||||
->table('items')
|
||||
->lte('updated', $_POST['before'])
|
||||
->update(array('status' => 'read'));
|
||||
if ($_POST['id'] > 0) {
|
||||
$db->in('feed_id', Model\Group\get_feeds_by_group($_POST['id']));
|
||||
}
|
||||
|
||||
$db->update(array('status' => 'read'));
|
||||
}
|
||||
|
||||
response($response);
|
||||
|
@ -115,7 +115,7 @@ $server->register('item.bookmark.delete', function ($item_id) {
|
||||
// Get all unread items
|
||||
$server->register('item.list_unread', function ($offset = null, $limit = null) {
|
||||
|
||||
return Model\Item\get_all_by_status('unread', $offset, $limit);
|
||||
return Model\Item\get_all_by_status('unread', null, $offset, $limit);
|
||||
});
|
||||
|
||||
// Count all unread items
|
||||
@ -127,7 +127,7 @@ $server->register('item.count_unread', function () {
|
||||
// Get all read items
|
||||
$server->register('item.list_read', function ($offset = null, $limit = null) {
|
||||
|
||||
return Model\Item\get_all_by_status('read', $offset, $limit);
|
||||
return Model\Item\get_all_by_status('read', null, $offset, $limit);
|
||||
});
|
||||
|
||||
// Count all read items
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
'Maximum number of HTTP redirections exceeded.' => 'Nombre maximal de redirections HTTP dépassé.',
|
||||
'The content size exceeds to maximum allowed size.' => 'La taille du contenu dépasse la taille maximale autorisée.',
|
||||
'Unable to detect the feed format.' => 'Impossible de détecter le format du flux.',
|
||||
'add a new group' => 'add a new group',
|
||||
'Groups' => 'Groups',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -238,4 +238,6 @@ return array(
|
||||
// 'Maximum number of HTTP redirections exceeded.' => '',
|
||||
// 'The content size exceeds to maximum allowed size.' => '',
|
||||
// 'Unable to detect the feed format.' => '',
|
||||
// 'add a new group' => '',
|
||||
// 'Groups' => '',
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ namespace Model\Feed;
|
||||
use UnexpectedValueException;
|
||||
use Model\Config;
|
||||
use Model\Item;
|
||||
use Model\Group;
|
||||
use SimpleValidator\Validator;
|
||||
use SimpleValidator\Validators;
|
||||
use PicoDb\Database;
|
||||
@ -93,7 +94,9 @@ function get_all_favicons()
|
||||
// Update feed information
|
||||
function update(array $values)
|
||||
{
|
||||
return Database::get('db')
|
||||
Database::get('db')->startTransaction();
|
||||
|
||||
$result = Database::get('db')
|
||||
->table('feeds')
|
||||
->eq('id', $values['id'])
|
||||
->save(array(
|
||||
@ -105,6 +108,17 @@ function update(array $values)
|
||||
'download_content' => $values['download_content'],
|
||||
'cloak_referrer' => $values['cloak_referrer'],
|
||||
));
|
||||
|
||||
if ($result) {
|
||||
if (! Group\update_feed_groups($values['id'], $values['feed_group_ids'], $values['create_group'])) {
|
||||
Database::get('db')->cancelTransaction();
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
Database::get('db')->closeTransaction();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Export all feeds
|
||||
@ -150,7 +164,7 @@ function import_opml($content)
|
||||
}
|
||||
|
||||
// Add a new feed from an URL
|
||||
function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referrer = false)
|
||||
function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referrer = false, $group_ids = array(), $create_group = '')
|
||||
{
|
||||
$feed_id = false;
|
||||
|
||||
@ -194,6 +208,7 @@ function create($url, $enable_grabber = false, $force_rtl = false, $cloak_referr
|
||||
if ($result) {
|
||||
$feed_id = $db->getConnection()->getLastId();
|
||||
|
||||
Group\update_feed_groups($feed_id, $group_ids, $create_group);
|
||||
Item\update_all($feed_id, $feed->getItems());
|
||||
fetch_favicon($feed_id, $feed->getSiteUrl(), $feed->getIcon());
|
||||
}
|
||||
|
220
models/group.php
Normal file
220
models/group.php
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Model\Group;
|
||||
|
||||
use PicoDb\Database;
|
||||
|
||||
/**
|
||||
* Get all groups
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_all()
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('groups')
|
||||
->orderBy('title')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assoc array of group ids with assigned feeds ids
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_map()
|
||||
{
|
||||
$result = Database::get('db')
|
||||
->table('feeds_groups')
|
||||
->findAll();
|
||||
|
||||
// TODO: add PDO::FETCH_COLUMN|PDO::FETCH_GROUP to picodb and use it instead
|
||||
// of the following lines
|
||||
$map = array();
|
||||
|
||||
foreach ($result as $row) {
|
||||
$group_id = $row['group_id'];
|
||||
$feed_id = $row['feed_id'];
|
||||
|
||||
if (isset($map[$group_id])) {
|
||||
$map[$group_id][] = $feed_id;
|
||||
}
|
||||
else {
|
||||
$map[$group_id] = array($feed_id);
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all groups assigned to feed
|
||||
*
|
||||
* @param integer $feed_id id of the feed
|
||||
* @return array
|
||||
*/
|
||||
function get_feed_group_ids($feed_id)
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('groups')
|
||||
->join('feeds_groups', 'group_id', 'id')
|
||||
->eq('feed_id', $feed_id)
|
||||
->findAllByColumn('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of a group
|
||||
*
|
||||
* @param string $title group name
|
||||
* @return mixed group id or false if not found
|
||||
*/
|
||||
function get_group_id($title)
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('groups')
|
||||
->eq('title', $title)
|
||||
->findOneColumn('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all feed ids assigned to a group
|
||||
*
|
||||
* @param array $group_id
|
||||
* @return array
|
||||
*/
|
||||
function get_feeds_by_group($group_id)
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('feeds_groups')
|
||||
->eq('group_id', $group_id)
|
||||
->findAllByColumn('feed_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group to the Database
|
||||
*
|
||||
* Returns either the id of the new group or the id of an existing group with
|
||||
* the same name
|
||||
*
|
||||
* @param string $title group name
|
||||
* @return mixed id of the created group or false on error
|
||||
*/
|
||||
function create($title)
|
||||
{
|
||||
$data = array('title' => $title);
|
||||
|
||||
// check if the group already exists
|
||||
$group_id = get_group_id($title);
|
||||
|
||||
// create group if missing
|
||||
if ($group_id === false) {
|
||||
Database::get('db')
|
||||
->table('groups')
|
||||
->insert($data);
|
||||
|
||||
$group_id = get_group_id($title);
|
||||
}
|
||||
|
||||
return $group_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add groups to feed
|
||||
*
|
||||
* @param integer $feed_id feed id
|
||||
* @param array $group_ids array of group ids
|
||||
* @return boolean true on success, false on error
|
||||
*/
|
||||
function add($feed_id, $group_ids)
|
||||
{
|
||||
foreach ($group_ids as $group_id){
|
||||
$data = array('feed_id' => $feed_id, 'group_id' => $group_id);
|
||||
|
||||
$result = Database::get('db')
|
||||
->table('feeds_groups')
|
||||
->insert($data);
|
||||
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove groups from feed
|
||||
*
|
||||
* @param integer $feed_id id of the feed
|
||||
* @param array $group_ids array of group ids
|
||||
* @return boolean true on success, false on error
|
||||
*/
|
||||
function remove($feed_id, $group_ids)
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('feeds_groups')
|
||||
->eq('feed_id', $feed_id)
|
||||
->in('group_id', $group_ids)
|
||||
->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge orphaned groups from database
|
||||
*/
|
||||
function purge_groups()
|
||||
{
|
||||
$groups = Database::get('db')
|
||||
->table('groups')
|
||||
->join('feeds_groups', 'group_id', 'id')
|
||||
->isnull('feed_id')
|
||||
->findAllByColumn('id');
|
||||
|
||||
if (! empty($groups)) {
|
||||
Database::get('db')
|
||||
->table('groups')
|
||||
->in('id', $groups)
|
||||
->remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update feed group associations
|
||||
*
|
||||
* @param integer $feed_id id of the feed to update
|
||||
* @param array $group_ids valid groups ids for feed
|
||||
* @param string $create_group group to create and assign to feed
|
||||
* @return boolean
|
||||
*/
|
||||
function update_feed_groups($feed_id, $group_ids, $create_group = '')
|
||||
{
|
||||
if ($create_group !== '') {
|
||||
$id = create($create_group);
|
||||
|
||||
if ($id === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! in_array($id, $group_ids)) {
|
||||
$group_ids[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$assigned = get_feed_group_ids($feed_id);
|
||||
$superfluous = array_diff($assigned, $group_ids);
|
||||
$missing = array_diff($group_ids, $assigned);
|
||||
|
||||
// remove no longer assigned groups from feed
|
||||
if (! empty($superfluous) && ! remove($feed_id, $superfluous)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add requested groups to feed
|
||||
if (! empty($missing) && ! add($feed_id, $missing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
purge_groups();
|
||||
|
||||
return true;
|
||||
}
|
@ -4,6 +4,7 @@ namespace Model\Item;
|
||||
|
||||
use Model\Service;
|
||||
use Model\Config;
|
||||
use Model\Group;
|
||||
use PicoDb\Database;
|
||||
use PicoFeed\Logging\Logger;
|
||||
use PicoFeed\Scraper\Scraper;
|
||||
@ -89,7 +90,7 @@ function get_all_status()
|
||||
}
|
||||
|
||||
// Get all items by status
|
||||
function get_all_by_status($status, $offset = null, $limit = null, $order_column = 'updated', $order_direction = 'desc')
|
||||
function get_all_by_status($status, $feed_ids = null, $offset = null, $limit = null, $order_column = 'updated', $order_direction = 'desc')
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('items')
|
||||
@ -111,6 +112,7 @@ function get_all_by_status($status, $offset = null, $limit = null, $order_column
|
||||
)
|
||||
->join('feeds', 'id', 'feed_id')
|
||||
->eq('status', $status)
|
||||
->in('feed_id', $feed_ids)
|
||||
->orderBy($order_column, $order_direction)
|
||||
->offset($offset)
|
||||
->limit($limit)
|
||||
@ -118,11 +120,12 @@ function get_all_by_status($status, $offset = null, $limit = null, $order_column
|
||||
}
|
||||
|
||||
// Get the number of items per status
|
||||
function count_by_status($status)
|
||||
function count_by_status($status, $feed_ids = null)
|
||||
{
|
||||
return Database::get('db')
|
||||
->table('items')
|
||||
->eq('status', $status)
|
||||
->in('feed_id', $feed_ids)
|
||||
->count();
|
||||
}
|
||||
|
||||
@ -355,6 +358,19 @@ function mark_feed_as_read($feed_id)
|
||||
->update(array('status' => 'read'));
|
||||
}
|
||||
|
||||
// Mark all items of a group as read
|
||||
function mark_group_as_read($group_id)
|
||||
{
|
||||
// workaround for missing update with join
|
||||
$feed_ids = Group\get_feeds_by_group($group_id);
|
||||
|
||||
return Database::get('db')
|
||||
->table('items')
|
||||
->eq('status', 'unread')
|
||||
->in('feed_id', $feed_ids)
|
||||
->update(array('status' => 'read'));
|
||||
}
|
||||
|
||||
// Mark all read items to removed after X days
|
||||
function autoflush_read()
|
||||
{
|
||||
|
@ -5,7 +5,27 @@ namespace Schema;
|
||||
use PDO;
|
||||
use Model\Config;
|
||||
|
||||
const VERSION = 40;
|
||||
const VERSION = 41;
|
||||
|
||||
function version_41($pdo)
|
||||
{
|
||||
$pdo->exec('
|
||||
CREATE TABLE "groups" (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT
|
||||
)
|
||||
');
|
||||
|
||||
$pdo->exec('
|
||||
CREATE TABLE "feeds_groups" (
|
||||
feed_id INTEGER NOT NULL,
|
||||
group_id INTEGER NOT NULL,
|
||||
PRIMARY KEY(feed_id, group_id)
|
||||
FOREIGN KEY(group_id) REFERENCES groups(id) ON DELETE CASCADE
|
||||
FOREIGN KEY(feed_id) REFERENCES feeds(id) ON DELETE CASCADE
|
||||
)
|
||||
');
|
||||
}
|
||||
|
||||
function version_40($pdo)
|
||||
{
|
||||
|
@ -22,6 +22,16 @@
|
||||
<?= Helper\form_checkbox('cloak_referrer', t('Cloak the image referrer'), 1, $values['cloak_referrer']) ?><br />
|
||||
|
||||
<p class="form-help"><?= t('Downloading full content is slower because Miniflux grab the content from the original website. You should use that for subscriptions that display only a summary. This feature doesn\'t work with all websites.') ?></p>
|
||||
|
||||
<?= Helper\form_label(t('Groups'), 'groups'); ?>
|
||||
|
||||
<div id="grouplist">
|
||||
<?php foreach ($groups as $group): ?>
|
||||
<?= Helper\form_checkbox('feed_group_ids[]', $group['title'], $group['id'], in_array($group['id'], $values['feed_group_ids']), 'hide') ?>
|
||||
<?php endforeach ?>
|
||||
<?= Helper\form_text('create_group', $values, array(), array('placeholder="'.t('add a new group').'"')) ?>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Add') ?></button>
|
||||
<?= t('or') ?> <a href="?action=feeds"><?= t('cancel') ?></a>
|
||||
|
@ -27,7 +27,16 @@
|
||||
|
||||
<?= Helper\form_checkbox('cloak_referrer', t('Cloak the image referrer'), 1, $values['cloak_referrer']) ?><br />
|
||||
|
||||
<?= Helper\form_checkbox('enabled', t('Activated'), 1, $values['enabled']) ?>
|
||||
<?= Helper\form_checkbox('enabled', t('Activated'), 1, $values['enabled']) ?><br />
|
||||
|
||||
<?= Helper\form_label(t('Groups'), 'groups'); ?>
|
||||
|
||||
<div id="grouplist">
|
||||
<?php foreach ($groups as $group): ?>
|
||||
<?= Helper\form_checkbox('feed_group_ids[]', $group['title'], $group['id'], in_array($group['id'], $values['feed_group_ids']), 'hide') ?>
|
||||
<?php endforeach ?>
|
||||
<?= Helper\form_text('create_group', $values, array(), array('placeholder="'.t('add a new group').'"')) ?>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
|
||||
|
@ -4,6 +4,6 @@
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (($nb_items - $offset) > $items_per_page): ?>
|
||||
<a id="next-page" href="?action=<?= $menu ?>&offset=<?= ($offset + $items_per_page) ?>&order=<?= $order ?>&direction=<?= $direction ?><?= isset($feed_id) ? '&feed_id='.$feed_id : '' ?>"><?= t('Next page') ?> »</a>
|
||||
<a id="next-page" href="?action=<?= $menu ?>&offset=<?= ($offset + $items_per_page) ?>&order=<?= $order ?>&direction=<?= $direction ?><?= isset($feed_id) ? '&feed_id='.$feed_id : '' ?><?= isset($group_id) ? '&group_id='.$group_id : '' ?>"><?= t('Next page') ?> »</a>
|
||||
<?php endif ?>
|
||||
</div>
|
@ -1,37 +1,49 @@
|
||||
<?php if (empty($items)): ?>
|
||||
<p class="alert alert-info"><?= t('Nothing to read') ?></p>
|
||||
<?php else: ?>
|
||||
|
||||
|
||||
<div class="page-header">
|
||||
<h2><?= t('Unread') ?><span id="page-counter"><?= isset($nb_items) ? $nb_items : '' ?></span></h2>
|
||||
<?php if (!empty($groups)): ?>
|
||||
<nav>
|
||||
<ul id="grouplist">
|
||||
<?php foreach ($groups as $group): ?>
|
||||
<li <?= $group['id'] == $group_id ? 'class="active"' : '' ?>>
|
||||
<a href="?action=unread&group_id=<?=$group['id']?>"><?=$group['title']?></a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php endif ?>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="?action=unread&order=updated&direction=<?= $direction == 'asc' ? 'desc' : 'asc' ?>"><?= tne('sort by date %s(%s)%s', '<span class="hide-mobile">',$direction == 'desc' ? t('older first') : t('most recent first'), '</span>') ?></a>
|
||||
<a href="?action=unread<?= is_null($group_id) ? '' : '&group_id='.$group_id ?>&order=updated&direction=<?= $direction == 'asc' ? 'desc' : 'asc' ?>"><?= tne('sort by date %s(%s)%s', '<span class="hide-mobile">',$direction == 'desc' ? t('older first') : t('most recent first'), '</span>') ?></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?action=mark-all-read"><?= t('mark all as read') ?></a>
|
||||
<a href="?action=mark-all-read<?= is_null($group_id) ? '' : '&group_id='.$group_id ?>"><?= t('mark all as read') ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<section class="items" id="listing">
|
||||
<?php foreach ($items as $item): ?>
|
||||
<?= \PicoFarad\Template\load('item', array(
|
||||
'item' => $item,
|
||||
'menu' => $menu,
|
||||
'offset' => $offset,
|
||||
'hide' => true,
|
||||
'display_mode' => $display_mode,
|
||||
'favicons' => $favicons,
|
||||
'original_marks_read' => $original_marks_read,
|
||||
)) ?>
|
||||
<?php endforeach ?>
|
||||
<?php if (empty($items)): ?>
|
||||
<p class="alert alert-info"><?= t('Nothing to read') ?></p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<?= \PicoFarad\Template\load('item', array(
|
||||
'item' => $item,
|
||||
'menu' => $menu,
|
||||
'offset' => $offset,
|
||||
'hide' => true,
|
||||
'display_mode' => $display_mode,
|
||||
'favicons' => $favicons,
|
||||
'original_marks_read' => $original_marks_read,
|
||||
)) ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<div id="bottom-menu">
|
||||
<a href="?action=mark-all-read"><?= t('mark all as read') ?></a>
|
||||
</div>
|
||||
<div id="bottom-menu">
|
||||
<a href="?action=mark-all-read<?= is_null($group_id) ? '' : '&group_id='.$group_id ?>"><?= t('mark all as read') ?></a>
|
||||
</div>
|
||||
|
||||
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction)) ?>
|
||||
<?= \PicoFarad\Template\load('paging', array('menu' => $menu, 'nb_items' => $nb_items, 'items_per_page' => $items_per_page, 'offset' => $offset, 'order' => $order, 'direction' => $direction, 'group_id' => $group_id)) ?>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<?php endif ?>
|
||||
|
1
vendor/composer/autoload_files.php
vendored
1
vendor/composer/autoload_files.php
vendored
@ -18,4 +18,5 @@ return array(
|
||||
$baseDir . '/models/auto_update.php',
|
||||
$baseDir . '/models/database.php',
|
||||
$baseDir . '/models/remember_me.php',
|
||||
$baseDir . '/models/group.php',
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user