Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / metamta / controller / PhabricatorMetaMTAMailViewController.php
blobd7d31ba254763b68a4b37d70317551721ac5e825
1 <?php
3 final class PhabricatorMetaMTAMailViewController
4 extends PhabricatorMetaMTAController {
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $this->getViewer();
9 $mail = id(new PhabricatorMetaMTAMailQuery())
10 ->setViewer($viewer)
11 ->withIDs(array($request->getURIData('id')))
12 ->executeOne();
13 if (!$mail) {
14 return new Aphront404Response();
17 if ($mail->hasSensitiveContent()) {
18 $title = pht('Content Redacted');
19 } else {
20 $title = $mail->getSubject();
23 $header = id(new PHUIHeaderView())
24 ->setHeader($title)
25 ->setUser($viewer)
26 ->setPolicyObject($mail)
27 ->setHeaderIcon('fa-envelope');
29 $status = $mail->getStatus();
30 $name = PhabricatorMailOutboundStatus::getStatusName($status);
31 $icon = PhabricatorMailOutboundStatus::getStatusIcon($status);
32 $color = PhabricatorMailOutboundStatus::getStatusColor($status);
33 $header->setStatus($icon, $color, $name);
35 if ($mail->getMustEncrypt()) {
36 Javelin::initBehavior('phabricator-tooltips');
37 $header->addTag(
38 id(new PHUITagView())
39 ->setType(PHUITagView::TYPE_SHADE)
40 ->setColor('blue')
41 ->setName(pht('Must Encrypt'))
42 ->setIcon('fa-shield blue')
43 ->addSigil('has-tooltip')
44 ->setMetadata(
45 array(
46 'tip' => pht(
47 'Message content can only be transmitted over secure '.
48 'channels.'),
49 )));
52 $crumbs = $this->buildApplicationCrumbs()
53 ->addTextCrumb(pht('Mail %d', $mail->getID()))
54 ->setBorder(true);
56 $tab_group = id(new PHUITabGroupView())
57 ->addTab(
58 id(new PHUITabView())
59 ->setName(pht('Message'))
60 ->setKey('message')
61 ->appendChild($this->buildMessageProperties($mail)))
62 ->addTab(
63 id(new PHUITabView())
64 ->setName(pht('Headers'))
65 ->setKey('headers')
66 ->appendChild($this->buildHeaderProperties($mail)))
67 ->addTab(
68 id(new PHUITabView())
69 ->setName(pht('Delivery'))
70 ->setKey('delivery')
71 ->appendChild($this->buildDeliveryProperties($mail)))
72 ->addTab(
73 id(new PHUITabView())
74 ->setName(pht('Metadata'))
75 ->setKey('metadata')
76 ->appendChild($this->buildMetadataProperties($mail)));
78 $header_view = id(new PHUIHeaderView())
79 ->setHeader(pht('Mail'));
81 $object_phid = $mail->getRelatedPHID();
82 if ($object_phid) {
83 $handles = $viewer->loadHandles(array($object_phid));
84 $handle = $handles[$object_phid];
85 if ($handle->isComplete() && $handle->getURI()) {
86 $view_button = id(new PHUIButtonView())
87 ->setTag('a')
88 ->setText(pht('View Object'))
89 ->setIcon('fa-chevron-right')
90 ->setHref($handle->getURI());
92 $header_view->addActionLink($view_button);
96 $object_box = id(new PHUIObjectBoxView())
97 ->setHeader($header_view)
98 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
99 ->addTabGroup($tab_group);
101 $view = id(new PHUITwoColumnView())
102 ->setHeader($header)
103 ->setFooter($object_box);
105 return $this->newPage()
106 ->setTitle($title)
107 ->setCrumbs($crumbs)
108 ->setPageObjectPHIDs(array($mail->getPHID()))
109 ->appendChild($view);
112 private function buildMessageProperties(PhabricatorMetaMTAMail $mail) {
113 $viewer = $this->getViewer();
115 $properties = id(new PHUIPropertyListView())
116 ->setUser($viewer)
117 ->setObject($mail);
119 if ($mail->getFrom()) {
120 $from_str = $viewer->renderHandle($mail->getFrom());
121 } else {
122 $from_str = pht('Sent by Phabricator');
124 $properties->addProperty(
125 pht('From'),
126 $from_str);
128 if ($mail->getToPHIDs()) {
129 $to_list = $viewer->renderHandleList($mail->getToPHIDs());
130 } else {
131 $to_list = pht('None');
133 $properties->addProperty(
134 pht('To'),
135 $to_list);
137 if ($mail->getCcPHIDs()) {
138 $cc_list = $viewer->renderHandleList($mail->getCcPHIDs());
139 } else {
140 $cc_list = pht('None');
142 $properties->addProperty(
143 pht('Cc'),
144 $cc_list);
146 $properties->addProperty(
147 pht('Sent'),
148 phabricator_datetime($mail->getDateCreated(), $viewer));
150 $properties->addSectionHeader(
151 pht('Message'),
152 PHUIPropertyListView::ICON_SUMMARY);
154 if ($mail->hasSensitiveContent()) {
155 $body = phutil_tag(
156 'em',
157 array(),
158 pht(
159 'The content of this mail is sensitive and it can not be '.
160 'viewed from the web UI.'));
161 } else {
162 $body = phutil_tag(
163 'div',
164 array(
165 'style' => 'white-space: pre-wrap',
167 $mail->getBody());
170 $properties->addTextContent($body);
172 $file_phids = $mail->getAttachmentFilePHIDs();
173 if ($file_phids) {
174 $properties->addProperty(
175 pht('Attached Files'),
176 $viewer->loadHandles($file_phids)->renderList());
179 return $properties;
182 private function buildHeaderProperties(PhabricatorMetaMTAMail $mail) {
183 $viewer = $this->getViewer();
185 $properties = id(new PHUIPropertyListView())
186 ->setUser($viewer)
187 ->setStacked(true);
189 $headers = $mail->getDeliveredHeaders();
190 if (!$headers) {
191 $headers = array();
194 // Sort headers by name.
195 $headers = isort($headers, 0);
197 foreach ($headers as $header) {
198 list($key, $value) = $header;
199 $properties->addProperty($key, $value);
202 $encrypt_phids = $mail->getMustEncryptReasons();
203 if ($encrypt_phids) {
204 $properties->addProperty(
205 pht('Must Encrypt'),
206 $viewer->loadHandles($encrypt_phids)
207 ->renderList());
211 return $properties;
214 private function buildDeliveryProperties(PhabricatorMetaMTAMail $mail) {
215 $viewer = $this->getViewer();
217 $properties = id(new PHUIPropertyListView())
218 ->setUser($viewer);
220 $actors = $mail->getDeliveredActors();
221 $reasons = null;
222 if (!$actors) {
223 if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
224 $delivery = $this->renderEmptyMessage(
225 pht(
226 'This message has not been delivered yet, so delivery information '.
227 'is not available.'));
228 } else {
229 $delivery = $this->renderEmptyMessage(
230 pht(
231 'This is an older message that predates recording delivery '.
232 'information, so none is available.'));
234 } else {
235 $actor = idx($actors, $viewer->getPHID());
236 if (!$actor) {
237 $delivery = phutil_tag(
238 'em',
239 array(),
240 pht('This message was not delivered to you.'));
241 } else {
242 $deliverable = $actor['deliverable'];
243 if ($deliverable) {
244 $delivery = pht('Delivered');
245 } else {
246 $delivery = pht('Voided');
249 $reasons = id(new PHUIStatusListView());
251 $reason_codes = $actor['reasons'];
252 if (!$reason_codes) {
253 $reason_codes = array(
254 PhabricatorMetaMTAActor::REASON_NONE,
258 $icon_yes = 'fa-check green';
259 $icon_no = 'fa-times red';
261 foreach ($reason_codes as $reason) {
262 $target = phutil_tag(
263 'strong',
264 array(),
265 PhabricatorMetaMTAActor::getReasonName($reason));
267 if (PhabricatorMetaMTAActor::isDeliveryReason($reason)) {
268 $icon = $icon_yes;
269 } else {
270 $icon = $icon_no;
273 $item = id(new PHUIStatusItemView())
274 ->setIcon($icon)
275 ->setTarget($target)
276 ->setNote(PhabricatorMetaMTAActor::getReasonDescription($reason));
278 $reasons->addItem($item);
283 $properties->addProperty(pht('Delivery'), $delivery);
284 if ($reasons) {
285 $properties->addProperty(pht('Reasons'), $reasons);
286 $properties->addProperty(
287 null,
288 $this->renderEmptyMessage(
289 pht(
290 'Delivery reasons are listed from weakest to strongest.')));
293 $properties->addSectionHeader(
294 pht('Routing Rules'), 'fa-paper-plane-o');
296 $map = $mail->getDeliveredRoutingMap();
297 $routing_detail = null;
298 if ($map === null) {
299 if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
300 $routing_result = $this->renderEmptyMessage(
301 pht(
302 'This message has not been sent yet, so routing rules have '.
303 'not been computed.'));
304 } else {
305 $routing_result = $this->renderEmptyMessage(
306 pht(
307 'This is an older message which predates routing rules.'));
309 } else {
310 $rule = idx($map, $viewer->getPHID());
311 if ($rule === null) {
312 $rule = idx($map, 'default');
315 if ($rule === null) {
316 $routing_result = $this->renderEmptyMessage(
317 pht(
318 'No routing rules applied when delivering this message to you.'));
319 } else {
320 $rule_const = $rule['rule'];
321 $reason_phid = $rule['reason'];
322 switch ($rule_const) {
323 case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION:
324 $routing_result = pht(
325 'This message was routed as a notification because it '.
326 'matched %s.',
327 $viewer->renderHandle($reason_phid)->render());
328 break;
329 case PhabricatorMailRoutingRule::ROUTE_AS_MAIL:
330 $routing_result = pht(
331 'This message was routed as an email because it matched %s.',
332 $viewer->renderHandle($reason_phid)->render());
333 break;
334 default:
335 $routing_result = pht('Unknown routing rule "%s".', $rule_const);
336 break;
340 $routing_rules = $mail->getDeliveredRoutingRules();
341 if ($routing_rules) {
342 $rules = array();
343 foreach ($routing_rules as $rule) {
344 $phids = idx($rule, 'phids');
345 if ($phids === null) {
346 $rules[] = $rule;
347 } else if (in_array($viewer->getPHID(), $phids)) {
348 $rules[] = $rule;
352 // Reorder rules by strength.
353 foreach ($rules as $key => $rule) {
354 $const = $rule['routingRule'];
355 $phids = $rule['phids'];
357 if ($phids === null) {
358 $type = 'A';
359 } else {
360 $type = 'B';
363 $rules[$key]['strength'] = sprintf(
364 '~%s%08d',
365 $type,
366 PhabricatorMailRoutingRule::getRuleStrength($const));
368 $rules = isort($rules, 'strength');
370 $routing_detail = id(new PHUIStatusListView());
371 foreach ($rules as $rule) {
372 $const = $rule['routingRule'];
373 $phids = $rule['phids'];
375 $name = PhabricatorMailRoutingRule::getRuleName($const);
377 $icon = PhabricatorMailRoutingRule::getRuleIcon($const);
378 $color = PhabricatorMailRoutingRule::getRuleColor($const);
380 if ($phids === null) {
381 $kind = pht('Global');
382 } else {
383 $kind = pht('Personal');
386 $target = array($kind, ': ', $name);
387 $target = phutil_tag('strong', array(), $target);
389 $item = id(new PHUIStatusItemView())
390 ->setTarget($target)
391 ->setNote($viewer->renderHandle($rule['reasonPHID']))
392 ->setIcon($icon, $color);
394 $routing_detail->addItem($item);
399 $properties->addProperty(pht('Effective Rule'), $routing_result);
401 if ($routing_detail !== null) {
402 $properties->addProperty(pht('All Matching Rules'), $routing_detail);
403 $properties->addProperty(
404 null,
405 $this->renderEmptyMessage(
406 pht(
407 'Matching rules are listed from weakest to strongest.')));
410 return $properties;
413 private function buildMetadataProperties(PhabricatorMetaMTAMail $mail) {
414 $viewer = $this->getViewer();
416 $properties = id(new PHUIPropertyListView())
417 ->setUser($viewer);
419 $properties->addProperty(pht('Message PHID'), $mail->getPHID());
421 $details = $mail->getMessage();
422 if (!strlen($details)) {
423 $details = phutil_tag('em', array(), pht('None'));
425 $properties->addProperty(pht('Status Details'), $details);
427 $actor_phid = $mail->getActorPHID();
428 if ($actor_phid) {
429 $actor_str = $viewer->renderHandle($actor_phid);
430 } else {
431 $actor_str = pht('Generated by Phabricator');
433 $properties->addProperty(pht('Actor'), $actor_str);
435 $related_phid = $mail->getRelatedPHID();
436 if ($related_phid) {
437 $related = $viewer->renderHandle($mail->getRelatedPHID());
438 } else {
439 $related = phutil_tag('em', array(), pht('None'));
441 $properties->addProperty(pht('Related Object'), $related);
443 return $properties;
446 private function renderEmptyMessage($message) {
447 return phutil_tag('em', array(), $message);