<?php
namespace App\EventSubscriber;
use App\Entity\User;
use App\Entity\JobQueue;
use App\Service\EsCache;
use App\Service\EsJobQueue;
use App\Handler\UserHandler;
use App\Entity\RoleContainer;
use App\Event\EsEventLogEvent;
use App\Event\UserPreRemoveEvent;
use App\Event\UserPreUpdateEvent;
use App\Event\UserPrePersistEvent;
use App\Event\UserPostPersistEvent;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
use App\Service\JobQueueAction\ElasticDependentUpdateAction;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserSubscriber implements EventSubscriberInterface
{
public function __construct(
private UserHandler $handler,
private UserPasswordHasherInterface $passwordEncoder,
private EntityManagerInterface $_em,
private EventDispatcherInterface $dispatcher,
private ValidatorInterface $validator,
private Security $security,
private EsJobQueue $esJobQueue,
private EsCache $esCache,
private $appEnvType
) {
}
public static function getSubscribedEvents(): array
{
return [
UserPostPersistEvent::NAME => 'onPostCreate',
UserPrePersistEvent::NAME => 'onPreCreate',
UserPreUpdateEvent::NAME => 'onPreUpdate',
UserPreRemoveEvent::NAME => 'onPreRemove'
];
}
public function onPostCreate(UserPostPersistEvent $event)
{
$object = $event->getObject();
$this->handler->assignContainerUserGroup($object);
$this->handler->attchUserToCompany([$object->getId()]);
$eventObj = new EsEventLogEvent($object, EsEventLogEvent::EVENT_USER_CREATE);
$this->dispatcher->dispatch($eventObj, EsEventLogEvent::EVENT_USER_CREATE);
}
public function onPreCreate(UserPrePersistEvent $event)
{
$object = $event->getObject();
$violations = $this->validator->validate($object);
if (count($violations) > 0) {
foreach ($violations as $v) {
throw new BadRequestHttpException($v->getMessage());
break;
}
}
if (empty($this->security->getUser())) {
return;
}
if (!$this->security->isGranted(RoleContainer::ROLE_ADMIN) && $this->security->isGranted(RoleContainer::ROLE_OPERATOR)) {
$allowRoles = [
RoleContainer::ROLE_SPEAKER,
RoleContainer::ROLE_MODERATOR,
RoleContainer::ROLE_OPERATOR
];
if (!in_array($object->getRole(), $allowRoles)) {
throw new AccessDeniedException();
}
}
$userContainer = $this->esCache->getContainer(false);
if (!$userContainer) {
throw new BadRequestHttpException("User creation container not found!");
}
$object->setUserContainer($userContainer);
$object->addNewsfeedContainerSubscription($userContainer);
if (($object->getIsConsiderSpeaker() && !$object->getIsDisplayAsGuest()) ||
($object->getIsConsiderModerator() && !$object->getIsDisplayAsGuest())) {
$object->setIsDisplayAsGuest(true);
}
if ($object->getIsConsiderSpeaker() || $object->getIsConsiderModerator()) {
$object->setIsOnboarded(true);
}
if ($object->getPlainPassword()) {
$object->setPassword(
$this->passwordEncoder->hashPassword($object, $object->getPlainPassword())
);
$object->eraseCredentials();
}
$object->setIsPwdGenerated(true);
$object->setIsEmailOff(false);
$object->setIsUnsubscribedInvite(false);
if ($object->getSpecialTitles()) {
foreach ($object->getSpecialTitles() as $title) {
$nfCategory = $title->getNewsfeedCategory();
if ($nfCategory) {
$object->addNewsfeedSubscription($nfCategory);
}
}
}
}
public function onPreUpdate(UserPreUpdateEvent $event)
{
$object = $event->getObject();
$violations = $this->validator->validate($object);
if (count($violations) > 0) {
foreach ($violations as $v) {
throw new BadRequestHttpException($v->getMessage());
break;
}
}
if ($object->getPlainPassword()) {
$object->setPassword(
$this->passwordEncoder->hashPassword($object, $object->getPlainPassword())
);
$object->eraseCredentials();
}
if (($object->getIsConsiderSpeaker() && !$object->getIsDisplayAsGuest()) ||
($object->getIsConsiderModerator() && !$object->getIsDisplayAsGuest())) {
$object->setIsDisplayAsGuest(true);
}
if ($object->getIsConsiderSpeaker() || $object->getIsConsiderModerator()) {
$object->setIsOnboarded(true);
}
if (empty($this->security->getUser())) {
return;
}
if ($object->getIsUpdateNewsfeedSubscriptions() && $object->getSpecialTitles()) {
foreach ($object->getSpecialTitles() as $title) {
$nfCategory = $title->getNewsfeedCategory();
if ($nfCategory) {
$object->addNewsfeedSubscription($nfCategory);
}
}
}
if (!$this->security->isGranted(RoleContainer::ROLE_ADMIN) && $this->security->isGranted(RoleContainer::ROLE_OPERATOR)) {
$allowRoles = [
RoleContainer::ROLE_SPEAKER,
RoleContainer::ROLE_MODERATOR,
RoleContainer::ROLE_OPERATOR
];
if (!in_array($object->getRole(), $allowRoles)) {
throw new AccessDeniedException();
}
}
$originalEvent = $event->getEvent();
$changeSet = $originalEvent->getEntityChangeSet();
if (isset($changeSet['isOnboarded'])) {
if ($changeSet['isOnboarded'][0] !== $changeSet['isOnboarded'][1]) {
$object->setOnboardedAt(new \DateTime());
$eventObj = new EsEventLogEvent($object, EsEventLogEvent::EVENT_ONBOARDING);
$this->dispatcher->dispatch($eventObj, EsEventLogEvent::EVENT_ONBOARDING);
}
}
if (isset($changeSet['firstName']) || isset($changeSet['lastName']) || isset($changeSet['imageName'])) {
$payload = [...$object->getQueueInfo(), 'operation' => 'UPDATE'];
$this->esJobQueue->create(
ElasticDependentUpdateAction::NAME,
json_encode($payload),
JobQueue::PRIORITY_LOW,
null,
1,
null,
false,
false
);
}
/*
if (is_array($changeSet) && count($changeSet) > 0) {
$eventObj = new EsEventLogEvent($object, EsEventLogEvent::EVENT_CHANGE_PROFILE);
$this->dispatcher->dispatch($eventObj, EsEventLogEvent::EVENT_CHANGE_PROFILE);
}
*/
}
public function onPreRemove(UserPreRemoveEvent $event)
{
$user = $this->security->getUser();
if (empty($user)) {
return;
}
$allowRoles = [];
if ($this->security->isGranted(RoleContainer::ROLE_OPERATOR)) {
$allowRoles = [
RoleContainer::ROLE_SPEAKER,
RoleContainer::ROLE_MODERATOR,
RoleContainer::ROLE_OPERATOR
];
}
if ($this->security->isGranted(RoleContainer::ROLE_ADMIN) || $this->security->isGranted(RoleContainer::ROLE_SUPPORT)) {
$allowRoles = [
RoleContainer::ROLE_GUEST_VOTER,
RoleContainer::ROLE_READER,
RoleContainer::ROLE_USER,
RoleContainer::ROLE_INSTRUCTOR,
RoleContainer::ROLE_STAFF,
RoleContainer::ROLE_RELATION_MANAGER,
RoleContainer::ROLE_SPEAKER,
RoleContainer::ROLE_MODERATOR,
RoleContainer::ROLE_SUPPORT,
RoleContainer::ROLE_OPERATOR,
RoleContainer::ROLE_ADMIN
];
}
if ($this->security->isGranted(RoleContainer::ROLE_SUPER_ADMIN)) {
if ($this->appEnvType === 'CS') {
$allowRoles = [
RoleContainer::ROLE_ADMIN,
RoleContainer::ROLE_OPERATOR
];
} else {
$allowRoles = [
...$allowRoles,
RoleContainer::ROLE_SUPER_ADMIN
];
}
}
$object = $event->getObject();
if (!in_array($object->getRole(), $allowRoles) && $user->getId() !== $object->getId()) {
throw new AccessDeniedException();
}
$payload = [...$object->getQueueInfo(), 'operation' => 'DELETE'];
$this->esJobQueue->create(
ElasticDependentUpdateAction::NAME,
json_encode($payload),
JobQueue::PRIORITY_LOW
);
$eventObj = new EsEventLogEvent($object, EsEventLogEvent::EVENT_USER_DELETE);
$this->dispatcher->dispatch($eventObj, EsEventLogEvent::EVENT_USER_DELETE);
}
}