public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $e_title = null;
     $priority_map = ManiphestTaskPriority::getTaskPriorityMap();
     $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($id))->needSubscriberPHIDs(true)->executeOne();
     if (!$task) {
         return new Aphront404Response();
     }
     $workflow = $request->getStr('workflow');
     $parent_task = null;
     if ($workflow && is_numeric($workflow)) {
         $parent_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($workflow))->executeOne();
     }
     $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW);
     $field_list->setViewer($viewer)->readFieldsFromStorage($task);
     $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST;
     $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
     $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
     $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
     $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST;
     $phid = $task->getPHID();
     $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock));
     $edges = idx($query->execute(), $phid);
     $phids = array_fill_keys($query->getDestinationPHIDs(), true);
     if ($task->getOwnerPHID()) {
         $phids[$task->getOwnerPHID()] = true;
     }
     $phids[$task->getAuthorPHID()] = true;
     $attached = $task->getAttached();
     foreach ($attached as $type => $list) {
         foreach ($list as $phid => $info) {
             $phids[$phid] = true;
         }
     }
     if ($parent_task) {
         $phids[$parent_task->getPHID()] = true;
     }
     $phids = array_keys($phids);
     $handles = $viewer->loadHandles($phids);
     $info_view = null;
     if ($parent_task) {
         $info_view = new PHUIInfoView();
         $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask')));
         $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID())));
     } else {
         if ($workflow == 'create') {
             $info_view = new PHUIInfoView();
             $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
             $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task')));
             $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task')));
             $info_view->appendChild(pht('New task created. Create another?'));
         }
     }
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($viewer);
     $engine->setContextObject($task);
     $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION);
     $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine);
     $actions = $this->buildActionView($task);
     $monogram = $task->getMonogram();
     $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($monogram, '/' . $monogram);
     $header = $this->buildHeaderView($task);
     $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles);
     $description = $this->buildDescriptionView($task, $engine);
     $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties);
     if ($description) {
         $object_box->addPropertyList($description);
     }
     $title = pht('%s %s', $monogram, $task->getTitle());
     $comment_view = id(new ManiphestEditEngine())->setViewer($viewer)->buildEditEngineCommentView($task);
     $timeline->setQuoteRef($monogram);
     $comment_view->setTransactionTimeline($timeline);
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setPageObjectPHIDs(array($task->getPHID()))->appendChild(array($info_view, $object_box, $timeline, $comment_view));
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $comments = $request->getStr('comments');
     $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($id))->executeOne();
     if (!$task) {
         return new Aphront404Response();
     }
     id(new PhabricatorDraft())->setAuthorPHID($viewer->getPHID())->setDraftKey($task->getPHID())->setDraft($comments)->replaceOrDelete();
     $action = $request->getStr('action');
     $transaction = new ManiphestTransaction();
     $transaction->setAuthorPHID($viewer->getPHID());
     $transaction->setTransactionType($action);
     // This should really be split into a separate transaction, but it should
     // all come out in the wash once we fully move to modern stuff.
     $transaction->attachComment(id(new ManiphestTransactionComment())->setContent($comments));
     $value = $request->getStr('value');
     // grab phids for handles and set transaction values based on action and
     // value (empty or control-specific format) coming in from the wire
     switch ($action) {
         case ManiphestTransaction::TYPE_PRIORITY:
             $transaction->setOldValue($task->getPriority());
             $transaction->setNewValue($value);
             break;
         case ManiphestTransaction::TYPE_OWNER:
             if ($value) {
                 $value = current(json_decode($value));
                 $phids = array($value);
             } else {
                 $phids = array();
             }
             $transaction->setNewValue($value);
             break;
         case PhabricatorTransactions::TYPE_SUBSCRIBERS:
             if ($value) {
                 $value = json_decode($value);
             }
             if (!$value) {
                 $value = array();
             }
             $phids = array();
             foreach ($value as $cc_phid) {
                 $phids[] = $cc_phid;
             }
             $transaction->setOldValue(array());
             $transaction->setNewValue($phids);
             break;
         case PhabricatorTransactions::TYPE_EDGE:
             if ($value) {
                 $value = phutil_json_decode($value);
             }
             if (!$value) {
                 $value = array();
             }
             $phids = array();
             $value = array_fuse($value);
             foreach ($value as $project_phid) {
                 $phids[] = $project_phid;
                 $value[$project_phid] = array('dst' => $project_phid);
             }
             $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
             $transaction->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setOldValue(array())->setNewValue($value);
             break;
         case ManiphestTransaction::TYPE_STATUS:
             $phids = array();
             $transaction->setOldValue($task->getStatus());
             $transaction->setNewValue($value);
             break;
         default:
             $phids = array();
             $transaction->setNewValue($value);
             break;
     }
     $phids[] = $viewer->getPHID();
     $handles = $this->loadViewerHandles($phids);
     $transactions = array();
     $transactions[] = $transaction;
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($viewer);
     $engine->setContextObject($task);
     if ($transaction->hasComment()) {
         $engine->addObject($transaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
     }
     $engine->process();
     $transaction->setHandles($handles);
     $view = id(new PhabricatorApplicationTransactionView())->setUser($viewer)->setTransactions($transactions)->setIsPreview(true);
     return id(new AphrontAjaxResponse())->setContent((string) phutil_implode_html('', $view->buildEvents()));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $e_title = null;
     $priority_map = ManiphestTaskPriority::getTaskPriorityMap();
     $task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($this->id))->needSubscriberPHIDs(true)->executeOne();
     if (!$task) {
         return new Aphront404Response();
     }
     $workflow = $request->getStr('workflow');
     $parent_task = null;
     if ($workflow && is_numeric($workflow)) {
         $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($workflow))->executeOne();
     }
     $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW);
     $field_list->setViewer($user)->readFieldsFromStorage($task);
     $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST;
     $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
     $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
     $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST;
     $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST;
     $phid = $task->getPHID();
     $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock));
     $edges = idx($query->execute(), $phid);
     $phids = array_fill_keys($query->getDestinationPHIDs(), true);
     if ($task->getOwnerPHID()) {
         $phids[$task->getOwnerPHID()] = true;
     }
     $phids[$task->getAuthorPHID()] = true;
     $attached = $task->getAttached();
     foreach ($attached as $type => $list) {
         foreach ($list as $phid => $info) {
             $phids[$phid] = true;
         }
     }
     if ($parent_task) {
         $phids[$parent_task->getPHID()] = true;
     }
     $phids = array_keys($phids);
     $handles = $user->loadHandles($phids);
     $info_view = null;
     if ($parent_task) {
         $info_view = new PHUIInfoView();
         $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
         $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask')));
         $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID())));
     } else {
         if ($workflow == 'create') {
             $info_view = new PHUIInfoView();
             $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
             $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task')));
             $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task')));
             $info_view->appendChild(pht('New task created. Create another?'));
         }
     }
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($user);
     $engine->setContextObject($task);
     $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION);
     $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine);
     $resolution_types = ManiphestTaskStatus::getTaskStatusMap();
     $transaction_types = array(PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), PhabricatorTransactions::TYPE_SUBSCRIBERS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), PhabricatorTransactions::TYPE_EDGE => pht('Associate Projects'));
     // Remove actions the user doesn't have permission to take.
     $requires = array(ManiphestTransaction::TYPE_OWNER => ManiphestEditAssignCapability::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestEditPriorityCapability::CAPABILITY, PhabricatorTransactions::TYPE_EDGE => ManiphestEditProjectsCapability::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestEditStatusCapability::CAPABILITY);
     foreach ($transaction_types as $type => $name) {
         if (isset($requires[$type])) {
             if (!$this->hasApplicationCapability($requires[$type])) {
                 unset($transaction_types[$type]);
             }
         }
     }
     // Don't show an option to change to the current status, or to change to
     // the duplicate status explicitly.
     unset($resolution_types[$task->getStatus()]);
     unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]);
     // Don't show owner/priority changes for closed tasks, as they don't make
     // much sense.
     if ($task->isClosed()) {
         unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]);
         unset($transaction_types[ManiphestTransaction::TYPE_OWNER]);
     }
     $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')');
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID());
     if ($draft) {
         $draft_text = $draft->getDraft();
     } else {
         $draft_text = null;
     }
     $projects_source = new PhabricatorProjectDatasource();
     $users_source = new PhabricatorPeopleDatasource();
     $mailable_source = new PhabricatorMetaMTAMailableDatasource();
     $comment_form = new AphrontFormView();
     $comment_form->setUser($user)->setWorkflow(true)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Assign To'))->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true)->setDatasource($users_source))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('CCs'))->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true)->setDatasource($mailable_source))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true)->setDatasource($projects_source))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('File'))->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setUser($user)->setLabel(pht('Comments'))->setName('comments')->setValue($draft_text)->setID('transaction-comments')->setUser($user))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit')));
     $control_map = array(ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', PhabricatorTransactions::TYPE_SUBSCRIBERS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', PhabricatorTransactions::TYPE_EDGE => 'projects');
     $tokenizer_map = array(PhabricatorTransactions::TYPE_EDGE => array('id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), ManiphestTransaction::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText()), PhabricatorTransactions::TYPE_SUBSCRIBERS => array('id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText()));
     // TODO: Initializing these behaviors for logged out users fatals things.
     if ($user->isLoggedIn()) {
         Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map));
         Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map));
     }
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In');
     $preview_panel = phutil_tag_div('aphront-panel-preview', phutil_tag('div', array('id' => 'transaction-preview'), phutil_tag_div('aphront-panel-preview-loading-text', pht('Loading preview...'))));
     $object_name = 'T' . $task->getID();
     $actions = $this->buildActionView($task);
     $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($object_name, '/' . $object_name);
     $header = $this->buildHeaderView($task);
     $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles);
     $description = $this->buildDescriptionView($task, $engine);
     if (!$user->isLoggedIn()) {
         // TODO: Eventually, everything should run through this. For now, we're
         // only using it to get a consistent "Login to Comment" button.
         $comment_box = id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI());
         $preview_panel = null;
     } else {
         $comment_box = id(new PHUIObjectBoxView())->setFlush(true)->setHeaderText($comment_header)->appendChild($comment_form);
         $timeline->setQuoteTargetID('transaction-comments');
         $timeline->setQuoteRef($object_name);
     }
     $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties);
     if ($info_view) {
         $object_box->setInfoView($info_view);
     }
     if ($description) {
         $object_box->addPropertyList($description);
     }
     return $this->buildApplicationPage(array($crumbs, $object_box, $timeline, $comment_box, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID())));
 }