1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 18:22:41 +01:00

(stable) Promote 2015 Week 43

This commit is contained in:
epriestley 2015-10-24 05:41:48 -07:00
commit 9520a6b0ed
54 changed files with 780 additions and 369 deletions

View file

@ -373,6 +373,7 @@ return array(
'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947', 'rsrc/js/application/diffusion/behavior-locate-file.js' => '6d3e1947',
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58', 'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
'rsrc/js/application/herald/HeraldRuleEditor.js' => '91a6031b', 'rsrc/js/application/herald/HeraldRuleEditor.js' => '91a6031b',
@ -576,6 +577,7 @@ return array(
'javelin-behavior-diffusion-locate-file' => '6d3e1947', 'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
'javelin-behavior-doorkeeper-tag' => 'e5822781', 'javelin-behavior-doorkeeper-tag' => 'e5822781',
'javelin-behavior-drydock-live-operation-status' => '901935ef',
'javelin-behavior-durable-column' => 'c72aa091', 'javelin-behavior-durable-column' => 'c72aa091',
'javelin-behavior-error-log' => '6882e80a', 'javelin-behavior-error-log' => '6882e80a',
'javelin-behavior-event-all-day' => '38dcf3c8', 'javelin-behavior-event-all-day' => '38dcf3c8',
@ -1518,6 +1520,11 @@ return array(
'javelin-dom', 'javelin-dom',
'javelin-stratcom', 'javelin-stratcom',
), ),
'901935ef' => array(
'javelin-behavior',
'javelin-dom',
'javelin-request',
),
'91a6031b' => array( '91a6031b' => array(
'multirow-row-manager', 'multirow-row-manager',
'javelin-install', 'javelin-install',

View file

@ -885,6 +885,8 @@ phutil_register_library_map(array(
'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php', 'DrydockRepositoryOperationPHIDType' => 'applications/drydock/phid/DrydockRepositoryOperationPHIDType.php',
'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php', 'DrydockRepositoryOperationQuery' => 'applications/drydock/query/DrydockRepositoryOperationQuery.php',
'DrydockRepositoryOperationSearchEngine' => 'applications/drydock/query/DrydockRepositoryOperationSearchEngine.php', 'DrydockRepositoryOperationSearchEngine' => 'applications/drydock/query/DrydockRepositoryOperationSearchEngine.php',
'DrydockRepositoryOperationStatusController' => 'applications/drydock/controller/DrydockRepositoryOperationStatusController.php',
'DrydockRepositoryOperationStatusView' => 'applications/drydock/view/DrydockRepositoryOperationStatusView.php',
'DrydockRepositoryOperationType' => 'applications/drydock/operation/DrydockRepositoryOperationType.php', 'DrydockRepositoryOperationType' => 'applications/drydock/operation/DrydockRepositoryOperationType.php',
'DrydockRepositoryOperationUpdateWorker' => 'applications/drydock/worker/DrydockRepositoryOperationUpdateWorker.php', 'DrydockRepositoryOperationUpdateWorker' => 'applications/drydock/worker/DrydockRepositoryOperationUpdateWorker.php',
'DrydockRepositoryOperationViewController' => 'applications/drydock/controller/DrydockRepositoryOperationViewController.php', 'DrydockRepositoryOperationViewController' => 'applications/drydock/controller/DrydockRepositoryOperationViewController.php',
@ -2552,6 +2554,7 @@ phutil_register_library_map(array(
'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php',
'PhabricatorPasteSchemaSpec' => 'applications/paste/storage/PhabricatorPasteSchemaSpec.php', 'PhabricatorPasteSchemaSpec' => 'applications/paste/storage/PhabricatorPasteSchemaSpec.php',
'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php',
'PhabricatorPasteSnippet' => 'applications/paste/snippet/PhabricatorPasteSnippet.php',
'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php', 'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php',
'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php', 'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php',
'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php', 'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php',
@ -4671,6 +4674,8 @@ phutil_register_library_map(array(
'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType', 'DrydockRepositoryOperationPHIDType' => 'PhabricatorPHIDType',
'DrydockRepositoryOperationQuery' => 'DrydockQuery', 'DrydockRepositoryOperationQuery' => 'DrydockQuery',
'DrydockRepositoryOperationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockRepositoryOperationSearchEngine' => 'PhabricatorApplicationSearchEngine',
'DrydockRepositoryOperationStatusController' => 'DrydockController',
'DrydockRepositoryOperationStatusView' => 'AphrontView',
'DrydockRepositoryOperationType' => 'Phobject', 'DrydockRepositoryOperationType' => 'Phobject',
'DrydockRepositoryOperationUpdateWorker' => 'DrydockWorker', 'DrydockRepositoryOperationUpdateWorker' => 'DrydockWorker',
'DrydockRepositoryOperationViewController' => 'DrydockController', 'DrydockRepositoryOperationViewController' => 'DrydockController',
@ -6633,6 +6638,7 @@ phutil_register_library_map(array(
'PhabricatorPasteRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorPasteRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorPasteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorPasteSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorPasteSnippet' => 'Phobject',
'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator',
'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment',

View file

@ -113,6 +113,27 @@ final class PhabricatorAuthLoginController
$provider->getProviderName())); $provider->getProviderName()));
} }
} else { } else {
// If the user already has a linked account of this type, prevent them
// from linking a second account. This can happen if they swap logins
// and then refresh the account link. See T6707. We will eventually
// allow this after T2549.
$existing_accounts = id(new PhabricatorExternalAccountQuery())
->setViewer($viewer)
->withUserPHIDs(array($viewer->getPHID()))
->withAccountTypes(array($account->getAccountType()))
->execute();
if ($existing_accounts) {
return $this->renderError(
pht(
'Your Phabricator account is already connected to an external '.
'account on this provider ("%s"), but you are currently logged '.
'in to the provider with a different account. Log out of the '.
'external service, then log back in with the correct account '.
'before refreshing the account link.',
$provider->getProviderName()));
}
if ($provider->shouldAllowAccountLink()) { if ($provider->shouldAllowAccountLink()) {
return $this->processLinkUser($account); return $this->processLinkUser($account);
} else { } else {

View file

@ -206,40 +206,12 @@ final class PhabricatorCaches extends Phobject {
// otherwise (we desire this property to give the cache the best hit rate // otherwise (we desire this property to give the cache the best hit rate
// we can). // we can).
// In some setups, the parent PID is more stable and longer-lived that the // Unfortunately, we don't have a very good strategy for minimizing the
// PID (e.g., under apache, our PID will be a worker while the ppid will // churn rate of the cache. We previously tried to use the parent process
// be the main httpd process). If we're confident we're running under such // PID in some cases, but this was not reliable. See T9599 for one case of
// a setup, we can try to use the PPID as the basis for our cache instead // this.
// of our own PID.
$use_ppid = false;
switch (php_sapi_name()) {
case 'cli-server':
// This is the PHP5.4+ built-in webserver. We should use the pid
// (the server), not the ppid (probably a shell or something).
$use_ppid = false;
break;
case 'fpm-fcgi':
// We should be safe to use PPID here.
$use_ppid = true;
break;
case 'apache2handler':
// We're definitely safe to use the PPID.
$use_ppid = true;
break;
}
$pid_basis = getmypid(); $pid_basis = getmypid();
if ($use_ppid) {
if (function_exists('posix_getppid')) {
$parent_pid = posix_getppid();
// On most systems, normal processes can never have PIDs lower than 100,
// so something likely went wrong if we we get one of these.
if ($parent_pid > 100) {
$pid_basis = $parent_pid;
}
}
}
// If possible, we also want to know when the process launched, so we can // If possible, we also want to know when the process launched, so we can
// drop the cache if a process restarts but gets the same PID an earlier // drop the cache if a process restarts but gets the same PID an earlier

View file

@ -63,7 +63,9 @@ final class PhabricatorDataCacheSpec extends PhabricatorCacheSpec {
private function initNoneSpec() { private function initNoneSpec() {
if (version_compare(phpversion(), '5.5', '>=')) { if (version_compare(phpversion(), '5.5', '>=')) {
$message = pht( $message = pht(
'Installing the "APCu" PHP extension will improve performance.'); 'Installing the "APCu" PHP extension will improve performance. '.
'This extension is strongly recommended. Without it, Phabricator '.
'must rely on a very inefficient disk-based cache.');
$this $this
->newIssue('extension.apcu') ->newIssue('extension.apcu')

View file

@ -7,18 +7,9 @@ final class PhabricatorConduitAPIController
return false; return false;
} }
private $method; public function handleRequest(AphrontRequest $request) {
$method = $request->getURIData('method');
public function willProcessRequest(array $data) {
$this->method = $data['method'];
return $this;
}
public function processRequest() {
$time_start = microtime(true); $time_start = microtime(true);
$request = $this->getRequest();
$method = $this->method;
$api_request = null; $api_request = null;
$method_implementation = null; $method_implementation = null;
@ -55,7 +46,7 @@ final class PhabricatorConduitAPIController
$conduit_username = '-'; $conduit_username = '-';
if ($call->shouldRequireAuthentication()) { if ($call->shouldRequireAuthentication()) {
$metadata['scope'] = $call->getRequiredScope(); $metadata['scope'] = $call->getRequiredScope();
$auth_error = $this->authenticateUser($api_request, $metadata); $auth_error = $this->authenticateUser($api_request, $metadata, $method);
// If we've explicitly authenticated the user here and either done // If we've explicitly authenticated the user here and either done
// CSRF validation or are using a non-web authentication mechanism. // CSRF validation or are using a non-web authentication mechanism.
$allow_unguarded_writes = true; $allow_unguarded_writes = true;
@ -169,7 +160,8 @@ final class PhabricatorConduitAPIController
*/ */
private function authenticateUser( private function authenticateUser(
ConduitAPIRequest $api_request, ConduitAPIRequest $api_request,
array $metadata) { array $metadata,
$method) {
$request = $this->getRequest(); $request = $this->getRequest();
@ -207,7 +199,7 @@ final class PhabricatorConduitAPIController
unset($protocol_data['scope']); unset($protocol_data['scope']);
ConduitClient::verifySignature( ConduitClient::verifySignature(
$this->method, $method,
$api_request->getAllParameters(), $api_request->getAllParameters(),
$protocol_data, $protocol_data,
$ssl_public_key); $ssl_public_key);

View file

@ -3,19 +3,13 @@
final class PhabricatorConduitListController final class PhabricatorConduitListController
extends PhabricatorConduitController { extends PhabricatorConduitController {
private $queryKey;
public function shouldAllowPublic() { public function shouldAllowPublic() {
return true; return true;
} }
public function willProcessRequest(array $data) { public function handleRequest(AphrontRequest $request) {
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$controller = id(new PhabricatorApplicationSearchController()) $controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($this->queryKey) ->setQueryKey($request->getURIData('queryKey'))
->setSearchEngine(new PhabricatorConduitSearchEngine()) ->setSearchEngine(new PhabricatorConduitSearchEngine())
->setNavigation($this->buildSideNavView()); ->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller); return $this->delegateToController($controller);

View file

@ -3,9 +3,8 @@
final class PhabricatorConduitLogController final class PhabricatorConduitLogController
extends PhabricatorConduitController { extends PhabricatorConduitController {
public function processRequest() { public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest(); $viewer = $request->getViewer();
$viewer = $request->getUser();
$conn_table = new PhabricatorConduitConnectionLog(); $conn_table = new PhabricatorConduitConnectionLog();
$call_table = new PhabricatorConduitMethodCallLog(); $call_table = new PhabricatorConduitMethodCallLog();

View file

@ -3,11 +3,11 @@
final class PhabricatorConduitTokenController final class PhabricatorConduitTokenController
extends PhabricatorConduitController { extends PhabricatorConduitController {
public function processRequest() { public function handleRequest(AphrontRequest $request) {
$user = $this->getRequest()->getUser(); $viewer = $request->getViewer();
id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
$user, $viewer,
$this->getRequest(), $this->getRequest(),
'/'); '/');
@ -19,13 +19,13 @@ final class PhabricatorConduitTokenController
$old_token = id(new PhabricatorConduitCertificateToken()) $old_token = id(new PhabricatorConduitCertificateToken())
->loadOneWhere( ->loadOneWhere(
'userPHID = %s', 'userPHID = %s',
$user->getPHID()); $viewer->getPHID());
if ($old_token) { if ($old_token) {
$old_token->delete(); $old_token->delete();
} }
$token = id(new PhabricatorConduitCertificateToken()) $token = id(new PhabricatorConduitCertificateToken())
->setUserPHID($user->getPHID()) ->setUserPHID($viewer->getPHID())
->setToken(Filesystem::readRandomCharacters(40)) ->setToken(Filesystem::readRandomCharacters(40))
->save(); ->save();
@ -42,7 +42,7 @@ final class PhabricatorConduitTokenController
Javelin::initBehavior('select-on-click'); Javelin::initBehavior('select-on-click');
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->setUser($viewer)
->appendRemarkupInstructions($pre_instructions) ->appendRemarkupInstructions($pre_instructions)
->appendChild( ->appendChild(
id(new AphrontFormTextAreaControl()) id(new AphrontFormTextAreaControl())

View file

@ -5,8 +5,8 @@ final class PhabricatorConduitTokenEditController
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$id = $request->getURIData('id'); $id = $request->getURIData('id');
if ($id) { if ($id) {
$token = id(new PhabricatorConduitTokenQuery()) $token = id(new PhabricatorConduitTokenQuery())
->setViewer($viewer) ->setViewer($viewer)

View file

@ -5,9 +5,9 @@ final class PhabricatorConduitTokenTerminateController
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$object_phid = $request->getStr('objectPHID'); $object_phid = $request->getStr('objectPHID');
$id = $request->getURIData('id'); $id = $request->getURIData('id');
if ($id) { if ($id) {
$token = id(new PhabricatorConduitTokenQuery()) $token = id(new PhabricatorConduitTokenQuery())
->setViewer($viewer) ->setViewer($viewer)

View file

@ -225,18 +225,8 @@ final class PhabricatorConfigWelcomeController
'fa-globe', 'fa-globe',
$content); $content);
$support_href = PhabricatorEnv::getDoclink('Give Feedback! Get Support!'); // TODO: Restore some sort of "Support" link here, but just nuke it for
$content = pht( // now as we figure stuff out.
"=== Need Help with Setup? ===\n\n".
'Having trouble getting something set up? See '.
'**[[ %s | Give Feedback! Get Support! ]]** for ways to get in touch '.
'to get answers to questions, report bugs, and request features.',
$support_href);
$explore[] = $this->newItem(
$request,
'fa-life-ring',
$content);
$differential_uri = PhabricatorEnv::getURI('/differential/'); $differential_uri = PhabricatorEnv::getURI('/differential/');
$differential_create_uri = PhabricatorEnv::getURI( $differential_create_uri = PhabricatorEnv::getURI(

View file

@ -20,8 +20,6 @@ final class PhabricatorSecurityConfigOptions
} }
public function getOptions() { public function getOptions() {
$support_href = PhabricatorEnv::getDoclink('Give Feedback! Get Support!');
$doc_href = PhabricatorEnv::getDoclink('Configuring a File Domain'); $doc_href = PhabricatorEnv::getDoclink('Configuring a File Domain');
$doc_name = pht('Configuration Guide: Configuring a File Domain'); $doc_name = pht('Configuration Guide: Configuring a File Domain');
@ -197,11 +195,8 @@ final class PhabricatorSecurityConfigOptions
->setSummary(pht('Whitelists editor protocols for "Open in Editor".')) ->setSummary(pht('Whitelists editor protocols for "Open in Editor".'))
->setDescription( ->setDescription(
pht( pht(
"Users can configure a URI pattern to open files in a text ". 'Users can configure a URI pattern to open files in a text '.
"editor. The URI must use a protocol on this whitelist.\n\n". 'editor. The URI must use a protocol on this whitelist.'))
"(If you use an editor which defines a protocol not on this ".
"list, [[ %s | let us know ]] and we'll update the defaults.)",
$support_href))
->setLocked(true), ->setLocked(true),
$this->newOption( $this->newOption(
'celerity.resource-hash', 'celerity.resource-hash',

View file

@ -1060,30 +1060,13 @@ final class DifferentialRevisionViewController extends DifferentialController {
$operation = head(msort($operations, 'getID')); $operation = head(msort($operations, 'getID'));
// TODO: This is completely made up for now, give it useful information and $box_view = id(new PHUIObjectBoxView())
// a sweet progress bar. ->setHeaderText(pht('Active Operations'));
switch ($operation->getOperationState()) { return id(new DrydockRepositoryOperationStatusView())
case DrydockRepositoryOperation::STATE_WAIT: ->setUser($viewer)
case DrydockRepositoryOperation::STATE_WORK: ->setBoxView($box_view)
$severity = PHUIInfoView::SEVERITY_NOTICE; ->setOperation($operation);
$text = pht(
'Some sort of repository operation is currently running.');
break;
default:
$severity = PHUIInfoView::SEVERITY_ERROR;
$text = pht(
'Some sort of repository operation failed.');
break;
}
$info_view = id(new PHUIInfoView())
->setSeverity($severity)
->appendChild($text);
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Active Operations (EXPERIMENTAL!)'))
->setInfoView($info_view);
} }
} }

View file

@ -288,7 +288,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController {
$repo = $drequest->getRepository(); $repo = $drequest->getRepository();
$symbol_repos = nonempty($repo->getSymbolSources(), array()); $symbol_repos = nonempty($repo->getSymbolSources(), array());
$symbol_repos[] = $repo; $symbol_repos[] = $repo->getPHID();
$lang = last(explode('.', $drequest->getPath())); $lang = last(explode('.', $drequest->getPath()));
$repo_languages = $repo->getSymbolLanguages(); $repo_languages = $repo->getSymbolLanguages();

View file

@ -95,6 +95,7 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication {
=> 'DrydockRepositoryOperationListController', => 'DrydockRepositoryOperationListController',
'(?P<id>[1-9]\d*)/' => array( '(?P<id>[1-9]\d*)/' => array(
'' => 'DrydockRepositoryOperationViewController', '' => 'DrydockRepositoryOperationViewController',
'status/' => 'DrydockRepositoryOperationStatusController',
), ),
), ),
), ),

View file

@ -0,0 +1,59 @@
<?php
final class DrydockRepositoryOperationStatusController
extends DrydockController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$operation = id(new DrydockRepositoryOperationQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$operation) {
return new Aphront404Response();
}
$id = $operation->getID();
$status_view = id(new DrydockRepositoryOperationStatusView())
->setUser($viewer)
->setOperation($operation);
if ($request->isAjax()) {
$payload = array(
'markup' => $status_view->renderUnderwayState(),
'isUnderway' => $operation->isUnderway(),
);
return id(new AphrontAjaxResponse())
->setContent($payload);
}
$title = pht('Repository Operation %d', $id);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Operations'),
$this->getApplicationURI('operation/'));
$crumbs->addTextCrumb($title);
return $this->buildApplicationPage(
array(
$crumbs,
$status_view,
),
array(
'title' => array(
$title,
pht('Status'),
),
));
}
}

View file

@ -11,6 +11,30 @@ final class DrydockLandRepositoryOperation
return pht('Land Revision'); return pht('Land Revision');
} }
public function getOperationCurrentStatus(
DrydockRepositoryOperation $operation,
PhabricatorUser $viewer) {
$target = $operation->getRepositoryTarget();
$repository = $operation->getRepository();
switch ($operation->getOperationState()) {
case DrydockRepositoryOperation::STATE_WAIT:
return pht(
'Waiting to land revision into %s on %s...',
$repository->getMonogram(),
$target);
case DrydockRepositoryOperation::STATE_WORK:
return pht(
'Landing revision into %s on %s...',
$repository->getMonogram(),
$target);
case DrydockRepositoryOperation::STATE_DONE:
return pht(
'Revision landed into %s.',
$repository->getMonogram());
}
}
public function applyOperation( public function applyOperation(
DrydockRepositoryOperation $operation, DrydockRepositoryOperation $operation,
DrydockInterface $interface) { DrydockInterface $interface) {

View file

@ -12,6 +12,10 @@ abstract class DrydockRepositoryOperationType extends Phobject {
DrydockRepositoryOperation $operation, DrydockRepositoryOperation $operation,
PhabricatorUser $viewer); PhabricatorUser $viewer);
abstract public function getOperationCurrentStatus(
DrydockRepositoryOperation $operation,
PhabricatorUser $viewer);
final public function setViewer(PhabricatorUser $viewer) { final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer; $this->viewer = $viewer;
return $this; return $this;

View file

@ -142,6 +142,22 @@ final class DrydockRepositoryOperation extends DrydockDAO
$viewer); $viewer);
} }
public function getOperationCurrentStatus(PhabricatorUser $viewer) {
return $this->getImplementation()->getOperationCurrentStatus(
$this,
$viewer);
}
public function isUnderway() {
switch ($this->getOperationState()) {
case self::STATE_WAIT:
case self::STATE_WORK:
return true;
}
return false;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -0,0 +1,84 @@
<?php
final class DrydockRepositoryOperationStatusView
extends AphrontView {
private $operation;
private $boxView;
public function setOperation(DrydockRepositoryOperation $operation) {
$this->operation = $operation;
return $this;
}
public function getOperation() {
return $this->operation;
}
public function setBoxView(PHUIObjectBoxView $box_view) {
$this->boxView = $box_view;
return $this;
}
public function getBoxView() {
return $this->boxView;
}
public function render() {
$viewer = $this->getUser();
$operation = $this->getOperation();
$list = $this->renderUnderwayState();
// If the operation is currently underway, refresh the status view.
if ($operation->isUnderway()) {
$status_id = celerity_generate_unique_node_id();
$id = $operation->getID();
$list->setID($status_id);
Javelin::initBehavior(
'drydock-live-operation-status',
array(
'statusID' => $status_id,
'updateURI' => "/drydock/operation/{$id}/status/",
));
}
$box_view = $this->getBoxView();
if (!$box_view) {
$box_view = id(new PHUIObjectBoxView())
->setHeaderText(pht('Operation Status'));
}
$box_view->setObjectList($list);
return $box_view;
}
public function renderUnderwayState() {
$viewer = $this->getUser();
$operation = $this->getOperation();
$id = $operation->getID();
$state = $operation->getOperationState();
$icon = DrydockRepositoryOperation::getOperationStateIcon($state);
$name = DrydockRepositoryOperation::getOperationStateName($state);
$item = id(new PHUIObjectItemView())
->setHref("/drydock/operation/{$id}/")
->setHeader($operation->getOperationDescription($viewer))
->setStatusIcon($icon, $name);
if ($state != DrydockRepositoryOperation::STATE_FAIL) {
$item->addAttribute($operation->getOperationCurrentStatus($viewer));
} else {
// TODO: Make this more useful.
$item->addAttribute(pht('Operation encountered an error.'));
}
return id(new PHUIObjectItemListView())
->addItem($item);
}
}

View file

@ -381,7 +381,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
private function buildActionView(ManiphestTask $task) { private function buildActionView(ManiphestTask $task) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getRequest()->getUser();
$viewer_phid = $viewer->getPHID();
$id = $task->getID(); $id = $task->getID();
$phid = $task->getPHID(); $phid = $task->getPHID();
@ -391,6 +390,8 @@ final class ManiphestTaskDetailController extends ManiphestController {
$task, $task,
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
$can_create = $viewer->isLoggedIn();
$view = id(new PhabricatorActionListView()) $view = id(new PhabricatorActionListView())
->setUser($viewer) ->setUser($viewer)
->setObject($task) ->setObject($task)
@ -417,7 +418,9 @@ final class ManiphestTaskDetailController extends ManiphestController {
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Create Subtask')) ->setName(pht('Create Subtask'))
->setHref($this->getApplicationURI("/task/create/?parent={$id}")) ->setHref($this->getApplicationURI("/task/create/?parent={$id}"))
->setIcon('fa-level-down')); ->setIcon('fa-level-down')
->setDisabled(!$can_create)
->setWorkflow(!$can_create));
$view->addAction( $view->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())

View file

@ -145,7 +145,12 @@ final class PhabricatorApplicationEditController
->setViewer($user) ->setViewer($user)
->setObject($template_object) ->setObject($template_object)
->execute(); ->execute();
$control->setPolicies($template_policies);
// NOTE: We want to expose both any object template policies
// (like "Subscribers") and any custom policy.
$all_policies = $template_policies + $policies;
$control->setPolicies($all_policies);
$control->setTemplateObject($template_object); $control->setTemplateObject($template_object);
} }
} }

View file

@ -54,9 +54,7 @@ final class PhabricatorContentSource extends Phobject {
public static function newFromRequest(AphrontRequest $request) { public static function newFromRequest(AphrontRequest $request) {
return self::newForSource( return self::newForSource(
self::SOURCE_WEB, self::SOURCE_WEB,
array( array());
'ip' => $request->getRemoteAddr(),
));
} }
public static function newFromConduitRequest(ConduitAPIRequest $request) { public static function newFromConduitRequest(ConduitAPIRequest $request) {

View file

@ -39,13 +39,11 @@ abstract class PhabricatorPasteController extends PhabricatorController {
public function buildSourceCodeView( public function buildSourceCodeView(
PhabricatorPaste $paste, PhabricatorPaste $paste,
$max_lines = null,
$highlights = array()) { $highlights = array()) {
$lines = phutil_split_lines($paste->getContent()); $lines = phutil_split_lines($paste->getContent());
return id(new PhabricatorSourceCodeView()) return id(new PhabricatorSourceCodeView())
->setLimit($max_lines)
->setLines($lines) ->setLines($lines)
->setHighlights($highlights) ->setHighlights($highlights)
->setURI(new PhutilURI($paste->getURI())); ->setURI(new PhutilURI($paste->getURI()));

View file

@ -56,10 +56,7 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
->setHeader($header) ->setHeader($header)
->addPropertyList($properties); ->addPropertyList($properties);
$source_code = $this->buildSourceCodeView( $source_code = $this->buildSourceCodeView($paste, $this->highlightMap);
$paste,
null,
$this->highlightMap);
require_celerity_resource('paste-css'); require_celerity_resource('paste-css');
$source_code = phutil_tag( $source_code = phutil_tag(

View file

@ -10,6 +10,7 @@ final class PhabricatorPasteQuery
private $needContent; private $needContent;
private $needRawContent; private $needRawContent;
private $needSnippets;
private $languages; private $languages;
private $includeNoLanguage; private $includeNoLanguage;
private $dateCreatedAfter; private $dateCreatedAfter;
@ -47,6 +48,11 @@ final class PhabricatorPasteQuery
return $this; return $this;
} }
public function needSnippets($need_snippets) {
$this->needSnippets = $need_snippets;
return $this;
}
public function withLanguages(array $languages) { public function withLanguages(array $languages) {
$this->includeNoLanguage = false; $this->includeNoLanguage = false;
foreach ($languages as $key => $language) { foreach ($languages as $key => $language) {
@ -91,6 +97,10 @@ final class PhabricatorPasteQuery
$pastes = $this->loadContent($pastes); $pastes = $this->loadContent($pastes);
} }
if ($this->needSnippets) {
$pastes = $this->loadSnippets($pastes);
}
return $pastes; return $pastes;
} }
@ -166,6 +176,17 @@ final class PhabricatorPasteQuery
)); ));
} }
private function getSnippetCacheKey(PhabricatorPaste $paste) {
return implode(
':',
array(
'P'.$paste->getID(),
$paste->getFilePHID(),
$paste->getLanguage(),
'snippet',
));
}
private function loadRawContent(array $pastes) { private function loadRawContent(array $pastes) {
$file_phids = mpull($pastes, 'getFilePHID'); $file_phids = mpull($pastes, 'getFilePHID');
$files = id(new PhabricatorFileQuery()) $files = id(new PhabricatorFileQuery())
@ -250,19 +271,114 @@ final class PhabricatorPasteQuery
return $pastes; return $pastes;
} }
private function buildContent(PhabricatorPaste $paste) { private function loadSnippets(array $pastes) {
$language = $paste->getLanguage(); $cache = new PhabricatorKeyValueDatabaseCache();
$source = $paste->getRawContent();
if (empty($language)) { $cache = new PhutilKeyValueCacheProfiler($cache);
return PhabricatorSyntaxHighlighter::highlightWithFilename( $cache->setProfiler(PhutilServiceProfiler::getInstance());
$paste->getTitle(),
$source); $keys = array();
} else { foreach ($pastes as $paste) {
return PhabricatorSyntaxHighlighter::highlightWithLanguage( $keys[] = $this->getSnippetCacheKey($paste);
$language,
$source);
} }
$caches = $cache->getKeys($keys);
$need_raw = array();
$have_cache = array();
foreach ($pastes as $paste) {
$key = $this->getSnippetCacheKey($paste);
if (isset($caches[$key])) {
$snippet_data = phutil_json_decode($caches[$key], true);
$snippet = new PhabricatorPasteSnippet(
phutil_safe_html($snippet_data['content']),
$snippet_data['type']);
$paste->attachSnippet($snippet);
$have_cache[$paste->getPHID()] = true;
} else {
$need_raw[$key] = $paste;
}
}
if (!$need_raw) {
return $pastes;
}
$write_data = array();
$have_raw = $this->loadRawContent($need_raw);
$have_raw = mpull($have_raw, null, 'getPHID');
foreach ($pastes as $key => $paste) {
$paste_phid = $paste->getPHID();
if (isset($have_cache[$paste_phid])) {
continue;
}
if (empty($have_raw[$paste_phid])) {
unset($pastes[$key]);
continue;
}
$snippet = $this->buildSnippet($paste);
$paste->attachSnippet($snippet);
$snippet_data = array(
'content' => (string)$snippet->getContent(),
'type' => (string)$snippet->getType(),
);
$write_data[$this->getSnippetCacheKey($paste)] = phutil_json_encode(
$snippet_data);
}
if ($write_data) {
$cache->setKeys($write_data);
}
return $pastes;
}
private function buildContent(PhabricatorPaste $paste) {
return $this->highlightSource(
$paste->getRawContent(),
$paste->getTitle(),
$paste->getLanguage());
}
private function buildSnippet(PhabricatorPaste $paste) {
$snippet_type = PhabricatorPasteSnippet::FULL;
$snippet = $paste->getRawContent();
if (strlen($snippet) > 1024) {
$snippet_type = PhabricatorPasteSnippet::FIRST_BYTES;
$snippet = id(new PhutilUTF8StringTruncator())
->setMaximumBytes(1024)
->setTerminator('')
->truncateString($snippet);
}
$lines = phutil_split_lines($snippet);
if (count($lines) > 5) {
$snippet_type = PhabricatorPasteSnippet::FIRST_LINES;
$snippet = implode('', array_slice($lines, 0, 5));
}
return new PhabricatorPasteSnippet(
$this->highlightSource(
$snippet,
$paste->getTitle(),
$paste->getLanguage()),
$snippet_type);
}
private function highlightSource($source, $title, $language) {
if (empty($language)) {
return PhabricatorSyntaxHighlighter::highlightWithFilename(
$title,
$source);
} else {
return PhabricatorSyntaxHighlighter::highlightWithLanguage(
$language,
$source);
}
} }
public function getQueryApplicationClass() { public function getQueryApplicationClass() {

View file

@ -13,7 +13,7 @@ final class PhabricatorPasteSearchEngine
public function newQuery() { public function newQuery() {
return id(new PhabricatorPasteQuery()) return id(new PhabricatorPasteQuery())
->needContent(true); ->needSnippets(true);
} }
protected function buildQueryFromParameters(array $map) { protected function buildQueryFromParameters(array $map) {
@ -136,11 +136,15 @@ final class PhabricatorPasteSearchEngine
$created = phabricator_date($paste->getDateCreated(), $viewer); $created = phabricator_date($paste->getDateCreated(), $viewer);
$author = $handles[$paste->getAuthorPHID()]->renderLink(); $author = $handles[$paste->getAuthorPHID()]->renderLink();
$lines = phutil_split_lines($paste->getContent()); $snippet_type = $paste->getSnippet()->getType();
$lines = phutil_split_lines($paste->getSnippet()->getContent());
$preview = id(new PhabricatorSourceCodeView()) $preview = id(new PhabricatorSourceCodeView())
->setLimit(5)
->setLines($lines) ->setLines($lines)
->setTruncatedFirstBytes(
$snippet_type == PhabricatorPasteSnippet::FIRST_BYTES)
->setTruncatedFirstLines(
$snippet_type == PhabricatorPasteSnippet::FIRST_LINES)
->setURI(new PhutilURI($paste->getURI())); ->setURI(new PhutilURI($paste->getURI()));
$source_code = phutil_tag( $source_code = phutil_tag(

View file

@ -0,0 +1,24 @@
<?php
final class PhabricatorPasteSnippet extends Phobject {
const FULL = 'full';
const FIRST_LINES = 'first_lines';
const FIRST_BYTES = 'first_bytes';
private $content;
private $type;
public function __construct($content, $type) {
$this->content = $content;
$this->type = $type;
}
public function getContent() {
return $this->content;
}
public function getType() {
return $this->type;
}
}

View file

@ -28,6 +28,7 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
private $content = self::ATTACHABLE; private $content = self::ATTACHABLE;
private $rawContent = self::ATTACHABLE; private $rawContent = self::ATTACHABLE;
private $snippet = self::ATTACHABLE;
public static function initializeNewPaste(PhabricatorUser $actor) { public static function initializeNewPaste(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery()) $app = id(new PhabricatorApplicationQuery())
@ -135,6 +136,15 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
return $this; return $this;
} }
public function getSnippet() {
return $this->assertAttached($this->snippet);
}
public function attachSnippet(PhabricatorPasteSnippet $snippet) {
$this->snippet = $snippet;
return $this;
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */ /* -( PhabricatorSubscribableInterface )----------------------------------- */

View file

@ -2,35 +2,29 @@
final class PhluxEditController extends PhluxController { final class PhluxEditController extends PhluxController {
private $key; public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$key = $request->getURIData('key');
public function willProcessRequest(array $data) { $is_new = ($key === null);
$this->key = idx($data, 'key');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$is_new = ($this->key === null);
if ($is_new) { if ($is_new) {
$var = new PhluxVariable(); $var = new PhluxVariable();
$var->setViewPolicy(PhabricatorPolicies::POLICY_USER); $var->setViewPolicy(PhabricatorPolicies::POLICY_USER);
$var->setEditPolicy(PhabricatorPolicies::POLICY_USER); $var->setEditPolicy(PhabricatorPolicies::POLICY_USER);
} else { } else {
$var = id(new PhluxVariableQuery()) $var = id(new PhluxVariableQuery())
->setViewer($user) ->setViewer($viewer)
->requireCapabilities( ->requireCapabilities(
array( array(
PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_EDIT,
)) ))
->withKeys(array($this->key)) ->withKeys(array($key))
->executeOne(); ->executeOne();
if (!$var) { if (!$var) {
return new Aphront404Response(); return new Aphront404Response();
} }
$view_uri = $this->getApplicationURI('/view/'.$this->key.'/'); $view_uri = $this->getApplicationURI('/view/'.$key.'/');
} }
$e_key = ($is_new ? true : null); $e_key = ($is_new ? true : null);
@ -67,7 +61,7 @@ final class PhluxEditController extends PhluxController {
if (!$errors) { if (!$errors) {
$editor = id(new PhluxVariableEditor()) $editor = id(new PhluxVariableEditor())
->setActor($user) ->setActor($viewer)
->setContinueOnNoEffect(true) ->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request); ->setContentSourceFromRequest($request);
@ -110,12 +104,12 @@ final class PhluxEditController extends PhluxController {
} }
$policies = id(new PhabricatorPolicyQuery()) $policies = id(new PhabricatorPolicyQuery())
->setViewer($user) ->setViewer($viewer)
->setObject($var) ->setObject($var)
->execute(); ->execute();
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->setUser($viewer)
->appendChild( ->appendChild(
id(new AphrontFormTextControl()) id(new AphrontFormTextControl())
->setValue($var->getVariableKey()) ->setValue($var->getVariableKey())
@ -161,7 +155,7 @@ final class PhluxEditController extends PhluxController {
$title = pht('Create Variable'); $title = pht('Create Variable');
$crumbs->addTextCrumb($title, $request->getRequestURI()); $crumbs->addTextCrumb($title, $request->getRequestURI());
} else { } else {
$title = pht('Edit %s', $this->key); $title = pht('Edit %s', $key);
$crumbs->addTextCrumb($title, $request->getRequestURI()); $crumbs->addTextCrumb($title, $request->getRequestURI());
} }

View file

@ -2,14 +2,13 @@
final class PhluxListController extends PhluxController { final class PhluxListController extends PhluxController {
public function processRequest() { public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest(); $viewer = $this->getViewer();
$user = $request->getUser();
$pager = new AphrontCursorPagerView(); $pager = new AphrontCursorPagerView();
$pager->readFromRequest($request); $pager->readFromRequest($request);
$query = id(new PhluxVariableQuery()) $query = id(new PhluxVariableQuery())
->setViewer($user); ->setViewer($viewer);
$vars = $query->executeWithCursorPager($pager); $vars = $query->executeWithCursorPager($pager);
@ -22,7 +21,7 @@ final class PhluxListController extends PhluxController {
$item->setHref($this->getApplicationURI('/view/'.$key.'/')); $item->setHref($this->getApplicationURI('/view/'.$key.'/'));
$item->addIcon( $item->addIcon(
'none', 'none',
phabricator_datetime($var->getDateModified(), $user)); phabricator_datetime($var->getDateModified(), $viewer));
$view->addItem($item); $view->addItem($item);
} }

View file

@ -2,19 +2,13 @@
final class PhluxViewController extends PhluxController { final class PhluxViewController extends PhluxController {
private $key; public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
public function willProcessRequest(array $data) { $key = $request->getURIData('key');
$this->key = $data['key'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$var = id(new PhluxVariableQuery()) $var = id(new PhluxVariableQuery())
->setViewer($user) ->setViewer($viewer)
->withKeys(array($this->key)) ->withKeys(array($key))
->executeOne(); ->executeOne();
if (!$var) { if (!$var) {
@ -29,16 +23,16 @@ final class PhluxViewController extends PhluxController {
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($title) ->setHeader($title)
->setUser($user) ->setUser($viewer)
->setPolicyObject($var); ->setPolicyObject($var);
$actions = id(new PhabricatorActionListView()) $actions = id(new PhabricatorActionListView())
->setUser($user) ->setUser($viewer)
->setObjectURI($request->getRequestURI()) ->setObjectURI($request->getRequestURI())
->setObject($var); ->setObject($var);
$can_edit = PhabricatorPolicyFilter::hasCapability( $can_edit = PhabricatorPolicyFilter::hasCapability(
$user, $viewer,
$var, $var,
PhabricatorPolicyCapability::CAN_EDIT); PhabricatorPolicyCapability::CAN_EDIT);
@ -53,7 +47,7 @@ final class PhluxViewController extends PhluxController {
$display_value = json_encode($var->getVariableValue()); $display_value = json_encode($var->getVariableValue());
$properties = id(new PHUIPropertyListView()) $properties = id(new PHUIPropertyListView())
->setUser($user) ->setUser($viewer)
->setObject($var) ->setObject($var)
->setActionList($actions) ->setActionList($actions)
->addProperty(pht('Value'), $display_value); ->addProperty(pht('Value'), $display_value);

View file

@ -67,6 +67,13 @@ final class PhabricatorProjectBoardViewController
// TODO: Expand the checks here if we add the ability // TODO: Expand the checks here if we add the ability
// to hide the Backlog column // to hide the Backlog column
if (!$columns) { if (!$columns) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_EDIT);
if (!$can_edit) {
return $this->noAccessDialog($project);
}
switch ($request->getStr('initialize-type')) { switch ($request->getStr('initialize-type')) {
case 'backlog-only': case 'backlog-only':
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
@ -713,6 +720,20 @@ final class PhabricatorProjectBoardViewController
->setDialog($dialog); ->setDialog($dialog);
} }
private function noAccessDialog(PhabricatorProject $project) {
$instructions = pht('This workboard has not been setup yet.');
$dialog = id(new AphrontDialogView())
->setUser($this->getRequest()->getUser())
->setTitle(pht('No Workboard'))
->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/'))
->appendParagraph($instructions);
return id(new AphrontDialogResponse())
->setDialog($dialog);
}
/** /**
* Add current state parameters (like order and the visibility of hidden * Add current state parameters (like order and the visibility of hidden

View file

@ -5,19 +5,12 @@ final class PhabricatorSearchController
const SCOPE_CURRENT_APPLICATION = 'application'; const SCOPE_CURRENT_APPLICATION = 'application';
private $queryKey;
public function shouldAllowPublic() { public function shouldAllowPublic() {
return true; return true;
} }
public function willProcessRequest(array $data) { public function handleRequest(AphrontRequest $request) {
$this->queryKey = idx($data, 'queryKey'); $viewer = $this->getViewer();
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
if ($request->getStr('jump') != 'no') { if ($request->getStr('jump') != 'no') {
$pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP; $pref_jump = PhabricatorUserPreferences::PREFERENCE_SEARCHBAR_JUMP;
@ -97,7 +90,7 @@ final class PhabricatorSearchController
} }
$controller = id(new PhabricatorApplicationSearchController()) $controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($this->queryKey) ->setQueryKey($request->getURIData('queryKey'))
->setSearchEngine($engine) ->setSearchEngine($engine)
->setNavigation($this->buildSideNavView()); ->setNavigation($this->buildSideNavView());
@ -105,7 +98,7 @@ final class PhabricatorSearchController
} }
public function buildSideNavView($for_app = false) { public function buildSideNavView($for_app = false) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getViewer();
$nav = new AphrontSideNavFilterView(); $nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI())); $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));

View file

@ -3,33 +3,24 @@
final class PhabricatorSearchDeleteController final class PhabricatorSearchDeleteController
extends PhabricatorSearchBaseController { extends PhabricatorSearchBaseController {
private $queryKey; public function handleRequest(AphrontRequest $request) {
private $engineClass; $viewer = $this->getViewer();
$key = $request->getURIData('queryKey');
public function willProcessRequest(array $data) { $engine_class = $request->getURIData('engine');
$this->queryKey = idx($data, 'queryKey');
$this->engineClass = idx($data, 'engine');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$key = $this->queryKey;
$base_class = 'PhabricatorApplicationSearchEngine'; $base_class = 'PhabricatorApplicationSearchEngine';
if (!is_subclass_of($this->engineClass, $base_class)) { if (!is_subclass_of($engine_class, $base_class)) {
return new Aphront400Response(); return new Aphront400Response();
} }
$engine = newv($this->engineClass, array()); $engine = newv($engine_class, array());
$engine->setViewer($user); $engine->setViewer($viewer);
$named_query = id(new PhabricatorNamedQueryQuery()) $named_query = id(new PhabricatorNamedQueryQuery())
->setViewer($user) ->setViewer($viewer)
->withEngineClassNames(array($this->engineClass)) ->withEngineClassNames(array($engine_class))
->withQueryKeys(array($key)) ->withQueryKeys(array($key))
->withUserPHIDs(array($user->getPHID())) ->withUserPHIDs(array($viewer->getPHID()))
->executeOne(); ->executeOne();
if (!$named_query && $engine->isBuiltinQuery($key)) { if (!$named_query && $engine->isBuiltinQuery($key)) {
@ -84,7 +75,7 @@ final class PhabricatorSearchDeleteController
} }
$dialog = id(new AphrontDialogView()) $dialog = id(new AphrontDialogView())
->setUser($user) ->setUser($viewer)
->setTitle($title) ->setTitle($title)
->appendChild($desc) ->appendChild($desc)
->addCancelButton($return_uri) ->addCancelButton($return_uri)

View file

@ -3,38 +3,31 @@
final class PhabricatorSearchEditController final class PhabricatorSearchEditController
extends PhabricatorSearchBaseController { extends PhabricatorSearchBaseController {
private $queryKey; public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
public function willProcessRequest(array $data) {
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$saved_query = id(new PhabricatorSavedQueryQuery()) $saved_query = id(new PhabricatorSavedQueryQuery())
->setViewer($user) ->setViewer($viewer)
->withQueryKeys(array($this->queryKey)) ->withQueryKeys(array($request->getURIData('queryKey')))
->executeOne(); ->executeOne();
if (!$saved_query) { if (!$saved_query) {
return new Aphront404Response(); return new Aphront404Response();
} }
$engine = $saved_query->newEngine()->setViewer($user); $engine = $saved_query->newEngine()->setViewer($viewer);
$complete_uri = $engine->getQueryManagementURI(); $complete_uri = $engine->getQueryManagementURI();
$cancel_uri = $complete_uri; $cancel_uri = $complete_uri;
$named_query = id(new PhabricatorNamedQueryQuery()) $named_query = id(new PhabricatorNamedQueryQuery())
->setViewer($user) ->setViewer($viewer)
->withQueryKeys(array($saved_query->getQueryKey())) ->withQueryKeys(array($saved_query->getQueryKey()))
->withUserPHIDs(array($user->getPHID())) ->withUserPHIDs(array($viewer->getPHID()))
->executeOne(); ->executeOne();
if (!$named_query) { if (!$named_query) {
$named_query = id(new PhabricatorNamedQuery()) $named_query = id(new PhabricatorNamedQuery())
->setUserPHID($user->getPHID()) ->setUserPHID($viewer->getPHID())
->setQueryKey($saved_query->getQueryKey()) ->setQueryKey($saved_query->getQueryKey())
->setEngineClassName($saved_query->getEngineClassName()); ->setEngineClassName($saved_query->getEngineClassName());
@ -64,7 +57,7 @@ final class PhabricatorSearchEditController
} }
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user); ->setUser($viewer);
$form->appendChild( $form->appendChild(
id(new AphrontFormTextControl()) id(new AphrontFormTextControl())

View file

@ -9,7 +9,6 @@ final class PhabricatorSearchHovercardController
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer(); $viewer = $this->getViewer();
$phids = $request->getArr('phids'); $phids = $request->getArr('phids');
$handles = id(new PhabricatorHandleQuery()) $handles = id(new PhabricatorHandleQuery())

View file

@ -3,25 +3,19 @@
final class PhabricatorSearchOrderController final class PhabricatorSearchOrderController
extends PhabricatorSearchBaseController { extends PhabricatorSearchBaseController {
private $engineClass; public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
public function willProcessRequest(array $data) { $engine_class = $request->getURIData('engine');
$this->engineClass = idx($data, 'engine');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$request->validateCSRF(); $request->validateCSRF();
$base_class = 'PhabricatorApplicationSearchEngine'; $base_class = 'PhabricatorApplicationSearchEngine';
if (!is_subclass_of($this->engineClass, $base_class)) { if (!is_subclass_of($engine_class, $base_class)) {
return new Aphront400Response(); return new Aphront400Response();
} }
$engine = newv($this->engineClass, array()); $engine = newv($engine_class, array());
$engine->setViewer($user); $engine->setViewer($viewer);
$queries = $engine->loadAllNamedQueries(); $queries = $engine->loadAllNamedQueries();
$queries = mpull($queries, null, 'getQueryKey'); $queries = mpull($queries, null, 'getQueryKey');

View file

@ -31,6 +31,9 @@
}, },
"fieldmanual": { "fieldmanual": {
"name": "Field Manuals" "name": "Field Manuals"
},
"cellar": {
"name": "Musty Cellar"
} }
} }
} }

View file

@ -3,6 +3,14 @@
Describes how to file an effective Phabricator bug report. Describes how to file an effective Phabricator bug report.
Include Reproduction Steps!
===========================
IMPORTANT: When filing a bug report, you **MUST** include reproduction
instructions. We can not help fix bugs we can not reproduce, and will not
accept reports which omit reproduction instructions. See below for details.
Overview Overview
======== ========
@ -28,6 +36,7 @@ If you have a feature request (not a bug report), see
For general information on contributing to Phabricator, see For general information on contributing to Phabricator, see
@{article:Contributor Introduction}. @{article:Contributor Introduction}.
Common Fixes Common Fixes
============ ============
@ -73,6 +82,9 @@ Supported Issues
Before filing a bug, make sure you're filing an issue against something we Before filing a bug, make sure you're filing an issue against something we
support. support.
**We can NOT help you with issues we can not reproduce.** It is critical that
you explain how to reproduce the issue when filing a report.
**We do NOT support prototype applications.** If you're running into an issue **We do NOT support prototype applications.** If you're running into an issue
with a prototype application, you're on your own. For more information about with a prototype application, you're on your own. For more information about
prototype applications, see @{article:User Guide: Prototype Applications}. prototype applications, see @{article:User Guide: Prototype Applications}.
@ -101,6 +113,7 @@ Otherwise, if you're having an issue with a supported first-party application
and followed the upstream install instructions on a normal computer, we're happy and followed the upstream install instructions on a normal computer, we're happy
to try to help. to try to help.
Getting More Information Getting More Information
======================== ========================
@ -121,6 +134,7 @@ help us figure out and resolve an issue.
troubleshooting. Adjusting settings or enabling debugging modes may give troubleshooting. Adjusting settings or enabling debugging modes may give
you more information about the issue. you more information about the issue.
Reproducibility Reproducibility
=============== ===============
@ -135,7 +149,9 @@ trouble narrowing something down or want to check if updating might fix an
issue. issue.
It is nearly impossible for us to resolve many issues if we can not reproduce It is nearly impossible for us to resolve many issues if we can not reproduce
them. them. We will not accept reports which do not contain the information required
to reproduce problems.
Unreproducible Problems Unreproducible Problems
======================= =======================
@ -161,6 +177,7 @@ We will make a reasonable effort to reproduce problems, but can not help with
issues which we can't reproduce. You can make sure we're able to help resolve issues which we can't reproduce. You can make sure we're able to help resolve
your issue by generating clear reproduction steps. your issue by generating clear reproduction steps.
Create a Task in Maniphest Create a Task in Maniphest
========================== ==========================
@ -168,11 +185,10 @@ If you're up to date, supported, have collected information about the problem,
and have the best reproduction instructions you can come up with, you're ready and have the best reproduction instructions you can come up with, you're ready
to file an issue. to file an issue.
We'll look at any issue report we can find (we monitor IRC, email, It is **particularly critical** that you include reproduction steps. We will
StackOverflow, Quora, Facebook and Twitter), but the upstream Maniphest is the not accept reports which describe issues we can not reproduce.
authoritative bug tracker and the best place to file:
https://secure.phabricator.com/maniphest/task/create/ (NOTE) https://secure.phabricator.com/maniphest/task/create/
If you don't want to file there (or, for example, your bug relates to being If you don't want to file there (or, for example, your bug relates to being
unable to log in or unable to file an issue in Maniphest) you can file on any unable to log in or unable to file an issue in Maniphest) you can file on any
@ -182,12 +198,9 @@ filed against the upstream than if they're filed somewhere else.
| Effectiveness | Filing Method | | Effectiveness | Filing Method |
|---|---| |---|---|
| Best | Upstream Maniphest | | Best | Upstream Maniphest |
| Ehhh | Quora, StackOverflow, Facebook, email, etc. | | Ehhh | Quora, StackOverflow, Facebook, Jelly, email, etc. |
| What | Passive-aggressive tweet | | What | Passive-aggressive tweet |
If you have a quick question or want to discuss something before filing an
issue, IRC is a great way to get a sanity check first. You can find information
about IRC in @{article: Give Feedback! Get Support!}.
Next Steps Next Steps
========== ==========
@ -195,6 +208,5 @@ Next Steps
Continue by: Continue by:
- learning about @{article: Contributing Feature Requests}; or - learning about @{article: Contributing Feature Requests}; or
- reading general support information in - reading general support information in @{article:Support Resources}; or
@{article: Give Feedback! Get Support!}; or
- returning to the @{article:Contributor Introduction}. - returning to the @{article:Contributor Introduction}.

View file

@ -23,8 +23,7 @@ contribute to Phabricator:
- Send us an email or drop by IRC just to say "thanks". A big part of the - Send us an email or drop by IRC just to say "thanks". A big part of the
reason we build this software is to help people solve problems, and knowing reason we build this software is to help people solve problems, and knowing
that our efforts are appreciated is really rewarding. You can find ways to that our efforts are appreciated is really rewarding.
get in touch in @{article:Give Feedback! Get Support!}
- Recommend Phabricator to people who you think might find it useful. Our - Recommend Phabricator to people who you think might find it useful. Our
most powerful growth channel is word of mouth, and mentioning or tweeting most powerful growth channel is word of mouth, and mentioning or tweeting
about Phabricator helps the project grow. If writing a tweet sounds like about Phabricator helps the project grow. If writing a tweet sounds like
@ -40,7 +39,6 @@ contribute to Phabricator:
- Report bugs and request features. We may not always be able to fix or build - Report bugs and request features. We may not always be able to fix or build
things right away, but knowing about issues users are encountering or things right away, but knowing about issues users are encountering or
features they'd like to see improves our ability to plan and prioritize. features they'd like to see improves our ability to plan and prioritize.
For ways to do this, see @{article:Give Feedback! Get Support!}
- For details on reporting bugs, see @{article:Contributing Bug Reports}. - For details on reporting bugs, see @{article:Contributing Bug Reports}.
- For details on requesting features, see @{article:Contributing Feature - For details on requesting features, see @{article:Contributing Feature
Requests}. Requests}.
@ -48,16 +46,11 @@ contribute to Phabricator:
6-12 months currently exists on the [[ Roadmap ]] or in Maniphest. Telling 6-12 months currently exists on the [[ Roadmap ]] or in Maniphest. Telling
us about use cases you have can help us build better products when the time us about use cases you have can help us build better products when the time
comes to write the code. comes to write the code.
- Hang out in IRC, and maybe answer a question or two. IRC is a completely
legit place for serious hackers to hang out anyway, but while you're there
you might see someone ask a question that you know the answer to. Helping
them out (or pointing them to the right documentation) is a big help to us.
You can find details about the IRC channel in
@{article:Give Feedback! Get Support!}
If all of this sounds nice but you really just want to write some code, that's If all of this sounds nice but you really just want to write some code, be
awesome too. To get started with contributing code, see aware that this project often presents a high barrier to entry for new
@{article:Contributing Code}. contributors. To continue, see @{article:Contributing Code}.
Next Steps Next Steps
========== ==========
@ -65,6 +58,6 @@ Next Steps
Continue by: Continue by:
- learning about bug reports in @{article:Contributing Bug Reports}; - learning about bug reports in @{article:Contributing Bug Reports};
- learning about feature requests in @{article:Contributing Feature Requests}; - learning about feature requests in
- learning about code contributions in @{article:Contributing Code}; or @{article:Contributing Feature Requests}; or
- getting in touch with @{article:Give Feedback! Get Support!} - learning about code contributions in @{article:Contributing Code}.

View file

@ -3,6 +3,13 @@
Describes how to file an effective Phabricator feature request. Describes how to file an effective Phabricator feature request.
Describe Your Problem!
======================
IMPORTANT: When filing a feature request, you **MUST** describe the root
problem you are facing. We will not accept feature requests which do not
include a problem description. See below for details.
Overview Overview
======== ========
@ -138,8 +145,9 @@ upstream.
Describe Problems Describe Problems
================= =================
When you file a feature request, it is really helpful to describe the problem When you file a feature request, we need you to describe the problem you're
you're facing first, not just your desired solution. facing first, not just your desired solution. Describing the problem you are
facing is the **most important part** of a feature request.
Often, your problem may have a lot in common with other similar problems. If we Often, your problem may have a lot in common with other similar problems. If we
understand your use case we can compare it to other use cases and sometimes find understand your use case we can compare it to other use cases and sometimes find
@ -159,6 +167,10 @@ which has approximately the same effect and does fit into the product direction.
If you only describe the solution and not the problem, we can't generalize, If you only describe the solution and not the problem, we can't generalize,
contextualize, merge, reframe, or offer alternative solutions or workarounds. contextualize, merge, reframe, or offer alternative solutions or workarounds.
You must describe the problem you are facing when filing a feature request. We
will not accept feature requests which do not contextualize the request by
describing the root problem.
Hypotheticals Hypotheticals
============= =============
@ -206,13 +218,13 @@ Create a Task in Maniphest
If you think your feature might be a good fit for the upstream, have reasonable If you think your feature might be a good fit for the upstream, have reasonable
expectations about it, and have a good description of the problem you're trying expectations about it, and have a good description of the problem you're trying
to solve, you're ready to file a feature request: to solve, you're ready to file a feature request.
https://secure.phabricator.com/maniphest/task/create/ It is **particularly critical** that you describe the problem you are facing,
not just the feature you want. We will not accept feature requests which do
not describe the root problem the feature is intended to resolve.
If you have a quick question or want to discuss something before filing a (NOTE) https://secure.phabricator.com/maniphest/task/create/
request, IRC is the best way to get a quick answer. You can find information
about IRC and other support channels in @{article: Give Feedback! Get Support!}.
Next Steps Next Steps
@ -221,6 +233,5 @@ Next Steps
Continue by: Continue by:
- learning about @{article: Contributing Bug Reports}; or - learning about @{article: Contributing Bug Reports}; or
- reading general support information in - reading general support information in @{article:Support Resources}; or
@{article: Give Feedback! Get Support!}; or
- returning to the @{article:Contributor Introduction}. - returning to the @{article:Contributor Introduction}.

View file

@ -1,44 +1,7 @@
@title Give Feedback! Get Support! @title Give Feedback! Get Support!
@short Feedback/Support @short Feedback/Support
@group intro @group cellar
How to give us feedback, report bugs, and request features, and get support for Deprecated.
problems with Phabricator.
Overview This article has moved to @{article:Support Resources}.
========
We'd love to hear your feedback about Phabricator, whether it's good or bad. The
best ways to provide feedback and get support are:
- For bug reports and feature requests, file a task in our task tracker,
Maniphest.
- For questions and real-time chat, join the IRC channel.
- If you just want to provide some quick feedback, you can tweet at
us ([[ http://twitter.com/phabricator | @phabricator ]]).
Bugs and Requests
=====================
The best way to report bugs and request features is through
[[http://secure.phabricator.com/maniphest/task/create/ | Maniphest]]. For
information on filing good bug reports and feature requests, see:
- @{article:Contributing Bug Reports}
- @{article:Contributing Feature Requests}
IRC
==========
We're active in `#phabricator` on FreeNode, and it's the best place to ask
questions and get support.
Next Steps
==========
Continue by:
- learning more about bug reports with @{article:Contributing Bug Reports}; or
- learning more about feature requests with
@{article:Contributing Feature Requests}; or
- contributing to Phabricator with @{article:Contributor Introduction}.

View file

@ -3,7 +3,8 @@
Describes how to report security vulnerabilities in Phabricator. Describes how to report security vulnerabilities in Phabricator.
= Overview = Overview
========
Phabricator runs a disclosure and award program through Phabricator runs a disclosure and award program through
[[ https://www.hackerone.com/ | HackerOne ]]. This program is the best way to [[ https://www.hackerone.com/ | HackerOne ]]. This program is the best way to
@ -19,23 +20,17 @@ how to participate.
We have a 24 hour response timeline, and are usually able to respond to (and, We have a 24 hour response timeline, and are usually able to respond to (and,
very often, fix) issues more quickly than that. very often, fix) issues more quickly than that.
= Other Channels =
You can also contact us on another channel if you prefer. See Other Channels
@{article:Give Feedback! Get Support!} for a list of ways to get in touch ==============
with us.
= Getting Notified = If you aren't sure if something qualifies or don't want to report via
HackerOne, you can submit the issue as a normal bug report. For instructions,
see @{article:Contributing Bug Reports}.
When we fix significant security vulnerabilities, we currently publish
information:
- on our [[ https://www.facebook.com/phabricator | Facebook Page ]]; Get Updated
- on our [[ https://twitter.com/phabricator | Twitter Feed ]]; ===========
- and on IRC (`#phabricator` on FreeNode).
If you'd prefer to receive information on other channels, let us know. General information about security changes is reported weekly in the
[[ https://secure.phabricator.com/w/changelog/ | Changelog ]].
General information about security is reported monthly in the
[[ http://phabricator.org/changelog/ | Changelog ]]. This includes low impact
issues, reports we did not act on, and other details.

View file

@ -0,0 +1,125 @@
@title Support Resources
@short Support
@group intro
Resources for reporting bugs, requesting features, and getting support.
Overview
========
This document describes available support resources.
The upstream provides active, free support for a narrow range of problems
(primarily, security issues and reproducible bugs).
The upstream does not provide free support for general problems with installing
or configuring Phabricator. You may be able to get some help with these
kinds of issues from the community.
Reporting Security Vulnerabilities
==================================
The upstream accepts, fixes, and awards bounties for reports of material
security issues with the software.
To report security issues, see @{article:Reporting Security Vulnerabilities}.
Reporting Bugs
==============
The upstream will accept **reproducible** bug reports in modern, first-party
production code running in reasonable environments.
To report bugs, see @{article:Contributing Bug Reports}.
Requesting Features
===================
The upstream accepts feature requests which **describe problems** you would
like Phabricator to be able to solve.
To request features, see @{article:Contributing Feature Requests}.
Contributing
============
Phabricator is a very difficult project to contribute to. New contributors
will face a high barrier to entry.
If you'd like to contribute to Phabricator, start with
@{article:Contributor Introduction}.
Installation and Setup Help
===========================
Installation and setup help is available from the upstream at consulting rates.
See [[ https://secure.phabricator.com/w/consulting/ | Consulting ]] for details.
Helping individual installs navigate unique setup problems takes our time
away from developing Phabricator, so we can not offer this service for free.
You may be able to get free help with these issues from the community. See
below for details.
Hosting
=========
The upstream offers Phabricator as a hosted service at
[[ https://phacility.com | Phacility ]]. This simplifies setting up and
operating a Phabricator instance, and gives you access to a broader range
of upstream support services.
Running this service gives us a strong financial incentive to make installing
and operating Phabricator as difficult as possible. Blinded by greed, we toil
endlessly to make installation a perplexing nightmare that none other than
ourselves can hope to navigate.
Prioritization
==============
The upstream offers prioritization, a service which allows you to control
our roadmap and get features you're interested in built sooner at reasonable
rates. See
[[ https://secure.phabricator.com/w/prioritization/ | Prioritization ]] for
details.
Consulting
==========
The upstream offers general-purpose consulting services. See
[[ https://secure.phabricator.com/w/consulting/ | Consulting ]] for details.
Community
=========
These resources are not provided by the upstream. They are not official support
channels and you may not receive support here, or you may receive help which is
misleading or wrong.
You may be able to get answers to questions on sites like
[[ http://stackoverflow.com | Stack Overflow ]],
[[ https://www.quora.com | Quora ]],
[[ https://jelly.co | Jelly ]], or
[[ https://twitter.com | Twitter ]]. The upstream occasionally participates on
these sites but these are not official support channels and you should not
expect to receive a response.
There is a
[[ https://secure.phabricator.com/conpherence/1336/ | General Chat ]]
Conpherence room on this install, and you can ask questions in
[[ https://secure.phabricator.com/ponder/ | Ponder ]]. These
are not upstream support channels and you may not receive a response to
questions, but someone in the community may be able to point you in the right
direction.
There is also a community IRC channel in `#phabricator` on FreeNode.

View file

@ -129,11 +129,6 @@ able to use:
- Another common approach is to write an install script as an action into - Another common approach is to write an install script as an action into
existing build scripts, so users can run `make install-arc` or existing build scripts, so users can run `make install-arc` or
`ant install-arc` or similar. `ant install-arc` or similar.
- In general, if this sucks and is causing you pain, let us know (see
@{article:Give Feedback! Get Support!}). We're planning to improve this at
some point, but it's somewhat complicated to get right. While it can take a
little time to set up, we aren't getting feedback that it's a persistent
pain point, so it hasn't been a priority.
== Installing Tab Completion == == Installing Tab Completion ==

View file

@ -12,9 +12,6 @@ Phabricator supports two code review workflows, "review" (pre-push) and
This document summarizes the post-push "audit" workflow implemented by the This document summarizes the post-push "audit" workflow implemented by the
creatively-named //Audit// tool. creatively-named //Audit// tool.
NOTE: The audit workflow is new, give us feedback about it! See
@{article:Give Feedback! Get Support!}.
= How Audit Works = = How Audit Works =
Using auditing allows you to push and deploy code without waiting for code Using auditing allows you to push and deploy code without waiting for code
@ -104,5 +101,4 @@ only changes that are relevant to them.
= Next Steps = = Next Steps =
- Learn more about Herald at @{article:Herald User Guide}; or - Learn more about Herald at @{article:Herald User Guide}.
- give us feedback at @{article:Give Feedback! Get Support!}.

View file

@ -65,5 +65,4 @@ files affected, etc.)
- learn about handling large changesets at - learn about handling large changesets at
@{article:Differential User Guide: Large Changes}; or @{article:Differential User Guide: Large Changes}; or
- learn about test plans at @{article:Differential User Guide: Test Plans}; or - learn about test plans at @{article:Differential User Guide: Test Plans}; or
- learn more about Herald at @{article:Herald User Guide}; or - learn more about Herald at @{article:Herald User Guide}.
- give us feedback at @{article:Give Feedback! Get Support!}.

View file

@ -5,6 +5,8 @@ Journal about your thoughts and feelings. Share with others. Profit.
= Overview = = Overview =
IMPORTANT: Phame is a prototype application.
Phame is a simple blogging platform. You can write drafts which only you can Phame is a simple blogging platform. You can write drafts which only you can
see. Later, you can publish these drafts as posts which anyone who can access see. Later, you can publish these drafts as posts which anyone who can access
the Phabricator instance can see. You can also add posts to blogs to increase the Phabricator instance can see. You can also add posts to blogs to increase
@ -55,9 +57,3 @@ this functionality.
A given comment widget is tied 1:1 with a given post. This means the same A given comment widget is tied 1:1 with a given post. This means the same
instance of a given comment widget will appear for a given post regardless instance of a given comment widget will appear for a given post regardless
of whether that post is being viewed in the context of a blog. of whether that post is being viewed in the context of a blog.
= Next Steps =
- Phame is extremely new and very basic for now. Give us feedback on
what you'd like to see improve! See @{article:Give Feedback! Get
Support!}.

View file

@ -3,10 +3,8 @@
Construct a detailed written history of your civilization. Construct a detailed written history of your civilization.
= Overview = Overview
========
Phriction is a simple wiki. You can edit pages, and the text you write will stay Phriction is a simple wiki. You can edit pages, and the text you write will stay
there. Other people can see it later. there. Other people can see it later.
NOTE: Phriction is extremely new and very basic for now. Give us feedback on
what you'd like to see improve! See @{article:Give Feedback! Get Support!}.

View file

@ -50,7 +50,7 @@ final class PHUIInfoView extends AphrontView {
require_celerity_resource('phui-info-view-css'); require_celerity_resource('phui-info-view-css');
$errors = $this->errors; $errors = $this->errors;
if ($errors) { if (count($errors) > 1) {
$list = array(); $list = array();
foreach ($errors as $error) { foreach ($errors as $error) {
$list[] = phutil_tag( $list[] = phutil_tag(
@ -64,6 +64,8 @@ final class PHUIInfoView extends AphrontView {
'class' => 'phui-info-view-list', 'class' => 'phui-info-view-list',
), ),
$list); $list);
} else if (count($errors) == 1) {
$list = $this->errors[0];
} else { } else {
$list = null; $list = null;
} }

View file

@ -3,15 +3,11 @@
final class PhabricatorSourceCodeView extends AphrontView { final class PhabricatorSourceCodeView extends AphrontView {
private $lines; private $lines;
private $limit;
private $uri; private $uri;
private $highlights = array(); private $highlights = array();
private $canClickHighlight = true; private $canClickHighlight = true;
private $truncatedFirstBytes = false;
public function setLimit($limit) { private $truncatedFirstLines = false;
$this->limit = $limit;
return $this;
}
public function setLines(array $lines) { public function setLines(array $lines) {
$this->lines = $lines; $this->lines = $lines;
@ -33,6 +29,16 @@ final class PhabricatorSourceCodeView extends AphrontView {
return $this; return $this;
} }
public function setTruncatedFirstBytes($truncated_first_bytes) {
$this->truncatedFirstBytes = $truncated_first_bytes;
return $this;
}
public function setTruncatedFirstLines($truncated_first_lines) {
$this->truncatedFirstLines = $truncated_first_lines;
return $this;
}
public function render() { public function render() {
require_celerity_resource('phabricator-source-code-view-css'); require_celerity_resource('phabricator-source-code-view-css');
require_celerity_resource('syntax-highlighting-css'); require_celerity_resource('syntax-highlighting-css');
@ -46,24 +52,31 @@ final class PhabricatorSourceCodeView extends AphrontView {
$rows = array(); $rows = array();
foreach ($this->lines as $line) { $lines = $this->lines;
$hit_limit = $this->limit && if ($this->truncatedFirstLines) {
($line_number == $this->limit) && $lines[] = phutil_tag(
(count($this->lines) != $this->limit);
if ($hit_limit) {
$content_number = '';
$content_line = phutil_tag(
'span', 'span',
array( array(
'class' => 'c', 'class' => 'c',
), ),
pht('...')); pht('...'));
} else { } else if ($this->truncatedFirstBytes) {
$content_number = $line_number; $last_key = last_key($lines);
// NOTE: See phabricator-oncopy behavior. $lines[$last_key] = hsprintf(
$content_line = hsprintf("\xE2\x80\x8B%s", $line); '%s%s',
} $lines[$last_key],
phutil_tag(
'span',
array(
'class' => 'c',
),
pht('...')));
}
foreach ($lines as $line) {
// NOTE: See phabricator-oncopy behavior.
$content_line = hsprintf("\xE2\x80\x8B%s", $line);
$row_attributes = array(); $row_attributes = array();
if (isset($this->highlights[$line_number])) { if (isset($this->highlights[$line_number])) {
@ -106,10 +119,6 @@ final class PhabricatorSourceCodeView extends AphrontView {
$content_line), $content_line),
)); ));
if ($hit_limit) {
break;
}
$line_number++; $line_number++;
} }

View file

@ -0,0 +1,32 @@
/**
* @provides javelin-behavior-drydock-live-operation-status
* @requires javelin-behavior
* javelin-dom
* javelin-request
* @javelin
*/
JX.behavior('drydock-live-operation-status', function(config) {
var node = JX.$(config.statusID);
function update() {
new JX.Request(config.updateURI, onresponse)
.send();
}
function onresponse(r) {
var new_node = JX.$H(r.markup).getNode();
JX.DOM.replace(node, new_node);
node = new_node;
if (r.isUnderway) {
poll();
}
}
function poll() {
setTimeout(update, 1000);
}
poll();
});