WIP: create and edit calendar

This commit is contained in:
Julien Fastré 2022-05-11 17:47:33 +02:00
parent f4b1a25a67
commit c60a54eb39
11 changed files with 217 additions and 69 deletions

View File

@ -17,6 +17,7 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterfa
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
@ -36,20 +37,22 @@ use Symfony\Component\Serializer\SerializerInterface;
class CalendarController extends AbstractController
{
protected AuthorizationHelper $authorizationHelper;
private AuthorizationHelper $authorizationHelper;
protected EventDispatcherInterface $eventDispatcher;
private EventDispatcherInterface $eventDispatcher;
protected LoggerInterface $logger;
private LoggerInterface $logger;
protected PaginatorFactory $paginator;
private PaginatorFactory $paginator;
protected SerializerInterface $serializer;
private SerializerInterface $serializer;
private CalendarRepository $calendarRepository;
private RemoteCalendarConnectorInterface $remoteCalendarConnector;
private UserRepository $userRepository;
public function __construct(
AuthorizationHelper $authorizationHelper,
CalendarRepository $calendarRepository,
@ -57,7 +60,8 @@ class CalendarController extends AbstractController
LoggerInterface $logger,
PaginatorFactory $paginator,
RemoteCalendarConnectorInterface $remoteCalendarConnector,
SerializerInterface $serializer
SerializerInterface $serializer,
UserRepository $userRepository
) {
$this->authorizationHelper = $authorizationHelper;
$this->calendarRepository = $calendarRepository;
@ -66,6 +70,7 @@ class CalendarController extends AbstractController
$this->paginator = $paginator;
$this->remoteCalendarConnector = $remoteCalendarConnector;
$this->serializer = $serializer;
$this->userRepository = $userRepository;
}
/**
@ -277,8 +282,13 @@ class CalendarController extends AbstractController
// }
$entity = new Calendar();
$entity->setUser($this->getUser());
$entity->setStatus($entity::STATUS_VALID);
if ($request->query->has('mainUser')) {
$entity->setMainUser($this->userRepository->find($request->query->getInt('mainUser')));
} else {
$entity->setMainUser($this->getUser());
}
dump($entity);
// if ($user instanceof User) {
// $entity->setPerson($user);

View File

@ -13,6 +13,10 @@ namespace Chill\CalendarBundle\Entity;
use Chill\ActivityBundle\Entity\Activity;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\User;
@ -35,8 +39,12 @@ use function in_array;
* @ORM\Table(name="chill_calendar.calendar")
* @ORM\Entity(repositoryClass=CalendarRepository::class)
*/
class Calendar
class Calendar implements TrackCreationInterface, TrackUpdateInterface
{
use TrackCreationTrait;
use TrackUpdateTrait;
public const STATUS_CANCELED = 'canceled';
public const STATUS_MOVED = 'moved';
@ -82,12 +90,15 @@ class Calendar
* @ORM\Column(type="integer")
* @Serializer\Groups({"calendar:read"})
*/
private ?int $id;
private ?int $id = null;
/**
* @ORM\ManyToMany(
* targetEntity="Invite",
* cascade={"persist", "remove", "merge", "detach"})
* @ORM\OneToMany(
* targetEntity=Invite::class,
* mappedBy="calendar",
* orphanRemoval=true,
* cascade={"persist", "remove", "merge", "detach"}
* )
* @ORM\JoinTable(name="chill_calendar.calendar_to_invites")
* @Groups({"read"})
*/
@ -137,16 +148,9 @@ class Calendar
private ?DateTimeImmutable $startDate = null;
/**
* @ORM\Column(type="string", length=255)
* @ORM\Column(type="string", length=255, nullable=false, options={"default": "valid"})
*/
private ?string $status = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
* @Groups({"read"})
* @Serializer\Groups({"calendar:read"})
*/
private ?User $user = null;
private string $status = self::STATUS_VALID;
public function __construct()
{
@ -156,29 +160,28 @@ class Calendar
$this->invites = new ArrayCollection();
}
public function addInvite(?Invite $invite): self
public function addInvite(Invite $invite): self
{
if (null !== $invite) {
if ($invite->getCalendar() instanceof Calendar && $this !== $invite->getCalendar()) {
throw new \LogicException('Not allowed to move an invitation to another Calendar');
}
$this->invites[] = $invite;
}
$invite->setCalendar($this);
return $this;
}
public function addPerson(?Person $person): self
public function addPerson(Person $person): self
{
if (null !== $person) {
$this->persons[] = $person;
}
return $this;
}
public function addProfessional(?ThirdParty $professional): self
public function addProfessional(ThirdParty $professional): self
{
if (null !== $professional) {
$this->professionals[] = $professional;
}
return $this;
}
@ -428,10 +431,5 @@ class Calendar
return $this;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
}

View File

@ -12,6 +12,10 @@ declare(strict_types=1);
namespace Chill\CalendarBundle\Entity;
use Chill\CalendarBundle\Repository\InviteRepository;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
@ -19,31 +23,54 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Table(name="chill_calendar.invite")
* @ORM\Entity(repositoryClass=InviteRepository::class)
*/
class Invite
class Invite implements TrackUpdateInterface, TrackCreationInterface
{
use TrackCreationTrait;
use TrackUpdateTrait;
public const ACCEPTED = 'accepted';
public const DECLINED = 'declined';
public const PENDING = 'pending';
public const TENTATIVELY_ACCEPTED = 'tentative';
/**
* @ORM\ManyToOne(targetEntity=Calendar::class, inversedBy="invites")
*/
private ?Calendar $calendar;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
private ?int $id;
/**
* @ORM\Column(type="json")
* @ORM\Column(type="text", nullable=false, options={"default": "pending"})
*/
private array $status = [];
private string $status = self::PENDING;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
* @ORM\JoinColumn(nullable=false)
*/
private User $user;
private ?User $user;
public function getCalendar(): ?Calendar
{
return $this->calendar;
}
public function getId(): ?int
{
return $this->id;
}
public function getStatus(): ?array
public function getStatus(): string
{
return $this->status;
}
@ -53,7 +80,17 @@ class Invite
return $this->user;
}
public function setStatus(array $status): self
/**
* @internal use Calendar::addInvite instead
* @param Calendar|null $calendar
* @return void
*/
public function setCalendar(?Calendar $calendar): void
{
$this->calendar = $calendar;
}
public function setStatus(string $status): self
{
$this->status = $status;

View File

@ -18,6 +18,7 @@ use Chill\CalendarBundle\Entity\Invite;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
@ -67,23 +68,13 @@ class CalendarType extends AbstractType
'expanded' => true,
]);
$builder->add('mainUser', HiddenType::class);
$builder->get('mainUser')
->addModelTransformer(new CallbackTransformer(
static function (?User $user): int {
if (null !== $user) {
$res = $user->getId();
} else {
$res = -1; //TODO cannot be null in any ways...
if ($options['data'] instanceof Calendar && $options['data']->getId() === null) {
$builder->add('mainUser', PickUserDynamicType::class, [
'required' => true,
'help' => 'chill_calendar.form.The main user is mandatory. He will organize the appointment.',
]);
}
return $res;
},
function (?int $userId): User {
return $this->om->getRepository(user::class)->findOneBy(['id' => (int) $userId]);
}
));
$builder->add('startDate', HiddenType::class);
$builder->get('startDate')
->addModelTransformer(new CallbackTransformer(

View File

@ -3,9 +3,6 @@
{{ form_start(form) }}
{{ form_errors(form) }}
{%- if form.mainUser is defined -%}
{{ form_row(form.mainUser) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>

View File

@ -118,10 +118,17 @@
{% endif %}
<ul class="record_actions">
<ul class="record_actions sticky-form-buttons">
{% if accompanyingCourse.user is not same as(null) %}
<li>
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id, 'mainUser': accompanyingCourse.user.id }) }}" class="btn btn-create">
{{ 'chill_calendar.Create for referrer'|trans }}
</a>
</li>
{% endif %}
<li>
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create">
{{ 'Add a new calendar' | trans }}
{{ 'Create'|trans }}
</a>
</li>
</ul>

View File

@ -3,12 +3,13 @@
{{ form_start(form) }}
{{ form_errors(form) }}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if form.mainUser is defined -%}
{{ form_row(form.mainUser) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if form.persons is defined -%}
{{ form_widget(form.persons) }}
{% endif %}

View File

@ -15,6 +15,7 @@
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
@ -28,6 +29,7 @@
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block block_post_menu %}

View File

@ -0,0 +1,87 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\Migrations\Calendar;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20220511134619 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('CREATE TABLE chill_calendar.calendar_to_invites (calendar_id INT NOT NULL, invite_id INT NOT NULL, PRIMARY KEY(calendar_id, invite_id))');
$this->addSql('CREATE INDEX idx_fcbeaaaea417747 ON chill_calendar.calendar_to_invites (invite_id)');
$this->addSql('CREATE INDEX idx_fcbeaaaa40a2c8 ON chill_calendar.calendar_to_invites (calendar_id)');
$this->addSql('ALTER TABLE chill_calendar.calendar_to_invites ADD CONSTRAINT fk_fcbeaaaa40a2c8 FOREIGN KEY (calendar_id) REFERENCES chill_calendar.calendar (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.calendar_to_invites ADD CONSTRAINT fk_fcbeaaaea417747 FOREIGN KEY (invite_id) REFERENCES chill_calendar.invite (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.invite DROP CONSTRAINT FK_F517FFA7A40A2C8');
$this->addSql('ALTER TABLE chill_calendar.invite DROP CONSTRAINT FK_F517FFA73174800F');
$this->addSql('ALTER TABLE chill_calendar.invite DROP CONSTRAINT FK_F517FFA765FF1AEC');
$this->addSql('DROP INDEX chill_calendar.IDX_F517FFA7A40A2C8');
$this->addSql('DROP INDEX chill_calendar.IDX_F517FFA73174800F');
$this->addSql('DROP INDEX chill_calendar.IDX_F517FFA765FF1AEC');
$this->addSql('ALTER TABLE chill_calendar.invite DROP calendar_id');
$this->addSql('ALTER TABLE chill_calendar.invite DROP createdAt');
$this->addSql('ALTER TABLE chill_calendar.invite DROP updatedAt');
$this->addSql('ALTER TABLE chill_calendar.invite DROP createdBy_id');
$this->addSql('ALTER TABLE chill_calendar.invite DROP updatedBy_id');
$this->addSql('ALTER TABLE chill_calendar.invite ALTER user_id DROP NOT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite DROP COLUMN status');
$this->addSql('ALTER TABLE chill_calendar.invite ADD COLUMN status JSON');
$this->addSql('ALTER TABLE chill_calendar.invite ALTER status DROP DEFAULT');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315AC3174800F');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315AC65FF1AEC');
$this->addSql('DROP INDEX chill_calendar.IDX_712315AC3174800F');
$this->addSql('DROP INDEX chill_calendar.IDX_712315AC65FF1AEC');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP createdAt');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP updatedAt');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP createdBy_id');
$this->addSql('ALTER TABLE chill_calendar.calendar DROP updatedBy_id');
}
public function getDescription(): string
{
return 'Prepare schema for handling calendar invites';
}
public function up(Schema $schema): void
{
$this->addSql('DROP TABLE chill_calendar.calendar_to_invites');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD createdBy_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD updatedBy_id INT DEFAULT NULL');
$this->addSql('COMMENT ON COLUMN chill_calendar.calendar.createdAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_calendar.calendar.updatedAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315AC3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315AC65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_712315AC3174800F ON chill_calendar.calendar (createdBy_id)');
$this->addSql('CREATE INDEX IDX_712315AC65FF1AEC ON chill_calendar.calendar (updatedBy_id)');
$this->addSql('ALTER TABLE chill_calendar.invite ADD calendar_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite ADD updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite ADD createdBy_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite ADD updatedBy_id INT DEFAULT NULL');
$this->addSql('DELETE FROM chill_calendar.invite WHERE user_id IS NULL');
$this->addSql('ALTER TABLE chill_calendar.invite ALTER user_id SET NOT NULL');
$this->addSql('ALTER TABLE chill_calendar.invite DROP COLUMN status');
$this->addSql('ALTER TABLE chill_calendar.invite ADD COLUMN status TEXT DEFAULT \'pending\'');
$this->addSql('COMMENT ON COLUMN chill_calendar.invite.createdAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_calendar.invite.updatedAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('ALTER TABLE chill_calendar.invite ADD CONSTRAINT FK_F517FFA7A40A2C8 FOREIGN KEY (calendar_id) REFERENCES chill_calendar.calendar (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.invite ADD CONSTRAINT FK_F517FFA73174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.invite ADD CONSTRAINT FK_F517FFA765FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_F517FFA7A40A2C8 ON chill_calendar.invite (calendar_id)');
$this->addSql('CREATE INDEX IDX_F517FFA73174800F ON chill_calendar.invite (createdBy_id)');
$this->addSql('CREATE INDEX IDX_F517FFA765FF1AEC ON chill_calendar.invite (updatedBy_id)');
}
}

View File

@ -27,6 +27,11 @@ From the day: Du
to the day: au
Transform to activity: Transformer en échange
chill_calendar:
form:
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
Create for referrer: Créer pour le référent
remote_ms_graph:
freebusy_statuses:
busy: Occupé

View File

@ -216,8 +216,21 @@
{% endif %}
{% endblock %}
{% block pick_entity_dynamic_widget %}
{% block pick_entity_dynamic_row %}
<div class="row">
<div class="col-md-12">
{{ form_label(form) }}
{{ form_help(form) }}
</div>
</div>
<div class="row justify-content-end">
<div class="col-md-7 col-sm-12">
{{ form_widget(form) }}
</div>
</div>
{% endblock %}
{% block pick_entity_dynamic_widget %}
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
<div data-module="pick-dynamic" data-types="{{ form.vars['types']|json_encode }}" data-multiple="{{ form.vars['multiple'] }}" data-uniqid="{{ form.vars['uniqid'] }}"></div>
{% endblock %}