add conferences, debriefings, projects, theme types, establishment groups

This commit is contained in:
Simon Vieille 2022-04-15 16:45:58 +02:00
parent dcefee3d38
commit 2a1a7d40f5
Signed by: deblan
GPG key ID: 03383D15A1D31745
18 changed files with 3198 additions and 546 deletions

4
.env
View file

@ -19,8 +19,8 @@ APP_SECRET=
###< symfony/framework-bundle ###
###> symfony/mailer ###
MAILER_DSN=smtp://mail.deblan.org:1666?verify_peer=false
MAILER_FROM=webtinternetsuiviinter@deblan.fr
MAILER_DSN=smtp://localhost
MAILER_FROM=contact@example.com
###< symfony/mailer ###
###> doctrine/doctrine-bundle ###

View file

@ -1,5 +1,6 @@
import '../../vendor/murph/murph-core/src/core/Resources/assets/js/admin.js'
const Sortable = require('sortablejs').Sortable
const Routing = require('../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js')
const routes = require('../../public/js/fos_js_routes.json')
@ -83,4 +84,28 @@ class AddressAutocomplete {
}
}
const addressAutocomplete = new AddressAutocomplete()
class FilesCollectionSorter {
constructor () {
const collections = document.querySelectorAll('div[data-collection^="collection-files"]')
for (const collection of collections) {
return new Sortable(collection, {
handle: '*[data-collection-item]',
sort: true,
animation: 150,
fallbackTolerance: 3,
onEnd: (e) => {
const positions = collection.querySelectorAll('*[data-collection-item] input[type=hidden]')
console.log(positions);
for (let u = 0; u < positions.length; u++) {
positions[u].value = u
}
}
})
}
}
}
new AddressAutocomplete()
new FilesCollectionSorter()

View file

@ -7,7 +7,7 @@
"prefer-stable": true,
"require": {
"php": ">=8.0.0",
"murph/murph-core": "^1.0"
"murph/murph-core": "dev-master"
},
"require-dev": {
"symfony/browser-kit": "^5.4",

View file

@ -38,5 +38,5 @@ core:
# - text/css
# path: "%kernel.project_dir%/public/uploads"
# path_uri: "/uploads"
# path_locked:
# - "%kernel.project_dir%/public/uploads"
path_locked: []
# - "%kernel.project_dir%/public/uploads"

View file

@ -120,6 +120,8 @@ class EstablishmentAdminController extends CrudController
->setForm('new', Type::class)
// ->setForm('filter', Type::class)
->setView('form', 'admin/establishment/_form.html.twig')
// ->setMaxPerPage('index', 20)
// ->setIsSortableCollection('index', false)

View file

@ -125,9 +125,13 @@ class InterventionAdminController extends CrudController
->setView('form', 'admin/intervention/_form.html.twig')
->setField('index', 'Establishment', Field\TextField::class, [
'property' => 'establishment',
'sort' => ['establishment', '.establishment'],
->setField('index', 'Establishments', Field\TextField::class, [
'property_builder' => function(EntityInterface $entity) {
return implode('<br>', array_map(function($e) {
return $e->getName();
}, $entity->getEstablishments()->toArray()));
},
'raw' => true,
])
->setField('index', 'Activity reference', Field\ButtonField::class, [
'property' => 'activityReference',
@ -137,6 +141,7 @@ class InterventionAdminController extends CrudController
])
->setField('index', 'Date', Field\DateField::class, [
'property' => 'date',
'format' => 'd/m/Y',
'sort' => ['date', '.date'],
'attr' => ['class' => 'col-3'],
])

View file

@ -124,6 +124,7 @@ class ToolAdminController extends CrudController
'property' => 'label',
'sort' => ['label', '.label'],
])
->setDefaultSort('index', 'label', 'asc')
->setBatchAction('index', 'delete', 'Delete', function(EntityInterface $entity, EntityManager $manager) {
$manager->delete($entity);

View file

@ -18,36 +18,42 @@ class Establishment implements EntityInterface
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
protected $name;
/**
* @ORM\Column(type="string", length=255)
*/
private $address;
protected $address;
/**
* @ORM\Column(type="string", length=10)
*/
private $zipCode;
protected $zipCode;
/**
* @ORM\Column(type="string", length=100)
*/
private $city;
protected $city;
/**
* @ORM\OneToMany(targetEntity=Intervention::class, mappedBy="establishment")
* @ORM\OneToMany(targetEntity=EstablishmentGroup::class, mappedBy="establishment", orphanRemoval=true, cascade={"persist", "remove"})
*/
private $interventions;
protected $establishmentGroups;
/**
* @ORM\ManyToMany(targetEntity=Project::class, mappedBy="establishments")
*/
protected $projects;
public function __construct()
{
$this->interventions = new ArrayCollection();
$this->establishmentGroups = new ArrayCollection();
$this->projects = new ArrayCollection();
}
public function __toString()
@ -109,32 +115,59 @@ class Establishment implements EntityInterface
}
/**
* @return Collection<int, Intervention>
* @return Collection<int, EstablishmentGroup>
*/
public function getInterventions(): Collection
public function getEstablishmentGroups(): Collection
{
return $this->interventions;
return $this->establishmentGroups;
}
public function addIntervention(Intervention $intervention): self
public function addEstablishmentGroup(EstablishmentGroup $establishmentGroup): self
{
if (!$this->interventions->contains($intervention)) {
$this->interventions[] = $intervention;
$intervention->setEstablishment($this);
if (!$this->establishmentGroups->contains($establishmentGroup)) {
$this->establishmentGroups[] = $establishmentGroup;
$establishmentGroup->setEstablishment($this);
}
return $this;
}
public function removeIntervention(Intervention $intervention): self
public function removeEstablishmentGroup(EstablishmentGroup $establishmentGroup): self
{
if ($this->interventions->removeElement($intervention)) {
if ($this->establishmentGroups->removeElement($establishmentGroup)) {
// set the owning side to null (unless already changed)
if ($intervention->getEstablishment() === $this) {
$intervention->setEstablishment(null);
if ($establishmentGroup->getEstablishment() === $this) {
$establishmentGroup->setEstablishment(null);
}
}
return $this;
}
/**
* @return Collection<int, Project>
*/
public function getProjects(): Collection
{
return $this->projects;
}
public function addProject(Project $project): self
{
if (!$this->projects->contains($project)) {
$this->projects[] = $project;
$project->addEstablishment($this);
}
return $this;
}
public function removeProject(Project $project): self
{
if ($this->projects->removeElement($project)) {
$project->removeEstablishment($this);
}
return $this;
}
}

View file

@ -18,73 +18,84 @@ class Intervention implements EntityInterface
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
protected $id;
/**
* @ORM\ManyToMany(targetEntity=Speaker::class, inversedBy="interventions")
*/
private $speakers;
/**
* @ORM\ManyToOne(targetEntity=Establishment::class, inversedBy="interventions")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
*/
private $establishment;
protected $speakers;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $activityReference;
protected $activityReference;
/**
* @ORM\Column(type="date", nullable=true)
*/
private $date;
protected $date;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $groups;
protected $groups;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $levels;
protected $levels;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $themes;
protected $themes;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $content;
protected $content;
/**
* @ORM\ManyToMany(targetEntity=Tool::class, inversedBy="interventions")
*/
private $tools;
protected $tools;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $toolsDetails;
protected $toolsDetails;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $feedback;
protected $feedback;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $vigilantPoints;
protected $vigilantPoints;
/**
* @ORM\ManyToOne(targetEntity=ThemeType::class, inversedBy="interventions")
* @ORM\JoinColumn(nullable=false)
*/
protected $themeType;
/**
* @ORM\Column(type="text", nullable=true)
*/
protected $comment;
/**
* @ORM\ManyToMany(targetEntity=EstablishmentGroup::class, inversedBy="interventions")
*/
protected $establishmentGroups;
public function __construct()
{
$this->speakers = new ArrayCollection();
$this->tools = new ArrayCollection();
$this->establishmentGroups = new ArrayCollection();
}
public function getId(): ?int
@ -116,18 +127,6 @@ class Intervention implements EntityInterface
return $this;
}
public function getEstablishment(): ?Establishment
{
return $this->establishment;
}
public function setEstablishment(?Establishment $establishment): self
{
$this->establishment = $establishment;
return $this;
}
public function getActivityReference(): ?string
{
return $this->activityReference;
@ -159,7 +158,7 @@ class Intervention implements EntityInterface
public function setGroups(?int $groups): self
{
$this->groups = $groups;
$this->groups = abs($groups);
return $this;
}
@ -259,4 +258,71 @@ class Intervention implements EntityInterface
return $this;
}
public function getThemeType(): ?ThemeType
{
return $this->themeType;
}
public function setThemeType(?ThemeType $themeType): self
{
$this->themeType = $themeType;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getEstablishments(): ArrayCollection
{
$data = new ArrayCollection();
foreach ($this->getEstablishmentGroups() as $group) {
if (!$data->contains($group->getEstablishment())) {
$data->add($group->getEstablishment());
}
}
$establishments = $data->toArray();
usort($establishments, function($a, $b) {
return $a->getName() <=> $b->getName();
});
return new ArrayCollection($establishments);
}
/**
* @return Collection<int, EstablishmentGroup>
*/
public function getEstablishmentGroups(): Collection
{
return $this->establishmentGroups;
}
public function addEstablishmentGroup(EstablishmentGroup $establishmentGroup): self
{
if (!$this->establishmentGroups->contains($establishmentGroup)) {
$this->establishmentGroups[] = $establishmentGroup;
}
return $this;
}
public function removeEstablishmentGroup(EstablishmentGroup $establishmentGroup): self
{
$this->establishmentGroups->removeElement($establishmentGroup);
return $this;
}
}

View file

@ -18,17 +18,17 @@ class Speaker implements EntityInterface
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
protected $name;
/**
* @ORM\ManyToMany(targetEntity=Intervention::class, mappedBy="speakers", cascade={"persist"})
*/
private $interventions;
protected $interventions;
public function __construct()
{

View file

@ -18,17 +18,17 @@ class Tool implements EntityInterface
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
protected $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $label;
protected $label;
/**
* @ORM\ManyToMany(targetEntity=Intervention::class, mappedBy="tools", cascade={"persist", "remove"})
*/
private $interventions;
protected $interventions;
public function __construct()
{

View file

@ -22,53 +22,53 @@ class User implements PasswordAuthenticatedUserInterface, UserInterface, TwoFact
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
protected $id;
/**
* @ORM\Column(type="string", length=180, unique=true)
*/
private $email;
protected $email;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
protected $roles = [];
/**
* @var string The hashed password
* @ORM\Column(type="string")
*/
private $password;
protected $password;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $displayName;
protected $displayName;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $totpSecret;
protected $totpSecret;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $passwordRequestedAt;
protected $passwordRequestedAt;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $confirmationToken;
protected $confirmationToken;
/**
* @ORM\Column(type="boolean", options={"default"=0})
*/
private $isAdmin;
protected $isAdmin;
/**
* @ORM\Column(type="boolean", options={"default"=0})
*/
private $isWriter;
protected $isWriter;
public function __construct()
{

View file

@ -2,6 +2,7 @@
namespace App\Form;
use App\Core\Form\Type\CollectionType;
use App\Entity\Establishment;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
@ -16,6 +17,14 @@ class EstablishmentType extends AbstractType
->add('address')
->add('zipCode')
->add('city')
->add('establishmentGroups', CollectionType::class, [
'collection_name' => 'establishment_groups',
'entry_type' => EstablishmentGroupType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'prototype' => true,
])
;
}

View file

@ -6,6 +6,9 @@ use App\Entity\Intervention;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use App\Entity\Establishment;
use Doctrine\ORM\EntityRepository;
class InterventionType extends AbstractType
{
@ -19,6 +22,7 @@ class InterventionType extends AbstractType
])
->add('groups')
->add('levels')
->add('themeType')
->add('themes', null, [
'attr' => ['rows' => 5],
])
@ -31,6 +35,9 @@ class InterventionType extends AbstractType
->add('toolsDetails', null, [
'attr' => ['rows' => 5],
])
->add('comment', null, [
'attr' => ['rows' => 7],
])
->add('feedback', null, [
'attr' => ['rows' => 5],
])
@ -40,7 +47,22 @@ class InterventionType extends AbstractType
->add('speakers', null, [
'expanded' => true,
])
->add('establishment')
->add('establishmentGroups', null, [
'multiple' => true,
'attr' => [
'size' => 15,
'data-jschoice' => '',
],
'group_by' => function($choice, $key, $value) {
return $choice->getEstablishment()->getName();
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('g')
->leftJoin('g.establishment', 'e')
->addOrderBy('e.name', 'ASC')
->addOrderBy('g.label', 'ASC');
},
])
;
}

View file

@ -1,11 +1,11 @@
<div class="row">
<div class="col-md-3">
{% for item in ['establishment', 'activityReference', 'date', 'groups', 'levels', 'speakers'] %}
{% for item in ['date', 'establishmentGroups', 'activityReference', 'groups', 'levels', 'speakers'] %}
{% include(configuration.view('form_widget', '@Core/admin/crud/_form_widget.html.twig')) with {form: form[item]} %}
{% endfor %}
</div>
<div class="col-md-9 pl-md-3">
{% for item in ['themes', 'content', 'tools', 'toolsDetails', 'feedback', 'vigilantPoints'] %}
<div class="col-md-9 pl-md-3 pr-md-3">
{% for item in ['themeType', 'themes', 'content', 'tools', 'toolsDetails', 'comment', 'feedback', 'vigilantPoints'] %}
{% include(configuration.view('form_widget', '@Core/admin/crud/_form_widget.html.twig')) with {form: form[item]} %}
{% endfor %}
</div>

View file

@ -1,5 +1,5 @@
{% if is_granted('ROLE_WRITER') %}
{{ include('@Core/admin/module/_menu_section.html.twig', {label: 'Interventions'}) }}
{{ include('@Core/admin/module/_menu_section.html.twig', {label: 'Configuration'}) }}
<ul class="nav flex-column">
{{ include('@Core/admin/module/_menu_item.html.twig', {
@ -15,6 +15,13 @@
route: path('admin_establishment_index'),
icon: 'fa fa-building'
}) }}
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'theme_type',
label: 'Types de thématiques',
route: path('admin_theme_type_index'),
icon: 'fa fa-dice-d6'
}) }}
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'tool',
@ -22,6 +29,17 @@
route: path('admin_tool_index'),
icon: 'fa fa-dice-d6'
}) }}
</ul>
{{ include('@Core/admin/module/_menu_section.html.twig', {label: 'Suivis'}) }}
<ul class="nav flex-column">
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'project',
label: 'Projets',
route: path('admin_project_index'),
icon: 'fa fa-box-open'
}) }}
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'intervention',
@ -29,5 +47,19 @@
route: path('admin_intervention_index'),
icon: 'fa fa-comment-dots'
}) }}
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'conference',
label: 'Conférences',
route: path('admin_conference_index'),
icon: 'fa fa-users'
}) }}
{{ include('@Core/admin/module/_menu_item.html.twig', {
id: 'debriefing',
label: 'Comptes-rendus',
route: path('admin_debriefing_index'),
icon: 'fa fa-list-alt'
}) }}
</ul>
{% endif %}

View file

@ -4,7 +4,10 @@
"Speaker": "Intervenant⋅e"
"Speakers": "Intervenant⋅e⋅s"
"Establishment": "Établissement"
"Establishments": "Établissements"
"Establishment groups": "Classes et groupes"
"Activity reference": "Activité de référence"
"Comment": "Commentaire"
"Groups": "Groupe(s)"
"Levels": "Niveau(x)"
"Themes": "Thématiques abordées"
@ -12,3 +15,9 @@
"Tools details": "Détails outils et supports"
"Feedback": "Les retours des participant⋅e⋅s"
"Vigilant points": "Point(s) de vigilance observé(s) par l'intervenant⋅e"
"Persons": "Personnes"
"Theme type": "Type de thématique"
"Topic": "Sujet"
"Project": "Projet"
"Internal contributors": "Contributeurs internes"
"External contributors": "Contributeurs externes"

3380
yarn.lock

File diff suppressed because it is too large Load diff