. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License version 3, * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ namespace Espo\Tools\Notification; use Espo\Core\Acl; use Espo\Core\Exceptions\BadRequest; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Record\Collection as RecordCollection; use Espo\Core\Select\SearchParams; use Espo\Core\Select\SelectBuilderFactory; use Espo\Entities\Notification; use Espo\Entities\User; use Espo\ORM\Collection; use Espo\ORM\EntityManager; use Espo\ORM\Name\Attribute; use Espo\ORM\Query\DeleteBuilder; use Espo\ORM\Query\Part\Condition as Cond; use Espo\ORM\Query\Part\Expression as Expr; use Espo\ORM\Query\Select; use Espo\ORM\Query\SelectBuilder; class GroupAllService { public function __construct( private EntityManager $entityManager, private Acl $acl, private User $user, private RecordService $recordService, private SelectBuilderFactory $selectBuilderFactory, ) {} /** * @return RecordCollection * @throws BadRequest * @throws Forbidden */ public function get(string $type, string $groupId, SearchParams $searchParams): RecordCollection { $collection = null; if ($type == Notification::GROUP_TYPE_NOTE) { $collection = $this->getNote($groupId, $searchParams); } else if ($type == Notification::GROUP_TYPE_EMAIL_RECEIVED) { $collection = $this->getEmailReceived($searchParams); } if (!$collection) { throw new BadRequest("Bad group."); } $this->markAsRead($collection); return $collection; } /** * @return RecordCollection * @throws BadRequest * @throws Forbidden */ private function getNote(string $groupId, SearchParams $searchParams): RecordCollection { if (substr_count($groupId, '_') < 2) { throw new BadRequest("Bad ID."); } [, $entityType, $id] = explode('_', $groupId, 3); if (!$this->acl->checkScope($entityType)) { /** @var Collection $collection */ $collection = $this->entityManager->getCollectionFactory()->create(Notification::ENTITY_TYPE); return RecordCollection::create($collection, 0); } $builder = $this->prepareBuilder($searchParams); $query = $builder ->where([ Notification::FIELD_TYPE => Notification::TYPE_NOTE, Notification::ATTR_RELATED_PARENT_TYPE => $entityType, Notification::ATTR_RELATED_PARENT_ID => $id, ]) ->build(); [$collection, $total] = $this->runQuery($query); $collection = $this->recordService->prepareCollection($collection, $this->user); return RecordCollection::create($collection, $total); } /** * @return RecordCollection * @throws BadRequest * @throws Forbidden */ private function getEmailReceived(SearchParams $searchParams): RecordCollection { $builder = $this->prepareBuilder($searchParams); $query = $builder ->where([ Notification::FIELD_TYPE => Notification::TYPE_EMAIL_RECEIVED, ]) ->build(); [$collection, $total] = $this->runQuery($query); $collection = $this->recordService->prepareCollection($collection, $this->user); return RecordCollection::create($collection, $total); } /** * @return array{0: Collection, 1: int} */ private function runQuery(Select $query): array { $collection = $this->entityManager ->getRDBRepositoryByClass(Notification::class) ->clone($query) ->find(); $total = $this->entityManager ->getRDBRepositoryByClass(Notification::class) ->clone($query) ->count(); return [$collection, $total]; } /** * @param string[] $ids */ private function markAsReadByIds(array $ids): void { if ($ids === []) { return; } $query = $this->entityManager ->getQueryBuilder() ->update() ->in(Notification::ENTITY_TYPE) ->set([Notification::ATTR_READ => true]) ->where([Notification::ATTR_USER_ID => $this->user->getId()]) ->where( Cond::in(Expr::column(Attribute::ID), $ids) ) ->build(); $this->entityManager->getQueryExecutor()->execute($query); } /** * @param RecordCollection $collection */ private function markAsRead(RecordCollection $collection): void { $ids = []; foreach ($collection->getCollection() as $entity) { $ids[] = $entity->getId(); } $this->markAsReadByIds($ids); } /** * @return SelectBuilder * @throws BadRequest * @throws Forbidden */ private function prepareBuilder(SearchParams $searchParams): SelectBuilder { return $this->selectBuilderFactory ->create() ->from(Notification::ENTITY_TYPE) ->withSearchParams($searchParams) ->withComplexExpressionsForbidden() ->buildQueryBuilder() ->where([ Notification::ATTR_USER_ID => $this->user->getId(), ]); } /** * @throws BadRequest */ public function remove(string $groupId): void { if (substr_count($groupId, '_') < 1) { throw new BadRequest("Bad ID."); } [$type,] = explode('_', $groupId, 2); if ($type == Notification::GROUP_TYPE_NOTE) { $this->removeNote($groupId); return; } if ($type == Notification::GROUP_TYPE_EMAIL_RECEIVED) { $this->removeEmailReceived(); return; } throw new BadRequest("Bad group type."); } /** * @throws BadRequest */ private function removeNote(string $groupId): void { if (substr_count($groupId, '_') < 2) { throw new BadRequest("Bad ID."); } [, $entityType, $id] = explode('_', $groupId, 3); $query = DeleteBuilder::create() ->from(Notification::ENTITY_TYPE) ->where([ Notification::ATTR_USER_ID => $this->user->getId(), ]) ->where([ Notification::FIELD_TYPE => Notification::TYPE_NOTE, Notification::ATTR_RELATED_PARENT_TYPE => $entityType, Notification::ATTR_RELATED_PARENT_ID => $id, ]) ->build(); $this->entityManager->getQueryExecutor()->execute($query); } private function removeEmailReceived(): void { $query = DeleteBuilder::create() ->from(Notification::ENTITY_TYPE) ->where([ Notification::ATTR_USER_ID => $this->user->getId(), ]) ->where([ Notification::FIELD_TYPE => Notification::TYPE_EMAIL_RECEIVED, ]) ->build(); $this->entityManager->getQueryExecutor()->execute($query); } }