mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-25 05:58:21 +01:00
(stable) Promote 2018 Week 31
This commit is contained in:
commit
b45047f952
32 changed files with 468 additions and 92 deletions
|
@ -9,7 +9,7 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => 'e68cf1fa',
|
||||
'conpherence.pkg.js' => '15191c65',
|
||||
'core.pkg.css' => 'e5233bff',
|
||||
'core.pkg.css' => 'f515619b',
|
||||
'core.pkg.js' => '2058ec09',
|
||||
'differential.pkg.css' => '06dc617c',
|
||||
'differential.pkg.js' => 'ef19e026',
|
||||
|
@ -154,7 +154,7 @@ return array(
|
|||
'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16',
|
||||
'rsrc/css/phui/phui-form.css' => '7aaa04e3',
|
||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||
'rsrc/css/phui/phui-header-view.css' => '31dc6c72',
|
||||
'rsrc/css/phui/phui-header-view.css' => 'edeb9252',
|
||||
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
|
||||
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
||||
'rsrc/css/phui/phui-icon.css' => 'cf24ceec',
|
||||
|
@ -821,7 +821,7 @@ return array(
|
|||
'phui-form-css' => '7aaa04e3',
|
||||
'phui-form-view-css' => 'ae9f8d16',
|
||||
'phui-head-thing-view-css' => 'fd311e5f',
|
||||
'phui-header-view-css' => '31dc6c72',
|
||||
'phui-header-view-css' => 'edeb9252',
|
||||
'phui-hovercard' => '1bd28176',
|
||||
'phui-hovercard-view-css' => 'f0592bcf',
|
||||
'phui-icon-set-selector-css' => '87db8fee',
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||
ADD spacePHID VARBINARY(64) DEFAULT NULL;
|
2
resources/sql/autopatches/20180730.project.01.spaces.sql
Normal file
2
resources/sql/autopatches/20180730.project.01.spaces.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_project.project
|
||||
ADD COLUMN spacePHID VARBINARY(64) DEFAULT NULL;
|
|
@ -27,7 +27,15 @@ $args->parsePartial(
|
|||
'param' => pht('port'),
|
||||
'help' => pht('Port number to connect to.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'options',
|
||||
'short' => 'o',
|
||||
'param' => pht('options'),
|
||||
'repeat' => true,
|
||||
'help' => pht('SSH options.'),
|
||||
),
|
||||
));
|
||||
|
||||
$unconsumed_argv = $args->getUnconsumedArgumentVector();
|
||||
|
||||
if (function_exists('pcntl_signal')) {
|
||||
|
@ -113,6 +121,25 @@ if ($port) {
|
|||
$arguments[] = $port;
|
||||
}
|
||||
|
||||
$options = $args->getArg('options');
|
||||
$allowed_ssh_options = array('SendEnv=GIT_PROTOCOL');
|
||||
|
||||
if (!empty($options)) {
|
||||
foreach ($options as $option) {
|
||||
if (array_search($option, $allowed_ssh_options) !== false) {
|
||||
$pattern[] = '-o %s';
|
||||
$arguments[] = $option;
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Disallowed ssh option "%s" given with "-o". '.
|
||||
'Allowed options are: %s.',
|
||||
$option,
|
||||
implode(', ', $allowed_ssh_options)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$pattern[] = '--';
|
||||
|
||||
$pattern[] = '%s';
|
||||
|
|
|
@ -9752,6 +9752,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFerretInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
'PhabricatorColumnProxyInterface',
|
||||
'PhabricatorSpacesInterface',
|
||||
),
|
||||
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
|
||||
'PhabricatorProjectApplication' => 'PhabricatorApplication',
|
||||
|
@ -11128,6 +11129,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
'PhabricatorPolicyCodexInterface',
|
||||
'PhabricatorSpacesInterface',
|
||||
),
|
||||
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
|
|
|
@ -9,6 +9,14 @@ final class DiffusionGetRecentCommitsByPathConduitAPIMethod
|
|||
return 'diffusion.getrecentcommitsbypath';
|
||||
}
|
||||
|
||||
public function getMethodStatus() {
|
||||
return self::METHOD_STATUS_DEPRECATED;
|
||||
}
|
||||
|
||||
public function getMethodStatusDescription() {
|
||||
return pht('Obsoleted by "diffusion.historyquery".');
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht(
|
||||
'Get commit identifiers for recent commits affecting a given path.');
|
||||
|
@ -23,6 +31,12 @@ final class DiffusionGetRecentCommitsByPathConduitAPIMethod
|
|||
);
|
||||
}
|
||||
|
||||
protected function defineErrorTypes() {
|
||||
return array(
|
||||
'ERR_NOT_FOUND' => pht('Repository was not found.'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function defineReturnType() {
|
||||
return 'nonempty list<string>';
|
||||
}
|
||||
|
@ -36,6 +50,10 @@ final class DiffusionGetRecentCommitsByPathConduitAPIMethod
|
|||
'branch' => $request->getValue('branch'),
|
||||
));
|
||||
|
||||
if ($drequest === null) {
|
||||
throw new ConduitException('ERR_NOT_FOUND');
|
||||
}
|
||||
|
||||
$limit = nonempty(
|
||||
$request->getValue('limit'),
|
||||
self::DEFAULT_LIMIT);
|
||||
|
|
|
@ -14,6 +14,8 @@ final class DiffusionPushLogListView extends AphrontView {
|
|||
$logs = $this->logs;
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$reject_herald = PhabricatorRepositoryPushLog::REJECT_HERALD;
|
||||
|
||||
$handle_phids = array();
|
||||
foreach ($logs as $log) {
|
||||
$handle_phids[] = $log->getPusherPHID();
|
||||
|
@ -21,9 +23,13 @@ final class DiffusionPushLogListView extends AphrontView {
|
|||
if ($device_phid) {
|
||||
$handle_phids[] = $device_phid;
|
||||
}
|
||||
|
||||
if ($log->getPushEvent()->getRejectCode() == $reject_herald) {
|
||||
$handle_phids[] = $log->getPushEvent()->getRejectDetails();
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($handle_phids);
|
||||
$viewer->loadHandles($handle_phids);
|
||||
|
||||
// Only administrators can view remote addresses.
|
||||
$remotes_visible = $viewer->getIsAdmin();
|
||||
|
@ -74,10 +80,17 @@ final class DiffusionPushLogListView extends AphrontView {
|
|||
$flag_names);
|
||||
|
||||
$reject_code = $log->getPushEvent()->getRejectCode();
|
||||
$reject_label = idx(
|
||||
$reject_map,
|
||||
$reject_code,
|
||||
pht('Unknown ("%s")', $reject_code));
|
||||
|
||||
if ($reject_code == $reject_herald) {
|
||||
$rule_phid = $log->getPushEvent()->getRejectDetails();
|
||||
$handle = $viewer->renderHandle($rule_phid);
|
||||
$reject_label = pht('Blocked: %s', $handle);
|
||||
} else {
|
||||
$reject_label = idx(
|
||||
$reject_map,
|
||||
$reject_code,
|
||||
pht('Unknown ("%s")', $reject_code));
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
phutil_tag(
|
||||
|
|
|
@ -159,10 +159,22 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
|
||||
public function saveAndIndex() {
|
||||
$this->save();
|
||||
PhabricatorSearchWorker::queueDocumentForIndexing($this->getPHID());
|
||||
|
||||
if ($this->isIndexableFile()) {
|
||||
PhabricatorSearchWorker::queueDocumentForIndexing($this->getPHID());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function isIndexableFile() {
|
||||
if ($this->getIsChunk()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getMonogram() {
|
||||
return 'F'.$this->getID();
|
||||
}
|
||||
|
|
|
@ -643,7 +643,13 @@ final class HarbormasterBuildLog
|
|||
$pos += $slice_length;
|
||||
|
||||
$map_bytes += $slice_length;
|
||||
$line_count += count(preg_split("/\r\n|\r|\n/", $slice)) - 1;
|
||||
|
||||
// Count newlines in the slice. This goofy approach is meaningfully
|
||||
// faster than "preg_match_all()" or "preg_split()". See PHI766.
|
||||
$n_rn = substr_count($slice, "\r\n");
|
||||
$n_r = substr_count($slice, "\r");
|
||||
$n_n = substr_count($slice, "\n");
|
||||
$line_count += ($n_rn) + ($n_r - $n_rn) + ($n_n - $n_rn);
|
||||
|
||||
if ($map_bytes >= ($marker_distance - $max_utf8_width)) {
|
||||
$map[] = array(
|
||||
|
|
|
@ -19,10 +19,18 @@ final class HeraldRuleDatasource
|
|||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$rules = id(new HeraldRuleQuery())
|
||||
->setViewer($viewer)
|
||||
->withDatasourceQuery($raw_query)
|
||||
->execute();
|
||||
$query = id(new HeraldRuleQuery())
|
||||
->setViewer($viewer);
|
||||
|
||||
if (preg_match('/^[hH]\d+\z/', $raw_query)) {
|
||||
$id = trim($raw_query, 'hH');
|
||||
$id = (int)$id;
|
||||
$query->withIDs(array($id));
|
||||
} else {
|
||||
$query->withDatasourceQuery($raw_query);
|
||||
}
|
||||
|
||||
$rules = $query->execute();
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($viewer)
|
||||
|
|
|
@ -6,6 +6,9 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
|||
private $priority;
|
||||
private $options = array();
|
||||
|
||||
private $supportsInbound = true;
|
||||
private $supportsOutbound = true;
|
||||
|
||||
final public function getAdapterType() {
|
||||
return $this->getPhobjectClassConstant('ADAPTERTYPE');
|
||||
}
|
||||
|
@ -67,6 +70,24 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
|||
return $this->priority;
|
||||
}
|
||||
|
||||
final public function setSupportsInbound($supports_inbound) {
|
||||
$this->supportsInbound = $supports_inbound;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getSupportsInbound() {
|
||||
return $this->supportsInbound;
|
||||
}
|
||||
|
||||
final public function setSupportsOutbound($supports_outbound) {
|
||||
$this->supportsOutbound = $supports_outbound;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getSupportsOutbound() {
|
||||
return $this->supportsOutbound;
|
||||
}
|
||||
|
||||
final public function getOption($key) {
|
||||
if (!array_key_exists($key, $this->options)) {
|
||||
throw new Exception(
|
||||
|
|
|
@ -17,9 +17,12 @@ final class PhabricatorMetaMTAMailgunReceiveController
|
|||
// inbound mail from any of them. Test the signature to see if it matches
|
||||
// any configured Mailgun mailer.
|
||||
|
||||
$mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(
|
||||
array(
|
||||
PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE,
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
foreach ($mailers as $mailer) {
|
||||
$api_key = $mailer->getOption('api-key');
|
||||
|
|
|
@ -12,9 +12,12 @@ final class PhabricatorMetaMTAPostmarkReceiveController
|
|||
*/
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
// Don't process requests if we don't have a configured Postmark adapter.
|
||||
$mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(
|
||||
array(
|
||||
PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE,
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
if (!$mailers) {
|
||||
return new Aphront404Response();
|
||||
|
|
|
@ -11,9 +11,12 @@ final class PhabricatorMetaMTASendGridReceiveController
|
|||
// SendGrid doesn't sign payloads so we can't be sure that SendGrid
|
||||
// actually sent this request, but require a configured SendGrid mailer
|
||||
// before we activate this endpoint.
|
||||
$mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(
|
||||
array(
|
||||
PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE,
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
if (!$mailers) {
|
||||
return new Aphront404Response();
|
||||
|
|
|
@ -168,7 +168,8 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
|
||||
$mailer_key = $args->getArg('mailer');
|
||||
if ($mailer_key !== null) {
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers();
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(array());
|
||||
|
||||
$mailers = mpull($mailers, null, 'getKey');
|
||||
if (!isset($mailers[$mailer_key])) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
|
@ -178,6 +179,13 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
implode(', ', array_keys($mailers))));
|
||||
}
|
||||
|
||||
if (!$mailers[$mailer_key]->getSupportsOutbound()) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Mailer ("%s") is not configured to support outbound mail.',
|
||||
$mailer_key));
|
||||
}
|
||||
|
||||
$mail->setTryMailers(array($mailer_key));
|
||||
}
|
||||
|
||||
|
|
|
@ -494,7 +494,10 @@ final class PhabricatorMetaMTAMail
|
|||
throw new Exception(pht('Trying to send an already-sent mail!'));
|
||||
}
|
||||
|
||||
$mailers = self::newMailers();
|
||||
$mailers = self::newMailers(
|
||||
array(
|
||||
'outbound' => true,
|
||||
));
|
||||
|
||||
$try_mailers = $this->getParam('mailers.try');
|
||||
if ($try_mailers) {
|
||||
|
@ -505,21 +508,15 @@ final class PhabricatorMetaMTAMail
|
|||
return $this->sendWithMailers($mailers);
|
||||
}
|
||||
|
||||
public static function newMailersWithTypes(array $types) {
|
||||
$mailers = self::newMailers();
|
||||
$types = array_fuse($types);
|
||||
public static function newMailers(array $constraints) {
|
||||
PhutilTypeSpec::checkMap(
|
||||
$constraints,
|
||||
array(
|
||||
'types' => 'optional list<string>',
|
||||
'inbound' => 'optional bool',
|
||||
'outbound' => 'optional bool',
|
||||
));
|
||||
|
||||
foreach ($mailers as $key => $mailer) {
|
||||
$mailer_type = $mailer->getAdapterType();
|
||||
if (!isset($types[$mailer_type])) {
|
||||
unset($mailers[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($mailers);
|
||||
}
|
||||
|
||||
public static function newMailers() {
|
||||
$mailers = array();
|
||||
|
||||
$config = PhabricatorEnv::getEnvConfig('cluster.mailers');
|
||||
|
@ -565,10 +562,45 @@ final class PhabricatorMetaMTAMail
|
|||
$options = idx($spec, 'options', array()) + $defaults;
|
||||
$mailer->setOptions($options);
|
||||
|
||||
$mailer->setSupportsInbound(idx($spec, 'inbound', true));
|
||||
$mailer->setSupportsOutbound(idx($spec, 'outbound', true));
|
||||
|
||||
$mailers[] = $mailer;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove mailers with the wrong types.
|
||||
if (isset($constraints['types'])) {
|
||||
$types = $constraints['types'];
|
||||
$types = array_fuse($types);
|
||||
foreach ($mailers as $key => $mailer) {
|
||||
$mailer_type = $mailer->getAdapterType();
|
||||
if (!isset($types[$mailer_type])) {
|
||||
unset($mailers[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're only looking for inbound mailers, remove mailers with inbound
|
||||
// support disabled.
|
||||
if (!empty($constraints['inbound'])) {
|
||||
foreach ($mailers as $key => $mailer) {
|
||||
if (!$mailer->getSupportsInbound()) {
|
||||
unset($mailers[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're only looking for outbound mailers, remove mailers with outbound
|
||||
// support disabled.
|
||||
if (!empty($constraints['outbound'])) {
|
||||
foreach ($mailers as $key => $mailer) {
|
||||
if (!$mailer->getSupportsOutbound()) {
|
||||
unset($mailers[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sorted = array();
|
||||
$groups = mgroup($mailers, 'getPriority');
|
||||
krsort($groups);
|
||||
|
@ -589,9 +621,24 @@ final class PhabricatorMetaMTAMail
|
|||
|
||||
public function sendWithMailers(array $mailers) {
|
||||
if (!$mailers) {
|
||||
$any_mailers = self::newMailers();
|
||||
|
||||
// NOTE: We can end up here with some custom list of "$mailers", like
|
||||
// from a unit test. In that case, this message could be misleading. We
|
||||
// can't really tell if the caller made up the list, so just assume they
|
||||
// aren't tricking us.
|
||||
|
||||
if ($any_mailers) {
|
||||
$void_message = pht(
|
||||
'No configured mailers support sending outbound mail.');
|
||||
} else {
|
||||
$void_message = pht(
|
||||
'No mailers are configured.');
|
||||
}
|
||||
|
||||
return $this
|
||||
->setStatus(PhabricatorMailOutboundStatus::STATUS_VOID)
|
||||
->setMessage(pht('No mailers are configured.'))
|
||||
->setMessage($void_message)
|
||||
->save();
|
||||
}
|
||||
|
||||
|
|
|
@ -118,11 +118,80 @@ final class PhabricatorMailConfigTestCase
|
|||
$this->assertTrue($saw_a1 && $saw_a2);
|
||||
}
|
||||
|
||||
private function newMailersWithConfig(array $config) {
|
||||
public function testMailerConstraints() {
|
||||
$config = array(
|
||||
array(
|
||||
'key' => 'X1',
|
||||
'type' => 'test',
|
||||
),
|
||||
array(
|
||||
'key' => 'X1-in',
|
||||
'type' => 'test',
|
||||
'outbound' => false,
|
||||
),
|
||||
array(
|
||||
'key' => 'X1-out',
|
||||
'type' => 'test',
|
||||
'inbound' => false,
|
||||
),
|
||||
array(
|
||||
'key' => 'X1-void',
|
||||
'type' => 'test',
|
||||
'inbound' => false,
|
||||
'outbound' => false,
|
||||
),
|
||||
);
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array());
|
||||
$this->assertEqual(4, count($mailers));
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array(
|
||||
'inbound' => true,
|
||||
));
|
||||
$this->assertEqual(2, count($mailers));
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array(
|
||||
'outbound' => true,
|
||||
));
|
||||
$this->assertEqual(2, count($mailers));
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array(
|
||||
'inbound' => true,
|
||||
'outbound' => true,
|
||||
));
|
||||
$this->assertEqual(1, count($mailers));
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array(
|
||||
'types' => array('test'),
|
||||
));
|
||||
$this->assertEqual(4, count($mailers));
|
||||
|
||||
$mailers = $this->newMailersWithConfig(
|
||||
$config,
|
||||
array(
|
||||
'types' => array('duck'),
|
||||
));
|
||||
$this->assertEqual(0, count($mailers));
|
||||
}
|
||||
|
||||
private function newMailersWithConfig(
|
||||
array $config,
|
||||
array $constraints = array()) {
|
||||
|
||||
$env = PhabricatorEnv::beginScopedEnv();
|
||||
$env->overrideEnvConfig('cluster.mailers', $config);
|
||||
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers();
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers($constraints);
|
||||
|
||||
unset($env);
|
||||
return $mailers;
|
||||
|
|
|
@ -254,7 +254,8 @@ final class PhrictionDocumentController
|
|||
PhrictionContent $content,
|
||||
$slug) {
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($document);
|
||||
|
@ -263,6 +264,10 @@ final class PhrictionDocumentController
|
|||
pht('Last Author'),
|
||||
$viewer->renderHandle($content->getAuthorPHID()));
|
||||
|
||||
$view->addProperty(
|
||||
pht('Last Edited'),
|
||||
phabricator_datetime($content->getDateCreated(), $viewer));
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ final class PhrictionEditController
|
|||
$v_projects = array_reverse($v_projects);
|
||||
}
|
||||
|
||||
$v_space = $document->getSpacePHID();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
||||
$title = $request->getStr('title');
|
||||
|
@ -131,6 +133,7 @@ final class PhrictionEditController
|
|||
$v_edit = $request->getStr('editPolicy');
|
||||
$v_cc = $request->getArr('cc');
|
||||
$v_projects = $request->getArr('projects');
|
||||
$v_space = $request->getStr('spacePHID');
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhrictionTransaction())
|
||||
|
@ -146,6 +149,9 @@ final class PhrictionEditController
|
|||
$xactions[] = id(new PhrictionTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||
->setNewValue($v_edit);
|
||||
$xactions[] = id(new PhrictionTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
|
||||
->setNewValue($v_space);
|
||||
$xactions[] = id(new PhrictionTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
|
||||
->setNewValue(array('=' => $v_cc));
|
||||
|
@ -192,6 +198,7 @@ final class PhrictionEditController
|
|||
|
||||
$document->setViewPolicy($v_view);
|
||||
$document->setEditPolicy($v_edit);
|
||||
$document->setSpacePHID($v_space);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +274,9 @@ final class PhrictionEditController
|
|||
->setDatasource(new PhabricatorMetaMTAMailableDatasource()))
|
||||
->appendChild(
|
||||
id(new AphrontFormPolicyControl())
|
||||
->setViewer($viewer)
|
||||
->setName('viewPolicy')
|
||||
->setSpacePHID($v_space)
|
||||
->setPolicyObject($document)
|
||||
->setCapability($view_capability)
|
||||
->setPolicies($policies)
|
||||
|
|
|
@ -131,6 +131,7 @@ final class PhrictionDocumentSearchEngine
|
|||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($content->getTitle())
|
||||
->setObject($document)
|
||||
->setHref($slug_uri)
|
||||
->addByline($byline)
|
||||
->addIcon('none', $updated);
|
||||
|
|
|
@ -12,7 +12,8 @@ final class PhrictionDocument extends PhrictionDAO
|
|||
PhabricatorProjectInterface,
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorConduitResultInterface,
|
||||
PhabricatorPolicyCodexInterface {
|
||||
PhabricatorPolicyCodexInterface,
|
||||
PhabricatorSpacesInterface {
|
||||
|
||||
protected $slug;
|
||||
protected $depth;
|
||||
|
@ -21,6 +22,7 @@ final class PhrictionDocument extends PhrictionDAO
|
|||
protected $mailKey;
|
||||
protected $viewPolicy;
|
||||
protected $editPolicy;
|
||||
protected $spacePHID;
|
||||
|
||||
private $contentObject = self::ATTACHABLE;
|
||||
private $ancestors = array();
|
||||
|
@ -81,12 +83,16 @@ final class PhrictionDocument extends PhrictionDAO
|
|||
}
|
||||
|
||||
if ($parent_doc) {
|
||||
$document->setViewPolicy($parent_doc->getViewPolicy());
|
||||
$document->setEditPolicy($parent_doc->getEditPolicy());
|
||||
$document
|
||||
->setViewPolicy($parent_doc->getViewPolicy())
|
||||
->setEditPolicy($parent_doc->getEditPolicy())
|
||||
->setSpacePHID($parent_doc->getSpacePHID());
|
||||
} else {
|
||||
$default_view_policy = PhabricatorPolicies::getMostOpenPolicy();
|
||||
$document->setViewPolicy($default_view_policy);
|
||||
$document->setEditPolicy(PhabricatorPolicies::POLICY_USER);
|
||||
$document
|
||||
->setViewPolicy($default_view_policy)
|
||||
->setEditPolicy(PhabricatorPolicies::POLICY_USER)
|
||||
->setSpacePHID($actor->getDefaultSpacePHID());
|
||||
}
|
||||
|
||||
return $document;
|
||||
|
@ -202,6 +208,15 @@ final class PhrictionDocument extends PhrictionDAO
|
|||
}
|
||||
|
||||
|
||||
/* -( PhabricatorSpacesInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getSpacePHID() {
|
||||
return $this->spacePHID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -106,8 +106,8 @@ final class PhabricatorProjectSubprojectsController
|
|||
->addClass('project-view-people-home')
|
||||
->setMainColumn(array(
|
||||
$info_view,
|
||||
$milestone_list,
|
||||
$subproject_list,
|
||||
$milestone_list,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
|
@ -132,28 +132,11 @@ final class PhabricatorProjectSubprojectsController
|
|||
$project,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$allows_milestones = $project->supportsMilestones();
|
||||
$allows_subprojects = $project->supportsSubprojects();
|
||||
$allows_milestones = $project->supportsMilestones();
|
||||
|
||||
$curtain = $this->newCurtainView();
|
||||
|
||||
if ($allows_milestones && $milestones) {
|
||||
$milestone_text = pht('Create Next Milestone');
|
||||
} else {
|
||||
$milestone_text = pht('Create Milestone');
|
||||
}
|
||||
|
||||
$can_milestone = ($can_create && $can_edit && $allows_milestones);
|
||||
$milestone_href = "/project/edit/?milestone={$id}";
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($milestone_text)
|
||||
->setIcon('fa-plus')
|
||||
->setHref($milestone_href)
|
||||
->setDisabled(!$can_milestone)
|
||||
->setWorkflow(!$can_milestone));
|
||||
|
||||
$can_subproject = ($can_create && $can_edit && $allows_subprojects);
|
||||
|
||||
// If we're offering to create the first subproject, we're going to warn
|
||||
|
@ -176,22 +159,22 @@ final class PhabricatorProjectSubprojectsController
|
|||
->setDisabled($subproject_disabled)
|
||||
->setWorkflow($subproject_workflow));
|
||||
|
||||
|
||||
if (!$project->supportsMilestones()) {
|
||||
$note = pht(
|
||||
'This project is already a milestone, and milestones may not '.
|
||||
'have their own milestones.');
|
||||
if ($allows_milestones && $milestones) {
|
||||
$milestone_text = pht('Create Next Milestone');
|
||||
} else {
|
||||
if (!$milestones) {
|
||||
$note = pht('Milestones can be created for this project.');
|
||||
} else {
|
||||
$note = pht('This project has milestones.');
|
||||
}
|
||||
$milestone_text = pht('Create Milestone');
|
||||
}
|
||||
|
||||
$curtain->newPanel()
|
||||
->setHeaderText(pht('Milestones'))
|
||||
->appendChild($note);
|
||||
$can_milestone = ($can_create && $can_edit && $allows_milestones);
|
||||
$milestone_href = "/project/edit/?milestone={$id}";
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($milestone_text)
|
||||
->setIcon('fa-plus')
|
||||
->setHref($milestone_href)
|
||||
->setDisabled(!$can_milestone)
|
||||
->setWorkflow(!$can_milestone));
|
||||
|
||||
if (!$project->supportsSubprojects()) {
|
||||
$note = pht(
|
||||
|
@ -209,6 +192,22 @@ final class PhabricatorProjectSubprojectsController
|
|||
->setHeaderText(pht('Subprojects'))
|
||||
->appendChild($note);
|
||||
|
||||
if (!$project->supportsSubprojects()) {
|
||||
$note = pht(
|
||||
'This project is already a milestone, and milestones may not '.
|
||||
'have their own milestones.');
|
||||
} else {
|
||||
if (!$milestones) {
|
||||
$note = pht('Milestones can be created for this project.');
|
||||
} else {
|
||||
$note = pht('This project has milestones.');
|
||||
}
|
||||
}
|
||||
|
||||
$curtain->newPanel()
|
||||
->setHeaderText(pht('Milestones'))
|
||||
->appendChild($note);
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,11 @@ final class PhabricatorProjectEditEngine
|
|||
}
|
||||
|
||||
protected function newEditableObject() {
|
||||
return PhabricatorProject::initializeNewProject($this->getViewer());
|
||||
$parent = nonempty($this->parentProject, $this->milestoneProject);
|
||||
|
||||
return PhabricatorProject::initializeNewProject(
|
||||
$this->getViewer(),
|
||||
$parent);
|
||||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
|
@ -112,6 +116,7 @@ final class PhabricatorProjectEditEngine
|
|||
PhabricatorTransactions::TYPE_VIEW_POLICY,
|
||||
PhabricatorTransactions::TYPE_EDIT_POLICY,
|
||||
PhabricatorTransactions::TYPE_JOIN_POLICY,
|
||||
PhabricatorTransactions::TYPE_SPACE,
|
||||
PhabricatorProjectIconTransaction::TRANSACTIONTYPE,
|
||||
PhabricatorProjectColorTransaction::TRANSACTIONTYPE,
|
||||
);
|
||||
|
|
|
@ -11,7 +11,8 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
PhabricatorFulltextInterface,
|
||||
PhabricatorFerretInterface,
|
||||
PhabricatorConduitResultInterface,
|
||||
PhabricatorColumnProxyInterface {
|
||||
PhabricatorColumnProxyInterface,
|
||||
PhabricatorSpacesInterface {
|
||||
|
||||
protected $name;
|
||||
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
|
||||
|
@ -38,6 +39,7 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
protected $projectPathKey;
|
||||
|
||||
protected $properties = array();
|
||||
protected $spacePHID;
|
||||
|
||||
private $memberPHIDs = self::ATTACHABLE;
|
||||
private $watcherPHIDs = self::ATTACHABLE;
|
||||
|
@ -59,7 +61,10 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
const ITEM_MILESTONES = 'project.milestones';
|
||||
const ITEM_SUBPROJECTS = 'project.subprojects';
|
||||
|
||||
public static function initializeNewProject(PhabricatorUser $actor) {
|
||||
public static function initializeNewProject(
|
||||
PhabricatorUser $actor,
|
||||
PhabricatorProject $parent = null) {
|
||||
|
||||
$app = id(new PhabricatorApplicationQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withClasses(array('PhabricatorProjectApplication'))
|
||||
|
@ -72,6 +77,14 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
$join_policy = $app->getPolicy(
|
||||
ProjectDefaultJoinCapability::CAPABILITY);
|
||||
|
||||
// If this is the child of some other project, default the Space to the
|
||||
// Space of the parent.
|
||||
if ($parent) {
|
||||
$space_phid = $parent->getSpacePHID();
|
||||
} else {
|
||||
$space_phid = $actor->getDefaultSpacePHID();
|
||||
}
|
||||
|
||||
$default_icon = PhabricatorProjectIconSet::getDefaultIconKey();
|
||||
$default_color = PhabricatorProjectIconSet::getDefaultColorKey();
|
||||
|
||||
|
@ -82,6 +95,7 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
->setViewPolicy($view_policy)
|
||||
->setEditPolicy($edit_policy)
|
||||
->setJoinPolicy($join_policy)
|
||||
->setSpacePHID($space_phid)
|
||||
->setIsMembershipLocked(0)
|
||||
->attachMemberPHIDs(array())
|
||||
->attachSlugs(array())
|
||||
|
@ -697,6 +711,17 @@ final class PhabricatorProject extends PhabricatorProjectDAO
|
|||
}
|
||||
|
||||
|
||||
/* -( PhabricatorSpacesInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getSpacePHID() {
|
||||
if ($this->isMilestone()) {
|
||||
return $this->getParentProject()->getSpacePHID();
|
||||
}
|
||||
return $this->spacePHID;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ final class PhabricatorProjectListView extends AphrontView {
|
|||
$icon_name = $project->getDisplayIconName();
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setObject($project)
|
||||
->setHeader($project->getName())
|
||||
->setHref("/project/view/{$id}/")
|
||||
->setImageURI($project->getProfileImageURI())
|
||||
|
|
|
@ -12,6 +12,7 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
private $pushEventPHIDs;
|
||||
private $epochMin;
|
||||
private $epochMax;
|
||||
private $blockingHeraldRulePHIDs;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -54,6 +55,11 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withBlockingHeraldRulePHIDs(array $phids) {
|
||||
$this->blockingHeraldRulePHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorRepositoryPushLog();
|
||||
}
|
||||
|
@ -89,71 +95,105 @@ final class PhabricatorRepositoryPushLogQuery
|
|||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
'log.id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
'log.phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->repositoryPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'repositoryPHID IN (%Ls)',
|
||||
'log.repositoryPHID IN (%Ls)',
|
||||
$this->repositoryPHIDs);
|
||||
}
|
||||
|
||||
if ($this->pusherPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'pusherPHID in (%Ls)',
|
||||
'log.pusherPHID in (%Ls)',
|
||||
$this->pusherPHIDs);
|
||||
}
|
||||
|
||||
if ($this->pushEventPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'pushEventPHID in (%Ls)',
|
||||
'log.pushEventPHID in (%Ls)',
|
||||
$this->pushEventPHIDs);
|
||||
}
|
||||
|
||||
if ($this->refTypes !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'refType IN (%Ls)',
|
||||
'log.refType IN (%Ls)',
|
||||
$this->refTypes);
|
||||
}
|
||||
|
||||
if ($this->newRefs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'refNew IN (%Ls)',
|
||||
'log.refNew IN (%Ls)',
|
||||
$this->newRefs);
|
||||
}
|
||||
|
||||
if ($this->epochMin !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'epoch >= %d',
|
||||
'log.epoch >= %d',
|
||||
$this->epochMin);
|
||||
}
|
||||
|
||||
if ($this->epochMax !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'epoch <= %d',
|
||||
'log.epoch <= %d',
|
||||
$this->epochMax);
|
||||
}
|
||||
|
||||
if ($this->blockingHeraldRulePHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'(event.rejectCode = %d AND event.rejectDetails IN (%Ls))',
|
||||
PhabricatorRepositoryPushLog::REJECT_HERALD,
|
||||
$this->blockingHeraldRulePHIDs);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$joins = parent::buildJoinClauseParts($conn);
|
||||
|
||||
if ($this->shouldJoinPushEventTable()) {
|
||||
$joins[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T event ON event.phid = log.pushEventPHID',
|
||||
id(new PhabricatorRepositoryPushEvent())->getTableName());
|
||||
}
|
||||
|
||||
return $joins;
|
||||
}
|
||||
|
||||
private function shouldJoinPushEventTable() {
|
||||
if ($this->blockingHeraldRulePHIDs !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
protected function getPrimaryTableAlias() {
|
||||
return 'log';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
|||
$map['createdEnd']);
|
||||
}
|
||||
|
||||
if ($map['blockingHeraldRulePHIDs']) {
|
||||
$query->withBlockingHeraldRulePHIDs($map['blockingHeraldRulePHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -43,13 +47,19 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
|||
->setAliases(array('repository', 'repositories', 'repositoryPHID'))
|
||||
->setLabel(pht('Repositories'))
|
||||
->setDescription(
|
||||
pht('Search for pull logs for specific repositories.')),
|
||||
pht('Search for push logs for specific repositories.')),
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setKey('pusherPHIDs')
|
||||
->setAliases(array('pusher', 'pushers', 'pusherPHID'))
|
||||
->setLabel(pht('Pushers'))
|
||||
->setDescription(
|
||||
pht('Search for pull logs by specific users.')),
|
||||
pht('Search for push logs by specific users.')),
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setDatasource(new HeraldRuleDatasource())
|
||||
->setKey('blockingHeraldRulePHIDs')
|
||||
->setLabel(pht('Blocked By'))
|
||||
->setDescription(
|
||||
pht('Search for pushes blocked by particular Herald rules.')),
|
||||
id(new PhabricatorSearchDateField())
|
||||
->setLabel(pht('Created After'))
|
||||
->setKey('createdStart'),
|
||||
|
@ -149,6 +159,9 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
|||
id(new PhabricatorStringExportField())
|
||||
->setKey('resultName')
|
||||
->setLabel(pht('Result Name')),
|
||||
id(new PhabricatorStringExportField())
|
||||
->setKey('resultDetails')
|
||||
->setLabel(pht('Result Details')),
|
||||
id(new PhabricatorIntExportField())
|
||||
->setKey('writeWait')
|
||||
->setLabel(pht('Write Wait (us)')),
|
||||
|
@ -237,6 +250,7 @@ final class PhabricatorRepositoryPushLogSearchEngine
|
|||
'flagNames' => $flag_names,
|
||||
'result' => $result,
|
||||
'resultName' => $result_name,
|
||||
'resultDetails' => $event->getRejectDetails(),
|
||||
'writeWait' => $event->getWriteWait(),
|
||||
'readWait' => $event->getReadWait(),
|
||||
'hostWait' => $event->getHostWait(),
|
||||
|
|
|
@ -49,6 +49,9 @@ final class PhabricatorRepositoryPushEvent
|
|||
'key_identifier' => array(
|
||||
'columns' => array('requestIdentifier'),
|
||||
),
|
||||
'key_reject' => array(
|
||||
'columns' => array('rejectCode', 'rejectDetails'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
|
|
@ -79,6 +79,14 @@ final class TransactionSearchConduitAPIMethod
|
|||
));
|
||||
|
||||
$with_phids = idx($constraints, 'phids');
|
||||
|
||||
if ($with_phids === array()) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Constraint "phids" to "transaction.search" requires nonempty list, '.
|
||||
'empty list provided.'));
|
||||
}
|
||||
|
||||
if ($with_phids) {
|
||||
$xaction_query->withPHIDs($with_phids);
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@ The supported keys for each mailer are:
|
|||
- `priority`: Optional string. Advanced option which controls load balancing
|
||||
and failover behavior. See below for details.
|
||||
- `options`: Optional map. Additional options for the mailer type.
|
||||
- `inbound`: Optional bool. Use `false` to prevent this mailer from being
|
||||
used to receive inbound mail.
|
||||
- `outbound`: Optional bool. Use `false` to prevent this mailer from being
|
||||
used to send outbound mail.
|
||||
|
||||
The `type` field can be used to select these third-party mailers:
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ final class PhabricatorClusterMailersConfigType
|
|||
'type' => 'string',
|
||||
'priority' => 'optional int',
|
||||
'options' => 'optional wild',
|
||||
'inbound' => 'optional bool',
|
||||
'outbound' => 'optional bool',
|
||||
));
|
||||
} catch (Exception $ex) {
|
||||
throw $this->newException(
|
||||
|
|
|
@ -294,7 +294,8 @@ body .phui-header-shell.phui-bleed-header
|
|||
}
|
||||
|
||||
.spaces-name .phui-handle,
|
||||
.spaces-name a.phui-handle {
|
||||
.spaces-name a.phui-handle,
|
||||
.phui-profile-header.phui-header-shell .spaces-name .phui-handle {
|
||||
color: {$sh-redtext};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue