public function execute(PhutilArgumentParser $args)
 {
     $viewer = $this->getViewer();
     $argv = $args->getArg('argv');
     if (count($argv) !== 2) {
         throw new PhutilArgumentUsageException(pht('Specify a commit and a revision to attach it to.'));
     }
     $commit_name = head($argv);
     $revision_name = last($argv);
     $commit = id(new DiffusionCommitQuery())->setViewer($viewer)->withIdentifiers(array($commit_name))->executeOne();
     if (!$commit) {
         throw new PhutilArgumentUsageException(pht('Commit "%s" does not exist.', $commit_name));
     }
     $revision = id(new PhabricatorObjectQuery())->setViewer($viewer)->withNames(array($revision_name))->executeOne();
     if (!$revision) {
         throw new PhutilArgumentUsageException(pht('Revision "%s" does not exist.', $revision_name));
     }
     if (!$revision instanceof DifferentialRevision) {
         throw new PhutilArgumentUsageException(pht('Object "%s" must be a Differential revision.', $revision_name));
     }
     // Reload the revision to get the active diff.
     $revision = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($revision->getID()))->needActiveDiffs(true)->executeOne();
     $differential_phid = id(new PhabricatorDifferentialApplication())->getPHID();
     $extraction_engine = id(new DifferentialDiffExtractionEngine())->setViewer($viewer)->setAuthorPHID($differential_phid);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONSOLE, array());
     $extraction_engine->updateRevisionWithCommit($revision, $commit, array(), $content_source);
     echo tsprintf("%s\n", pht('Attached "%s" to "%s".', $commit->getMonogram(), $revision->getMonogram()));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $revision_id = $request->getInt('revision_id');
     $revision = id(new DifferentialRevision())->load($revision_id);
     if (!$revision) {
         return new Aphront400Response();
     }
     $comment = $request->getStr('comment');
     $action = $request->getStr('action');
     $reviewers = $request->getArr('reviewers');
     $ccs = $request->getArr('ccs');
     $editor = new DifferentialCommentEditor($revision, $request->getUser()->getPHID(), $action);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     $editor->setMessage($comment)->setContentSource($content_source)->setAttachInlineComments(true)->setAddCC($action != DifferentialAction::ACTION_RESIGN)->setAddedReviewers($reviewers)->setAddedCCs($ccs)->save();
     // TODO: Diff change detection?
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $request->getUser()->getPHID(), 'differential-comment-' . $revision->getID());
     if ($draft) {
         $draft->delete();
     }
     return id(new AphrontRedirectResponse())->setURI('/D' . $revision->getID());
 }
 public function generateObject()
 {
     $author_phid = $this->loadPhabrictorUserPHID();
     $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $author_phid);
     $task = ManiphestTask::initializeNewTask($author)->setSubPriority($this->generateTaskSubPriority())->setTitle($this->generateTitle());
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_UNKNOWN, array());
     $template = new ManiphestTransaction();
     // Accumulate Transactions
     $changes = array();
     $changes[ManiphestTransaction::TYPE_TITLE] = $this->generateTitle();
     $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $this->generateDescription();
     $changes[ManiphestTransaction::TYPE_OWNER] = $this->loadOwnerPHID();
     $changes[ManiphestTransaction::TYPE_STATUS] = $this->generateTaskStatus();
     $changes[ManiphestTransaction::TYPE_PRIORITY] = $this->generateTaskPriority();
     $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('=' => $this->getCCPHIDs());
     $transactions = array();
     foreach ($changes as $type => $value) {
         $transaction = clone $template;
         $transaction->setTransactionType($type);
         $transaction->setNewValue($value);
         $transactions[] = $transaction;
     }
     $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)->setNewValue(array('=' => array_fuse($this->getProjectPHIDs())));
     // Apply Transactions
     $editor = id(new ManiphestTransactionEditor())->setActor($author)->setContentSource($content_source)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($task, $transactions);
     return $task;
 }
 protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender)
 {
     $title = $mail->getSubject();
     if (!$title) {
         $title = pht('Email Paste');
     }
     $file = PhabricatorPasteEditor::initializeFileForPaste($sender, $title, $mail->getCleanTextBody());
     $xactions = array();
     $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)->setNewValue($file->getPHID());
     $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)->setNewValue($title);
     $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)->setNewValue('');
     // auto-detect
     $paste = PhabricatorPaste::initializeNewPaste($sender);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     $editor = id(new PhabricatorPasteEditor())->setActor($sender)->setContentSource($content_source)->setContinueOnNoEffect(true);
     $xactions = $editor->applyTransactions($paste, $xactions);
     $mail->setRelatedPHID($paste->getPHID());
     $subject_prefix = PhabricatorEnv::getEnvConfig('metamta.paste.subject-prefix');
     $subject = pht('You successfully created a paste.');
     $paste_uri = PhabricatorEnv::getProductionURI($paste->getURI());
     $body = new PhabricatorMetaMTAMailBody();
     $body->addRawSection($subject);
     $body->addTextSection(pht('PASTE LINK'), $paste_uri);
     id(new PhabricatorMetaMTAMail())->addTos(array($sender->getPHID()))->setSubject($subject)->setSubjectPrefix($subject_prefix)->setFrom($sender->getPHID())->setRelatedPHID($paste->getPHID())->setBody($body->render())->saveAndSend();
 }
 protected function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     // Reload the commit to pull commit data and audit requests.
     $commit = id(new DiffusionCommitQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($commit->getID()))->needCommitData(true)->needAuditRequests(true)->executeOne();
     $data = $commit->getCommitData();
     if (!$data) {
         throw new PhabricatorWorkerPermanentFailureException(pht('Unable to load commit data. The data for this task is invalid ' . 'or no longer exists.'));
     }
     $commit->attachRepository($repository);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_DAEMON, array());
     $committer_phid = $data->getCommitDetail('committerPHID');
     $author_phid = $data->getCommitDetail('authorPHID');
     $acting_as_phid = nonempty($committer_phid, $author_phid, id(new PhabricatorDiffusionApplication())->getPHID());
     $editor = id(new PhabricatorAuditEditor())->setActor(PhabricatorUser::getOmnipotentUser())->setActingAsPHID($acting_as_phid)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->setContentSource($content_source);
     $xactions = array();
     $xactions[] = id(new PhabricatorAuditTransaction())->setTransactionType(PhabricatorAuditTransaction::TYPE_COMMIT)->setDateCreated($commit->getEpoch())->setNewValue(array('description' => $data->getCommitMessage(), 'summary' => $data->getSummary(), 'authorName' => $data->getAuthorName(), 'authorPHID' => $commit->getAuthorPHID(), 'committerName' => $data->getCommitDetail('committer'), 'committerPHID' => $data->getCommitDetail('committerPHID')));
     $reverts_refs = id(new DifferentialCustomFieldRevertsParser())->parseCorpus($data->getCommitMessage());
     $reverts = array_mergev(ipull($reverts_refs, 'monograms'));
     if ($reverts) {
         $reverted_commits = id(new DiffusionCommitQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withRepository($repository)->withIdentifiers($reverts)->execute();
         $reverted_commit_phids = mpull($reverted_commits, 'getPHID', 'getPHID');
         // NOTE: Skip any write attempts if a user cleverly implies a commit
         // reverts itself.
         unset($reverted_commit_phids[$commit->getPHID()]);
         $reverts_edge = DiffusionCommitRevertsCommitEdgeType::EDGECONST;
         $xactions[] = id(new PhabricatorAuditTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $reverts_edge)->setNewValue(array('+' => array_fuse($reverted_commit_phids)));
     }
     try {
         $raw_patch = $this->loadRawPatchText($repository, $commit);
     } catch (Exception $ex) {
         $raw_patch = pht('Unable to generate patch: %s', $ex->getMessage());
     }
     $editor->setRawPatch($raw_patch);
     return $editor->applyTransactions($commit, $xactions);
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $diff = id(new DifferentialDiff())->load($request->getValue('diffid'));
     if (!$diff) {
         throw new ConduitException('ERR_BAD_DIFF');
     }
     $revision = id(new DifferentialRevision())->load($request->getValue('id'));
     if (!$revision) {
         throw new ConduitException('ERR_BAD_REVISION');
     }
     if ($request->getUser()->getPHID() !== $revision->getAuthorPHID()) {
         throw new ConduitException('ERR_WRONG_USER');
     }
     if ($revision->getStatus() == ArcanistDifferentialRevisionStatus::CLOSED) {
         throw new ConduitException('ERR_CLOSED');
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array());
     $editor = new DifferentialRevisionEditor($revision, $revision->getAuthorPHID());
     $editor->setContentSource($content_source);
     $fields = $request->getValue('fields');
     $editor->copyFieldsFromConduit($fields);
     $editor->addDiff($diff, $request->getValue('message'));
     $editor->save();
     return array('revisionid' => $revision->getID(), 'uri' => PhabricatorEnv::getURI('/D' . $revision->getID()));
 }
예제 #7
0
 protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail)
 {
     $actor = $this->getActor();
     $document = $this->getMailReceiver();
     $body_data = $mail->parseBody();
     $body = $body_data['body'];
     $body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     $xactions = array();
     $command = $body_data['command'];
     switch ($command) {
         case 'unsubscribe':
             $xaction = id(new LegalpadTransaction())->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)->setNewValue(array('-' => array($actor->getPHID())));
             $xactions[] = $xaction;
             break;
     }
     $xactions[] = id(new LegalpadTransaction())->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(new LegalpadTransactionComment())->setDocumentID($document->getID())->setLineNumber(0)->setLineLength(0)->setContent($body));
     $editor = id(new LegalpadDocumentEditor())->setActor($actor)->setContentSource($content_source)->setContinueOnNoEffect(true)->setIsPreview(false);
     try {
         $xactions = $editor->applyTransactions($document, $xactions);
     } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
         // just do nothing, though unclear why you're sending a blank email
         return true;
     }
     $head_xaction = head($xactions);
     return $head_xaction->getID();
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $question_id = $request->getInt('question_id');
     $question = id(new PonderQuestionQuery())->setViewer($viewer)->withIDs(array($question_id))->needAnswers(true)->executeOne();
     if (!$question) {
         return new Aphront404Response();
     }
     $answer = $request->getStr('answer');
     if (!strlen(trim($answer))) {
         $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Empty Answer'))->appendChild(phutil_tag('p', array(), pht('Your answer must not be empty.')))->addCancelButton('/Q' . $question_id);
         return id(new AphrontDialogResponse())->setDialog($dialog);
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     $res = id(new PonderAnswer())->setAuthorPHID($viewer->getPHID())->setQuestionID($question->getID())->setContent($answer)->setVoteCount(0)->setContentSource($content_source);
     $xactions = array();
     $xactions[] = id(new PonderQuestionTransaction())->setTransactionType(PonderQuestionTransaction::TYPE_ANSWERS)->setNewValue(array('+' => array(array('answer' => $res))));
     $editor = id(new PonderQuestionEditor())->setActor($viewer)->setContentSourceFromRequest($request);
     $editor->applyTransactions($question, $xactions);
     return id(new AphrontRedirectResponse())->setURI(id(new PhutilURI('/Q' . $question->getID())));
 }
 protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail)
 {
     $conpherence = $this->getMailReceiver();
     $user = $this->getActor();
     if (!$conpherence->getPHID()) {
         $conpherence->attachParticipants(array())->attachFilePHIDs(array());
     } else {
         $edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
         $file_phids = PhabricatorEdgeQuery::loadDestinationPHIDs($conpherence->getPHID(), $edge_type);
         $conpherence->attachFilePHIDs($file_phids);
         $participants = id(new ConpherenceParticipant())->loadAllWhere('conpherencePHID = %s', $conpherence->getPHID());
         $participants = mpull($participants, null, 'getParticipantPHID');
         $conpherence->attachParticipants($participants);
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     $editor = id(new ConpherenceEditor())->setActor($user)->setContentSource($content_source)->setParentMessageID($mail->getMessageID());
     $body = $mail->getCleanTextBody();
     $body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
     $xactions = array();
     if ($this->getMailAddedParticipantPHIDs()) {
         $xactions[] = id(new ConpherenceTransaction())->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)->setNewValue(array('+' => $this->getMailAddedParticipantPHIDs()));
     }
     $xactions = array_merge($xactions, $editor->generateTransactionsFromText($user, $conpherence, $body));
     $editor->applyTransactions($conpherence, $xactions);
     return $conpherence;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $user = $request->getUser();
     $question_id = $request->getInt('question_id');
     $question = PonderQuestionQuery::loadSingle($user, $question_id);
     if (!$question) {
         return new Aphront404Response();
     }
     $answer = $request->getStr('answer');
     // Only want answers with some non whitespace content
     if (!strlen(trim($answer))) {
         $dialog = new AphrontDialogView();
         $dialog->setUser($request->getUser());
         $dialog->setTitle('Empty answer');
         $dialog->appendChild('<p>Your answer must not be empty.</p>');
         $dialog->addCancelButton('/Q' . $question_id);
         return id(new AphrontDialogResponse())->setDialog($dialog);
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     $res = new PonderAnswer();
     $res->setContent($answer)->setAuthorPHID($user->getPHID())->setVoteCount(0)->setQuestionID($question_id)->setContentSource($content_source);
     id(new PonderAnswerEditor())->setUser($user)->setQuestion($question)->setAnswer($res)->saveAnswer();
     return id(new AphrontRedirectResponse())->setURI(id(new PhutilURI('/Q' . $question->getID())));
 }
 /**
  * Build and configure an Editor to publish these transactions.
  */
 private function buildEditor(PhabricatorApplicationTransactionInterface $object)
 {
     $data = $this->getTaskData();
     $daemon_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_DAEMON, array());
     $viewer = PhabricatorUser::getOmnipotentUser();
     $editor = $object->getApplicationTransactionEditor()->setActor($viewer)->setContentSource($daemon_source)->setActingAsPHID(idx($data, 'actorPHID'))->loadWorkerState(idx($data, 'state', array()));
     return $editor;
 }
 private function newEditor(PhabricatorMetaMTAReceivedMail $mail)
 {
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     $editor = $this->getMailReceiver()->getApplicationTransactionEditor()->setActor($this->getActor())->setContentSource($content_source)->setContinueOnMissingFields(true)->setParentMessageID($mail->getMessageID())->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs());
     if ($this->getApplicationEmail()) {
         $editor->setApplicationEmail($this->getApplicationEmail());
     }
     return $editor;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $action = $request->getValue('action');
     $new_commit_id = $request->getValue('commitIdentifier');
     $releeph_request = id(new ReleephRequest())->loadOneWhere('phid = %s', $request->getValue('requestPHID'));
     $xactions = array();
     $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_COMMIT)->setMetadataValue('action', $action)->setNewValue($new_commit_id);
     $editor = id(new ReleephRequestTransactionalEditor())->setActor($request->getUser())->setContinueOnNoEffect(true)->setContentSource(PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array()));
     $editor->applyTransactions($releeph_request, $xactions);
 }
 protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail)
 {
     $commit = $this->getMailReceiver();
     $actor = $this->getActor();
     $message = $mail->getCleanTextBody();
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     // TODO: Support !raise, !accept, etc.
     $xactions = array();
     $xactions[] = id(new PhabricatorAuditTransaction())->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(new PhabricatorAuditTransactionComment())->setCommitPHID($commit->getPHID())->setContent($message));
     $editor = id(new PhabricatorAuditEditor())->setActor($actor)->setContentSource($content_source)->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())->setContinueOnMissingFields(true)->applyTransactions($commit, $xactions);
 }
 protected function doWork()
 {
     $subscription = $this->loadSubscription();
     $range = $this->getBillingPeriodRange($subscription);
     list($last_epoch, $next_epoch) = $range;
     $should_invoice = $subscription->shouldInvoiceForBillingPeriod($last_epoch, $next_epoch);
     if (!$should_invoice) {
         return;
     }
     $currency = $subscription->getCostForBillingPeriodAsCurrency($last_epoch, $next_epoch);
     if (!$currency->isPositive()) {
         return;
     }
     $account = $subscription->getAccount();
     $merchant = $subscription->getMerchant();
     $viewer = PhabricatorUser::getOmnipotentUser();
     $product = id(new PhortuneProductQuery())->setViewer($viewer)->withClassAndRef('PhortuneSubscriptionProduct', $subscription->getPHID())->executeOne();
     $cart_implementation = id(new PhortuneSubscriptionCart())->setSubscription($subscription);
     // TODO: This isn't really ideal. It would be better to use an application
     // actor than the original author of the subscription. In particular, if
     // someone initiates a subscription, adds some other account managers, and
     // later leaves the company, they'll continue "acting" here indefinitely.
     // However, for now, some of the stuff later in the pipeline requires a
     // valid actor with a real PHID. The subscription should eventually be
     // able to create these invoices "as" the application it is acting on
     // behalf of.
     $actor = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withPHIDs(array($subscription->getAuthorPHID()))->executeOne();
     if (!$actor) {
         throw new Exception(pht('Failed to load actor to bill subscription!'));
     }
     $cart = $account->newCart($actor, $cart_implementation, $merchant);
     $purchase = $cart->newPurchase($actor, $product);
     $purchase->setBasePriceAsCurrency($currency)->setMetadataValue('subscriptionPHID', $subscription->getPHID())->setMetadataValue('epoch.start', $last_epoch)->setMetadataValue('epoch.end', $next_epoch)->save();
     $cart->setSubscriptionPHID($subscription->getPHID())->setIsInvoice(1)->save();
     $cart->activateCart();
     try {
         $issues = $this->chargeSubscription($actor, $subscription, $cart);
     } catch (Exception $ex) {
         $issues = array(pht('There was a technical error while trying to automatically bill ' . 'this subscription: %s', $ex));
     }
     if (!$issues) {
         // We're all done; charging the cart sends a billing email as a side
         // effect.
         return;
     }
     // We're shoving this through the CartEditor because it has all the logic
     // for sending mail about carts. This doesn't really affect the state of
     // the cart, but reduces the amount of code duplication.
     $xactions = array();
     $xactions[] = id(new PhortuneCartTransaction())->setTransactionType(PhortuneCartTransaction::TYPE_INVOICED)->setNewValue(true);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_PHORTUNE, array());
     $acting_phid = id(new PhabricatorPhortuneApplication())->getPHID();
     $editor = id(new PhortuneCartEditor())->setActor($viewer)->setActingAsPHID($acting_phid)->setContentSource($content_source)->setContinueOnMissingFields(true)->setInvoiceIssues($issues)->applyTransactions($cart, $xactions);
 }
 protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail)
 {
     $rq = $this->getMailReceiver();
     $user = $this->getActor();
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID()));
     $editor = id(new ReleephRequestTransactionalEditor())->setActor($user)->setContentSource($content_source)->setParentMessageID($mail->getMessageID());
     $body = $mail->getCleanTextBody();
     $xactions = array();
     $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment($body);
     $editor->applyTransactions($rq, $xactions);
     return $rq;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $revision = id(new DifferentialRevision())->load($request->getValue('revision_id'));
     if (!$revision) {
         throw new ConduitException('ERR_BAD_REVISION');
     }
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array());
     $editor = new DifferentialCommentEditor($revision, $request->getUser()->getPHID(), DifferentialAction::ACTION_COMMENT);
     $editor->setContentSource($content_source);
     $editor->setMessage($request->getValue('message'));
     $editor->save();
     return array('revisionid' => $revision->getID(), 'uri' => PhabricatorEnv::getURI('/D' . $revision->getID()));
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $viewer = $request->getUser();
     $id = $request->getValue('revisionID');
     $revision = id(new DifferentialRevisionQuery())->withIDs(array($id))->setViewer($viewer)->needReviewerStatus(true)->executeOne();
     if (!$revision) {
         throw new ConduitException('ERR_NOT_FOUND');
     }
     $xactions = array();
     $xactions[] = id(new DifferentialTransaction())->setTransactionType(DifferentialTransaction::TYPE_ACTION)->setNewValue(DifferentialAction::ACTION_CLOSE);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array());
     $editor = id(new DifferentialTransactionEditor())->setActor($viewer)->setContentSourceFromConduitRequest($request)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true);
     $editor->applyTransactions($revision, $xactions);
     return;
 }
 public function generate()
 {
     $author = $this->loadPhabrictorUser();
     $revision = DifferentialRevision::initializeNewRevision($author);
     $revision->attachReviewerStatus(array());
     $revision->attachActiveDiff(null);
     // This could be a bit richer and more formal than it is.
     $revision->setTitle($this->generateTitle());
     $revision->setSummary($this->generateDescription());
     $revision->setTestPlan($this->generateDescription());
     $diff = $this->generateDiff($author);
     $xactions = array();
     $xactions[] = id(new DifferentialTransaction())->setTransactionType(DifferentialTransaction::TYPE_UPDATE)->setNewValue($diff->getPHID());
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_LIPSUM, array());
     id(new DifferentialTransactionEditor())->setActor($author)->setContentSource($content_source)->applyTransactions($revision, $xactions);
     return $revision;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $task = new ManiphestTask();
     $task->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
     $task->setAuthorPHID($request->getUser()->getPHID());
     $task->setTitle((string) $request->getValue('title'));
     $task->setDescription((string) $request->getValue('description'));
     $changes = array();
     $changes[ManiphestTransactionType::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN;
     $priority = $request->getValue('priority');
     if ($priority !== null) {
         $changes[ManiphestTransactionType::TYPE_PRIORITY] = $priority;
     }
     $owner_phid = $request->getValue('ownerPHID');
     if ($owner_phid !== null) {
         $changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid;
     }
     $ccs = $request->getValue('ccPHIDs');
     if ($ccs !== null) {
         $changes[ManiphestTransactionType::TYPE_CCS] = $ccs;
     }
     $project_phids = $request->getValue('projectPHIDs');
     if ($project_phids !== null) {
         $changes[ManiphestTransactionType::TYPE_PROJECTS] = $project_phids;
     }
     $file_phids = $request->getValue('filePHIDs');
     if ($file_phids !== null) {
         $file_map = array_fill_keys($file_phids, true);
         $changes[ManiphestTransactionType::TYPE_ATTACH] = array(PhabricatorPHIDConstants::PHID_TYPE_FILE => $file_map);
     }
     $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);
         $transactions[] = $transaction;
     }
     $editor = new ManiphestTransactionEditor();
     $editor->applyTransactions($task, $transactions);
     return $this->buildTaskInfoDictionary($task);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $revision_id = $request->getInt('revision_id');
     $revision = id(new DifferentialRevision())->load($revision_id);
     if (!$revision) {
         return new Aphront400Response();
     }
     $comment = $request->getStr('comment');
     $action = $request->getStr('action');
     $reviewers = $request->getArr('reviewers');
     $ccs = $request->getArr('ccs');
     $editor = new DifferentialCommentEditor($revision, $request->getUser()->getPHID(), $action);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     try {
         $editor->setMessage($comment)->setContentSource($content_source)->setAttachInlineComments(true)->setAddedReviewers($reviewers)->setAddedCCs($ccs)->save();
     } catch (DifferentialActionHasNoEffectException $no_effect) {
         $has_inlines = id(new DifferentialInlineComment())->loadAllWhere('authorPHID = %s AND revisionID = %d AND commentID IS NULL', $request->getUser()->getPHID(), $revision->getID());
         $dialog = new AphrontDialogView();
         $dialog->setUser($request->getUser());
         $dialog->addCancelButton('/D' . $revision_id);
         $dialog->addHiddenInput('revision_id', $revision_id);
         $dialog->addHiddenInput('action', 'none');
         $dialog->addHiddenInput('reviewers', $reviewers);
         $dialog->addHiddenInput('ccs', $ccs);
         $dialog->addHiddenInput('comment', $comment);
         $dialog->setTitle('Action Has No Effect');
         $dialog->appendChild('<p>' . phutil_escape_html($no_effect->getMessage()) . '</p>');
         if (strlen($comment) || $has_inlines) {
             $dialog->addSubmitButton('Post as Comment');
             $dialog->appendChild('<br />');
             $dialog->appendChild('<p>Do you want to post your feedback anyway, as a normal ' . 'comment?</p>');
         }
         return id(new AphrontDialogResponse())->setDialog($dialog);
     }
     // TODO: Diff change detection?
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $request->getUser()->getPHID(), 'differential-comment-' . $revision->getID());
     if ($draft) {
         $draft->delete();
     }
     return id(new AphrontRedirectResponse())->setURI('/D' . $revision->getID());
 }
 public function generate()
 {
     $author_phid = $this->loadPhabrictorUserPHID();
     $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $author_phid);
     $mock = PholioMock::initializeNewMock($author);
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_UNKNOWN, array());
     $template = id(new PholioTransaction())->setContentSource($content_source);
     // Accumulate Transactions
     $changes = array();
     $changes[PholioTransaction::TYPE_NAME] = $this->generateTitle();
     $changes[PholioTransaction::TYPE_DESCRIPTION] = $this->generateDescription();
     $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] = PhabricatorPolicies::POLICY_PUBLIC;
     $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('=' => $this->getCCPHIDs());
     // Get Files and make Images
     $file_phids = $this->generateImages();
     $files = id(new PhabricatorFileQuery())->setViewer($author)->withPHIDs($file_phids)->execute();
     $mock->setCoverPHID(head($files)->getPHID());
     $sequence = 0;
     $images = array();
     foreach ($files as $file) {
         $image = new PholioImage();
         $image->setFilePHID($file->getPHID());
         $image->setSequence($sequence++);
         $image->attachMock($mock);
         $images[] = $image;
     }
     // Apply Transactions
     $transactions = array();
     foreach ($changes as $type => $value) {
         $transaction = clone $template;
         $transaction->setTransactionType($type);
         $transaction->setNewValue($value);
         $transactions[] = $transaction;
     }
     $mock->openTransaction();
     $editor = id(new PholioMockEditor())->setContentSource($content_source)->setContinueOnNoEffect(true)->setActor($author)->applyTransactions($mock, $transactions);
     foreach ($images as $image) {
         $image->setMockID($mock->getID());
         $image->save();
     }
     $mock->saveTransaction();
     return $mock->save();
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     if (!$request->isFormPost()) {
         return new Aphront400Response();
     }
     $user = $request->getUser();
     $question_id = $request->getInt('question_id');
     $question = PonderQuestionQuery::loadSingle($user, $question_id);
     if (!$question) {
         return new Aphront404Response();
     }
     $answer = $request->getStr('answer');
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     $res = new PonderAnswer();
     $res->setContent($answer)->setAuthorPHID($user->getPHID())->setVoteCount(0)->setQuestionID($question_id)->setContentSource($content_source);
     id(new PonderAnswerEditor())->setQuestion($question)->setAnswer($res)->saveAnswer();
     PhabricatorSearchPonderIndexer::indexQuestion($question);
     return id(new AphrontRedirectResponse())->setURI(id(new PhutilURI('/Q' . $question->getID()))->setFragment('A' . $res->getID()));
 }
 private function handlePost()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $errors = array();
     $title = $request->getStr('title');
     $content = $request->getStr('content');
     // form validation
     if (phutil_utf8_strlen($title) < 1 || phutil_utf8_strlen($title) > 255) {
         $errors[] = "Please enter a title (1-255 characters)";
     }
     if ($errors) {
         return $this->showForm($errors, $title, $content);
     }
     // no validation errors -> save it
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
     $question = id(new PonderQuestion())->setTitle($title)->setContent($content)->setAuthorPHID($user->getPHID())->setContentSource($content_source)->setVoteCount(0)->setAnswerCount(0)->setHeat(0.0)->save();
     PhabricatorSearchPonderIndexer::indexQuestion($question);
     return id(new AphrontRedirectResponse())->setURI('/Q' . $question->getID());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $question = id(new PonderQuestion())->setAuthorPHID($user->getPHID())->setVoteCount(0)->setAnswerCount(0)->setHeat(0.0);
     $errors = array();
     $e_title = true;
     if ($request->isFormPost()) {
         $question->setTitle($request->getStr('title'));
         $question->setContent($request->getStr('content'));
         $len = phutil_utf8_strlen($question->getTitle());
         if ($len < 1) {
             $errors[] = pht('Title must not be empty.');
             $e_title = pht('Required');
         } else {
             if ($len > 255) {
                 $errors[] = pht('Title is too long.');
                 $e_title = pht('Too Long');
             }
         }
         if (!$errors) {
             $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_WEB, array('ip' => $request->getRemoteAddr()));
             $question->setContentSource($content_source);
             id(new PonderQuestionEditor())->setQuestion($question)->setUser($user)->save();
             return id(new AphrontRedirectResponse())->setURI('/Q' . $question->getID());
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors);
     }
     $header = id(new PhabricatorHeaderView())->setHeader(pht('Ask Question'));
     $form = id(new AphrontFormView())->setUser($user)->setFlexible(true)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Question'))->setName('title')->setValue($question->getTitle())->setError($e_title))->appendChild(id(new PhabricatorRemarkupControl())->setName('content')->setID('content')->setValue($question->getContent())->setLabel(pht('Description')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Ask Away!'));
     $preview = '<div class="aphront-panel-flush">' . '<div id="question-preview">' . '<span class="aphront-panel-preview-loading-text">' . pht('Loading question preview...') . '</span>' . '</div>' . '</div>';
     Javelin::initBehavior('ponder-feedback-preview', array('uri' => '/ponder/question/preview/', 'content' => 'content', 'preview' => 'question-preview', 'question_id' => null));
     $nav = $this->buildSideNavView($question);
     $nav->selectFilter($question->getID() ? null : 'question/ask');
     $nav->appendChild(array($header, $error_view, $form, $preview));
     return $this->buildApplicationPage($nav, array('device' => true, 'title' => 'Ask a Question'));
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $action = $request->getValue('action');
     $ok = $request->getValue('ok');
     $dry_run = $request->getValue('dryRun');
     $details = $request->getValue('details', array());
     switch ($request->getValue('action')) {
         case 'pick':
             $pick_status = $ok ? ReleephRequest::PICK_OK : ReleephRequest::PICK_FAILED;
             break;
         case 'revert':
             $pick_status = $ok ? ReleephRequest::REVERT_OK : ReleephRequest::REVERT_FAILED;
             break;
         default:
             throw new Exception(pht('Unknown action %s!', $action));
     }
     $releeph_request = id(new ReleephRequest())->loadOneWhere('phid = %s', $request->getValue('requestPHID'));
     $editor = id(new ReleephRequestTransactionalEditor())->setActor($request->getUser())->setContinueOnNoEffect(true)->setContentSource(PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_CONDUIT, array()));
     $xactions = array();
     $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_PICK_STATUS)->setMetadataValue('dryRun', $dry_run)->setMetadataValue('details', $details)->setNewValue($pick_status);
     $editor->applyTransactions($releeph_request, $xactions);
 }
 public final function applyTransactions(PhabricatorLiskDAO $object, array $xactions)
 {
     $this->object = $object;
     $this->xactions = $xactions;
     $this->isNewObject = $object->getPHID() === null;
     $this->validateEditParameters($object, $xactions);
     $actor = $this->requireActor();
     // NOTE: Some transaction expansion requires that the edited object be
     // attached.
     foreach ($xactions as $xaction) {
         $xaction->attachObject($object);
         $xaction->attachViewer($actor);
     }
     $xactions = $this->expandTransactions($object, $xactions);
     $xactions = $this->expandSupportTransactions($object, $xactions);
     $xactions = $this->combineTransactions($xactions);
     foreach ($xactions as $xaction) {
         $xaction = $this->populateTransaction($object, $xaction);
     }
     $is_preview = $this->getIsPreview();
     $read_locking = false;
     $transaction_open = false;
     if (!$is_preview) {
         $errors = array();
         $type_map = mgroup($xactions, 'getTransactionType');
         foreach ($this->getTransactionTypes() as $type) {
             $type_xactions = idx($type_map, $type, array());
             $errors[] = $this->validateTransaction($object, $type, $type_xactions);
         }
         $errors = array_mergev($errors);
         $continue_on_missing = $this->getContinueOnMissingFields();
         foreach ($errors as $key => $error) {
             if ($continue_on_missing && $error->getIsMissingFieldError()) {
                 unset($errors[$key]);
             }
         }
         if ($errors) {
             throw new PhabricatorApplicationTransactionValidationException($errors);
         }
         $file_phids = $this->extractFilePHIDs($object, $xactions);
         if ($object->getID()) {
             foreach ($xactions as $xaction) {
                 // If any of the transactions require a read lock, hold one and
                 // reload the object. We need to do this fairly early so that the
                 // call to `adjustTransactionValues()` (which populates old values)
                 // is based on the synchronized state of the object, which may differ
                 // from the state when it was originally loaded.
                 if ($this->shouldReadLock($object, $xaction)) {
                     $object->openTransaction();
                     $object->beginReadLocking();
                     $transaction_open = true;
                     $read_locking = true;
                     $object->reload();
                     break;
                 }
             }
         }
         if ($this->shouldApplyInitialEffects($object, $xactions)) {
             if (!$transaction_open) {
                 $object->openTransaction();
                 $transaction_open = true;
             }
         }
     }
     if ($this->shouldApplyInitialEffects($object, $xactions)) {
         $this->applyInitialEffects($object, $xactions);
     }
     foreach ($xactions as $xaction) {
         $this->adjustTransactionValues($object, $xaction);
     }
     $xactions = $this->filterTransactions($object, $xactions);
     if (!$xactions) {
         if ($read_locking) {
             $object->endReadLocking();
             $read_locking = false;
         }
         if ($transaction_open) {
             $object->killTransaction();
             $transaction_open = false;
         }
         return array();
     }
     // Now that we've merged, filtered, and combined transactions, check for
     // required capabilities.
     foreach ($xactions as $xaction) {
         $this->requireCapabilities($object, $xaction);
     }
     $xactions = $this->sortTransactions($xactions);
     if ($is_preview) {
         $this->loadHandles($xactions);
         return $xactions;
     }
     $comment_editor = id(new PhabricatorApplicationTransactionCommentEditor())->setActor($actor)->setActingAsPHID($this->getActingAsPHID())->setContentSource($this->getContentSource());
     if (!$transaction_open) {
         $object->openTransaction();
     }
     foreach ($xactions as $xaction) {
         $this->applyInternalEffects($object, $xaction);
     }
     $object->save();
     foreach ($xactions as $xaction) {
         $xaction->setObjectPHID($object->getPHID());
         if ($xaction->getComment()) {
             $xaction->setPHID($xaction->generatePHID());
             $comment_editor->applyEdit($xaction, $xaction->getComment());
         } else {
             $xaction->save();
         }
     }
     if ($file_phids) {
         $this->attachFiles($object, $file_phids);
     }
     foreach ($xactions as $xaction) {
         $this->applyExternalEffects($object, $xaction);
     }
     $xactions = $this->applyFinalEffects($object, $xactions);
     if ($read_locking) {
         $object->endReadLocking();
         $read_locking = false;
     }
     $object->saveTransaction();
     // Now that we've completely applied the core transaction set, try to apply
     // Herald rules. Herald rules are allowed to either take direct actions on
     // the database (like writing flags), or take indirect actions (like saving
     // some targets for CC when we generate mail a little later), or return
     // transactions which we'll apply normally using another Editor.
     // First, check if *this* is a sub-editor which is itself applying Herald
     // rules: if it is, stop working and return so we don't descend into
     // madness.
     // Otherwise, we're not a Herald editor, so process Herald rules (possibly
     // using a Herald editor to apply resulting transactions) and then send out
     // mail, notifications, and feed updates about everything.
     if ($this->getIsHeraldEditor()) {
         // We are the Herald editor, so stop work here and return the updated
         // transactions.
         return $xactions;
     } else {
         if ($this->shouldApplyHeraldRules($object, $xactions)) {
             // We are not the Herald editor, so try to apply Herald rules.
             $herald_xactions = $this->applyHeraldRules($object, $xactions);
             if ($herald_xactions) {
                 $xscript_id = $this->getHeraldTranscript()->getID();
                 foreach ($herald_xactions as $herald_xaction) {
                     $herald_xaction->setMetadataValue('herald:transcriptID', $xscript_id);
                 }
                 // NOTE: We're acting as the omnipotent user because rules deal with
                 // their own policy issues. We use a synthetic author PHID (the
                 // Herald application) as the author of record, so that transactions
                 // will render in a reasonable way ("Herald assigned this task ...").
                 $herald_actor = PhabricatorUser::getOmnipotentUser();
                 $herald_phid = id(new PhabricatorHeraldApplication())->getPHID();
                 // TODO: It would be nice to give transactions a more specific source
                 // which points at the rule which generated them. You can figure this
                 // out from transcripts, but it would be cleaner if you didn't have to.
                 $herald_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_HERALD, array());
                 $herald_editor = newv(get_class($this), array())->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->setParentMessageID($this->getParentMessageID())->setIsHeraldEditor(true)->setActor($herald_actor)->setActingAsPHID($herald_phid)->setContentSource($herald_source);
                 $herald_xactions = $herald_editor->applyTransactions($object, $herald_xactions);
                 // Merge the new transactions into the transaction list: we want to
                 // send email and publish feed stories about them, too.
                 $xactions = array_merge($xactions, $herald_xactions);
             }
         }
     }
     // Before sending mail or publishing feed stories, reload the object
     // subscribers to pick up changes caused by Herald (or by other side effects
     // in various transaction phases).
     $this->loadSubscribers($object);
     $this->loadHandles($xactions);
     $mail = null;
     if (!$this->getDisableEmail()) {
         if ($this->shouldSendMail($object, $xactions)) {
             $mail = $this->sendMail($object, $xactions);
         }
     }
     if ($this->supportsSearch()) {
         id(new PhabricatorSearchIndexer())->queueDocumentForIndexing($object->getPHID());
     }
     if ($this->shouldPublishFeedStory($object, $xactions)) {
         $mailed = array();
         if ($mail) {
             $mailed = $mail->buildRecipientList();
         }
         $this->publishFeedStory($object, $xactions, $mailed);
     }
     $this->didApplyTransactions($xactions);
     if ($object instanceof PhabricatorCustomFieldInterface) {
         // Maybe this makes more sense to move into the search index itself? For
         // now I'm putting it here since I think we might end up with things that
         // need it to be up to date once the next page loads, but if we don't go
         // there we we could move it into search once search moves to the daemons.
         // It now happens in the search indexer as well, but the search indexer is
         // always daemonized, so the logic above still potentially holds. We could
         // possibly get rid of this. The major motivation for putting it in the
         // indexer was to enable reindexing to work.
         $fields = PhabricatorCustomField::getObjectFields($object, PhabricatorCustomField::ROLE_APPLICATIONSEARCH);
         $fields->readFieldsFromStorage($object);
         $fields->rebuildIndexes($object);
     }
     return $xactions;
 }
 public function didParseCommit(PhabricatorRepository $repo, PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data)
 {
     // NOTE: This is currently dead code. See T2222.
     $releeph_requests = $this->loadReleephRequests();
     if (!$releeph_requests) {
         return;
     }
     $releeph_branch = head($releeph_requests)->getBranch();
     if (!$this->isCommitOnBranch($repo, $commit, $releeph_branch)) {
         return;
     }
     foreach ($releeph_requests as $releeph_request) {
         if ($this->releephAction === self::ACTION_PICKS) {
             $action = 'pick';
         } else {
             $action = 'revert';
         }
         $actor_phid = coalesce($data->getCommitDetail('committerPHID'), $data->getCommitDetail('authorPHID'));
         $actor = id(new PhabricatorUser())->loadOneWhere('phid = %s', $actor_phid);
         $xactions = array();
         $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_DISCOVERY)->setMetadataValue('action', $action)->setMetadataValue('authorPHID', $data->getCommitDetail('authorPHID'))->setMetadataValue('committerPHID', $data->getCommitDetail('committerPHID'))->setNewValue($commit->getPHID());
         $editor = id(new ReleephRequestTransactionalEditor())->setActor($actor)->setContinueOnNoEffect(true)->setContentSource(PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_UNKNOWN, array()));
         $editor->applyTransactions($releeph_request, $xactions);
     }
 }
 public function getTransactionCommentForSave()
 {
     $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_LEGACY, array());
     $this->proxy->setViewPolicy('public')->setEditPolicy($this->getAuthorPHID())->setContentSource($content_source)->setCommentVersion(1);
     return $this->proxy;
 }
<?php

$conn_w = id(new DifferentialRevision())->establishConnection('w');
$rows = new LiskRawMigrationIterator($conn_w, 'differential_comment');
$content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_LEGACY, array())->serialize();
echo pht('Migrating Differential comment text to modern storage...') . "\n";
foreach ($rows as $row) {
    $id = $row['id'];
    echo pht('Migrating Differential comment %d...', $id) . "\n";
    if (!strlen($row['content'])) {
        echo pht('Comment has no text, continuing.') . "\n";
        continue;
    }
    $revision = id(new DifferentialRevision())->load($row['revisionID']);
    if (!$revision) {
        echo pht('Comment has no valid revision, continuing.') . "\n";
        continue;
    }
    $revision_phid = $revision->getPHID();
    $dst_table = 'differential_inline_comment';
    $xaction_phid = PhabricatorPHID::generateNewPHID(PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, DifferentialRevisionPHIDType::TYPECONST);
    $comment_phid = PhabricatorPHID::generateNewPHID(PhabricatorPHIDConstants::PHID_TYPE_XCMT, DifferentialRevisionPHIDType::TYPECONST);
    queryfx($conn_w, 'INSERT IGNORE INTO %T
      (phid, transactionPHID, authorPHID, viewPolicy, editPolicy,
        commentVersion, content, contentSource, isDeleted,
        dateCreated, dateModified, revisionPHID, changesetID,
        legacyCommentID)
      VALUES (%s, %s, %s, %s, %s,
        %d, %s, %s, %d,
        %d, %d, %s, %nd,
        %d)', 'differential_transaction_comment', $comment_phid, $xaction_phid, $row['authorPHID'], 'public', $row['authorPHID'], 1, $row['content'], $content_source, 0, $row['dateCreated'], $row['dateModified'], $revision_phid, null, $row['id']);