diff --git a/assets/css/app.css b/assets/css/app.css
index d0c3572..1e8741f 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -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;
diff --git a/composer.json b/composer.json
index a8a8668..ea1cf14 100644
--- a/composer.json
+++ b/composer.json
@@ -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/",
diff --git a/controllers/feed.php b/controllers/feed.php
index c39e8cc..8bdf8c9 100644
--- a/controllers/feed.php
+++ b/controllers/feed.php
@@ -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')
)));
diff --git a/controllers/history.php b/controllers/history.php
index 4fd5a27..0970e4f 100644
--- a/controllers/history.php
+++ b/controllers/history.php
@@ -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',
diff --git a/controllers/item.php b/controllers/item.php
index 0a17e93..10a15ba 100644
--- a/controllers/item.php
+++ b/controllers/item.php
@@ -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');
});
diff --git a/fever/index.php b/fever/index.php
index ae1cad6..f975f7f 100644
--- a/fever/index.php
+++ b/fever/index.php
@@ -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);
diff --git a/jsonrpc.php b/jsonrpc.php
index 9924b37..cebfbef 100644
--- a/jsonrpc.php
+++ b/jsonrpc.php
@@ -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
diff --git a/locales/ar_AR/translations.php b/locales/ar_AR/translations.php
index 0cf8e2c..1af0e8f 100644
--- a/locales/ar_AR/translations.php
+++ b/locales/ar_AR/translations.php
@@ -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' => '',
);
diff --git a/locales/cs_CZ/translations.php b/locales/cs_CZ/translations.php
index 93bc96e..1c0249f 100644
--- a/locales/cs_CZ/translations.php
+++ b/locales/cs_CZ/translations.php
@@ -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' => '',
);
diff --git a/locales/de_DE/translations.php b/locales/de_DE/translations.php
index f57c63e..61f06f8 100644
--- a/locales/de_DE/translations.php
+++ b/locales/de_DE/translations.php
@@ -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' => '',
);
diff --git a/locales/es_ES/translations.php b/locales/es_ES/translations.php
index e285e0b..3b18430 100644
--- a/locales/es_ES/translations.php
+++ b/locales/es_ES/translations.php
@@ -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' => '',
);
diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php
index 0148399..32cb259 100644
--- a/locales/fr_FR/translations.php
+++ b/locales/fr_FR/translations.php
@@ -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',
);
diff --git a/locales/it_IT/translations.php b/locales/it_IT/translations.php
index 45cf88f..8601044 100644
--- a/locales/it_IT/translations.php
+++ b/locales/it_IT/translations.php
@@ -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' => '',
);
diff --git a/locales/pt_BR/translations.php b/locales/pt_BR/translations.php
index 553bd17..01036ae 100644
--- a/locales/pt_BR/translations.php
+++ b/locales/pt_BR/translations.php
@@ -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' => '',
);
diff --git a/locales/ru_RU/translations.php b/locales/ru_RU/translations.php
index 6829649..2e477de 100644
--- a/locales/ru_RU/translations.php
+++ b/locales/ru_RU/translations.php
@@ -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' => '',
);
diff --git a/locales/sr_RS/translations.php b/locales/sr_RS/translations.php
index bffcf62..a369d26 100755
--- a/locales/sr_RS/translations.php
+++ b/locales/sr_RS/translations.php
@@ -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' => '',
);
diff --git a/locales/sr_RS@latin/translations.php b/locales/sr_RS@latin/translations.php
index fb2eefe..8cd03e0 100755
--- a/locales/sr_RS@latin/translations.php
+++ b/locales/sr_RS@latin/translations.php
@@ -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' => '',
);
diff --git a/locales/zh_CN/translations.php b/locales/zh_CN/translations.php
index daa23d1..fc939ad 100644
--- a/locales/zh_CN/translations.php
+++ b/locales/zh_CN/translations.php
@@ -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' => '',
);
diff --git a/models/feed.php b/models/feed.php
index d5308b7..0e293b2 100644
--- a/models/feed.php
+++ b/models/feed.php
@@ -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());
}
diff --git a/models/group.php b/models/group.php
new file mode 100644
index 0000000..dcdffcd
--- /dev/null
+++ b/models/group.php
@@ -0,0 +1,220 @@
+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;
+}
diff --git a/models/item.php b/models/item.php
index f66a35b..ee31a61 100644
--- a/models/item.php
+++ b/models/item.php
@@ -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()
{
diff --git a/models/schema.php b/models/schema.php
index 7375c06..6acd42a 100644
--- a/models/schema.php
+++ b/models/schema.php
@@ -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)
{
diff --git a/templates/add.php b/templates/add.php
index 7e7b2fe..beb0c3c 100644
--- a/templates/add.php
+++ b/templates/add.php
@@ -22,6 +22,16 @@
= Helper\form_checkbox('cloak_referrer', t('Cloak the image referrer'), 1, $values['cloak_referrer']) ?>
= 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.') ?>
+ + = Helper\form_label(t('Groups'), 'groups'); ?> + += t('Nothing to read') ?>
- += t('Nothing to read') ?>
+ + + = \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, + )) ?> + - + - = \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)) ?> +