/**
  * Validate that the edit is permissible, and the actor has permission to
  * perform it.
  */
 private function validateEdit(PhabricatorApplicationTransaction $xaction, PhabricatorApplicationTransactionComment $comment)
 {
     if (!$xaction->getPHID()) {
         throw new Exception('Transaction must have a PHID before calling applyEdit()!');
     }
     $type_comment = PhabricatorTransactions::TYPE_COMMENT;
     if ($xaction->getTransactionType() == $type_comment) {
         if ($comment->getPHID()) {
             throw new Exception('Transaction comment must not yet have a PHID!');
         }
     }
     if (!$this->getContentSource()) {
         throw new Exception('Call setContentSource() before applyEdit()!');
     }
     $actor = $this->requireActor();
     PhabricatorPolicyFilter::requireCapability($actor, $xaction, PhabricatorPolicyCapability::CAN_VIEW);
     if ($comment->getIsRemoved() && $actor->getIsAdmin()) {
         // NOTE: Administrators can remove comments by any user, and don't need
         // to pass the edit check.
     } else {
         PhabricatorPolicyFilter::requireCapability($actor, $xaction, PhabricatorPolicyCapability::CAN_EDIT);
     }
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case ConpherenceTransaction::TYPE_FILES:
             $editor = new PhabricatorEdgeEditor();
             $edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
             $old = array_fill_keys($xaction->getOldValue(), true);
             $new = array_fill_keys($xaction->getNewValue(), true);
             $add_edges = array_keys(array_diff_key($new, $old));
             $remove_edges = array_keys(array_diff_key($old, $new));
             foreach ($add_edges as $file_phid) {
                 $editor->addEdge($object->getPHID(), $edge_type, $file_phid);
             }
             foreach ($remove_edges as $file_phid) {
                 $editor->removeEdge($object->getPHID(), $edge_type, $file_phid);
             }
             $editor->save();
             break;
         case ConpherenceTransaction::TYPE_PARTICIPANTS:
             if ($this->getIsNewObject()) {
                 continue;
             }
             $participants = $object->getParticipants();
             $old_map = array_fuse($xaction->getOldValue());
             $new_map = array_fuse($xaction->getNewValue());
             $remove = array_keys(array_diff_key($old_map, $new_map));
             foreach ($remove as $phid) {
                 $remove_participant = $participants[$phid];
                 $remove_participant->delete();
                 unset($participants[$phid]);
             }
             $add = array_keys(array_diff_key($new_map, $old_map));
             foreach ($add as $phid) {
                 if ($phid == $this->getActor()->getPHID()) {
                     $status = ConpherenceParticipationStatus::UP_TO_DATE;
                     $message_count = $object->getMessageCount();
                 } else {
                     $status = ConpherenceParticipationStatus::BEHIND;
                     $message_count = 0;
                 }
                 $participants[$phid] = id(new ConpherenceParticipant())->setConpherencePHID($object->getPHID())->setParticipantPHID($phid)->setParticipationStatus($status)->setDateTouched(time())->setBehindTransactionPHID($xaction->getPHID())->setSeenMessageCount($message_count)->save();
             }
             $object->attachParticipants($participants);
             break;
     }
 }
 private function renderEvent(PhabricatorApplicationTransaction $xaction, array $group)
 {
     $viewer = $this->getUser();
     $event = id(new PHUITimelineEventView())->setUser($viewer)->setAuthorPHID($xaction->getAuthorPHID())->setTransactionPHID($xaction->getPHID())->setUserHandle($xaction->getHandle($xaction->getAuthorPHID()))->setIcon($xaction->getIcon())->setColor($xaction->getColor())->setHideCommentOptions($this->getHideCommentOptions());
     list($token, $token_removed) = $xaction->getToken();
     if ($token) {
         $event->setToken($token, $token_removed);
     }
     if (!$this->shouldSuppressTitle($xaction, $group)) {
         if ($this->renderAsFeed) {
             $title = $xaction->getTitleForFeed();
         } else {
             $title = $xaction->getTitle();
         }
         if ($xaction->hasChangeDetails()) {
             if (!$this->isPreview) {
                 $details = $this->buildChangeDetailsLink($xaction);
                 $title = array($title, ' ', $details);
             }
         }
         if (!$this->isPreview) {
             $more = $this->buildExtraInformationLink($xaction);
             if ($more) {
                 $title = array($title, ' ', $more);
             }
         }
         $event->setTitle($title);
     }
     if ($this->isPreview) {
         $event->setIsPreview(true);
     } else {
         $event->setDateCreated($xaction->getDateCreated())->setContentSource($xaction->getContentSource())->setAnchor($xaction->getID());
     }
     $transaction_type = $xaction->getTransactionType();
     $comment_type = PhabricatorTransactions::TYPE_COMMENT;
     $is_normal_comment = $transaction_type == $comment_type;
     if ($this->getShowEditActions() && !$this->isPreview && $is_normal_comment) {
         $has_deleted_comment = $xaction->getComment() && $xaction->getComment()->getIsDeleted();
         $has_removed_comment = $xaction->getComment() && $xaction->getComment()->getIsRemoved();
         if ($xaction->getCommentVersion() > 1 && !$has_removed_comment) {
             $event->setIsEdited(true);
         }
         if (!$has_removed_comment) {
             $event->setIsNormalComment(true);
         }
         // If we have a place for quoted text to go and this is a quotable
         // comment, pass the quote target ID to the event view.
         if ($this->getQuoteTargetID()) {
             if ($xaction->hasComment()) {
                 if (!$has_removed_comment && !$has_deleted_comment) {
                     $event->setQuoteTargetID($this->getQuoteTargetID());
                     $event->setQuoteRef($this->getQuoteRef());
                 }
             }
         }
         $can_edit = PhabricatorPolicyCapability::CAN_EDIT;
         if ($xaction->hasComment() || $has_deleted_comment) {
             $has_edit_capability = PhabricatorPolicyFilter::hasCapability($viewer, $xaction, $can_edit);
             if ($has_edit_capability && !$has_removed_comment) {
                 $event->setIsEditable(true);
             }
             if ($has_edit_capability || $viewer->getIsAdmin()) {
                 if (!$has_removed_comment) {
                     $event->setIsRemovable(true);
                 }
             }
         }
     }
     $comment = $this->renderTransactionContent($xaction);
     if ($comment) {
         $event->appendChild($comment);
     }
     return $event;
 }