mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 18:22:41 +01:00
Merge branch 'master' of git://github.com/facebook/phabricator
This commit is contained in:
commit
c5508c214e
22 changed files with 299 additions and 160 deletions
|
@ -856,17 +856,6 @@ return array(
|
||||||
'image/vnd.microsoft.icon' => true,
|
'image/vnd.microsoft.icon' => true,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Phabricator can proxy images from other servers so you can paste the URI
|
|
||||||
// to a funny picture of a cat into the comment box and have it show up as an
|
|
||||||
// image. However, this means the webserver Phabricator is running on will
|
|
||||||
// make HTTP requests to arbitrary URIs. If the server has access to internal
|
|
||||||
// resources, this could be a security risk. You should only enable it if you
|
|
||||||
// are installed entirely a VPN and VPN access is required to access
|
|
||||||
// Phabricator, or if the webserver has no special access to anything. If
|
|
||||||
// unsure, it is safer to leave this disabled.
|
|
||||||
'files.enable-proxy' => false,
|
|
||||||
|
|
||||||
|
|
||||||
// -- Storage --------------------------------------------------------------- //
|
// -- Storage --------------------------------------------------------------- //
|
||||||
|
|
||||||
// Phabricator allows users to upload files, and can keep them in various
|
// Phabricator allows users to upload files, and can keep them in various
|
||||||
|
|
1
resources/sql/patches/dropfileproxyimage.sql
Normal file
1
resources/sql/patches/dropfileproxyimage.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE {$NAMESPACE}_file.file_proxyimage;
|
42
resources/sql/patches/liskcounters.php
Normal file
42
resources/sql/patches/liskcounters.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Switch PhabricatorWorkerActiveTask from autoincrement IDs to counter IDs.
|
||||||
|
// Set the initial counter ID to be larger than any known task ID.
|
||||||
|
|
||||||
|
$active_table = new PhabricatorWorkerActiveTask();
|
||||||
|
$archive_table = new PhabricatorWorkerArchiveTask();
|
||||||
|
|
||||||
|
$conn_w = $active_table->establishConnection('w');
|
||||||
|
|
||||||
|
$active_auto = head(queryfx_one(
|
||||||
|
$conn_w,
|
||||||
|
'SELECT auto_increment FROM information_schema.tables
|
||||||
|
WHERE table_name = %s
|
||||||
|
AND table_schema = DATABASE()',
|
||||||
|
$active_table->getTableName()));
|
||||||
|
|
||||||
|
$active_max = head(queryfx_one(
|
||||||
|
$conn_w,
|
||||||
|
'SELECT MAX(id) FROM %T',
|
||||||
|
$active_table->getTableName()));
|
||||||
|
|
||||||
|
$archive_max = head(queryfx_one(
|
||||||
|
$conn_w,
|
||||||
|
'SELECT MAX(id) FROM %T',
|
||||||
|
$archive_table->getTableName()));
|
||||||
|
|
||||||
|
$initial_counter = max((int)$active_auto, (int)$active_max, (int)$archive_max);
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'INSERT IGNORE INTO %T (counterName, counterValue)
|
||||||
|
VALUES (%s, %d)',
|
||||||
|
LiskDAO::COUNTER_TABLE_NAME,
|
||||||
|
$active_table->getTableName(),
|
||||||
|
$initial_counter + 1);
|
||||||
|
|
||||||
|
// Drop AUTO_INCREMENT from the ID column.
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'ALTER TABLE %T CHANGE id id INT UNSIGNED NOT NULL',
|
||||||
|
$active_table->getTableName());
|
9
resources/sql/patches/liskcounters.sql
Normal file
9
resources/sql/patches/liskcounters.sql
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
CREATE TABLE `{$NAMESPACE}_harbormaster`.`lisk_counter` (
|
||||||
|
counterName VARCHAR(64) COLLATE utf8_bin PRIMARY KEY,
|
||||||
|
counterValue BIGINT UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
CREATE TABLE `{$NAMESPACE}_worker`.`lisk_counter` (
|
||||||
|
counterName VARCHAR(64) COLLATE utf8_bin PRIMARY KEY,
|
||||||
|
counterValue BIGINT UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -608,6 +608,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php',
|
'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php',
|
||||||
'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php',
|
'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php',
|
||||||
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
|
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
|
||||||
|
'PhabricatorButtonsExample' => 'applications/uiexample/examples/PhabricatorButtonsExample.php',
|
||||||
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
||||||
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php',
|
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php',
|
||||||
'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php',
|
'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php',
|
||||||
|
@ -744,8 +745,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
|
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
|
||||||
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
|
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
|
||||||
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
|
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
|
||||||
'PhabricatorFileProxyController' => 'applications/files/controller/PhabricatorFileProxyController.php',
|
|
||||||
'PhabricatorFileProxyImage' => 'applications/files/storage/PhabricatorFileProxyImage.php',
|
|
||||||
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
|
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
|
||||||
'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php',
|
'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php',
|
||||||
'PhabricatorFileSideNavView' => 'applications/files/view/PhabricatorFileSideNavView.php',
|
'PhabricatorFileSideNavView' => 'applications/files/view/PhabricatorFileSideNavView.php',
|
||||||
|
@ -987,7 +986,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObjectName.php',
|
'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObjectName.php',
|
||||||
'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/rule/PhabricatorRemarkupRulePaste.php',
|
'PhabricatorRemarkupRulePaste' => 'infrastructure/markup/rule/PhabricatorRemarkupRulePaste.php',
|
||||||
'PhabricatorRemarkupRulePhriction' => 'infrastructure/markup/rule/PhabricatorRemarkupRulePhriction.php',
|
'PhabricatorRemarkupRulePhriction' => 'infrastructure/markup/rule/PhabricatorRemarkupRulePhriction.php',
|
||||||
'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleProxyImage.php',
|
|
||||||
'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php',
|
'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php',
|
||||||
'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php',
|
'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php',
|
||||||
'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php',
|
'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php',
|
||||||
|
@ -1824,6 +1822,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBarePageView' => 'AphrontPageView',
|
'PhabricatorBarePageView' => 'AphrontPageView',
|
||||||
'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation',
|
'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation',
|
||||||
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
|
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
|
||||||
|
'PhabricatorButtonsExample' => 'PhabricatorUIExample',
|
||||||
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
|
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
|
||||||
'PhabricatorCalendarController' => 'PhabricatorController',
|
'PhabricatorCalendarController' => 'PhabricatorController',
|
||||||
|
@ -1955,8 +1954,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileLinkListView' => 'AphrontView',
|
'PhabricatorFileLinkListView' => 'AphrontView',
|
||||||
'PhabricatorFileLinkView' => 'AphrontView',
|
'PhabricatorFileLinkView' => 'AphrontView',
|
||||||
'PhabricatorFileListController' => 'PhabricatorFileController',
|
'PhabricatorFileListController' => 'PhabricatorFileController',
|
||||||
'PhabricatorFileProxyController' => 'PhabricatorFileController',
|
|
||||||
'PhabricatorFileProxyImage' => 'PhabricatorFileDAO',
|
|
||||||
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorFileShortcutController' => 'PhabricatorFileController',
|
'PhabricatorFileShortcutController' => 'PhabricatorFileController',
|
||||||
'PhabricatorFileSideNavView' => 'AphrontView',
|
'PhabricatorFileSideNavView' => 'AphrontView',
|
||||||
|
@ -2172,7 +2169,6 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule',
|
'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule',
|
||||||
'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName',
|
'PhabricatorRemarkupRulePaste' => 'PhabricatorRemarkupRuleObjectName',
|
||||||
'PhabricatorRemarkupRulePhriction' => 'PhutilRemarkupRule',
|
'PhabricatorRemarkupRulePhriction' => 'PhutilRemarkupRule',
|
||||||
'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule',
|
|
||||||
'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule',
|
'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule',
|
||||||
'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
|
'PhabricatorRepository' => 'PhabricatorRepositoryDAO',
|
||||||
'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
|
'PhabricatorRepositoryArcanistProject' => 'PhabricatorRepositoryDAO',
|
||||||
|
|
|
@ -383,6 +383,31 @@ abstract class DifferentialFieldSpecification {
|
||||||
return $key;
|
return $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -( Extending the Search Interface )------------------------------------ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task search
|
||||||
|
*/
|
||||||
|
public function shouldAddToSearchIndex() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @task search
|
||||||
|
*/
|
||||||
|
public function getValueForSearchIndex() {
|
||||||
|
throw new DifferentialFieldSpecificationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: Keys *must be* 4 characters for
|
||||||
|
* @{class:PhabricatorSearchEngineMySQL}.
|
||||||
|
*
|
||||||
|
* @task search
|
||||||
|
*/
|
||||||
|
public function getKeyForSearchIndex() {
|
||||||
|
throw new DifferentialFieldSpecificationIncompleteException($this);
|
||||||
|
}
|
||||||
|
|
||||||
/* -( Extending Commit Messages )------------------------------------------ */
|
/* -( Extending Commit Messages )------------------------------------------ */
|
||||||
|
|
||||||
|
|
|
@ -95,4 +95,16 @@ final class DifferentialRevertPlanFieldSpecification
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToSearchIndex() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueForSearchIndex() {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeyForSearchIndex() {
|
||||||
|
return 'rpln';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,4 +70,16 @@ final class DifferentialSummaryFieldSpecification
|
||||||
return $this->summary;
|
return $this->summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToSearchIndex() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueForSearchIndex() {
|
||||||
|
return $this->summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeyForSearchIndex() {
|
||||||
|
return PhabricatorSearchField::FIELD_BODY;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,22 @@ final class DifferentialTestPlanFieldSpecification
|
||||||
return "TEST PLAN\n".preg_replace('/^/m', ' ', $this->plan);
|
return "TEST PLAN\n".preg_replace('/^/m', ' ', $this->plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAddToSearchIndex() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueForSearchIndex() {
|
||||||
|
return $this->plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKeyForSearchIndex() {
|
||||||
|
return 'tpln';
|
||||||
|
}
|
||||||
|
|
||||||
private function isRequired() {
|
private function isRequired() {
|
||||||
return PhabricatorEnv::getEnvConfig('differential.require-test-plan-field');
|
return PhabricatorEnv::getEnvConfig('differential.require-test-plan-field');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorFileProxyController extends PhabricatorFileController {
|
|
||||||
|
|
||||||
private $uri;
|
|
||||||
|
|
||||||
public function processRequest() {
|
|
||||||
|
|
||||||
if (!PhabricatorEnv::getEnvConfig('files.enable-proxy')) {
|
|
||||||
return new Aphront400Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$uri = $request->getStr('uri');
|
|
||||||
|
|
||||||
$proxy = id(new PhabricatorFileProxyImage())->loadOneWhere(
|
|
||||||
'uri = %s',
|
|
||||||
$uri);
|
|
||||||
|
|
||||||
if (!$proxy) {
|
|
||||||
// This write is fine to skip CSRF checks for, we're just building a
|
|
||||||
// cache of some remote image.
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
||||||
|
|
||||||
$file = PhabricatorFile::newFromFileDownload(
|
|
||||||
$uri,
|
|
||||||
nonempty(basename($uri), 'proxied-file'));
|
|
||||||
if ($file) {
|
|
||||||
$proxy = new PhabricatorFileProxyImage();
|
|
||||||
$proxy->setURI($uri);
|
|
||||||
$proxy->setFilePHID($file->getPHID());
|
|
||||||
$proxy->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($unguarded);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($proxy) {
|
|
||||||
$file = id(new PhabricatorFile())->loadOneWhere('phid = %s',
|
|
||||||
$proxy->getFilePHID());
|
|
||||||
if ($file) {
|
|
||||||
$view_uri = $file->getBestURI();
|
|
||||||
} else {
|
|
||||||
$bad_phid = $proxy->getFilePHID();
|
|
||||||
throw new Exception(
|
|
||||||
"Unable to load file with phid {$bad_phid}."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Aphront400Response();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorFileProxyImage extends PhabricatorFileDAO {
|
|
||||||
|
|
||||||
protected $uri;
|
|
||||||
protected $filePHID;
|
|
||||||
|
|
||||||
public function getConfiguration() {
|
|
||||||
return array(
|
|
||||||
self::CONFIG_TIMESTAMPS => false,
|
|
||||||
) + parent::getConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
static public function getProxyImageURI($uri) {
|
|
||||||
return '/file/proxy/?uri='.phutil_escape_uri($uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -543,6 +543,7 @@ final class ManiphestTaskListController extends ManiphestController {
|
||||||
$owner_phids,
|
$owner_phids,
|
||||||
$author_phids,
|
$author_phids,
|
||||||
$project_group_phids,
|
$project_group_phids,
|
||||||
|
$any_project_phids,
|
||||||
array_mergev(mpull($data, 'getProjectPHIDs')));
|
array_mergev(mpull($data, 'getProjectPHIDs')));
|
||||||
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
||||||
->loadHandles();
|
->loadHandles();
|
||||||
|
|
|
@ -7,7 +7,6 @@ final class PhabricatorSearchField {
|
||||||
|
|
||||||
const FIELD_TITLE = 'titl';
|
const FIELD_TITLE = 'titl';
|
||||||
const FIELD_BODY = 'body';
|
const FIELD_BODY = 'body';
|
||||||
const FIELD_TEST_PLAN = 'tpln';
|
|
||||||
const FIELD_COMMENT = 'cmnt';
|
const FIELD_COMMENT = 'cmnt';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,23 @@ final class PhabricatorSearchDifferentialIndexer
|
||||||
$doc->setDocumentCreated($rev->getDateCreated());
|
$doc->setDocumentCreated($rev->getDateCreated());
|
||||||
$doc->setDocumentModified($rev->getDateModified());
|
$doc->setDocumentModified($rev->getDateModified());
|
||||||
|
|
||||||
$doc->addField(
|
$aux_fields = DifferentialFieldSelector::newSelector()
|
||||||
PhabricatorSearchField::FIELD_BODY,
|
->getFieldSpecifications();
|
||||||
$rev->getSummary());
|
foreach ($aux_fields as $key => $aux_field) {
|
||||||
$doc->addField(
|
if (!$aux_field->shouldAddToSearchIndex()) {
|
||||||
PhabricatorSearchField::FIELD_TEST_PLAN,
|
unset($aux_fields[$key]);
|
||||||
$rev->getTestPlan());
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$aux_fields = DifferentialAuxiliaryField::loadFromStorage(
|
||||||
|
$rev,
|
||||||
|
$aux_fields);
|
||||||
|
foreach ($aux_fields as $aux_field) {
|
||||||
|
$doc->addField(
|
||||||
|
$aux_field->getKeyForSearchIndex(),
|
||||||
|
$aux_field->getValueForSearchIndex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$doc->addRelationship(
|
$doc->addRelationship(
|
||||||
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
|
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorButtonsExample extends PhabricatorUIExample {
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return 'Buttons';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return 'Use <tt><button></tt> to render buttons.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderExample() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$colors = array('', 'green', 'grey', 'disabled');
|
||||||
|
$sizes = array('', 'small');
|
||||||
|
$tags = array('a', 'button');
|
||||||
|
|
||||||
|
$view = array();
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
foreach ($colors as $color) {
|
||||||
|
foreach ($sizes as $size) {
|
||||||
|
$class = implode(' ', array($color, $size));
|
||||||
|
|
||||||
|
if ($tag == 'a') {
|
||||||
|
$class .= ' button';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view[] = phutil_render_tag(
|
||||||
|
$tag,
|
||||||
|
array(
|
||||||
|
'class' => $class,
|
||||||
|
),
|
||||||
|
phutil_escape_html(ucwords($size.' '.$color.' '.$tag)));
|
||||||
|
|
||||||
|
$view[] = '<br /><br />';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<div style="margin: 1em 2em;">'.implode('', $view).'</div>';
|
||||||
|
}
|
||||||
|
}
|
|
@ -307,16 +307,14 @@ Valid options are:
|
||||||
|
|
||||||
= Embedding Media =
|
= Embedding Media =
|
||||||
|
|
||||||
If you set configuration flags, you can embed media directly in text:
|
If you set a configuration flag, you can embed media directly in text:
|
||||||
|
|
||||||
- **files.enable-proxy**: allows you to paste in image URLs and have them
|
|
||||||
render inline.
|
|
||||||
- **remarkup.enable-embedded-youtube**: allows you to paste in YouTube videos
|
- **remarkup.enable-embedded-youtube**: allows you to paste in YouTube videos
|
||||||
and have them render inline.
|
and have them render inline.
|
||||||
|
|
||||||
These options are disabled by default because they have security and/or
|
This option is disabled by default because it has security and/or
|
||||||
silliness implications, read their descriptions in ##default.conf.php## before
|
silliness implications. Read the description in ##default.conf.php## before
|
||||||
enabling them.
|
enabling it.
|
||||||
|
|
||||||
= Image Macros =
|
= Image Macros =
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ final class PhabricatorWorkerActiveTask extends PhabricatorWorkerTask {
|
||||||
|
|
||||||
public function getConfiguration() {
|
public function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
|
self::CONFIG_IDS => self::IDS_COUNTER,
|
||||||
self::CONFIG_TIMESTAMPS => false,
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ final class PhabricatorMarkupEngine {
|
||||||
|
|
||||||
private $objects = array();
|
private $objects = array();
|
||||||
private $viewer;
|
private $viewer;
|
||||||
private $version = 0;
|
private $version = 1;
|
||||||
|
|
||||||
|
|
||||||
/* -( Markup Pipeline )---------------------------------------------------- */
|
/* -( Markup Pipeline )---------------------------------------------------- */
|
||||||
|
@ -286,7 +286,6 @@ final class PhabricatorMarkupEngine {
|
||||||
return self::newMarkupEngine(
|
return self::newMarkupEngine(
|
||||||
array(
|
array(
|
||||||
'macros' => false,
|
'macros' => false,
|
||||||
'fileproxy' => false,
|
|
||||||
'youtube' => false,
|
'youtube' => false,
|
||||||
|
|
||||||
));
|
));
|
||||||
|
@ -345,7 +344,6 @@ final class PhabricatorMarkupEngine {
|
||||||
private static function getMarkupEngineDefaultConfiguration() {
|
private static function getMarkupEngineDefaultConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
'pygments' => PhabricatorEnv::getEnvConfig('pygments.enabled'),
|
'pygments' => PhabricatorEnv::getEnvConfig('pygments.enabled'),
|
||||||
'fileproxy' => PhabricatorEnv::getEnvConfig('files.enable-proxy'),
|
|
||||||
'youtube' => PhabricatorEnv::getEnvConfig(
|
'youtube' => PhabricatorEnv::getEnvConfig(
|
||||||
'remarkup.enable-embedded-youtube'),
|
'remarkup.enable-embedded-youtube'),
|
||||||
'custom-inline' => array(),
|
'custom-inline' => array(),
|
||||||
|
@ -394,10 +392,6 @@ final class PhabricatorMarkupEngine {
|
||||||
|
|
||||||
$rules[] = new PhutilRemarkupRuleDocumentLink();
|
$rules[] = new PhutilRemarkupRuleDocumentLink();
|
||||||
|
|
||||||
if ($options['fileproxy']) {
|
|
||||||
$rules[] = new PhabricatorRemarkupRuleProxyImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($options['youtube']) {
|
if ($options['youtube']) {
|
||||||
$rules[] = new PhabricatorRemarkupRuleYoutube();
|
$rules[] = new PhabricatorRemarkupRuleYoutube();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group markup
|
|
||||||
*/
|
|
||||||
final class PhabricatorRemarkupRuleProxyImage
|
|
||||||
extends PhutilRemarkupRule {
|
|
||||||
|
|
||||||
public function apply($text) {
|
|
||||||
|
|
||||||
$filetypes = '\.(?:jpe?g|png|gif)';
|
|
||||||
|
|
||||||
$text = preg_replace_callback(
|
|
||||||
'@[<](\w{3,}://.+?'.$filetypes.')[>]@',
|
|
||||||
array($this, 'markupProxyImage'),
|
|
||||||
$text);
|
|
||||||
|
|
||||||
$text = preg_replace_callback(
|
|
||||||
'@(?<=^|\s)(\w{3,}://\S+'.$filetypes.')(?=\s|$)@',
|
|
||||||
array($this, 'markupProxyImage'),
|
|
||||||
$text);
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function markupProxyImage($matches) {
|
|
||||||
|
|
||||||
$uri = PhabricatorFileProxyImage::getProxyImageURI($matches[1]);
|
|
||||||
|
|
||||||
return $this->getEngine()->storeText(
|
|
||||||
phutil_render_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => $uri,
|
|
||||||
'target' => '_blank',
|
|
||||||
),
|
|
||||||
phutil_render_tag(
|
|
||||||
'img',
|
|
||||||
array(
|
|
||||||
'src' => $uri,
|
|
||||||
'class' => 'remarkup-proxy-image',
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -177,9 +177,12 @@ abstract class LiskDAO {
|
||||||
const SERIALIZATION_PHP = 'php';
|
const SERIALIZATION_PHP = 'php';
|
||||||
|
|
||||||
const IDS_AUTOINCREMENT = 'ids-auto';
|
const IDS_AUTOINCREMENT = 'ids-auto';
|
||||||
|
const IDS_COUNTER = 'ids-counter';
|
||||||
const IDS_PHID = 'ids-phid';
|
const IDS_PHID = 'ids-phid';
|
||||||
const IDS_MANUAL = 'ids-manual';
|
const IDS_MANUAL = 'ids-manual';
|
||||||
|
|
||||||
|
const COUNTER_TABLE_NAME = 'lisk_counter';
|
||||||
|
|
||||||
private $__dirtyFields = array();
|
private $__dirtyFields = array();
|
||||||
private $__missingFields = array();
|
private $__missingFields = array();
|
||||||
private static $processIsolationLevel = 0;
|
private static $processIsolationLevel = 0;
|
||||||
|
@ -327,8 +330,23 @@ abstract class LiskDAO {
|
||||||
* Lisk objects need to have a unique identifying ID. The three mechanisms
|
* Lisk objects need to have a unique identifying ID. The three mechanisms
|
||||||
* available for generating this ID are IDS_AUTOINCREMENT (default, assumes
|
* available for generating this ID are IDS_AUTOINCREMENT (default, assumes
|
||||||
* the ID column is an autoincrement primary key), IDS_PHID (to generate a
|
* the ID column is an autoincrement primary key), IDS_PHID (to generate a
|
||||||
* unique PHID for each object) or IDS_MANUAL (you are taking full
|
* unique PHID for each object), IDS_MANUAL (you are taking full
|
||||||
* responsibility for ID management).
|
* responsibility for ID management), or IDS_COUNTER (see below).
|
||||||
|
*
|
||||||
|
* InnoDB does not persist the value of `auto_increment` across restarts,
|
||||||
|
* and instead initializes it to `MAX(id) + 1` during startup. This means it
|
||||||
|
* may reissue the same autoincrement ID more than once, if the row is deleted
|
||||||
|
* and then the database is restarted. To avoid this, you can set an object to
|
||||||
|
* use a counter table with IDS_COUNTER. This will generally behave like
|
||||||
|
* IDS_AUTOINCREMENT, except that the counter value will persist across
|
||||||
|
* restarts and inserts will be slightly slower. If a database stores any
|
||||||
|
* DAOs which use this mechanism, you must create a table there with this
|
||||||
|
* schema:
|
||||||
|
*
|
||||||
|
* CREATE TABLE lisk_counter (
|
||||||
|
* counterName VARCHAR(64) COLLATE utf8_bin PRIMARY KEY,
|
||||||
|
* counterValue BIGINT UNSIGNED NOT NULL
|
||||||
|
* ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
*
|
*
|
||||||
* CONFIG_TIMESTAMPS
|
* CONFIG_TIMESTAMPS
|
||||||
* Lisk can automatically handle keeping track of a `dateCreated' and
|
* Lisk can automatically handle keeping track of a `dateCreated' and
|
||||||
|
@ -365,7 +383,6 @@ abstract class LiskDAO {
|
||||||
* directly access or assign protected members of your class (use the getters
|
* directly access or assign protected members of your class (use the getters
|
||||||
* and setters).
|
* and setters).
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @return dictionary Map of configuration options to values.
|
* @return dictionary Map of configuration options to values.
|
||||||
*
|
*
|
||||||
* @task config
|
* @task config
|
||||||
|
@ -1181,7 +1198,6 @@ abstract class LiskDAO {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal implementation of INSERT and REPLACE.
|
* Internal implementation of INSERT and REPLACE.
|
||||||
*
|
*
|
||||||
|
@ -1193,6 +1209,8 @@ abstract class LiskDAO {
|
||||||
$this->willSaveObject();
|
$this->willSaveObject();
|
||||||
$data = $this->getPropertyValues();
|
$data = $this->getPropertyValues();
|
||||||
|
|
||||||
|
$conn = $this->establishConnection('w');
|
||||||
|
|
||||||
$id_mechanism = $this->getConfigOption(self::CONFIG_IDS);
|
$id_mechanism = $this->getConfigOption(self::CONFIG_IDS);
|
||||||
switch ($id_mechanism) {
|
switch ($id_mechanism) {
|
||||||
case self::IDS_AUTOINCREMENT:
|
case self::IDS_AUTOINCREMENT:
|
||||||
|
@ -1204,6 +1222,17 @@ abstract class LiskDAO {
|
||||||
unset($data[$id_key]);
|
unset($data[$id_key]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case self::IDS_COUNTER:
|
||||||
|
// If we are using counter IDs, assign a new ID if we don't already have
|
||||||
|
// one.
|
||||||
|
$id_key = $this->getIDKeyForUse();
|
||||||
|
if (empty($data[$id_key])) {
|
||||||
|
$counter_name = $this->getTableName();
|
||||||
|
$id = self::loadNextCounterID($conn, $counter_name);
|
||||||
|
$this->setID($id);
|
||||||
|
$data[$id_key] = $id;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case self::IDS_PHID:
|
case self::IDS_PHID:
|
||||||
if (empty($data[$this->getIDKeyForUse()])) {
|
if (empty($data[$this->getIDKeyForUse()])) {
|
||||||
$phid = $this->generatePHID();
|
$phid = $this->generatePHID();
|
||||||
|
@ -1219,8 +1248,6 @@ abstract class LiskDAO {
|
||||||
|
|
||||||
$this->willWriteData($data);
|
$this->willWriteData($data);
|
||||||
|
|
||||||
$conn = $this->establishConnection('w');
|
|
||||||
|
|
||||||
$columns = array_keys($data);
|
$columns = array_keys($data);
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
foreach ($data as $key => $value) {
|
||||||
|
@ -1761,4 +1788,37 @@ abstract class LiskDAO {
|
||||||
$this->$name = $value;
|
$this->$name = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments a named counter and returns the next value.
|
||||||
|
*
|
||||||
|
* @param AphrontDatabaseConnection Database where the counter resides.
|
||||||
|
* @param string Counter name to create or increment.
|
||||||
|
* @return int Next counter value.
|
||||||
|
*
|
||||||
|
* @task util
|
||||||
|
*/
|
||||||
|
public static function loadNextCounterID(
|
||||||
|
AphrontDatabaseConnection $conn_w,
|
||||||
|
$counter_name) {
|
||||||
|
|
||||||
|
// NOTE: If an insert does not touch an autoincrement row or call
|
||||||
|
// LAST_INSERT_ID(), MySQL normally does not change the value of
|
||||||
|
// LAST_INSERT_ID(). This can cause a counter's value to leak to a
|
||||||
|
// new counter if the second counter is created after the first one is
|
||||||
|
// updated. To avoid this, we insert LAST_INSERT_ID(1), to ensure the
|
||||||
|
// LAST_INSERT_ID() is always updated and always set correctly after the
|
||||||
|
// query completes.
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'INSERT INTO %T (counterName, counterValue) VALUES
|
||||||
|
(%s, LAST_INSERT_ID(1))
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
counterValue = LAST_INSERT_ID(counterValue + 1)',
|
||||||
|
self::COUNTER_TABLE_NAME,
|
||||||
|
$counter_name);
|
||||||
|
|
||||||
|
return $conn_w->getInsertID();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,5 +95,40 @@ final class LiskFixtureTestCase extends PhabricatorTestCase {
|
||||||
$this->assertEqual(true, (bool)$load->load((string)$id));
|
$this->assertEqual(true, (bool)$load->load((string)$id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCounters() {
|
||||||
|
$obj = new HarbormasterObject();
|
||||||
|
$conn_w = $obj->establishConnection('w');
|
||||||
|
|
||||||
|
// Test that the counter bascially behaves as expected.
|
||||||
|
$this->assertEqual(1, LiskDAO::loadNextCounterID($conn_w, 'a'));
|
||||||
|
$this->assertEqual(2, LiskDAO::loadNextCounterID($conn_w, 'a'));
|
||||||
|
$this->assertEqual(3, LiskDAO::loadNextCounterID($conn_w, 'a'));
|
||||||
|
|
||||||
|
// This first insert is primarily a test that the previous LAST_INSERT_ID()
|
||||||
|
// value does not bleed into the creation of a new counter.
|
||||||
|
$this->assertEqual(1, LiskDAO::loadNextCounterID($conn_w, 'b'));
|
||||||
|
$this->assertEqual(2, LiskDAO::loadNextCounterID($conn_w, 'b'));
|
||||||
|
|
||||||
|
// These inserts alternate database connections. Since unit tests are
|
||||||
|
// transactional by default, we need to break out of them or we'll deadlock
|
||||||
|
// since the transactions don't normally close until we exit the test.
|
||||||
|
LiskDAO::endIsolateAllLiskEffectsToTransactions();
|
||||||
|
try {
|
||||||
|
|
||||||
|
$conn_1 = $obj->establishConnection('w', $force_new = true);
|
||||||
|
$conn_2 = $obj->establishConnection('w', $force_new = true);
|
||||||
|
|
||||||
|
$this->assertEqual(1, LiskDAO::loadNextCounterID($conn_1, 'z'));
|
||||||
|
$this->assertEqual(2, LiskDAO::loadNextCounterID($conn_2, 'z'));
|
||||||
|
$this->assertEqual(3, LiskDAO::loadNextCounterID($conn_1, 'z'));
|
||||||
|
$this->assertEqual(4, LiskDAO::loadNextCounterID($conn_2, 'z'));
|
||||||
|
$this->assertEqual(5, LiskDAO::loadNextCounterID($conn_1, 'z'));
|
||||||
|
|
||||||
|
LiskDAO::beginIsolateAllLiskEffectsToTransactions();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
LiskDAO::beginIsolateAllLiskEffectsToTransactions();
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1012,6 +1012,18 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('drydockresourcetype.sql'),
|
'name' => $this->getPatchPath('drydockresourcetype.sql'),
|
||||||
),
|
),
|
||||||
|
'liskcounters.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('liskcounters.sql'),
|
||||||
|
),
|
||||||
|
'liskcounters.php' => array(
|
||||||
|
'type' => 'php',
|
||||||
|
'name' => $this->getPatchPath('liskcounters.php'),
|
||||||
|
),
|
||||||
|
'dropfileproxyimage.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('dropfileproxyimage.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue