Skip to content

Commit 010c538

Browse files
committed
Merge remote-tracking branch 'remotes/dev/1.10' into 1.10
2 parents 776b604 + 7d549b3 commit 010c538

File tree

27 files changed

+636
-71
lines changed

27 files changed

+636
-71
lines changed

src/Oro/Bundle/ActionBundle/Resources/config/conditions.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ services:
5252
- { name: oro_action.condition, alias: not }
5353

5454
oro_action.expression.true:
55-
class: Oro\Component\ConfigExpression\Condition\True
55+
class: Oro\Component\ConfigExpression\Condition\TrueCondition
5656
tags:
5757
- { name: oro_action.condition, alias: "true" }
5858

5959
oro_action.expression.false:
60-
class: Oro\Component\ConfigExpression\Condition\False
60+
class: Oro\Component\ConfigExpression\Condition\FalseCondition
6161
tags:
6262
- { name: oro_action.condition, alias: "false" }
6363

src/Oro/Bundle/CalendarBundle/Resources/config/form.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ parameters:
1616
oro_calendar.attendees_to_view_transformer.class: Oro\Bundle\CalendarBundle\Form\DataTransformer\AttendeesToViewTransformer
1717
oro_calendar.user_ids_to_users.tranformer.class: Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer
1818
oro_calendar.recurrence.form.type.class: Oro\Bundle\CalendarBundle\Form\Type\RecurrenceFormType
19-
oro_calendar.exception.form.type.class: Oro\Bundle\CalendarBundle\Form\Type\ExceptionFormType
2019

2120
services:
2221
oro_calendar.calendar_event.form.type:
@@ -213,8 +212,3 @@ services:
213212
- '@oro_calendar.model.recurrence'
214213
tags:
215214
- { name: form.type, alias: oro_calendar_event_recurrence }
216-
217-
oro_calendar.exception.form.type:
218-
class: '%oro_calendar.exception.form.type.class%'
219-
tags:
220-
- { name: form.type, alias: oro_calendar_event_exception }

src/Oro/Bundle/EmailBundle/Controller/EmailController.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,59 @@ public function threadWidgetAction(Email $entity)
215215
];
216216
}
217217

218+
/**
219+
* Used on `My Emails` page to show emails thread with only emails being related to currently logged user.
220+
*
221+
* @Route("/view/user-thread/{id}", name="oro_email_user_thread_view", requirements={"id"="\d+"})
222+
* @AclAncestor("oro_email_email_view")
223+
* @Template("OroEmailBundle:Email/Thread:userEmails.html.twig")
224+
*/
225+
public function viewUserThreadAction(Email $entity)
226+
{
227+
$this->getEmailManager()->setSeenStatus($entity, true, true);
228+
229+
return ['entity' => $entity];
230+
}
231+
232+
/**
233+
* Used on `My Emails` page to show emails thread with only emails being related to currently logged user.
234+
*
235+
* @Route("/widget/user-thread/{id}", name="oro_email_user_thread_widget", requirements={"id"="\d+"})
236+
* @Template("OroEmailBundle:Email/widget:thread.html.twig")
237+
*/
238+
public function userThreadWidgetAction(Email $entity)
239+
{
240+
$emails = [];
241+
if ($this->getRequest()->get('showSingleEmail', false)) {
242+
$emails[] = $entity;
243+
} else {
244+
$emails = $this->get('oro_email.email.thread.provider')->getUserThreadEmails(
245+
$this->get('doctrine')->getManager(),
246+
$entity,
247+
$this->getUser(),
248+
$this->get('oro_email.mailbox.manager')->findAvailableMailboxes(
249+
$this->getUser(),
250+
$this->get('security.token_storage')->getToken()->getOrganizationContext()
251+
)
252+
);
253+
}
254+
255+
$emails = array_filter($emails, function ($email) {
256+
return $this->get('security.context')->isGranted('VIEW', $email);
257+
});
258+
$this->loadEmailBody($emails);
259+
260+
return [
261+
'entity' => $entity,
262+
'thread' => $emails,
263+
'target' => $this->getTargetEntity(),
264+
'hasGrantReattach' => $this->isAttachmentCreationGranted(),
265+
'routeParameters' => $this->getTargetEntityConfig(),
266+
'renderContexts' => $this->getRequest()->get('renderContexts', true),
267+
'defaultReplyButton' => $this->get('oro_config.user')->get('oro_email.default_button_reply')
268+
];
269+
}
270+
218271
/**
219272
* @Route("/view-items", name="oro_email_items_view")
220273
* @Template

src/Oro/Bundle/EmailBundle/Datagrid/EmailQueryFactory.php

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Oro\Bundle\EmailBundle\Datagrid;
44

55
use Doctrine\Bundle\DoctrineBundle\Registry;
6+
use Doctrine\ORM\Query\Expr;
67
use Doctrine\ORM\QueryBuilder;
78

89
use Oro\Bundle\EmailBundle\Entity\Manager\MailboxManager;
@@ -67,18 +68,16 @@ public function prepareQuery(QueryBuilder $qb, $emailFromTableAlias = 'a')
6768
*/
6869
public function applyAcl(QueryBuilder $qb)
6970
{
70-
$user = $this->securityFacade->getLoggedUser();
71-
$organization = $this->getOrganization();
72-
73-
$mailboxIds = $this->mailboxManager->findAvailableMailboxIds($user, $organization);
74-
7571
$exprs = [$qb->expr()->eq('eu.owner', ':owner')];
72+
73+
$organization = $this->getOrganization();
7674
if ($organization) {
7775
$exprs[] = $qb->expr()->eq('eu.organization ', ':organization');
7876
$qb->setParameter('organization', $organization->getId());
7977
}
8078
$uoCheck = call_user_func_array([$qb->expr(), 'andX'], $exprs);
8179

80+
$mailboxIds = $this->getAvailableMailboxIds();
8281
if (!empty($mailboxIds)) {
8382
$qb->andWhere(
8483
$qb->expr()->orX(
@@ -90,7 +89,154 @@ public function applyAcl(QueryBuilder $qb)
9089
} else {
9190
$qb->andWhere($uoCheck);
9291
}
93-
$qb->setParameter('owner', $user->getId());
92+
93+
$qb->setParameter('owner', $this->securityFacade->getLoggedUserId());
94+
}
95+
96+
/**
97+
* Apply custom ACL checks in case emails should be shown in threads view
98+
* Adds additional WHERE condition:
99+
*
100+
* o0_.id IN (
101+
* SELECT max(u.id)
102+
* FROM OroEmailBundle:EmailUser as u
103+
* INNER JOIN OroEmailBundle:Email as m on u.email_id = m.id
104+
* WHERE
105+
* m.thread_id is not null
106+
* AND (
107+
* (
108+
* u.user_owner_id = {owner_id}
109+
* AND u.organization_id = {organization_id}
110+
* )
111+
* OR u.mailbox_owner_id IN ( {allowed_mailboxes_ids} )
112+
* )
113+
* GROUP BY m.thread_id
114+
* )
115+
* OR (o3_.is_head = 1 AND o3_.thread_id is null)
116+
*
117+
* @param QueryBuilder $qb
118+
*/
119+
public function applyAclThreadsGrouping(QueryBuilder $qb)
120+
{
121+
$innerQb = $qb->getEntityManager()->createQueryBuilder();
122+
$innerQb
123+
->select('MAX(u.id)')
124+
->from('OroEmailBundle:EmailUser', 'u')
125+
->innerJoin('OroEmailBundle:Email', 'm', 'WITH', 'u.email = m.id')
126+
->where(
127+
$innerQb->expr()->andX(
128+
$innerQb->expr()->isNotNull('m.thread'),
129+
$this->getOwningExpression($innerQb->expr(), 'u')
130+
)
131+
)
132+
->groupBy('m.thread');
133+
134+
$qb->andWhere(
135+
$qb->expr()->orX(
136+
$qb->expr()->in('eu.id', $innerQb->getDQL()),
137+
$qb->expr()->andX(
138+
$qb->expr()->isNull('e.thread'),
139+
$qb->expr()->eq('e.head', 'TRUE')
140+
)
141+
)
142+
);
143+
}
144+
145+
/**
146+
* In case threaded view, adds email counting (SELECT COUNT) expression.
147+
*
148+
* SELECT COUNT(eu.id)
149+
* FROM oro_email_user AS eu
150+
* INNER JOIN oro_email e ON (eu.email_id = e.id)
151+
* WHERE
152+
* e.thread_id = o3_.thread_id
153+
* AND (
154+
* (
155+
* eu.user_owner_id = {owner_id}
156+
* AND eu.organization_id = {organization_id}
157+
* )
158+
* OR eu.mailbox_owner_id IN ( {allowed_mailboxes_ids} )
159+
* )
160+
* AND o3_.thread_id IS NOT NULL -- `o3_` is alias for `oro_email` table from base query
161+
* as thread_email_count
162+
*
163+
* @param QueryBuilder $qb
164+
* @param bool $isThreadGroupingEnabled
165+
*/
166+
public function addEmailsCount(QueryBuilder $qb, $isThreadGroupingEnabled)
167+
{
168+
// in case threading view is disabled the default value for counting is `0`
169+
$selectExpression = '0 AS thread_email_count';
170+
171+
if ($isThreadGroupingEnabled) {
172+
$innerQb = $qb->getEntityManager()->createQueryBuilder();
173+
$innerQb
174+
->select('COUNT(emailUser.id)')
175+
->from('OroEmailBundle:EmailUser', 'emailUser')
176+
->innerJoin('OroEmailBundle:Email', 'email', 'WITH', 'emailUser.email = email.id')
177+
->where(
178+
$innerQb->expr()->andX(
179+
$innerQb->expr()->isNotNull('e.thread'),
180+
$innerQb->expr()->eq('email.thread', 'e.thread'),
181+
$this->getOwningExpression($innerQb->expr(), 'emailUser')
182+
)
183+
);
184+
185+
$selectExpression = '(' . $innerQb->getDQL() . ') AS thread_email_count';
186+
}
187+
188+
$qb->addSelect($selectExpression);
189+
}
190+
191+
/**
192+
* Builds owning expression part, being used in case of threaded emails view enabled.
193+
*
194+
* (
195+
* eu.user_owner_id = {owner_id}
196+
* AND eu.organization_id = {organization_id}
197+
* )
198+
* OR eu.mailbox_owner_id IN ( {allowed_mailboxes_ids} )
199+
*
200+
* @param Expr $expr
201+
* @param string $tableAlias
202+
*
203+
* @return Expr\Andx|Expr\Comparison|Expr\Orx
204+
*/
205+
protected function getOwningExpression($expr, $tableAlias)
206+
{
207+
$user = $this->securityFacade->getLoggedUser();
208+
$organization = $this->getOrganization();
209+
210+
if ($organization === null) {
211+
$ownerExpression =
212+
$expr->eq($tableAlias . '.owner', $user->getId());
213+
} else {
214+
$ownerExpression = $expr->andX(
215+
$expr->eq($tableAlias . '.owner', $user->getId()),
216+
$expr->eq($tableAlias . '.organization', $organization->getId())
217+
);
218+
}
219+
220+
$availableMailboxIds = $this->getAvailableMailboxIds();
221+
if ($availableMailboxIds) {
222+
return $expr->orX(
223+
$ownerExpression,
224+
$expr->in($tableAlias . '.mailboxOwner', $this->getAvailableMailboxIds())
225+
);
226+
} else {
227+
return $ownerExpression;
228+
}
229+
}
230+
231+
/**
232+
* @return array
233+
*/
234+
protected function getAvailableMailboxIds()
235+
{
236+
return $this->mailboxManager->findAvailableMailboxIds(
237+
$this->securityFacade->getLoggedUser(),
238+
$this->getOrganization()
239+
);
94240
}
95241

96242
/**
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
namespace Oro\Bundle\EmailBundle\DependencyInjection\Compiler;
3+
4+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
5+
use Symfony\Component\DependencyInjection\ContainerBuilder;
6+
use Symfony\Component\DependencyInjection\Reference;
7+
8+
class OverrideServiceSwiftMailer implements CompilerPassInterface
9+
{
10+
public function process(ContainerBuilder $container)
11+
{
12+
/* @var $definition \Symfony\Component\DependencyInjection\DefinitionDecorator */
13+
$definition = $container->findDefinition('mailer');
14+
$definition->addArgument(new Reference('oro_email.logger.link'));
15+
}
16+
}

src/Oro/Bundle/EmailBundle/Entity/Provider/EmailThreadProvider.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Oro\Bundle\EmailBundle\Entity\Email;
1111
use Oro\Bundle\EmailBundle\Entity\EmailThread;
12+
use Oro\Bundle\UserBundle\Entity\User;
1213

1314
class EmailThreadProvider
1415
{
@@ -118,4 +119,50 @@ public function getThreadEmails(EntityManager $entityManager, Email $entity)
118119

119120
return $result;
120121
}
122+
123+
/**
124+
* Get emails in thread by given email.
125+
* Used on `My Emails` page to show emails thread with only emails being related to currently logged user.
126+
*
127+
* @param EntityManager $entityManager
128+
* @param Email $entity
129+
* @param User $user
130+
* @param array $mailboxes
131+
* @return array
132+
*/
133+
public function getUserThreadEmails(EntityManager $entityManager, Email $entity, User $user, $mailboxes = [])
134+
{
135+
$thread = $entity->getThread();
136+
if ($thread) {
137+
/** @var QueryBuilder $queryBuilder */
138+
$queryBuilder = $entityManager->getRepository('OroEmailBundle:Email')->createQueryBuilder('e');
139+
$queryBuilder->join('e.emailUsers', 'eu');
140+
141+
$criteria = new Criteria();
142+
$criteria->where($criteria->expr()->eq('thread', $thread));
143+
$criteria->orderBy(['sentAt' => Criteria::DESC]);
144+
145+
if ($mailboxes) {
146+
$criteria->andWhere(
147+
$criteria->expr()->orX(
148+
$criteria->expr()->in('eu.mailboxOwner', $mailboxes),
149+
$criteria->expr()->eq('eu.owner', $user)
150+
)
151+
);
152+
} else {
153+
$criteria->andWhere(
154+
$criteria->expr()->eq('eu.owner', $user)
155+
);
156+
}
157+
158+
$result = $queryBuilder
159+
->addCriteria($criteria)
160+
->getQuery()
161+
->getResult();
162+
} else {
163+
$result = [$entity];
164+
}
165+
166+
return $result;
167+
}
121168
}

0 commit comments

Comments
 (0)