Remove all "FileHasObject" edge reads and writes
[phabricator.git] / src / applications / audit / editor / PhabricatorAuditEditor.php
blob7b97ea515af2313d57404b6daf54daec72f79447
1 <?php
3 final class PhabricatorAuditEditor
4 extends PhabricatorApplicationTransactionEditor {
6 const MAX_FILES_SHOWN_IN_EMAIL = 1000;
8 private $affectedFiles;
9 private $rawPatch;
10 private $auditorPHIDs = array();
12 private $didExpandInlineState = false;
13 private $oldAuditStatus = null;
15 public function setRawPatch($patch) {
16 $this->rawPatch = $patch;
17 return $this;
20 public function getRawPatch() {
21 return $this->rawPatch;
24 public function getEditorApplicationClass() {
25 return 'PhabricatorDiffusionApplication';
28 public function getEditorObjectsDescription() {
29 return pht('Audits');
32 public function getTransactionTypes() {
33 $types = parent::getTransactionTypes();
35 $types[] = PhabricatorTransactions::TYPE_COMMENT;
36 $types[] = PhabricatorTransactions::TYPE_EDGE;
37 $types[] = PhabricatorTransactions::TYPE_INLINESTATE;
39 $types[] = PhabricatorAuditTransaction::TYPE_COMMIT;
41 // TODO: These will get modernized eventually, but that can happen one
42 // at a time later on.
43 $types[] = PhabricatorAuditActionConstants::INLINE;
45 return $types;
48 protected function expandTransactions(
49 PhabricatorLiskDAO $object,
50 array $xactions) {
52 foreach ($xactions as $xaction) {
53 switch ($xaction->getTransactionType()) {
54 case PhabricatorTransactions::TYPE_INLINESTATE:
55 $this->didExpandInlineState = true;
56 break;
60 $this->oldAuditStatus = $object->getAuditStatus();
62 return parent::expandTransactions($object, $xactions);
65 protected function transactionHasEffect(
66 PhabricatorLiskDAO $object,
67 PhabricatorApplicationTransaction $xaction) {
69 switch ($xaction->getTransactionType()) {
70 case PhabricatorAuditActionConstants::INLINE:
71 return $xaction->hasComment();
74 return parent::transactionHasEffect($object, $xaction);
77 protected function getCustomTransactionOldValue(
78 PhabricatorLiskDAO $object,
79 PhabricatorApplicationTransaction $xaction) {
80 switch ($xaction->getTransactionType()) {
81 case PhabricatorAuditActionConstants::INLINE:
82 case PhabricatorAuditTransaction::TYPE_COMMIT:
83 return null;
86 return parent::getCustomTransactionOldValue($object, $xaction);
89 protected function getCustomTransactionNewValue(
90 PhabricatorLiskDAO $object,
91 PhabricatorApplicationTransaction $xaction) {
93 switch ($xaction->getTransactionType()) {
94 case PhabricatorAuditActionConstants::INLINE:
95 case PhabricatorAuditTransaction::TYPE_COMMIT:
96 return $xaction->getNewValue();
99 return parent::getCustomTransactionNewValue($object, $xaction);
102 protected function applyCustomInternalTransaction(
103 PhabricatorLiskDAO $object,
104 PhabricatorApplicationTransaction $xaction) {
106 switch ($xaction->getTransactionType()) {
107 case PhabricatorAuditActionConstants::INLINE:
108 $comment = $xaction->getComment();
110 $comment->setAttribute('editing', false);
112 PhabricatorVersionedDraft::purgeDrafts(
113 $comment->getPHID(),
114 $this->getActingAsPHID());
115 return;
116 case PhabricatorAuditTransaction::TYPE_COMMIT:
117 return;
120 return parent::applyCustomInternalTransaction($object, $xaction);
123 protected function applyCustomExternalTransaction(
124 PhabricatorLiskDAO $object,
125 PhabricatorApplicationTransaction $xaction) {
127 switch ($xaction->getTransactionType()) {
128 case PhabricatorAuditTransaction::TYPE_COMMIT:
129 return;
130 case PhabricatorAuditActionConstants::INLINE:
131 $reply = $xaction->getComment()->getReplyToComment();
132 if ($reply && !$reply->getHasReplies()) {
133 $reply->setHasReplies(1)->save();
135 return;
138 return parent::applyCustomExternalTransaction($object, $xaction);
141 protected function applyBuiltinExternalTransaction(
142 PhabricatorLiskDAO $object,
143 PhabricatorApplicationTransaction $xaction) {
145 switch ($xaction->getTransactionType()) {
146 case PhabricatorTransactions::TYPE_INLINESTATE:
147 $table = new PhabricatorAuditTransactionComment();
148 $conn_w = $table->establishConnection('w');
149 foreach ($xaction->getNewValue() as $phid => $state) {
150 queryfx(
151 $conn_w,
152 'UPDATE %T SET fixedState = %s WHERE phid = %s',
153 $table->getTableName(),
154 $state,
155 $phid);
157 break;
160 return parent::applyBuiltinExternalTransaction($object, $xaction);
163 protected function applyFinalEffects(
164 PhabricatorLiskDAO $object,
165 array $xactions) {
167 // Load auditors explicitly; we may not have them if the caller was a
168 // generic piece of infrastructure.
170 $commit = id(new DiffusionCommitQuery())
171 ->setViewer($this->requireActor())
172 ->withIDs(array($object->getID()))
173 ->needAuditRequests(true)
174 ->executeOne();
175 if (!$commit) {
176 throw new Exception(
177 pht('Failed to load commit during transaction finalization!'));
179 $object->attachAudits($commit->getAudits());
181 $actor_phid = $this->getActingAsPHID();
182 $actor_is_author = ($object->getAuthorPHID()) &&
183 ($actor_phid == $object->getAuthorPHID());
185 $import_status_flag = null;
186 foreach ($xactions as $xaction) {
187 switch ($xaction->getTransactionType()) {
188 case PhabricatorAuditTransaction::TYPE_COMMIT:
189 $import_status_flag = PhabricatorRepositoryCommit::IMPORTED_PUBLISH;
190 break;
194 $old_status = $this->oldAuditStatus;
196 $requests = $object->getAudits();
197 $object->updateAuditStatus($requests);
199 $new_status = $object->getAuditStatus();
201 $object->save();
203 if ($import_status_flag) {
204 $object->writeImportStatusFlag($import_status_flag);
207 // If the commit has changed state after this edit, add an informational
208 // transaction about the state change.
209 if ($old_status != $new_status) {
210 if ($object->isAuditStatusPartiallyAudited()) {
211 // This state isn't interesting enough to get a transaction. The
212 // best way we could lead the user forward is something like "This
213 // commit still requires additional audits." but that's redundant and
214 // probably not very useful.
215 } else {
216 $xaction = $object->getApplicationTransactionTemplate()
217 ->setTransactionType(DiffusionCommitStateTransaction::TRANSACTIONTYPE)
218 ->setOldValue($old_status)
219 ->setNewValue($new_status);
221 $xaction = $this->populateTransaction($object, $xaction);
223 $xaction->save();
227 // Collect auditor PHIDs for building mail.
228 $this->auditorPHIDs = mpull($object->getAudits(), 'getAuditorPHID');
230 return $xactions;
233 protected function expandTransaction(
234 PhabricatorLiskDAO $object,
235 PhabricatorApplicationTransaction $xaction) {
237 $auditors_type = DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE;
239 $xactions = parent::expandTransaction($object, $xaction);
241 switch ($xaction->getTransactionType()) {
242 case PhabricatorAuditTransaction::TYPE_COMMIT:
243 $phids = $this->getAuditRequestTransactionPHIDsFromCommitMessage(
244 $object);
245 if ($phids) {
246 $xactions[] = $object->getApplicationTransactionTemplate()
247 ->setTransactionType($auditors_type)
248 ->setNewValue(
249 array(
250 '+' => array_fuse($phids),
252 $this->addUnmentionablePHIDs($phids);
254 break;
255 default:
256 break;
259 if (!$this->didExpandInlineState) {
260 switch ($xaction->getTransactionType()) {
261 case PhabricatorTransactions::TYPE_COMMENT:
262 $this->didExpandInlineState = true;
264 $query_template = id(new DiffusionDiffInlineCommentQuery())
265 ->withCommitPHIDs(array($object->getPHID()));
267 $state_xaction = $this->newInlineStateTransaction(
268 $object,
269 $query_template);
271 if ($state_xaction) {
272 $xactions[] = $state_xaction;
274 break;
278 return $xactions;
281 private function getAuditRequestTransactionPHIDsFromCommitMessage(
282 PhabricatorRepositoryCommit $commit) {
284 $actor = $this->getActor();
285 $data = $commit->getCommitData();
286 $message = $data->getCommitMessage();
288 $result = DifferentialCommitMessageParser::newStandardParser($actor)
289 ->setRaiseMissingFieldErrors(false)
290 ->parseFields($message);
292 $field_key = DifferentialAuditorsCommitMessageField::FIELDKEY;
293 $phids = idx($result, $field_key, null);
295 if (!$phids) {
296 return array();
299 // If a commit lists its author as an auditor, just pretend it does not.
300 foreach ($phids as $key => $phid) {
301 if ($phid == $commit->getAuthorPHID()) {
302 unset($phids[$key]);
306 if (!$phids) {
307 return array();
310 return $phids;
313 protected function sortTransactions(array $xactions) {
314 $xactions = parent::sortTransactions($xactions);
316 $head = array();
317 $tail = array();
319 foreach ($xactions as $xaction) {
320 $type = $xaction->getTransactionType();
321 if ($type == PhabricatorAuditActionConstants::INLINE) {
322 $tail[] = $xaction;
323 } else {
324 $head[] = $xaction;
328 return array_values(array_merge($head, $tail));
331 protected function supportsSearch() {
332 return true;
335 protected function expandCustomRemarkupBlockTransactions(
336 PhabricatorLiskDAO $object,
337 array $xactions,
338 array $changes,
339 PhutilMarkupEngine $engine) {
341 $actor = $this->getActor();
342 $result = array();
344 // Some interactions (like "Fixes Txxx" interacting with Maniphest) have
345 // already been processed, so we're only re-parsing them here to avoid
346 // generating an extra redundant mention. Other interactions are being
347 // processed for the first time.
349 // We're only recognizing magic in the commit message itself, not in
350 // audit comments.
352 $is_commit = false;
353 foreach ($xactions as $xaction) {
354 switch ($xaction->getTransactionType()) {
355 case PhabricatorAuditTransaction::TYPE_COMMIT:
356 $is_commit = true;
357 break;
361 if (!$is_commit) {
362 return $result;
365 $flat_blocks = mpull($changes, 'getNewValue');
366 $huge_block = implode("\n\n", $flat_blocks);
367 $phid_map = array();
368 $monograms = array();
370 $task_refs = id(new ManiphestCustomFieldStatusParser())
371 ->parseCorpus($huge_block);
372 foreach ($task_refs as $match) {
373 foreach ($match['monograms'] as $monogram) {
374 $monograms[] = $monogram;
378 $rev_refs = id(new DifferentialCustomFieldDependsOnParser())
379 ->parseCorpus($huge_block);
380 foreach ($rev_refs as $match) {
381 foreach ($match['monograms'] as $monogram) {
382 $monograms[] = $monogram;
386 $objects = id(new PhabricatorObjectQuery())
387 ->setViewer($this->getActor())
388 ->withNames($monograms)
389 ->execute();
390 $phid_map[] = mpull($objects, 'getPHID', 'getPHID');
392 $reverts_refs = id(new DifferentialCustomFieldRevertsParser())
393 ->parseCorpus($huge_block);
394 $reverts = array_mergev(ipull($reverts_refs, 'monograms'));
395 if ($reverts) {
396 $reverted_objects = DiffusionCommitRevisionQuery::loadRevertedObjects(
397 $actor,
398 $object,
399 $reverts,
400 $object->getRepository());
402 $reverted_phids = mpull($reverted_objects, 'getPHID', 'getPHID');
404 $reverts_edge = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
405 $result[] = id(new PhabricatorAuditTransaction())
406 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
407 ->setMetadataValue('edge:type', $reverts_edge)
408 ->setNewValue(array('+' => $reverted_phids));
410 $phid_map[] = $reverted_phids;
413 // See T13463. Copy "related task" edges from the associated revision, if
414 // one exists.
416 $revision = DiffusionCommitRevisionQuery::loadRevisionForCommit(
417 $actor,
418 $object);
419 if ($revision) {
420 $task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
421 $revision->getPHID(),
422 DifferentialRevisionHasTaskEdgeType::EDGECONST);
423 $task_phids = array_fuse($task_phids);
425 if ($task_phids) {
426 $related_edge = DiffusionCommitHasTaskEdgeType::EDGECONST;
427 $result[] = id(new PhabricatorAuditTransaction())
428 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
429 ->setMetadataValue('edge:type', $related_edge)
430 ->setNewValue(array('+' => $task_phids));
433 // Mark these objects as unmentionable, since the explicit relationship
434 // is stronger and any mentions are redundant.
435 $phid_map[] = $task_phids;
438 $phid_map = array_mergev($phid_map);
439 $this->addUnmentionablePHIDs($phid_map);
441 return $result;
444 protected function buildReplyHandler(PhabricatorLiskDAO $object) {
445 $reply_handler = new PhabricatorAuditReplyHandler();
446 $reply_handler->setMailReceiver($object);
447 return $reply_handler;
450 protected function getMailSubjectPrefix() {
451 return pht('[Diffusion]');
454 protected function getMailThreadID(PhabricatorLiskDAO $object) {
455 // For backward compatibility, use this legacy thread ID.
456 return 'diffusion-audit-'.$object->getPHID();
459 protected function buildMailTemplate(PhabricatorLiskDAO $object) {
460 $identifier = $object->getCommitIdentifier();
461 $repository = $object->getRepository();
463 $summary = $object->getSummary();
464 $name = $repository->formatCommitName($identifier);
466 $subject = "{$name}: {$summary}";
468 $template = id(new PhabricatorMetaMTAMail())
469 ->setSubject($subject);
471 $this->attachPatch(
472 $template,
473 $object);
475 return $template;
478 protected function getMailTo(PhabricatorLiskDAO $object) {
479 $this->requireAuditors($object);
481 $phids = array();
483 if ($object->getAuthorPHID()) {
484 $phids[] = $object->getAuthorPHID();
487 foreach ($object->getAudits() as $audit) {
488 if (!$audit->isResigned()) {
489 $phids[] = $audit->getAuditorPHID();
493 $phids[] = $this->getActingAsPHID();
495 return $phids;
498 protected function newMailUnexpandablePHIDs(PhabricatorLiskDAO $object) {
499 $this->requireAuditors($object);
501 $phids = array();
503 foreach ($object->getAudits() as $auditor) {
504 if ($auditor->isResigned()) {
505 $phids[] = $auditor->getAuditorPHID();
509 return $phids;
512 protected function getObjectLinkButtonLabelForMail(
513 PhabricatorLiskDAO $object) {
514 return pht('View Commit');
517 protected function buildMailBody(
518 PhabricatorLiskDAO $object,
519 array $xactions) {
521 $body = parent::buildMailBody($object, $xactions);
523 $type_inline = PhabricatorAuditActionConstants::INLINE;
524 $type_push = PhabricatorAuditTransaction::TYPE_COMMIT;
526 $is_commit = false;
527 $inlines = array();
528 foreach ($xactions as $xaction) {
529 if ($xaction->getTransactionType() == $type_inline) {
530 $inlines[] = $xaction;
532 if ($xaction->getTransactionType() == $type_push) {
533 $is_commit = true;
537 if ($inlines) {
538 $body->addTextSection(
539 pht('INLINE COMMENTS'),
540 $this->renderInlineCommentsForMail($object, $inlines));
543 if ($is_commit) {
544 $data = $object->getCommitData();
545 $body->addTextSection(pht('AFFECTED FILES'), $this->affectedFiles);
546 $this->inlinePatch(
547 $body,
548 $object);
551 $data = $object->getCommitData();
553 $user_phids = array();
555 $author_phid = $object->getAuthorPHID();
556 if ($author_phid) {
557 $user_phids[$author_phid][] = pht('Author');
560 $committer_phid = $data->getCommitDetail('committerPHID');
561 if ($committer_phid && ($committer_phid != $author_phid)) {
562 $user_phids[$committer_phid][] = pht('Committer');
565 foreach ($this->auditorPHIDs as $auditor_phid) {
566 $user_phids[$auditor_phid][] = pht('Auditor');
569 // TODO: It would be nice to show pusher here too, but that information
570 // is a little tricky to get at right now.
572 if ($user_phids) {
573 $handle_phids = array_keys($user_phids);
574 $handles = id(new PhabricatorHandleQuery())
575 ->setViewer($this->requireActor())
576 ->withPHIDs($handle_phids)
577 ->execute();
579 $user_info = array();
580 foreach ($user_phids as $phid => $roles) {
581 $user_info[] = pht(
582 '%s (%s)',
583 $handles[$phid]->getName(),
584 implode(', ', $roles));
587 $body->addTextSection(
588 pht('USERS'),
589 implode("\n", $user_info));
592 $monogram = $object->getRepository()->formatCommitName(
593 $object->getCommitIdentifier());
595 $body->addLinkSection(
596 pht('COMMIT'),
597 PhabricatorEnv::getProductionURI('/'.$monogram));
599 return $body;
602 private function attachPatch(
603 PhabricatorMetaMTAMail $template,
604 PhabricatorRepositoryCommit $commit) {
606 if (!$this->getRawPatch()) {
607 return;
610 $attach_key = 'metamta.diffusion.attach-patches';
611 $attach_patches = PhabricatorEnv::getEnvConfig($attach_key);
612 if (!$attach_patches) {
613 return;
616 $repository = $commit->getRepository();
617 $encoding = $repository->getDetail('encoding', 'UTF-8');
619 $raw_patch = $this->getRawPatch();
620 $commit_name = $repository->formatCommitName(
621 $commit->getCommitIdentifier());
623 $template->addAttachment(
624 new PhabricatorMailAttachment(
625 $raw_patch,
626 $commit_name.'.patch',
627 'text/x-patch; charset='.$encoding));
630 private function inlinePatch(
631 PhabricatorMetaMTAMailBody $body,
632 PhabricatorRepositoryCommit $commit) {
634 if (!$this->getRawPatch()) {
635 return;
638 $inline_key = 'metamta.diffusion.inline-patches';
639 $inline_patches = PhabricatorEnv::getEnvConfig($inline_key);
640 if (!$inline_patches) {
641 return;
644 $repository = $commit->getRepository();
645 $raw_patch = $this->getRawPatch();
646 $result = null;
647 $len = substr_count($raw_patch, "\n");
648 if ($len <= $inline_patches) {
649 // We send email as utf8, so we need to convert the text to utf8 if
650 // we can.
651 $encoding = $repository->getDetail('encoding', 'UTF-8');
652 if ($encoding) {
653 $raw_patch = phutil_utf8_convert($raw_patch, 'UTF-8', $encoding);
655 $result = phutil_utf8ize($raw_patch);
658 if ($result) {
659 $result = "PATCH\n\n{$result}\n";
661 $body->addRawSection($result);
664 private function renderInlineCommentsForMail(
665 PhabricatorLiskDAO $object,
666 array $inline_xactions) {
668 $inlines = mpull($inline_xactions, 'getComment');
670 $block = array();
672 $path_map = id(new DiffusionPathQuery())
673 ->withPathIDs(mpull($inlines, 'getPathID'))
674 ->execute();
675 $path_map = ipull($path_map, 'path', 'id');
677 foreach ($inlines as $inline) {
678 $path = idx($path_map, $inline->getPathID());
679 if ($path === null) {
680 continue;
683 $start = $inline->getLineNumber();
684 $len = $inline->getLineLength();
685 if ($len) {
686 $range = $start.'-'.($start + $len);
687 } else {
688 $range = $start;
691 $content = $inline->getContent();
692 $block[] = "{$path}:{$range} {$content}";
695 return implode("\n", $block);
698 public function getMailTagsMap() {
699 return array(
700 PhabricatorAuditTransaction::MAILTAG_COMMIT =>
701 pht('A commit is created.'),
702 PhabricatorAuditTransaction::MAILTAG_ACTION_CONCERN =>
703 pht('A commit has a concerned raised against it.'),
704 PhabricatorAuditTransaction::MAILTAG_ACTION_ACCEPT =>
705 pht('A commit is accepted.'),
706 PhabricatorAuditTransaction::MAILTAG_ACTION_RESIGN =>
707 pht('A commit has an auditor resign.'),
708 PhabricatorAuditTransaction::MAILTAG_ACTION_CLOSE =>
709 pht('A commit is closed.'),
710 PhabricatorAuditTransaction::MAILTAG_ADD_AUDITORS =>
711 pht('A commit has auditors added.'),
712 PhabricatorAuditTransaction::MAILTAG_ADD_CCS =>
713 pht("A commit's subscribers change."),
714 PhabricatorAuditTransaction::MAILTAG_PROJECTS =>
715 pht("A commit's projects change."),
716 PhabricatorAuditTransaction::MAILTAG_COMMENT =>
717 pht('Someone comments on a commit.'),
718 PhabricatorAuditTransaction::MAILTAG_OTHER =>
719 pht('Other commit activity not listed above occurs.'),
723 protected function shouldApplyHeraldRules(
724 PhabricatorLiskDAO $object,
725 array $xactions) {
727 foreach ($xactions as $xaction) {
728 switch ($xaction->getTransactionType()) {
729 case PhabricatorAuditTransaction::TYPE_COMMIT:
730 $repository = $object->getRepository();
731 $publisher = $repository->newPublisher();
732 if (!$publisher->shouldPublishCommit($object)) {
733 return false;
735 return true;
736 default:
737 break;
740 return parent::shouldApplyHeraldRules($object, $xactions);
743 protected function buildHeraldAdapter(
744 PhabricatorLiskDAO $object,
745 array $xactions) {
746 return id(new HeraldCommitAdapter())
747 ->setObject($object);
750 protected function didApplyHeraldRules(
751 PhabricatorLiskDAO $object,
752 HeraldAdapter $adapter,
753 HeraldTranscript $transcript) {
755 $limit = self::MAX_FILES_SHOWN_IN_EMAIL;
756 $files = $adapter->loadAffectedPaths();
757 sort($files);
758 if (count($files) > $limit) {
759 array_splice($files, $limit);
760 $files[] = pht(
761 '(This commit affected more than %d files. Only %d are shown here '.
762 'and additional ones are truncated.)',
763 $limit,
764 $limit);
766 $this->affectedFiles = implode("\n", $files);
768 return array();
771 private function isCommitMostlyImported(PhabricatorLiskDAO $object) {
772 $has_message = PhabricatorRepositoryCommit::IMPORTED_MESSAGE;
773 $has_changes = PhabricatorRepositoryCommit::IMPORTED_CHANGE;
775 // Don't publish feed stories or email about events which occur during
776 // import. In particular, this affects tasks being attached when they are
777 // closed by "Fixes Txxxx" in a commit message. See T5851.
779 $mask = ($has_message | $has_changes);
781 return $object->isPartiallyImported($mask);
785 private function shouldPublishRepositoryActivity(
786 PhabricatorLiskDAO $object,
787 array $xactions) {
789 // not every code path loads the repository so tread carefully
790 // TODO: They should, and then we should simplify this.
791 $repository = $object->getRepository($assert_attached = false);
792 if ($repository != PhabricatorLiskDAO::ATTACHABLE) {
793 $publisher = $repository->newPublisher();
794 if (!$publisher->shouldPublishCommit($object)) {
795 return false;
799 return $this->isCommitMostlyImported($object);
802 protected function shouldSendMail(
803 PhabricatorLiskDAO $object,
804 array $xactions) {
805 return $this->shouldPublishRepositoryActivity($object, $xactions);
808 protected function shouldEnableMentions(
809 PhabricatorLiskDAO $object,
810 array $xactions) {
811 return $this->shouldPublishRepositoryActivity($object, $xactions);
814 protected function shouldPublishFeedStory(
815 PhabricatorLiskDAO $object,
816 array $xactions) {
817 return $this->shouldPublishRepositoryActivity($object, $xactions);
820 protected function getCustomWorkerState() {
821 return array(
822 'rawPatch' => $this->rawPatch,
823 'affectedFiles' => $this->affectedFiles,
824 'auditorPHIDs' => $this->auditorPHIDs,
828 protected function getCustomWorkerStateEncoding() {
829 return array(
830 'rawPatch' => self::STORAGE_ENCODING_BINARY,
834 protected function loadCustomWorkerState(array $state) {
835 $this->rawPatch = idx($state, 'rawPatch');
836 $this->affectedFiles = idx($state, 'affectedFiles');
837 $this->auditorPHIDs = idx($state, 'auditorPHIDs');
838 return $this;
841 protected function willPublish(PhabricatorLiskDAO $object, array $xactions) {
842 return id(new DiffusionCommitQuery())
843 ->setViewer($this->requireActor())
844 ->withIDs(array($object->getID()))
845 ->needAuditRequests(true)
846 ->needCommitData(true)
847 ->executeOne();
850 private function requireAuditors(PhabricatorRepositoryCommit $commit) {
851 if ($commit->hasAttachedAudits()) {
852 return;
855 $with_auditors = id(new DiffusionCommitQuery())
856 ->setViewer($this->getActor())
857 ->needAuditRequests(true)
858 ->withPHIDs(array($commit->getPHID()))
859 ->executeOne();
860 if (!$with_auditors) {
861 throw new Exception(
862 pht(
863 'Failed to reload commit ("%s").',
864 $commit->getPHID()));
867 $commit->attachAudits($with_auditors->getAudits());