mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-22 13:30:55 +01:00
Build an early multi-step repository create form
Summary: Ref T2231. Ref T2232. This form doesn't do anything yet and there are no link sto it, but it lets you enter all the data to create a repository in a relatively simple, straightforward way. Test Plan: {F49740} {F49741} {F49742} {F49743} Reviewers: chad, btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2231, T2232 Differential Revision: https://secure.phabricator.com/D6430
This commit is contained in:
parent
b92acf0e5a
commit
a0084bbb0d
7 changed files with 698 additions and 34 deletions
|
@ -490,6 +490,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRemarkupRule.php',
|
||||
'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php',
|
||||
'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php',
|
||||
'DiffusionRepositoryCreateController' => 'applications/diffusion/controller/DiffusionRepositoryCreateController.php',
|
||||
'DiffusionRepositoryEditBasicController' => 'applications/diffusion/controller/DiffusionRepositoryEditBasicController.php',
|
||||
'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php',
|
||||
'DiffusionRepositoryEditEncodingController' => 'applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php',
|
||||
|
@ -2423,6 +2424,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionRawDiffQuery' => 'DiffusionQuery',
|
||||
'DiffusionRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
||||
'DiffusionRepositoryController' => 'DiffusionController',
|
||||
'DiffusionRepositoryCreateController' => 'DiffusionController',
|
||||
'DiffusionRepositoryEditBasicController' => 'DiffusionController',
|
||||
'DiffusionRepositoryEditController' => 'DiffusionController',
|
||||
'DiffusionRepositoryEditEncodingController' => 'DiffusionController',
|
||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication {
|
|||
=> 'DiffusionCommitController',
|
||||
'/diffusion/' => array(
|
||||
'' => 'DiffusionHomeController',
|
||||
'create/' => 'DiffusionRepositoryCreateController',
|
||||
'(?P<callsign>[A-Z]+)/' => array(
|
||||
'' => 'DiffusionRepositoryController',
|
||||
|
||||
|
|
|
@ -0,0 +1,545 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionRepositoryCreateController extends DiffusionController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$form = id(new PHUIPagedFormView())
|
||||
->setUser($viewer)
|
||||
->addPage('vcs', $this->buildVCSPage())
|
||||
->addPage('name', $this->buildNamePage())
|
||||
->addPage('auth', $this->buildAuthPage())
|
||||
->addPage('done', $this->buildDonePage());
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$form->readFromRequest($request);
|
||||
if ($form->isComplete()) {
|
||||
// TODO: This exception is heartwarming but should probably take more
|
||||
// substantive actions.
|
||||
throw new Exception("GOOD JOB AT FORM");
|
||||
}
|
||||
} else {
|
||||
$form->readFromObject(null);
|
||||
}
|
||||
|
||||
$title = pht('Import Repository');
|
||||
|
||||
$crumbs = $this->buildCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName($title));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$form,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
'dust' => true,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: VCS Type )----------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildVCSPage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Repository Type'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setValidateFormPageCallback(array($this, 'validateVCSPage'))
|
||||
->addControl(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('vcs')
|
||||
->setLabel(pht('Type'))
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT,
|
||||
pht('Git'),
|
||||
pht(
|
||||
'Import a Git repository (for example, a repository hosted '.
|
||||
'on GitHub).'))
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL,
|
||||
pht('Mercurial'),
|
||||
pht(
|
||||
'Import a Mercurial repository (for example, a repository '.
|
||||
'hosted on Bitbucket).'))
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN,
|
||||
pht('Subversion'),
|
||||
pht('Import a Subversion repository.'))
|
||||
->addButton(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_PERFORCE,
|
||||
pht('Perforce'),
|
||||
pht(
|
||||
'Perforce is not directly supported, but you can import '.
|
||||
'a Perforce repository as a Git repository using %s.',
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' =>
|
||||
'http://www.perforce.com/product/components/git-fusion',
|
||||
'target' => '_blank',
|
||||
),
|
||||
pht('Perforce Git Fusion'))),
|
||||
'disabled',
|
||||
$disabled = true));
|
||||
}
|
||||
|
||||
public function validateVCSPage(PHUIFormPageView $page) {
|
||||
$valid = array(
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => true,
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => true,
|
||||
PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => true,
|
||||
);
|
||||
|
||||
$c_vcs = $page->getControl('vcs');
|
||||
$v_vcs = $c_vcs->getValue();
|
||||
if (!$v_vcs) {
|
||||
$c_vcs->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must select a version control system.'));
|
||||
} else if (empty($valid[$v_vcs])) {
|
||||
$c_vcs->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht('You must select a valid version control system.'));
|
||||
}
|
||||
|
||||
return $c_vcs->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Name and Callsign )-------------------------------------------- */
|
||||
|
||||
|
||||
private function buildNamePage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setPageName(pht('Repository Name and Location'))
|
||||
->setValidateFormPageCallback(array($this, 'validateNamePage'))
|
||||
->setAdjustFormPageCallback(array($this, 'adjustNamePage'))
|
||||
->addRemarkupInstructions(
|
||||
pht(
|
||||
'**Choose a human-readable name for this repository**, like '.
|
||||
'"CompanyName Mobile App" or "CompanyName Backend Server". You '.
|
||||
'can change this later.'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setCaption(pht('Human-readable repository name.')))
|
||||
->addRemarkupInstructions(
|
||||
pht(
|
||||
'**Choose a "Callsign" for the repository.** This is a short, '.
|
||||
'unique string which identifies commits elsewhere in Phabricator. '.
|
||||
'For example, you might use `M` for your mobile app repository '.
|
||||
'and `B` for your backend repository.'.
|
||||
"\n\n".
|
||||
'**Callsigns must be UPPERCASE**, and can not be edited after the '.
|
||||
'repository is created. Generally, you should choose short '.
|
||||
'callsigns.'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('callsign')
|
||||
->setLabel(pht('Callsign'))
|
||||
->setCaption(pht('Short UPPERCASE identifier.')))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('remoteURI'));
|
||||
}
|
||||
|
||||
public function adjustNamePage(PHUIFormPageView $page) {
|
||||
$form = $page->getForm();
|
||||
|
||||
$is_git = false;
|
||||
$is_svn = false;
|
||||
$is_mercurial = false;
|
||||
|
||||
switch ($form->getPage('vcs')->getControl('vcs')->getValue()) {
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
||||
$is_git = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
||||
$is_svn = true;
|
||||
break;
|
||||
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
||||
$is_mercurial = true;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unsupported VCS!");
|
||||
}
|
||||
|
||||
$has_local = ($is_git || $is_mercurial);
|
||||
if ($is_git) {
|
||||
$uri_label = pht('Remote URI');
|
||||
$instructions = pht(
|
||||
'Enter the URI to clone this Git repository from. It should usually '.
|
||||
'look like one of these examples:'.
|
||||
"\n\n".
|
||||
"| Example Git Remote URIs |\n".
|
||||
"| ----------------------- |\n".
|
||||
"| `git@github.com:example/example.git` |\n".
|
||||
"| `ssh://user@host.com/git/example.git` |\n".
|
||||
"| `file:///local/path/to/repo` |\n".
|
||||
"| `https://example.com/repository.git` |\n");
|
||||
} else if ($is_mercurial) {
|
||||
$uri_label = pht('Remote URI');
|
||||
$instructions = pht(
|
||||
'Enter the URI to clone this Mercurial repository from. It should '.
|
||||
'usually look like one of these examples:'.
|
||||
"\n\n".
|
||||
"| Example Mercurial Remote URIs |\n".
|
||||
"| ----------------------- |\n".
|
||||
"| `ssh://hg@bitbucket.org/example/repository` |\n".
|
||||
"| `file:///local/path/to/repo` |\n");
|
||||
} else if ($is_svn) {
|
||||
$uri_label = pht('Repository Root');
|
||||
$instructions = pht(
|
||||
'Enter the **Repository Root** for this Subversion repository. '.
|
||||
'You can figure this out by running `svn info` in a working copy '.
|
||||
'and looking at the value in the `Repository Root` field. It '.
|
||||
'should be a URI and will usually look like these:'.
|
||||
"\n\n".
|
||||
"| Example Subversion Repository Root URIs |\n".
|
||||
"| ------------------------------ |\n".
|
||||
"| `http://svn.example.org/svnroot/` |\n".
|
||||
"| `svn+ssh://svn.example.com/svnroot/` |\n".
|
||||
"| `svn://svn.example.net/svnroot/` |\n".
|
||||
"| `file:///local/path/to/svnroot/` |\n".
|
||||
"\n\n".
|
||||
"Make sure you specify the root of the repository, not a ".
|
||||
"subdirectory.");
|
||||
} else {
|
||||
throw new Exception("Unsupported VCS!");
|
||||
}
|
||||
|
||||
$page->addRemarkupInstructions($instructions, 'remoteURI');
|
||||
$page->getControl('remoteURI')->setLabel($uri_label);
|
||||
}
|
||||
|
||||
public function validateNamePage(PHUIFormPageView $page) {
|
||||
$c_name = $page->getControl('name');
|
||||
$v_name = $c_name->getValue();
|
||||
if (!strlen($v_name)) {
|
||||
$c_name->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must choose a name for this repository.'));
|
||||
}
|
||||
|
||||
$c_call = $page->getControl('callsign');
|
||||
$v_call = $c_call->getValue();
|
||||
if (!strlen($v_call)) {
|
||||
$c_call->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must choose a callsign for this repository.'));
|
||||
} else if (!preg_match('/^[A-Z]+$/', $v_call)) {
|
||||
$c_call->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht('The callsign must contain only UPPERCASE letters.'));
|
||||
} else {
|
||||
$exists = false;
|
||||
try {
|
||||
$repo = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($this->getRequest()->getUser())
|
||||
->withCallsigns(array($v_call))
|
||||
->executeOne();
|
||||
$exists = (bool)$repo;
|
||||
} catch (PhabricatorPolicyException $ex) {
|
||||
$exists = true;
|
||||
}
|
||||
if ($exists) {
|
||||
$c_call->setError(pht('Not Unique'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'Another repository already uses that callsign. You must choose '.
|
||||
'a unique callsign.'));
|
||||
}
|
||||
}
|
||||
|
||||
$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 {
|
||||
$proto = $this->getRemoteURIProtocol($v_remote);
|
||||
|
||||
if ($proto === 'file') {
|
||||
if (!preg_match('@^file:///@', $v_remote)) {
|
||||
$c_remote->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
"URIs using the 'file://' protocol should have three slashes ".
|
||||
"(e.g., 'file:///absolute/path/to/file'). You only have two. ".
|
||||
"Add another one."));
|
||||
}
|
||||
}
|
||||
|
||||
switch ($proto) {
|
||||
case 'ssh':
|
||||
case 'http':
|
||||
case 'https':
|
||||
case 'file':
|
||||
case 'git':
|
||||
case 'svn':
|
||||
case 'svn+ssh':
|
||||
break;
|
||||
default:
|
||||
$c_remote->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
"The URI protocol is unrecognized. It should begin ".
|
||||
"'ssh://', 'http://', 'https://', 'file://', 'git://', ".
|
||||
"'svn://', 'svn+ssh://', or be in the form ".
|
||||
"'git@domain.com:path'."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $c_name->isValid() &&
|
||||
$c_call->isValid() &&
|
||||
$c_remote->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Page: Authentication )----------------------------------------------- */
|
||||
|
||||
|
||||
public function buildAuthPage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Authentication'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setAdjustFormPageCallback(array($this, 'adjustAuthPage'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('ssh-login')
|
||||
->setLabel('SSH User'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setName('ssh-key')
|
||||
->setLabel('SSH Private Key')
|
||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT)
|
||||
->setCaption(
|
||||
hsprintf('Specify the entire private key, <em>or</em>...')))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('ssh-keyfile')
|
||||
->setLabel('SSH Private Key Path')
|
||||
->setCaption(
|
||||
'...specify a path on disk where the daemon should '.
|
||||
'look for a private key.'))
|
||||
->addControl(
|
||||
id(new AphrontFormTextControl())
|
||||
->setName('http-login')
|
||||
->setLabel('Username'))
|
||||
->addControl(
|
||||
id(new AphrontFormPasswordControl())
|
||||
->setName('http-pass')
|
||||
->setLabel('Password'));
|
||||
}
|
||||
|
||||
|
||||
public function adjustAuthPage($page) {
|
||||
$form = $page->getForm();
|
||||
$remote_uri = $form->getPage('name')->getControl('remoteURI')->getValue();
|
||||
$vcs = $form->getPage('vcs')->getControl('vcs')->getValue();
|
||||
$proto = $this->getRemoteURIProtocol($remote_uri);
|
||||
$remote_user = $this->getRemoteURIUser($remote_uri);
|
||||
|
||||
$page->getControl('ssh-login')->setHidden(true);
|
||||
$page->getControl('ssh-key')->setHidden(true);
|
||||
$page->getControl('ssh-keyfile')->setHidden(true);
|
||||
$page->getControl('http-login')->setHidden(true);
|
||||
$page->getControl('http-pass')->setHidden(true);
|
||||
|
||||
if ($this->isSSHProtocol($proto)) {
|
||||
$page->getControl('ssh-login')->setHidden(false);
|
||||
$page->getControl('ssh-key')->setHidden(false);
|
||||
$page->getControl('ssh-keyfile')->setHidden(false);
|
||||
|
||||
$c_login = $page->getControl('ssh-login');
|
||||
if (!strlen($c_login->getValue())) {
|
||||
$c_login->setValue($remote_user);
|
||||
}
|
||||
|
||||
$page->addRemarkupInstructions(
|
||||
pht(
|
||||
'Enter the username and private key to use to connect to the '.
|
||||
'the repository hosted at:'.
|
||||
"\n\n".
|
||||
" lang=text\n".
|
||||
" %s".
|
||||
"\n\n".
|
||||
'You can either copy/paste the entire private key, or put it '.
|
||||
'somewhere on disk and provide the path to it.',
|
||||
$remote_uri),
|
||||
'ssh-login');
|
||||
|
||||
} else if ($this->isUsernamePasswordProtocol($proto)) {
|
||||
$page->getControl('http-login')->setHidden(false);
|
||||
$page->getControl('http-pass')->setHidden(false);
|
||||
|
||||
$page->addRemarkupInstructions(
|
||||
pht(
|
||||
'Enter the a username and pasword used to connect to the '.
|
||||
'repository hosted at:'.
|
||||
"\n\n".
|
||||
" lang=text\n".
|
||||
" %s".
|
||||
"\n\n".
|
||||
"If this repository does not require a username or password, ".
|
||||
"you can leave these fields blank.",
|
||||
$remote_uri),
|
||||
'http-login');
|
||||
} else if ($proto == 'file') {
|
||||
$page->addRemarkupInstructions(
|
||||
pht(
|
||||
'You do not need to configure any authentication options for '.
|
||||
'repositories accessed over the `file://` protocol. Continue '.
|
||||
'to the next step.'),
|
||||
'ssh-login');
|
||||
} else {
|
||||
throw new Exception("Unknown URI protocol!");
|
||||
}
|
||||
}
|
||||
|
||||
public function validateAuthPage(PHUIFormPageView $page) {
|
||||
$form = $page->getForm();
|
||||
$remote_uri = $form->getPage('remote')->getControl('remoteURI')->getValue();
|
||||
$proto = $this->getRemoteURIProtocol($remote_uri);
|
||||
|
||||
if ($this->isSSHProtocol($proto)) {
|
||||
$c_user = $page->getControl('ssh-login');
|
||||
$c_key = $page->getControl('ssh-key');
|
||||
$c_file = $page->getControl('ssh-keyfile');
|
||||
|
||||
$v_user = $c_user->getValue();
|
||||
$v_key = $c_key->getValue();
|
||||
$v_file = $c_file->getValue();
|
||||
|
||||
if (!strlen($v_user)) {
|
||||
$c_user->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('You must provide an SSH login username to connect over SSH.'));
|
||||
}
|
||||
|
||||
if (!strlen($v_key) && !strlen($v_file)) {
|
||||
$c_key->setError(pht('No Key'));
|
||||
$c_file->setError(pht('No Key'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'You must provide either a private key or the path to a private '.
|
||||
'key to connect over SSH.'));
|
||||
} else if (strlen($v_key) && strlen($v_file)) {
|
||||
$c_key->setError(pht('Ambiguous'));
|
||||
$c_file->setError(pht('Ambiguous'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'Provide either a private key or the path to a private key, not '.
|
||||
'both.'));
|
||||
} else if (!preg_match('/PRIVATE KEY/', $v_key)) {
|
||||
$c_key->setError(pht('Invalid'));
|
||||
$page->addPageError(
|
||||
pht(
|
||||
'The private key you provided is missing the PRIVATE KEY header. '.
|
||||
'You should include the header and footer. (Did you provide a '.
|
||||
'public key by mistake?)'));
|
||||
}
|
||||
|
||||
return $c_user->isValid() &&
|
||||
$c_key->isValid() &&
|
||||
$c_file->isValid();
|
||||
} else if ($this->isUsernamePasswordProtocol($proto)) {
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* -( Page: Done )--------------------------------------------------------- */
|
||||
|
||||
|
||||
private function buildDonePage() {
|
||||
return id(new PHUIFormPageView())
|
||||
->setPageName(pht('Repository Ready!'))
|
||||
->setValidateFormPageCallback(array($this, 'validateDonePage'))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->addControl(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('activate')
|
||||
->setLabel(pht('Start Now'))
|
||||
->addButton(
|
||||
'start',
|
||||
pht('Start Import Now'),
|
||||
pht(
|
||||
'Start importing the repository right away. This will import '.
|
||||
'the entire repository using default settings.'))
|
||||
->addButton(
|
||||
'wait',
|
||||
pht('Configure More Options First'),
|
||||
pht(
|
||||
'Configure more options before beginning the repository '.
|
||||
'import. This will let you fine-tune settings.. You can '.
|
||||
'start the import whenever you are ready.')));
|
||||
}
|
||||
|
||||
public function validateDonePage(PHUIFormPageView $page) {
|
||||
$c_activate = $page->getControl('activate');
|
||||
$v_activate = $c_activate->getValue();
|
||||
|
||||
if ($v_activate != 'start' && $v_activate != 'wait') {
|
||||
$c_activate->setError(pht('Required'));
|
||||
$page->addPageError(
|
||||
pht('Make a choice about repository activation.'));
|
||||
}
|
||||
|
||||
return $c_activate->isValid();
|
||||
}
|
||||
|
||||
|
||||
/* -( Internal )----------------------------------------------------------- */
|
||||
|
||||
|
||||
private function getRemoteURIProtocol($raw_uri) {
|
||||
$uri = new PhutilURI($raw_uri);
|
||||
if ($uri->getProtocol()) {
|
||||
return strtolower($uri->getProtocol());
|
||||
}
|
||||
|
||||
$git_uri = new PhutilGitURI($raw_uri);
|
||||
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
|
||||
return 'ssh';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getRemoteURIUser($raw_uri) {
|
||||
$uri = new PhutilURI($raw_uri);
|
||||
if ($uri->getUser()) {
|
||||
return $uri->getUser();
|
||||
}
|
||||
|
||||
$git_uri = new PhutilGitURI($raw_uri);
|
||||
if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) {
|
||||
return $git_uri->getUser();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function isSSHProtocol($proto) {
|
||||
return ($proto == 'git' || $proto == 'ssh' || $proto == 'svn+ssh');
|
||||
}
|
||||
|
||||
private function isUsernamePasswordProtocol($proto) {
|
||||
return ($proto == 'http' || $proto == 'https' || $proto == 'svn');
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ final class PhabricatorRepositoryType {
|
|||
const REPOSITORY_TYPE_GIT = 'git';
|
||||
const REPOSITORY_TYPE_SVN = 'svn';
|
||||
const REPOSITORY_TYPE_MERCURIAL = 'hg';
|
||||
const REPOSITORY_TYPE_PERFORCE = 'p4';
|
||||
|
||||
public static function getAllRepositoryTypes() {
|
||||
static $map = array(
|
||||
|
|
|
@ -8,8 +8,78 @@ class PHUIFormPageView extends AphrontView {
|
|||
private $key;
|
||||
private $form;
|
||||
private $controls = array();
|
||||
private $content = array();
|
||||
private $values = array();
|
||||
private $isValid;
|
||||
private $validateFormPageCallback;
|
||||
private $adjustFormPageCallback;
|
||||
private $pageErrors;
|
||||
private $pageName;
|
||||
|
||||
|
||||
public function setPageName($page_name) {
|
||||
$this->pageName = $page_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPageName() {
|
||||
return $this->pageName;
|
||||
}
|
||||
|
||||
public function addPageError($page_error) {
|
||||
$this->pageErrors[] = $page_error;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPageErrors() {
|
||||
return $this->pageErrors;
|
||||
}
|
||||
|
||||
public function setAdjustFormPageCallback($adjust_form_page_callback) {
|
||||
$this->adjustFormPageCallback = $adjust_form_page_callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setValidateFormPageCallback($validate_form_page_callback) {
|
||||
$this->validateFormPageCallback = $validate_form_page_callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addInstructions($text, $before = null) {
|
||||
$tag = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'aphront-form-instructions',
|
||||
),
|
||||
$text);
|
||||
|
||||
$append = true;
|
||||
if ($before !== null) {
|
||||
for ($ii = 0; $ii < count($this->content); $ii++) {
|
||||
if ($this->content[$ii] instanceof AphrontFormControl) {
|
||||
if ($this->content[$ii]->getName() == $before) {
|
||||
array_splice($this->content, $ii, 0, array($tag));
|
||||
$append = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($append) {
|
||||
$this->content[] = $tag;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addRemarkupInstructions($remarkup, $before = null) {
|
||||
return $this->addInstructions(
|
||||
PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($remarkup),
|
||||
'default',
|
||||
$this->getUser()), $before);
|
||||
}
|
||||
|
||||
public function addControl(AphrontFormControl $control) {
|
||||
$name = $control->getName();
|
||||
|
@ -24,6 +94,7 @@ class PHUIFormPageView extends AphrontView {
|
|||
}
|
||||
|
||||
$this->controls[$name] = $control;
|
||||
$this->content[] = $control;
|
||||
$control->setFormPage($this);
|
||||
|
||||
return $this;
|
||||
|
@ -53,12 +124,26 @@ class PHUIFormPageView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function adjustFormPage() {
|
||||
if ($this->adjustFormPageCallback) {
|
||||
call_user_func($this->adjustFormPageCallback, $this);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function validateFormPage() {
|
||||
if ($this->validateFormPageCallback) {
|
||||
return call_user_func($this->validateFormPageCallback, $this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getKey() {
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
return $this->getControls();
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getForm() {
|
||||
|
@ -91,7 +176,7 @@ class PHUIFormPageView extends AphrontView {
|
|||
|
||||
public function isValid() {
|
||||
if ($this->isValid === null) {
|
||||
$this->isValid = $this->validateControls();
|
||||
$this->isValid = $this->validateControls() && $this->validateFormPage();
|
||||
}
|
||||
return $this->isValid;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
}
|
||||
$this->pages[$key] = $page;
|
||||
$page->setPagedFormView($this, $key);
|
||||
|
||||
$this->selectedPage = null;
|
||||
$this->complete = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -104,12 +108,7 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
}
|
||||
|
||||
public function readFromObject($object) {
|
||||
foreach ($this->pages as $page) {
|
||||
$page->validateObjectType($object);
|
||||
$page->readFromObject($object);
|
||||
}
|
||||
|
||||
return $this->processForm();
|
||||
return $this->processForm($is_request = false, $object);
|
||||
}
|
||||
|
||||
public function writeToResponse($response) {
|
||||
|
@ -122,21 +121,11 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
}
|
||||
|
||||
public function readFromRequest(AphrontRequest $request) {
|
||||
$active_page = $request->getStr($this->getRequestKey('page'));
|
||||
|
||||
foreach ($this->pages as $key => $page) {
|
||||
if ($key == $active_page) {
|
||||
$page->readFromRequest($request);
|
||||
} else {
|
||||
$page->readSerializedValues($request);
|
||||
}
|
||||
}
|
||||
|
||||
$this->choosePage = $active_page;
|
||||
$this->choosePage = $request->getStr($this->getRequestKey('page'));
|
||||
$this->nextPage = $request->getStr('__submit__');
|
||||
$this->prevPage = $request->getStr('__back__');
|
||||
|
||||
return $this->processForm();
|
||||
return $this->processForm($is_request = true, $request);
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
|
@ -154,13 +143,7 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function processForm() {
|
||||
foreach ($this->pages as $key => $page) {
|
||||
if (!$page->isValid()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function processForm($is_request, $source) {
|
||||
if ($this->pageExists($this->choosePage)) {
|
||||
$selected = $this->getPage($this->choosePage);
|
||||
} else {
|
||||
|
@ -182,20 +165,39 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
}
|
||||
|
||||
$validation_error = false;
|
||||
$found_selected = false;
|
||||
foreach ($this->pages as $key => $page) {
|
||||
if (!$page->isValid()) {
|
||||
$validation_error = true;
|
||||
break;
|
||||
if ($is_request) {
|
||||
if ($key === $this->choosePage) {
|
||||
$page->readFromRequest($source);
|
||||
} else {
|
||||
$page->readSerializedValues($source);
|
||||
}
|
||||
} else {
|
||||
$page->readFromObject($source);
|
||||
}
|
||||
|
||||
if (!$found_selected) {
|
||||
$page->adjustFormPage();
|
||||
}
|
||||
|
||||
if ($page === $selected) {
|
||||
break;
|
||||
$found_selected = true;
|
||||
}
|
||||
|
||||
if (!$found_selected || $is_attempt_complete) {
|
||||
if (!$page->isValid()) {
|
||||
$selected = $page;
|
||||
$validation_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_attempt_complete && !$validation_error) {
|
||||
$this->complete = true;
|
||||
} else {
|
||||
$this->selectedPage = $page;
|
||||
$this->selectedPage = $selected;
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -222,8 +224,11 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
$this->getRequestKey('page'),
|
||||
$selected_page->getKey());
|
||||
|
||||
$errors = array();
|
||||
|
||||
foreach ($this->pages as $page) {
|
||||
if ($page == $selected_page) {
|
||||
$errors = $page->getPageErrors();
|
||||
continue;
|
||||
}
|
||||
foreach ($page->getSerializedValues() as $key => $value) {
|
||||
|
@ -246,7 +251,21 @@ final class PHUIPagedFormView extends AphrontTagView {
|
|||
$form->appendChild($selected_page);
|
||||
$form->appendChild($submit);
|
||||
|
||||
return $form;
|
||||
if ($errors) {
|
||||
$errors = id(new AphrontErrorView())->setErrors($errors);
|
||||
}
|
||||
|
||||
$header = null;
|
||||
if ($selected_page->getPageName()) {
|
||||
$header = id(new PhabricatorHeaderView())
|
||||
->setHeader($selected_page->getPageName());
|
||||
}
|
||||
|
||||
return array(
|
||||
$header,
|
||||
$errors,
|
||||
$form,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,12 @@ abstract class AphrontFormControl extends AphrontView {
|
|||
private $controlStyle;
|
||||
private $formPage;
|
||||
private $required;
|
||||
private $hidden;
|
||||
|
||||
public function setHidden($hidden) {
|
||||
$this->hidden = $hidden;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
|
@ -203,12 +209,17 @@ abstract class AphrontFormControl extends AphrontView {
|
|||
$classes[] = 'aphront-form-control';
|
||||
$classes[] = $custom_class;
|
||||
|
||||
$style = $this->controlStyle;
|
||||
if ($this->hidden) {
|
||||
$style = 'display: none; '.$style;
|
||||
}
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => implode(' ', $classes),
|
||||
'id' => $this->controlID,
|
||||
'style' => $this->controlStyle,
|
||||
'style' => $style,
|
||||
),
|
||||
array(
|
||||
$label,
|
||||
|
|
Loading…
Reference in a new issue