aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag
diff options
context:
space:
mode:
authorThomas Citharel <tcit@tcit.fr>2017-06-15 09:43:48 +0200
committerThomas Citharel <tcit@tcit.fr>2017-06-23 09:42:20 +0200
commite0f9010ec2a558f6cf7d16fb96a2c4cdb34e3f37 (patch)
tree904f42fa442188bf456b9773295fb9582634ba6c /src/Wallabag
parent29714661b1df78871ceaf0e079f11041a8641d4b (diff)
downloadwallabag-e0f9010ec2a558f6cf7d16fb96a2c4cdb34e3f37.tar.gz
wallabag-e0f9010ec2a558f6cf7d16fb96a2c4cdb34e3f37.tar.zst
wallabag-e0f9010ec2a558f6cf7d16fb96a2c4cdb34e3f37.zip
Notifications
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
Diffstat (limited to 'src/Wallabag')
-rw-r--r--src/Wallabag/CoreBundle/Command/AbstractNotificationCommand.php41
-rw-r--r--src/Wallabag/CoreBundle/Command/AdminNotificationCommand.php103
-rw-r--r--src/Wallabag/CoreBundle/Command/ReleaseNotificationCommand.php88
-rw-r--r--src/Wallabag/CoreBundle/Controller/NotificationsController.php96
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/Configuration.php3
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php1
-rw-r--r--src/Wallabag/CoreBundle/Entity/Notification.php308
-rw-r--r--src/Wallabag/CoreBundle/Notifications/Action.php91
-rw-r--r--src/Wallabag/CoreBundle/Notifications/ActionInterface.php42
-rw-r--r--src/Wallabag/CoreBundle/Notifications/InfoAction.php13
-rw-r--r--src/Wallabag/CoreBundle/Notifications/NoAction.php13
-rw-r--r--src/Wallabag/CoreBundle/Notifications/NotificationInterface.php103
-rw-r--r--src/Wallabag/CoreBundle/Notifications/OkAction.php13
-rw-r--r--src/Wallabag/CoreBundle/Notifications/YesAction.php13
-rw-r--r--src/Wallabag/CoreBundle/Repository/NotificationRepository.php26
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml6
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.da.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.de.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.en.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.es.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.fa.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.fr.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.it.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.oc.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.pl.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.pt.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.ro.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/date.tr.yml9
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.da.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.de.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml11
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.es.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.it.yml11
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml12
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Static/about.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Notification/notifications.html.twig56
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig1
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig54
-rw-r--r--src/Wallabag/CoreBundle/Twig/WallabagExtension.php41
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php21
-rw-r--r--src/Wallabag/UserBundle/Resources/views/manage.html.twig2
53 files changed, 1385 insertions, 11 deletions
diff --git a/src/Wallabag/CoreBundle/Command/AbstractNotificationCommand.php b/src/Wallabag/CoreBundle/Command/AbstractNotificationCommand.php
new file mode 100644
index 00000000..b40b589a
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Command/AbstractNotificationCommand.php
@@ -0,0 +1,41 @@
1<?php
2
3namespace Wallabag\CoreBundle\Command;
4
5use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
6use Symfony\Component\Console\Input\InputArgument;
7use Symfony\Component\Console\Output\OutputInterface;
8
9abstract class AbstractNotificationCommand extends ContainerAwareCommand
10{
11 /** @var OutputInterface */
12 protected $output;
13
14 protected function configure()
15 {
16 $this
17 ->addArgument(
18 'username',
19 InputArgument::OPTIONAL,
20 'User to send the notification to'
21 )
22 ;
23 }
24
25 /**
26 * Fetches a user from its username.
27 *
28 * @param string $username
29 *
30 * @return \Wallabag\UserBundle\Entity\User
31 */
32 protected function getUser($username)
33 {
34 return $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findOneByUserName($username);
35 }
36
37 protected function getDoctrine()
38 {
39 return $this->getContainer()->get('doctrine');
40 }
41}
diff --git a/src/Wallabag/CoreBundle/Command/AdminNotificationCommand.php b/src/Wallabag/CoreBundle/Command/AdminNotificationCommand.php
new file mode 100644
index 00000000..cfde714b
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Command/AdminNotificationCommand.php
@@ -0,0 +1,103 @@
1<?php
2
3namespace Wallabag\CoreBundle\Command;
4
5use Doctrine\ORM\NoResultException;
6use Symfony\Component\Console\Input\InputArgument;
7use Symfony\Component\Console\Input\InputInterface;
8use Symfony\Component\Console\Input\InputOption;
9use Symfony\Component\Console\Output\OutputInterface;
10use Wallabag\CoreBundle\Entity\Notification;
11use Wallabag\CoreBundle\Notifications\InfoAction;
12use Wallabag\UserBundle\Entity\User;
13
14class AdminNotificationCommand extends AbstractNotificationCommand
15{
16 protected function configure()
17 {
18 $this
19 ->setName('wallabag:notification:send')
20 ->setDescription('Emits a notification to all users')
21 ->setHelp('This command helps you send notifications to all of the users instance, or just for one user.')
22 ->addArgument(
23 'title',
24 InputArgument::REQUIRED,
25 'Title of your notification. This is required if if the type of notification is an admin one.'
26 )
27 ->addArgument(
28 'message',
29 InputArgument::REQUIRED,
30 'Message of your notification. This is required if the type of notification is an admin one.'
31 )
32 ->addOption(
33 'link',
34 'l',
35 InputOption::VALUE_REQUIRED,
36 'A link to display with the notification'
37 )
38 ;
39 parent::configure();
40 }
41
42 protected function execute(InputInterface $input, OutputInterface $output)
43 {
44 $this->output = $output;
45
46 $username = $input->getArgument('username');
47
48 $message = $input->getArgument('message');
49 $title = $input->getArgument('title');
50
51 $link = $input->getOption('link');
52
53 if ($username) {
54 try {
55 $user = $this->getUser($username);
56 $this->sendNotification($user, $title, $message, $link);
57 } catch (NoResultException $e) {
58 $output->writeln(sprintf('<error>User "%s" not found.</error>', $username));
59
60 return 1;
61 }
62 } else {
63 $users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll();
64
65 $output->writeln(sprintf('Sending notifications to %d user accounts. This can take some time.', count($users)));
66
67 foreach ($users as $user) {
68 $output->writeln(sprintf('Processing user %s', $user->getUsername()));
69 $this->sendNotification($user, $title, $message, $link);
70 }
71 $output->writeln('Finished sending notifications.');
72 }
73
74 return 0;
75 }
76
77 /**
78 * @param User $user
79 * @param $title
80 * @param $message
81 * @param null $link
82 */
83 private function sendNotification(User $user, $title, $message, $link = null)
84 {
85 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
86
87 $notification = new Notification($user);
88 $notification->setTitle($title)
89 ->setDescription($message)
90 ->setType(Notification::TYPE_ADMIN);
91
92 if ($link) {
93 $action = new InfoAction($link);
94
95 $notification->addAction($action);
96 }
97
98 $em->persist($notification);
99 $em->flush();
100
101 $this->output->writeln(sprintf('Sent notification for user %s', $user->getUserName()));
102 }
103}
diff --git a/src/Wallabag/CoreBundle/Command/ReleaseNotificationCommand.php b/src/Wallabag/CoreBundle/Command/ReleaseNotificationCommand.php
new file mode 100644
index 00000000..cd9c61a3
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Command/ReleaseNotificationCommand.php
@@ -0,0 +1,88 @@
1<?php
2
3namespace Wallabag\CoreBundle\Command;
4
5use Doctrine\ORM\NoResultException;
6use Symfony\Component\Console\Input\InputArgument;
7use Symfony\Component\Console\Input\InputInterface;
8use Symfony\Component\Console\Output\OutputInterface;
9use Wallabag\CoreBundle\Entity\Notification;
10use Wallabag\CoreBundle\Notifications\Action;
11use Wallabag\UserBundle\Entity\User;
12
13class ReleaseNotificationCommand extends AbstractNotificationCommand
14{
15 /** @var OutputInterface */
16 protected $output;
17
18 protected function configure()
19 {
20 $this
21 ->setName('wallabag:notification:release')
22 ->setDescription('Emits a notification to all users to let them know of a new release')
23 ->setHelp('This command helps you send a release notification to all of the users instance, or just for one user.')
24 ->addArgument(
25 'link',
26 InputArgument::OPTIONAL,
27 'A link to display with the notification'
28 )
29 ;
30 parent::configure();
31 }
32
33 protected function execute(InputInterface $input, OutputInterface $output)
34 {
35 $this->output = $output;
36
37 $username = $input->getArgument('username');
38
39 $link = $input->getArgument('link');
40
41 if ($username) {
42 try {
43 $user = $this->getUser($username);
44 $this->sendNotification($user, $link);
45 } catch (NoResultException $e) {
46 $output->writeln(sprintf('<error>User "%s" not found.</error>', $username));
47
48 return 1;
49 }
50 } else {
51 $users = $this->getDoctrine()->getRepository('WallabagUserBundle:User')->findAll();
52
53 $output->writeln(sprintf('Sending notifications to %d user accounts. This can take some time.', count($users)));
54
55 foreach ($users as $user) {
56 $output->writeln(sprintf('Processing user %s', $user->getUsername()));
57 $this->sendNotification($user, $link);
58 }
59 $output->writeln('Finished sending notifications.');
60 }
61
62 return 0;
63 }
64
65 /**
66 * @param User $user
67 */
68 private function sendNotification(User $user, $link)
69 {
70 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
71
72 $notification = new Notification($user);
73 $notification->setTitle('notifications.release.title')
74 ->addParameter('%version%', $this->getContainer()->getParameter('wallabag_core.version'))
75 ->setType(Notification::TYPE_RELEASE);
76 if ($link) {
77 $details = new Action();
78 $details->setType(Action::TYPE_INFO)
79 ->setLabel('notifications.release.details')
80 ->setLink($link);
81 $notification->addAction($details);
82 }
83 $em->persist($notification);
84 $em->flush();
85
86 $this->output->writeln(sprintf('Sent notification for user %s', $user->getUserName()));
87 }
88}
diff --git a/src/Wallabag/CoreBundle/Controller/NotificationsController.php b/src/Wallabag/CoreBundle/Controller/NotificationsController.php
new file mode 100644
index 00000000..17e576cd
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Controller/NotificationsController.php
@@ -0,0 +1,96 @@
1<?php
2
3namespace Wallabag\CoreBundle\Controller;
4
5use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Pagerfanta\Pagerfanta;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request;
11use Symfony\Component\HttpFoundation\Response;
12use Wallabag\CoreBundle\Entity\Notification;
13
14class NotificationsController extends Controller
15{
16 /**
17 * @Route("/notifications/{page}", name="notifications-all", defaults={"page" = "1"})
18 *
19 * @param int $page
20 *
21 * @return Response
22 */
23 public function getAllNotificationsAction($page = 1)
24 {
25 $qb = $this->getDoctrine()->getRepository('WallabagCoreBundle:Notification')->getBuilderForNotificationsByUser($this->getUser()->getId());
26 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
27
28 $notifications = new Pagerfanta($pagerAdapter);
29 $notifications->setMaxPerPage($this->getParameter('wallabag_core.notifications_nb'));
30
31 try {
32 $notifications->setCurrentPage($page);
33 } catch (OutOfRangeCurrentPageException $e) {
34 if ($page > 1) {
35 return $this->redirect($this->generateUrl('notifications-all', ['page' => $notifications->getNbPages()]), 302);
36 }
37 }
38
39 return $this->render('WallabagCoreBundle:Notification:notifications.html.twig', [
40 'notifications' => $notifications,
41 'currentPage' => $page,
42 ]);
43 }
44
45 /**
46 * @Route("/notifications/readall", name="notification-archive-all")
47 *
48 * @param Request $request
49 *
50 * @return Response
51 */
52 public function markAllNotificationsAsReadAction(Request $request)
53 {
54 $this->getDoctrine()->getRepository('WallabagCoreBundle:Notification')->markAllAsReadForUser($this->getUser()->getId());
55
56 return $this->redirectToRoute('notifications-all');
57 }
58
59 /**
60 * @Route("/notifications/read/{notification}", name="notification-archive")
61 *
62 * @param Notification $notification
63 *
64 * @return Response
65 */
66 public function markNotificationsAsReadAction(Notification $notification)
67 {
68 $em = $this->getDoctrine()->getManager();
69
70 $notification->setRead(true);
71
72 $em->persist($notification);
73 $em->flush();
74
75 return $this->redirectToRoute('notifications-all');
76 }
77
78 /**
79 * @Route("/notifications/read/{notification}/redirect", name="notification-archive-redirect", requirements={"notification" = "\d+"})
80 *
81 * @param Request $request
82 * @param Notification $notification
83 */
84 public function markNotificationAsReadAndRedirectAction(Request $request, Notification $notification)
85 {
86 $em = $this->getDoctrine()->getManager();
87
88 $notification->setRead(true);
89
90 $em->persist($notification);
91 $em->flush();
92
93 $redirection = $request->get('redirection');
94 $this->redirect($redirection);
95 }
96}
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
index a9791f6b..478e4cba 100644
--- a/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
+++ b/src/Wallabag/CoreBundle/DependencyInjection/Configuration.php
@@ -49,6 +49,9 @@ class Configuration implements ConfigurationInterface
49 ->scalarNode('list_mode') 49 ->scalarNode('list_mode')
50 ->defaultValue(1) 50 ->defaultValue(1)
51 ->end() 51 ->end()
52 ->scalarNode('notifications_nb')
53 ->defaultValue(5)
54 ->end()
52 ->scalarNode('api_limit_mass_actions') 55 ->scalarNode('api_limit_mass_actions')
53 ->defaultValue(10) 56 ->defaultValue(10)
54 ->end() 57 ->end()
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
index 532ce238..f8b5c7fe 100644
--- a/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
+++ b/src/Wallabag/CoreBundle/DependencyInjection/WallabagCoreExtension.php
@@ -25,6 +25,7 @@ class WallabagCoreExtension extends Extension
25 $container->setParameter('wallabag_core.cache_lifetime', $config['cache_lifetime']); 25 $container->setParameter('wallabag_core.cache_lifetime', $config['cache_lifetime']);
26 $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']); 26 $container->setParameter('wallabag_core.action_mark_as_read', $config['action_mark_as_read']);
27 $container->setParameter('wallabag_core.list_mode', $config['list_mode']); 27 $container->setParameter('wallabag_core.list_mode', $config['list_mode']);
28 $container->setParameter('wallabag_core.notifications_nb', $config['notifications_nb']);
28 $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']); 29 $container->setParameter('wallabag_core.fetching_error_message', $config['fetching_error_message']);
29 $container->setParameter('wallabag_core.fetching_error_message_title', $config['fetching_error_message_title']); 30 $container->setParameter('wallabag_core.fetching_error_message_title', $config['fetching_error_message_title']);
30 $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']); 31 $container->setParameter('wallabag_core.api_limit_mass_actions', $config['api_limit_mass_actions']);
diff --git a/src/Wallabag/CoreBundle/Entity/Notification.php b/src/Wallabag/CoreBundle/Entity/Notification.php
new file mode 100644
index 00000000..6b30b044
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Entity/Notification.php
@@ -0,0 +1,308 @@
1<?php
2
3namespace Wallabag\CoreBundle\Entity;
4
5use Doctrine\Common\Collections\ArrayCollection;
6use Doctrine\ORM\Mapping as ORM;
7use Psr\Log\LoggerInterface;
8use Psr\Log\NullLogger;
9use Wallabag\CoreBundle\Notifications\ActionInterface;
10use Wallabag\CoreBundle\Notifications\NotificationInterface;
11use Wallabag\UserBundle\Entity\User;
12
13/**
14 * Class Notification.
15 *
16 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\NotificationRepository")
17 * @ORM\Table(name="`notification`")
18 */
19class Notification implements NotificationInterface
20{
21 /**
22 * @var int
23 *
24 * @ORM\Column(name="id", type="integer")
25 * @ORM\Id
26 * @ORM\GeneratedValue(strategy="AUTO")
27 */
28 protected $id;
29
30 /**
31 * @var int
32 *
33 * @ORM\Column(name="type", type="integer")
34 */
35 protected $type;
36
37 /**
38 * @var User
39 *
40 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="notifications")
41 */
42 protected $user;
43
44 /**
45 * @var \DateTime
46 *
47 * @ORM\Column(name="timestamp", type="datetime")
48 */
49 protected $timestamp;
50
51 /**
52 * @var string
53 *
54 * @ORM\Column(name="title", type="string")
55 */
56 protected $title;
57
58 /**
59 * @var string
60 *
61 * @ORM\Column(name="description", type="string", nullable=true)
62 */
63 protected $description;
64
65 /**
66 * @var bool
67 *
68 * @ORM\Column(name="read", type="boolean")
69 */
70 protected $read;
71
72 /**
73 * @var array
74 *
75 * @ORM\Column(name="parameters", type="array", nullable=true)
76 */
77 protected $parameters;
78
79 protected $logger;
80
81 /**
82 * @var ArrayCollection<ActionInterface>
83 *
84 * @ORM\Column(name="actions", type="array", nullable=true)
85 */
86 protected $actions;
87
88 protected $actionTypes = [];
89
90 const TYPE_ADMIN = 0;
91 const TYPE_USER = 1;
92 const TYPE_RELEASE = 2;
93
94 public function __construct(User $user = null)
95 {
96 $this->logger = new NullLogger();
97 $this->timestamp = new \DateTime();
98 $this->actions = new ArrayCollection();
99 $this->parameters = [];
100 $this->read = false;
101 $this->user = $user;
102 }
103
104 /**
105 * @param LoggerInterface $logger
106 *
107 * @return NotificationInterface
108 */
109 public function setLogger(LoggerInterface $logger)
110 {
111 $this->logger = $logger;
112
113 return $this;
114 }
115
116 /**
117 * @return mixed
118 */
119 public function getId()
120 {
121 return $this->id;
122 }
123
124 /**
125 * @return mixed
126 */
127 public function getType()
128 {
129 return $this->type;
130 }
131
132 /**
133 * @param mixed $type
134 *
135 * @return NotificationInterface
136 */
137 public function setType($type)
138 {
139 $this->type = $type;
140
141 return $this;
142 }
143
144 /**
145 * @return User
146 */
147 public function getUser()
148 {
149 return $this->user;
150 }
151
152 /**
153 * @param User $user
154 *
155 * @return NotificationInterface
156 */
157 public function setUser(User $user)
158 {
159 $this->user = $user;
160
161 return $this;
162 }
163
164 /**
165 * @return \DateTime
166 */
167 public function getTimestamp()
168 {
169 return $this->timestamp;
170 }
171
172 /**
173 * @param \DateTime $timestamp
174 *
175 * @return NotificationInterface
176 */
177 public function setTimestamp(\DateTime $timestamp)
178 {
179 $this->timestamp = $timestamp;
180
181 return $this;
182 }
183
184 /**
185 * @return string
186 */
187 public function getTitle()
188 {
189 return $this->title;
190 }
191
192 /**
193 * @param string $title
194 *
195 * @return NotificationInterface
196 */
197 public function setTitle($title)
198 {
199 $this->title = $title;
200
201 return $this;
202 }
203
204 /**
205 * @return bool
206 */
207 public function isRead()
208 {
209 return $this->read;
210 }
211
212 /**
213 * @param bool $read
214 *
215 * @return NotificationInterface
216 */
217 public function setRead($read)
218 {
219 $this->read = $read;
220
221 return $this;
222 }
223
224 /**
225 * @param ActionInterface $action
226 *
227 * @return NotificationInterface
228 *
229 * @throws \InvalidArgumentException
230 */
231 public function addAction(ActionInterface $action)
232 {
233 if (isset($this->actionTypes[$action->getType()])) {
234 throw new \InvalidArgumentException('The notification already has a primary action');
235 }
236 $this->actionTypes[$action->getType()] = true;
237 $this->actions->add($action);
238
239 return $this;
240 }
241
242 /**
243 * @return ArrayCollection<ActionInterface>
244 */
245 public function getActions()
246 {
247 return $this->actions;
248 }
249
250 /**
251 * @return string
252 */
253 public function getDescription()
254 {
255 return $this->description;
256 }
257
258 /**
259 * @param string $description
260 *
261 * @return Notification
262 */
263 public function setDescription($description)
264 {
265 $this->description = $description;
266
267 return $this;
268 }
269
270 /**
271 * @return array
272 */
273 public function getParameters()
274 {
275 return $this->parameters;
276 }
277
278 /**
279 * @param array $parameters
280 *
281 * @return Notification
282 */
283 public function setParameters($parameters)
284 {
285 $this->parameters = $parameters;
286
287 return $this;
288 }
289
290 /**
291 * @param string $key
292 * @param string $value
293 *
294 * @return Notification
295 *
296 * @throws \InvalidArgumentException
297 */
298 public function addParameter($key, $value)
299 {
300 if (in_array($key, $this->parameters, true)) {
301 throw new \InvalidArgumentException('This parameter already is set');
302 }
303
304 $this->parameters[$key] = $value;
305
306 return $this;
307 }
308}
diff --git a/src/Wallabag/CoreBundle/Notifications/Action.php b/src/Wallabag/CoreBundle/Notifications/Action.php
new file mode 100644
index 00000000..d032adf9
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/Action.php
@@ -0,0 +1,91 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5class Action implements ActionInterface
6{
7 /**
8 * @var string
9 */
10 protected $label;
11
12 /**
13 * @var int
14 */
15 protected $type;
16
17 const TYPE_OK = 1;
18 const TYPE_YES = 2;
19 const TYPE_NO = 3;
20 const TYPE_INFO = 4;
21
22 /**
23 * @var string
24 */
25 protected $link;
26
27 /**
28 * @return string
29 */
30 public function getLabel()
31 {
32 return $this->label;
33 }
34
35 /**
36 * @param string $label
37 *
38 * @return ActionInterface
39 */
40 public function setLabel($label)
41 {
42 $this->label = $label;
43
44 return $this;
45 }
46
47 /**
48 * @return int
49 */
50 public function getType()
51 {
52 return $this->type;
53 }
54
55 /**
56 * @param int $type
57 *
58 * @return ActionInterface
59 *
60 * @throws \InvalidArgumentException
61 */
62 public function setType($type)
63 {
64 if ($type <= 0 || $type > 4) {
65 throw new \InvalidArgumentException('The given type option is invalid');
66 }
67 $this->type = $type;
68
69 return $this;
70 }
71
72 /**
73 * @return string
74 */
75 public function getLink()
76 {
77 return $this->link;
78 }
79
80 /**
81 * @param string $link
82 *
83 * @return ActionInterface
84 */
85 public function setLink($link)
86 {
87 $this->link = $link;
88
89 return $this;
90 }
91}
diff --git a/src/Wallabag/CoreBundle/Notifications/ActionInterface.php b/src/Wallabag/CoreBundle/Notifications/ActionInterface.php
new file mode 100644
index 00000000..e166e45b
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/ActionInterface.php
@@ -0,0 +1,42 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5interface ActionInterface
6{
7 /**
8 * @return string
9 */
10 public function getLabel();
11
12 /**
13 * @param string $label
14 *
15 * @return ActionInterface
16 */
17 public function setLabel($label);
18
19 /**
20 * @return int
21 */
22 public function getType();
23
24 /**
25 * @param int $type
26 *
27 * @return ActionInterface
28 */
29 public function setType($type);
30
31 /**
32 * @return string
33 */
34 public function getLink();
35
36 /**
37 * @param string $link
38 *
39 * @return ActionInterface
40 */
41 public function setLink($link);
42}
diff --git a/src/Wallabag/CoreBundle/Notifications/InfoAction.php b/src/Wallabag/CoreBundle/Notifications/InfoAction.php
new file mode 100644
index 00000000..3006b04a
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/InfoAction.php
@@ -0,0 +1,13 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5class InfoAction extends Action
6{
7 public function __construct($link)
8 {
9 $this->link = $link;
10 $this->label = 'Info';
11 $this->type = Action::TYPE_INFO;
12 }
13}
diff --git a/src/Wallabag/CoreBundle/Notifications/NoAction.php b/src/Wallabag/CoreBundle/Notifications/NoAction.php
new file mode 100644
index 00000000..606372b6
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/NoAction.php
@@ -0,0 +1,13 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5class NoAction extends Action
6{
7 public function __construct($link)
8 {
9 $this->link = $link;
10 $this->label = 'No';
11 $this->type = Action::TYPE_NO;
12 }
13}
diff --git a/src/Wallabag/CoreBundle/Notifications/NotificationInterface.php b/src/Wallabag/CoreBundle/Notifications/NotificationInterface.php
new file mode 100644
index 00000000..4a3c2759
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/NotificationInterface.php
@@ -0,0 +1,103 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5use Psr\Log\LoggerAwareInterface;
6
7interface NotificationInterface extends LoggerAwareInterface
8{
9 /**
10 * Title of the notification.
11 *
12 * @return string
13 */
14 public function getTitle();
15
16 /**
17 * @param string $title
18 *
19 * @return NotificationInterface
20 */
21 public function setTitle($title);
22
23 /**
24 * Type of the notification.
25 *
26 * @return string
27 */
28 public function getType();
29
30 /**
31 * @param int $type
32 *
33 * @return NotificationInterface
34 */
35 public function setType($type);
36
37 /**
38 * If the notification has been viewed / dismissed or not.
39 *
40 * @return bool
41 */
42 public function isRead();
43
44 /**
45 * @param bool $read
46 *
47 * @return NotificationInterface
48 */
49 public function setRead($read);
50
51 /**
52 * When the notification was sent.
53 *
54 * @return \DateTime
55 */
56 public function getTimestamp();
57
58 /**
59 * @param \DateTime $timestamp
60 *
61 * @return NotificationInterface
62 */
63 public function setTimestamp(\DateTime $timestamp);
64
65 /**
66 * @param ActionInterface $action
67 *
68 * @return NotificationInterface
69 */
70 public function addAction(ActionInterface $action);
71
72 /**
73 * @return string
74 */
75 public function getDescription();
76
77 /**
78 * @param string $description
79 *
80 * @return NotificationInterface
81 */
82 public function setDescription($description);
83
84 /**
85 * @return array
86 */
87 public function getParameters();
88
89 /**
90 * @param array $parameters
91 *
92 * @return NotificationInterface
93 */
94 public function setParameters($parameters);
95
96 /**
97 * @param string $key
98 * @param string $value
99 *
100 * @return NotificationInterface
101 */
102 public function addParameter($key, $value);
103}
diff --git a/src/Wallabag/CoreBundle/Notifications/OkAction.php b/src/Wallabag/CoreBundle/Notifications/OkAction.php
new file mode 100644
index 00000000..521e6742
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/OkAction.php
@@ -0,0 +1,13 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5class OkAction extends Action
6{
7 public function __construct($link)
8 {
9 $this->link = $link;
10 $this->label = 'OK';
11 $this->type = Action::TYPE_OK;
12 }
13}
diff --git a/src/Wallabag/CoreBundle/Notifications/YesAction.php b/src/Wallabag/CoreBundle/Notifications/YesAction.php
new file mode 100644
index 00000000..9b48eca5
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Notifications/YesAction.php
@@ -0,0 +1,13 @@
1<?php
2
3namespace Wallabag\CoreBundle\Notifications;
4
5class YesAction extends Action
6{
7 public function __construct($link)
8 {
9 $this->link = $link;
10 $this->label = 'Yes';
11 $this->type = Action::TYPE_YES;
12 }
13}
diff --git a/src/Wallabag/CoreBundle/Repository/NotificationRepository.php b/src/Wallabag/CoreBundle/Repository/NotificationRepository.php
new file mode 100644
index 00000000..6d6938ae
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Repository/NotificationRepository.php
@@ -0,0 +1,26 @@
1<?php
2
3namespace Wallabag\CoreBundle\Repository;
4
5use Doctrine\ORM\EntityRepository;
6
7class NotificationRepository extends EntityRepository
8{
9 public function markAllAsReadForUser($userId)
10 {
11 return $this->getEntityManager()->createQueryBuilder()
12 ->update('WallabagCoreBundle:Notification', 'n')
13 ->set('n.read', true)
14 ->where('n.user = :userId')->setParameter('userId', $userId)
15 ->getQuery()
16 ->getResult();
17 }
18
19 public function getBuilderForNotificationsByUser($userId)
20 {
21 return $this->createQueryBuilder('n')
22 ->andWhere('n.user = :userId')->setParameter('userId', $userId)
23 ->orderBy('n.timestamp', 'desc')
24 ;
25 }
26}
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index e09b0f18..183b6690 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -129,6 +129,12 @@ services:
129 calls: 129 calls:
130 - [ setCrypto, [ "@wallabag_core.helper.crypto_proxy" ] ] 130 - [ setCrypto, [ "@wallabag_core.helper.crypto_proxy" ] ]
131 131
132 wallabag_core.notification_repository:
133 class: Wallabag\CoreBundle\Repository\NotificationRepository
134 factory: [ "@doctrine.orm.default_entity_manager", getRepository ]
135 arguments:
136 - WallabagCoreBundle:Notification
137
132 wallabag_core.helper.entries_export: 138 wallabag_core.helper.entries_export:
133 class: Wallabag\CoreBundle\Helper\EntriesExport 139 class: Wallabag\CoreBundle\Helper\EntriesExport
134 arguments: 140 arguments:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.da.yml b/src/Wallabag/CoreBundle/Resources/translations/date.da.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.da.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.de.yml b/src/Wallabag/CoreBundle/Resources/translations/date.de.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.de.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.en.yml b/src/Wallabag/CoreBundle/Resources/translations/date.en.yml
new file mode 100644
index 00000000..7bcd6d0c
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.en.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 empty: 'Now'
4 second: 'One second ago|%count% seconds ago'
5 minute: 'One minute ago|%count% minutes ago'
6 hour: 'One hour ago|%count% hours ago'
7 day: 'One day ago|%count% days ago'
8 month: 'One month ago|%count% months ago'
9 year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.es.yml b/src/Wallabag/CoreBundle/Resources/translations/date.es.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.es.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/date.fa.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.fa.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/date.fr.yml
new file mode 100644
index 00000000..02eb96b0
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.fr.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 empty: 'Maintenant'
4 second: 'Il y a une seconde|il y a %count% secondes'
5 minute: 'Il y a une minute|il y a %count% minutes'
6 hour: 'Il y a une heure|il y a %count% heures'
7 day: 'Il y a un jour|Il y a %count% jours'
8 month: 'Il y a un mois|il y a %count% mois'
9 year: 'Il y a un an|il y a %count% ans'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.it.yml b/src/Wallabag/CoreBundle/Resources/translations/date.it.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.it.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/date.oc.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.oc.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/date.pl.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.pl.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/date.pt.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.pt.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/date.ro.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.ro.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/date.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/date.tr.yml
new file mode 100644
index 00000000..3797b6bf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/translations/date.tr.yml
@@ -0,0 +1,9 @@
1diff:
2 ago:
3 # empty: 'Now'
4 # second: 'One second ago|%count% seconds ago'
5 # minute: 'One minute ago|%count% minutes ago'
6 # hour: 'One hour ago|%count% hours ago'
7 # day: 'One day ago|%count% days ago'
8 # month: 'One month ago|%count% months ago'
9 # year: 'One year ago|%count% years ago'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
index 5229ac73..ad03fa91 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Søg' 38 search: 'Søg'
39 filter_entries: 'Filtrer artikler' 39 filter_entries: 'Filtrer artikler'
40 # export: 'Export' 40 # export: 'Export'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Indtast søgning' 43 input_label: 'Indtast søgning'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'Om' 266 page_title: 'Om'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
index 996f173a..f2d75a62 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Suche' 38 search: 'Suche'
39 filter_entries: 'Artikel filtern' 39 filter_entries: 'Artikel filtern'
40 export: 'Exportieren' 40 export: 'Exportieren'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Suchbegriff hier eingeben' 43 input_label: 'Suchbegriff hier eingeben'
43 44
@@ -250,6 +251,17 @@ entry:
250 delete: "Bist du sicher, dass du diesen Artikel löschen möchtest?" 251 delete: "Bist du sicher, dass du diesen Artikel löschen möchtest?"
251 delete_tag: "Bist du sicher, dass du diesen Tag vom Artikel entfernen möchtest?" 252 delete_tag: "Bist du sicher, dass du diesen Tag vom Artikel entfernen möchtest?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'Über' 266 page_title: 'Über'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index aa1cd1a9..228dd87e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Search' 38 search: 'Search'
39 filter_entries: 'Filter entries' 39 filter_entries: 'Filter entries'
40 export: 'Export' 40 export: 'Export'
41 notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Enter your search here' 43 input_label: 'Enter your search here'
43 44
@@ -250,6 +251,16 @@ entry:
250 delete: "Are you sure you want to remove that article?" 251 delete: "Are you sure you want to remove that article?"
251 delete_tag: "Are you sure you want to remove that tag from that article?" 252 delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254notifications:
255 sidebar:
256 view_more: 'View more'
257 list:
258 page_title: 'Notifications'
259 mark_all_as_read: 'Mark all as read'
260 none: "No notifications yet :'("
261 release:
262 title: "wallabag has been updated to version %version%"
263 details: "View update's details"
253about: 264about:
254 page_title: 'About' 265 page_title: 'About'
255 top_menu: 266 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
index 96998f53..28f064c7 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Buscar' 38 search: 'Buscar'
39 filter_entries: 'Filtrar los artículos' 39 filter_entries: 'Filtrar los artículos'
40 export: 'Exportar' 40 export: 'Exportar'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Introduzca su búsqueda aquí' 43 input_label: 'Introduzca su búsqueda aquí'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'Acerca de' 266 page_title: 'Acerca de'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
index 57e6c029..4496a2f2 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'جستجو' 38 search: 'جستجو'
39 filter_entries: 'فیلترکردن مقاله‌ها' 39 filter_entries: 'فیلترکردن مقاله‌ها'
40 export: 'برون‌بری' 40 export: 'برون‌بری'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'جستجوی خود را این‌جا بنویسید:' 43 input_label: 'جستجوی خود را این‌جا بنویسید:'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'درباره' 266 page_title: 'درباره'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index 6eac4c36..8bccc8a4 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -38,6 +38,7 @@ menu:
38 search: "Rechercher" 38 search: "Rechercher"
39 filter_entries: "Filtrer les articles" 39 filter_entries: "Filtrer les articles"
40 export: "Exporter" 40 export: "Exporter"
41 notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: "Saisissez votre terme de recherche" 43 input_label: "Saisissez votre terme de recherche"
43 44
@@ -250,6 +251,17 @@ entry:
250 delete: "Voulez-vous vraiment supprimer cet article ?" 251 delete: "Voulez-vous vraiment supprimer cet article ?"
251 delete_tag: "Voulez-vous vraiment supprimer ce tag de cet article ?" 252 delete_tag: "Voulez-vous vraiment supprimer ce tag de cet article ?"
252 253
254notifications:
255 sidebar:
256 view_more: 'Voir plus'
257 list:
258 page_title: 'Notifications'
259 mark_all_as_read: 'Marquer tout comme lu'
260 none: "Aucune notification pour le moment :'("
261 release:
262 title: "wallabag a été mis à jour vers la version %version%"
263 details: "Voir les détails de la mise à jour"
264
253about: 265about:
254 page_title: "À propos" 266 page_title: "À propos"
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
index 4e26f38c..c404b3e5 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Cerca' 38 search: 'Cerca'
39 filter_entries: 'Filtra contenuti' 39 filter_entries: 'Filtra contenuti'
40 export: 'Esporta' 40 export: 'Esporta'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Inserisci qui la tua ricerca' 43 input_label: 'Inserisci qui la tua ricerca'
43 44
@@ -250,6 +251,16 @@ entry:
250 delete: "Vuoi veramente rimuovere quell'articolo?" 251 delete: "Vuoi veramente rimuovere quell'articolo?"
251 delete_tag: "Vuoi veramente rimuovere quell'etichetta da quell'articolo?" 252 delete_tag: "Vuoi veramente rimuovere quell'etichetta da quell'articolo?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
253about: 264about:
254 page_title: 'A proposito' 265 page_title: 'A proposito'
255 top_menu: 266 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
index be57e903..af9d85c3 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Cercar' 38 search: 'Cercar'
39 filter_entries: 'Filtrar los articles' 39 filter_entries: 'Filtrar los articles'
40 export: 'Exportar' 40 export: 'Exportar'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Picatz vòstre mot-clau a cercar aquí' 43 input_label: 'Picatz vòstre mot-clau a cercar aquí'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'A prepaus' 266 page_title: 'A prepaus'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
index 00c559ed..78464162 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Szukaj' 38 search: 'Szukaj'
39 filter_entries: 'Filtruj wpisy' 39 filter_entries: 'Filtruj wpisy'
40 export: 'Eksportuj' 40 export: 'Eksportuj'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Wpisz swoje zapytanie tutaj' 43 input_label: 'Wpisz swoje zapytanie tutaj'
43 44
@@ -250,6 +251,17 @@ entry:
250 delete: "Czy jesteś pewien, że chcesz usunąć ten artykuł?" 251 delete: "Czy jesteś pewien, że chcesz usunąć ten artykuł?"
251 delete_tag: "Czy jesteś pewien, że chcesz usunąć ten tag, z tego artykułu?" 252 delete_tag: "Czy jesteś pewien, że chcesz usunąć ten tag, z tego artykułu?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'O nas' 266 page_title: 'O nas'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
index 4ab5f144..07eeefc2 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Pesquisa' 38 search: 'Pesquisa'
39 filter_entries: 'Filtrar entradas' 39 filter_entries: 'Filtrar entradas'
40 export: 'Exportar' 40 export: 'Exportar'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Digite aqui sua pesquisa' 43 input_label: 'Digite aqui sua pesquisa'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'Sobre' 266 page_title: 'Sobre'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
index f16504ed..ba7b11d5 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Căutare' 38 search: 'Căutare'
39 filter_entries: 'Filtrează articolele' 39 filter_entries: 'Filtrează articolele'
40 # export: 'Export' 40 # export: 'Export'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Introdu căutarea ta' 43 input_label: 'Introdu căutarea ta'
43 44
@@ -250,6 +251,17 @@ entry:
250 # delete: "Are you sure you want to remove that article?" 251 # delete: "Are you sure you want to remove that article?"
251 # delete_tag: "Are you sure you want to remove that tag from that article?" 252 # delete_tag: "Are you sure you want to remove that tag from that article?"
252 253
254# notifications:
255# sidebar:
256# view_more: 'View more'
257# list:
258# page_title: 'Notifications'
259# mark_all_as_read: 'Mark all as read'
260# none: "No notifications yet :'("
261# release:
262# title: "wallabag has been updated to version %version%"
263# details: "View update's details"
264
253about: 265about:
254 page_title: 'Despre' 266 page_title: 'Despre'
255 top_menu: 267 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
index 90a140cd..6cbe6dcd 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
@@ -38,6 +38,7 @@ menu:
38 search: 'Ara' 38 search: 'Ara'
39 filter_entries: 'Filtrele' 39 filter_entries: 'Filtrele'
40 export: 'Dışa Aktar' 40 export: 'Dışa Aktar'
41 # notifications: 'Notifications'
41 search_form: 42 search_form:
42 input_label: 'Aramak istediğiniz herhangi bir şey yazın' 43 input_label: 'Aramak istediğiniz herhangi bir şey yazın'
43 44
@@ -248,6 +249,17 @@ entry:
248 # delete: "Are you sure you want to remove that article?" 249 # delete: "Are you sure you want to remove that article?"
249 # delete_tag: "Are you sure you want to remove that tag from that article?" 250 # delete_tag: "Are you sure you want to remove that tag from that article?"
250 251
252# notifications:
253# sidebar:
254# view_more: 'View more'
255# list:
256# page_title: 'Notifications'
257# mark_all_as_read: 'Mark all as read'
258# none: "No notifications yet :'("
259# release:
260# title: "wallabag has been updated to version %version%"
261# details: "View update's details"
262
251about: 263about:
252 page_title: 'Hakkımızda' 264 page_title: 'Hakkımızda'
253 top_menu: 265 top_menu:
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client.html.twig
index 8a5da71a..d566795d 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/client.html.twig
@@ -3,6 +3,7 @@
3{% block title %}{{ 'developer.client.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'developer.client.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6{{ parent() }}
6<div class="row"> 7<div class="row">
7 <div class="col s12"> 8 <div class="col s12">
8 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig
index 528b055c..53210688 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Developer/index.html.twig
@@ -3,6 +3,7 @@
3{% block title %}{{ 'developer.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'developer.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6{{ parent() }}
6<div class="row"> 7<div class="row">
7 <div class="col s12"> 8 <div class="col s12">
8 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/about.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/about.html.twig
index 1cd3485c..ffd9b1b8 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/about.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/about.html.twig
@@ -3,7 +3,7 @@
3{% block title %}{{ 'about.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'about.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 6 {{ parent() }}
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
index 231f9bdf..4c598b85 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
@@ -3,7 +3,7 @@
3{% block title %}{{ 'howto.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'howto.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 6 {{ parent() }}
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
index 4580813c..70265be2 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
@@ -3,7 +3,7 @@
3{% block title %}{{ 'quickstart.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'quickstart.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 6 {{ parent() }}
7 <div class="row quickstart"> 7 <div class="row quickstart">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
index a8143315..bd5932b0 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
@@ -3,7 +3,7 @@
3{% block title %}{{ 'config.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'config.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 6 {{ parent() }}
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel settings"> 9 <div class="card-panel settings">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
index 0c4dc80b..1cc5489f 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
@@ -19,6 +19,7 @@
19{% endblock %} 19{% endblock %}
20 20
21{% block content %} 21{% block content %}
22 {{ parent() }}
22 {% set listMode = app.user.config.listMode %} 23 {% set listMode = app.user.config.listMode %}
23 {% set currentRoute = app.request.attributes.get('_route') %} 24 {% set currentRoute = app.request.attributes.get('_route') %}
24 <div class="results clearfix"> 25 <div class="results clearfix">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Notification/notifications.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Notification/notifications.html.twig
new file mode 100644
index 00000000..49cc0d40
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Notification/notifications.html.twig
@@ -0,0 +1,56 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'notifications.list.page_title' | trans }}{% endblock %}
4
5{% block content %}
6 {{ parent() }}
7 <div class="row notifications-page">
8 <div class="col l8 offset-l2">
9 {% if app.user.notifications is not empty %}
10 <div class="row">
11 <a href="{{ path('notification-archive-all') }}" class="btn-light waves-effect waves-light right"><i class="material-icons">done_all</i> {{ 'notifications.list.mark_all_as_read' | trans }}</a>
12 </div>
13 <ul class="collection">
14 {% for notification in notifications | slice(0, 10) %}
15 <li class="notification collection-item avatar{% if not notification.read %} light-blue lighten-5{% else %} grey-text{% endif %}">
16 <i class="material-icons circle">{% spaceless %}
17 {% if notification.type == constant('TYPE_ADMIN', notification) %}
18 build
19 {% elseif notification.type == constant('TYPE_USER', notification) %}
20 person
21 {% elseif notification.type == constant('TYPE_RELEASE', notification) %}
22 new_releases
23 {% endif %}
24 {% endspaceless %}</i>
25 <span class="title">{{ notification.title | trans(notification.parameters) }}</span>
26 <p>{{ notification.description | trans | trans(notification.parameters) }}</p>
27 <time datetime="{{ notification.timestamp | date }}">{{ notification.timestamp | time_diff }}</time>
28 <div class="secondary-content">
29 {% if not notification.read %}
30 {% for action in notification.actions %}
31 <a class="notification-action btn waves-effect waves-light {% spaceless %}
32 {% if action.type == constant('TYPE_OK', action) %}
33 {% elseif action.type == constant('TYPE_YES', action) %}
34 cyan
35 {% elseif action.type == constant('TYPE_NO', action) %}
36 red
37 {% elseif action.type == constant('TYPE_INFO', action) %}
38 blue-grey
39 {% endif %}
40 {% endspaceless %}" data-id="{{ notification.id }}" href="{{ path('notification-archive-redirect', {'redirection': action.link, 'notification': notification.id}) }}">{{ action.label | trans(notification.parameters) }}</a>
41 {% endfor %}
42 <a href="{{ path('notification-archive', {'notification': notification.id}) }}" class="notification-action waves-effect waves-teal btn-flat"><i class="material-icons">check</i></a>
43 {% endif %}
44 </div>
45 </li>
46 {% endfor %}
47 </ul>
48 {% else %}
49 {{ 'notifications.list.none' | trans }}
50 {% endif %}
51 {% if notifications.getNbPages > 1 %}
52 {{ pagerfanta(notifications, 'twitter_bootstrap_translated', {'proximity': 1}) }}
53 {% endif %}
54 </div>
55 </div>
56{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
index 97ddedc9..7a0f793c 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/tags.html.twig
@@ -3,6 +3,7 @@
3{% block title %}{{ 'tag.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'tag.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 {{ parent() }}
6 <div class="results clearfix"> 7 <div class="results clearfix">
7 <div class="nb-results left">{{ 'tag.list.number_on_the_page'|transchoice(tags|length) }}</div> 8 <div class="nb-results left">{{ 'tag.list.number_on_the_page'|transchoice(tags|length) }}</div>
8 </div> 9 </div>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
index 60907e11..ccc44931 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -110,6 +110,13 @@
110 <i class="material-icons">search</i> 110 <i class="material-icons">search</i>
111 </a> 111 </a>
112 </li> 112 </li>
113 <li id="button_notifications">
114 {% set unreadNotifs = get_notifications() | unread_notif | length %}
115 <a class="nav-panel-menu button-collapse-right tooltipped js-notifications-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.notifications' | trans }}" href="#" data-activates="notifications">
116 <i class="material-icons">notifications{% if unreadNotifs == 0 %}_none{% endif %}</i>
117 {% if unreadNotifs > 0 %}<span id="notifications-count" class="red-text text-accent-2">{{ unreadNotifs }}</span>{% endif %}
118 </a>
119 </li>
113 <li id="button_filters"> 120 <li id="button_filters">
114 <a class="nav-panel-menu button-collapse-right tooltipped js-filters-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters"> 121 <a class="nav-panel-menu button-collapse-right tooltipped js-filters-action" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters">
115 <i class="material-icons">filter_list</i> 122 <i class="material-icons">filter_list</i>
@@ -135,6 +142,53 @@
135 </nav> 142 </nav>
136{% endblock %} 143{% endblock %}
137 144
145{% block content %}
146
147 <div id="notifications" class="side-nav">
148 {% if app.user.notifications is not empty %}
149 <div class="notifications-area">
150 <ul class="collection">
151 {% for notification in get_notifications() | slice(0, 10) %}
152 <li class="notification collection-item avatar{% if not notification.read %} light-blue lighten-5{% else %} grey-text{% endif %}">
153 <i class="material-icons circle">{% spaceless %}
154 {% if notification.type == constant('TYPE_ADMIN', notification) %}
155 build
156 {% elseif notification.type == constant('TYPE_USER', notification) %}
157 person
158 {% elseif notification.type == constant('TYPE_RELEASE', notification) %}
159 new_releases
160 {% endif %}
161 {% endspaceless %}</i>
162 <span class="title">{{ notification.title | trans(notification.parameters) }}</span>
163 <p>{{ notification.description | trans(notification.parameters) }}</p>
164 <time datetime="{{ notification.timestamp | date }}">{{ notification.timestamp | time_diff }}</time>
165 <div>
166 {% for action in notification.actions %}
167 <a class="notification-action-button btn waves-effect waves-light {% spaceless %}
168 {% if action.type == constant('TYPE_OK', action) %}
169 {% elseif action.type == constant('TYPE_YES', action) %}
170 cyan
171 {% elseif action.type == constant('TYPE_NO', action) %}
172 red
173 {% elseif action.type == constant('TYPE_INFO', action) %}
174 blue-grey
175 {% endif %}
176 {% if notification.read %}lighten-3{% endif %}
177 {% endspaceless %}" href="{{ path('notification-archive-redirect', {'redirection': action.link, 'notification': notification.id}) }}">{{ action.label | trans(notification.parameters) }}</a>
178 {% endfor %}
179 </div>
180 </li>
181 {% endfor %}
182 </ul>
183 </div>
184 <a href="{{ path('notification-archive-all') }}" class="btn-light waves-effect waves-light right"><i class="material-icons">done_all</i> {{ 'notifications.list.mark_all_as_read' | trans }}</a>
185 <a class="waves-effect waves-light btn view-more" href="{{ path('notifications-all') }}">{{ 'notifications.sidebar.view_more' | trans }}</a>
186 {% else %}
187 <div class="no-notifications grey-text">{{ 'notifications.list.none' | trans }}</div>
188 {% endif %}
189 </div>
190{% endblock %}
191
138{% block footer %} 192{% block footer %}
139 <footer class="page-footer cyan darken-2"> 193 <footer class="page-footer cyan darken-2">
140 <div class="footer-copyright"> 194 <div class="footer-copyright">
diff --git a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php
index a305c53f..034b3fa2 100644
--- a/src/Wallabag/CoreBundle/Twig/WallabagExtension.php
+++ b/src/Wallabag/CoreBundle/Twig/WallabagExtension.php
@@ -3,7 +3,9 @@
3namespace Wallabag\CoreBundle\Twig; 3namespace Wallabag\CoreBundle\Twig;
4 4
5use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 5use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
6use Wallabag\CoreBundle\Notifications\NotificationInterface;
6use Wallabag\CoreBundle\Repository\EntryRepository; 7use Wallabag\CoreBundle\Repository\EntryRepository;
8use Wallabag\CoreBundle\Repository\NotificationRepository;
7use Wallabag\CoreBundle\Repository\TagRepository; 9use Wallabag\CoreBundle\Repository\TagRepository;
8use Symfony\Component\Translation\TranslatorInterface; 10use Symfony\Component\Translation\TranslatorInterface;
9 11
@@ -12,15 +14,19 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
12 private $tokenStorage; 14 private $tokenStorage;
13 private $entryRepository; 15 private $entryRepository;
14 private $tagRepository; 16 private $tagRepository;
17 private $notificationRepository;
15 private $lifeTime; 18 private $lifeTime;
19 private $nbNotifications;
16 private $translator; 20 private $translator;
17 21
18 public function __construct(EntryRepository $entryRepository, TagRepository $tagRepository, TokenStorageInterface $tokenStorage, $lifeTime, TranslatorInterface $translator) 22 public function __construct(EntryRepository $entryRepository, TagRepository $tagRepository, NotificationRepository $notificationRepository, TokenStorageInterface $tokenStorage, $lifeTime, $nbNotifications, TranslatorInterface $translator)
19 { 23 {
20 $this->entryRepository = $entryRepository; 24 $this->entryRepository = $entryRepository;
21 $this->tagRepository = $tagRepository; 25 $this->tagRepository = $tagRepository;
26 $this->notificationRepository = $notificationRepository;
22 $this->tokenStorage = $tokenStorage; 27 $this->tokenStorage = $tokenStorage;
23 $this->lifeTime = $lifeTime; 28 $this->lifeTime = $lifeTime;
29 $this->nbNotifications = $nbNotifications;
24 $this->translator = $translator; 30 $this->translator = $translator;
25 } 31 }
26 32
@@ -28,6 +34,7 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
28 { 34 {
29 return [ 35 return [
30 new \Twig_SimpleFilter('removeWww', [$this, 'removeWww']), 36 new \Twig_SimpleFilter('removeWww', [$this, 'removeWww']),
37 new \Twig_SimpleFilter('unread_notif', [$this, 'unreadNotif']),
31 ]; 38 ];
32 } 39 }
33 40
@@ -37,6 +44,7 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
37 new \Twig_SimpleFunction('count_entries', [$this, 'countEntries']), 44 new \Twig_SimpleFunction('count_entries', [$this, 'countEntries']),
38 new \Twig_SimpleFunction('count_tags', [$this, 'countTags']), 45 new \Twig_SimpleFunction('count_tags', [$this, 'countTags']),
39 new \Twig_SimpleFunction('display_stats', [$this, 'displayStats']), 46 new \Twig_SimpleFunction('display_stats', [$this, 'displayStats']),
47 new \Twig_SimpleFunction('get_notifications', [$this, 'getNotifications'])
40 ); 48 );
41 } 49 }
42 50
@@ -46,6 +54,17 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
46 } 54 }
47 55
48 /** 56 /**
57 * @param $notifs
58 * @return array
59 */
60 public function unreadNotif($notifs)
61 {
62 return array_filter($notifs, function (NotificationInterface $notif) {
63 return !$notif->isRead();
64 });
65 }
66
67 /**
49 * Return number of entries depending of the type (unread, archive, starred or all). 68 * Return number of entries depending of the type (unread, archive, starred or all).
50 * 69 *
51 * @param string $type Type of entries to count 70 * @param string $type Type of entries to count
@@ -111,6 +130,21 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
111 return $this->tagRepository->countAllTags($user->getId()); 130 return $this->tagRepository->countAllTags($user->getId());
112 } 131 }
113 132
133 public function getNotifications()
134 {
135 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
136
137 if (null === $user || !is_object($user)) {
138 return 0;
139 }
140
141 return $this->notificationRepository->findBy(
142 ['user' => $user->getId()],
143 ['timestamp' => 'DESC'],
144 $this->nbNotifications
145 );
146 }
147
114 /** 148 /**
115 * Display a single line about reading stats. 149 * Display a single line about reading stats.
116 * 150 *
@@ -147,9 +181,4 @@ class WallabagExtension extends \Twig_Extension implements \Twig_Extension_Globa
147 '%per_day%' => round($nbArchives / $nbDays, 2), 181 '%per_day%' => round($nbArchives / $nbDays, 2),
148 ]); 182 ]);
149 } 183 }
150
151 public function getName()
152 {
153 return 'wallabag_extension';
154 }
155} 184}
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index aba76ca7..aed5c73e 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -88,6 +88,11 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
88 protected $entries; 88 protected $entries;
89 89
90 /** 90 /**
91 * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Notification", mappedBy="user", cascade={"remove"})
92 */
93 protected $notifications;
94
95 /**
91 * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user", cascade={"remove"}) 96 * @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user", cascade={"remove"})
92 */ 97 */
93 protected $config; 98 protected $config;
@@ -312,4 +317,20 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
312 return $this->clients->first(); 317 return $this->clients->first();
313 } 318 }
314 } 319 }
320
321 /**
322 * @return ArrayCollection<NotificationInterface>
323 */
324 public function getNotifications()
325 {
326 return $this->notifications;
327 }
328
329 /**
330 * @param ArrayCollection<NotificationInterface> $notifications
331 */
332 public function setNotifications($notifications)
333 {
334 $this->notifications = $notifications;
335 }
315} 336}
diff --git a/src/Wallabag/UserBundle/Resources/views/manage.html.twig b/src/Wallabag/UserBundle/Resources/views/manage.html.twig
index c614c55f..10d8050c 100644
--- a/src/Wallabag/UserBundle/Resources/views/manage.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/manage.html.twig
@@ -3,7 +3,7 @@
3{% block title %}{{ 'user.manage.page_title'|trans }}{% endblock %} 3{% block title %}{{ 'user.manage.page_title'|trans }}{% endblock %}
4 4
5{% block content %} 5{% block content %}
6 6 {{ parent() }}
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel"> 9 <div class="card-panel">