protected function applyRequest(ManiphestTask $task, ConduitAPIRequest $request, $is_new)
 {
     $changes = array();
     if ($is_new) {
         $task->setTitle((string) $request->getValue('title'));
         $task->setDescription((string) $request->getValue('description'));
         $changes[ManiphestTransactionType::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN;
     } else {
         $comments = $request->getValue('comments');
         if (!$is_new && $comments !== null) {
             $changes[ManiphestTransactionType::TYPE_NONE] = null;
         }
         $title = $request->getValue('title');
         if ($title !== null) {
             $changes[ManiphestTransactionType::TYPE_TITLE] = $title;
         }
         $desc = $request->getValue('description');
         if ($desc !== null) {
             $changes[ManiphestTransactionType::TYPE_DESCRIPTION] = $desc;
         }
         $status = $request->getValue('status');
         if ($status !== null) {
             $valid_statuses = ManiphestTaskStatus::getTaskStatusMap();
             if (!isset($valid_statuses[$status])) {
                 throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription('Status set to invalid value.');
             }
             $changes[ManiphestTransactionType::TYPE_STATUS] = $status;
         }
     }
     $priority = $request->getValue('priority');
     if ($priority !== null) {
         $valid_priorities = ManiphestTaskPriority::getTaskPriorityMap();
         if (!isset($valid_priorities[$priority])) {
             throw id(new ConduitException('ERR-INVALID-PARAMETER'))->setErrorDescription('Priority set to invalid value.');
         }
         $changes[ManiphestTransactionType::TYPE_PRIORITY] = $priority;
     }
     $owner_phid = $request->getValue('ownerPHID');
     if ($owner_phid !== null) {
         $this->validatePHIDList(array($owner_phid), PhabricatorPHIDConstants::PHID_TYPE_USER, 'ownerPHID');
         $changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid;
     }
     $ccs = $request->getValue('ccPHIDs');
     if ($ccs !== null) {
         $this->validatePHIDList($ccs, PhabricatorPHIDConstants::PHID_TYPE_USER, 'ccPHIDS');
         $changes[ManiphestTransactionType::TYPE_CCS] = $ccs;
     }
     $project_phids = $request->getValue('projectPHIDs');
     if ($project_phids !== null) {
         $this->validatePHIDList($project_phids, PhabricatorPHIDConstants::PHID_TYPE_PROJ, 'projectPHIDS');
         $changes[ManiphestTransactionType::TYPE_PROJECTS] = $project_phids;
     }
     $file_phids = $request->getValue('filePHIDs');
     if ($file_phids !== null) {
         $this->validatePHIDList($file_phids, PhabricatorPHIDConstants::PHID_TYPE_FILE, 'filePHIDS');
         $file_map = array_fill_keys($file_phids, true);
         $attached = $task->getAttached();
         $attached[PhabricatorPHIDConstants::PHID_TYPE_FILE] = $file_map;
         $changes[ManiphestTransactionType::TYPE_ATTACH] = $attached;
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array());
     $template = new ManiphestTransaction();
     $template->setContentSource($content_source);
     $template->setAuthorPHID($request->getUser()->getPHID());
     $transactions = array();
     foreach ($changes as $type => $value) {
         $transaction = clone $template;
         $transaction->setTransactionType($type);
         $transaction->setNewValue($value);
         if ($type == ManiphestTransactionType::TYPE_NONE) {
             $transaction->setComments($comments);
         }
         $transactions[] = $transaction;
     }
     $auxiliary = $request->getValue('auxiliary');
     if ($auxiliary) {
         $task->loadAndAttachAuxiliaryAttributes();
         foreach ($auxiliary as $aux_key => $aux_value) {
             $transaction = clone $template;
             $transaction->setTransactionType(ManiphestTransactionType::TYPE_AUXILIARY);
             $transaction->setMetadataValue('aux:key', $aux_key);
             $transaction->setNewValue($aux_value);
             $transactions[] = $transaction;
         }
     }
     $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions));
     $event->setUser($request->getUser());
     $event->setConduitRequest($request);
     PhutilEventEngine::dispatchEvent($event);
     $task = $event->getValue('task');
     $transactions = $event->getValue('transactions');
     $editor = new ManiphestTransactionEditor();
     $editor->applyTransactions($task, $transactions);
     $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions));
     $event->setUser($request->getUser());
     $event->setConduitRequest($request);
     PhutilEventEngine::dispatchEvent($event);
 }
 public function applyTransactions(ManiphestTask $task, array $transactions)
 {
     assert_instances_of($transactions, 'ManiphestTransaction');
     $email_cc = $task->getCCPHIDs();
     $email_to = array();
     $email_to[] = $task->getOwnerPHID();
     $pri_changed = $this->isCreate($transactions);
     foreach ($transactions as $key => $transaction) {
         $type = $transaction->getTransactionType();
         $new = $transaction->getNewValue();
         $email_to[] = $transaction->getAuthorPHID();
         $value_is_phid_set = false;
         switch ($type) {
             case ManiphestTransactionType::TYPE_NONE:
                 $old = null;
                 break;
             case ManiphestTransactionType::TYPE_STATUS:
                 $old = $task->getStatus();
                 break;
             case ManiphestTransactionType::TYPE_OWNER:
                 $old = $task->getOwnerPHID();
                 break;
             case ManiphestTransactionType::TYPE_CCS:
                 $old = $task->getCCPHIDs();
                 $value_is_phid_set = true;
                 break;
             case ManiphestTransactionType::TYPE_PRIORITY:
                 $old = $task->getPriority();
                 break;
             case ManiphestTransactionType::TYPE_ATTACH:
                 $old = $task->getAttached();
                 break;
             case ManiphestTransactionType::TYPE_TITLE:
                 $old = $task->getTitle();
                 break;
             case ManiphestTransactionType::TYPE_DESCRIPTION:
                 $old = $task->getDescription();
                 break;
             case ManiphestTransactionType::TYPE_PROJECTS:
                 $old = $task->getProjectPHIDs();
                 $value_is_phid_set = true;
                 break;
             case ManiphestTransactionType::TYPE_AUXILIARY:
                 $aux_key = $transaction->getMetadataValue('aux:key');
                 if (!$aux_key) {
                     throw new Exception("Expected 'aux:key' metadata on TYPE_AUXILIARY transaction.");
                 }
                 $old = $task->getAuxiliaryAttribute($aux_key);
                 break;
             default:
                 throw new Exception('Unknown action type.');
         }
         $old_cmp = $old;
         $new_cmp = $new;
         if ($value_is_phid_set) {
             // Normalize the old and new values if they are PHID sets so we don't
             // get any no-op transactions where the values differ only by keys,
             // order, duplicates, etc.
             if (is_array($old)) {
                 $old = array_filter($old);
                 $old = array_unique($old);
                 sort($old);
                 $old = array_values($old);
                 $old_cmp = $old;
             }
             if (is_array($new)) {
                 $new = array_filter($new);
                 $new = array_unique($new);
                 $transaction->setNewValue($new);
                 $new_cmp = $new;
                 sort($new_cmp);
                 $new_cmp = array_values($new_cmp);
             }
         }
         if ($old !== null && $old_cmp == $new_cmp) {
             if (count($transactions) > 1 && !$transaction->hasComments()) {
                 // If we have at least one other transaction and this one isn't
                 // doing anything and doesn't have any comments, just throw it
                 // away.
                 unset($transactions[$key]);
                 continue;
             } else {
                 $transaction->setOldValue(null);
                 $transaction->setNewValue(null);
                 $transaction->setTransactionType(ManiphestTransactionType::TYPE_NONE);
             }
         } else {
             switch ($type) {
                 case ManiphestTransactionType::TYPE_NONE:
                     break;
                 case ManiphestTransactionType::TYPE_STATUS:
                     $task->setStatus($new);
                     break;
                 case ManiphestTransactionType::TYPE_OWNER:
                     if ($new) {
                         $handles = id(new PhabricatorObjectHandleData(array($new)))->loadHandles();
                         $task->setOwnerOrdering($handles[$new]->getName());
                     } else {
                         $task->setOwnerOrdering(null);
                     }
                     $task->setOwnerPHID($new);
                     break;
                 case ManiphestTransactionType::TYPE_CCS:
                     $task->setCCPHIDs($new);
                     break;
                 case ManiphestTransactionType::TYPE_PRIORITY:
                     $task->setPriority($new);
                     $pri_changed = true;
                     break;
                 case ManiphestTransactionType::TYPE_ATTACH:
                     $task->setAttached($new);
                     break;
                 case ManiphestTransactionType::TYPE_TITLE:
                     $task->setTitle($new);
                     break;
                 case ManiphestTransactionType::TYPE_DESCRIPTION:
                     $task->setDescription($new);
                     break;
                 case ManiphestTransactionType::TYPE_PROJECTS:
                     $task->setProjectPHIDs($new);
                     break;
                 case ManiphestTransactionType::TYPE_AUXILIARY:
                     $aux_key = $transaction->getMetadataValue('aux:key');
                     $task->setAuxiliaryAttribute($aux_key, $new);
                     break;
                 default:
                     throw new Exception('Unknown action type.');
             }
             $transaction->setOldValue($old);
             $transaction->setNewValue($new);
         }
     }
     if ($pri_changed) {
         $subpriority = ManiphestTransactionEditor::getNextSubpriority($task->getPriority(), null);
         $task->setSubpriority($subpriority);
     }
     $task->save();
     foreach ($transactions as $transaction) {
         $transaction->setTaskID($task->getID());
         $transaction->save();
     }
     $email_to[] = $task->getOwnerPHID();
     $email_cc = array_merge($email_cc, $task->getCCPHIDs());
     $this->publishFeedStory($task, $transactions);
     // TODO: Do this offline via timeline
     PhabricatorSearchManiphestIndexer::indexTask($task);
     $this->sendEmail($task, $transactions, $email_to, $email_cc);
 }
 private function applyTaskTransaction(ManiphestTask $task, $attach_type, array $new_phids)
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before editing attachments!");
     }
     $user = $this->user;
     $editor = new ManiphestTransactionEditor();
     $type = ManiphestTransactionType::TYPE_ATTACH;
     $transaction = new ManiphestTransaction();
     $transaction->setAuthorPHID($user->getPHID());
     $transaction->setTransactionType($type);
     $new = $task->getAttached();
     $new[$attach_type] = array_fill_keys($new_phids, array());
     $transaction->setNewValue($new);
     $editor->applyTransactions($task, array($transaction));
 }
 private function applyTaskTransaction(ManiphestTask $task, $attach_type, array $new_phids)
 {
     $user = $this->getRequest()->getUser();
     $editor = new ManiphestTransactionEditor();
     $type = ManiphestTransactionType::TYPE_ATTACH;
     $transaction = new ManiphestTransaction();
     $transaction->setAuthorPHID($user->getPHID());
     $transaction->setTransactionType($type);
     $new = $task->getAttached();
     $new[$attach_type] = array_fill_keys($new_phids, array());
     $transaction->setNewValue($new);
     $editor->applyTransactions($task, array($transaction));
 }