Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
mRoca committed May 26, 2020
1 parent f751ec9 commit 1c6b77b
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 69 deletions.
2 changes: 1 addition & 1 deletion features/organization/users.feature
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Feature:
And the response status code should be 403

Scenario: As a super-admin, I can impersonate a user
Given I am authenticated as "michel.roca@resop.com"
Given I am authenticated as "super.admin@resop.com"
When I go to "/organizations/201/users/"
Then I should see "Usurper l'identité"
When I follow "Usurper l'identité"
Expand Down
10 changes: 5 additions & 5 deletions fixtures/users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ App\Entity\User:
properties: {"occupation": "<randomElement(['Pharmacien', 'Pompier', 'Ambulancier.e', 'Logisticien', 'Infirmier.e'])>", "organizationOccupation": "Secouriste", "vulnerable": <boolean(50)>, "fullyEquipped": <boolean(50)>, "drivingLicence": <boolean(50)>}
organizations: ['@Organization.DT77']

# Michel Roca is a super-admin, he can do whatever he wants.
User.michel_roca:
# Super ADMIN is a super-admin, he can do whatever he wants.
User.super_admin:
id: 107
firstName: Michel
lastName: ROCA
firstName: Super
lastName: ADMIN
organization: '@Organization.DT75'
identificationNumber: 990008A
emailAddress: michel.roca@resop.com
emailAddress: super.admin@resop.com
plainPassword: covid19
phoneNumber: '<phoneNumberObject("0612345678", "FR")>'
birthday: '1990-01-01'
Expand Down
88 changes: 55 additions & 33 deletions src/DataFixtures/ApplicationFixtures.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ final class ApplicationFixtures extends Fixture
private const PERCENT_ASSET_AVAILABLE = 0.30;
private const PERCENT_ASSET_PARTIALLY_AVAILABLE = 0.30;

private const USER_TYPE = 'user';
private const ADMIN_TYPE = 'admin';
private const SUPER_ADMIN_TYPE = 'super_admin';

private const ORGANIZATIONS = [
'DT75' => [
'UL 01-02',
Expand Down Expand Up @@ -97,7 +101,7 @@ final class ApplicationFixtures extends Fixture
private array $missionTypes = [];

private SkillSetDomain $skillSetDomain;
private int $nbUsers;
private int $nbUsers = 15;
private int $nbAvailabilities;

private int $availabilitiesId = 1;
Expand All @@ -116,10 +120,10 @@ public function __construct(
string $slotInterval,
int $nbUsers = null,
int $nbAvailabilities = null
) {
)
{
$this->validator = $validator;
$this->skillSetDomain = $skillSetDomain;
$this->nbUsers = $nbUsers ?: random_int(10, 20);
$this->nbAvailabilities = $nbAvailabilities ?: random_int(2, 6);
$this->slotBookingGuesser = $slotBookingGuesser;
$this->slotAvailabilityGuesser = $slotAvailabilityGuesser;
Expand Down Expand Up @@ -296,44 +300,62 @@ private function loadCommissionableAssets(ObjectManager $manager): void
$manager->flush();
}

private function loadUsers(ObjectManager $manager): void
private function createUser(int $organizationUserNumber, Organization $organization = null, string $type = self::USER_TYPE): User
{
$startIdNumber = 990000;
$organizationId = $organization ? $organization->getId() : 0;
$firstNames = ['Audrey', 'Arnaud', 'Bastien', 'Beatrice', 'Benoit', 'Camille', 'Claire', 'Hugo', 'Fabien', 'Florian', 'Francis', 'Lilia', 'Lisa', 'Marie', 'Marine', 'Mathias', 'Mathieu', 'Michel', 'Nassim', 'Nathalie', 'Olivier', 'Pierre', 'Philippe', 'Sybille', 'Thomas', 'Tristan'];
$lastNames = ['Bryant', 'Butler', 'Curry', 'Davis', 'Doncic', 'Durant', 'Embiid', 'Fournier', 'Grant', 'Gobert', 'Harden', 'Irving', 'James', 'Johnson', 'Jordan', 'Lilliard', 'Morant', 'Noah', 'Oneal', 'Parker', 'Pippen', 'Skywalker', 'Thompson', 'Westbrook'];
$occupations = ['Pharmacien', 'Pompier', 'Ambulancier.e', 'Logisticien', 'Infirmier.e'];

$x = 1;
$occupations = [null, 'Pharmacien', 'Pompier', 'Ambulancier.e', 'Logisticien', 'Infirmier.e'];
$organizationOcccupations = [null, 'Secouriste', 'DLUS', 'DLAS'];
$availableSkillSet = $this->skillSetDomain->getSkillSet();

$user = new User();
$user->id = $organizationId * 100 + $organizationUserNumber;
$user->firstName = $firstNames[array_rand($firstNames)];
$user->lastName = $lastNames[array_rand($lastNames)];
$user->organization = $organization;

// e.g. 990001A
$user->setIdentificationNumber($user->id.'A');
$user->setEmailAddress($type.$user->id.'@resop.com');
$user->phoneNumber = $this->phoneNumberUtil->parse('0102030405', 'FR');
$user->birthday = '1990-01-01';
$user->properties = [
'organizationOccupation' => $organizationOcccupations[array_rand($organizationOcccupations)],
'fullyEquipped' => (bool) random_int(0, 1),
'drivingLicence' => (bool) random_int(0, 1),
'vulnerable' => (bool) random_int(0, 1),
'occupation' => $occupations[array_rand($occupations)],
];
$user->skillSet = (array) array_rand($availableSkillSet, random_int(1, 3));

if (self::ADMIN_TYPE === $type || self::SUPER_ADMIN_TYPE === $type) {
// Set encoded password directly for performances on fixtures loading
// Plain password is: covid19
$user->password = '$argon2id$v=19$m=65536,t=4,p=1$cEjk39WnLC+QRVJfNI5nmw$eM0J3UZ75hwFJRGQmph2OiBGRzJU6/NGVWcj0j+WVYw';

if (null !== $organization) {
$user->addOrganization($organization);
}
}

return $user;
}

private function loadUsers(ObjectManager $manager): void
{
$user = $this->createUser(1, null, self::SUPER_ADMIN_TYPE);
$user->roles[] = 'ROLE_SUPER_ADMIN';
$this->validateAndPersist($manager, $user);

foreach ($this->organizations as $organization) {
for ($i = 0; $i < $this->nbUsers; ++$i) {
$user = new User();
$user->id = $i + 1;
$user->firstName = $firstNames[array_rand($firstNames)];
$user->lastName = $lastNames[array_rand($lastNames)];
$user->organization = $organization;
// Set encoded password directly for performances on fixtures loading
// Plain password is: covid19
$user->password = '$argon2id$v=19$m=65536,t=4,p=1$cEjk39WnLC+QRVJfNI5nmw$eM0J3UZ75hwFJRGQmph2OiBGRzJU6/NGVWcj0j+WVYw';

// e.g. 990001A
$user->setIdentificationNumber(str_pad(''.++$startIdNumber.'', 10, '0', \STR_PAD_LEFT).'A');
$user->setEmailAddress('user'.$x.'@resop.com');
$user->phoneNumber = $this->phoneNumberUtil->parse('0102030405', 'FR');
$user->birthday = '1990-01-01';
$user->properties = [
'organizationOccupation' => 'Secouriste',
'fullyEquipped' => (bool) random_int(0, 1),
'drivingLicence' => (bool) random_int(0, 1),
'vulnerable' => (bool) random_int(0, 1),
'occupation' => $occupations[array_rand($occupations)],
];
$user->skillSet = (array) array_rand($availableSkillSet, random_int(1, 3));
$user = $this->createUser(1, $organization, self::ADMIN_TYPE);
$this->validateAndPersist($manager, $user);

for ($i = 0; $i < $this->nbUsers; ++$i) {
$user = $this->createUser($i+2, $organization);
$this->users[$organization->getParentOrganization()->id][] = $user;

$this->validateAndPersist($manager, $user);
++$x;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Entity/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class User implements UserPasswordInterface, AvailabilitableInterface, UserSeria

/**
* @ORM\ManyToOne(targetEntity="App\Entity\Organization", fetch="EAGER")
* @Assert\NotNull()
* @Assert\Expression("'ROLE_SUPER_ADMIN' in this.roles or value != null")
*/
public ?Organization $organization = null;

Expand Down Expand Up @@ -234,7 +234,7 @@ public function unserialize($serialized): void
$this->identificationNumber,
$this->emailAddress,
$this->birthday,
$this->password) = unserialize($serialized);
$this->password) = unserialize($serialized, ['allowed_classes' => [__CLASS__]]);
}

public function getId(): ?int
Expand Down
5 changes: 3 additions & 2 deletions src/Form/Type/UserPasswordType.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'type' => PasswordType::class,
'required' => true,
'first_options' => [
'label' => 'Mot de passe',
'label' => 'user.password',
],
'second_options' => [
'label' => 'Confirmation',
'label' => 'user.confirmPassword',
],
]);

Expand All @@ -34,6 +34,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
if (!empty($user->getPassword())) {
$event->getForm()->add('currentPassword', PasswordType::class, [
'required' => true,
'label' => 'user.currentPassword',
]);
}
});
Expand Down
21 changes: 6 additions & 15 deletions templates/_navbar.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,12 @@
<span class="navbar-text navbar-separator d-none d-lg-block"></span>

<div class="collapse navbar-collapse" id="navbarContent">
{% if app.user and app.user.password is not empty %}
{% set organizationsCount = app.user.organizations.count %}
{% if 1 == organizationsCount %}
<a class="nav-link active" href="{{ path('app_organization_dashboard', {organization: app.user.organizations.first.id}) }}">Gérer ma structure</a>
{% elseif 1 < organizationsCount %}
<ul>Gérer ma structure :
{% for organization in app.user.organizations %}
<li>
<a class="nav-link active" href="{{ path('app_organization_dashboard', {organization: organization.id}) }}">{{ organization.name }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
{% endif %}
<div class="navbar-nav ml-auto">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{{ path('app_user_home') }}">{{ 'nav.section.volunteer' | trans }}</a>
</li>
</ul>
<div class="navbar-nav">
{% if not app.user %}
<a class="btn btn-outline-primary" href="{{ path('app_user_create') }}">{{ 'user.createMyAccount' | trans }}</a>
{% else %}
Expand Down
8 changes: 0 additions & 8 deletions templates/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@
{% include '_navbar.html.twig' %}

<div class="container my-5">
{% if app.user and 0 < app.user.organizations.count and app.user.password is empty %}
<p class="alert alert-warning">
<a href="{{ path('app_user_password') }}">
Vous devez renseigner votre mot de passe afin d'administrer votre structure.
</a>
</p>
{% endif %}

{{ include('misc/flash-messages.html.twig') }}

{% block body '' %}
Expand Down
8 changes: 7 additions & 1 deletion templates/organization/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@

<div class="collapse navbar-collapse" id="navbarContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{{ path('app_organization_dashboard')}}">
{{ 'nav.section.organization' | trans }}
{{ app.request.attributes.get('currentOrganization') }}
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('app_user_home')}}">{{ 'nav.section.volunteer' | trans }}</a>
</li>
Expand Down Expand Up @@ -53,7 +59,7 @@

<span class="navbar-text navbar-separator mt-1 ml-3 mr-4 d-none d-lg-block"></span>
<span class="navbar-text active text-dark font-weight-bold">
{{ app.request.attributes.get('currentOrganization') }}
{{ app.user.fullName }} - {{ app.request.attributes.get('currentOrganization') }}
</span>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
{% endblock %}

{% block body %}
<a href="{{ path('app_organization_assets') }}">{{ 'common.backToList' | trans }}</a>

<h1>{{ 'organization.asset.availabilities' | trans ({ '%asset%' : asset }) }}</h1>

{% include 'availability/_table.html.twig' with { availabilityType: 'assets', availabilityId: asset.id } %}
Expand Down
2 changes: 2 additions & 0 deletions templates/organization/commissionable_asset/form.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

{% block body %}

<a href="{{ path('app_organization_assets') }}">{{ 'common.backToList' | trans }}</a>

{% if asset.id %}
<a
class="btn btn-outline-danger trigger-delete float-right"
Expand Down
2 changes: 2 additions & 0 deletions templates/organization/user/edit.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
{% endblock %}

{% block body %}
<a href="{{ path('app_organization_user_list') }}">{{ 'common.backToList' | trans }}</a>

<h1>{{ 'organization.editUserProfile' | trans }}</h1>

<div class="float-right">
Expand Down
16 changes: 16 additions & 0 deletions templates/user/index.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@

<hr class="mt-5">

<h3 class="mb-5">{{ 'nav.section.organization'|trans }}</h3>

{% if app.user.organizations|length %}
{% if app.user.password is empty %}
<p class="alert alert-danger">
<a href="{{ path('app_user_password') }}">{{ 'user.passwordRequired'|trans }}</a>
</p>
{% else %}
{% for organization in app.user.organizations %}
<p><a href="{{ path('app_organization_dashboard', {organization: organization.id}) }}" class="btn btn-danger">{{ organization.name }}</a></p>
{% endfor %}
{% endif %}
{% endif %}

<hr class="mt-5">

<h3 class="mb-5">{{ 'common.myAvailabilities'|trans }}</h3>

<p>
Expand Down
8 changes: 6 additions & 2 deletions translations/messages.fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ action:
edit: Modifier
loading: Chargement...
login: Connexion
promote: Promouvoir
revoke: Révoquer
promote: Promouvoir en tant qu'admin de %organization%
revoke: Révoquer les droits d'admin sur %organization%
impersonate: Usurper l'identité
search: Rechercher
searchQuery: Rechercher "%query%"
Expand Down Expand Up @@ -230,12 +230,15 @@ user:
editMyInfo: Modifier mes informations
editMyPassword: Modifier mon mot de passe
createMyPassword: Renseigner mon mot de passe
passwordRequired: Vous devez renseigner votre mot de passe afin d'administrer votre structure
email: E-mail
firstName: Prénom
identificationNumber: NIVOL
lastName: Nom
login: Numéro NIVOL ou Adresse e-mail
currentPassword: Mot de passe actuel
password: Mot de passe
confirmPassword: Confirmation du mot de passe
mobile: Numéro de téléphone portable
occupationTitle: Profession
occupation:
Expand All @@ -259,6 +262,7 @@ user:

# Symfony default translations
Submit: Enregistrer
Current password: Votre mot de passe actuel

register:
introduction: |
Expand Down

0 comments on commit 1c6b77b

Please sign in to comment.