1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-20 13:52:40 +01:00

Add hosting, serving, and push policy options to repository edit

Summary:
Basically straight from D7391. The differences are basically:

  - Policy stuff is all application-scope instead of global-scope.
  - Made a few strings a little nicer.
  - Deleted a bit of dead code.
  - Added a big "THIS DOESN'T WORK YET" warning.

Test Plan: See screenshots.

Reviewers: hach-que, btrahan

Reviewed By: hach-que

CC: aran

Maniphest Tasks: T2230

Differential Revision: https://secure.phabricator.com/D7416
This commit is contained in:
epriestley 2013-10-25 20:13:38 -07:00
parent 86fe020a97
commit bb35f8ec9f
9 changed files with 458 additions and 6 deletions

View file

@ -516,6 +516,7 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php',
'DiffusionRepositoryEditDeleteController' => 'applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php',
'DiffusionRepositoryEditEncodingController' => 'applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php',
'DiffusionRepositoryEditHostingController' => 'applications/diffusion/controller/DiffusionRepositoryEditHostingController.php',
'DiffusionRepositoryEditLocalController' => 'applications/diffusion/controller/DiffusionRepositoryEditLocalController.php',
'DiffusionRepositoryEditMainController' => 'applications/diffusion/controller/DiffusionRepositoryEditMainController.php',
'DiffusionRepositoryEditPolicyController' => 'applications/diffusion/controller/DiffusionRepositoryEditPolicyController.php',
@ -2697,6 +2698,7 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditController' => 'DiffusionController',
'DiffusionRepositoryEditDeleteController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditEncodingController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditHostingController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditLocalController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditMainController' => 'DiffusionRepositoryEditController',
'DiffusionRepositoryEditPolicyController' => 'DiffusionRepositoryEditController',

View file

@ -75,6 +75,8 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication {
'(?P<edit>remote)/' => 'DiffusionRepositoryCreateController',
'local/' => 'DiffusionRepositoryEditLocalController',
'delete/' => 'DiffusionRepositoryEditDeleteController',
'hosting/' => 'DiffusionRepositoryEditHostingController',
'(?P<serve>serve)/' => 'DiffusionRepositoryEditHostingController',
),
),
'inline/' => array(
@ -110,6 +112,8 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication {
DiffusionCapabilityDefaultEdit::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),
DiffusionCapabilityDefaultPush::CAPABILITY => array(
),
DiffusionCapabilityCreateRepositories::CAPABILITY => array(
'default' => PhabricatorPolicies::POLICY_ADMIN,
),

View file

@ -0,0 +1,229 @@
<?php
final class DiffusionRepositoryEditHostingController
extends DiffusionRepositoryEditController {
private $serve;
public function willProcessRequest(array $data) {
parent::willProcessRequest($data);
$this->serve = idx($data, 'serve');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$drequest = $this->diffusionRequest;
$repository = $drequest->getRepository();
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($user)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withIDs(array($repository->getID()))
->executeOne();
if (!$repository) {
return new Aphront404Response();
}
if (!$this->serve) {
return $this->handleHosting($repository);
} else {
return $this->handleProtocols($repository);
}
}
public function handleHosting(PhabricatorRepository $repository) {
$request = $this->getRequest();
$user = $request->getUser();
$v_hosting = $repository->isHosted();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$next_uri = $this->getRepositoryControllerURI($repository, 'edit/serve/');
if ($request->isFormPost()) {
$v_hosting = $request->getBool('hosting');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_hosting = PhabricatorRepositoryTransaction::TYPE_HOSTING;
$xactions[] = id(clone $template)
->setTransactionType($type_hosting)
->setNewValue($v_hosting);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($user)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($next_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Edit Hosting')));
$title = pht('Edit Hosting (%s)', $repository->getName());
$hosted_control = id(new AphrontFormRadioButtonControl())
->setName('hosting')
->setLabel(pht('Hosting'))
->addButton(
true,
pht('Host Repository on Phabricator'),
pht(
'Phabricator will host this repository. Users will be able to '.
'push commits to Phabricator. Phabricator will not pull '.
'changes from elsewhere.'))
->addButton(
false,
pht('Host Repository Elsewhere'),
pht(
'Phabricator will pull updates to this repository from a master '.
'repository elsewhere (for example, on GitHub or Bitbucket). '.
'Users will not be able to push commits to this repository.'))
->setValue($v_hosting);
$form = id(new AphrontFormView())
->setUser($user)
->appendRemarkupInstructions(
pht(
'NOTE: Hosting is extremely new and barely works! Use it at '.
'your own risk.'.
"\n\n".
'Phabricator can host repositories, or it can track repositories '.
'hosted elsewhere (like on GitHub or Bitbucket).'))
->appendChild($hosted_control)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save and Continue'))
->addCancelButton($edit_uri));
$object_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setForm($form);
return $this->buildApplicationPage(
array(
$crumbs,
$object_box,
),
array(
'title' => $title,
'device' => true,
));
}
public function handleProtocols(PhabricatorRepository $repository) {
$request = $this->getRequest();
$user = $request->getUser();
$v_http_mode = $repository->getServeOverHTTP();
$v_ssh_mode = $repository->getServeOverSSH();
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$prev_uri = $this->getRepositoryControllerURI($repository, 'edit/hosting/');
if ($request->isFormPost()) {
$v_http_mode = $request->getStr('http');
$v_ssh_mode = PhabricatorRepository::SERVE_OFF;
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
$xactions[] = id(clone $template)
->setTransactionType($type_http)
->setNewValue($v_http_mode);
$xactions[] = id(clone $template)
->setTransactionType($type_ssh)
->setNewValue($v_ssh_mode);
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->setActor($user)
->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Edit Protocols')));
$title = pht('Edit Protocols (%s)', $repository->getName());
if ($repository->isHosted()) {
$rw_message = pht(
'Phabricator will serve a read-write copy of this repository');
} else {
$rw_message = pht(
'This repository is hosted elsewhere, so Phabricator can not perform '.
'writes.');
}
$http_control =
id(new AphrontFormRadioButtonControl())
->setName('http')
->setLabel(pht('HTTP'))
->setValue($v_http_mode)
->addButton(
PhabricatorRepository::SERVE_OFF,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_OFF),
pht('Phabricator will not serve this repository.'))
->addButton(
PhabricatorRepository::SERVE_READONLY,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READONLY),
pht('Phabricator will serve a read-only copy of this repository.'))
->addButton(
PhabricatorRepository::SERVE_READWRITE,
PhabricatorRepository::getProtocolAvailabilityName(
PhabricatorRepository::SERVE_READWRITE),
$rw_message,
$repository->isHosted() ? null : 'disabled',
$repository->isHosted() ? null : true);
$form = id(new AphrontFormView())
->setUser($user)
->appendRemarkupInstructions(
pht(
'Phabricator can serve repositories over various protocols. You can '.
'configure server protocols here.'))
->appendChild($http_control)
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Changes'))
->addCancelButton($prev_uri, pht('Back')));
$object_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setForm($form);
return $this->buildApplicationPage(
array(
$crumbs,
$object_box,
),
array(
'title' => $title,
'device' => true,
));
}
}

View file

@ -23,8 +23,7 @@ final class DiffusionRepositoryEditMainController
$is_git = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// TOOD: This will be true for hosted SVN repositories.
$has_local = false;
$has_local = $repository->isHosted();
$is_svn = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
@ -63,6 +62,10 @@ final class DiffusionRepositoryEditMainController
$encoding_properties =
$this->buildEncodingProperties($repository, $encoding_actions);
$hosting_properties = $this->buildHostingProperties(
$repository,
$this->buildHostingActions($repository));
$branches_properties = null;
if ($has_branches) {
$branches_properties = $this->buildBranchesProperties(
@ -114,6 +117,7 @@ final class DiffusionRepositoryEditMainController
->setHeader($header)
->addPropertyList($basic_properties)
->addPropertyList($policy_properties)
->addPropertyList($hosting_properties)
->addPropertyList($remote_properties);
if ($local_properties) {
@ -298,6 +302,10 @@ final class DiffusionRepositoryEditMainController
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$pushable = $repository->isHosted()
? $descriptions[DiffusionCapabilityPush::CAPABILITY]
: phutil_tag('em', array(), pht('Not a Hosted Repository'));
$view->addProperty(pht('Pushable By'), $pushable);
return $view;
}
@ -501,4 +509,57 @@ final class DiffusionRepositoryEditMainController
return $view;
}
private function buildHostingActions(PhabricatorRepository $repository) {
$user = $this->getRequest()->getUser();
$view = id(new PhabricatorActionListView())
->setObjectURI($this->getRequest()->getRequestURI())
->setUser($user);
$edit = id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Hosting'))
->setHref(
$this->getRepositoryControllerURI($repository, 'edit/hosting/'));
$view->addAction($edit);
return $view;
}
private function buildHostingProperties(
PhabricatorRepository $repository,
PhabricatorActionListView $actions) {
$user = $this->getRequest()->getUser();
$view = id(new PHUIPropertyListView())
->setUser($user)
->setActionList($actions)
->addSectionHeader(pht('Hosting'));
$hosting = $repository->isHosted()
? pht('Hosted on Phabricator')
: pht('Hosted Elsewhere');
$view->addProperty(pht('Hosting'), phutil_tag('em', array(), $hosting));
$view->addProperty(
pht('Serve over HTTP'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverHTTP())));
$view->addProperty(
pht('Serve over SSH'),
phutil_tag(
'em',
array(),
PhabricatorRepository::getProtocolAvailabilityName(
$repository->getServeOverSSH())));
return $view;
}
}

View file

@ -27,16 +27,19 @@ final class DiffusionRepositoryEditPolicyController
$v_view = $repository->getViewPolicy();
$v_edit = $repository->getEditPolicy();
$v_push = $repository->getPushPolicy();
if ($request->isFormPost()) {
$v_view = $request->getStr('viewPolicy');
$v_edit = $request->getStr('editPolicy');
$v_push = $request->getStr('pushPolicy');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_view = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;
$type_push = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
$xactions[] = id(clone $template)
->setTransactionType($type_view)
@ -46,6 +49,12 @@ final class DiffusionRepositoryEditPolicyController
->setTransactionType($type_edit)
->setNewValue($v_edit);
if ($repository->isHosted()) {
$xactions[] = id(clone $template)
->setTransactionType($type_push)
->setNewValue($v_push);
}
id(new PhabricatorRepositoryEditor())
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
@ -62,7 +71,7 @@ final class DiffusionRepositoryEditPolicyController
id(new PhabricatorCrumbView())
->setName(pht('Edit Policies')));
$title = pht('Edit %s', $repository->getName());
$title = pht('Edit Policies (%s)', $repository->getName());
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
@ -84,7 +93,25 @@ final class DiffusionRepositoryEditPolicyController
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicyObject($repository)
->setPolicies($policies)
->setName('editPolicy'))
->setName('editPolicy'));
if ($repository->isHosted()) {
$form->appendChild(
id(new AphrontFormPolicyControl())
->setUser($viewer)
->setCapability(DiffusionCapabilityPush::CAPABILITY)
->setPolicyObject($repository)
->setPolicies($policies)
->setName('pushPolicy'));
} else {
$form->appendChild(
id(new AphrontFormMarkupControl())
->setLabel(pht('Can Push'))
->setValue(
phutil_tag('em', array(), pht('Not a Hosted Repository'))));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Policies'))

View file

@ -25,6 +25,10 @@ final class PhabricatorRepositoryEditor
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_LOGIN;
$types[] = PhabricatorRepositoryTransaction::TYPE_HTTP_PASS;
$types[] = PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH;
$types[] = PhabricatorRepositoryTransaction::TYPE_HOSTING;
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$types[] = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
$types[] = PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@ -75,6 +79,14 @@ final class PhabricatorRepositoryEditor
return $object->getDetail('http-pass');
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
return $object->getDetail('local-path');
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
return $object->isHosted();
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
return $object->getServeOverHTTP();
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
return $object->getServeOverSSH();
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
return $object->getPushPolicy();
}
}
@ -100,6 +112,10 @@ final class PhabricatorRepositoryEditor
case PhabricatorRepositoryTransaction::TYPE_HTTP_PASS:
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
case PhabricatorRepositoryTransaction::TYPE_VCS:
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
return $xaction->getNewValue();
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
@ -170,6 +186,14 @@ final class PhabricatorRepositoryEditor
case PhabricatorRepositoryTransaction::TYPE_LOCAL_PATH:
$object->setDetail('local-path', $xaction->getNewValue());
break;
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
return $object->setHosted($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
return $object->setServeOverHTTP($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
return $object->setServeOverSSH($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
return $object->setPushPolicy($xaction->getNewValue());
case PhabricatorRepositoryTransaction::TYPE_ENCODING:
// Make sure the encoding is valid by converting to UTF-8. This tests
// that the user has mbstring installed, and also that they didn't type
@ -250,6 +274,10 @@ final class PhabricatorRepositoryEditor
case PhabricatorRepositoryTransaction::TYPE_VCS:
case PhabricatorRepositoryTransaction::TYPE_NOTIFY:
case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
case PhabricatorRepositoryTransaction::TYPE_HOSTING:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP:
case PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH:
case PhabricatorRepositoryTransaction::TYPE_PUSH_POLICY:
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,

View file

@ -26,6 +26,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
const TABLE_BADCOMMIT = 'repository_badcommit';
const TABLE_LINTMESSAGE = 'repository_lintmessage';
const SERVE_OFF = 'off';
const SERVE_READONLY = 'readonly';
const SERVE_READWRITE = 'readwrite';
protected $name;
protected $callsign;
protected $uuid;
@ -708,6 +712,43 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL);
}
public function isHosted() {
return (bool)$this->getDetail('hosting-enabled', false);
}
public function setHosted($enabled) {
return $this->setDetail('hosting-enabled', $enabled);
}
public function getServeOverHTTP() {
return $this->getDetail('serve-over-http', self::SERVE_OFF);
}
public function setServeOverHTTP($mode) {
return $this->setDetail('serve-over-http', $mode);
}
public function getServeOverSSH() {
return $this->getDetail('serve-over-ssh', self::SERVE_OFF);
}
public function setServeOverSSH($mode) {
return $this->setDetail('serve-over-ssh', $mode);
}
public static function getProtocolAvailabilityName($constant) {
switch ($constant) {
case self::SERVE_OFF:
return pht('Off');
case self::SERVE_READONLY:
return pht('Read Only');
case self::SERVE_READWRITE:
return pht('Read/Write');
default:
return pht('Unknown');
}
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -22,6 +22,10 @@ final class PhabricatorRepositoryTransaction
const TYPE_HTTP_LOGIN = 'repo:http-login';
const TYPE_HTTP_PASS = 'repo:http-pass';
const TYPE_LOCAL_PATH = 'repo:local-path';
const TYPE_HOSTING = 'repo:hosting';
const TYPE_PROTOCOL_HTTP = 'repo:serve-http';
const TYPE_PROTOCOL_SSH = 'repo:serve-ssh';
const TYPE_PUSH_POLICY = 'repo:push-policy';
public function getApplicationName() {
return 'repository';
@ -35,6 +39,22 @@ final class PhabricatorRepositoryTransaction
return null;
}
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_PUSH_POLICY:
$phids[] = $old;
$phids[] = $new;
break;
}
return $phids;
}
public function shouldHide() {
$old = $this->getOldValue();
$new = $this->getNewValue();
@ -285,6 +305,36 @@ final class PhabricatorRepositoryTransaction
$this->renderHandleLink($author_phid),
$old,
$new);
case self::TYPE_HOSTING:
if ($new) {
return pht(
'%s changed this repository to be hosted on Phabricator.',
$this->renderHandleLink($author_phid));
} else {
return pht(
'%s changed this repository to track a remote elsewhere.',
$this->renderHandleLink($author_phid));
}
case self::TYPE_PROTOCOL_HTTP:
return pht(
'%s changed the availability of this repository over HTTP from '.
'"%s" to "%s".',
$this->renderHandleLink($author_phid),
PhabricatorRepository::getProtocolAvailabilityName($old),
PhabricatorRepository::getProtocolAvailabilityName($new));
case self::TYPE_PROTOCOL_SSH:
return pht(
'%s changed the availability of this repository over SSH from '.
'"%s" to "%s".',
$this->renderHandleLink($author_phid),
PhabricatorRepository::getProtocolAvailabilityName($old),
PhabricatorRepository::getProtocolAvailabilityName($new));
case self::TYPE_PUSH_POLICY:
return pht(
'%s changed the push policy of this repository from "%s" to "%s".',
$this->renderHandleLink($author_phid),
$this->renderPolicyName($old),
$this->renderPolicyName($new));
}
return parent::getTitle();
@ -310,6 +360,5 @@ final class PhabricatorRepositoryTransaction
return $view->render();
}
}

View file

@ -26,7 +26,18 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
PhabricatorPolicyCapability::CAN_JOIN => pht('Joinable By'),
);
$this->setLabel(idx($labels, $this->capability, pht('Unknown Policy')));
if (isset($labels[$capability])) {
$label = $labels[$capability];
} else {
$capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability);
if ($capobj) {
$label = $capobj->getCapabilityName();
} else {
$label = pht('Capability "%s"', $capability);
}
}
$this->setLabel($label);
return $this;
}