Skip to content
Snippets Groups Projects
Commit 4ad16d5d authored by Sebastien's avatar Sebastien
Browse files

Merge branch 'tuleap-170-capsule-groups-should-be-own-by-user' into 'main'

tuleap-170-capsule-groups-should-be-own-by-user

See merge request !59
parents d887ca1c fb65bcad
No related branches found
No related tags found
1 merge request!59tuleap-170-capsule-groups-should-be-own-by-user
Pipeline #843 passed
Showing
with 596 additions and 137 deletions
......@@ -95,16 +95,15 @@ button[type=submit]{
.standard-button {
line-height: 40px;
margin: 30px 0 0 0;
padding: 0.5em 2em;
font-size: 14px;
text-transform: uppercase;
font-size: 16px;
font-weight: bold;
border: none;
color: #FFF !important;
border-radius: 3px;
background: #49AD9A;
box-shadow: 0 -2px 0 #3B8C7E inset;
flex-basis: auto;
}
.standard-button:hover {
......
......@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20220208145209 extends AbstractMigration
final class Version20220216153510 extends AbstractMigration
{
public function getDescription(): string
{
......@@ -20,8 +20,9 @@ final class Version20220208145209 extends AbstractMigration
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE `group` (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE `group` (id INT AUTO_INCREMENT NOT NULL, author INT NOT NULL, name VARCHAR(255) NOT NULL, INDEX IDX_6DC044C5BDAFD8C8 (author), UNIQUE INDEX UNIQ_6DC044C55E237E06BDAFD8C8 (name, author), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE group_capsule (group_id INT NOT NULL, capsule_id INT NOT NULL, INDEX IDX_4468F58FFE54D947 (group_id), INDEX IDX_4468F58F714704E9 (capsule_id), PRIMARY KEY(group_id, capsule_id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE `group` ADD CONSTRAINT FK_6DC044C5BDAFD8C8 FOREIGN KEY (author) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE group_capsule ADD CONSTRAINT FK_4468F58FFE54D947 FOREIGN KEY (group_id) REFERENCES `group` (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE group_capsule ADD CONSTRAINT FK_4468F58F714704E9 FOREIGN KEY (capsule_id) REFERENCES capsule (id) ON DELETE CASCADE');
}
......@@ -32,5 +33,9 @@ final class Version20220208145209 extends AbstractMigration
$this->addSql('ALTER TABLE group_capsule DROP FOREIGN KEY FK_4468F58FFE54D947');
$this->addSql('DROP TABLE `group`');
$this->addSql('DROP TABLE group_capsule');
$this->addSql('ALTER TABLE capsule CHANGE nom nom VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE link link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE edition_link edition_link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE password password VARCHAR(50) DEFAULT \'\' NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE invitation_editeur_capsule CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE reset_password_request CHANGE selector selector VARCHAR(20) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE hashed_token hashed_token VARCHAR(100) NOT NULL COLLATE `utf8_unicode_ci`');
$this->addSql('ALTER TABLE `user` CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE email_canonical email_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE name name VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE firstname firstname VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username username VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username_canonical username_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE roles roles LONGTEXT NOT NULL COLLATE `utf8_unicode_ci` COMMENT \'(DC2Type:json)\', CHANGE password password VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE salt salt VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`');
}
}
......@@ -12,8 +12,6 @@ use App\Helper\StringHelper;
use App\Repository\CapsuleRepository;
use App\Builder\CapsuleBuilder;
use App\Form\CreateCapsuleFormType;
use App\Repository\GroupRepository;
use ArrayObject;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
......@@ -57,7 +55,9 @@ class CapsuleController extends AbstractController
// get all capsules without any filter
$all_capsules = $current_user->getCapsules()->toArray();
$form = $this->createGroupFilterForm($current_user);
$groups = $this->prependGroupAllToUserGroups($current_user);
$form = $this->createForm(FilterByGroupFormType::class, ['groups' => $groups]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
......@@ -67,8 +67,8 @@ class CapsuleController extends AbstractController
throw new \Exception('Group not found');
}
if ($group->getId() !== Group::$ALL_GROUP_ID) {
$all_capsules = $group->getCapsulesIntersection($all_capsules);
if ($group->getId() !== Group::$GROUP_ALL_ID) {
$all_capsules = $group->getCapsules()->toArray();
}
}
......@@ -323,24 +323,27 @@ class CapsuleController extends AbstractController
return $capsule;
}
private function getDefaultGroup(): Group
private function createGroupAll(User $current_user): Group
{
$noGroup = new Group();
// TODO : to be translated
$noGroup->setName($this->translator->trans('groups.filter.no_filter'));
$noGroup->setId(Group::$ALL_GROUP_ID);
$group_all = new Group();
$group_all->setName($this->translator->trans('groups.filter.no_filter'));
$group_all->setId(Group::$GROUP_ALL_ID);
$group_all->setAuthor($current_user);
return $noGroup;
return $group_all;
}
private function createGroupFilterForm(User $current_user): FormInterface
/**
* @return array<Group>
*/
private function prependGroupAllToUserGroups(User $current_user): array
{
$groups = new ArrayObject($current_user->getGroups());
$groups = $groups->getArrayCopy();
array_unshift($groups, self::getDefaultGroup());
$group_all = $this->createGroupAll($current_user);
$author_groups_without_group_all = $current_user->getGroups()->toArray();
$groups[] = $group_all;
$groups = array_merge($groups, $author_groups_without_group_all);
return $this->createForm(FilterByGroupFormType::class, ['groups' => $groups]);
return $groups;
}
}
......@@ -6,11 +6,11 @@ use App\Entity\Capsule;
use App\Entity\Group;
use App\Entity\User;
use App\Form\CreateCapsuleGroupsFormType;
use App\Form\DeleteGroupFormType;
use App\Form\RemoveGroupFormType;
use App\Form\SelectCapsuleGroupsFormType;
use App\Repository\CapsuleRepository;
use App\Repository\GroupRepository;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
......@@ -39,9 +39,9 @@ class CapsuleGroupController extends AbstractController
}
/**
* @Route("/capsule/{capsule_id}/groups/edit", name="edit_capsule_groups")
* @Route("/my_groups", name="edit_user_groups")
*/
public function edit(int $capsule_id, Request $request): Response
public function editUserGroups(): Response
{
$current_user = $this->getUser();
......@@ -49,55 +49,105 @@ class CapsuleGroupController extends AbstractController
return $this->redirectToRoute('app_logout');
}
$capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]);
$groups = $current_user->getGroups()->toArray();
if (! $capsule instanceof Capsule) {
throw new \Exception("Capsule does not exist");
return $this->render('capsule/groups/user_groups.html.twig', [
'groups' => $groups
]);
}
/**
* @Route("my_groups/create", name="create_group")
*/
public function create(Request $request): Response
{
$current_user = $this->getUser();
if (! $current_user instanceof User) {
return $this->redirectToRoute('app_logout');
}
$groups = $capsule->getGroups();
$editor_groups_not_added = $this->getEditorGroupsNotAdded($current_user, $groups);
$group = new Group();
$group->setAuthor($current_user);
$form = $this->createForm(SelectCapsuleGroupsFormType::class, ['groups' => $editor_groups_not_added]);
$form = $this->createForm(CreateCapsuleGroupsFormType::class, $group);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$groups = $this->addGroups($form, $capsule);
$group = $this->createAGroup($form, $group);
$groups_names = [];
$this->addFlash(
'success',
$this->translator->trans(
'groups.create.success',
[
'group_name' => $group->getName()
]
)
);
foreach ($groups as $group) {
$groups_names[] = $group->getName();
return $this->redirectToRoute('edit_user_groups');
}
return $this->render('capsule/groups/create.html.twig', [
'createCapsuleGroupsForm' => $form->createView()
]);
}
/**
* @Route("/my_groups/{group_id}/delete", name="delete_group")
*/
public function deleteGroup(int $group_id, Request $request): Response
{
$current_user = $this->getUser();
if (! $current_user instanceof User) {
return $this->redirectToRoute('app_logout');
}
$group = $this->group_repository->findOneBy(['id' => $group_id]);
if (! $group instanceof Group) {
throw new \Exception('Group not found');
}
$form = $this->createForm(DeleteGroupFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$capsules = $group->getCapsules()->toArray();
foreach ($capsules as $capsule) {
$capsule->removeGroup($group);
$this->entity_manager->persist($capsule);
}
$current_user->removeGroup($group);
$this->entity_manager->persist($current_user);
$this->entity_manager->remove($group);
$this->entity_manager->flush();
$this->addFlash(
'success',
$this->translator->trans(
'groups.add.success',
'groups.general.delete.success',
[
'groups_names' => implode(",", $groups_names),
'capsule_name' => $capsule->getName()
'group_name' => $group->getName()
]
)
);
return $this->redirectToRoute('edit_capsule_groups', [
'capsule_id' => $capsule_id
]);
return $this->redirectToRoute('edit_user_groups');
}
return $this->render('capsule/groups/edit.html.twig', [
'selectCapsuleGroupsForm' => $form->createView(),
'capsule' => $capsule,
'groups' => $groups,
'existing_groups' => $editor_groups_not_added
return $this->render('capsule/groups/delete.html.twig', [
'deleteGroupForm' => $form->createView(),
'group_name' => $group->getName()
]);
}
/**
* @Route("capsule/{capsule_id}/groups/create", name="create_group")
* @Route("/capsule/{capsule_id}/groups/edit", name="edit_capsule_groups")
*/
public function create(int $capsule_id, Request $request): Response
public function edit(int $capsule_id, Request $request): Response
{
$current_user = $this->getUser();
......@@ -111,18 +161,31 @@ class CapsuleGroupController extends AbstractController
throw new \Exception("Capsule does not exist");
}
$form = $this->createForm(CreateCapsuleGroupsFormType::class);
$capsule_groups_by_author = $current_user->getGroupsByCapsule($capsule);
$author_capsule_groups_not_added = $capsule->getNotAddedGroupsByAuthor($current_user);
$form = $this->createForm(
SelectCapsuleGroupsFormType::class,
['groups' => $author_capsule_groups_not_added]
);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$group = $this->createAGroup($form, $capsule);
$capsule_groups = $this->addGroups($form, $capsule);
$groups_names = [];
foreach ($capsule_groups as $group) {
$groups_names[] = $group->getName();
}
$this->addFlash(
'success',
$this->translator->trans(
'groups.create.success',
'groups.add.success',
[
'group_name' => $group->getName()
'groups_names' => implode(",", $groups_names),
'capsule_name' => $capsule->getName()
]
)
);
......@@ -132,9 +195,11 @@ class CapsuleGroupController extends AbstractController
]);
}
return $this->render('capsule/groups/create.html.twig', [
'createCapsuleGroupsForm' => $form->createView(),
'capsule' => $capsule
return $this->render('capsule/groups/capsule_groups.html.twig', [
'selectCapsuleGroupsForm' => $form->createView(),
'capsule' => $capsule,
'groups' => $capsule_groups_by_author,
'groups_not_added' => $author_capsule_groups_not_added
]);
}
......@@ -167,6 +232,10 @@ class CapsuleGroupController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$capsule->removeGroup($group);
$this->entity_manager->persist($capsule);
$current_user->removeGroup($group);
$this->entity_manager->persist($current_user);
$group->removeCapsule($capsule);
$this->entity_manager->persist($group);
$this->entity_manager->flush();
$this->addFlash(
......@@ -217,34 +286,15 @@ class CapsuleGroupController extends AbstractController
return $groups;
}
private function createAGroup(FormInterface $form, Capsule $capsule): Group
{
private function createAGroup(
FormInterface $form,
Group $group
): Group {
$group_name = $form->get('name')->getData();
$group = new Group();
$group->setName($group_name);
$this->entity_manager->persist($group);
$capsule->addGroup($group);
$this->entity_manager->persist($capsule);
$this->entity_manager->flush();
return $group;
}
/**
* @param Collection<Group> $groups
* @return array<Group>
*/
private function getEditorGroupsNotAdded(User $current_user, Collection $groups): array
{
return array_udiff(
$current_user->getGroups(),
$groups->toArray(),
function ($obj_a, $obj_b) {
return $obj_a->getId() - $obj_b->getId();
}
);
}
}
......@@ -3,24 +3,51 @@
namespace App\DataFixtures;
use App\Entity\Group;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class GroupFixtures extends Fixture
class GroupFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
$group_all = new Group();
$group_all->setName("All");
$manager->persist($group_all);
$user_repository = $manager->getRepository(User::class);
$group_author_1 = $user_repository->findOneBy(['email' => "defaultUser@localhost.com"]);
if (! $group_author_1 instanceof User) {
throw new \Exception("User does not exist.");
}
$group_author_2 = $user_repository->findOneBy(['email' => "defaultUser2@localhost.com"]);
if (! $group_author_2 instanceof User) {
throw new \Exception("User does not exist.");
}
$group_pop_1 = $this->createGroup($group_author_1, "Pop", $manager);
$group_rock = $this->createGroup($group_author_1, "Rock", $manager);
$group_pop_2 = $this->createGroup($group_author_2, "Pop", $manager);
$author_1_capsules = $group_author_1->getCapsules();
$author_1_capsules->toArray()[0]->addGroup($group_pop_1);
$manager->flush();
}
/** @phpstan-ignore-next-line */
private function createGroup(User $author, string $group_name, ObjectManager $manager): Group
{
$group = new Group();
$group->setName($group_name);
$group->setAuthor($author);
$manager->persist($group);
return $group;
}
public function getDependencies(): array
{
return [
CapsuleFixtures::class,
UserFixtures::class,
];
}
}
......@@ -264,4 +264,18 @@ class Capsule
return $this;
}
/**
* @return array<Group>
*/
public function getNotAddedGroupsByAuthor(User $author): array
{
return array_udiff(
$author->getGroups()->toArray(),
$this->getGroups()->toArray(),
function ($obj1, $obj2) {
return $obj1->getId() - $obj2->getId();
}
);
}
}
......@@ -10,12 +10,17 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass=GroupRepository::class)
* @ORM\Table(name="`group`")
* @UniqueEntity(fields={"name"}, message="group.name.unique")
* @ORM\Table(name="`group`", uniqueConstraints={@ORM\UniqueConstraint(columns={"name", "author"})})
* @UniqueEntity(
* fields={"name", "author"},
* errorPath="name",
* message="group.name.unique"
* )
*/
class Group
{
public static int $ALL_GROUP_ID = -1;
public static int $GROUP_ALL_ID = -1;
/**
* @ORM\Id
* @ORM\GeneratedValue
......@@ -26,7 +31,15 @@ class Group
/**
* @ORM\Column(type="string", length=255)
*/
private string $name;
protected string $name;
/**
*
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="groups")
* @ORM\JoinColumn(name="author", referencedColumnName="id", nullable=false)
*
*/
protected User $author;
/**
* @var Collection<Capsule>
......@@ -61,6 +74,18 @@ class Group
return $this;
}
public function getAuthor(): User
{
return $this->author;
}
public function setAuthor(User $author): self
{
$this->author = $author;
return $this;
}
/**
* @return Collection|Capsule[]
*/
......@@ -97,19 +122,4 @@ class Group
return $this;
}
/**
* @param array<Capsule> $capsules
* @return array<Capsule>
*/
public function getCapsulesIntersection(array $capsules): array
{
return array_uintersect(
$capsules,
$this->getCapsules()->toArray(),
function ($obj_a, $obj_b) {
return $obj_a->getId() - $obj_b->getId();
}
);
}
}
......@@ -99,6 +99,12 @@ class User implements UserInterface, LegacyPasswordAuthenticatedUserInterface
*/
private Collection $capsules;
/**
* @var Collection<Group>
* @ORM\OneToMany(targetEntity="App\Entity\Group", mappedBy="author")
*/
private Collection $groups;
/**
* @var string $plainPassword plain password to store before hashing it
*/
......@@ -107,6 +113,7 @@ class User implements UserInterface, LegacyPasswordAuthenticatedUserInterface
public function __construct()
{
$this->capsules = new ArrayCollection();
$this->groups = new ArrayCollection();
$this->acceptGeneralConditions = false;
$this->isVerified = false;
$this->credentialExpired = false;
......@@ -301,19 +308,42 @@ class User implements UserInterface, LegacyPasswordAuthenticatedUserInterface
}
/**
* @return array<Group>
* @return Collection<Group>
*/
public function getGroups(): array
public function getGroups(): Collection
{
$editor_capsules = $this->getCapsules();
$existing_groups_for_current_editor = [];
foreach ($editor_capsules as $editor_capsule) {
$existing_groups_for_current_editor = array_merge(
$existing_groups_for_current_editor,
$editor_capsule->getGroups()->toArray()
);
return $this->groups;
}
public function setGroupAll(Group $group_all): void
{
$groups = $this->getGroups()->toArray();
array_unshift($groups, $group_all);
}
public function addGroup(Group $group): void
{
$this->groups[] = $group;
}
return $existing_groups_for_current_editor;
public function removeGroup(Group $group): User
{
$this->groups->removeElement($group);
return $this;
}
/**
* @param Capsule $capsule
* @return array<Group>
*/
public function getGroupsByCapsule(Capsule $capsule): array
{
return array_uintersect(
$this->getGroups()->toArray(),
$capsule->getGroups()->toArray(),
function ($obj1, $obj2) {
return $obj1->getId() - $obj2->getId();
}
);
}
}
<?php
namespace App\Form;
use App\Entity\Group;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DeleteGroupFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add(
'cancel',
ButtonType::class,
['label' => 'general.cancel_button',
'attr' => ['class' => 'button-cancel']
]
)
->add(
'delete',
SubmitType::class,
['label' => 'general.delete']
);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Group::class,
]);
}
}
......@@ -38,9 +38,11 @@
</h5>
<ul class="ps-0">
{% for group in groups %}
{% if group.getName() != 'All' %}
<li class="text-capitalize text-secondary list-unstyled p-1">
{% if group.getName() != 'groups.filter.no_filter'|trans %}
<li class="text-secondary list-unstyled p-1">
<span class="text-capitalize">
{{ group.getName() }}
</span>
-
<a href="/capsule/{{ capsule.getId() }}/groups/{{ group.getId() }}/remove" class="remove-link">
{{ 'groups.remove.link'|trans }}
......@@ -53,13 +55,7 @@
</div>
<div class="d-flex flex-column justify-content-center order-md-2 mb-4 col-sm-8 col-md-6 col-lg-5 col-xl-4">
<h5 class="mb-5">
<a href="/capsule/{{ capsule.getId() }}/groups/create" class="list-unstyled">
{{ 'groups.create.title'|trans }}
</a>
</h5>
{% if existing_groups is not empty %}
{% if groups_not_added is not empty %}
<div class="d-flex flex-column justify-content-center mb-4">
{{ form_start(selectCapsuleGroupsForm, {'attr': {novalidate: 'novalidate'}}) }}
{{ form_row(selectCapsuleGroupsForm.name, {'row_attr': {'class' : 'm-auto mb-4'}}) }}
......
......@@ -23,7 +23,7 @@
<div class="d-flex flex-column flex-sm-row justify-content-center align-items-center align-items-sm-start">
{{ form_row(createCapsuleGroupsForm.validate, {'row_attr': {'class' : 'me-sm-3 mb-3'}}) }}
<a href="/capsule/{{ capsule.getId() }}/groups/edit">
<a href="/my_groups">
{{ form_row(createCapsuleGroupsForm.go_back) }}
</a>
</div>
......
{% extends 'layout.html.twig' %}
{% block title %}
{{ 'groups.general.delete.title'|trans }}
{% endblock %}
{% block body %}
<div>
<div class="row w-100 gx-0">
<div class="row-title-box">
<h3 class="row-title">
{{ 'groups.general.delete.title'|trans }}
</h3>
</div>
</div>
<div class="d-flex flex-column justify-content-center align-items-center">
<p class="text-secondary fs-5 mb-5">
{{ 'groups.general.delete.text'|trans({'%group_name%': group_name}) }}
</p>
{{ form_start(deleteGroupForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-row justify-content-center'}}) }}
{{ form_row(deleteGroupForm.delete, {'row_attr': {'class' : 'm-auto mb-2 me-3'}}) }}
<a href="/my_groups">
{{ form_row(deleteGroupForm.cancel, {'row_attr': {'class' : 'm-auto mb-2 bg-secondary rounded ms-3'}}) }}
</a>
{{ form_end(deleteGroupForm) }}
</div>
</div>
{% endblock %}
\ No newline at end of file
{% extends 'layout.html.twig' %}
{% block title %}
{{ 'groups.general.title'|trans }}
-
{{ parent() }}
{% endblock %}
{% block body %}
<div>
<div class="row w-100 gx-0">
<div class="row-title-box">
<h3 class="row-title">
{{ 'groups.general.title'|trans }}
</h3>
</div>
</div>
{% for flashWarning in app.flashes('warning') %}
<div class="text-center alert alert-warning col-5 mx-auto my-5 mt-2" role="alert">
{{ flashWarning }}
</div>
{% endfor %}
{% for flashSuccess in app.flashes('success') %}
<div class="text-center alert alert-success col-5 mx-auto my-5 mt-2" role="alert">
{{ flashSuccess }}
</div>
{% endfor %}
<div class="d-flex flex-md-row flex-column justify-content-center">
<div class="d-flex flex-row pe-md-5 fw-normal me-0 me-md-5">
<div class="pe-3 pe-md-4 text-nowrap">
<h5>
{{ 'groups.general.all'|trans }}
</h5>
<ul class="ps-0">
{% for group in groups %}
{% if group.getName() != 'groups.filter.no_filter'|trans %}
<li class="text-secondary list-unstyled p-1">
<span class="text-capitalize">
{{ group.getName() }}
</span>
-
<a href="/my_groups/{{ group.getId() }}/delete" class="remove-link">
{{ 'general.delete'|trans }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
</div>
<div class="d-flex align-items-center mt-3 mt-md-0">
<button type="submit" class="p-2">
<a href="/my_groups/create" class="list-unstyled text-decoration-none text-white">
{{ 'groups.create.title'|trans }}
</a>
</button>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
......@@ -14,6 +14,7 @@
</h2>
{% if app.request.query.get('page')|default(1) == 1 %}
{% if current_user.getGroups()|length > 1 %}
<div class="mb-3 mb-sm-0">
{{ form_start(filterByGroupForm, {'attr': {novalidate: 'novalidate', 'class': 'd-flex flex-column flex-sm-row mb-0 align-items-center pt-3'}}) }}
{{ form_row(filterByGroupForm.name, {'attr': {'class': ''}}) }}
......@@ -21,6 +22,7 @@
{{ form_end(filterByGroupForm) }}
</div>
{% endif %}
{% endif %}
<form class="d-flex mb-4 mb-lg-0">
<button id="btn-orange" formaction="/create">
......
......@@ -25,9 +25,14 @@
</a>
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
<div id="user-block">
<div id="user-block" class="d-flex flex-column">
<div id="user-block-nom">{{ app.user.firstName }} {{ app.user.lastName }}</div>
<a href="{{ path('show_profile') }}" class="text-decoration-none fs-5">My profile</a>
<a href="{{ path('show_profile') }}" class="text-decoration-none fs-5">
{{ 'user.profile.title'|trans }}
</a>
<a href="{{ path('edit_user_groups') }}" class="text-decoration-none fs-5">
{{ 'groups.general.title'|trans }}
</a>
<form>
<button class="btn btn-primary" formaction="/logout">
{{ 'general.log_out'|trans }}
......
......@@ -30,7 +30,6 @@ class CapsuleEditorControllerTest extends WebTestCase
->get('doctrine')
->getManager();
$this->user_repository = $this->object_manager->getRepository(User::class);
$this->capsule_repository = $this->object_manager->getRepository(Capsule::class);
......
<?php
namespace App\Tests\functional;
use App\Entity\Capsule;
use App\Entity\Group;
use App\Entity\User;
use App\Repository\CapsuleRepository;
use App\Repository\GroupRepository;
use App\Repository\UserRepository;
use Doctrine\Persistence\ObjectManager;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class CapsuleGroupControllerTest extends WebTestCase
{
private KernelBrowser $client;
private ObjectManager $object_manager;
private UserRepository $user_repository; /** @phpstan-ignore-line */
private CapsuleRepository $capsule_repository; /** @phpstan-ignore-line */
private GroupRepository $group_repository;
private User $user_1;
private User $user_2;
private Group $group_pop_own_by_user_1;
private Group $group_rock_own_by_user_1;
protected function setUp(): void
{
self::ensureKernelShutdown();
$this->client = static::createClient();
$this->object_manager = $this->client->getContainer()
->get('doctrine')
->getManager();
$this->user_repository = $this->object_manager->getRepository(User::class);
$this->capsule_repository = $this->object_manager->getRepository(Capsule::class);
$this->group_repository = $this->object_manager->getRepository(Group::class);
$this->setUsers();
$this->setCapsuleGroupPop();
$this->setCapsuleGroupRock();
}
protected function tearDown(): void
{
parent::tearDown();
self::ensureKernelShutdown();
}
public function testUserShouldNotBeAbleToCreateACapsuleGroupWithExistingGroupName(): void
{
$this->client->loginUser($this->user_1);
$uri = '/my_groups/create';
$crawler = $this->client->request('GET', $uri);
$this->assertResponseIsSuccessful();
$this->client->enableProfiler();
$submit_button = $crawler->selectButton('Create a new group');
$form = $submit_button->form();
$this->assertContains($this->group_pop_own_by_user_1, $this->user_1->getGroups()->toArray());
$form['create_capsule_groups_form[name]'] = $this->group_pop_own_by_user_1->getName();
$this->client->submit($form);
$this->assertFalse($this->client->getResponse()->isRedirect());
}
public function testUserShouldBeAbleToCreateACapsuleGroupWithTheSameGroupNameUsedByAnotherUser(): void
{
$this->client->loginUser($this->user_2);
$uri = '/my_groups/create';
$crawler = $this->client->request('GET', $uri);
$this->assertResponseIsSuccessful();
$this->client->enableProfiler();
$submit_button = $crawler->selectButton('Create a new group');
$form = $submit_button->form();
$this->assertContains($this->group_pop_own_by_user_1, $this->user_1->getGroups()->toArray());
$form['create_capsule_groups_form[name]'] = $this->group_rock_own_by_user_1->getName();
$this->client->submit($form);
$this->assertTrue($this->client->getResponse()->isRedirect());
}
private function setUsers(): void
{
$verified_user_1 = $this->user_repository
->findOneBy(['email' => 'defaultUser@localhost.com']);
if (! $verified_user_1 instanceof User) {
throw new \Exception("User does not exist.");
}
$this->user_1 = $verified_user_1;
$user_2 = $this->user_repository
->findOneBy(['email' => 'defaultUser2@localhost.com']);
if (! $user_2 instanceof User) {
throw new \Exception("User does not exist.");
}
$this->user_2 = $user_2;
}
private function setCapsuleGroupPop(): void
{
$group_pop = $this->group_repository->findOneBy(['name' => 'Pop', 'author' => $this->user_1]);
if (! $group_pop instanceof Group) {
throw new \Exception("Group does not exist.");
}
$this->group_pop_own_by_user_1 = $group_pop;
}
private function setCapsuleGroupRock(): void
{
$group_rock = $this->group_repository->findOneBy(['name' => 'Rock', 'author' => $this->user_1]);
if (! $group_rock instanceof Group) {
throw new \Exception("Group does not exist.");
}
$this->group_rock_own_by_user_1 = $group_rock;
}
}
......@@ -9,6 +9,7 @@ general:
greeting: Cheers!
validate: Validate
save: Save
delete: Delete
login:
account_disabled_feedback: Your user account is disabled. Please click on the link your receive by email to validate your registration.
......@@ -159,6 +160,13 @@ editors:
If you want to remove the capsule from your list, go to the capsule list page and click on "delete capsule"
groups:
general:
title: My groups
all: All groups
delete:
title: Delete
text: Do you really want to delete group %group_name%?
success: Group group_name deleted successfully
list:
title: Capsule groups
edit:
......@@ -169,7 +177,7 @@ groups:
success: Group group_name has been created and added to the capsule successfully
name: Choose a new group name
validate: Create a new group
go_back: Go back to capsule groups
go_back: Go back to my groups
add:
success: Group(s) groups_names has/have been added successfully to capsule capsule_name
validate: Add theses groups to the capsule
......
......@@ -9,6 +9,7 @@ general:
greeting: Salutation !
validate: Valider
save: Enregistrer
delete: Supprimer
login:
account_disabled_feedback: Le compte utilisateur a été désactivé. Veuillez cliquer sur le lien pour recevoir un courriel de validation
......@@ -158,6 +159,13 @@ editors:
Si vous voulez enlever la capsule de votre liste, allez sur la page qui affiche la liste de vos capsules et cliquer sur "supprimer la capsule"
groups:
general:
title: Mes groupes
all: Tous les groupes
delete:
title: Supprimer le groupe
text: Souhaitez-vous vraiment supprimer le groupe %group_name% ?
success: Le groupe group_name a bien été supprimé
list:
title: Groupes de la capsule
edit:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment