protected function execute(ConduitAPIRequest $request)
 {
     $application = id(new PhabricatorApplicationQuery())->setViewer($request->getUser())->withClasses(array('PhabricatorDiffusionApplication'))->executeOne();
     PhabricatorPolicyFilter::requireCapability($request->getUser(), $application, DiffusionCreateRepositoriesCapability::CAPABILITY);
     // TODO: This has some duplication with (and lacks some of the validation
     // of) the web workflow; refactor things so they can share more code as this
     // stabilizes. Specifically, this should move to transactions since they
     // work properly now.
     $repository = PhabricatorRepository::initializeNewRepository($request->getUser());
     $repository->setName($request->getValue('name'));
     $callsign = $request->getValue('callsign');
     if (!preg_match('/^[A-Z]+\\z/', $callsign)) {
         throw new ConduitException('ERR-BAD-CALLSIGN');
     }
     $repository->setCallsign($callsign);
     $local_path = PhabricatorEnv::getEnvConfig('repository.default-local-path');
     $local_path = rtrim($local_path, '/');
     $local_path = $local_path . '/' . $callsign . '/';
     $vcs = $request->getValue('vcs');
     $map = array('git' => PhabricatorRepositoryType::REPOSITORY_TYPE_GIT, 'hg' => PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL, 'svn' => PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
     if (empty($map[$vcs])) {
         throw new ConduitException('ERR-UNKNOWN-REPOSITORY-VCS');
     }
     $repository->setVersionControlSystem($map[$vcs]);
     $repository->setCredentialPHID($request->getValue('credentialPHID'));
     $remote_uri = $request->getValue('uri');
     PhabricatorRepository::assertValidRemoteURI($remote_uri);
     $details = array('encoding' => $request->getValue('encoding'), 'description' => $request->getValue('description'), 'tracking-enabled' => (bool) $request->getValue('tracking', true), 'remote-uri' => $remote_uri, 'local-path' => $local_path, 'branch-filter' => array_fill_keys($request->getValue('branchFilter', array()), true), 'close-commits-filter' => array_fill_keys($request->getValue('closeCommitsFilter', array()), true), 'pull-frequency' => $request->getValue('pullFrequency'), 'default-branch' => $request->getValue('defaultBranch'), 'herald-disabled' => !$request->getValue('heraldEnabled', true), 'svn-subpath' => $request->getValue('svnSubpath'), 'disable-autoclose' => !$request->getValue('autocloseEnabled', true));
     foreach ($details as $key => $value) {
         $repository->setDetail($key, $value);
     }
     try {
         $repository->save();
     } catch (AphrontDuplicateKeyQueryException $ex) {
         throw new ConduitException('ERR-DUPLICATE');
     }
     return $repository->toDictionary();
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $drequest = $this->diffusionRequest;
     $repository = $drequest->getRepository();
     if ($this->id) {
         $mirror = id(new PhabricatorRepositoryMirrorQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne();
         if (!$mirror) {
             return new Aphront404Response();
         }
         $is_new = false;
     } else {
         $mirror = PhabricatorRepositoryMirror::initializeNewMirror($viewer)->setRepositoryPHID($repository->getPHID())->attachRepository($repository);
         $is_new = true;
     }
     $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors');
     $v_remote = $mirror->getRemoteURI();
     $e_remote = true;
     $v_credentials = $mirror->getCredentialPHID();
     $e_credentials = null;
     $credentials = id(new PassphraseCredentialQuery())->setViewer($viewer)->withIsDestroyed(false)->execute();
     $errors = array();
     if ($request->isFormPost()) {
         $v_remote = $request->getStr('remoteURI');
         if (strlen($v_remote)) {
             try {
                 PhabricatorRepository::assertValidRemoteURI($v_remote);
                 $e_remote = null;
             } catch (Exception $ex) {
                 $e_remote = pht('Invalid');
                 $errors[] = $ex->getMessage();
             }
         } else {
             $e_remote = pht('Required');
             $errors[] = pht('You must provide a remote URI.');
         }
         $v_credentials = $request->getStr('credential');
         if ($v_credentials) {
             $phids = mpull($credentials, null, 'getPHID');
             if (empty($phids[$v_credentials])) {
                 $e_credentials = pht('Invalid');
                 $errors[] = pht('You do not have permission to use those credentials.');
             }
         }
         if (!$errors) {
             $mirror->setRemoteURI($v_remote)->setCredentialPHID($v_credentials)->save();
             return id(new AphrontReloadResponse())->setURI($edit_uri);
         }
     }
     $form_errors = null;
     if ($errors) {
         $form_errors = id(new AphrontErrorView())->setErrors($errors);
     }
     if ($is_new) {
         $title = pht('Create Mirror');
         $submit = pht('Create Mirror');
     } else {
         $title = pht('Edit Mirror');
         $submit = pht('Save Changes');
     }
     $form = id(new PHUIFormLayoutView())->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Remote URI'))->setName('remoteURI')->setValue($v_remote)->setError($e_remote))->appendChild(id(new PassphraseCredentialControl())->setLabel(pht('Credentials'))->setName('credential')->setAllowNull(true)->setValue($v_credentials)->setError($e_credentials)->setOptions($credentials));
     $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle($title)->setWidth(AphrontDialogView::WIDTH_FORM)->appendChild($form_errors)->appendChild($form)->addSubmitButton($submit)->addCancelButton($edit_uri);
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 public function validateRemoteURIPage(PHUIFormPageView $page)
 {
     $c_remote = $page->getControl('remoteURI');
     $v_remote = $c_remote->getValue();
     if (!strlen($v_remote)) {
         $c_remote->setError(pht('Required'));
         $page->addPageError(pht('You must specify a URI.'));
     } else {
         try {
             PhabricatorRepository::assertValidRemoteURI($v_remote);
         } catch (Exception $ex) {
             $c_remote->setError(pht('Invalid'));
             $page->addPageError($ex->getMessage());
         }
     }
     return $c_remote->isValid();
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
         case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
             foreach ($xactions as $xaction) {
                 foreach ($xaction->getNewValue() as $pattern) {
                     // Check for invalid regular expressions.
                     $regexp = PhabricatorRepository::extractBranchRegexp($pattern);
                     if ($regexp !== null) {
                         $ok = @preg_match($regexp, '');
                         if ($ok === false) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Expression "%s" is not a valid regular expression. Note ' . 'that you must include delimiters.', $regexp), $xaction);
                             $errors[] = $error;
                             continue;
                         }
                     }
                     // Check for formatting mistakes like `regex(...)` instead of
                     // `regexp(...)`.
                     $matches = null;
                     if (preg_match('/^([^(]+)\\(.*\\)\\z/', $pattern, $matches)) {
                         switch ($matches[1]) {
                             case 'regexp':
                                 break;
                             default:
                                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Matching function "%s(...)" is not recognized. Valid ' . 'functions are: regexp(...).', $matches[1]), $xaction);
                                 $errors[] = $error;
                                 break;
                         }
                     }
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
             foreach ($xactions as $xaction) {
                 $new_uri = $xaction->getNewValue();
                 try {
                     PhabricatorRepository::assertValidRemoteURI($new_uri);
                 } catch (Exception $ex) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
             $ok = PassphraseCredentialControl::validateTransactions($this->getActor(), $xactions);
             if (!$ok) {
                 foreach ($xactions as $xaction) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The selected credential does not exist, or you do not have ' . 'permission to use it.'), $xaction);
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_AUTOMATION_BLUEPRINTS:
             foreach ($xactions as $xaction) {
                 $old = nonempty($xaction->getOldValue(), array());
                 $new = nonempty($xaction->getNewValue(), array());
                 $add = array_diff($new, $old);
                 $invalid = PhabricatorObjectQuery::loadInvalidPHIDsForViewer($this->getActor(), $add);
                 if ($invalid) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Some of the selected automation blueprints are invalid ' . 'or restricted: %s.', implode(', ', $invalid)), $xaction);
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_SLUG:
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 $new = $xaction->getNewValue();
                 if (!strlen($new)) {
                     continue;
                 }
                 if ($new === $old) {
                     continue;
                 }
                 try {
                     PhabricatorRepository::asssertValidRepositorySlug($new);
                 } catch (Exception $ex) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                     continue;
                 }
                 $other = id(new PhabricatorRepositoryQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs(array($new))->executeOne();
                 if ($other && $other->getID() !== $object->getID()) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('The selected repository short name is already in use by ' . 'another repository. Choose a unique short name.'), $xaction);
                     continue;
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
         case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
             foreach ($xactions as $xaction) {
                 foreach ($xaction->getNewValue() as $pattern) {
                     // Check for invalid regular expressions.
                     $regexp = PhabricatorRepository::extractBranchRegexp($pattern);
                     if ($regexp !== null) {
                         $ok = @preg_match($regexp, '');
                         if ($ok === false) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Expression "%s" is not a valid regular expression. Note ' . 'that you must include delimiters.', $regexp), $xaction);
                             $errors[] = $error;
                             continue;
                         }
                     }
                     // Check for formatting mistakes like `regex(...)` instead of
                     // `regexp(...)`.
                     $matches = null;
                     if (preg_match('/^([^(]+)\\(.*\\)\\z/', $pattern, $matches)) {
                         switch ($matches[1]) {
                             case 'regexp':
                                 break;
                             default:
                                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Matching function "%s(...)" is not recognized. Valid ' . 'functions are: regexp(...).', $matches[1]), $xaction);
                                 $errors[] = $error;
                                 break;
                         }
                     }
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
             foreach ($xactions as $xaction) {
                 $new_uri = $xaction->getNewValue();
                 try {
                     PhabricatorRepository::assertValidRemoteURI($new_uri);
                 } catch (Exception $ex) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                 }
             }
             break;
         case PhabricatorRepositoryTransaction::TYPE_CREDENTIAL:
             $ok = PassphraseCredentialControl::validateTransactions($this->getActor(), $xactions);
             if (!$ok) {
                 foreach ($xactions as $xaction) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The selected credential does not exist, or you do not have ' . 'permission to use it.'), $xaction);
                 }
             }
             break;
     }
     return $errors;
 }
Пример #6
0
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorRepositoryURITransaction::TYPE_REPOSITORY:
             // Save this, since we need it to validate TYPE_IO transactions.
             $this->repositoryPHID = $object->getRepositoryPHID();
             $missing = $this->validateIsEmptyTextField($object->getRepositoryPHID(), $xactions);
             if ($missing) {
                 // NOTE: This isn't being marked as a missing field error because
                 // it's a fundamental, required property of the URI.
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('When creating a repository URI, you must specify which ' . 'repository the URI will belong to.'), nonempty(last($xactions), null));
                 break;
             }
             $viewer = $this->getActor();
             foreach ($xactions as $xaction) {
                 $repository_phid = $xaction->getNewValue();
                 // If this isn't changing anything, let it through as-is.
                 if ($repository_phid == $object->getRepositoryPHID()) {
                     continue;
                 }
                 if (!$this->getIsNewObject()) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The repository a URI is associated with is immutable, and ' . 'can not be changed after the URI is created.'), $xaction);
                     continue;
                 }
                 $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs(array($repository_phid))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
                 if (!$repository) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('To create a URI for a repository ("%s"), it must exist and ' . 'you must have permission to edit it.', $repository_phid), $xaction);
                     continue;
                 }
                 $this->repository = $repository;
                 $this->repositoryPHID = $repository_phid;
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL:
             $viewer = $this->getActor();
             foreach ($xactions as $xaction) {
                 $credential_phid = $xaction->getNewValue();
                 if ($credential_phid == $object->getCredentialPHID()) {
                     continue;
                 }
                 // Anyone who can edit a URI can remove the credential.
                 if ($credential_phid === null) {
                     continue;
                 }
                 $credential = id(new PassphraseCredentialQuery())->setViewer($viewer)->withPHIDs(array($credential_phid))->executeOne();
                 if (!$credential) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can only associate a credential ("%s") with a repository ' . 'URI if it exists and you have permission to see it.', $credential_phid), $xaction);
                     continue;
                 }
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_URI:
             $missing = $this->validateIsEmptyTextField($object->getURI(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('A repository URI must have a nonempty URI.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
                 break;
             }
             foreach ($xactions as $xaction) {
                 $new_uri = $xaction->getNewValue();
                 if ($new_uri == $object->getURI()) {
                     continue;
                 }
                 try {
                     PhabricatorRepository::assertValidRemoteURI($new_uri);
                 } catch (Exception $ex) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                     continue;
                 }
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_IO:
             $available = $object->getAvailableIOTypeOptions();
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if (empty($available[$new])) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Value "%s" is not a valid display setting for this URI. ' . 'Available types for this URI are: %s.', implode(', ', array_keys($available))), $xaction);
                     continue;
                 }
                 // If we are setting this URI to use "Observe", we must have no
                 // other "Observe" URIs and must also have no "Read/Write" URIs.
                 // If we are setting this URI to "Read/Write", we must have no
                 // other "Observe" URIs. It's OK to have other "Read/Write" URIs.
                 $no_observers = false;
                 $no_readwrite = false;
                 switch ($new) {
                     case PhabricatorRepositoryURI::IO_OBSERVE:
                         $no_readwrite = true;
                         $no_observers = true;
                         break;
                     case PhabricatorRepositoryURI::IO_READWRITE:
                         $no_observers = true;
                         break;
                 }
                 if ($no_observers || $no_readwrite) {
                     $repository = id(new PhabricatorRepositoryQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs(array($this->repositoryPHID))->needURIs(true)->executeOne();
                     $uris = $repository->getURIs();
                     $observe_conflict = null;
                     $readwrite_conflict = null;
                     foreach ($uris as $uri) {
                         // If this is the URI being edited, it can not conflict with
                         // itself.
                         if ($uri->getID() == $object->getID()) {
                             continue;
                         }
                         $io_type = $uri->getIoType();
                         if ($io_type == PhabricatorRepositoryURI::IO_READWRITE) {
                             if ($no_readwrite) {
                                 $readwite_conflict = $uri;
                                 break;
                             }
                         }
                         if ($io_type == PhabricatorRepositoryURI::IO_OBSERVE) {
                             if ($no_observers) {
                                 $observe_conflict = $uri;
                                 break;
                             }
                         }
                     }
                     if ($observe_conflict) {
                         if ($new == PhabricatorRepositoryURI::IO_OBSERVE) {
                             $message = pht('You can not set this URI to use Observe IO because ' . 'another URI for this repository is already configured ' . 'in Observe IO mode. A repository can not observe two ' . 'different remotes simultaneously. Turn off IO for the ' . 'other URI first.');
                         } else {
                             $message = pht('You can not set this URI to use Read/Write IO because ' . 'another URI for this repository is already configured ' . 'in Observe IO mode. An observed repository can not be ' . 'made writable. Turn off IO for the other URI first.');
                         }
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $message, $xaction);
                         continue;
                     }
                     if ($readwrite_conflict) {
                         $message = pht('You can not set this URI to use Observe IO because ' . 'another URI for this repository is already configured ' . 'in Read/Write IO mode. A repository can not simultaneously ' . 'be writable and observe a remote. Turn off IO for the ' . 'other URI first.');
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $message, $xaction);
                         continue;
                     }
                 }
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_DISPLAY:
             $available = $object->getAvailableDisplayTypeOptions();
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if (empty($available[$new])) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Value "%s" is not a valid display setting for this URI. ' . 'Available types for this URI are: %s.', implode(', ', array_keys($available))));
                 }
             }
             break;
         case PhabricatorRepositoryURITransaction::TYPE_DISABLE:
             $old = $object->getIsDisabled();
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if ($old == $new) {
                     continue;
                 }
                 if (!$object->isBuiltin()) {
                     continue;
                 }
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not manually disable builtin URIs.'));
             }
             break;
     }
     return $errors;
 }