aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/CoreBundle
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag/CoreBundle')
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php53
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php13
-rw-r--r--src/Wallabag/CoreBundle/Controller/ShareController.php165
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php5
-rw-r--r--src/Wallabag/CoreBundle/Entity/Activity.php295
-rw-r--r--src/Wallabag/CoreBundle/Entity/Config.php2
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php26
-rw-r--r--src/Wallabag/CoreBundle/Entity/Notification.php1
-rw-r--r--src/Wallabag/CoreBundle/Entity/Share.php140
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationCreatedEvent.php8
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationDeletedEvent.php8
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEditedEvent.php8
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEvent.php39
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryDeletedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEditedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEvent.php41
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryFavouriteEvent.php14
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryReadEvent.php14
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntrySavedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryTaggedEvent.php55
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FederationEvent.php40
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FollowEvent.php39
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/RecommendedEntryEvent.php43
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/UnfollowEvent.php39
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareAcceptedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCancelledEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCreatedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareDeniedEvent.php11
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareEvent.php39
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserDeletedEvent.php8
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEditedEvent.php8
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEvent.php41
-rw-r--r--src/Wallabag/CoreBundle/Event/Activity/ActivitySubscriber.php224
-rw-r--r--src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php26
-rw-r--r--src/Wallabag/CoreBundle/Event/EntrySavedEvent.php26
-rw-r--r--src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php4
-rw-r--r--src/Wallabag/CoreBundle/Repository/ChangeRepository.php26
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php14
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml8
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml11
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml5
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig45
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig5
45 files changed, 1552 insertions, 67 deletions
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index eb725a59..e327bbe5 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -286,7 +286,7 @@ class InstallCommand extends ContainerAwareCommand
286 286
287 protected function setupConfig() 287 protected function setupConfig()
288 { 288 {
289 $this->defaultOutput->writeln('<info><comment>Step 4 of 5.</comment> Config setup.</info>'); 289 $this->defaultOutput->writeln('<info><comment>Step 4 of 5.</comment> config setup.</info>');
290 $em = $this->getContainer()->get('doctrine.orm.entity_manager'); 290 $em = $this->getContainer()->get('doctrine.orm.entity_manager');
291 291
292 // cleanup before insert new stuff 292 // cleanup before insert new stuff
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index d4170d39..23af98e5 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -10,12 +10,16 @@ use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; 10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
11use Wallabag\CoreBundle\Entity\Config; 11use Wallabag\CoreBundle\Entity\Config;
12use Wallabag\CoreBundle\Entity\TaggingRule; 12use Wallabag\CoreBundle\Entity\TaggingRule;
13use Wallabag\CoreBundle\Event\Activity\Actions\User\UserDeletedEvent;
14use Wallabag\CoreBundle\Event\Activity\Actions\User\UserEditedEvent;
13use Wallabag\CoreBundle\Form\Type\ConfigType; 15use Wallabag\CoreBundle\Form\Type\ConfigType;
14use Wallabag\CoreBundle\Form\Type\ChangePasswordType; 16use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
15use Wallabag\CoreBundle\Form\Type\RssType; 17use Wallabag\CoreBundle\Form\Type\RssType;
16use Wallabag\CoreBundle\Form\Type\TaggingRuleType; 18use Wallabag\CoreBundle\Form\Type\TaggingRuleType;
17use Wallabag\CoreBundle\Form\Type\UserInformationType; 19use Wallabag\CoreBundle\Form\Type\UserInformationType;
18use Wallabag\CoreBundle\Tools\Utils; 20use Wallabag\CoreBundle\Tools\Utils;
21use Wallabag\FederationBundle\Form\Type\AccountType;
22use Wallabag\UserBundle\Entity\User;
19 23
20class ConfigController extends Controller 24class ConfigController extends Controller
21{ 25{
@@ -82,6 +86,50 @@ class ConfigController extends Controller
82 if ($userForm->isSubmitted() && $userForm->isValid()) { 86 if ($userForm->isSubmitted() && $userForm->isValid()) {
83 $userManager->updateUser($user, true); 87 $userManager->updateUser($user, true);
84 88
89 $this->get('event_dispatcher')->dispatch(UserEditedEvent::NAME, new UserEditedEvent($user->getAccount()));
90
91 $this->get('session')->getFlashBag()->add(
92 'notice',
93 'flashes.config.notice.user_updated'
94 );
95
96 return $this->redirect($this->generateUrl('config').'#set3');
97 }
98
99 // handle account information
100 $account = $user->getAccount();
101 $accountForm = $this->createForm(AccountType::class, $account, [
102 'action' => $this->generateUrl('config').'#set3',
103 ]);
104 $accountForm->handleRequest($request);
105
106 if ($accountForm->isSubmitted() && $accountForm->isValid()) {
107
108 $avatar = $account->getAvatar();
109 $banner = $account->getBanner();
110
111 if (null !== $avatar) {
112 $avatarFileName = md5(uniqid('', true)) . '.' . $avatar->guessExtension();
113
114 $avatar->move(
115 $this->getParameter('media_directory') . '/avatar',
116 $avatarFileName
117 );
118 $account->setAvatar($avatarFileName);
119 }
120
121 if (null != $banner) {
122 $bannerFileName = md5(uniqid('', true)) . '.' . $banner->guessExtension();
123
124 $banner->move(
125 $this->get('media_directory') . '/banner',
126 $bannerFileName
127 );
128 $account->setBanner($bannerFileName);
129 }
130
131 $this->get('event_dispatcher')->dispatch(UserEditedEvent::NAME, new UserEditedEvent($user));
132
85 $this->get('session')->getFlashBag()->add( 133 $this->get('session')->getFlashBag()->add(
86 'notice', 134 'notice',
87 'flashes.config.notice.user_updated' 135 'flashes.config.notice.user_updated'
@@ -145,6 +193,7 @@ class ConfigController extends Controller
145 'pwd' => $pwdForm->createView(), 193 'pwd' => $pwdForm->createView(),
146 'user' => $userForm->createView(), 194 'user' => $userForm->createView(),
147 'new_tagging_rule' => $newTaggingRule->createView(), 195 'new_tagging_rule' => $newTaggingRule->createView(),
196 'account' => $accountForm->createView(),
148 ], 197 ],
149 'rss' => [ 198 'rss' => [
150 'username' => $user->getUsername(), 199 'username' => $user->getUsername(),
@@ -400,9 +449,13 @@ class ConfigController extends Controller
400 $this->get('security.token_storage')->setToken(null); 449 $this->get('security.token_storage')->setToken(null);
401 $request->getSession()->invalidate(); 450 $request->getSession()->invalidate();
402 451
452 $account = $user->getAccount();
453
403 $em = $this->get('fos_user.user_manager'); 454 $em = $this->get('fos_user.user_manager');
404 $em->deleteUser($user); 455 $em->deleteUser($user);
405 456
457 $this->get('event_dispatcher')->dispatch(UserDeletedEvent::NAME, new UserDeletedEvent($account));
458
406 return $this->redirect($this->generateUrl('fos_user_security_login')); 459 return $this->redirect($this->generateUrl('fos_user_security_login'));
407 } 460 }
408 461
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index fafa49f1..5e4462ed 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -9,12 +9,14 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
9use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 10use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
11use Wallabag\CoreBundle\Entity\Entry; 11use Wallabag\CoreBundle\Entity\Entry;
12use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryEditedEvent;
13use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryFavouriteEvent;
14use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryReadEvent;
15use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntrySavedEvent;
12use Wallabag\CoreBundle\Form\Type\EntryFilterType; 16use Wallabag\CoreBundle\Form\Type\EntryFilterType;
13use Wallabag\CoreBundle\Form\Type\EditEntryType; 17use Wallabag\CoreBundle\Form\Type\EditEntryType;
14use Wallabag\CoreBundle\Form\Type\NewEntryType; 18use Wallabag\CoreBundle\Form\Type\NewEntryType;
15use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; 19use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
16use Wallabag\CoreBundle\Event\EntrySavedEvent;
17use Wallabag\CoreBundle\Event\EntryDeletedEvent;
18use Wallabag\CoreBundle\Form\Type\SearchEntryType; 20use Wallabag\CoreBundle\Form\Type\SearchEntryType;
19 21
20class EntryController extends Controller 22class EntryController extends Controller
@@ -405,6 +407,8 @@ class EntryController extends Controller
405 $entry->toggleArchive(); 407 $entry->toggleArchive();
406 $this->getDoctrine()->getManager()->flush(); 408 $this->getDoctrine()->getManager()->flush();
407 409
410 $this->get('event_dispatcher')->dispatch(EntryReadEvent::NAME, new EntryReadEvent($entry));
411
408 $message = 'flashes.entry.notice.entry_unarchived'; 412 $message = 'flashes.entry.notice.entry_unarchived';
409 if ($entry->isArchived()) { 413 if ($entry->isArchived()) {
410 $message = 'flashes.entry.notice.entry_archived'; 414 $message = 'flashes.entry.notice.entry_archived';
@@ -437,6 +441,8 @@ class EntryController extends Controller
437 $entry->toggleStar(); 441 $entry->toggleStar();
438 $this->getDoctrine()->getManager()->flush(); 442 $this->getDoctrine()->getManager()->flush();
439 443
444 $this->get('event_dispatcher')->dispatch(EntryFavouriteEvent::NAME, new EntryFavouriteEvent($entry));
445
440 $message = 'flashes.entry.notice.entry_unstarred'; 446 $message = 'flashes.entry.notice.entry_unstarred';
441 if ($entry->isStarred()) { 447 if ($entry->isStarred()) {
442 $message = 'flashes.entry.notice.entry_starred'; 448 $message = 'flashes.entry.notice.entry_starred';
@@ -473,9 +479,6 @@ class EntryController extends Controller
473 UrlGeneratorInterface::ABSOLUTE_PATH 479 UrlGeneratorInterface::ABSOLUTE_PATH
474 ); 480 );
475 481
476 // entry deleted, dispatch event about it!
477 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
478
479 $em = $this->getDoctrine()->getManager(); 482 $em = $this->getDoctrine()->getManager();
480 $em->remove($entry); 483 $em->remove($entry);
481 $em->flush(); 484 $em->flush();
diff --git a/src/Wallabag/CoreBundle/Controller/ShareController.php b/src/Wallabag/CoreBundle/Controller/ShareController.php
new file mode 100644
index 00000000..d6f83ebc
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Controller/ShareController.php
@@ -0,0 +1,165 @@
1<?php
2
3namespace Wallabag\CoreBundle\Controller;
4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\RedirectResponse;
8use Symfony\Component\Security\Core\Exception\AccessDeniedException;
9use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
10use Wallabag\CoreBundle\Entity\Entry;
11use Wallabag\CoreBundle\Entity\Notification;
12use Wallabag\CoreBundle\Entity\Share;
13use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntrySavedEvent;
14use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareAcceptedEvent;
15use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareCancelledEvent;
16use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareCreatedEvent;
17use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareDeniedEvent;
18use Wallabag\CoreBundle\Notifications\NoAction;
19use Wallabag\CoreBundle\Notifications\YesAction;
20use Wallabag\UserBundle\Entity\User;
21
22class ShareController extends Controller
23{
24 /**
25 * @Route("/share-user/{entry}/{destination}", name="share-entry-user", requirements={"entry" = "\d+", "destination" = "\d+"})
26 * @param Entry $entry
27 * @param User $destination
28 * @throws AccessDeniedException
29 * @throws InvalidArgumentException
30 */
31 public function shareEntryAction(Entry $entry, User $destination)
32 {
33
34 if ($entry->getUser() !== $this->getUser()) {
35 throw new AccessDeniedException("You can't share this entry");
36 }
37
38 if ($destination === $this->getUser()) {
39 throw new InvalidArgumentException("You can't share entries to yourself");
40 }
41
42 $share = new Share();
43 $share->setUserOrigin($this->getUser())
44 ->setEntry($entry)
45 ->setUserDestination($destination);
46
47 $em = $this->getDoctrine()->getManager();
48 $em->persist($share);
49 $em->flush();
50
51 $this->get('event_dispatcher')->dispatch(ShareCreatedEvent::NAME, new ShareCancelledEvent($share));
52
53 $accept = new YesAction($this->generateUrl('share-entry-user-accept', ['share' => $share->getId()]));
54
55 $deny = new NoAction($this->generateUrl('share-entry-user-refuse', ['share' => $share->getId()]));
56
57 $notification = new Notification($destination);
58 $notification->setType(Notification::TYPE_SHARE)
59 ->setTitle($this->get('translator')->trans('share.notification.new.title'))
60 ->addAction($accept)
61 ->addAction($deny);
62
63 $em->persist($notification);
64 $em->flush();
65
66 $this->redirectToRoute('view', ['id' => $entry->getId()]);
67 }
68
69 /**
70 * @Route("/share-user/accept/{share}", name="share-entry-user-accept")
71 *
72 * @param Share $share
73 * @return RedirectResponse
74 * @throws AccessDeniedException
75 */
76 public function acceptShareAction(Share $share)
77 {
78 if ($share->getUserDestination() !== $this->getUser()) {
79 throw new AccessDeniedException("You can't accept this entry");
80 }
81
82 $entry = new Entry($this->getUser());
83 $entry->setUrl($share->getEntry()->getUrl());
84
85 $em = $this->getDoctrine()->getManager();
86
87 if (false === $this->checkIfEntryAlreadyExists($entry)) {
88 $this->updateEntry($entry);
89
90 $em->persist($entry);
91 $em->flush();
92
93 $this->get('event_dispatcher')->dispatch(ShareAcceptedEvent::NAME, new ShareAcceptedEvent($share));
94
95 // entry saved, dispatch event about it!
96 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
97 }
98
99 $em->remove($share);
100 $em->flush(); // we keep the previous flush above in case the event dispatcher would lead in using the saved entry
101
102 return $this->redirect($this->generateUrl('homepage'));
103 }
104
105 /**
106 * @Route("/share-user/refuse/{share}", name="share-entry-user-refuse")
107 *
108 * @param Share $share
109 * @return RedirectResponse
110 */
111 public function refuseShareAction(Share $share)
112 {
113 $em = $this->getDoctrine()->getManager();
114 $em->remove($share);
115 $em->flush();
116
117 $this->get('event_dispatcher')->dispatch(ShareDeniedEvent::NAME, new ShareDeniedEvent($share));
118
119 return $this->redirect($this->generateUrl('homepage'));
120 }
121
122 /**
123 * Fetch content and update entry.
124 * In case it fails, entry will return to avod loosing the data.
125 *
126 * @param Entry $entry
127 * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded
128 *
129 * @return Entry
130 */
131 private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved')
132 {
133 // put default title in case of fetching content failed
134 $entry->setTitle('No title found');
135
136 $message = 'flashes.entry.notice.'.$prefixMessage;
137
138 try {
139 $entry = $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
140 } catch (\Exception $e) {
141 $this->get('logger')->error('Error while saving an entry', [
142 'exception' => $e,
143 'entry' => $entry,
144 ]);
145
146 $message = 'flashes.entry.notice.'.$prefixMessage.'_failed';
147 }
148
149 $this->get('session')->getFlashBag()->add('notice', $message);
150
151 return $entry;
152 }
153
154 /**
155 * Check for existing entry, if it exists, redirect to it with a message.
156 *
157 * @param Entry $entry
158 *
159 * @return Entry|bool
160 */
161 private function checkIfEntryAlreadyExists(Entry $entry)
162 {
163 return $this->get('wallabag_core.entry_repository')->findByUrlAndUserId($entry->getUrl(), $this->getUser()->getId());
164 }
165}
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php
index a8b1eadd..6cc78458 100644
--- a/src/Wallabag/CoreBundle/Controller/TagController.php
+++ b/src/Wallabag/CoreBundle/Controller/TagController.php
@@ -9,6 +9,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
9use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Wallabag\CoreBundle\Entity\Entry; 10use Wallabag\CoreBundle\Entity\Entry;
11use Wallabag\CoreBundle\Entity\Tag; 11use Wallabag\CoreBundle\Entity\Tag;
12use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryTaggedEvent;
12use Wallabag\CoreBundle\Form\Type\NewTagType; 13use Wallabag\CoreBundle\Form\Type\NewTagType;
13use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 14use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
14 15
@@ -37,6 +38,8 @@ class TagController extends Controller
37 $em->persist($entry); 38 $em->persist($entry);
38 $em->flush(); 39 $em->flush();
39 40
41 $this->get('event_dispatcher')->dispatch(EntryTaggedEvent::NAME, new EntryTaggedEvent($entry, $tags));
42
40 $this->get('session')->getFlashBag()->add( 43 $this->get('session')->getFlashBag()->add(
41 'notice', 44 'notice',
42 'flashes.tag.notice.tag_added' 45 'flashes.tag.notice.tag_added'
@@ -64,6 +67,8 @@ class TagController extends Controller
64 $em = $this->getDoctrine()->getManager(); 67 $em = $this->getDoctrine()->getManager();
65 $em->flush(); 68 $em->flush();
66 69
70 $this->get('event_dispatcher')->dispatch(EntryTaggedEvent::NAME, new EntryTaggedEvent($entry, $tag), true);
71
67 // remove orphan tag in case no entries are associated to it 72 // remove orphan tag in case no entries are associated to it
68 if (count($tag->getEntries()) === 0) { 73 if (count($tag->getEntries()) === 0) {
69 $em->remove($tag); 74 $em->remove($tag);
diff --git a/src/Wallabag/CoreBundle/Entity/Activity.php b/src/Wallabag/CoreBundle/Entity/Activity.php
new file mode 100644
index 00000000..08a3f1fb
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Entity/Activity.php
@@ -0,0 +1,295 @@
1<?php
2
3namespace Wallabag\CoreBundle\Entity;
4
5use Doctrine\ORM\Mapping as ORM;
6use Wallabag\FederationBundle\Entity\Account;
7
8/**
9 * Change.
10 *
11 * This entity stores a datetime for each activity.
12 *
13 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ChangeRepository")
14 * @ORM\Table(name="`activity`")
15 */
16class Activity
17{
18 /**
19 * Object types
20 */
21 const ENTRY_OBJECT = 1;
22 const TAG_OBJECT = 2;
23 const USER_OBJECT = 3;
24 const SHARE_OBJECT = 4;
25 const GROUP_OBJECT = 5;
26 const ANNOTATION_OBJECT = 6;
27 const CONFIG_OBJECT = 7;
28 const ACCOUNT_OBJECT = 8;
29
30 /**
31 * Events
32 */
33
34 /**
35 * Entry events
36 */
37 const ENTRY_ADD = 10; // done
38 const ENTRY_EDIT = 11; // done
39 const ENTRY_READ = 12; // done
40 const ENTRY_UNREAD = 13; // done
41 const ENTRY_FAVOURITE = 14; // done
42 const ENTRY_UNFAVOURITE = 15; // done
43 const ENTRY_DELETE = 19; // done
44
45 /**
46 * Tag events
47 */
48 const TAG_CREATE = 20; // not yet implemented
49 const TAG_EDIT = 21; // not yet implemented
50 const TAG_REMOVE = 29; // not yet implemented
51
52 /**
53 * Entry - Tag events
54 */
55 const ENTRY_ADD_TAG = 30; // done
56 const ENTRY_REMOVE_TAG = 39; // done
57
58 /**
59 * Entry - Annotation events
60 */
61 const ANNOTATION_ADD = 40; // done
62 const ANNOTATION_EDIT = 41; // done
63 const ANNOTATION_REMOVE = 49; // done
64
65 /**
66 * User events
67 */
68 const USER_CREATE = 50; // done
69 const USER_EDIT = 51; // done
70 const USER_REMOVE = 59; // done
71
72 /**
73 * Federation events
74 */
75 const FOLLOW_ACCOUNT = 61;
76 const UNFOLLOW_ACCOUNT = 62;
77 const RECOMMEND_ENTRY = 63;
78
79 /**
80 * Share events
81 */
82 const USER_SHARE_CREATED = 70; // done
83 const USER_SHARE_ACCEPTED = 71; // done
84 const USER_SHARE_REFUSED = 72; // done
85 const USER_SHARE_CANCELLED = 79; // not implemented yet
86
87 /**
88 * Group events
89 */
90 const GROUP_CREATE = 80;
91 const GROUP_EDIT = 81;
92 const GROUP_ADD_MEMBER = 82;
93 const GROUP_EDIT_MEMBER = 83;
94 const GROUP_REMOVE_MEMBER = 84;
95 const GROUP_SHARE_ENTRY = 85;
96 const GROUP_DELETE = 89;
97
98 /**
99 * @var int
100 *
101 * @ORM\Column(type="integer")
102 * @ORM\Id
103 * @ORM\GeneratedValue(strategy="AUTO")
104 */
105 private $id;
106
107 /**
108 * @var int
109 *
110 * @ORM\Column(type="integer")
111 */
112 private $activityType;
113
114 /**
115 * @var Account
116 */
117 private $user;
118
119 /**
120 * @var int
121 *
122 * @ORM\Column(type="integer")
123 */
124 private $primaryObjectType;
125
126 /**
127 * @var int
128 *
129 * @ORM\Column(type="integer")
130 */
131 private $primaryObjectId;
132
133 /**
134 * @var int
135 *
136 * @ORM\Column(type="integer", nullable=true)
137 */
138 private $secondaryObjectType;
139
140 /**
141 * @var int
142 *
143 * @ORM\Column(type="integer", nullable=true)
144 */
145 private $secondaryObjectId;
146
147 /**
148 * @var \DateTime
149 *
150 * @ORM\Column(name="created_at", type="datetime")
151 */
152 private $createdAt;
153
154 public function __construct($activityType, $primaryObjectType, $primaryObjectId)
155 {
156 $this->activityType = $activityType;
157 $this->primaryObjectType = $primaryObjectType;
158 $this->primaryObjectId = $primaryObjectId;
159 $this->createdAt = new \DateTime();
160 }
161
162 /**
163 * @return int
164 */
165 public function getId()
166 {
167 return $this->id;
168 }
169
170 /**
171 * @return int
172 */
173 public function getActivityType()
174 {
175 return $this->activityType;
176 }
177
178 /**
179 * @param int $activityType
180 * @return Activity
181 */
182 public function setActivityType($activityType)
183 {
184 $this->activityType = $activityType;
185 return $this;
186 }
187
188 /**
189 * @return \DateTime
190 */
191 public function getCreatedAt()
192 {
193 return $this->createdAt;
194 }
195
196 /**
197 * @param \DateTime $createdAt
198 * @return Activity
199 */
200 public function setCreatedAt(\DateTime $createdAt)
201 {
202 $this->createdAt = $createdAt;
203 return $this;
204 }
205
206 /**
207 * @return int
208 */
209 public function getPrimaryObjectId()
210 {
211 return $this->primaryObjectId;
212 }
213
214 /**
215 * @param $primaryObjectId
216 * @return Activity
217 */
218 public function setPrimaryObjectId($primaryObjectId)
219 {
220 $this->primaryObjectId = $primaryObjectId;
221 return $this;
222 }
223
224 /**
225 * @return Account
226 */
227 public function getUser()
228 {
229 return $this->user;
230 }
231
232 /**
233 * @param Account $user
234 * @return Activity
235 */
236 public function setUser($user)
237 {
238 $this->user = $user;
239 return $this;
240 }
241
242 /**
243 * @return int
244 */
245 public function getPrimaryObjectType()
246 {
247 return $this->primaryObjectType;
248 }
249
250 /**
251 * @param int $primaryObjectType
252 * @return Activity
253 */
254 public function setPrimaryObjectType($primaryObjectType)
255 {
256 $this->primaryObjectType = $primaryObjectType;
257 return $this;
258 }
259
260 /**
261 * @return int
262 */
263 public function getSecondaryObjectType()
264 {
265 return $this->secondaryObjectType;
266 }
267
268 /**
269 * @param int $secondaryObjectType
270 * @return Activity
271 */
272 public function setSecondaryObjectType($secondaryObjectType)
273 {
274 $this->secondaryObjectType = $secondaryObjectType;
275 return $this;
276 }
277
278 /**
279 * @return int
280 */
281 public function getSecondaryObjectId()
282 {
283 return $this->secondaryObjectId;
284 }
285
286 /**
287 * @param int $secondaryObjectId
288 * @return Activity
289 */
290 public function setSecondaryObjectId($secondaryObjectId)
291 {
292 $this->secondaryObjectId = $secondaryObjectId;
293 return $this;
294 }
295}
diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php
index b902ae2c..f42a49b3 100644
--- a/src/Wallabag/CoreBundle/Entity/Config.php
+++ b/src/Wallabag/CoreBundle/Entity/Config.php
@@ -8,7 +8,7 @@ use Symfony\Component\Validator\Constraints as Assert;
8use Wallabag\UserBundle\Entity\User; 8use Wallabag\UserBundle\Entity\User;
9 9
10/** 10/**
11 * Config. 11 * config.
12 * 12 *
13 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ConfigRepository") 13 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ConfigRepository")
14 * @ORM\Table(name="`config`") 14 * @ORM\Table(name="`config`")
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index a0503c39..6ca17126 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -233,13 +233,21 @@ class Entry
233 */ 233 */
234 private $tags; 234 private $tags;
235 235
236 /* 236 /**
237 * @var boolean
238 *
239 * @ORM\Column(name="recommended", type="boolean", nullable=true)
240 */
241 private $recommended;
242
243 /**
237 * @param User $user 244 * @param User $user
238 */ 245 */
239 public function __construct(User $user) 246 public function __construct(User $user)
240 { 247 {
241 $this->user = $user; 248 $this->user = $user;
242 $this->tags = new ArrayCollection(); 249 $this->tags = new ArrayCollection();
250 $this->changes = new ArrayCollection();
243 } 251 }
244 252
245 /** 253 /**
@@ -778,4 +786,20 @@ class Entry
778 786
779 return $this; 787 return $this;
780 } 788 }
789
790 /**
791 * @return bool
792 */
793 public function isRecommended()
794 {
795 return $this->recommended;
796 }
797
798 /**
799 * @param bool $recommended
800 */
801 public function setRecommended($recommended)
802 {
803 $this->recommended = $recommended;
804 }
781} 805}
diff --git a/src/Wallabag/CoreBundle/Entity/Notification.php b/src/Wallabag/CoreBundle/Entity/Notification.php
index aa4c03c3..d4304f39 100644
--- a/src/Wallabag/CoreBundle/Entity/Notification.php
+++ b/src/Wallabag/CoreBundle/Entity/Notification.php
@@ -91,6 +91,7 @@ class Notification implements NotificationInterface
91 const TYPE_ADMIN = 0; 91 const TYPE_ADMIN = 0;
92 const TYPE_USER = 1; 92 const TYPE_USER = 1;
93 const TYPE_RELEASE = 2; 93 const TYPE_RELEASE = 2;
94 const TYPE_SHARE = 3;
94 95
95 public function __construct(User $user = null) 96 public function __construct(User $user = null)
96 { 97 {
diff --git a/src/Wallabag/CoreBundle/Entity/Share.php b/src/Wallabag/CoreBundle/Entity/Share.php
new file mode 100644
index 00000000..a55b4e67
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Entity/Share.php
@@ -0,0 +1,140 @@
1<?php
2
3namespace Wallabag\CoreBundle\Entity;
4
5use Wallabag\FederationBundle\Entity\Account;
6use Wallabag\UserBundle\Entity\User;
7use Doctrine\ORM\Mapping as ORM;
8
9/**
10 * Share.
11 *
12 * @ORM\Entity
13 */
14class Share
15{
16 /**
17 * @var int
18 *
19 * @ORM\Column(name="id", type="integer")
20 * @ORM\Id
21 * @ORM\GeneratedValue(strategy="AUTO")
22 */
23 private $id;
24
25 /**
26 * @var Account
27 *
28 * @ORM\ManyToOne(targetEntity="Wallabag\FederationBundle\Entity\Account")
29 */
30 private $userOrigin;
31
32 /**
33 * @var Account
34 *
35 * @ORM\ManyToOne(targetEntity="Wallabag\FederationBundle\Entity\Account")
36 */
37 private $userDestination;
38
39 /**
40 * @var Entry
41 *
42 * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Entry")
43 */
44 private $entry;
45
46 /**
47 * @var boolean
48 *
49 * @ORM\Column(name="accepted", type="boolean")
50 */
51 private $accepted;
52
53 /**
54 * Share constructor.
55 */
56 public function __construct()
57 {
58 $this->accepted = false;
59 }
60
61 /**
62 * @return int
63 */
64 public function getId()
65 {
66 return $this->id;
67 }
68
69 /**
70 * @return Account
71 */
72 public function getUserOrigin()
73 {
74 return $this->userOrigin;
75 }
76
77 /**
78 * @param User $userOrigin
79 * @return Share
80 */
81 public function setUserOrigin(User $userOrigin)
82 {
83 $this->userOrigin = $userOrigin;
84 return $this;
85 }
86
87 /**
88 * @return Account
89 */
90 public function getUserDestination()
91 {
92 return $this->userDestination;
93 }
94
95 /**
96 * @param User $userDestination
97 * @return Share
98 */
99 public function setUserDestination(User $userDestination)
100 {
101 $this->userDestination = $userDestination;
102 return $this;
103 }
104
105 /**
106 * @return bool
107 */
108 public function isAccepted()
109 {
110 return $this->accepted;
111 }
112
113 /**
114 * @param bool $accepted
115 * @return Share
116 */
117 public function setAccepted($accepted)
118 {
119 $this->accepted = $accepted;
120 return $this;
121 }
122
123 /**
124 * @return Entry
125 */
126 public function getEntry()
127 {
128 return $this->entry;
129 }
130
131 /**
132 * @param Entry $entry
133 * @return Share
134 */
135 public function setEntry(Entry $entry)
136 {
137 $this->entry = $entry;
138 return $this;
139 }
140}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationCreatedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationCreatedEvent.php
new file mode 100644
index 00000000..b3667703
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationCreatedEvent.php
@@ -0,0 +1,8 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Annotation;
4
5class AnnotationCreatedEvent extends AnnotationEvent
6{
7 const NAME = 'annotation.created';
8}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationDeletedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationDeletedEvent.php
new file mode 100644
index 00000000..60d53849
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationDeletedEvent.php
@@ -0,0 +1,8 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Annotation;
4
5class AnnotationDeletedEvent extends AnnotationEvent
6{
7 const NAME = 'annotation.deleted';
8}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEditedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEditedEvent.php
new file mode 100644
index 00000000..385b8025
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEditedEvent.php
@@ -0,0 +1,8 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Annotation;
4
5class AnnotationEditedEvent extends AnnotationEvent
6{
7 const NAME = 'annotation.edited';
8}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEvent.php
new file mode 100644
index 00000000..b4cb93af
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Annotation/AnnotationEvent.php
@@ -0,0 +1,39 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Annotation;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\AnnotationBundle\Entity\Annotation;
7
8/**
9 * This event is fired when annotation-relative stuff is made.
10 */
11abstract class AnnotationEvent extends Event
12{
13 protected $annotation;
14
15 /**
16 * AnnotationEvent constructor.
17 * @param Annotation $annotation
18 */
19 public function __construct(Annotation $annotation)
20 {
21 $this->annotation = $annotation;
22 }
23
24 /**
25 * @return Annotation
26 */
27 public function getAnnotation()
28 {
29 return $this->annotation;
30 }
31
32 /**
33 * @param Annotation $annotation
34 */
35 public function setAnnotation(Annotation $annotation)
36 {
37 $this->annotation = $annotation;
38 }
39}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryDeletedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryDeletedEvent.php
new file mode 100644
index 00000000..1d413d41
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryDeletedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5/**
6 * This event is fired as soon as an entry is deleted.
7 */
8class EntryDeletedEvent extends EntryEvent
9{
10 const NAME = 'entry.deleted';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEditedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEditedEvent.php
new file mode 100644
index 00000000..f7528bb4
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEditedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5/**
6 * This event is fired as soon as an entry was edited.
7 */
8class EntryEditedEvent extends EntryEvent
9{
10 const NAME = 'entry.edited';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEvent.php
new file mode 100644
index 00000000..0e0c90d0
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryEvent.php
@@ -0,0 +1,41 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired when entry-related stuff is made.
10 */
11abstract class EntryEvent extends Event
12{
13 protected $entry;
14
15 /**
16 * EntryEvent constructor.
17 * @param Entry $entry
18 */
19 public function __construct(Entry $entry)
20 {
21 $this->entry = $entry;
22 }
23
24 /**
25 * @return Entry
26 */
27 public function getEntry()
28 {
29 return $this->entry;
30 }
31
32 /**
33 * @param Entry $entry
34 * @return EntryEvent
35 */
36 public function setEntry(Entry $entry)
37 {
38 $this->entry = $entry;
39 return $this;
40 }
41}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryFavouriteEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryFavouriteEvent.php
new file mode 100644
index 00000000..98edb00d
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryFavouriteEvent.php
@@ -0,0 +1,14 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry was favourited.
10 */
11class EntryFavouriteEvent extends EntryEvent
12{
13 const NAME = 'entry.favourite';
14}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryReadEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryReadEvent.php
new file mode 100644
index 00000000..be6e6b40
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryReadEvent.php
@@ -0,0 +1,14 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry was favourited.
10 */
11class EntryReadEvent extends EntryEvent
12{
13 const NAME = 'entry.read';
14}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntrySavedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntrySavedEvent.php
new file mode 100644
index 00000000..20c623c5
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntrySavedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5/**
6 * This event is fired as soon as an entry was saved.
7 */
8class EntrySavedEvent extends EntryEvent
9{
10 const NAME = 'entry.saved';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryTaggedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryTaggedEvent.php
new file mode 100644
index 00000000..1ea8a7f1
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Entry/EntryTaggedEvent.php
@@ -0,0 +1,55 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Entry;
4
5use Wallabag\CoreBundle\Entity\Entry;
6use Wallabag\CoreBundle\Entity\Tag;
7
8/**
9 * This event is fired as soon as a tag is added on an entry.
10 */
11class EntryTaggedEvent extends EntryEvent
12{
13 const NAME = 'entry.tagged';
14
15 /** @var Tag[] */
16 protected $tags;
17
18 /**
19 * @var boolean
20 */
21 protected $remove;
22
23 /**
24 * EntryTaggedEvent constructor.
25 * @param Entry $entry
26 * @param $tags
27 * @param bool $remove
28 */
29 public function __construct(Entry $entry, $tags, $remove = false)
30 {
31 parent::__construct($entry);
32
33 if (false === is_array($tags)) {
34 $tags = [$tags];
35 }
36
37 $this->tags = $tags;
38 }
39
40 /**
41 * @return Tag[]
42 */
43 public function getTags()
44 {
45 return $this->tags;
46 }
47
48 /**
49 * @return bool
50 */
51 public function isRemove()
52 {
53 return $this->remove;
54 }
55}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FederationEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FederationEvent.php
new file mode 100644
index 00000000..da18330e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FederationEvent.php
@@ -0,0 +1,40 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Federation;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\FederationBundle\Entity\Account;
7
8abstract class FederationEvent extends Event
9{
10 protected $account;
11
12 /**
13 * FederationEvent constructor.
14 * @param Account $account
15 */
16 public function __construct(Account $account)
17 {
18 $this->account = $account;
19 }
20
21 /**
22 * @return Account
23 */
24 public function getAccount()
25 {
26 return $this->account;
27 }
28
29 /**
30 * @param Account $account
31 * @return FederationEvent
32 */
33 public function setAccount(Account $account)
34 {
35 $this->account = $account;
36 return $this;
37 }
38
39
40}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FollowEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FollowEvent.php
new file mode 100644
index 00000000..4004932e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/FollowEvent.php
@@ -0,0 +1,39 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Federation;
4
5use Wallabag\FederationBundle\Entity\Account;
6
7/**
8 * This event is fired as soon as an account was followed.
9 */
10class FollowEvent extends FederationEvent
11{
12 const NAME = 'federation.follow';
13
14 protected $follower;
15
16 public function __construct(Account $accountFollowed, Account $follower)
17 {
18 parent::__construct($accountFollowed);
19 $this->follower = $follower;
20 }
21
22 /**
23 * @return Account
24 */
25 public function getFollower()
26 {
27 return $this->follower;
28 }
29
30 /**
31 * @param Account $follower
32 * @return FollowEvent
33 */
34 public function setFollower(Account $follower)
35 {
36 $this->follower = $follower;
37 return $this;
38 }
39}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/RecommendedEntryEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/RecommendedEntryEvent.php
new file mode 100644
index 00000000..998b56d5
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/RecommendedEntryEvent.php
@@ -0,0 +1,43 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Federation;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry was recommended.
10 */
11class RecommendedEntryEvent extends Event
12{
13 const NAME = 'federation.recommend';
14
15 protected $entry;
16
17 /**
18 * FederationEvent constructor.
19 * @param Entry $entry
20 */
21 public function __construct(Entry $entry)
22 {
23 $this->entry = $entry;
24 }
25
26 /**
27 * @return Entry
28 */
29 public function getEntry()
30 {
31 return $this->entry;
32 }
33
34 /**
35 * @param Entry $entry
36 * @return RecommendedEntryEvent
37 */
38 public function setEntry(Entry $entry)
39 {
40 $this->entry = $entry;
41 return $this;
42 }
43}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/UnfollowEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/UnfollowEvent.php
new file mode 100644
index 00000000..bf9a35f8
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Federation/UnfollowEvent.php
@@ -0,0 +1,39 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Federation;
4
5use Wallabag\FederationBundle\Entity\Account;
6
7/**
8 * This event is fired as soon as an account is being unfollowed
9 */
10class UnfollowEvent extends FederationEvent
11{
12 const NAME = 'federation.unfollow';
13
14 protected $follower;
15
16 public function __construct(Account $accountFollowed, Account $follower)
17 {
18 parent::__construct($accountFollowed);
19 $this->follower = $follower;
20 }
21
22 /**
23 * @return Account
24 */
25 public function getFollower()
26 {
27 return $this->follower;
28 }
29
30 /**
31 * @param Account $follower
32 * @return UnfollowEvent
33 */
34 public function setFollower(Account $follower)
35 {
36 $this->follower = $follower;
37 return $this;
38 }
39}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareAcceptedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareAcceptedEvent.php
new file mode 100644
index 00000000..e171ef04
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareAcceptedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Share;
4
5/**
6 * This event is fired as soon as an share is accepted
7 */
8class ShareAcceptedEvent extends ShareEvent
9{
10 const NAME = 'share.accepted';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCancelledEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCancelledEvent.php
new file mode 100644
index 00000000..26bee896
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCancelledEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Share;
4
5/**
6 * This event is fired as soon as an share is cancelled
7 */
8class ShareCancelledEvent extends ShareEvent
9{
10 const NAME = 'share.cancelled';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCreatedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCreatedEvent.php
new file mode 100644
index 00000000..c2cb72d8
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareCreatedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Share;
4
5/**
6 * This event is fired as soon as a share is created.
7 */
8class ShareCreatedEvent extends ShareEvent
9{
10 const NAME = 'share.created';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareDeniedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareDeniedEvent.php
new file mode 100644
index 00000000..fcdfd1ce
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareDeniedEvent.php
@@ -0,0 +1,11 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Share;
4
5/**
6 * This event is fired as soon as an share is denied
7 */
8class ShareDeniedEvent extends ShareEvent
9{
10 const NAME = 'share.denied';
11}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareEvent.php
new file mode 100644
index 00000000..0022a39f
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/Share/ShareEvent.php
@@ -0,0 +1,39 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\Share;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Share;
7
8/**
9 * This event is fired when share-related stuff is made.
10 */
11abstract class ShareEvent extends Event
12{
13 protected $share;
14
15 /**
16 * ShareEvent constructor.
17 * @param Share $share
18 */
19 public function __construct(Share $share)
20 {
21 $this->share = $share;
22 }
23
24 /**
25 * @return Share
26 */
27 public function getShare()
28 {
29 return $this->share;
30 }
31
32 /**
33 * @param Share $share
34 */
35 public function setShare(Share $share)
36 {
37 $this->share = $share;
38 }
39}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserDeletedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserDeletedEvent.php
new file mode 100644
index 00000000..df06db8c
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserDeletedEvent.php
@@ -0,0 +1,8 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\User;
4
5class UserDeletedEvent extends UserEvent
6{
7 const NAME = 'user.deleted';
8}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEditedEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEditedEvent.php
new file mode 100644
index 00000000..27f8f2d5
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEditedEvent.php
@@ -0,0 +1,8 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\User;
4
5class UserEditedEvent extends UserEvent
6{
7 const NAME = 'user.edited';
8}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEvent.php b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEvent.php
new file mode 100644
index 00000000..e3807abf
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/Actions/User/UserEvent.php
@@ -0,0 +1,41 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity\Actions\User;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\UserBundle\Entity\User;
7
8/**
9 * This event is fired when user-related stuff is made.
10 */
11abstract class UserEvent extends Event
12{
13 protected $user;
14
15 /**
16 * UserEvent constructor.
17 * @param User $user
18 */
19 public function __construct(User $user)
20 {
21 $this->user = $user;
22 }
23
24 /**
25 * @return User
26 */
27 public function getUser()
28 {
29 return $this->user;
30 }
31
32 /**
33 * @param User $user
34 * @return UserEvent
35 */
36 public function setUser(User $user)
37 {
38 $this->user = $user;
39 return $this;
40 }
41}
diff --git a/src/Wallabag/CoreBundle/Event/Activity/ActivitySubscriber.php b/src/Wallabag/CoreBundle/Event/Activity/ActivitySubscriber.php
new file mode 100644
index 00000000..81379ff2
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Activity/ActivitySubscriber.php
@@ -0,0 +1,224 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Activity;
4
5use Doctrine\ORM\EntityManager;
6use FOS\UserBundle\Event\UserEvent;
7use FOS\UserBundle\FOSUserEvents;
8use Psr\Log\LoggerInterface;
9use Symfony\Component\EventDispatcher\Event;
10use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11use Wallabag\CoreBundle\Entity\Activity;
12use Wallabag\CoreBundle\Event\Activity\Actions\Annotation\AnnotationCreatedEvent;
13use Wallabag\CoreBundle\Event\Activity\Actions\Annotation\AnnotationDeletedEvent;
14use Wallabag\CoreBundle\Event\Activity\Actions\Annotation\AnnotationEditedEvent;
15use Wallabag\CoreBundle\Event\Activity\Actions\Annotation\AnnotationEvent;
16use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryDeletedEvent;
17use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryEditedEvent;
18use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryEvent;
19use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryFavouriteEvent;
20use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryReadEvent;
21use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntrySavedEvent;
22use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryTaggedEvent;
23use Wallabag\CoreBundle\Event\Activity\Actions\Federation\FollowEvent;
24use Wallabag\CoreBundle\Event\Activity\Actions\Federation\RecommendedEntryEvent;
25use Wallabag\CoreBundle\Event\Activity\Actions\Federation\UnfollowEvent;
26use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareAcceptedEvent;
27use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareCancelledEvent;
28use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareCreatedEvent;
29use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareDeniedEvent;
30use Wallabag\CoreBundle\Event\Activity\Actions\Share\ShareEvent;
31use Wallabag\CoreBundle\Event\Activity\Actions\User\UserDeletedEvent;
32use Wallabag\CoreBundle\Event\Activity\Actions\User\UserEditedEvent;
33use Wallabag\CoreBundle\Notifications\ActionInterface;
34
35/**
36 * This listener will create the associated configuration when a user register.
37 * This configuration will be created right after the registration (no matter if it needs an email validation).
38 */
39class ActivitySubscriber implements EventSubscriberInterface
40{
41
42 /**
43 * @var EntityManager
44 */
45 private $em;
46
47 /**
48 * @var LoggerInterface $logger
49 */
50 private $logger;
51
52 public function __construct(EntityManager $em, LoggerInterface $logger)
53 {
54 $this->em = $em;
55 $this->logger = $logger;
56 }
57
58 public static function getSubscribedEvents()
59 {
60 return [
61 EntrySavedEvent::NAME => 'entryActivity',
62 EntryDeletedEvent::NAME => 'entryActivity',
63 EntryEditedEvent::NAME => 'entryActivity',
64 EntryTaggedEvent::NAME => 'taggedEntry',
65 EntryFavouriteEvent::NAME => 'entryActivity',
66 EntryReadEvent::NAME => 'entryActivity',
67
68 AnnotationCreatedEvent::NAME => 'annotationActivity',
69 AnnotationEditedEvent::NAME => 'annotationActivity',
70 AnnotationDeletedEvent::NAME => 'annotationActivity',
71
72 FollowEvent::NAME => 'followedAccount',
73 UnfollowEvent::NAME => 'unfollowedAccount',
74 RecommendedEntryEvent::NAME => 'recommendedEntry',
75
76 ShareCreatedEvent::NAME => 'shareActivity',
77 ShareAcceptedEvent::NAME => 'shareActivity',
78 ShareDeniedEvent::NAME => 'shareActivity',
79 ShareCancelledEvent::NAME => 'shareActivity',
80
81 // when a user register using the normal form
82 FOSUserEvents::REGISTRATION_COMPLETED => 'userActivity',
83 // when we manually create a user using the command line
84 // OR when we create it from the config UI
85 FOSUserEvents::USER_CREATED => 'userActivity',
86 UserEditedEvent::NAME => 'userActivity',
87 UserDeletedEvent::NAME => 'userActivity',
88 ];
89 }
90
91 public function userActivity(Event $event)
92 {
93 $activityType = 0;
94 if ($event instanceof UserEvent) {
95 $activityType = Activity::USER_CREATE;
96 } elseif ($event instanceof UserEditedEvent) {
97 $activityType = Activity::USER_EDIT;
98 } elseif ($event instanceof UserDeletedEvent) {
99 $activityType = Activity::USER_REMOVE;
100 }
101
102 $user = $event->getUser();
103 $activity = new Activity($activityType, Activity::USER_OBJECT, $user->getId());
104 $activity->setUser($user->getAccount());
105 $this->em->persist($activity);
106 $this->em->flush();
107 }
108
109 public function entryActivity(EntryEvent $event)
110 {
111 $entry = $event->getEntry();
112
113 $activityType = 0;
114 if ($event instanceof EntrySavedEvent) {
115 $activityType = Activity::ENTRY_ADD;
116 } elseif ($event instanceof EntryDeletedEvent) {
117 $activityType = Activity::ENTRY_DELETE;
118 } elseif ($event instanceof EntryEditedEvent) {
119 $activityType = Activity::ENTRY_EDIT;
120 } elseif ($event instanceof EntryFavouriteEvent) {
121 if ($entry->isStarred()) {
122 $activityType = Activity::ENTRY_FAVOURITE;
123 } else {
124 $activityType = Activity::ENTRY_UNFAVOURITE;
125 }
126 } elseif ($event instanceof EntryReadEvent) {
127 if ($entry->isArchived()) {
128 $activityType = Activity::ENTRY_READ;
129 } else {
130 $activityType = Activity::ENTRY_UNREAD;
131 }
132 }
133
134 $activity = new Activity($activityType, Activity::ENTRY_OBJECT, $entry->getId());
135 $activity->setUser($entry->getUser()->getAccount());
136 $this->em->persist($activity);
137 $this->em->flush();
138 }
139
140 public function taggedEntry(EntryTaggedEvent $event)
141 {
142 $entry = $event->getEntry();
143 $activity = new Activity($event->isRemove() ? Activity::ENTRY_REMOVE_TAG : Activity::ENTRY_ADD_TAG, Activity::ENTRY_OBJECT, $entry->getId());
144 $activity->setUser($entry->getUser()->getAccount());
145 $activity->setSecondaryObjectType(Activity::TAG_OBJECT)
146 ->setSecondaryObjectId($event->getTags()[0]->getId());
147 $this->em->persist($activity);
148 $this->em->flush();
149 }
150
151 public function annotationActivity(AnnotationEvent $event)
152 {
153 $annotation = $event->getAnnotation();
154
155 $activityType = 0;
156 if ($event instanceof AnnotationCreatedEvent) {
157 $activityType = Activity::ANNOTATION_ADD;
158 } elseif ($event instanceof AnnotationEditedEvent) {
159 $activityType = Activity::ANNOTATION_EDIT;
160 } elseif ($event instanceof AnnotationDeletedEvent) {
161 $activityType = Activity::ANNOTATION_REMOVE;
162 }
163
164 $activity = new Activity($activityType, Activity::ANNOTATION_OBJECT, $annotation->getId());
165 $activity->setUser($annotation->getUser()->getAccount());
166 $this->em->persist($activity);
167 $this->em->flush();
168 }
169
170 public function followedAccount(FollowEvent $event)
171 {
172 $activity = new Activity(Activity::FOLLOW_ACCOUNT, Activity::ACCOUNT_OBJECT, $event->getAccount()->getId());
173 $activity->setUser($event->getAccount());
174 $activity->setSecondaryObjectType(Activity::ACCOUNT_OBJECT)
175 ->setSecondaryObjectId($event->getFollower()->getId());
176 $this->em->persist($activity);
177 $this->em->flush();
178 }
179
180 public function unfollowedAccount(UnfollowEvent $event)
181 {
182 $activity = new Activity(Activity::UNFOLLOW_ACCOUNT, Activity::ACCOUNT_OBJECT, $event->getAccount()->getId());
183 $activity->setUser($event->getAccount());
184 $activity->setSecondaryObjectType(Activity::ACCOUNT_OBJECT)
185 ->setSecondaryObjectId($event->getFollower()->getId());
186 $this->em->persist($activity);
187 $this->em->flush();
188 }
189
190 public function recommendedEntry(RecommendedEntryEvent $event)
191 {
192 $entry = $event->getEntry();
193 $account = $entry->getUser()->getAccount();
194 $activity = new Activity(Activity::RECOMMEND_ENTRY, Activity::ACCOUNT_OBJECT, $account->getId());
195 $activity->setUser($account);
196 $activity->setSecondaryObjectType(Activity::ENTRY_OBJECT)
197 ->setSecondaryObjectId($entry->getId());
198 $this->em->persist($activity);
199 $this->em->flush();
200 }
201
202 public function shareActivity(ShareEvent $event)
203 {
204 $share = $event->getShare();
205
206 $activityType = 0;
207 if ($event instanceof ShareCreatedEvent) {
208 $activityType = Activity::USER_SHARE_CREATED;
209 } elseif ($event instanceof ShareAcceptedEvent) {
210 $activityType = Activity::USER_SHARE_ACCEPTED;
211 } elseif ($event instanceof ShareDeniedEvent) {
212 $activityType = Activity::USER_SHARE_REFUSED;
213 } elseif ($event instanceof ShareCancelledEvent) {
214 $activityType = Activity::USER_SHARE_CANCELLED;
215 }
216
217 $activity = new Activity($activityType, Activity::SHARE_OBJECT, $share->getId());
218 $activity->setUser($share->getUserOrigin());
219 $activity->setSecondaryObjectType(Activity::ACCOUNT_OBJECT)
220 ->setSecondaryObjectId($share->getUserDestination()->getId());
221 $this->em->persist($activity);
222 $this->em->flush();
223 }
224}
diff --git a/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php b/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php
deleted file mode 100644
index e9061d04..00000000
--- a/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php
+++ /dev/null
@@ -1,26 +0,0 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry is deleted.
10 */
11class EntryDeletedEvent extends Event
12{
13 const NAME = 'entry.deleted';
14
15 protected $entry;
16
17 public function __construct(Entry $entry)
18 {
19 $this->entry = $entry;
20 }
21
22 public function getEntry()
23 {
24 return $this->entry;
25 }
26}
diff --git a/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php b/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php
deleted file mode 100644
index 5fdb5221..00000000
--- a/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php
+++ /dev/null
@@ -1,26 +0,0 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry was saved.
10 */
11class EntrySavedEvent extends Event
12{
13 const NAME = 'entry.saved';
14
15 protected $entry;
16
17 public function __construct(Entry $entry)
18 {
19 $this->entry = $entry;
20 }
21
22 public function getEntry()
23 {
24 return $this->entry;
25 }
26}
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php
index 4ebe837b..5c3550c2 100644
--- a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php
+++ b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php
@@ -4,10 +4,10 @@ namespace Wallabag\CoreBundle\Event\Subscriber;
4 4
5use Symfony\Component\EventDispatcher\EventSubscriberInterface; 5use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6use Psr\Log\LoggerInterface; 6use Psr\Log\LoggerInterface;
7use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntryDeletedEvent;
8use Wallabag\CoreBundle\Event\Activity\Actions\Entry\EntrySavedEvent;
7use Wallabag\CoreBundle\Helper\DownloadImages; 9use Wallabag\CoreBundle\Helper\DownloadImages;
8use Wallabag\CoreBundle\Entity\Entry; 10use Wallabag\CoreBundle\Entity\Entry;
9use Wallabag\CoreBundle\Event\EntrySavedEvent;
10use Wallabag\CoreBundle\Event\EntryDeletedEvent;
11use Doctrine\ORM\EntityManager; 11use Doctrine\ORM\EntityManager;
12 12
13class DownloadImagesSubscriber implements EventSubscriberInterface 13class DownloadImagesSubscriber implements EventSubscriberInterface
diff --git a/src/Wallabag/CoreBundle/Repository/ChangeRepository.php b/src/Wallabag/CoreBundle/Repository/ChangeRepository.php
new file mode 100644
index 00000000..18d015a7
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Repository/ChangeRepository.php
@@ -0,0 +1,26 @@
1<?php
2
3namespace Wallabag\CoreBundle\Repository;
4
5use Doctrine\ORM\EntityRepository;
6
7class ChangeRepository extends EntityRepository
8{
9 /**
10 * Used only in test case to get a tag for our entry.
11 *
12 * @param int $timestamp
13 *
14 * @return Tag
15 */
16 public function findChangesSinceDate($timestamp)
17 {
18 $date = new \DateTime();
19 $date->setTimestamp($timestamp);
20
21 return $this->createQueryBuilder('c')
22 ->where('c.createdAt >= :timestamp')->setParameter('timestamp', $date)
23 ->getQuery()
24 ->getResult();
25 }
26}
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index 9bda4e15..4bbd05ff 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -4,6 +4,7 @@ namespace Wallabag\CoreBundle\Repository;
4 4
5use Doctrine\ORM\EntityRepository; 5use Doctrine\ORM\EntityRepository;
6use Doctrine\ORM\Query; 6use Doctrine\ORM\Query;
7use Doctrine\ORM\QueryBuilder;
7use Pagerfanta\Adapter\DoctrineORMAdapter; 8use Pagerfanta\Adapter\DoctrineORMAdapter;
8use Pagerfanta\Pagerfanta; 9use Pagerfanta\Pagerfanta;
9use Wallabag\CoreBundle\Entity\Tag; 10use Wallabag\CoreBundle\Entity\Tag;
@@ -89,7 +90,7 @@ class EntryRepository extends EntityRepository
89 * 90 *
90 * @param int $userId 91 * @param int $userId
91 * @param string $term 92 * @param string $term
92 * @param strint $currentRoute 93 * @param string $currentRoute
93 * 94 *
94 * @return QueryBuilder 95 * @return QueryBuilder
95 */ 96 */
@@ -414,4 +415,15 @@ class EntryRepository extends EntityRepository
414 ->getQuery() 415 ->getQuery()
415 ->getResult(); 416 ->getResult();
416 } 417 }
418
419 /**
420 * @param $userId
421 * @return QueryBuilder
422 */
423 public function getBuilderForRecommendationsByUser($userId)
424 {
425 return $this->getBuilderByUser($userId)
426 ->andWhere('e.recommended = true')
427 ;
428 }
417} 429}
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index 183b6690..6864993c 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -222,3 +222,11 @@ services:
222 arguments: 222 arguments:
223 - "%wallabag_core.site_credentials.encryption_key_path%" 223 - "%wallabag_core.site_credentials.encryption_key_path%"
224 - "@logger" 224 - "@logger"
225
226 wallabag_core.activity.subscriber:
227 class: Wallabag\CoreBundle\Event\Activity\ActivitySubscriber
228 arguments:
229 - "@doctrine.orm.default_entity_manager"
230 - "@logger"
231 tags:
232 - { name: kernel.event_subscriber }
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index 98f1b48c..4f19556f 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -20,7 +20,7 @@ menu:
20 starred: 'Starred' 20 starred: 'Starred'
21 archive: 'Archive' 21 archive: 'Archive'
22 all_articles: 'All entries' 22 all_articles: 'All entries'
23 config: 'Config' 23 config: 'config'
24 tags: 'Tags' 24 tags: 'Tags'
25 internal_settings: 'Internal Settings' 25 internal_settings: 'Internal Settings'
26 import: 'Import' 26 import: 'Import'
@@ -51,7 +51,7 @@ footer:
51 stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day! 51 stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day!
52 52
53config: 53config:
54 page_title: 'Config' 54 page_title: 'config'
55 tab_menu: 55 tab_menu:
56 settings: 'Settings' 56 settings: 'Settings'
57 rss: 'RSS' 57 rss: 'RSS'
@@ -108,6 +108,11 @@ config:
108 description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out. 108 description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
109 confirm: Are you really sure? (THIS CAN'T BE UNDONE) 109 confirm: Are you really sure? (THIS CAN'T BE UNDONE)
110 button: Delete my account 110 button: Delete my account
111 form_account:
112 title: "Profile"
113 description_label: "Description de votre compte. Ce texte sera affiché sur votre page de profil."
114 avatar_label: "Avatar"
115 banner_label: "Bannière"
111 reset: 116 reset:
112 title: Reset area (a.k.a danger zone) 117 title: Reset area (a.k.a danger zone)
113 description: By hitting buttons below you'll have ability to remove some information from your account. Be aware that these actions are IRREVERSIBLE. 118 description: By hitting buttons below you'll have ability to remove some information from your account. Be aware that these actions are IRREVERSIBLE.
@@ -562,7 +567,7 @@ error:
562flashes: 567flashes:
563 config: 568 config:
564 notice: 569 notice:
565 config_saved: 'Config saved.' 570 config_saved: 'config saved.'
566 password_updated: 'Password updated' 571 password_updated: 'Password updated'
567 password_not_updated_demo: "In demonstration mode, you can't change password for this user." 572 password_not_updated_demo: "In demonstration mode, you can't change password for this user."
568 user_updated: 'Information updated' 573 user_updated: 'Information updated'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index 277f2f63..2c53c12b 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -108,6 +108,11 @@ config:
108 description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté." 108 description: "Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c’est IRRÉVERSIBLE). Vous serez ensuite déconnecté."
109 confirm: "Vous êtes vraiment sûr ? (C’EST IRRÉVERSIBLE)" 109 confirm: "Vous êtes vraiment sûr ? (C’EST IRRÉVERSIBLE)"
110 button: "Supprimer mon compte" 110 button: "Supprimer mon compte"
111 form_account:
112 title: "Profil"
113 description_label: "Description de votre compte. Ce texte sera affiché sur votre page de profil."
114 avatar_label: "Avatar"
115 banner_label: "Bannière"
111 reset: 116 reset:
112 title: "Réinitialisation (attention danger !)" 117 title: "Réinitialisation (attention danger !)"
113 description: "En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES !" 118 description: "En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES !"
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
index 2d71cb9d..b77bfd7f 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
@@ -51,7 +51,7 @@ footer:
51 stats: 'Desde %user_creation% você leu %nb_archives% artigos. Isso é %per_day% por dia!' 51 stats: 'Desde %user_creation% você leu %nb_archives% artigos. Isso é %per_day% por dia!'
52 52
53config: 53config:
54 page_title: 'Config' 54 page_title: 'config'
55 tab_menu: 55 tab_menu:
56 settings: 'Configurações' 56 settings: 'Configurações'
57 rss: 'RSS' 57 rss: 'RSS'
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 bd5932b0..c2beb35a 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
@@ -220,6 +220,51 @@
220 </form> 220 </form>
221 221
222 <br /><hr /><br /> 222 <br /><hr /><br />
223 <h5>{{ 'config.form_account.title'|trans }}</h5>
224
225 {{ form_start(form.account) }}
226 {{ form_errors(form.account) }}
227
228 <div class="row">
229 <div class="input-field col s12">
230 {{ form_errors(form.account.description) }}
231 {{ form_widget(form.account.description, {'attr': {'class': 'materialize-textarea'}}) }}
232 {{ form_label(form.account.description) }}
233 </div>
234 </div>
235
236 <div class="row">
237 <div class="file-field input-field col s12">
238 {{ form_errors(form.account.avatar) }}
239 <div class="btn">
240 <span>{{ 'config.form_account.avatar_label'|trans }}</span>
241 {{ form_widget(form.account.avatar) }}
242 </div>
243 <div class="file-path-wrapper">
244 <input class="file-path validate" type="text">
245 </div>
246 </div>
247 </div>
248
249 <div class="row">
250 <div class="file-field input-field col s12">
251 {{ form_errors(form.account.banner) }}
252 <div class="btn">
253 <span>{{ 'config.form_account.banner_label'|trans }}</span>
254 {{ form_widget(form.account.banner) }}
255 </div>
256 <div class="file-path-wrapper">
257 <input class="file-path validate" type="text">
258 </div>
259 </div>
260 </div>
261
262 {{ form_widget(form.account.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
263 <a href="{{ path('user-profile', {'user': app.user.account.username}) }}" class="btn">{{ 'config.form_account.view_profile' | trans }}</a>
264 {{ form_widget(form.account._token) }}
265 </form>
266
267 <br /><hr /><br />
223 268
224 <div class="row"> 269 <div class="row">
225 <h5>{{ 'config.reset.title'|trans }}</h5> 270 <h5>{{ 'config.reset.title'|trans }}</h5>
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 ccc44931..f93b635f 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -117,6 +117,11 @@
117 {% if unreadNotifs > 0 %}<span id="notifications-count" class="red-text text-accent-2">{{ unreadNotifs }}</span>{% endif %} 117 {% if unreadNotifs > 0 %}<span id="notifications-count" class="red-text text-accent-2">{{ unreadNotifs }}</span>{% endif %}
118 </a> 118 </a>
119 </li> 119 </li>
120 <li id="button_profile">
121 <a class="nav-panel-menu button-collapse-right tooltipped" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.profile' | trans }}" href="{{ path('user-profile', {'user': app.user.account.username}) }}">
122 <i class="material-icons">person</i>
123 </a>
124 </li>
120 <li id="button_filters"> 125 <li id="button_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"> 126 <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">
122 <i class="material-icons">filter_list</i> 127 <i class="material-icons">filter_list</i>