aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorThomas Citharel <tcit@tcit.fr>2017-04-27 19:17:19 +0200
committerThomas Citharel <tcit@tcit.fr>2017-06-23 09:27:23 +0200
commit5847dd3572caf06c0e0d5e307241c3b6bc3f8611 (patch)
tree8905d4de388dd18239ea323f4650ff0070064eab
parent2585953e0dae631b65c59b0e31196d65bdde84df (diff)
downloadwallabag-5847dd3572caf06c0e0d5e307241c3b6bc3f8611.tar.gz
wallabag-5847dd3572caf06c0e0d5e307241c3b6bc3f8611.tar.zst
wallabag-5847dd3572caf06c0e0d5e307241c3b6bc3f8611.zip
MOAR WIP
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php89
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php2
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php18
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/EditGroupSharesType.php43
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php13
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml26
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml27
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_share_groups.html.twig24
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig11
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig6
-rw-r--r--src/Wallabag/GroupBundle/Controller/ManageController.php184
-rw-r--r--src/Wallabag/GroupBundle/Form/UserGroupType.php6
-rw-r--r--src/Wallabag/GroupBundle/Resources/config/services.yml7
-rw-r--r--src/Wallabag/GroupBundle/Resources/views/Manage/edit_user.html.twig26
-rw-r--r--src/Wallabag/GroupBundle/Resources/views/Manage/index.html.twig29
-rw-r--r--src/Wallabag/GroupBundle/Resources/views/Manage/manage.html.twig102
-rw-r--r--src/Wallabag/GroupBundle/Resources/views/Manage/requests.html.twig31
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php9
-rw-r--r--src/Wallabag/UserBundle/Repository/UserRepository.php10
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig2
20 files changed, 651 insertions, 14 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index fafa49f1..f1376f43 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -4,11 +4,15 @@ namespace Wallabag\CoreBundle\Controller;
4 4
5use Pagerfanta\Adapter\DoctrineORMAdapter; 5use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Pagerfanta\Pagerfanta;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
8use Symfony\Bundle\FrameworkBundle\Controller\Controller; 9use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\RedirectResponse;
9use Symfony\Component\HttpFoundation\Request; 11use Symfony\Component\HttpFoundation\Request;
12use Symfony\Component\HttpFoundation\Response;
10use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 13use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
11use Wallabag\CoreBundle\Entity\Entry; 14use Wallabag\CoreBundle\Entity\Entry;
15use Wallabag\CoreBundle\Form\Type\EditGroupSharesType;
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;
@@ -16,6 +20,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
16use Wallabag\CoreBundle\Event\EntrySavedEvent; 20use Wallabag\CoreBundle\Event\EntrySavedEvent;
17use Wallabag\CoreBundle\Event\EntryDeletedEvent; 21use Wallabag\CoreBundle\Event\EntryDeletedEvent;
18use Wallabag\CoreBundle\Form\Type\SearchEntryType; 22use Wallabag\CoreBundle\Form\Type\SearchEntryType;
23use Wallabag\GroupBundle\Entity\Group;
19 24
20class EntryController extends Controller 25class EntryController extends Controller
21{ 26{
@@ -604,4 +609,88 @@ class EntryController extends Controller
604 { 609 {
605 return $this->showEntries('untagged', $request, $page); 610 return $this->showEntries('untagged', $request, $page);
606 } 611 }
612
613 /**
614 * @Route("/group-articles/{group}/{page}", name="group-presentations", defaults={"page" = "1"}, requirements={"page": "\d+", "group": "\d+"})
615 *
616 * @param Request $request
617 * @param Group $group
618 * @param int $page
619 * @return Response
620 */
621 public function showGroupSharedTemplatesAction(Request $request, Group $group, int $page)
622 {
623 if (!$this->getUser()->inGroup($group)) {
624 throw $this->createAccessDeniedException();
625 }
626
627 $repository = $this->get('wallabag_core.entry_repository');
628
629 /** @var QueryBuilder $entries */
630 $entries = $repository->findByGroup($group->getId());
631
632 $pagerAdapter = new DoctrineORMAdapter($entries->getQuery(), true, false);
633 $pagerFanta = new Pagerfanta($pagerAdapter);
634 $pagerFanta->setMaxPerPage(9);
635
636 $form = $this->createForm(EntryFilterType::class);
637
638 if ($request->query->has($form->getName())) {
639 // manually bind values from the request
640 $form->submit($request->query->get($form->getName()));
641
642 // build the query from the given form object
643 $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $qb);
644 }
645
646 $searchTerm = (isset($request->get('search_entry')['term']) ? $request->get('search_entry')['term'] : '');
647
648 try {
649 $pagerFanta->setCurrentPage($page);
650 } catch (OutOfRangeCurrentPageException $e) {
651 if ($page > 1) {
652 return $this->redirect($this->generateUrl('group-presentations', [
653 'page' => $pagerFanta->getNbPages(),
654 'group' => $group->getId()
655 ]), 302);
656 }
657 }
658
659 return $this->render('WallabagCoreBundle:Entry:entries.html.twig', [
660 'form' => $form->createView(),
661 'entries' => $pagerFanta,
662 'currentPage' => $page,
663 'searchTerm' => $searchTerm,
664 ]);
665 }
666
667 /**
668 *
669 * @Route("/entry/group-shares/{entry}", name="group-shares-entry")
670 *
671 * @param Request $request
672 * @param Entry $entry
673 * @return Response
674 */
675 public function groupShareAction(Request $request, Entry $entry)
676 {
677 $this->checkUserAction($entry);
678
679 $form = $this->createForm(EditGroupSharesType::class, $entry, ['groups' => $this->getUser()->getGroups()]);
680
681 $form->handleRequest($request);
682
683 if ($form->isSubmitted() && $form->isValid()) {
684 $em = $this->getDoctrine()->getManager();
685 $em->persist($entry);
686 $em->flush();
687
688 return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()]));
689 }
690
691 return $this->render('WallabagCoreBundle:Entry:_share_groups.html.twig', [
692 'form' => $form->createView(),
693 'entry' => $entry,
694 ]);
695 }
607} 696}
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php
index fda04cfb..4bb2b706 100644
--- a/src/Wallabag/CoreBundle/Controller/ExportController.php
+++ b/src/Wallabag/CoreBundle/Controller/ExportController.php
@@ -47,7 +47,7 @@ class ExportController extends Controller
47 * 47 *
48 * @Route("/export/{category}.{format}", name="export_entries", requirements={ 48 * @Route("/export/{category}.{format}", name="export_entries", requirements={
49 * "format": "epub|mobi|pdf|json|xml|txt|csv", 49 * "format": "epub|mobi|pdf|json|xml|txt|csv",
50 * "category": "all|unread|starred|archive|tag_entries|untagged|search" 50 * "category": "all|unread|starred|archive|tag_entries|untagged|search|group-presentations"
51 * }) 51 * })
52 * 52 *
53 * @return \Symfony\Component\HttpFoundation\Response 53 * @return \Symfony\Component\HttpFoundation\Response
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index 84555b36..028eeb52 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -235,7 +235,7 @@ class Entry
235 235
236 /** 236 /**
237 * @var ArrayCollection 237 * @var ArrayCollection
238 * @ORM\ManyToMany(targetEntity="Wallabag\GroupBundle\Entity\Group", inversedBy="presentations", cascade={"persist"}) 238 * @ORM\ManyToMany(targetEntity="Wallabag\GroupBundle\Entity\Group", inversedBy="entries", cascade={"persist"})
239 */ 239 */
240 private $groupShares; 240 private $groupShares;
241 241
@@ -784,4 +784,20 @@ class Entry
784 784
785 return $this; 785 return $this;
786 } 786 }
787
788 /**
789 * @return ArrayCollection
790 */
791 public function getGroupShares()
792 {
793 return $this->groupShares;
794 }
795
796 /**
797 * @param ArrayCollection $groupShares
798 */
799 public function setGroupShares($groupShares)
800 {
801 $this->groupShares = $groupShares;
802 }
787} 803}
diff --git a/src/Wallabag/CoreBundle/Form/Type/EditGroupSharesType.php b/src/Wallabag/CoreBundle/Form/Type/EditGroupSharesType.php
new file mode 100644
index 00000000..2c2e3b36
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Form/Type/EditGroupSharesType.php
@@ -0,0 +1,43 @@
1<?php
2
3namespace Wallabag\CoreBundle\Form\Type;
4
5use Symfony\Bridge\Doctrine\Form\Type\EntityType;
6use Symfony\Component\Form\AbstractType;
7use Symfony\Component\Form\Extension\Core\Type\SubmitType;
8use Symfony\Component\Form\FormBuilderInterface;
9use Symfony\Component\OptionsResolver\OptionsResolver;
10use Wallabag\CoreBundle\Entity\Entry;
11use Wallabag\GroupBundle\Entity\Group;
12
13class EditGroupSharesType extends AbstractType
14{
15 public function buildForm(FormBuilderInterface $builder, array $options)
16 {
17 $builder
18 ->add('groupshares', EntityType::class, [
19 'required' => true,
20 'class' => Group::class,
21 'choices' => $options['groups'],
22 'multiple' => true,
23 'expanded' => true,
24 ])
25 ->add('save', SubmitType::class, [
26 'label' => 'Share',
27 ])
28 ;
29 }
30
31 public function configureOptions(OptionsResolver $resolver)
32 {
33 $resolver->setDefaults([
34 'data_class' => Entry::class,
35 ]);
36 $resolver->setRequired('groups');
37 }
38
39 public function getBlockPrefix()
40 {
41 return 'group_shares';
42 }
43}
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index 9bda4e15..ade3d6bc 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -414,4 +414,17 @@ class EntryRepository extends EntityRepository
414 ->getQuery() 414 ->getQuery()
415 ->getResult(); 415 ->getResult();
416 } 416 }
417
418 /**
419 * Find all entries for a group
420 *
421 * @param $groupId
422 * @return \Doctrine\ORM\QueryBuilder
423 */
424 public function findByGroup($groupId)
425 {
426 return $this->createQueryBuilder('p')
427 ->innerJoin('p.groupShares', 'g', 'WITH', 'g.id = :group')
428 ->setParameter(':group', $groupId);
429 }
417} 430}
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index 8f507c40..94bce434 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -224,6 +224,7 @@ entry:
224 delete_public_link: 'delete public link' 224 delete_public_link: 'delete public link'
225 export: 'Export' 225 export: 'Export'
226 print: 'Print' 226 print: 'Print'
227 groups: Groups
227 problem: 228 problem:
228 label: 'Problems?' 229 label: 'Problems?'
229 description: 'Does this article appear wrong?' 230 description: 'Does this article appear wrong?'
@@ -515,6 +516,31 @@ group:
515 delete: Delete 516 delete: Delete
516 delete_confirm: Are you sure? 517 delete_confirm: Are you sure?
517 back_to_list: Back to list 518 back_to_list: Back to list
519 role_label: Default roles
520 access_label: Access
521 password_label: Password (if applicable)
522
523 roles:
524 readonly: Read only
525 write: Write access
526 manage_entries: Managing articles
527 manage_users: Managing members
528 admin: Administrator
529 access:
530 open: Open
531 request: On request
532 password: With password
533 invitation: Upon invitation
534 hidden: Upon invitation and private
535 tab_menu:
536 public: Public groups
537 own: My groups
538 manage:
539 label: Manage this group
540 entries:
541 label: Entries shared with this group
542 leave:
543 label: Leave
518 544
519user: 545user:
520 page_title: Users management 546 page_title: Users management
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index d909cf15..007d5b2a 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -240,6 +240,7 @@ entry:
240 delete_public_link: "Supprimer le lien public" 240 delete_public_link: "Supprimer le lien public"
241 export: "Exporter" 241 export: "Exporter"
242 print: "Imprimer" 242 print: "Imprimer"
243 groups: Groupes
243 problem: 244 problem:
244 label: "Un problème ?" 245 label: "Un problème ?"
245 description: "Est-ce que cet article s’affiche mal ?" 246 description: "Est-ce que cet article s’affiche mal ?"
@@ -549,6 +550,32 @@ group:
549 tab_menu: 550 tab_menu:
550 public: Groupes publics 551 public: Groupes publics
551 own: Mes groupes 552 own: Mes groupes
553 requests:
554 list: Liste des requêtes
555 sent: Requête envoyée
556 username: Utilisateur
557 action: Action
558 manage:
559 label: Gérer le groupe
560 title: Gérer le groupe
561 entries:
562 label: Liste des articles partagés avec ce groupe
563 leave:
564 label: Sortir de ce groupe
565 user:
566 inGroup: "{0}Il n'y a personne dans ce groupe|{1}Vous êtes tout seul dans ce groupe|]1,Inf[Vous êtes %count% utilisateurs dans ce groupe"
567 notInGroup: "{0}Il n'y a personne dans ce groupe|{1}Il y a un seul utilisateur dans ce groupe|]1,Inf[%count% utilisateurs dans ce groupe"
568 members:
569 empty: Le groupe est vide
570 name: Nom d'utilisateur
571 role: Rôle
572 action: Action
573 edit: Modifier les droits de l'utilisateur
574 exclude: Exclure l'utilisateur
575 edit_user:
576 title: Édition des droits de l'utilisateur
577 role: Rôle
578 cancel: Annuler
552 579
553user: 580user:
554 page_title: "Gestion des utilisateurs" 581 page_title: "Gestion des utilisateurs"
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_share_groups.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_share_groups.html.twig
new file mode 100644
index 00000000..5c81ccc2
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/_share_groups.html.twig
@@ -0,0 +1,24 @@
1<!-- Groups Modal -->
2<div id="groups-modal" class="modal bottom-sheet">
3 <div class="modal-content">
4 <div class="row">
5 <h4>Groups</h4>
6 <p>Select the groups you want to share this article with</p>
7 <form name="search" method="POST" action="{{ path('group-shares-entry', {'entry': entry.id})}}">
8 {% if form_errors(form) %}
9 <span class="black-text">{{ form_errors(form) }}</span>
10 {% endif %}
11
12 {% if form_errors(form.groupshares) %}
13 <span class="black-text">{{ form_errors(form.groupshares) }}</span>
14 {% endif %}
15
16 {{ form_widget(form.groupshares) }}
17 {{ form_widget(form.save, {'attr': {'class': 'modal-action modal-close waves-effect waves-light btn'}}) }}
18
19 {{ form_rest(form) }}
20 </form>
21
22 </div>
23 </div>
24</div>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
index 4cff7bf2..05f51aa8 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
@@ -170,6 +170,15 @@
170 </div> 170 </div>
171 </li> 171 </li>
172 172
173 {#{% if craue_setting('groups') %}#}
174 <li class="bold border-bottom hide-on-med-and-down">
175 <a class="waves-effect groups-button" onclick="$('#groups-modal').openModal();" title="{{ 'entry.view.left_menu.group'|trans }}">
176 <i class="material-icons small">group</i>
177 <span>{{ 'entry.view.left_menu.groups'|trans }}</span>
178 </a>
179 </li>
180 {#{% endif %}#}
181
173 {% if craue_setting('show_printlink') %} 182 {% if craue_setting('show_printlink') %}
174 <li class="bold border-bottom hide-on-med-and-down"> 183 <li class="bold border-bottom hide-on-med-and-down">
175 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.print'|trans }}" href="javascript: window.print();"> 184 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.print'|trans }}" href="javascript: window.print();">
@@ -287,6 +296,8 @@
287 </div> 296 </div>
288 </div> 297 </div>
289 298
299 {{ render(controller( "WallabagCoreBundle:Entry:GroupShare", { 'entry': entry.id } )) }}
300
290<script id="annotationroutes" type="application/json"> 301<script id="annotationroutes" type="application/json">
291{ 302{
292 "prefix": "", 303 "prefix": "",
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 575c77f2..92b47dac 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -75,14 +75,14 @@
75 <li class="bold {% if currentRoute starts with 'user_' %}active{% endif %}"> 75 <li class="bold {% if currentRoute starts with 'user_' %}active{% endif %}">
76 <a class="waves-effect" href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a> 76 <a class="waves-effect" href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a>
77 </li> 77 </li>
78 <li class="bold {% if currentRoute starts with 'group_' %}active{% endif %}">
79 <a class="waves-effect" href="{{ path('group_index') }}">{{ 'menu.left.groups_management'|trans }}</a>
80 </li>
81 78
82 <li class="bold border-bottom {% if currentRoute == 'craue_config_settings_modify' %}active{% endif %}"> 79 <li class="bold border-bottom {% if currentRoute == 'craue_config_settings_modify' %}active{% endif %}">
83 <a class="waves-effect" href="{{ path('craue_config_settings_modify') }}">{{ 'menu.left.internal_settings'|trans }}</a> 80 <a class="waves-effect" href="{{ path('craue_config_settings_modify') }}">{{ 'menu.left.internal_settings'|trans }}</a>
84 </li> 81 </li>
85 {% endif %} 82 {% endif %}
83 <li class="bold {% if currentRoute starts with 'group_' %}active{% endif %}">
84 <a class="waves-effect" href="{{ path('group_index') }}">{{ 'menu.left.groups_management'|trans }}</a>
85 </li>
86 <li class="bold {% if currentRoute == 'import' %}active{% endif %}"> 86 <li class="bold {% if currentRoute == 'import' %}active{% endif %}">
87 <a class="waves-effect" href="{{ path('import') }}">{{ 'menu.left.import'|trans }}</a> 87 <a class="waves-effect" href="{{ path('import') }}">{{ 'menu.left.import'|trans }}</a>
88 </li> 88 </li>
diff --git a/src/Wallabag/GroupBundle/Controller/ManageController.php b/src/Wallabag/GroupBundle/Controller/ManageController.php
index 31a0c7b1..7214d899 100644
--- a/src/Wallabag/GroupBundle/Controller/ManageController.php
+++ b/src/Wallabag/GroupBundle/Controller/ManageController.php
@@ -2,6 +2,7 @@
2 2
3namespace Wallabag\GroupBundle\Controller; 3namespace Wallabag\GroupBundle\Controller;
4 4
5use Pagerfanta\Adapter\ArrayAdapter;
5use Pagerfanta\Adapter\DoctrineORMAdapter; 6use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 7use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Pagerfanta\Pagerfanta; 8use Pagerfanta\Pagerfanta;
@@ -15,6 +16,7 @@ use Wallabag\GroupBundle\Entity\Group;
15use Wallabag\GroupBundle\Entity\UserGroup; 16use Wallabag\GroupBundle\Entity\UserGroup;
16use Wallabag\GroupBundle\Form\GroupType; 17use Wallabag\GroupBundle\Form\GroupType;
17use Wallabag\GroupBundle\Form\NewGroupType; 18use Wallabag\GroupBundle\Form\NewGroupType;
19use Wallabag\GroupBundle\Form\UserGroupType;
18use Wallabag\UserBundle\Entity\User; 20use Wallabag\UserBundle\Entity\User;
19 21
20/** 22/**
@@ -210,4 +212,186 @@ class ManageController extends Controller
210 } 212 }
211 throw $this->createAccessDeniedException(); 213 throw $this->createAccessDeniedException();
212 } 214 }
215
216 /**
217 * @Route("/join/{group}", name="group_join")
218 * @param Group $group
219 * @return Response
220 */
221 public function joinGroupAction(Group $group): Response
222 {
223 $em = $this->getDoctrine()->getManager();
224
225 if ($group->getAcceptSystem() === Group::ACCESS_PASSWORD) {
226 return $this->redirectToRoute('group_password', ['group' => $group->getId()]);
227 }
228 $this->getUser()->addAGroup($group, $group->getDefaultRole());
229
230 $em->flush();
231
232 return $this->redirect($this->generateUrl('group_index'), 302);
233 }
234
235 /**
236 * @Route("/manage/{group}/{page}", name="group-manage", defaults={"page" = "1"})
237 * @param Group $group
238 * @return Response
239 */
240 public function manageGroupUsersAction(Group $group, int $page): Response
241 {
242 if ($this->getUser()->getGroupRoleForUser($group) < Group::ROLE_MANAGE_USERS) {
243 $this->createAccessDeniedException();
244 }
245
246 $members = $this->get('wallabag_user.user_repository')->findGroupMembers($group->getId());
247
248 $pagerAdapter = new DoctrineORMAdapter($members->getQuery(), true, false);
249 $pagerFanta = new Pagerfanta($pagerAdapter);
250 $pagerFanta->setMaxPerPage(9);
251
252 try {
253 $pagerFanta->setCurrentPage($page);
254 } catch (OutOfRangeCurrentPageException $e) {
255 if ($page > 1) {
256 return $this->redirect($this->generateUrl('groups', ['page' => $pagerFanta->getNbPages()]), 302);
257 }
258 }
259
260 return $this->render('WallabagGroupBundle:Manage:manage.html.twig', [
261 'members' => $pagerFanta,
262 'group' => $group,
263 'currentPage' => $page,
264 ]);
265 }
266
267 /**
268 * @Route("/leave/{group}", name="group_leave")
269 * @param Group $group
270 * @return Response
271 */
272 public function leaveGroupAction(Group $group): Response
273 {
274 $logger = $this->get('logger');
275 $em = $this->getDoctrine()->getManager();
276 $removeGroup = false;
277
278 if ($this->getUser()->getGroupRoleForUser($group) == Group::ROLE_ADMIN) {
279 $logger->info('User ' . $this->getUser()->getUsername() . ' is the admin for group ' . $group->getName());
280 $newUser = $group->getUsers()->first();
281 $newUser->setGroupRole($group, Group::ROLE_ADMIN);
282 $logger->info('The new admin for group ' . $group->getName() . ' is user ' . $newUser->getUsername());
283 }
284
285 if ($group->getUsers()->count() <= 1) {
286 $logger->info('User ' . $this->getUser()->getUsername() . ' was the last one on the group ' . $group->getName() . ' so it will be deleted');
287 $removeGroup = true;
288 }
289
290 $logger->info('Removing user ' . $this->getUser()->getUsername() . ' from group ' . $group->getName());
291 $em->remove($this->getUser()->getUserGroupFromGroup($group));
292
293 if ($removeGroup) {
294 $logger->info("Removing group " . $group->getName() . " as it doesn't contains users anymore");
295 $em->remove($group);
296 }
297
298 $em->flush();
299 return $this->redirect($this->generateUrl('groups'), 302);
300 }
301
302 /**
303 * @Route("/requests/{group}/{page}", name="group-requests", defaults={"page" = "1"})
304 * @param Request $request
305 * @param int $page
306 * @return Response
307 */
308 public function showRequestsAction(Group $group, int $page): Response
309 {
310 if ($this->getUser()->getGroupRoleForUser($group) < Group::ROLE_MANAGE_USERS) {
311 $this->createAccessDeniedException();
312 }
313
314 $requests = $group->getRequests();
315 $pagerAdapter = new ArrayAdapter($requests->toArray());
316
317 $pagerFanta = new Pagerfanta($pagerAdapter);
318 $pagerFanta->setMaxPerPage(9);
319
320 try {
321 $pagerFanta->setCurrentPage($page);
322 } catch (OutOfRangeCurrentPageException $e) {
323 if ($page > 1) {
324 return $this->redirect($this->generateUrl('groups', ['page' => $pagerFanta->getNbPages()]), 302);
325 }
326 }
327
328 return $this->render('WallabagGroupBundle:Manage:requests.html.twig', [
329 'requests' => $pagerFanta,
330 'group' => $group,
331 'currentPage' => $page,
332 ]);
333 }
334
335 /**
336 * @Route("/activate/{group}/{user}/{accept}", name="group-activate", requirements={"accept" = "\d+"})
337 * @param Group $group
338 * @param User $user
339 * @param $accept
340 * @return Response
341 */
342 public function postRequestAction(Group $group, User $user, $accept): Response
343 {
344 if (!$this->getUser() < Group::ROLE_MANAGE_USERS) {
345 $this->createAccessDeniedException("You don't have the rights to do this");
346 }
347
348 $em = $this->getDoctrine()->getManager();
349
350 $accept = $accept == 1;
351 $user->getUserGroupFromGroup($group)->setAccepted($accept);
352 if (!$accept) {
353 $em->remove($user->getUserGroupFromGroup($group));
354 }
355
356 $em->flush();
357
358 return $this->redirectToRoute('group_index');
359 }
360
361 /**
362 * @Route("/user-edit/{group}/{user}", name="group-user-edit")
363 * @param Request $request
364 * @param Group $group
365 * @param User $user
366 * @return Response
367 */
368 public function editGroupUsersAction(Request $request, Group $group, User $user): Response
369 {
370 if ($this->getUser()->getGroupRoleForUser($group) < Group::ROLE_MANAGE_USERS) {
371 $this->createAccessDeniedException();
372 }
373
374 $groupUser = $user->getUserGroupFromGroup($group);
375 $editForm = $this->createForm(UserGroupType::class, $groupUser);
376 $editForm->handleRequest($request);
377
378 if ($editForm->isSubmitted() && $editForm->isValid()) {
379 $em = $this->getDoctrine()->getManager();
380 $em->persist($groupUser);
381 $em->flush();
382
383 $this->get('session')->getFlashBag()->add(
384 'notice',
385 $this->get('translator')->trans('flashes.group.notice.user.edited', ['%user%' => $user->getUsername(), '%group%' => $group->getName()])
386 );
387
388 return $this->redirectToRoute('group-manage', ['group' => $group->getId()]);
389 }
390
391 return $this->render('WallabagGroupBundle:Manage:edit_user.html.twig', array(
392 'user' => $user,
393 'group' => $group,
394 'edit_form' => $editForm->createView(),
395 ));
396 }
213} 397}
diff --git a/src/Wallabag/GroupBundle/Form/UserGroupType.php b/src/Wallabag/GroupBundle/Form/UserGroupType.php
index e8f814e4..326fa682 100644
--- a/src/Wallabag/GroupBundle/Form/UserGroupType.php
+++ b/src/Wallabag/GroupBundle/Form/UserGroupType.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Wallabag\GroupBundle\Form\Type; 3namespace Wallabag\GroupBundle\Form;
4 4
5use Wallabag\GroupBundle\Entity\Group; 5use Wallabag\GroupBundle\Entity\Group;
6use Symfony\Component\Form\AbstractType; 6use Symfony\Component\Form\AbstractType;
@@ -23,7 +23,7 @@ class UserGroupType extends AbstractType
23 'choices' => [ 23 'choices' => [
24 'group.roles.readonly' => Group::ROLE_READ_ONLY, 24 'group.roles.readonly' => Group::ROLE_READ_ONLY,
25 'group.roles.write' => Group::ROLE_WRITE, 25 'group.roles.write' => Group::ROLE_WRITE,
26 'group.roles.manage_prez' => Group::ROLE_MANAGE_PREZ, 26 'group.roles.manage_entries' => Group::ROLE_MANAGE_ENTRIES,
27 'group.roles.manage_users' => Group::ROLE_MANAGE_USERS, 27 'group.roles.manage_users' => Group::ROLE_MANAGE_USERS,
28 'group.roles.admin' => Group::ROLE_ADMIN, 28 'group.roles.admin' => Group::ROLE_ADMIN,
29 ], 29 ],
@@ -40,7 +40,7 @@ class UserGroupType extends AbstractType
40 public function configureOptions(OptionsResolver $resolver) 40 public function configureOptions(OptionsResolver $resolver)
41 { 41 {
42 $resolver->setDefaults(array( 42 $resolver->setDefaults(array(
43 'data_class' => 'Strut\StrutBundle\Entity\UserGroup', 43 'data_class' => 'Wallabag\GroupBundle\Entity\UserGroup',
44 )); 44 ));
45 } 45 }
46} 46}
diff --git a/src/Wallabag/GroupBundle/Resources/config/services.yml b/src/Wallabag/GroupBundle/Resources/config/services.yml
index 76e8427a..618f7ed7 100644
--- a/src/Wallabag/GroupBundle/Resources/config/services.yml
+++ b/src/Wallabag/GroupBundle/Resources/config/services.yml
@@ -1,3 +1,8 @@
1services: 1services:
2 sha256salted_encoder: 2 sha256salted_encoder:
3 class: Strut\StrutBundle\Service\Sha256Salted \ No newline at end of file 3 class: Wallabag\GroupBundle\Service\Sha256Salted
4
5 wallabag_core.filter.type.entry:
6 class: Wallabag\GroupBundle\Form\UserGroupType
7 tags:
8 - { name: form.type } \ No newline at end of file
diff --git a/src/Wallabag/GroupBundle/Resources/views/Manage/edit_user.html.twig b/src/Wallabag/GroupBundle/Resources/views/Manage/edit_user.html.twig
new file mode 100644
index 00000000..b7771690
--- /dev/null
+++ b/src/Wallabag/GroupBundle/Resources/views/Manage/edit_user.html.twig
@@ -0,0 +1,26 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'group.edit_user.title'|trans }}{% endblock %}
4
5{% block content %}
6
7<div class="row">
8 <div class="col-md-6">
9
10 {{ form_start(edit_form) }}
11 {{ form_errors(edit_form) }}
12
13 <div class="form-group">
14 {{ form_label(edit_form.role) }}
15 {{ form_errors(edit_form.role) }}
16 {{ form_widget(edit_form.role) }}
17 </div>
18
19 {{ form_widget(edit_form.save, {'attr': {'class': 'btn waves-effect'}}) }}
20 <a class="btn btn-default" href="{{ path('group-manage', {'group': group.id}) }}">{{ 'group.edit_user.cancel' | trans }}</a>
21 {{ form_widget(edit_form._token) }}
22 {{ form_end(edit_form) }}
23 </div>
24</div>
25
26{% endblock %}
diff --git a/src/Wallabag/GroupBundle/Resources/views/Manage/index.html.twig b/src/Wallabag/GroupBundle/Resources/views/Manage/index.html.twig
index 01466e52..35a70400 100644
--- a/src/Wallabag/GroupBundle/Resources/views/Manage/index.html.twig
+++ b/src/Wallabag/GroupBundle/Resources/views/Manage/index.html.twig
@@ -12,7 +12,7 @@
12 <p class="help">{{ 'group.description'|trans|raw }}</p> 12 <p class="help">{{ 'group.description'|trans|raw }}</p>
13 13
14 {% if groups is not empty %} 14 {% if groups is not empty %}
15 <table class="bordered"> 15 <table class="bordered responsive-table">
16 <thead> 16 <thead>
17 <tr> 17 <tr>
18 <th>{{ 'group.form.name_label'|trans }}</th> 18 <th>{{ 'group.form.name_label'|trans }}</th>
@@ -24,9 +24,32 @@
24 {% for group in groups %} 24 {% for group in groups %}
25 <tr> 25 <tr>
26 <td>{{ group.name }}</td> 26 <td>{{ group.name }}</td>
27 <td></td>
28 <td> 27 <td>
29 <a href="{{ path('group_edit', { 'id': group.id }) }}">{{ 'group.list.edit_action'|trans }}</a> 28 {% if app.user in group.users and app.user.inGroup(group) %}
29 {{ 'group.user.inGroup' | transchoice(group.users | length) }}
30 {% else %}
31 {{ 'group.user.notInGroup' | transchoice(group.users | length) }}
32 {% endif %}
33 </td>
34 <td>
35 {% if app.user in group.users and app.user.inGroup(group) %}
36 {% if app.user.getGroupRoleForUser(group) >= 5 %}
37 <a href="{{ path('group_edit', { 'id': group.id }) }}" class="waves-effect waves-light btn tooltipped" data-delay="50" data-position="bottom" data-tooltip="{{ 'group.list.edit_action'|trans }}"><i class="material-icons">edit</i></a>
38 <a href="{{ path('group-manage', { 'group': group.id }) }}" class="waves-effect waves-light btn tooltipped" data-delay="50" data-position="bottom" data-tooltip="{{ 'group.manage.label'|trans }}"><i class="material-icons">settings_applications</i></a>
39 {% endif %}
40 <a href="{{ path('group-presentations', { 'group': group.id }) }}" class="waves-effect waves-light btn tooltipped" data-delay="50" data-position="bottom" data-tooltip="{{ 'group.entries.label'|trans }}"><i class="material-icons">view_list</i></a>
41 <a href="{{ path('group_leave', { 'group': group.id }) }}" class="waves-effect waves-light btn red tooltipped" data-delay="50" data-position="bottom" data-tooltip="{{ 'group.leave.label'|trans }}"><i class="material-icons">clear</i></a>
42 {% elseif app.user in group.users and not app.user.inGroup(group) %}
43 {{ 'group.requests.sent' | trans }}
44 {% else %}
45 <a href="{{ path('group_join', { 'group': group.id }) }}" class="waves-effect waves-light btn tooltipped" data-tooltip="{{ 'group.join.label'|trans }}" data-delay="50" data-position="bottom">
46 {% if group.acceptSystem == 3 %}
47 <i class="material-icons md-18 vertical-align-middle" data-toggle="tooltip" data-placement="bottom" title="{{ 'group.join'|trans }}">lock</i>
48 {% else %}
49 <i class="material-icons" data-toggle="tooltip" data-placement="bottom" title="{{ 'group.join'|trans }}">input</i>
50 {% endif %}
51 </a>
52 {% endif %}
30 </td> 53 </td>
31 </tr> 54 </tr>
32 {% endfor %} 55 {% endfor %}
diff --git a/src/Wallabag/GroupBundle/Resources/views/Manage/manage.html.twig b/src/Wallabag/GroupBundle/Resources/views/Manage/manage.html.twig
new file mode 100644
index 00000000..2226b299
--- /dev/null
+++ b/src/Wallabag/GroupBundle/Resources/views/Manage/manage.html.twig
@@ -0,0 +1,102 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'group.manage.title' |trans({ '%group%': group.name }) }}{% endblock %}
4
5{% block content %}
6
7<div class="row">
8 <div class="input-field col s12">
9 <p>
10 {{ 'group.form.role_label' |trans }}:
11 <em>
12 {% if group.defaultRole == 1 %}
13 {{ 'group.roles.readonly' | trans }}
14 {% elseif group.defaultRole == 2 %}
15 {{ 'group.roles.write' | trans }}
16 {% elseif group.defaultRole == 3 %}
17 {{ 'group.roles.manage_prez' | trans }}
18 {% elseif group.defaultRole == 5 %}
19 {{ 'group.roles.manage_users' | trans }}
20 {% elseif group.defaultRole == 10 %}
21 {{ 'group.roles.admin' | trans }}
22 {% else %}
23 {{ 'group.roles.unknown' | trans }}
24 {% endif %}
25 </em>
26 </p>
27 <p>
28 {{ 'group.form.access_label' | trans }}:
29 <em>
30 {% if group.acceptSystem == 1 %}
31 {{ 'group.access.open' | trans }}
32 {% elseif group.acceptSystem == 2 %}
33 {{ 'group.access.request' | trans }}
34 {% elseif group.acceptSystem == 3 %}
35 {{ 'group.access.password' | trans }}
36 {% elseif group.acceptSystem == 4 %}
37 {{ 'group.access.invitation' | trans }}
38 {% elseif group.acceptSystem == 10 %}
39 {{ 'group.access.hidden' | trans }}
40 {% else %}
41 {{ 'group.access.unknown' | trans }}
42 {% endif %}
43 </em>
44 </p>
45 <a href="{{ path('group_edit', {'id' : group.id}) }}" class="btn waves-effect">{{ 'group.edit_group' | trans }}</a>
46 {% if group.acceptSystem == 2 %}
47 <a href="{{ path('group-requests', {'group' : group.id}) }}" class="btn waves-effect">{{ 'group.requests.list' | trans }} <span class="badge">{{ group.getRequests() | length }}</span></a>
48 {% elseif group.acceptSystem >= 4 %}
49 <a href="{{ path('group-invitations', {'group' : group.id}) }}" class="btn waves-effect">{{ 'group.edit.invitations' | trans }} <span class="badge">{{ group.getInvited() | length }}</span></a>
50 {% endif %}
51 <a href="{{ path('group_delete', { 'id': group.id }) }}" class="btn waves-effect red"><i class="material-icons md-18" data-toggle="tooltip" data-placement="bottom" title="{{ 'group.form.delete'|trans }}">delete</i></a>
52
53 {% if members | length > 1 %}
54 <table class="table">
55 <thead>
56 <tr>
57 <th>{{ 'group.members.name'|trans }}</th>
58 <th>{{ 'group.members.role' | trans }}</th>
59 <th>{{ 'group.members.action'|trans }}</th>
60 </tr>
61 </thead>
62
63 <tbody>
64 {% for user in members %}
65 {% if user != app.user %}
66 <tr>
67 <td>{{ user.username }}</td>
68 <td>
69 {% if user.getGroupRoleForUser(group) == 1 %}
70 {{ 'group.roles.readonly' | trans }}
71 {% elseif user.getGroupRoleForUser(group) == 2 %}
72 {{ 'group.roles.write' | trans }}
73 {% elseif user.getGroupRoleForUser(group) == 3 %}
74 {{ 'group.roles.manage_prez' | trans }}
75 {% elseif user.getGroupRoleForUser(group) == 5 %}
76 {{ 'group.roles.manage_users' | trans }}
77 {% elseif user.getGroupRoleForUser(group) == 10 %}
78 {{ 'group.roles.admin' | trans }}
79 {% else %}
80 {{ 'group.roles.unknown' | trans }}
81 {% endif %}
82 </td>
83 <td>
84 <a href="{{ path('group-user-edit', { 'group': group.id, 'user': user.id }) }}" class="btn waves-effect"><i class="material-icons md-18" data-toggle="tooltip" data-placement="bottom" title="{{ 'group.members.edit'|trans }}">edit</i></a>
85 <a class="btn waves-effect red" href="{{ path('group-user-exclude', { 'group': group.id, 'user': user.id }) }}"><i class="material-icons md-18" data-toggle="tooltip" data-placement="bottom" title="{{ 'group.members.exclude'|trans }}">clear</i></a>
86 </td>
87 </tr>
88 {% endif %}
89 {% endfor %}
90 </tbody>
91 </table>
92 {% else %}
93 <p>{{ 'group.members.empty' | trans }}</p>
94 {% endif %}
95 <div class="pull-right">
96 {% if members.getNbPages > 1 %}
97 {{ pagerfanta(members, 'twitter_bootstrap3', {'proximity': 1}) }}
98 {% endif %}
99 </div>
100 </div>
101</div>
102{% endblock %}
diff --git a/src/Wallabag/GroupBundle/Resources/views/Manage/requests.html.twig b/src/Wallabag/GroupBundle/Resources/views/Manage/requests.html.twig
new file mode 100644
index 00000000..36d069ce
--- /dev/null
+++ b/src/Wallabag/GroupBundle/Resources/views/Manage/requests.html.twig
@@ -0,0 +1,31 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'group.requests.list'|trans }}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8
9 <table class="table">
10 <thead>
11 <tr>
12 <th>{{ 'group.requests.username'|trans }}</th>
13 <th>{{ 'group.requests.action'|trans }}</th>
14 </tr>
15 </thead>
16
17 <tbody>
18 {% for request in requests %}
19 <tr>
20 <td>{{ request.username }}</td>
21 <td>
22 <a class="btn waves-effect" href="{{ path('group-activate', {'group': group.id, 'user': request.id, 'accept': 1}) }}"><i class="material-icons">check</i></a>
23 <a class="btn waves-effect red" href="{{ path('group-activate', {'group': group.id, 'user': request.id, 'accept': 2}) }}"><i class="material-icons">close</i></a>
24 </td>
25 </tr>
26 {% endfor %}
27 </tbody>
28 </table>
29 </div>
30</div>
31{% endblock %}
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index 4f24b17a..4a52b186 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -393,4 +393,13 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
393 393
394 return $groups; 394 return $groups;
395 } 395 }
396
397 /**
398 * @param Group $group
399 * @param $role
400 */
401 public function addAGroup(Group $group, $role)
402 {
403 $this->userGroups->add(new UserGroup($this, $group, $role));
404 }
396} 405}
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php
index 6adbe329..b4b13605 100644
--- a/src/Wallabag/UserBundle/Repository/UserRepository.php
+++ b/src/Wallabag/UserBundle/Repository/UserRepository.php
@@ -58,11 +58,19 @@ class UserRepository extends EntityRepository
58 * 58 *
59 * @param string $term 59 * @param string $term
60 * 60 *
61 * @return QueryBuilder 61 * @return \Doctrine\ORM\QueryBuilder
62 */ 62 */
63 public function getQueryBuilderForSearch($term) 63 public function getQueryBuilderForSearch($term)
64 { 64 {
65 return $this->createQueryBuilder('u') 65 return $this->createQueryBuilder('u')
66 ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%'.$term.'%'); 66 ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%'.$term.'%');
67 } 67 }
68
69 public function findGroupMembers($groupid)
70 {
71 return $this->createQueryBuilder('u')
72 ->leftJoin('u.userGroups', 'usergroup')
73 ->where('usergroup.group = :group')->setParameter(':group', $groupid)
74 ->andWhere('usergroup.accepted = true');
75 }
68} 76}
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
index 5fc6163e..9d5abcaf 100644
--- a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig
@@ -30,7 +30,7 @@
30 {{ form_rest(searchForm) }} 30 {{ form_rest(searchForm) }}
31 </form> 31 </form>
32 </div> 32 </div>
33 33
34 </div> 34 </div>
35 35
36 <table class="bordered"> 36 <table class="bordered">