protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorMacroTransaction::TYPE_FILE:
         case PhabricatorMacroTransaction::TYPE_AUDIO:
             // When changing a macro's image or audio, attach the underlying files
             // to the macro (and detach the old files).
             $old = $xaction->getOldValue();
             $new = $xaction->getNewValue();
             $all = array();
             if ($old) {
                 $all[] = $old;
             }
             if ($new) {
                 $all[] = $new;
             }
             $files = id(new PhabricatorFileQuery())->setViewer($this->requireActor())->withPHIDs($all)->execute();
             $files = mpull($files, null, 'getPHID');
             $old_file = idx($files, $old);
             if ($old_file) {
                 $old_file->detachFromObject($object->getPHID());
             }
             $new_file = idx($files, $new);
             if ($new_file) {
                 $new_file->attachToObject($object->getPHID());
             }
             break;
     }
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case AlmanacDeviceTransaction::TYPE_NAME:
             return;
         case AlmanacDeviceTransaction::TYPE_INTERFACE:
             $old = $xaction->getOldValue();
             if ($old) {
                 $interface = id(new AlmanacInterfaceQuery())->setViewer($this->requireActor())->withIDs(array($old['id']))->executeOne();
                 if (!$interface) {
                     throw new Exception(pht('Unable to load interface!'));
                 }
             } else {
                 $interface = AlmanacInterface::initializeNewInterface()->setDevicePHID($object->getPHID());
             }
             $new = $xaction->getNewValue();
             if ($new) {
                 $interface->setNetworkPHID($new['networkPHID'])->setAddress($new['address'])->setPort((int) $new['port']);
                 if (idx($new, 'phid')) {
                     $interface->setPHID($new['phid']);
                 }
                 $interface->save();
             } else {
                 $interface->delete();
             }
             return;
     }
     return parent::applyCustomExternalTransaction($object, $xaction);
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorTransactions::TYPE_COMMENT:
         case PhabricatorTransactions::TYPE_SUBSCRIBERS:
         case PhabricatorTransactions::TYPE_EDGE:
         case PhabricatorAuditActionConstants::ACTION:
         case PhabricatorAuditActionConstants::INLINE:
             return;
         case PhabricatorAuditActionConstants::ADD_AUDITORS:
             $new = $xaction->getNewValue();
             if (!is_array($new)) {
                 $new = array();
             }
             $old = $xaction->getOldValue();
             if (!is_array($old)) {
                 $old = array();
             }
             $add = array_diff_key($new, $old);
             $actor = $this->requireActor();
             $requests = $object->getAudits();
             $requests = mpull($requests, null, 'getAuditorPHID');
             foreach ($add as $phid) {
                 if (isset($requests[$phid])) {
                     continue;
                 }
                 $audit_requested = PhabricatorAuditStatusConstants::AUDIT_REQUESTED;
                 $requests[] = id(new PhabricatorRepositoryAuditRequest())->setCommitPHID($object->getPHID())->setAuditorPHID($phid)->setAuditStatus($audit_requested)->setAuditReasons(array('Added by ' . $actor->getUsername()))->save();
             }
             $object->attachAudits($requests);
             return;
     }
     return parent::applyCustomExternalTransaction($object, $xaction);
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case AlmanacBindingTransaction::TYPE_DISABLE:
             return;
         case AlmanacBindingTransaction::TYPE_INTERFACE:
             $interface_phids = array();
             $interface_phids[] = $xaction->getOldValue();
             $interface_phids[] = $xaction->getNewValue();
             $interface_phids = array_filter($interface_phids);
             $interface_phids = array_unique($interface_phids);
             $interfaces = id(new AlmanacInterfaceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($interface_phids)->execute();
             $device_phids = array();
             foreach ($interfaces as $interface) {
                 $device_phids[] = $interface->getDevicePHID();
             }
             $device_phids = array_unique($device_phids);
             $devices = id(new AlmanacDeviceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($device_phids)->execute();
             foreach ($devices as $device) {
                 $device->rebuildClusterBindingStatus();
             }
             return;
     }
     return parent::applyCustomExternalTransaction($object, $xaction);
 }
 public function getApplicationTransactionTitleForFeed(PhabricatorApplicationTransaction $xaction)
 {
     $object_phid = $xaction->getObjectPHID();
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     return pht('%s updated the blame revision for %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid));
 }
 public function getApplicationTransactionTitle(PhabricatorApplicationTransaction $xaction)
 {
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     if ($new) {
         return pht('%s checked %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName());
     } else {
         return pht('%s unchecked %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName());
     }
 }
 public function getApplicationTransactionTitleForFeed(PhabricatorApplicationTransaction $xaction, PhabricatorFeedStory $story)
 {
     $object_phid = $xaction->getObjectPHID();
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     if (strlen($old)) {
         return pht('%s retitled %s, from "%s" to "%s".', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid), $old, $new);
     } else {
         return pht('%s created %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid));
     }
 }
 public function getApplicationTransactionTitleForFeed(PhabricatorApplicationTransaction $xaction, PhabricatorFeedStory $story)
 {
     $object_phid = $xaction->getObjectPHID();
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     if ($old) {
         return pht('%s updated the repository for %s from %s to %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid), $xaction->renderHandleLink($old), $xaction->renderHandleLink($new));
     } else {
         return pht('%s set the repository for %s to %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($object_phid), $xaction->renderHandleLink($new));
     }
 }
 public function getApplicationTransactionHasEffect(PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     if (!strlen($old) && strlen($new)) {
         return true;
     } else {
         if (strlen($old) && !strlen($new)) {
             return true;
         } else {
             return (int) $old !== (int) $new;
         }
     }
 }
 protected function transactionHasEffect(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     $type = $xaction->getTransactionType();
     switch ($type) {
         case PhabricatorConfigTransaction::TYPE_EDIT:
             // If an edit deletes an already-deleted entry, no-op it.
             if (idx($old, 'deleted') && idx($new, 'deleted')) {
                 return false;
             }
             break;
     }
     return parent::transactionHasEffect($object, $xaction);
 }
 public function getApplicationTransactionTitle(PhabricatorApplicationTransaction $xaction)
 {
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     if ($old && !$new) {
         return pht('%s removed %s as %s.', $xaction->renderHandleLink($author_phid), $xaction->renderHandleLink($old), $this->getFieldName());
     } else {
         if ($new && !$old) {
             return pht('%s set %s to %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), $xaction->renderHandleLink($new));
         } else {
             return pht('%s changed %s from %s to %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), $xaction->renderHandleLink($old), $xaction->renderHandleLink($new));
         }
     }
 }
 public function applyApplicationTransactionExternalEffects(PhabricatorApplicationTransaction $xaction)
 {
     $object_phid = $xaction->getObjectPHID();
     $old = $this->decodeValue($xaction->getOldValue());
     $new = $this->decodeValue($xaction->getNewValue());
     $old_phids = array_fuse($old);
     $new_phids = array_fuse($new);
     $rem_phids = array_diff_key($old_phids, $new_phids);
     $add_phids = array_diff_key($new_phids, $old_phids);
     $altered_phids = $rem_phids + $add_phids;
     if (!$altered_phids) {
         return;
     }
     $authorizations = id(new DrydockAuthorizationQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withObjectPHIDs(array($object_phid))->withBlueprintPHIDs($altered_phids)->execute();
     $authorizations = mpull($authorizations, null, 'getBlueprintPHID');
     $state_active = DrydockAuthorization::OBJECTAUTH_ACTIVE;
     $state_inactive = DrydockAuthorization::OBJECTAUTH_INACTIVE;
     $state_requested = DrydockAuthorization::BLUEPRINTAUTH_REQUESTED;
     // Disable the object side of the authorization for any existing
     // authorizations.
     foreach ($rem_phids as $rem_phid) {
         $authorization = idx($authorizations, $rem_phid);
         if (!$authorization) {
             continue;
         }
         $authorization->setObjectAuthorizationState($state_inactive)->save();
     }
     // For new authorizations, either add them or reactivate them depending
     // on the current state.
     foreach ($add_phids as $add_phid) {
         $needs_update = false;
         $authorization = idx($authorizations, $add_phid);
         if (!$authorization) {
             $authorization = id(new DrydockAuthorization())->setObjectPHID($object_phid)->setObjectAuthorizationState($state_active)->setBlueprintPHID($add_phid)->setBlueprintAuthorizationState($state_requested);
             $needs_update = true;
         } else {
             $current_state = $authorization->getObjectAuthorizationState();
             if ($current_state != $state_active) {
                 $authorization->setObjectAuthorizationState($state_active);
                 $needs_update = true;
             }
         }
         if ($needs_update) {
             $authorization->save();
         }
     }
 }
 protected function transactionHasEffect(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     switch ($xaction->getTransactionType()) {
         case PhabricatorSlowvoteTransaction::TYPE_RESPONSES:
             if ($old === null) {
                 return true;
             }
             return (int) $old !== (int) $new;
         case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE:
             if ($old === null) {
                 return true;
             }
             return (bool) $old !== (bool) $new;
     }
     return parent::transactionHasEffect($object, $xaction);
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case ManiphestTransaction::TYPE_PROJECT_COLUMN:
             $board_phid = idx($xaction->getNewValue(), 'projectPHID');
             if (!$board_phid) {
                 throw new Exception(pht("Expected '%s' in column transaction.", 'projectPHID'));
             }
             $old_phids = idx($xaction->getOldValue(), 'columnPHIDs', array());
             $new_phids = idx($xaction->getNewValue(), 'columnPHIDs', array());
             if (count($new_phids) !== 1) {
                 throw new Exception(pht("Expected exactly one '%s' in column transaction.", 'columnPHIDs'));
             }
             $columns = id(new PhabricatorProjectColumnQuery())->setViewer($this->requireActor())->withPHIDs($new_phids)->execute();
             $columns = mpull($columns, null, 'getPHID');
             $positions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($this->requireActor())->withObjectPHIDs(array($object->getPHID()))->withBoardPHIDs(array($board_phid))->execute();
             $before_phid = idx($xaction->getNewValue(), 'beforePHID');
             $after_phid = idx($xaction->getNewValue(), 'afterPHID');
             if (!$before_phid && !$after_phid && $old_phids == $new_phids) {
                 // If we are not moving the object between columns and also not
                 // reordering the position, this is a move on some other order
                 // (like priority). We can leave the positions untouched and just
                 // bail, there's no work to be done.
                 return;
             }
             // Otherwise, we're either moving between columns or adjusting the
             // object's position in the "natural" ordering, so we do need to update
             // some rows.
             // Remove all existing column positions on the board.
             foreach ($positions as $position) {
                 $position->delete();
             }
             // Add the new column positions.
             foreach ($new_phids as $phid) {
                 $column = idx($columns, $phid);
                 if (!$column) {
                     throw new Exception(pht('No such column "%s" exists!', $phid));
                 }
                 // Load the other object positions in the column. Note that we must
                 // skip implicit column creation to avoid generating a new position
                 // if the target column is a backlog column.
                 $other_positions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($this->requireActor())->withColumns(array($column))->withBoardPHIDs(array($board_phid))->setSkipImplicitCreate(true)->execute();
                 $other_positions = msort($other_positions, 'getOrderingKey');
                 // Set up the new position object. We're going to figure out the
                 // right sequence number and then persist this object with that
                 // sequence number.
                 $new_position = id(new PhabricatorProjectColumnPosition())->setBoardPHID($board_phid)->setColumnPHID($column->getPHID())->setObjectPHID($object->getPHID());
                 $updates = array();
                 $sequence = 0;
                 // If we're just dropping this into the column without any specific
                 // position information, put it at the top.
                 if (!$before_phid && !$after_phid) {
                     $new_position->setSequence($sequence)->save();
                     $sequence++;
                 }
                 foreach ($other_positions as $position) {
                     $object_phid = $position->getObjectPHID();
                     // If this is the object we're moving before and we haven't
                     // saved yet, insert here.
                     if ($before_phid == $object_phid && !$new_position->getID()) {
                         $new_position->setSequence($sequence)->save();
                         $sequence++;
                     }
                     // This object goes here in the sequence; we might need to update
                     // the row.
                     if ($sequence != $position->getSequence()) {
                         $updates[$position->getID()] = $sequence;
                     }
                     $sequence++;
                     // If this is the object we're moving after and we haven't saved
                     // yet, insert here.
                     if ($after_phid == $object_phid && !$new_position->getID()) {
                         $new_position->setSequence($sequence)->save();
                         $sequence++;
                     }
                 }
                 // We should have found a place to put it.
                 if (!$new_position->getID()) {
                     throw new Exception(pht('Unable to find a place to insert object on column!'));
                 }
                 // If we changed other objects' column positions, bulk reorder them.
                 if ($updates) {
                     $position = new PhabricatorProjectColumnPosition();
                     $conn_w = $position->establishConnection('w');
                     $pairs = array();
                     foreach ($updates as $id => $sequence) {
                         // This is ugly because MySQL gets upset with us if it is
                         // configured strictly and we attempt inserts which can't work.
                         // We'll never actually do these inserts since they'll always
                         // collide (triggering the ON DUPLICATE KEY logic), so we just
                         // provide dummy values in order to get there.
                         $pairs[] = qsprintf($conn_w, '(%d, %d, "", "", "")', $id, $sequence);
                     }
                     queryfx($conn_w, 'INSERT INTO %T (id, sequence, boardPHID, columnPHID, objectPHID)
             VALUES %Q ON DUPLICATE KEY UPDATE sequence = VALUES(sequence)', $position->getTableName(), implode(', ', $pairs));
                 }
             }
             break;
         default:
             break;
     }
 }
 private function applyInverseEdgeTransactions(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction, $inverse_type)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     $add = array_keys(array_diff_key($new, $old));
     $rem = array_keys(array_diff_key($old, $new));
     $add = array_fuse($add);
     $rem = array_fuse($rem);
     $all = $add + $rem;
     $nodes = id(new PhabricatorObjectQuery())->setViewer($this->requireActor())->withPHIDs($all)->execute();
     foreach ($nodes as $node) {
         if (!$node instanceof PhabricatorApplicationTransactionInterface) {
             continue;
         }
         $editor = $node->getApplicationTransactionEditor();
         $template = $node->getApplicationTransactionTemplate();
         $target = $node->getApplicationTransactionObject();
         if (isset($add[$node->getPHID()])) {
             $edge_edit_type = '+';
         } else {
             $edge_edit_type = '-';
         }
         $template->setTransactionType($xaction->getTransactionType())->setMetadataValue('edge:type', $inverse_type)->setNewValue(array($edge_edit_type => array($object->getPHID() => $object->getPHID())));
         $editor->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->setParentMessageID($this->getParentMessageID())->setIsInverseEdgeEditor(true)->setActor($this->requireActor())->setActingAsPHID($this->getActingAsPHID())->setContentSource($this->getContentSource());
         $editor->applyTransactions($target, array($template));
     }
 }
 protected function requireCapabilities(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorProjectTransaction::TYPE_NAME:
         case PhabricatorProjectTransaction::TYPE_STATUS:
         case PhabricatorProjectTransaction::TYPE_IMAGE:
         case PhabricatorProjectTransaction::TYPE_ICON:
         case PhabricatorProjectTransaction::TYPE_COLOR:
             PhabricatorPolicyFilter::requireCapability($this->requireActor(), $object, PhabricatorPolicyCapability::CAN_EDIT);
             return;
         case PhabricatorProjectTransaction::TYPE_LOCKED:
             PhabricatorPolicyFilter::requireCapability($this->requireActor(), newv($this->getEditorApplicationClass(), array()), ProjectCanLockProjectsCapability::CAPABILITY);
             return;
         case PhabricatorTransactions::TYPE_EDGE:
             switch ($xaction->getMetadataValue('edge:type')) {
                 case PhabricatorProjectProjectHasMemberEdgeType::EDGECONST:
                     $old = $xaction->getOldValue();
                     $new = $xaction->getNewValue();
                     $add = array_keys(array_diff_key($new, $old));
                     $rem = array_keys(array_diff_key($old, $new));
                     $actor_phid = $this->requireActor()->getPHID();
                     $is_join = $add === array($actor_phid) && !$rem;
                     $is_leave = $rem === array($actor_phid) && !$add;
                     if ($is_join) {
                         // You need CAN_JOIN to join a project.
                         PhabricatorPolicyFilter::requireCapability($this->requireActor(), $object, PhabricatorPolicyCapability::CAN_JOIN);
                     } else {
                         if ($is_leave) {
                             // You usually don't need any capabilities to leave a project.
                             if ($object->getIsMembershipLocked()) {
                                 // you must be able to edit though to leave locked projects
                                 PhabricatorPolicyFilter::requireCapability($this->requireActor(), $object, PhabricatorPolicyCapability::CAN_EDIT);
                             }
                         } else {
                             // You need CAN_EDIT to change members other than yourself.
                             PhabricatorPolicyFilter::requireCapability($this->requireActor(), $object, PhabricatorPolicyCapability::CAN_EDIT);
                         }
                     }
                     return;
             }
             break;
     }
     return parent::requireCapabilities($object, $xaction);
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorAuditActionConstants::ACTION:
         case PhabricatorAuditTransaction::TYPE_COMMIT:
             return;
         case PhabricatorAuditActionConstants::INLINE:
             $reply = $xaction->getComment()->getReplyToComment();
             if ($reply && !$reply->getHasReplies()) {
                 $reply->setHasReplies(1)->save();
             }
             return;
         case PhabricatorAuditActionConstants::ADD_AUDITORS:
             $new = $xaction->getNewValue();
             if (!is_array($new)) {
                 $new = array();
             }
             $old = $xaction->getOldValue();
             if (!is_array($old)) {
                 $old = array();
             }
             $add = array_diff_key($new, $old);
             $actor = $this->requireActor();
             $requests = $object->getAudits();
             $requests = mpull($requests, null, 'getAuditorPHID');
             foreach ($add as $phid) {
                 if (isset($requests[$phid])) {
                     continue;
                 }
                 if ($this->getIsHeraldEditor()) {
                     $audit_requested = $xaction->getMetadataValue('auditStatus');
                     $audit_reason_map = $xaction->getMetadataValue('auditReasonMap');
                     $audit_reason = $audit_reason_map[$phid];
                 } else {
                     $audit_requested = PhabricatorAuditStatusConstants::AUDIT_REQUESTED;
                     $audit_reason = $this->getAuditReasons($phid);
                 }
                 $requests[] = id(new PhabricatorRepositoryAuditRequest())->setCommitPHID($object->getPHID())->setAuditorPHID($phid)->setAuditStatus($audit_requested)->setAuditReasons($audit_reason)->save();
             }
             $object->attachAudits($requests);
             return;
     }
     return parent::applyCustomExternalTransaction($object, $xaction);
 }
 public function getApplicationTransactionChangeDetails(PhabricatorApplicationTransaction $xaction, PhabricatorUser $viewer)
 {
     return $xaction->renderTextCorpusChangeDetails($viewer, $xaction->getOldValue(), $xaction->getNewValue());
 }
Example #19
0
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PholioTransactionType::TYPE_IMAGE_FILE:
             $old_map = array_fuse($xaction->getOldValue());
             $new_map = array_fuse($xaction->getNewValue());
             $obsolete_map = array_diff_key($old_map, $new_map);
             $images = $object->getImages();
             foreach ($images as $seq => $image) {
                 if (isset($obsolete_map[$image->getPHID()])) {
                     $image->setIsObsolete(1);
                     $image->save();
                     unset($images[$seq]);
                 }
             }
             $object->attachImages($images);
             break;
         case PholioTransactionType::TYPE_IMAGE_REPLACE:
             $old = $xaction->getOldValue();
             $images = $object->getImages();
             foreach ($images as $seq => $image) {
                 if ($image->getPHID() == $old) {
                     $image->setIsObsolete(1);
                     $image->save();
                     unset($images[$seq]);
                 }
             }
             $object->attachImages($images);
             break;
         case PholioTransactionType::TYPE_IMAGE_NAME:
             $image = $this->getImageForXaction($object, $xaction);
             $value = (string) head($xaction->getNewValue());
             $image->setName($value);
             $image->save();
             break;
         case PholioTransactionType::TYPE_IMAGE_DESCRIPTION:
             $image = $this->getImageForXaction($object, $xaction);
             $value = (string) head($xaction->getNewValue());
             $image->setDescription($value);
             $image->save();
             break;
         case PholioTransactionType::TYPE_IMAGE_SEQUENCE:
             $image = $this->getImageForXaction($object, $xaction);
             $value = (int) head($xaction->getNewValue());
             $image->setSequence($value);
             $image->save();
             break;
         case PhabricatorTransactions::TYPE_EDGE:
             return;
     }
 }
 public function getApplicationTransactionTitle(PhabricatorApplicationTransaction $xaction)
 {
     $author_phid = $xaction->getAuthorPHID();
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     $viewer = $this->getViewer();
     $old_date = null;
     if ($old) {
         $old_date = phabricator_datetime($old, $viewer);
     }
     $new_date = null;
     if ($new) {
         $new_date = phabricator_datetime($new, $viewer);
     }
     if (!$old) {
         return pht('%s set %s to %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), $new_date);
     } else {
         if (!$new) {
             return pht('%s removed %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName());
         } else {
             return pht('%s changed %s from %s to %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), $old_date, $new_date);
         }
     }
 }
 protected function transactionHasEffect(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     $type = $xaction->getTransactionType();
     switch ($type) {
     }
     return parent::transactionHasEffect($object, $xaction);
 }
 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;
     }
 }
 public function getApplicationTransactionTitle(PhabricatorApplicationTransaction $xaction)
 {
     $author_phid = $xaction->getAuthorPHID();
     $old = $this->decodeValue($xaction->getOldValue());
     $new = $this->decodeValue($xaction->getNewValue());
     $add = array_diff($new, $old);
     $rem = array_diff($old, $new);
     if ($add && !$rem) {
         return pht('%s updated %s, added %d: %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), new PhutilNumber(count($add)), $xaction->renderHandleList($add));
     } else {
         if ($rem && !$add) {
             return pht('%s updated %s, removed %d: %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), new PhutilNumber(count($rem)), $xaction->renderHandleList($rem));
         } else {
             return pht('%s updated %s, added %d: %s; removed %d: %s.', $xaction->renderHandleLink($author_phid), $this->getFieldName(), new PhutilNumber(count($add)), $xaction->renderHandleList($add), new PhutilNumber(count($rem)), $xaction->renderHandleList($rem));
         }
     }
 }
 protected function applyCustomInternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PonderQuestionTransaction::TYPE_TITLE:
             $object->setTitle($xaction->getNewValue());
             break;
         case PonderQuestionTransaction::TYPE_CONTENT:
             $object->setContent($xaction->getNewValue());
             break;
         case PonderQuestionTransaction::TYPE_STATUS:
             $object->setStatus($xaction->getNewValue());
             break;
         case PonderQuestionTransaction::TYPE_ANSWERS:
             $old = $xaction->getOldValue();
             $new = $xaction->getNewValue();
             $add = array_diff_key($new, $old);
             $rem = array_diff_key($old, $new);
             $count = $object->getAnswerCount();
             $count += count($add);
             $count -= count($rem);
             $object->setAnswerCount($count);
             break;
     }
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case ManiphestTransaction::TYPE_PARENT:
             $parent_phid = $xaction->getNewValue();
             $parent_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
             $task_phid = $object->getPHID();
             id(new PhabricatorEdgeEditor())->addEdge($parent_phid, $parent_type, $task_phid)->save();
             break;
         case ManiphestTransaction::TYPE_PROJECT_COLUMN:
             $board_phid = idx($xaction->getNewValue(), 'projectPHID');
             if (!$board_phid) {
                 throw new Exception(pht("Expected '%s' in column transaction.", 'projectPHID'));
             }
             $old_phids = idx($xaction->getOldValue(), 'columnPHIDs', array());
             $new_phids = idx($xaction->getNewValue(), 'columnPHIDs', array());
             if (count($new_phids) !== 1) {
                 throw new Exception(pht("Expected exactly one '%s' in column transaction.", 'columnPHIDs'));
             }
             $before_phid = idx($xaction->getNewValue(), 'beforePHID');
             $after_phid = idx($xaction->getNewValue(), 'afterPHID');
             if (!$before_phid && !$after_phid && $old_phids == $new_phids) {
                 // If we are not moving the object between columns and also not
                 // reordering the position, this is a move on some other order
                 // (like priority). We can leave the positions untouched and just
                 // bail, there's no work to be done.
                 return;
             }
             // Otherwise, we're either moving between columns or adjusting the
             // object's position in the "natural" ordering, so we do need to update
             // some rows.
             $object_phid = $object->getPHID();
             // We're doing layout with the ominpotent viewer to make sure we don't
             // remove positions in columns that exist, but which the actual actor
             // can't see.
             $omnipotent_viewer = PhabricatorUser::getOmnipotentUser();
             $select_phids = array($board_phid);
             $descendants = id(new PhabricatorProjectQuery())->setViewer($omnipotent_viewer)->withAncestorProjectPHIDs($select_phids)->execute();
             foreach ($descendants as $descendant) {
                 $select_phids[] = $descendant->getPHID();
             }
             $board_tasks = id(new ManiphestTaskQuery())->setViewer($omnipotent_viewer)->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_ANCESTOR, array($select_phids))->execute();
             $object_phids = mpull($board_tasks, 'getPHID');
             $object_phids[] = $object_phid;
             $engine = id(new PhabricatorBoardLayoutEngine())->setViewer($omnipotent_viewer)->setBoardPHIDs(array($board_phid))->setObjectPHIDs($object_phids)->executeLayout();
             // TODO: This logic needs to be revised if we legitimately support
             // multiple column positions.
             // NOTE: When a task is newly created, it's implicitly added to the
             // backlog but we don't currently record that in the "$old_phids". Just
             // clean it up for now.
             $columns = $engine->getObjectColumns($board_phid, $object_phid);
             foreach ($columns as $column) {
                 $engine->queueRemovePosition($board_phid, $column->getPHID(), $object_phid);
             }
             // Remove all existing column positions on the board.
             foreach ($old_phids as $column_phid) {
                 $engine->queueRemovePosition($board_phid, $column_phid, $object_phid);
             }
             // Add new positions.
             foreach ($new_phids as $column_phid) {
                 if ($before_phid) {
                     $engine->queueAddPositionBefore($board_phid, $column_phid, $object_phid, $before_phid);
                 } else {
                     if ($after_phid) {
                         $engine->queueAddPositionAfter($board_phid, $column_phid, $object_phid, $after_phid);
                     } else {
                         $engine->queueAddPosition($board_phid, $column_phid, $object_phid);
                     }
                 }
             }
             $engine->applyPositionUpdates();
             break;
         default:
             break;
     }
 }
 public function getApplicationTransactionTitle(PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     if (!is_array($old)) {
         $old = array();
     }
     $new = $xaction->getNewValue();
     if (!is_array($new)) {
         $new = array();
     }
     $add = array_diff($new, $old);
     $rem = array_diff($old, $new);
     $author_phid = $xaction->getAuthorPHID();
     if ($add && $rem) {
         return pht('%s updated JIRA issue(s): added %d %s; removed %d %s.', $xaction->renderHandleLink($author_phid), phutil_count($add), implode(', ', $add), phutil_count($rem), implode(', ', $rem));
     } else {
         if ($add) {
             return pht('%s added %d JIRA issue(s): %s.', $xaction->renderHandleLink($author_phid), phutil_count($add), implode(', ', $add));
         } else {
             if ($rem) {
                 return pht('%s removed %d JIRA issue(s): %s.', $xaction->renderHandleLink($author_phid), phutil_count($rem), implode(', ', $rem));
             }
         }
     }
     return parent::getApplicationTransactionTitle($xaction);
 }
 public function shouldHideInApplicationTransactions(PhabricatorApplicationTransaction $xaction)
 {
     return $xaction->getOldValue() === null;
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorOwnersPackageTransaction::TYPE_NAME:
         case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY:
         case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION:
         case PhabricatorOwnersPackageTransaction::TYPE_AUDITING:
             return;
         case PhabricatorOwnersPackageTransaction::TYPE_OWNERS:
             $old = $xaction->getOldValue();
             $new = $xaction->getNewValue();
             // TODO: needOwners this
             $owners = $object->loadOwners();
             $owners = mpull($owners, null, 'getUserPHID');
             $rem = array_diff($old, $new);
             foreach ($rem as $phid) {
                 if (isset($owners[$phid])) {
                     $owners[$phid]->delete();
                     unset($owners[$phid]);
                 }
             }
             $add = array_diff($new, $old);
             foreach ($add as $phid) {
                 $owners[$phid] = id(new PhabricatorOwnersOwner())->setPackageID($object->getID())->setUserPHID($phid)->save();
             }
             // TODO: Attach owners here
             return;
         case PhabricatorOwnersPackageTransaction::TYPE_PATHS:
             $old = $xaction->getOldValue();
             $new = $xaction->getNewValue();
             // TODO: needPaths this
             $paths = $object->loadPaths();
             $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new);
             list($rem, $add) = $diffs;
             $set = PhabricatorOwnersPath::getSetFromTransactionValue($rem);
             foreach ($paths as $path) {
                 $ref = $path->getRef();
                 if (PhabricatorOwnersPath::isRefInSet($ref, $set)) {
                     $path->delete();
                 }
             }
             foreach ($add as $ref) {
                 $path = PhabricatorOwnersPath::newFromRef($ref)->setPackageID($object->getID())->save();
             }
             return;
     }
     return parent::applyCustomExternalTransaction($object, $xaction);
 }
 protected function transactionHasEffect(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     $old = $xaction->getOldValue();
     $new = $xaction->getNewValue();
     switch ($xaction->getTransactionType()) {
         case PhabricatorTransactions::TYPE_COLUMNS:
             return (bool) $new;
     }
     return parent::transactionHasEffect($object, $xaction);
 }
 protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction)
 {
     switch ($xaction->getTransactionType()) {
         case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
             // Adjust the object <-> credential edge for this repository.
             $old_phid = $xaction->getOldValue();
             $new_phid = $xaction->getNewValue();
             $editor = new PhabricatorEdgeEditor();
             $edge_type = PhabricatorObjectUsesCredentialsEdgeType::EDGECONST;
             $src_phid = $object->getPHID();
             if ($old_phid) {
                 $editor->removeEdge($src_phid, $edge_type, $old_phid);
             }
             if ($new_phid) {
                 $editor->addEdge($src_phid, $edge_type, $new_phid);
             }
             $editor->save();
             break;
         case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
             DrydockAuthorization::applyAuthorizationChanges($this->getActor(), $object->getPHID(), $xaction->getOldValue(), $xaction->getNewValue());
             break;
     }
 }