mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-14 14:24:24 +00:00
parent
b89ed5d534
commit
55a2c66793
84
DataFixtures/ORM/LoadRolesACL.php
Normal file
84
DataFixtures/ORM/LoadRolesACL.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace Chill\EventBundle\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
|
||||
use Chill\MainBundle\Entity\RoleScope;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
|
||||
/**
|
||||
* Add roles to existing groups
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
* @author Champs Libres <info@champs-libres.coop>
|
||||
*/
|
||||
class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
|
||||
$permissionsGroup = $this->getReference($permissionsGroupRef);
|
||||
foreach (LoadScopes::$references as $scopeRef){
|
||||
$scope = $this->getReference($scopeRef);
|
||||
//create permission group
|
||||
switch ($permissionsGroup->getName()) {
|
||||
case 'social':
|
||||
if ($scope->getName()['en'] === 'administrative') {
|
||||
break 2; // we do not want any power on administrative
|
||||
}
|
||||
break;
|
||||
case 'administrative':
|
||||
case 'direction':
|
||||
if (in_array($scope->getName()['en'], array('administrative', 'social'))) {
|
||||
break 2; // we do not want any power on social or administrative
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Adding CHILL_EVENT_UPDATE & CHILL_EVENT_CREATE to %s "
|
||||
. "permission group, scope '%s' \n",
|
||||
$permissionsGroup->getName(), $scope->getName()['en']);
|
||||
$roleScopeUpdate = (new RoleScope())
|
||||
->setRole('CHILL_EVENT_UPDATE')
|
||||
->setScope($scope);
|
||||
$permissionsGroup->addRoleScope($roleScopeUpdate);
|
||||
$roleScopeCreate = (new RoleScope())
|
||||
->setRole('CHILL_EVENT_CREATE')
|
||||
->setScope($scope);
|
||||
$permissionsGroup->addRoleScope($roleScopeCreate);
|
||||
$manager->persist($roleScopeUpdate);
|
||||
$manager->persist($roleScopeCreate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
public function getOrder()
|
||||
{
|
||||
return 30011;
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
|
||||
/**
|
||||
* This is the class that loads and manages your bundle configuration
|
||||
@ -23,8 +24,11 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
$loader = new Loader\YamlFileLoader($container,
|
||||
new FileLocator(__DIR__.'/../Resources/config/services'));
|
||||
$loader->load('repositories.yml');
|
||||
$loader->load('search.yml');
|
||||
$loader->load('authorization.yml');
|
||||
}
|
||||
|
||||
/* (non-PHPdoc)
|
||||
@ -32,7 +36,17 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface
|
||||
*/
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
$this->prependAuthorization($container);
|
||||
$this->prependRoute($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* add route to route loader for chill
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
protected function prependRoute(ContainerBuilder $container)
|
||||
{
|
||||
//add routes for custom bundle
|
||||
$container->prependExtensionConfig('chill_main', array(
|
||||
'routing' => array(
|
||||
@ -42,4 +56,20 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* add authorization hierarchy
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
protected function prependAuthorization(ContainerBuilder $container)
|
||||
{
|
||||
$container->prependExtensionConfig('security', array(
|
||||
'role_hierarchy' => array(
|
||||
EventVoter::SEE_DETAILS => array(EventVoter::SEE),
|
||||
EventVoter::UPDATE => array(EventVoter::SEE_DETAILS),
|
||||
EventVoter::CREATE => array(EventVoter::SEE_DETAILS)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
services:
|
||||
# chill_event.example:
|
||||
# class: Chill\EventBundle\Example
|
||||
# arguments: [@service_id, "plain_value", %parameter%]
|
8
Resources/config/services/authorization.yml
Normal file
8
Resources/config/services/authorization.yml
Normal file
@ -0,0 +1,8 @@
|
||||
services:
|
||||
chill_event.event_voter:
|
||||
class: Chill\EventBundle\Security\Authorization\EventVoter
|
||||
arguments:
|
||||
- "@chill.main.security.authorization.helper"
|
||||
tags:
|
||||
- { name: chill.role }
|
||||
- { name: security.voter }
|
6
Resources/config/services/repositories.yml
Normal file
6
Resources/config/services/repositories.yml
Normal file
@ -0,0 +1,6 @@
|
||||
services:
|
||||
chill_group.repository.event:
|
||||
class: Doctrine\ORM\EntityRepository
|
||||
factory: ['@doctrine.orm.entity_manager', getRepository]
|
||||
arguments:
|
||||
- 'Chill\EventBundle\Entity\Event'
|
11
Resources/config/services/search.yml
Normal file
11
Resources/config/services/search.yml
Normal file
@ -0,0 +1,11 @@
|
||||
services:
|
||||
chill_event.search_events:
|
||||
class: Chill\EventBundle\Search\EventSearch
|
||||
arguments:
|
||||
- "@security.token_storage"
|
||||
- "@chill_group.repository.event"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@templating"
|
||||
tags:
|
||||
- { name: chill.search, alias: 'event_regular' }
|
||||
|
11
Resources/translations/messages.fr.yml
Normal file
11
Resources/translations/messages.fr.yml
Normal file
@ -0,0 +1,11 @@
|
||||
#events
|
||||
Name: Nom
|
||||
Date: Date
|
||||
Event type : Type d'événement
|
||||
See: Voir
|
||||
|
||||
|
||||
|
||||
#search
|
||||
Event search: Recherche d'événements
|
||||
'%total% events match the search %pattern%' : '{0} Aucun événement ne correspond aux termes de recherche "%pattern%" | {1} Un événement a été trouvé par la recherche "%pattern%" | ]1,Inf] %total% événements correspondent aux termes de recherche "%pattern%".'
|
43
Resources/views/Event/list.html.twig
Normal file
43
Resources/views/Event/list.html.twig
Normal file
@ -0,0 +1,43 @@
|
||||
<h2>{{ 'Event search'|trans }}</h2>
|
||||
|
||||
<p>{% transchoice total with { '%pattern%' : pattern } %}%total% events match the search %pattern%{% endtranschoice %}</p>
|
||||
|
||||
|
||||
{% if events|length > 0 %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="chill-red">{{ 'Name'|trans }}</th>
|
||||
<th class="chill-green">{{ 'Date'|trans }}</th>
|
||||
<th class="chill-orange">{{ 'Event type'|trans }}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in events %}
|
||||
<tr>
|
||||
<td>{{ event.label }}</td>
|
||||
<td>{{ event.date|localizeddate('long', 'none') }}</td>
|
||||
<td>{{ event.type.label|localize_translatable_string }}</td>
|
||||
<td>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
{% if is_granted('CHILL_EVENT_SEE_DETAILS', event) %}
|
||||
<a href="#" class="sc-button btn-action">
|
||||
{{ 'See'|trans }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_EVENT_UPDATE', event) %}
|
||||
<a href="#" class="sc-button btn-edit">
|
||||
{{ 'Edit'|trans }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endif %}
|
143
Search/EventSearch.php
Normal file
143
Search/EventSearch.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Chill\EventBundle\Search;
|
||||
|
||||
use Chill\MainBundle\Search\AbstractSearch;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Symfony\Component\Templating\EngineInterface as TemplatingEngine;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
/**
|
||||
* Search within Events.
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
* @author Champs Libres <info@champs-libres.coop>
|
||||
*/
|
||||
class EventSearch extends AbstractSearch
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @var EntityRepository
|
||||
*/
|
||||
private $er;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \Chill\MainBundle\Entity\User
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
private $helper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TemplatingEngine
|
||||
*/
|
||||
private $templating;
|
||||
|
||||
|
||||
public function __construct(
|
||||
TokenStorageInterface $tokenStorage,
|
||||
EntityRepository $eventRepository,
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
TemplatingEngine $templating
|
||||
)
|
||||
{
|
||||
$this->user = $tokenStorage->getToken()->getUser();
|
||||
$this->er = $eventRepository;
|
||||
$this->helper = $authorizationHelper;
|
||||
$this->templating = $templating;
|
||||
}
|
||||
|
||||
public function supports($domain)
|
||||
{
|
||||
return 'event' === $domain or 'events' === $domain;
|
||||
}
|
||||
|
||||
public function isActiveByDefault()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getOrder()
|
||||
{
|
||||
return 3000;
|
||||
}
|
||||
|
||||
public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array())
|
||||
{
|
||||
return $this->templating->render('ChillEventBundle:Event:list.html.twig',
|
||||
array(
|
||||
'events' => $this->search($terms, $start, $limit, $options),
|
||||
'pattern' => $this->recomposePattern($terms, array(), $terms['_domain']),
|
||||
'total' => $this->count($terms)
|
||||
));
|
||||
}
|
||||
|
||||
protected function search(array $terms, $start, $limit, $options)
|
||||
{
|
||||
$qb = $this->er->createQueryBuilder('e');
|
||||
$qb->select('e');
|
||||
$this->composeQuery($qb, $terms)
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($start)
|
||||
->orderBy('e.date', 'DESC')
|
||||
;
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
protected function count(array $terms)
|
||||
{
|
||||
$qb = $this->er->createQueryBuilder('e');
|
||||
$qb->select('COUNT(e)');
|
||||
$this->composeQuery($qb, $terms)
|
||||
;
|
||||
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
protected function composeQuery(QueryBuilder &$qb, $terms)
|
||||
{
|
||||
|
||||
// add security clauses
|
||||
$reachableCenters = $this->helper
|
||||
->getReachableCenters($this->user, new Role('CHILL_EVENT_SEE'));
|
||||
|
||||
if (count($reachableCenters) === 0) {
|
||||
// add a clause to block all events
|
||||
$where = $qb->expr()->isNull('e.center');
|
||||
$qb->andWhere($where);
|
||||
} else {
|
||||
|
||||
$n = 0;
|
||||
$orWhere = $qb->expr()->orX();
|
||||
foreach ($reachableCenters as $center) {
|
||||
$circles = $this->helper->getReachableScopes($this->user,
|
||||
new Role('CHILL_EVENT_SEE'), $center);
|
||||
$where = $qb->expr()->andX(
|
||||
$qb->expr()->eq('e.center', ':center_'.$n),
|
||||
$qb->expr()->in('e.circle', ':circle_'.$n)
|
||||
);
|
||||
$qb->setParameter('center_'.$n, $center);
|
||||
$qb->setParameter('circle_'.$n, $circles);
|
||||
$orWhere->add($where);
|
||||
}
|
||||
|
||||
$qb->andWhere($orWhere);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
63
Security/Authorization/EventVoter.php
Normal file
63
Security/Authorization/EventVoter.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
namespace Chill\EventBundle\Security\Authorization;
|
||||
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\ProvideRoleInterface;
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
|
||||
/**
|
||||
* Description of EventVoter
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
* @author Champs Libres <info@champs-libres.coop>
|
||||
*/
|
||||
class EventVoter extends AbstractChillVoter implements ProvideRoleInterface
|
||||
{
|
||||
|
||||
const SEE = 'CHILL_EVENT_SEE';
|
||||
const SEE_DETAILS = 'CHILL_EVENT_SEE_DETAILS';
|
||||
const CREATE = 'CHILL_EVENT_CREATE';
|
||||
const UPDATE = 'CHILL_EVENT_UPDATE';
|
||||
|
||||
protected $authorizationHelper;
|
||||
|
||||
public function __construct(AuthorizationHelper $helper)
|
||||
{
|
||||
$this->authorizationHelper = $helper;
|
||||
}
|
||||
|
||||
protected function getSupportedAttributes()
|
||||
{
|
||||
return array(self::SEE, self::SEE_DETAILS,
|
||||
self::CREATE, self::UPDATE);
|
||||
}
|
||||
|
||||
protected function getSupportedClasses()
|
||||
{
|
||||
return array(Event::class);
|
||||
}
|
||||
|
||||
protected function isGranted($attribute, $event, $user = null)
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->helper->userHasAccess($user, $event, $attribute);
|
||||
}
|
||||
|
||||
public function getRoles()
|
||||
{
|
||||
return $this->getSupportedAttributes();
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user