public static function purgeDrafts($object_phid, $viewer_phid, $version)
 {
     $draft = new PhabricatorVersionedDraft();
     $conn_w = $draft->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE objectPHID = %s AND authorPHID = %s
     AND version <= %d', $draft->getTableName(), $object_phid, $viewer_phid, $version);
 }
 private function buildCommentResponse($object)
 {
     $viewer = $this->getViewer();
     if ($this->getIsCreate()) {
         return new Aphront404Response();
     }
     $controller = $this->getController();
     $request = $controller->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $config = $this->loadDefaultEditConfiguration();
     if (!$config) {
         return new Aphront404Response();
     }
     $fields = $this->buildEditFields($object);
     $is_preview = $request->isPreviewRequest();
     $view_uri = $this->getObjectViewURI($object);
     $template = $object->getApplicationTransactionTemplate();
     $comment_template = $template->getApplicationTransactionCommentObject();
     $comment_text = $request->getStr('comment');
     $actions = $request->getStr('editengine.actions');
     if ($actions) {
         $actions = phutil_json_decode($actions);
     }
     if ($is_preview) {
         $version_key = PhabricatorVersionedDraft::KEY_VERSION;
         $request_version = $request->getInt($version_key);
         $current_version = $this->loadDraftVersion($object);
         if ($request_version >= $current_version) {
             $draft = PhabricatorVersionedDraft::loadOrCreateDraft($object->getPHID(), $viewer->getPHID(), $current_version);
             $draft->setProperty('comment', $comment_text)->setProperty('actions', $actions)->save();
         }
     }
     $xactions = array();
     if ($actions) {
         $action_map = array();
         foreach ($actions as $action) {
             $type = idx($action, 'type');
             if (!$type) {
                 continue;
             }
             if (empty($fields[$type])) {
                 continue;
             }
             $action_map[$type] = $action;
         }
         foreach ($action_map as $type => $action) {
             $field = $fields[$type];
             if (!$field->shouldGenerateTransactionsFromComment()) {
                 continue;
             }
             if (array_key_exists('initialValue', $action)) {
                 $field->setInitialValue($action['initialValue']);
             }
             $field->readValueFromComment(idx($action, 'value'));
             $type_xactions = $field->generateTransactions(clone $template, array('value' => $field->getValueForTransaction()));
             foreach ($type_xactions as $type_xaction) {
                 $xactions[] = $type_xaction;
             }
         }
     }
     if (strlen($comment_text) || !$xactions) {
         $xactions[] = id(clone $template)->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(clone $comment_template)->setContent($comment_text));
     }
     $editor = $object->getApplicationTransactionEditor()->setActor($viewer)->setContinueOnNoEffect($request->isContinueRequest())->setContinueOnMissingFields(true)->setContentSourceFromRequest($request)->setIsPreview($is_preview);
     try {
         $xactions = $editor->applyTransactions($object, $xactions);
     } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
         return id(new PhabricatorApplicationTransactionNoEffectResponse())->setCancelURI($view_uri)->setException($ex);
     }
     if (!$is_preview) {
         PhabricatorVersionedDraft::purgeDrafts($object->getPHID(), $viewer->getPHID(), $this->loadDraftVersion($object));
     }
     if ($request->isAjax() && $is_preview) {
         return id(new PhabricatorApplicationTransactionResponse())->setViewer($viewer)->setTransactions($xactions)->setIsPreview($is_preview);
     } else {
         return id(new AphrontRedirectResponse())->setURI($view_uri);
     }
 }
 private function buildCommentResponse($object)
 {
     $viewer = $this->getViewer();
     if ($this->getIsCreate()) {
         return new Aphront404Response();
     }
     $controller = $this->getController();
     $request = $controller->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $config = $this->loadEditEngineConfiguration(null);
     $fields = $this->buildEditFields($object);
     $is_preview = $request->isPreviewRequest();
     $view_uri = $this->getObjectViewURI($object);
     $template = $object->getApplicationTransactionTemplate();
     $comment_template = $template->getApplicationTransactionCommentObject();
     $comment_text = $request->getStr('comment');
     if ($is_preview) {
         $version_key = PhabricatorVersionedDraft::KEY_VERSION;
         $request_version = $request->getInt($version_key);
         $current_version = $this->loadDraftVersion($object);
         if ($request_version >= $current_version) {
             $draft = PhabricatorVersionedDraft::loadOrCreateDraft($object->getPHID(), $viewer->getPHID(), $current_version);
             // TODO: This is just a proof of concept.
             $draft->setProperty('temporary.comment', $comment_text);
             $draft->save();
         }
     }
     $xactions = array();
     $actions = $request->getStr('editengine.actions');
     if ($actions) {
         $type_map = array();
         foreach ($fields as $field) {
             $types = $field->getCommentEditTypes();
             foreach ($types as $type) {
                 $type_map[$type->getEditType()] = $type;
             }
         }
         $actions = phutil_json_decode($actions);
         foreach ($actions as $action) {
             $type = idx($action, 'type');
             if (!$type) {
                 continue;
             }
             $edit_type = idx($type_map, $type);
             if (!$edit_type) {
                 continue;
             }
             $type_xactions = $edit_type->generateTransactions($template, array('value' => idx($action, 'value')));
             foreach ($type_xactions as $type_xaction) {
                 $xactions[] = $type_xaction;
             }
         }
     }
     if (strlen($comment_text) || !$xactions) {
         $xactions[] = id(clone $template)->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(clone $comment_template)->setContent($comment_text));
     }
     $editor = $object->getApplicationTransactionEditor()->setActor($viewer)->setContinueOnNoEffect($request->isContinueRequest())->setContentSourceFromRequest($request)->setIsPreview($is_preview);
     try {
         $xactions = $editor->applyTransactions($object, $xactions);
     } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
         return id(new PhabricatorApplicationTransactionNoEffectResponse())->setCancelURI($view_uri)->setException($ex);
     }
     if (!$is_preview) {
         PhabricatorVersionedDraft::purgeDrafts($object->getPHID(), $viewer->getPHID(), $this->loadDraftVersion($object));
     }
     if ($request->isAjax() && $is_preview) {
         return id(new PhabricatorApplicationTransactionResponse())->setViewer($viewer)->setTransactions($xactions)->setIsPreview($is_preview);
     } else {
         return id(new AphrontRedirectResponse())->setURI($view_uri);
     }
 }