diff --git a/Phraseanet-production-client/dist/production.js b/Phraseanet-production-client/dist/production.js index 476027a690..a2904c2940 100644 --- a/Phraseanet-production-client/dist/production.js +++ b/Phraseanet-production-client/dist/production.js @@ -18905,8 +18905,8 @@ var notifyLayout = function notifyLayout(services) { var $notificationBoxContainer = (0, _jquery2.default)('#notification_box'); var $notificationTrigger = (0, _jquery2.default)('.notification_trigger'); var $notificationDialog = (0, _jquery2.default)('#notifications-dialog'); - var $notifications = null; - var $navigation = null; + var $notifications = (0, _jquery2.default)('.notifications', $notificationDialog); + var $navigation = (0, _jquery2.default)('.navigation', $notificationDialog); var initialize = function initialize() { /** @@ -19020,15 +19020,6 @@ var notifyLayout = function notifyLayout(services) { $notificationDialog.dialog('close'); }; - // create the dlg div if it does not exists - // - // if ($notificationDialog.length === 0) { - // $('body').append('
'); - // $notificationDialog = $('#notifications-dialog'); - $notifications = (0, _jquery2.default)('.notifications', $notificationDialog); - $navigation = (0, _jquery2.default)('.navigation', $notificationDialog); - // } - // open the dlg (even if it is already opened when "load more") // $notificationDialog.dialog({ @@ -19076,7 +19067,8 @@ var notifyLayout = function notifyLayout(services) { var notifications = data.notifications.notifications; var i = 0; - for (i in notifications) { + + var _loop = function _loop() { var notification = notifications[i]; // group notifs by day @@ -19093,6 +19085,13 @@ var notifyLayout = function notifyLayout(services) { // add pre-formatted notif date_cont.append(notification.html); + (0, _jquery2.default)('.notification_' + notification.id + '_unread', $notifications).tooltip().click(function () { + mark_read(notification.id); + }); + }; + + for (i in notifications) { + _loop(); } // handle "show more" button @@ -19109,52 +19108,36 @@ var notifyLayout = function notifyLayout(services) { // no more ? no button $navigation.hide(); } - /* - if (data.notifications.next_page_html) { - $navigation - .off('click', '.notification__print-action'); - $navigation.empty().show().append(data.notifications.next_page_html); - $navigation - .on('click', '.notification__print-action', function (event) { - event.preventDefault(); - let $el = $(event.currentTarget); - let offset = $el.data('offset'); - print_notifications(offset); - }); - } - else { - $navigation.empty().hide(); - } - */ } }); }; - /* remove in favor of existing /session/ route - const read_notifications = () => { - var notifications = []; - $('#notification_box .unread').each(function () { - notifications.push($(this).attr('id').split('_').pop()); - }); - $.ajax({ - type: 'POST', - url: '/user/notifications/read/', + + var mark_read = function mark_read(notification_id) { + _jquery2.default.ajax({ + type: 'PATCH', + url: '/user/notifications/' + notification_id + '/', data: { - notifications: notifications.join('_') + 'read': 1 }, - success: function (data) { - $('.notification_trigger .counter').css('visibility', 'hidden').empty(); + success: function success(data) { + (0, _jquery2.default)('.notification_' + notification_id + '_unread', $notifications).hide(); + (0, _jquery2.default)('.notification_' + notification_id + '_read', $notifications).show(); } }); }; - const clear_notifications = () => { - var unread = $('#notification_box .unread'); - if (unread.length === 0) { - return; - } - unread.removeClass('unread'); - $('.notification_trigger .counter').css('visibility', 'hidden').empty(); - }; - */ + /* + const clear_notifications = () => { + var unread = $('#notification_box .unread'); + + if (unread.length === 0) { + return; + } + + unread.removeClass('unread'); + $('.notification_trigger .counter').css('visibility', 'hidden').empty(); + }; + + */ return { initialize: initialize diff --git a/Phraseanet-production-client/dist/production.min.js b/Phraseanet-production-client/dist/production.min.js index 476027a690..a2904c2940 100644 --- a/Phraseanet-production-client/dist/production.min.js +++ b/Phraseanet-production-client/dist/production.min.js @@ -18905,8 +18905,8 @@ var notifyLayout = function notifyLayout(services) { var $notificationBoxContainer = (0, _jquery2.default)('#notification_box'); var $notificationTrigger = (0, _jquery2.default)('.notification_trigger'); var $notificationDialog = (0, _jquery2.default)('#notifications-dialog'); - var $notifications = null; - var $navigation = null; + var $notifications = (0, _jquery2.default)('.notifications', $notificationDialog); + var $navigation = (0, _jquery2.default)('.navigation', $notificationDialog); var initialize = function initialize() { /** @@ -19020,15 +19020,6 @@ var notifyLayout = function notifyLayout(services) { $notificationDialog.dialog('close'); }; - // create the dlg div if it does not exists - // - // if ($notificationDialog.length === 0) { - // $('body').append('
'); - // $notificationDialog = $('#notifications-dialog'); - $notifications = (0, _jquery2.default)('.notifications', $notificationDialog); - $navigation = (0, _jquery2.default)('.navigation', $notificationDialog); - // } - // open the dlg (even if it is already opened when "load more") // $notificationDialog.dialog({ @@ -19076,7 +19067,8 @@ var notifyLayout = function notifyLayout(services) { var notifications = data.notifications.notifications; var i = 0; - for (i in notifications) { + + var _loop = function _loop() { var notification = notifications[i]; // group notifs by day @@ -19093,6 +19085,13 @@ var notifyLayout = function notifyLayout(services) { // add pre-formatted notif date_cont.append(notification.html); + (0, _jquery2.default)('.notification_' + notification.id + '_unread', $notifications).tooltip().click(function () { + mark_read(notification.id); + }); + }; + + for (i in notifications) { + _loop(); } // handle "show more" button @@ -19109,52 +19108,36 @@ var notifyLayout = function notifyLayout(services) { // no more ? no button $navigation.hide(); } - /* - if (data.notifications.next_page_html) { - $navigation - .off('click', '.notification__print-action'); - $navigation.empty().show().append(data.notifications.next_page_html); - $navigation - .on('click', '.notification__print-action', function (event) { - event.preventDefault(); - let $el = $(event.currentTarget); - let offset = $el.data('offset'); - print_notifications(offset); - }); - } - else { - $navigation.empty().hide(); - } - */ } }); }; - /* remove in favor of existing /session/ route - const read_notifications = () => { - var notifications = []; - $('#notification_box .unread').each(function () { - notifications.push($(this).attr('id').split('_').pop()); - }); - $.ajax({ - type: 'POST', - url: '/user/notifications/read/', + + var mark_read = function mark_read(notification_id) { + _jquery2.default.ajax({ + type: 'PATCH', + url: '/user/notifications/' + notification_id + '/', data: { - notifications: notifications.join('_') + 'read': 1 }, - success: function (data) { - $('.notification_trigger .counter').css('visibility', 'hidden').empty(); + success: function success(data) { + (0, _jquery2.default)('.notification_' + notification_id + '_unread', $notifications).hide(); + (0, _jquery2.default)('.notification_' + notification_id + '_read', $notifications).show(); } }); }; - const clear_notifications = () => { - var unread = $('#notification_box .unread'); - if (unread.length === 0) { - return; - } - unread.removeClass('unread'); - $('.notification_trigger .counter').css('visibility', 'hidden').empty(); - }; - */ + /* + const clear_notifications = () => { + var unread = $('#notification_box .unread'); + + if (unread.length === 0) { + return; + } + + unread.removeClass('unread'); + $('.notification_trigger .counter').css('visibility', 'hidden').empty(); + }; + + */ return { initialize: initialize diff --git a/Phraseanet-production-client/src/components/notify/notifyLayout.js b/Phraseanet-production-client/src/components/notify/notifyLayout.js index b85802760d..09681e2b0d 100644 --- a/Phraseanet-production-client/src/components/notify/notifyLayout.js +++ b/Phraseanet-production-client/src/components/notify/notifyLayout.js @@ -194,6 +194,10 @@ const notifyLayout = (services) => { // add pre-formatted notif date_cont.append(notification.html); + $('.notification_' + notification.id + '_unread', $notifications).tooltip().click( + function () { + mark_read(notification.id); + }); } // handle "show more" button @@ -216,26 +220,21 @@ const notifyLayout = (services) => { } }); }; - /* remove in favor of existing /session/ route - const read_notifications = () => { - var notifications = []; - - $('#notification_box .unread').each(function () { - notifications.push($(this).attr('id').split('_').pop()); - }); + const mark_read = (notification_id) => { $.ajax({ - type: 'POST', - url: '/user/notifications/read/', + type: 'PATCH', + url: '/user/notifications/' + notification_id + '/', data: { - notifications: notifications.join('_') + 'read': 1 }, success: function (data) { - $('.notification_trigger .counter').css('visibility', 'hidden').empty(); + $('.notification_' + notification_id + '_unread', $notifications).hide(); + $('.notification_' + notification_id + '_read', $notifications).show(); } }); }; - +/* const clear_notifications = () => { var unread = $('#notification_box .unread'); diff --git a/lib/Alchemy/Phrasea/Controller/User/UserNotificationController.php b/lib/Alchemy/Phrasea/Controller/User/UserNotificationController.php index 3892f4ffe9..e8de06f7bc 100644 --- a/lib/Alchemy/Phrasea/Controller/User/UserNotificationController.php +++ b/lib/Alchemy/Phrasea/Controller/User/UserNotificationController.php @@ -130,37 +130,35 @@ class UserNotificationController extends Controller } - - - - - - /** - * Set notifications as read + * patch a notification + * for now the only usefull thing is to mark it as "read" * * @param Request $request * @return JsonResponse */ - /* remove in favor of existing /session/ route - public function readNotifications(Request $request) + public function patchNotification(Request $request, $notification_id) { if (!$request->isXmlHttpRequest()) { $this->app->abort(400); } - try { - $this->getEventsManager()->read( - explode('_', (string) $request->request->get('notifications')), - $this->getAuthenticatedUser()->getId() - ); + if($request->get('read', '0') === '1') { + // mark as read + try { + $this->getEventsManager()->read( + [$notification_id], + $this->getAuthenticatedUser()->getId() + ); - return $this->app->json(['success' => true, 'message' => '']); - } catch (\Exception $e) { - return $this->app->json(['success' => false, 'message' => $e->getMessage()]); + return $this->app->json(['success' => true, 'message' => '']); + } + catch (\Exception $e) { + return $this->app->json(['success' => false, 'message' => $e->getMessage()]); + } } } - */ + /** * Get all notifications diff --git a/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php b/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php index e94b29a3d5..483f5f63cc 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php @@ -54,8 +54,11 @@ class Notifications implements ControllerProviderInterface, ServiceProviderInter // ->bind('get_notifications') ; - /* todo : re-implement "read" route - * + $controllers->patch('/{notification_id}/', 'controller.user.notifications:patchNotification') + ->assert('notification_id', '\d+') + ->bind('set_notifications_readed'); + + /* /** @uses UserNotificationController::listNotifications * / $controllers->get('/', 'controller.user.notifications:getNotifications') ->bind('get_notifications'); diff --git a/lib/classes/eventsmanager/broker.php b/lib/classes/eventsmanager/broker.php index 0b3daef552..611dac34ad 100644 --- a/lib/classes/eventsmanager/broker.php +++ b/lib/classes/eventsmanager/broker.php @@ -233,8 +233,16 @@ class eventsmanager_broker // delete old already read notifs (nb: we do this for everybody - not only the current user -) // todo: for now we use "created_on" since there is no timestamp set when reading. // + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // do restore : for testing we do not yet delete + $sql = "DELETE FROM `notifications` WHERE `unread`=0 AND TIMESTAMPDIFF(HOUR, `created_on`, NOW()) > 10"; - $this->app->getApplicationBox()->get_connection()->exec($sql); + // $this->app->getApplicationBox()->get_connection()->exec($sql); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // get count of unread notifications (to be displayed on navbar) // diff --git a/resources/www/common/js/components/common.js b/resources/www/common/js/components/common.js index 523cdac566..568d42bcaa 100644 --- a/resources/www/common/js/components/common.js +++ b/resources/www/common/js/components/common.js @@ -135,8 +135,16 @@ var commonModule = (function ($, p4) { } else { $('.no_notifications', $box).hide(); - for (n in data.notifications.notifications) { - $box_notifications.append(data.notifications.notifications[n].html); + for (var n in data.notifications.notifications) { + var notification = data.notifications.notifications[n]; + $box_notifications.append(notification.html); + + $('.notification_' + notification.id + '_read', $box_notifications).click( + function (event) { + console.log("++++++++++ clicked("+notification.id+")") + }); + + } $('.show_all', $box).show(); } diff --git a/templates/web/admin/index.html.twig b/templates/web/admin/index.html.twig index 9a53cf14ac..eb79f8f99a 100644 --- a/templates/web/admin/index.html.twig +++ b/templates/web/admin/index.html.twig @@ -64,7 +64,7 @@ {##} {% endblock %} {% block content %} -
+
diff --git a/templates/web/prod/notification.html.twig b/templates/web/prod/notification.html.twig index 978abc6013..6bf5778179 100644 --- a/templates/web/prod/notification.html.twig +++ b/templates/web/prod/notification.html.twig @@ -1,4 +1,4 @@ -
+
+
@@ -10,6 +10,10 @@ {{notification['created_on']}}

+ + 👁 +
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/SessionManagerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/SessionManagerSubscriberTest.php index 538c780028..01c28d040e 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/SessionManagerSubscriberTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/SessionManagerSubscriberTest.php @@ -2,8 +2,8 @@ namespace Alchemy\Tests\Phrasea\Core\Event\Subscriber; -use Alchemy\Phrasea\Core\Event\Subscriber\SessionManagerSubscriber; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Core\Event\Subscriber\SessionManagerSubscriber; use Alchemy\Phrasea\Model\Entities\Session; use Symfony\Component\HttpKernel\Client; @@ -235,10 +235,6 @@ class SessionManagerSubscriberTest extends \PhraseanetAuthenticatedWebTestCase $app['orm.em'] = $this->getMockBuilder('Doctrine\ORM\EntityManager')->disableOriginalConstructor()->getMock(); $app['orm.em']->expects($this->never())->method('flush'); - $app->get('/login', function () { - return ''; - })->bind("homepage"); - $app->get($route, function () { return ''; }); @@ -254,8 +250,43 @@ class SessionManagerSubscriberTest extends \PhraseanetAuthenticatedWebTestCase public function forbiddenRouteProvider() { return [ - ['/admin/databox/17/informations/documents/'], + ['/'], + ['/login/'], + ]; + } + + /** + * @dataProvider notUserActivityRouteProvider + */ + public function testNotUserActivityRoutes($route) + { + $app = new Application(Application::ENV_TEST); + $app['dispatcher']->addSubscriber(new SessionManagerSubscriber($app)); + $app['authentication'] = $this->getMockBuilder('Alchemy\Phrasea\Authentication\Authenticator')->disableOriginalConstructor()->getMock(); + $app['authentication']->expects($this->once())->method('isAuthenticated'); + + $app['orm.em'] = $this->getMockBuilder('Doctrine\ORM\EntityManager')->disableOriginalConstructor()->getMock(); + $app['orm.em']->expects($this->never())->method('flush'); + + $app->get($route, function () { + return ''; + }); + + $client = new Client($app); + $client->request('GET', $route, [], [], [ + 'HTTP_CONTENT-TYPE' => 'application/json', + 'HTTP_ACCEPT' => 'application/json', + 'HTTP_X-Requested-With' => 'XMLHttpRequest', + ]); + } + + public function notUserActivityRouteProvider() + { + return [ + ['/session/'], + ['/user/'], ['/admin/task-manager/tasks/'], + ['/admin/databox/17/informations/documents/'] ]; } }