Offer the possibility to edit/delete groups

This commit is contained in:
Frederic Guillot 2017-02-01 17:25:32 -05:00
parent 19a0f41a9e
commit 3dfc748155
28 changed files with 363 additions and 6 deletions

View File

@ -0,0 +1,87 @@
<?php
namespace Miniflux\Controller;
use Miniflux\Session\SessionStorage;
use Miniflux\Validator;
use Miniflux\Router;
use Miniflux\Response;
use Miniflux\Request;
use Miniflux\Template;
use Miniflux\Handler;
use Miniflux\Model;
// Display all groups
Router\get_action('groups', function () {
$user_id = SessionStorage::getInstance()->getUserId();
Response\html(Template\layout('groups/list', array(
'groups' => Model\Group\get_all($user_id),
'menu' => 'feeds',
'title' => t('Groups'),
)));
});
// Confirmation dialog to remove a group
Router\get_action('confirm-remove-group', function () {
$user_id = SessionStorage::getInstance()->getUserId();
$group_id = Request\int_param('group_id');
Response\html(Template\layout('groups/remove', array(
'group' => Model\Group\get_group($user_id, $group_id),
'menu' => 'feeds',
'title' => t('Confirmation')
)));
});
// Remove a group
Router\get_action('remove-group', function () {
$user_id = SessionStorage::getInstance()->getUserId();
$group_id = Request\int_param('group_id');
if (Model\Group\remove_group($user_id, $group_id)) {
SessionStorage::getInstance()->setFlashMessage(t('This group has been removed successfully.'));
} else {
SessionStorage::getInstance()->setFlashErrorMessage(t('Unable to remove this group.'));
}
Response\redirect('?action=groups');
});
// Edit group form
Router\get_action('edit-group', function () {
$user_id = SessionStorage::getInstance()->getUserId();
$group_id = Request\int_param('group_id');
$values = Model\Group\get_group($user_id, $group_id);
Response\html(Template\layout('groups/edit', array(
'values' => $values,
'errors' => array(),
'menu' => 'feeds',
'title' => t('Edit group')
)));
});
// Submit edit group form
Router\post_action('edit-group', function () {
$user_id = SessionStorage::getInstance()->getUserId();
$values = Request\values();
list($valid, $errors) = Validator\Group\validate_modification($values);
if ($valid) {
if (Model\Group\update_group($user_id, $values['id'], $values['title'])) {
SessionStorage::getInstance()->setFlashMessage(t('Group updated successfully.'));
Response\redirect('?action=groups');
} else {
SessionStorage::getInstance()->setFlashErrorMessage(t('Unable to edit this group.'));
}
}
Response\html(Template\layout('groups/edit', array(
'values' => $values,
'errors' => $errors,
'menu' => 'feeds',
'title' => t('Edit group')
)));
});

View File

@ -126,3 +126,9 @@ function link($label, $action, array $params = array())
$params['action'] = $action; $params['action'] = $action;
return sprintf('<a href="?%s">%s</a>', http_build_query($params, '', '&amp;'), escape($label)); return sprintf('<a href="?%s">%s</a>', http_build_query($params, '', '&amp;'), escape($label));
} }
function button($type, $label, $action, array $params = array())
{
$params['action'] = $action;
return sprintf('<a href="?%s" class="btn btn-%s">%s</a>', http_build_query($params, '', '&amp;'), $type, escape($label));
}

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
'New Password' => 'Nové heslo', 'New Password' => 'Nové heslo',
'Wrong password' => 'Špatné heslo', 'Wrong password' => 'Špatné heslo',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
'New Password' => 'Nouveau mot de passe', 'New Password' => 'Nouveau mot de passe',
'Wrong password' => 'Mauvais mot de passe', 'Wrong password' => 'Mauvais mot de passe',
'Duplicated feed' => 'Abonnement dupliqué', 'Duplicated feed' => 'Abonnement dupliqué',
'This group has been removed successfully.' => 'Ce libellé a été supprimé avec succès.',
'Unable to remove this group.' => 'Impossible de supprimer ce libellé.',
'Edit group' => 'Modifier un libellé',
'Group updated successfully.' => 'Libellé modifié avec succès.',
'Unable to edit this group.' => 'Impossible de modifier ce libellé.',
'groups' => 'libellés',
'There is no group.' => 'Il n\'y a aucun libellé.',
'Do you really want to remove this group: "%s"?' => 'Voulez-vous vraiment supprimer ce libellé : « %s » ?',
'This field is required' => 'Ce champ est requis',
'This value must be an integer' => 'Cette valeur doit être un entier',
'This text is too long (max. %d)' => 'Ce texte est trop long (max. %d)',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -257,4 +257,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
'New Password' => 'Новый пароль', 'New Password' => 'Новый пароль',
'Wrong password' => 'Неверный пароль', 'Wrong password' => 'Неверный пароль',
'Duplicated feed' => 'Дублирующийся канал', 'Duplicated feed' => 'Дублирующийся канал',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
// 'New Password' => '', // 'New Password' => '',
// 'Wrong password' => '', // 'Wrong password' => '',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -255,4 +255,15 @@ return array(
'New Password' => '新密码', 'New Password' => '新密码',
'Wrong password' => '密码错误', 'Wrong password' => '密码错误',
// 'Duplicated feed' => '', // 'Duplicated feed' => '',
// 'This group has been removed successfully.' => '',
// 'Unable to remove this group.' => '',
// 'Edit group' => '',
// 'Group updated successfully.' => '',
// 'Unable to edit this group.' => '',
// 'groups' => '',
// 'There is no group.' => '',
// 'Do you really want to remove this group: "%s"?' => '',
// 'This field is required' => '',
// 'This value must be an integer' => '',
// 'This text is too long (max. %d)' => '',
); );

View File

@ -16,6 +16,33 @@ function get_all($user_id)
->findAll(); ->findAll();
} }
function get_group($user_id, $group_id)
{
return Database::getInstance('db')
->table(TABLE)
->eq('user_id', $user_id)
->eq('id', $group_id)
->findOne();
}
function remove_group($user_id, $group_id)
{
return Database::getInstance('db')
->table(TABLE)
->eq('user_id', $user_id)
->eq('id', $group_id)
->remove();
}
function update_group($user_id, $group_id, $title)
{
return Database::getInstance('db')
->table(TABLE)
->eq('user_id', $user_id)
->eq('id', $group_id)
->update(array('title' => $title));
}
function get_groups_feed_ids($user_id) function get_groups_feed_ids($user_id)
{ {
$result = array(); $result = array();

View File

@ -4,6 +4,7 @@
<ul> <ul>
<li class="active"><a href="?action=add"><?php echo t('add') ?></a></li> <li class="active"><a href="?action=add"><?php echo t('add') ?></a></li>
<li><a href="?action=feeds"><?php echo t('feeds') ?></a></li> <li><a href="?action=feeds"><?php echo t('feeds') ?></a></li>
<li><a href="?action=groups"><?php echo t('groups') ?></a></li>
<li><a href="?action=import"><?php echo t('import') ?></a></li> <li><a href="?action=import"><?php echo t('import') ?></a></li>
<li><a href="?action=export"><?php echo t('export') ?></a></li> <li><a href="?action=export"><?php echo t('export') ?></a></li>
</ul> </ul>

View File

@ -3,6 +3,7 @@
<ul> <ul>
<li><a href="?action=add"><?php echo t('add') ?></a></li> <li><a href="?action=add"><?php echo t('add') ?></a></li>
<li><a href="?action=feeds"><?php echo t('feeds') ?></a></li> <li><a href="?action=feeds"><?php echo t('feeds') ?></a></li>
<li><a href="?action=groups"><?php echo t('groups') ?></a></li>
<li><a href="?action=import"><?php echo t('import') ?></a></li> <li><a href="?action=import"><?php echo t('import') ?></a></li>
<li><a href="?action=export"><?php echo t('export') ?></a></li> <li><a href="?action=export"><?php echo t('export') ?></a></li>
</ul> </ul>

View File

@ -4,6 +4,7 @@
<ul> <ul>
<li><a href="?action=add"><?php echo t('add') ?></a></li> <li><a href="?action=add"><?php echo t('add') ?></a></li>
<li class="active"><a href="?action=feeds"><?php echo t('feeds') ?></a></li> <li class="active"><a href="?action=feeds"><?php echo t('feeds') ?></a></li>
<li><a href="?action=groups"><?php echo t('groups') ?></a></li>
<li><a href="?action=import"><?php echo t('import') ?></a></li> <li><a href="?action=import"><?php echo t('import') ?></a></li>
<li><a href="?action=export"><?php echo t('export') ?></a></li> <li><a href="?action=export"><?php echo t('export') ?></a></li>
<li><a href="?action=refresh-all" data-action="refresh-all" data-concurrent-requests="<?php echo SUBSCRIPTION_CONCURRENT_REQUESTS ?>"><?php echo t('refresh all') ?></a></li> <li><a href="?action=refresh-all" data-action="refresh-all" data-concurrent-requests="<?php echo SUBSCRIPTION_CONCURRENT_REQUESTS ?>"><?php echo t('refresh all') ?></a></li>

View File

@ -0,0 +1,24 @@
<div class="page-header">
<h2><?php echo t('Edt group') ?></h2>
<nav>
<ul>
<li><a href="?action=add"><?php echo t('add') ?></a></li>
<li><a href="?action=feeds"><?php echo t('feeds') ?></a></li>
<li class="active"><a href="?action=groups"><?php echo t('groups') ?></a></li>
<li><a href="?action=import"><?php echo t('import') ?></a></li>
<li><a href="?action=export"><?php echo t('export') ?></a></li>
</ul>
</nav>
</div>
<form method="post" action="?action=edit-group" autocomplete="off">
<?php echo Miniflux\Helper\form_hidden('id', $values) ?>
<?php echo Miniflux\Helper\form_label(t('Title'), 'title') ?>
<?php echo Miniflux\Helper\form_text('title', $values, $errors, array('required', 'autofocus')) ?>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?php echo t('Save') ?></button>
<?php echo t('or') ?> <?php echo Miniflux\Helper\link(t('cancel'), 'groups') ?>
</div>
</form>

View File

@ -0,0 +1,32 @@
<div class="page-header">
<h2><?php echo t('Groups') ?></h2>
<nav>
<ul>
<li><a href="?action=add"><?php echo t('add') ?></a></li>
<li><a href="?action=feeds"><?php echo t('feeds') ?></a></li>
<li class="active"><a href="?action=groups"><?php echo t('groups') ?></a></li>
<li><a href="?action=import"><?php echo t('import') ?></a></li>
<li><a href="?action=export"><?php echo t('export') ?></a></li>
</ul>
</nav>
</div>
<?php if (empty($groups)): ?>
<p class="alert alert-info"><?php echo t('There is no group.') ?></p>
<?php else: ?>
<section class="items">
<?php foreach ($groups as $group): ?>
<article>
<h2><?php echo Miniflux\Helper\escape($group['title']) ?></h2>
<ul class="item-menu">
<li>
<?php echo Miniflux\Helper\link(t('edit'), 'edit-group', array('group_id' => $group['id'])) ?>
</li>
<li>
<?php echo Miniflux\Helper\link(t('remove'), 'confirm-remove-group', array('group_id' => $group['id'])) ?>
</li>
</ul>
</article>
<?php endforeach ?>
</section>
<?php endif ?>

View File

@ -0,0 +1,10 @@
<div class="page-header">
<h2><?php echo t('Confirmation') ?></h2>
</div>
<p class="alert alert-info"><?php echo t('Do you really want to remove this group: "%s"?', Miniflux\Helper\escape($group['title'])) ?></p>
<div class="form-actions">
<?php echo Miniflux\Helper\button('red', t('Remove'), 'remove-group', array('group_id' => $group['id'])) ?>
<?php echo t('or') ?> <?php echo Miniflux\Helper\link(t('cancel'), 'groups') ?>
</div>

21
app/validators/group.php Normal file
View File

@ -0,0 +1,21 @@
<?php
namespace Miniflux\Validator\Group;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
function validate_modification(array $values)
{
$v = new Validator($values, array(
new Validators\Required('id', t('This field is required')),
new Validators\Integer('id', t('This value must be an integer')),
new Validators\Required('title', t('The title is required')),
new Validators\MaxLength('title', t('This text is too long (max. %d)', 255), 255),
));
return array(
$v->execute(),
$v->getErrors(),
);
}

View File

@ -63,6 +63,7 @@
"app/models/favicon.php", "app/models/favicon.php",
"app/validators/config.php", "app/validators/config.php",
"app/validators/feed.php", "app/validators/feed.php",
"app/validators/group.php",
"app/validators/user.php" "app/validators/user.php"
], ],
"classmap": [ "classmap": [

12
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "84a5e3b6cc5bebc61559f062e3d3cb6f", "hash": "287ac8083a99b8a4abb829567a4a7627",
"content-hash": "7964640dd4d057358aeb236996973c90", "content-hash": "7964640dd4d057358aeb236996973c90",
"packages": [ "packages": [
{ {
@ -967,16 +967,16 @@
}, },
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
"version": "1.2.2", "version": "1.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git", "url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f" "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f", "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1027,7 +1027,7 @@
"compare", "compare",
"equality" "equality"
], ],
"time": "2016-11-19 09:18:40" "time": "2017-01-29 09:50:25"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",

View File

@ -18,6 +18,7 @@ Router\bootstrap(
'bookmark', 'bookmark',
'config', 'config',
'feed', 'feed',
'groups',
'help', 'help',
'history', 'history',
'item', 'item',

View File

@ -39,5 +39,6 @@ return array(
'785cebb801997d40232b8337459f1606' => $baseDir . '/app/models/favicon.php', '785cebb801997d40232b8337459f1606' => $baseDir . '/app/models/favicon.php',
'e348a7661429e81fa0e42efff1ebfe6e' => $baseDir . '/app/validators/config.php', 'e348a7661429e81fa0e42efff1ebfe6e' => $baseDir . '/app/validators/config.php',
'679a0a7c75414c39298328823e0be180' => $baseDir . '/app/validators/feed.php', '679a0a7c75414c39298328823e0be180' => $baseDir . '/app/validators/feed.php',
'c9b6df0c6d89508a97bc5c3af8a92707' => $baseDir . '/app/validators/group.php',
'eea04c7f459daa801618b71f49a8c470' => $baseDir . '/app/validators/user.php', 'eea04c7f459daa801618b71f49a8c470' => $baseDir . '/app/validators/user.php',
); );

View File

@ -40,6 +40,7 @@ class ComposerStaticInitfc88bf644a3dc0d30b5792ad2fec7895
'785cebb801997d40232b8337459f1606' => __DIR__ . '/../..' . '/app/models/favicon.php', '785cebb801997d40232b8337459f1606' => __DIR__ . '/../..' . '/app/models/favicon.php',
'e348a7661429e81fa0e42efff1ebfe6e' => __DIR__ . '/../..' . '/app/validators/config.php', 'e348a7661429e81fa0e42efff1ebfe6e' => __DIR__ . '/../..' . '/app/validators/config.php',
'679a0a7c75414c39298328823e0be180' => __DIR__ . '/../..' . '/app/validators/feed.php', '679a0a7c75414c39298328823e0be180' => __DIR__ . '/../..' . '/app/validators/feed.php',
'c9b6df0c6d89508a97bc5c3af8a92707' => __DIR__ . '/../..' . '/app/validators/group.php',
'eea04c7f459daa801618b71f49a8c470' => __DIR__ . '/../..' . '/app/validators/user.php', 'eea04c7f459daa801618b71f49a8c470' => __DIR__ . '/../..' . '/app/validators/user.php',
); );