public function processRequest()
 {
     $request = $this->getRequest();
     if ($request->isFormPost()) {
         $diff = null;
         try {
             $diff = PhabricatorFile::readUploadedFileData($_FILES['diff-file']);
         } catch (Exception $ex) {
             $diff = $request->getStr('diff');
         }
         $call = new ConduitCall('differential.createrawdiff', array('diff' => $diff));
         $call->setUser($request->getUser());
         $result = $call->execute();
         $path = id(new PhutilURI($result['uri']))->getPath();
         return id(new AphrontRedirectResponse())->setURI($path);
     }
     $form = new AphrontFormView();
     $arcanist_href = PhabricatorEnv::getDoclink('article/Arcanist_User_Guide.html');
     $arcanist_link = phutil_render_tag('a', array('href' => $arcanist_href, 'target' => '_blank'), 'Arcanist');
     $form->setAction('/differential/diff/create/')->setEncType('multipart/form-data')->setUser($request->getUser())->appendChild('<p class="aphront-form-instructions">The best way to create a ' . "Differential diff is by using {$arcanist_link}, but you " . 'can also just paste a diff (e.g., from <tt>svn diff</tt> or ' . '<tt>git diff</tt>) into this box or upload it as a file if you ' . 'really want.</p>')->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Raw Diff')->setName('diff')->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL))->appendChild(id(new AphrontFormFileControl())->setLabel('Raw Diff from file')->setName('diff-file'))->appendChild(id(new AphrontFormSubmitControl())->setValue("Create Diff »"));
     $panel = new AphrontPanelView();
     $panel->setHeader('Create New Diff');
     $panel->appendChild($form);
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     return $this->buildStandardPageResponse($panel, array('title' => 'Create Diff', 'tab' => 'create'));
 }
 private function getBlockers(PhabricatorRepositoryCommit $commit, HarbormasterBuildPlan $plan, HarbormasterBuild $source)
 {
     $call = new ConduitCall('diffusion.commitparentsquery', array('commit' => $commit->getCommitIdentifier(), 'repository' => $commit->getRepository()->getPHID()));
     $call->setUser(PhabricatorUser::getOmnipotentUser());
     $parents = $call->execute();
     $parents = id(new DiffusionCommitQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withRepository($commit->getRepository())->withIdentifiers($parents)->execute();
     $blockers = array();
     $build_objects = array();
     foreach ($parents as $parent) {
         if (!$parent->isImported()) {
             $blockers[] = pht('Commit %s', $parent->getCommitIdentifier());
         } else {
             $build_objects[] = $parent->getPHID();
         }
     }
     if ($build_objects) {
         $buildables = id(new HarbormasterBuildableQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withBuildablePHIDs($build_objects)->withManualBuildables(false)->execute();
         $buildable_phids = mpull($buildables, 'getPHID');
         if ($buildable_phids) {
             $builds = id(new HarbormasterBuildQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withBuildablePHIDs($buildable_phids)->withBuildPlanPHIDs(array($plan->getPHID()))->execute();
             foreach ($builds as $build) {
                 if (!$build->isComplete()) {
                     $blockers[] = pht('Build %d', $build->getID());
                 }
             }
         }
     }
     return $blockers;
 }
 private function attemptLand($revision, $request)
 {
     $status = $revision->getStatus();
     if ($status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
         throw new Exception(pht('Only Accepted revisions can be landed.'));
     }
     $repository = $revision->getRepository();
     if ($repository === null) {
         throw new Exception(pht('Revision is not attached to a repository.'));
     }
     $can_push = PhabricatorPolicyFilter::hasCapability($request->getUser(), $repository, DiffusionPushCapability::CAPABILITY);
     if (!$can_push) {
         throw new Exception(pht('You do not have permission to push to this repository.'));
     }
     $lock = $this->lockRepository($repository);
     try {
         $response = $this->pushStrategy->processLandRequest($request, $revision, $repository);
     } catch (Exception $e) {
         $lock->unlock();
         throw $e;
     }
     $lock->unlock();
     $looksoon = new ConduitCall('diffusion.looksoon', array('repositories' => array($repository->getPHID())));
     $looksoon->setUser($request->getUser());
     $looksoon->execute();
     return $response;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $diff_id = $request->getValue('diffID');
     $linter_map = $request->getValue('linters');
     $diff = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withIDs(array($diff_id))->executeOne();
     if (!$diff) {
         throw new ConduitException('ERR-BAD-DIFF');
     }
     // Extract the finished linters and messages from the linter map.
     $finished_linters = array_keys($linter_map);
     $new_messages = array();
     foreach ($linter_map as $linter => $messages) {
         $new_messages = array_merge($new_messages, $messages);
     }
     // Load the postponed linters attached to this diff.
     $postponed_linters_property = id(new DifferentialDiffProperty())->loadOneWhere('diffID = %d AND name = %s', $diff_id, 'arc:lint-postponed');
     if ($postponed_linters_property) {
         $postponed_linters = $postponed_linters_property->getData();
     } else {
         $postponed_linters = array();
     }
     foreach ($finished_linters as $linter) {
         if (!in_array($linter, $postponed_linters)) {
             throw new ConduitException('ERR-BAD-LINTER');
         }
     }
     foreach ($postponed_linters as $idx => $linter) {
         if (in_array($linter, $finished_linters)) {
             unset($postponed_linters[$idx]);
         }
     }
     // Load the lint messages currenty attached to the diff. If this
     // diff property doesn't exist, create it.
     $messages_property = id(new DifferentialDiffProperty())->loadOneWhere('diffID = %d AND name = %s', $diff_id, 'arc:lint');
     if ($messages_property) {
         $messages = $messages_property->getData();
     } else {
         $messages = array();
     }
     // Add new lint messages, removing duplicates.
     foreach ($new_messages as $new_message) {
         if (!in_array($new_message, $messages)) {
             $messages[] = $new_message;
         }
     }
     // Use setdiffproperty to update the postponed linters and messages,
     // as these will also update the lint status correctly.
     $call = new ConduitCall('differential.setdiffproperty', array('diff_id' => $diff_id, 'name' => 'arc:lint', 'data' => json_encode($messages)));
     $call->setForceLocal(true);
     $call->setUser($request->getUser());
     $call->execute();
     $call = new ConduitCall('differential.setdiffproperty', array('diff_id' => $diff_id, 'name' => 'arc:lint-postponed', 'data' => json_encode($postponed_linters)));
     $call->setForceLocal(true);
     $call->setUser($request->getUser());
     $call->execute();
 }
Ejemplo n.º 5
0
 public function testConduitAuth()
 {
     $call = new ConduitCall('user.whoami', array());
     $caught = null;
     try {
         $result = $call->execute();
     } catch (ConduitException $ex) {
         $caught = $ex;
     }
     $this->assertEqual(true, $caught instanceof ConduitException, "user.whoami should require authentication");
 }
Ejemplo n.º 6
0
 public function testConduitAuth()
 {
     $call = new ConduitCall('user.whoami', array(), true);
     $caught = null;
     try {
         $result = $call->execute();
     } catch (ConduitException $ex) {
         $caught = $ex;
     }
     $this->assertTrue($caught instanceof ConduitException, pht('%s should require authentication.', 'user.whoami'));
 }
Ejemplo n.º 7
0
 public function execute(PhutilArgumentParser $args)
 {
     $time_start = microtime(true);
     $methodv = $args->getArg('method');
     if (!$methodv) {
         throw new Exception(pht('No Conduit method provided.'));
     } else {
         if (count($methodv) > 1) {
             throw new Exception(pht('Too many Conduit methods provided.'));
         }
     }
     $method = head($methodv);
     $json = $this->readAllInput();
     $raw_params = null;
     try {
         $raw_params = phutil_json_decode($json);
     } catch (PhutilJSONParserException $ex) {
         throw new PhutilProxyException(pht('Invalid JSON input.'), $ex);
     }
     $params = idx($raw_params, 'params', '[]');
     $params = phutil_json_decode($params);
     $metadata = idx($params, '__conduit__', array());
     unset($params['__conduit__']);
     $call = null;
     $error_code = null;
     $error_info = null;
     try {
         $call = new ConduitCall($method, $params);
         $call->setUser($this->getUser());
         $result = $call->execute();
     } catch (ConduitException $ex) {
         $result = null;
         $error_code = $ex->getMessage();
         if ($ex->getErrorDescription()) {
             $error_info = $ex->getErrorDescription();
         } else {
             if ($call) {
                 $error_info = $call->getErrorDescription($error_code);
             }
         }
     }
     $response = id(new ConduitAPIResponse())->setResult($result)->setErrorCode($error_code)->setErrorInfo($error_info);
     $json_out = json_encode($response->toDictionary());
     $json_out = $json_out . "\n";
     $this->getIOChannel()->write($json_out);
     // NOTE: Flush here so we can get an accurate result for the duration,
     // if the response is large and the receiver is slow to read it.
     $this->getIOChannel()->flush();
     $time_end = microtime(true);
     $connection_id = idx($metadata, 'connectionID');
     $log = id(new PhabricatorConduitMethodCallLog())->setCallerPHID($this->getUser()->getPHID())->setConnectionID($connection_id)->setMethod($method)->setError((string) $error_code)->setDuration(1000000 * ($time_end - $time_start))->save();
 }
 public function didParseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data)
 {
     $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $data->getCommitDetail('authorPHID'));
     if (!$user) {
         return;
     }
     $prefixes = array('resolves' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'fixes' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'wontfix' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'wontfixes' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'spites' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'invalidate' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, 'invaldiates' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, 'close' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'closes' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'ref' => null, 'refs' => null, 'references' => null, 'cf.' => null);
     $suffixes = array('as resolved' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'as fixed' => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, 'as wontfix' => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, 'as spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'out of spite' => ManiphestTaskStatus::STATUS_CLOSED_SPITE, 'as invalid' => ManiphestTaskStatus::STATUS_CLOSED_INVALID, '' => null);
     $prefix_regex = array();
     foreach ($prefixes as $prefix => $resolution) {
         $prefix_regex[] = preg_quote($prefix, '/');
     }
     $prefix_regex = implode('|', $prefix_regex);
     $suffix_regex = array();
     foreach ($suffixes as $suffix => $resolution) {
         $suffix_regex[] = preg_quote($suffix, '/');
     }
     $suffix_regex = implode('|', $suffix_regex);
     $matches = null;
     $ok = preg_match_all("/({$prefix_regex})\\s+T(\\d+)\\s*({$suffix_regex})/i", $this->renderValueForCommitMessage($is_edit = false), $matches, PREG_SET_ORDER);
     if (!$ok) {
         return;
     }
     foreach ($matches as $set) {
         $prefix = strtolower($set[1]);
         $task_id = (int) $set[2];
         $suffix = strtolower($set[3]);
         $status = idx($suffixes, $suffix);
         if (!$status) {
             $status = idx($prefixes, $prefix);
         }
         $tasks = id(new ManiphestTaskQuery())->withTaskIDs(array($task_id))->execute();
         $task = idx($tasks, $task_id);
         if (!$task) {
             // Task doesn't exist, or the user can't see it.
             continue;
         }
         id(new PhabricatorEdgeEditor())->setUser($user)->addEdge($task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT, $commit->getPHID())->save();
         if (!$status) {
             // Text like "Ref T123", don't change the task status.
             continue;
         }
         if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) {
             // Task is already closed.
             continue;
         }
         $commit_name = $repository->formatCommitName($commit->getCommitIdentifier());
         $call = new ConduitCall('maniphest.update', array('id' => $task->getID(), 'status' => $status, 'comments' => "Closed by commit {$commit_name}."));
         $call->setUser($user);
         $call->execute();
     }
 }
 public function generateDiff($author)
 {
     $paste_generator = new PhabricatorPasteTestDataGenerator();
     $languages = $paste_generator->supportedLanguages;
     $lang = array_rand($languages);
     $code = $paste_generator->generateContent($lang);
     $altcode = $paste_generator->generateContent($lang);
     $newcode = $this->randomlyModify($code, $altcode);
     $diff = id(new PhabricatorDifferenceEngine())->generateRawDiffFromFileContent($code, $newcode);
     $call = new ConduitCall('differential.createrawdiff', array('diff' => $diff));
     $call->setUser($author);
     $result = $call->execute();
     $thediff = id(new DifferentialDiff())->load($result['id']);
     $thediff->setDescription($this->generateTitle())->save();
     return $thediff;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $viewer = $request->getUser();
     $call = new ConduitCall('harbormaster.build.search', array_filter(array('constraints' => array_filter(array('ids' => $request->getValue('ids'), 'phids' => $request->getValue('phids'), 'statuses' => $request->getValue('buildStatuses'), 'buildables' => $request->getValue('buildablePHIDs'), 'plans' => $request->getValue('buildPlanPHIDs'))), 'attachments' => array('querybuilds' => true), 'limit' => $request->getValue('limit'), 'before' => $request->getValue('before'), 'after' => $request->getValue('after'))));
     $subsumption = $call->setUser($viewer)->execute();
     $data = array();
     foreach ($subsumption['data'] as $build_data) {
         $querybuilds = idxv($build_data, array('attachments', 'querybuilds'), array());
         $fields = idx($build_data, 'fields', array());
         unset($build_data['fields']);
         unset($build_data['attachments']);
         $data[] = array_mergev(array($build_data, $querybuilds, $fields));
     }
     $subsumption['data'] = $data;
     return $subsumption;
 }
 public function commitRevisionToWorkspace(DifferentialRevision $revision, ArcanistRepositoryAPI $workspace, PhabricatorUser $user)
 {
     $diff_id = $revision->loadActiveDiff()->getID();
     $call = new ConduitCall('differential.getrawdiff', array('diffID' => $diff_id));
     $call->setUser($user);
     $raw_diff = $call->execute();
     $future = $workspace->execFutureLocal('patch --no-commit -');
     $future->write($raw_diff);
     $future->resolvex();
     $workspace->reloadWorkingCopy();
     $call = new ConduitCall('differential.getcommitmessage', array('revision_id' => $revision->getID()));
     $call->setUser($user);
     $message = $call->execute();
     $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $revision->getAuthorPHID());
     $author_string = sprintf('%s <%s>', $author->getRealName(), $author->loadPrimaryEmailAddress());
     $author_date = $revision->getDateCreated();
     $workspace->execxLocal('commit --date=%s --user=%s ' . '--message=%s', $author_date . ' 0', $author_string, $message);
 }
 public function commitRevisionToWorkspace(DifferentialRevision $revision, ArcanistRepositoryAPI $workspace, PhabricatorUser $user)
 {
     $diff_id = $revision->loadActiveDiff()->getID();
     $call = new ConduitCall('differential.getrawdiff', array('diffID' => $diff_id));
     $call->setUser($user);
     $raw_diff = $call->execute();
     $missing_binary = "\nindex " . "0000000000000000000000000000000000000000.." . "0000000000000000000000000000000000000000\n";
     if (strpos($raw_diff, $missing_binary) !== false) {
         throw new Exception(pht('Patch is missing content for a binary file'));
     }
     $future = $workspace->execFutureLocal('apply --index -');
     $future->write($raw_diff);
     $future->resolvex();
     $workspace->reloadWorkingCopy();
     $call = new ConduitCall('differential.getcommitmessage', array('revision_id' => $revision->getID()));
     $call->setUser($user);
     $message = $call->execute();
     $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $revision->getAuthorPHID());
     $author_string = sprintf('%s <%s>', $author->getRealName(), $author->loadPrimaryEmailAddress());
     $author_date = $revision->getDateCreated();
     $workspace->execxLocal('-c user.name=%s -c user.email=%s ' . 'commit --date=%s --author=%s ' . '--message=%s', $user->getRealName(), $user->loadPrimaryEmailAddress(), $author_date, $author_string, $message);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $errors = array();
     $e_diff = null;
     $e_file = null;
     if ($request->isFormPost()) {
         $diff = null;
         if ($request->getFileExists('diff-file')) {
             $diff = PhabricatorFile::readUploadedFileData($_FILES['diff-file']);
         } else {
             $diff = $request->getStr('diff');
         }
         if (!strlen($diff)) {
             $errors[] = pht('You can not create an empty diff. Copy/paste a diff, or upload a ' . 'diff file.');
             $e_diff = pht('Required');
             $e_file = pht('Required');
         }
         if (!$errors) {
             $call = new ConduitCall('differential.createrawdiff', array('diff' => $diff));
             $call->setUser($request->getUser());
             $result = $call->execute();
             $path = id(new PhutilURI($result['uri']))->getPath();
             return id(new AphrontRedirectResponse())->setURI($path);
         }
     }
     $form = new AphrontFormView();
     $arcanist_href = PhabricatorEnv::getDoclink('Arcanist User Guide');
     $arcanist_link = phutil_tag('a', array('href' => $arcanist_href, 'target' => '_blank'), 'Arcanist');
     $cancel_uri = $this->getApplicationURI();
     $form->setAction('/differential/diff/create/')->setEncType('multipart/form-data')->setUser($request->getUser())->appendInstructions(pht('The best way to create a Differential diff is by using %s, but you ' . 'can also just paste a diff (for example, from %s, %s or %s) into ' . 'this box, or upload a diff file.', $arcanist_link, phutil_tag('tt', array(), 'svn diff'), phutil_tag('tt', array(), 'git diff'), phutil_tag('tt', array(), 'hg diff --git')))->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Raw Diff'))->setName('diff')->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setError($e_diff))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('Raw Diff From File'))->setName('diff-file')->setError($e_file))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue(pht('Create Diff')));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Create New Diff'))->setForm($form)->setFormErrors($errors);
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Create Diff'));
     return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => pht('Create Diff')));
 }
 public function processRequest()
 {
     $time_start = microtime(true);
     $request = $this->getRequest();
     $method = $this->method;
     $api_request = null;
     $log = new PhabricatorConduitMethodCallLog();
     $log->setMethod($method);
     $metadata = array();
     try {
         $params = $this->decodeConduitParams($request, $method);
         $metadata = idx($params, '__conduit__', array());
         unset($params['__conduit__']);
         $call = new ConduitCall($method, $params);
         $result = null;
         // TODO: Straighten out the auth pathway here. We shouldn't be creating
         // a ConduitAPIRequest at this level, but some of the auth code expects
         // it. Landing a halfway version of this to unblock T945.
         $api_request = new ConduitAPIRequest($params);
         $allow_unguarded_writes = false;
         $auth_error = null;
         $conduit_username = '******';
         if ($call->shouldRequireAuthentication()) {
             $metadata['scope'] = $call->getRequiredScope();
             $auth_error = $this->authenticateUser($api_request, $metadata);
             // If we've explicitly authenticated the user here and either done
             // CSRF validation or are using a non-web authentication mechanism.
             $allow_unguarded_writes = true;
             if (isset($metadata['actAsUser'])) {
                 $this->actAsUser($api_request, $metadata['actAsUser']);
             }
             if ($auth_error === null) {
                 $conduit_user = $api_request->getUser();
                 if ($conduit_user && $conduit_user->getPHID()) {
                     $conduit_username = $conduit_user->getUsername();
                 }
                 $call->setUser($api_request->getUser());
             }
         }
         $access_log = PhabricatorAccessLog::getLog();
         if ($access_log) {
             $access_log->setData(array('u' => $conduit_username, 'm' => $method));
         }
         if ($call->shouldAllowUnguardedWrites()) {
             $allow_unguarded_writes = true;
         }
         if ($auth_error === null) {
             if ($allow_unguarded_writes) {
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             }
             try {
                 $result = $call->execute();
                 $error_code = null;
                 $error_info = null;
             } catch (ConduitException $ex) {
                 $result = null;
                 $error_code = $ex->getMessage();
                 if ($ex->getErrorDescription()) {
                     $error_info = $ex->getErrorDescription();
                 } else {
                     $error_info = $call->getErrorDescription($error_code);
                 }
             }
             if ($allow_unguarded_writes) {
                 unset($unguarded);
             }
         } else {
             list($error_code, $error_info) = $auth_error;
         }
     } catch (Exception $ex) {
         phlog($ex);
         $result = null;
         $error_code = 'ERR-CONDUIT-CORE';
         $error_info = $ex->getMessage();
     }
     $time_end = microtime(true);
     $connection_id = null;
     if (idx($metadata, 'connectionID')) {
         $connection_id = $metadata['connectionID'];
     } else {
         if ($method == 'conduit.connect' && $result) {
             $connection_id = idx($result, 'connectionID');
         }
     }
     $log->setConnectionID($connection_id);
     $log->setError((string) $error_code);
     $log->setDuration(1000000 * ($time_end - $time_start));
     // TODO: This is a hack, but the insert is comparatively expensive and
     // we only really care about having these logs for real CLI clients, if
     // even that.
     if (empty($metadata['authToken'])) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $log->save();
         unset($unguarded);
     }
     $response = id(new ConduitAPIResponse())->setResult($result)->setErrorCode($error_code)->setErrorInfo($error_info);
     switch ($request->getStr('output')) {
         case 'human':
             return $this->buildHumanReadableResponse($method, $api_request, $response->toDictionary());
         case 'json':
         default:
             return id(new AphrontJSONResponse())->setAddJSONShield(false)->setContent($response->toDictionary());
     }
 }
 public function processRequest()
 {
     $time_start = microtime(true);
     $request = $this->getRequest();
     $method = $this->method;
     $api_request = null;
     $method_implementation = null;
     $log = new PhabricatorConduitMethodCallLog();
     $log->setMethod($method);
     $metadata = array();
     $multimeter = MultimeterControl::getInstance();
     if ($multimeter) {
         $multimeter->setEventContext('api.' . $method);
     }
     try {
         list($metadata, $params) = $this->decodeConduitParams($request, $method);
         $call = new ConduitCall($method, $params);
         $method_implementation = $call->getMethodImplementation();
         $result = null;
         // TODO: The relationship between ConduitAPIRequest and ConduitCall is a
         // little odd here and could probably be improved. Specifically, the
         // APIRequest is a sub-object of the Call, which does not parallel the
         // role of AphrontRequest (which is an indepenent object).
         // In particular, the setUser() and getUser() existing independently on
         // the Call and APIRequest is very awkward.
         $api_request = $call->getAPIRequest();
         $allow_unguarded_writes = false;
         $auth_error = null;
         $conduit_username = '******';
         if ($call->shouldRequireAuthentication()) {
             $metadata['scope'] = $call->getRequiredScope();
             $auth_error = $this->authenticateUser($api_request, $metadata);
             // If we've explicitly authenticated the user here and either done
             // CSRF validation or are using a non-web authentication mechanism.
             $allow_unguarded_writes = true;
             if ($auth_error === null) {
                 $conduit_user = $api_request->getUser();
                 if ($conduit_user && $conduit_user->getPHID()) {
                     $conduit_username = $conduit_user->getUsername();
                 }
                 $call->setUser($api_request->getUser());
             }
         }
         $access_log = PhabricatorAccessLog::getLog();
         if ($access_log) {
             $access_log->setData(array('u' => $conduit_username, 'm' => $method));
         }
         if ($call->shouldAllowUnguardedWrites()) {
             $allow_unguarded_writes = true;
         }
         if ($auth_error === null) {
             if ($allow_unguarded_writes) {
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             }
             try {
                 $result = $call->execute();
                 $error_code = null;
                 $error_info = null;
             } catch (ConduitException $ex) {
                 $result = null;
                 $error_code = $ex->getMessage();
                 if ($ex->getErrorDescription()) {
                     $error_info = $ex->getErrorDescription();
                 } else {
                     $error_info = $call->getErrorDescription($error_code);
                 }
             }
             if ($allow_unguarded_writes) {
                 unset($unguarded);
             }
         } else {
             list($error_code, $error_info) = $auth_error;
         }
     } catch (Exception $ex) {
         if (!$ex instanceof ConduitMethodNotFoundException) {
             phlog($ex);
         }
         $result = null;
         $error_code = $ex instanceof ConduitException ? 'ERR-CONDUIT-CALL' : 'ERR-CONDUIT-CORE';
         $error_info = $ex->getMessage();
     }
     $time_end = microtime(true);
     $connection_id = null;
     if (idx($metadata, 'connectionID')) {
         $connection_id = $metadata['connectionID'];
     } else {
         if ($method == 'conduit.connect' && $result) {
             $connection_id = idx($result, 'connectionID');
         }
     }
     $log->setCallerPHID(isset($conduit_user) ? $conduit_user->getPHID() : null)->setConnectionID($connection_id)->setError((string) $error_code)->setDuration(1000000 * ($time_end - $time_start));
     $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
     $log->save();
     unset($unguarded);
     $response = id(new ConduitAPIResponse())->setResult($result)->setErrorCode($error_code)->setErrorInfo($error_info);
     switch ($request->getStr('output')) {
         case 'human':
             return $this->buildHumanReadableResponse($method, $api_request, $response->toDictionary(), $method_implementation);
         case 'json':
         default:
             return id(new AphrontJSONResponse())->setAddJSONShield(false)->setContent($response->toDictionary());
     }
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     // If we're on the "Update Diff" workflow, load the revision we're going
     // to update.
     $revision = null;
     $revision_id = $request->getURIData('revisionID');
     if ($revision_id) {
         $revision = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($revision_id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$revision) {
             return new Aphront404Response();
         }
     }
     $diff = null;
     // This object is just for policy stuff
     $diff_object = DifferentialDiff::initializeNewDiff($viewer);
     $repository_phid = null;
     $errors = array();
     $e_diff = null;
     $e_file = null;
     $validation_exception = null;
     if ($request->isFormPost()) {
         $repository_tokenizer = $request->getArr(id(new DifferentialRepositoryField())->getFieldKey());
         if ($repository_tokenizer) {
             $repository_phid = reset($repository_tokenizer);
         }
         if ($request->getFileExists('diff-file')) {
             $diff = PhabricatorFile::readUploadedFileData($_FILES['diff-file']);
         } else {
             $diff = $request->getStr('diff');
         }
         if (!strlen($diff)) {
             $errors[] = pht('You can not create an empty diff. Paste a diff or upload a ' . 'file containing a diff.');
             $e_diff = pht('Required');
             $e_file = pht('Required');
         }
         if (!$errors) {
             try {
                 $call = new ConduitCall('differential.createrawdiff', array('diff' => $diff, 'repositoryPHID' => $repository_phid, 'viewPolicy' => $request->getStr('viewPolicy')));
                 $call->setUser($viewer);
                 $result = $call->execute();
                 $diff_id = $result['id'];
                 $uri = $this->getApplicationURI("diff/{$diff_id}/");
                 $uri = new PhutilURI($uri);
                 if ($revision) {
                     $uri->setQueryParam('revisionID', $revision->getID());
                 }
                 return id(new AphrontRedirectResponse())->setURI($uri);
             } catch (PhabricatorApplicationTransactionValidationException $ex) {
                 $validation_exception = $ex;
             }
         }
     }
     $form = new AphrontFormView();
     $arcanist_href = PhabricatorEnv::getDoclink('Arcanist User Guide');
     $arcanist_link = phutil_tag('a', array('href' => $arcanist_href, 'target' => '_blank'), pht('Learn More'));
     $cancel_uri = $this->getApplicationURI();
     $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($diff_object)->execute();
     $info_view = null;
     if (!$request->isFormPost()) {
         $info_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->setErrors(array(array(pht('The best way to create a diff is to use the Arcanist ' . 'command-line tool.'), ' ', $arcanist_link), pht('You can also paste a diff below, or upload a file ' . 'containing a diff (for example, from %s, %s or %s).', phutil_tag('tt', array(), 'svn diff'), phutil_tag('tt', array(), 'git diff'), phutil_tag('tt', array(), 'hg diff --git'))));
     }
     if ($revision) {
         $title = pht('Update Diff');
         $header = pht('Update Diff');
         $button = pht('Continue');
     } else {
         $title = pht('Create Diff');
         $header = pht('Create New Diff');
         $button = pht('Create Diff');
     }
     $form->setEncType('multipart/form-data')->setUser($viewer);
     if ($revision) {
         $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Updating Revision'))->setValue($viewer->renderHandle($revision->getPHID())));
     }
     if ($repository_phid) {
         $repository_value = array($repository_phid);
     } else {
         $repository_value = array();
     }
     $form->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Raw Diff'))->setName('diff')->setValue($diff)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setError($e_diff))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('Raw Diff From File'))->setName('diff-file')->setError($e_file))->appendControl(id(new AphrontFormTokenizerControl())->setName(id(new DifferentialRepositoryField())->getFieldKey())->setLabel(pht('Repository'))->setDatasource(new DiffusionRepositoryDatasource())->setValue($repository_value)->setLimit(1))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setName('viewPolicy')->setPolicyObject($diff_object)->setPolicies($policies)->setCapability(PhabricatorPolicyCapability::CAN_VIEW))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($button));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($header)->setValidationException($validation_exception)->setForm($form)->setFormErrors($errors);
     if ($info_view) {
         $form_box->setInfoView($info_view);
     }
     $crumbs = $this->buildApplicationCrumbs();
     if ($revision) {
         $crumbs->addTextCrumb($revision->getMonogram(), '/' . $revision->getMonogram());
     }
     $crumbs->addTextCrumb($title);
     return $this->buildApplicationPage(array($crumbs, $form_box), array('title' => $title));
 }
 protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender)
 {
     $attachments = $mail->getAttachments();
     $files = array();
     $errors = array();
     if ($attachments) {
         $files = id(new PhabricatorFileQuery())->setViewer($sender)->withPHIDs($attachments)->execute();
         foreach ($files as $index => $file) {
             if ($file->getMimeType() != 'text/plain') {
                 $errors[] = pht('Could not parse file %s; only files with mimetype text/plain ' . 'can be parsed via email.', $file->getName());
                 unset($files[$index]);
             }
         }
     }
     $diffs = array();
     foreach ($files as $file) {
         $call = new ConduitCall('differential.createrawdiff', array('diff' => $file->loadFileData()));
         $call->setUser($sender);
         try {
             $result = $call->execute();
             $diffs[$file->getName()] = $result['uri'];
         } catch (Exception $e) {
             $errors[] = pht('Could not parse attachment %s; only attachments (and mail bodies) ' . 'generated via "diff" commands can be parsed.', $file->getName());
         }
     }
     $body = $mail->getCleanTextBody();
     if ($body) {
         $call = new ConduitCall('differential.createrawdiff', array('diff' => $body));
         $call->setUser($sender);
         try {
             $result = $call->execute();
             $diffs[pht('Mail Body')] = $result['uri'];
         } catch (Exception $e) {
             $errors[] = pht('Could not parse mail body; only mail bodies (and attachments) ' . 'generated via "diff" commands can be parsed.');
         }
     }
     $subject_prefix = PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix');
     if (count($diffs)) {
         $subject = pht('You successfully created %d diff(s).', count($diffs));
     } else {
         $subject = pht('Diff creation failed; see body for %s error(s).', new PhutilNumber(count($errors)));
     }
     $body = new PhabricatorMetaMTAMailBody();
     $body->addRawSection($subject);
     if (count($diffs)) {
         $text_body = '';
         $html_body = array();
         $body_label = pht('%s DIFF LINK(S)', new PhutilNumber(count($diffs)));
         foreach ($diffs as $filename => $diff_uri) {
             $text_body .= $filename . ': ' . $diff_uri . "\n";
             $html_body[] = phutil_tag('a', array('href' => $diff_uri), $filename);
             $html_body[] = phutil_tag('br');
         }
         $body->addTextSection($body_label, $text_body);
         $body->addHTMLSection($body_label, $html_body);
     }
     if (count($errors)) {
         $body_section = new PhabricatorMetaMTAMailSection();
         $body_label = pht('%s ERROR(S)', new PhutilNumber(count($errors)));
         foreach ($errors as $error) {
             $body_section->addFragment($error);
         }
         $body->addTextSection($body_label, $body_section);
     }
     id(new PhabricatorMetaMTAMail())->addTos(array($sender->getPHID()))->setSubject($subject)->setSubjectPrefix($subject_prefix)->setFrom($sender->getPHID())->setBody($body->render())->saveAndSend();
 }
 protected final function updateCommitData($author, $message, $committer = null)
 {
     $commit = $this->commit;
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     if (!$data) {
         $data = new PhabricatorRepositoryCommitData();
     }
     $data->setCommitID($commit->getID());
     $data->setAuthorName($author);
     $data->setCommitMessage($message);
     if ($committer) {
         $data->setCommitDetail('committer', $committer);
     }
     $repository = $this->repository;
     $detail_parser = $repository->getDetail('detail-parser', 'PhabricatorRepositoryDefaultCommitMessageDetailParser');
     if ($detail_parser) {
         $parser_obj = newv($detail_parser, array($commit, $data));
         $parser_obj->parseCommitDetails();
     }
     $author_phid = $this->lookupUser($commit, $data->getAuthorName(), $data->getCommitDetail('authorPHID'));
     $data->setCommitDetail('authorPHID', $author_phid);
     $committer_phid = $this->lookupUser($commit, $data->getCommitDetail('committer'), $data->getCommitDetail('committerPHID'));
     $data->setCommitDetail('committerPHID', $committer_phid);
     if ($author_phid != $commit->getAuthorPHID()) {
         $commit->setAuthorPHID($author_phid);
         $commit->save();
     }
     $conn_w = id(new DifferentialRevision())->establishConnection('w');
     // NOTE: The `differential_commit` table has a unique ID on `commitPHID`,
     // preventing more than one revision from being associated with a commit.
     // Generally this is good and desirable, but with the advent of hash
     // tracking we may end up in a situation where we match several different
     // revisions. We just kind of ignore this and pick one, we might want to
     // revisit this and do something differently. (If we match several revisions
     // someone probably did something very silly, though.)
     $revision = null;
     $should_autoclose = $repository->shouldAutocloseCommit($commit, $data);
     $revision_id = $data->getCommitDetail('differential.revisionID');
     if (!$revision_id) {
         $hashes = $this->getCommitHashes($this->repository, $this->commit);
         if ($hashes) {
             $query = new DifferentialRevisionQuery();
             $query->withCommitHashes($hashes);
             $revisions = $query->execute();
             if (!empty($revisions)) {
                 $revision = $this->identifyBestRevision($revisions);
                 $revision_id = $revision->getID();
             }
         }
     }
     if ($revision_id) {
         $lock = PhabricatorGlobalLock::newLock(get_class($this) . ':' . $revision_id);
         $lock->lock(5 * 60);
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             $revision->loadRelationships();
             queryfx($conn_w, 'INSERT IGNORE INTO %T (revisionID, commitPHID) VALUES (%d, %s)', DifferentialRevision::TABLE_COMMIT, $revision->getID(), $commit->getPHID());
             $status_closed = ArcanistDifferentialRevisionStatus::CLOSED;
             $should_close = $revision->getStatus() != $status_closed && $should_autoclose;
             if ($should_close) {
                 $actor_phid = nonempty($committer_phid, $author_phid, $revision->getAuthorPHID());
                 $diff = $this->attachToRevision($revision, $actor_phid);
                 $revision->setDateCommitted($commit->getEpoch());
                 $editor = new DifferentialCommentEditor($revision, $actor_phid, DifferentialAction::ACTION_CLOSE);
                 $editor->setIsDaemonWorkflow(true);
                 $vs_diff = $this->loadChangedByCommit($diff);
                 if ($vs_diff) {
                     $data->setCommitDetail('vsDiff', $vs_diff->getID());
                     $changed_by_commit = PhabricatorEnv::getProductionURI('/D' . $revision->getID() . '?vs=' . $vs_diff->getID() . '&id=' . $diff->getID() . '#toc');
                     $editor->setChangedByCommit($changed_by_commit);
                 }
                 $commit_name = $repository->formatCommitName($commit->getCommitIdentifier());
                 $committer_name = $this->loadUserName($committer_phid, $data->getCommitDetail('committer'));
                 $author_name = $this->loadUserName($author_phid, $data->getAuthorName());
                 $info = array();
                 $info[] = "authored by {$author_name}";
                 if ($committer_name && $committer_name != $author_name) {
                     $info[] = "committed by {$committer_name}";
                 }
                 $info = implode(', ', $info);
                 $editor->setMessage("Closed by commit {$commit_name} ({$info}).")->save();
             }
         }
         $lock->unlock();
     }
     if ($should_autoclose && $author_phid) {
         $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $author_phid);
         $call = new ConduitCall('differential.parsecommitmessage', array('corpus' => $message, 'partial' => true));
         $call->setUser($user);
         $result = $call->execute();
         $field_values = $result['fields'];
         $fields = DifferentialFieldSelector::newSelector()->getFieldSpecifications();
         foreach ($fields as $key => $field) {
             if (!$field->shouldAppearOnCommitMessage()) {
                 continue;
             }
             $field->setUser($user);
             $value = idx($field_values, $field->getCommitMessageKey());
             $field->setValueFromParsedCommitMessage($value);
             if ($revision) {
                 $field->setRevision($revision);
             }
             $field->didParseCommit($repository, $commit, $data);
         }
     }
     $data->save();
 }