394 lines
13 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Tests\Controller;
use Chill\ActivityBundle\Entity\ActivityType;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Role\Role;
use function count;
use function in_array;
/**
* @internal
* @coversNothing
*/
final class ActivityControllerTest extends WebTestCase
{
public function getSecuredPagesAuthenticated()
{
self::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
$user = $this->createFakeUser();
return [
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/', $person->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/new', $person->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()),
],
[
$this->getAuthenticatedClient($user->getUsername()),
sprintf('fr/person/%d/activity/new', $person->getId()),
],
];
}
/**
* Provide a client unauthenticated and.
*/
public function getSecuredPagesUnauthenticated()
{
self::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
return [
[sprintf('fr/person/%d/activity/', $person->getId())],
[sprintf('fr/person/%d/activity/new', $person->getId())],
[sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())],
[sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())],
];
}
/**
* @dataProvider getSecuredPagesUnauthenticated
*
* @param mixed $url
*/
public function testAccessIsDeniedForUnauthenticated($url)
{
$client = $this->createClient();
$client->request('GET', $url);
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertTrue(
$client->getResponse()->isRedirect('http://localhost/login'),
sprintf('the page "%s" does not redirect to http://localhost/login', $url)
);
}
/**
* @dataProvider getSecuredPagesAuthenticated
*
* @param type $client
* @param type $url
*/
public function testAccessIsDeniedForUnauthorized($client, $url)
{
$client->request('GET', $url);
$this->assertEquals(403, $client->getResponse()->getStatusCode());
}
public function testCompleteScenario()
{
// Create a new client to browse the application
$client = $this->getAuthenticatedClient();
$person = $this->getPersonFromFixtures();
// Create a new entry in the database
$crawler = $client->request('GET', sprintf(
'en/person/%d/activity/',
$person->getId()
));
$this->assertEquals(
200,
$client->getResponse()->getStatusCode(),
'Unexpected HTTP status code for GET /activity/'
);
$crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité')
->link());
$reason1 = $this->getRandomActivityReason();
$reason2 = $this->getRandomActivityReason([$reason1->getId()]);
// Fill in the form and submit it
$form = $crawler->selectButton('Ajouter une nouvelle activité')->form([
'chill_activitybundle_activity' => [
'date' => '15-01-2015',
'durationTime' => 600,
// 'remark' => 'blabla',
'scope' => $this->getRandomScope('center a_social', 'Center A')->getId(),
'type' => $this->getRandomActivityType()->getId(),
],
]);
$form['chill_activitybundle_activity[reasons]']->select([$reason1->getId(), $reason2->getId()]);
$client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect());
$crawler = $client->followRedirect();
// Check data in the show view
$this->assertGreaterThan(
0,
$crawler->filter('dd:contains("January 15, 2015")')->count(),
'Missing element dd:contains("January 15, 2015")'
);
// Edit the entity
$crawler = $client->click($crawler->selectLink("Modifier l'activité")->link());
$form = $crawler->selectButton("Sauver l'activité")->form([
'chill_activitybundle_activity' => [
'date' => '25-01-2015',
// 'remark' => 'Foo'
],
]);
$client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect());
$crawler = $client->followRedirect();
// check that new data are present
$this->assertGreaterThan(
0,
$crawler->filter('dd:contains("January 25, 2015")')->count(),
'Missing element dd:contains("January 25, 2015")'
);
$this->assertGreaterThan(
0,
$crawler->filter('dd:contains("Foo")')->count(),
'Missing element dd:contains("Foo")'
);
// delete the actvity
$crawler = $client->click($crawler->selectLink('Supprimer')->link());
$button = $crawler->selectButton('Supprimer');
$form = $button->form();
$client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect(sprintf(
'/en/person/%d/activity/',
$person->getId()
)));
$crawler = $client->followRedirect();
$this->assertNotContains('January 25, 2015', $crawler->text());
}
/**
* create a user without any permissions on CHILL_ACTIVITY_* but with
* permissions on center.
*
* @return \Chill\MainBundle\Entity\User a fake user within a group without activity
*/
private function createFakeUser()
{
$container = self::$kernel->getContainer();
$em = $container->get('doctrine.orm.entity_manager');
//get the social PermissionGroup, and remove CHILL_ACTIVITY_*
$socialPermissionGroup = $em
->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)
->findOneByName('social');
$withoutActivityPermissionGroup = (new \Chill\MainBundle\Entity\PermissionsGroup())
->setName('social without activity');
//copy role scopes where ACTIVITY is not present
foreach ($socialPermissionGroup->getRoleScopes() as $roleScope) {
if (!strpos($roleScope->getRole(), 'ACTIVITY')) {
$withoutActivityPermissionGroup->addRoleScope($roleScope);
}
}
//create groupCenter
$groupCenter = new \Chill\MainBundle\Entity\GroupCenter();
$groupCenter->setCenter($em->getRepository(\Chill\MainBundle\Entity\Center::class)
->findOneBy(['name' => 'Center A']))
->setPermissionsGroup($withoutActivityPermissionGroup);
$em->persist($withoutActivityPermissionGroup);
$em->persist($groupCenter);
//create user
$faker = \Faker\Factory::create();
$username = $faker->name;
$user = new \Chill\MainBundle\Entity\User();
$user
->setPassword($container->get('security.password_encoder')
->encodePassword($user, 'password'))
->setUsername($username)
->addGroupCenter($groupCenter);
$em->persist($user);
$em->flush();
return $user;
}
private function getActivitiesForPerson(\Chill\PersonBundle\Entity\Person $person)
{
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$activities = $em->getRepository(\Chill\ActivityBundle\Entity\Activity::class)
->findBy(['person' => $person]);
if (count($activities) === 0) {
throw new RuntimeException('We need activities associated with this '
. 'person. Did you forget to add fixtures ?');
}
return $activities;
}
/**
* @param mixed $username
*
* @return \Symfony\Component\BrowserKit\Client
*/
private function getAuthenticatedClient($username = 'center a_social')
{
return self::createClient([], [
'PHP_AUTH_USER' => $username,
'PHP_AUTH_PW' => 'password',
]);
}
/**
* @return \Chill\PersonBundle\Entity\Person
*/
private function getPersonFromFixtures()
{
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$person = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)
->findOneBy([
'firstName' => 'Depardieu',
'lastName' => 'Gérard',
]);
if (null === $person) {
throw new RuntimeException('We need a person with firstname Gérard and'
. ' lastname Depardieu. Did you add fixtures ?');
}
return $person;
}
/**
* @param int[] $excludeIds An array of id to exclude
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludeIds = [])
{
$reasons = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(\Chill\ActivityBundle\Entity\ActivityReason::class)
->findAll();
$reason = $reasons[array_rand($reasons)];
if (in_array($reason->getId(), $excludeIds, true)) {
return $this->getRandomActivityReason($excludeIds);
}
return $reason;
}
/**
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$types = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(ActivityType::class)
->findAll();
return $types[array_rand($types)];
}
/**
* @param string $username
* @param string $centerName
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope($username, $centerName)
{
$user = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(\Chill\MainBundle\Entity\User::class)
->findOneByUsername($username);
if (null === $user) {
throw new RuntimeException("The user with username {$username} "
. 'does not exists in database. Did you add fixtures ?');
}
$center = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository(\Chill\MainBundle\Entity\Center::class)
->findOneByName($centerName);
// get scope reachable by both role UPDATE and DELETE
$reachableScopesUpdate = self::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes(
$user,
new Role('CHILL_ACTIVITY_UPDATE'),
$center
);
$reachableScopesDelete = self::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes(
$user,
new Role('CHILL_ACTIVITY_DELETE'),
$center
);
$reachableScopesId = array_intersect(
array_map(static function ($s) {
return $s->getId();
}, $reachableScopesDelete),
array_map(static function ($s) {
return $s->getId();
}, $reachableScopesUpdate)
);
if (count($reachableScopesId) === 0) {
throw new RuntimeException('there are not scope reachable for '
. 'both CHILL_ACTIVITY_UPDATE and CHILL_ACTIVITY_DELETE');
}
foreach ($reachableScopesUpdate as $scope) {
if (in_array($scope->getId(), $reachableScopesId, true)) {
$reachableScopes[] = $scope;
}
}
return $reachableScopes[array_rand($reachableScopes)];
}
}