mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-28 17:52:43 +01:00
(stable) Promote 2016 Week 23
This commit is contained in:
commit
03403ca8b0
119 changed files with 3027 additions and 360 deletions
|
@ -10,7 +10,7 @@ return array(
|
|||
'core.pkg.css' => '8aeacc63',
|
||||
'core.pkg.js' => '3f15fa62',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '33da0633',
|
||||
'differential.pkg.css' => 'a3a7e5df',
|
||||
'differential.pkg.js' => '4b7d8f19',
|
||||
'diffusion.pkg.css' => '91c5d3a6',
|
||||
'diffusion.pkg.js' => '3a9a8bfa',
|
||||
|
@ -57,7 +57,7 @@ return array(
|
|||
'rsrc/css/application/dashboard/dashboard.css' => 'bc6f2127',
|
||||
'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a',
|
||||
'rsrc/css/application/differential/add-comment.css' => 'c47f8c40',
|
||||
'rsrc/css/application/differential/changeset-view.css' => '7bcbe615',
|
||||
'rsrc/css/application/differential/changeset-view.css' => 'febd2372',
|
||||
'rsrc/css/application/differential/core.css' => '5b7b8ff4',
|
||||
'rsrc/css/application/differential/phui-inline-comment.css' => '5953c28e',
|
||||
'rsrc/css/application/differential/revision-comment.css' => '14b8565a',
|
||||
|
@ -81,7 +81,7 @@ return array(
|
|||
'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b',
|
||||
'rsrc/css/application/paste/paste.css' => '1898e534',
|
||||
'rsrc/css/application/people/people-profile.css' => '2473d929',
|
||||
'rsrc/css/application/phame/phame.css' => '737792d6',
|
||||
'rsrc/css/application/phame/phame.css' => '7448a969',
|
||||
'rsrc/css/application/pholio/pholio-edit.css' => 'b15fec4a',
|
||||
'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49',
|
||||
'rsrc/css/application/pholio/pholio.css' => 'ca89d380',
|
||||
|
@ -116,7 +116,7 @@ return array(
|
|||
'rsrc/css/layout/phabricator-side-menu-view.css' => 'dd849797',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'e0866209',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => '56e6381a',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => '476be7e0',
|
||||
'rsrc/css/phui/calendar/phui-calendar.css' => 'ccabe893',
|
||||
'rsrc/css/phui/phui-action-list.css' => 'c5eba19d',
|
||||
|
@ -156,7 +156,7 @@ return array(
|
|||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '6bbd83e2',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => '6e342216',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'b9538af1',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => '9fb86c85',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'ac6fe6a7',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'e6d89647',
|
||||
'rsrc/css/phui/workboards/phui-workcard.css' => '0c62d7c5',
|
||||
|
@ -552,7 +552,7 @@ return array(
|
|||
'conpherence-update-css' => 'faf6be09',
|
||||
'conpherence-widget-pane-css' => '775eaaba',
|
||||
'd3' => 'a11a5ff2',
|
||||
'differential-changeset-view-css' => '7bcbe615',
|
||||
'differential-changeset-view-css' => 'febd2372',
|
||||
'differential-core-view-css' => '5b7b8ff4',
|
||||
'differential-inline-comment-editor' => '64a5550f',
|
||||
'differential-revision-add-comment-css' => 'c47f8c40',
|
||||
|
@ -806,7 +806,7 @@ return array(
|
|||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||
'phabricator-zindex-css' => '5b6fcf3f',
|
||||
'phame-css' => '737792d6',
|
||||
'phame-css' => '7448a969',
|
||||
'pholio-css' => 'ca89d380',
|
||||
'pholio-edit-css' => 'b15fec4a',
|
||||
'pholio-inline-comments-css' => '8e545e49',
|
||||
|
@ -822,7 +822,7 @@ return array(
|
|||
'phui-button-css' => 'a64a8de6',
|
||||
'phui-calendar-css' => 'ccabe893',
|
||||
'phui-calendar-day-css' => 'd1cf6f93',
|
||||
'phui-calendar-list-css' => 'e0866209',
|
||||
'phui-calendar-list-css' => '56e6381a',
|
||||
'phui-calendar-month-css' => '476be7e0',
|
||||
'phui-chart-css' => '6bf6f78e',
|
||||
'phui-crumbs-view-css' => '6b813619',
|
||||
|
@ -859,7 +859,7 @@ return array(
|
|||
'phui-tag-view-css' => '6bbd83e2',
|
||||
'phui-theme-css' => '027ba77e',
|
||||
'phui-timeline-view-css' => '6e342216',
|
||||
'phui-two-column-view-css' => 'b9538af1',
|
||||
'phui-two-column-view-css' => '9fb86c85',
|
||||
'phui-workboard-color-css' => 'ac6fe6a7',
|
||||
'phui-workboard-view-css' => 'e6d89647',
|
||||
'phui-workcard-view-css' => '0c62d7c5',
|
||||
|
@ -1513,9 +1513,6 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
),
|
||||
'7bcbe615' => array(
|
||||
'phui-inline-comment-view-css',
|
||||
),
|
||||
'7cbe244b' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -2203,6 +2200,9 @@ return array(
|
|||
'fea0eb47' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
'febd2372' => array(
|
||||
'phui-inline-comment-view-css',
|
||||
),
|
||||
),
|
||||
'packages' => array(
|
||||
'core.pkg.css' => array(
|
||||
|
|
|
@ -74,35 +74,9 @@ foreach ($applications as $application) {
|
|||
|
||||
/* -( User preferences )--------------------------------------------------- */
|
||||
|
||||
echo pht('Migrating user preferences...')."\n";
|
||||
$table = new PhabricatorUserPreferences();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$pref_pinned = PhabricatorUserPreferences::PREFERENCE_APP_PINNED;
|
||||
|
||||
foreach (new LiskMigrationIterator(new PhabricatorUser()) as $user) {
|
||||
$user_preferences = $user->loadPreferences();
|
||||
|
||||
$old_pinned_apps = $user_preferences->getPreference($pref_pinned);
|
||||
$new_pinned_apps = array();
|
||||
|
||||
if (!$old_pinned_apps) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($old_pinned_apps as $pinned_app) {
|
||||
$new_pinned_apps[] = idx($map, $pinned_app, $pinned_app);
|
||||
}
|
||||
|
||||
$user_preferences
|
||||
->setPreference($pref_pinned, $new_pinned_apps);
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET preferences = %s WHERE id = %d',
|
||||
$user_preferences->getTableName(),
|
||||
json_encode($user_preferences->getPreferences()),
|
||||
$user_preferences->getID());
|
||||
}
|
||||
// This originally migrated pinned applications in user preferences, but was
|
||||
// removed to simplify preference changes after about 22 months.
|
||||
|
||||
|
||||
/* -( Dashboard installs )------------------------------------------------- */
|
||||
|
|
19
resources/sql/autopatches/20160531.pref.01.xaction.sql
Normal file
19
resources/sql/autopatches/20160531.pref.01.xaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE {$NAMESPACE}_user.user_preferencestransaction (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
phid VARBINARY(64) NOT NULL,
|
||||
authorPHID VARBINARY(64) NOT NULL,
|
||||
objectPHID VARBINARY(64) NOT NULL,
|
||||
viewPolicy VARBINARY(64) NOT NULL,
|
||||
editPolicy VARBINARY(64) NOT NULL,
|
||||
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||
commentVersion INT UNSIGNED NOT NULL,
|
||||
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_phid` (`phid`),
|
||||
KEY `key_object` (`objectPHID`)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user_preferences
|
||||
ADD dateCreated INT UNSIGNED NOT NULL;
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user_preferences
|
||||
ADD dateModified INT UNSIGNED NOT NULL;
|
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_user.user_preferences
|
||||
SET dateCreated = UNIX_TIMESTAMP() WHERE dateCreated = 0;
|
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_user.user_preferences
|
||||
SET dateModified = UNIX_TIMESTAMP() WHERE dateModified = 0;
|
2
resources/sql/autopatches/20160531.pref.06.phidcol.sql
Normal file
2
resources/sql/autopatches/20160531.pref.06.phidcol.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user_preferences
|
||||
ADD phid VARBINARY(64) NOT NULL;
|
17
resources/sql/autopatches/20160531.pref.07.phidval.php
Normal file
17
resources/sql/autopatches/20160531.pref.07.phidval.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorUserPreferences();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $row) {
|
||||
if ($row->getPHID() !== '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET phid = %s WHERE id = %d',
|
||||
$table->getTableName(),
|
||||
$table->generatePHID(),
|
||||
$row->getID());
|
||||
}
|
11
resources/sql/autopatches/20160601.user.01.cache.sql
Normal file
11
resources/sql/autopatches/20160601.user.01.cache.sql
Normal file
|
@ -0,0 +1,11 @@
|
|||
CREATE TABLE {$NAMESPACE}_user.user_cache (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
userPHID VARBINARY(64) NOT NULL,
|
||||
cacheIndex BINARY(12) NOT NULL,
|
||||
cacheKey VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
cacheData LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
cacheType VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
UNIQUE KEY `key_usercache` (userPHID, cacheIndex),
|
||||
KEY `key_cachekey` (cacheIndex),
|
||||
KEY `key_cachetype` (cacheType)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
59
resources/sql/autopatches/20160601.user.02.copyprefs.php
Normal file
59
resources/sql/autopatches/20160601.user.02.copyprefs.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
// Move timezone, translation and pronoun from the user object to preferences
|
||||
// so they can be defaulted and edited like other settings.
|
||||
|
||||
$table = new PhabricatorUser();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$table_name = $table->getTableName();
|
||||
$prefs_table = new PhabricatorUserPreferences();
|
||||
|
||||
foreach (new LiskRawMigrationIterator($conn_w, $table_name) as $row) {
|
||||
$phid = $row['phid'];
|
||||
|
||||
$pref_row = queryfx_one(
|
||||
$conn_w,
|
||||
'SELECT preferences FROM %T WHERE userPHID = %s',
|
||||
$prefs_table->getTableName(),
|
||||
$phid);
|
||||
|
||||
if ($pref_row) {
|
||||
try {
|
||||
$prefs = phutil_json_decode($pref_row['preferences']);
|
||||
} catch (Exception $ex) {
|
||||
$prefs = array();
|
||||
}
|
||||
} else {
|
||||
$prefs = array();
|
||||
}
|
||||
|
||||
$zone = $row['timezoneIdentifier'];
|
||||
if (strlen($zone)) {
|
||||
$prefs[PhabricatorTimezoneSetting::SETTINGKEY] = $zone;
|
||||
}
|
||||
|
||||
$pronoun = $row['sex'];
|
||||
if (strlen($pronoun)) {
|
||||
$prefs[PhabricatorPronounSetting::SETTINGKEY] = $pronoun;
|
||||
}
|
||||
|
||||
$translation = $row['translation'];
|
||||
if (strlen($translation)) {
|
||||
$prefs[PhabricatorTranslationSetting::SETTINGKEY] = $translation;
|
||||
}
|
||||
|
||||
if ($prefs) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (phid, userPHID, preferences, dateModified, dateCreated)
|
||||
VALUES (%s, %s, %s, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())
|
||||
ON DUPLICATE KEY UPDATE preferences = VALUES(preferences)',
|
||||
$prefs_table->getTableName(),
|
||||
$prefs_table->generatePHID(),
|
||||
$phid,
|
||||
phutil_json_encode($prefs));
|
||||
}
|
||||
}
|
||||
|
||||
$prefs_key = PhabricatorUserPreferencesCacheType::KEY_PREFERENCES;
|
||||
PhabricatorUserCache::clearCacheForAllUsers($prefs_key);
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user
|
||||
DROP COLUMN timezoneIdentifier;
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user
|
||||
DROP COLUMN translation;
|
2
resources/sql/autopatches/20160601.user.05.removesex.sql
Normal file
2
resources/sql/autopatches/20160601.user.05.removesex.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_user.user
|
||||
DROP COLUMN sex;
|
|
@ -1711,6 +1711,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAccessControlTestCase' => 'applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php',
|
||||
'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php',
|
||||
'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php',
|
||||
'PhabricatorAccessibilitySetting' => 'applications/settings/setting/PhabricatorAccessibilitySetting.php',
|
||||
'PhabricatorAccountSettingsPanel' => 'applications/settings/panel/PhabricatorAccountSettingsPanel.php',
|
||||
'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php',
|
||||
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
|
||||
|
@ -2238,6 +2239,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonsApplication' => 'applications/daemon/application/PhabricatorDaemonsApplication.php',
|
||||
'PhabricatorDaemonsSetupCheck' => 'applications/config/check/PhabricatorDaemonsSetupCheck.php',
|
||||
'PhabricatorDailyRoutineTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorDailyRoutineTriggerClock.php',
|
||||
'PhabricatorDarkConsoleSetting' => 'applications/settings/setting/PhabricatorDarkConsoleSetting.php',
|
||||
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
|
||||
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
|
||||
'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php',
|
||||
|
@ -2295,6 +2297,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php',
|
||||
'PhabricatorDatasourceEditField' => 'applications/transactions/editfield/PhabricatorDatasourceEditField.php',
|
||||
'PhabricatorDatasourceEditType' => 'applications/transactions/edittype/PhabricatorDatasourceEditType.php',
|
||||
'PhabricatorDateFormatSetting' => 'applications/settings/setting/PhabricatorDateFormatSetting.php',
|
||||
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
|
||||
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
|
||||
|
@ -2373,13 +2376,20 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php',
|
||||
'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php',
|
||||
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
|
||||
'PhabricatorEditorMultipleSetting' => 'applications/settings/setting/PhabricatorEditorMultipleSetting.php',
|
||||
'PhabricatorEditorSetting' => 'applications/settings/setting/PhabricatorEditorSetting.php',
|
||||
'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php',
|
||||
'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php',
|
||||
'PhabricatorEmailAddressesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php',
|
||||
'PhabricatorEmailContentSource' => 'applications/metamta/contentsource/PhabricatorEmailContentSource.php',
|
||||
'PhabricatorEmailFormatSetting' => 'applications/settings/setting/PhabricatorEmailFormatSetting.php',
|
||||
'PhabricatorEmailFormatSettingsPanel' => 'applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php',
|
||||
'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php',
|
||||
'PhabricatorEmailNotificationsSetting' => 'applications/settings/setting/PhabricatorEmailNotificationsSetting.php',
|
||||
'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php',
|
||||
'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php',
|
||||
'PhabricatorEmailSelfActionsSetting' => 'applications/settings/setting/PhabricatorEmailSelfActionsSetting.php',
|
||||
'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php',
|
||||
'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php',
|
||||
'PhabricatorEmbedFileRemarkupRule' => 'applications/files/markup/PhabricatorEmbedFileRemarkupRule.php',
|
||||
'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php',
|
||||
|
@ -2732,6 +2742,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php',
|
||||
'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php',
|
||||
'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php',
|
||||
'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php',
|
||||
'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php',
|
||||
'PhabricatorMotivatorProfilePanel' => 'applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php',
|
||||
'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php',
|
||||
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
|
||||
|
@ -2822,8 +2834,10 @@ phutil_register_library_map(array(
|
|||
'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php',
|
||||
'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php',
|
||||
'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php',
|
||||
'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php',
|
||||
'PhabricatorOneTimeTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorOneTimeTriggerClock.php',
|
||||
'PhabricatorOpcodeCacheSpec' => 'applications/cache/spec/PhabricatorOpcodeCacheSpec.php',
|
||||
'PhabricatorOptionGroupSetting' => 'applications/settings/setting/PhabricatorOptionGroupSetting.php',
|
||||
'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php',
|
||||
'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php',
|
||||
'PhabricatorOwnersArchiveController' => 'applications/owners/controller/PhabricatorOwnersArchiveController.php',
|
||||
|
@ -3155,6 +3169,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineAttachment.php',
|
||||
'PhabricatorProjectsSearchEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsSearchEngineExtension.php',
|
||||
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsWatchersSearchEngineAttachment.php',
|
||||
'PhabricatorPronounSetting' => 'applications/settings/setting/PhabricatorPronounSetting.php',
|
||||
'PhabricatorProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorProtocolAdapter.php',
|
||||
'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php',
|
||||
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
|
||||
|
@ -3348,11 +3363,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php',
|
||||
'PhabricatorSecuritySetupCheck' => 'applications/config/check/PhabricatorSecuritySetupCheck.php',
|
||||
'PhabricatorSelectEditField' => 'applications/transactions/editfield/PhabricatorSelectEditField.php',
|
||||
'PhabricatorSelectSetting' => 'applications/settings/setting/PhabricatorSelectSetting.php',
|
||||
'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php',
|
||||
'PhabricatorSessionsSettingsPanel' => 'applications/settings/panel/PhabricatorSessionsSettingsPanel.php',
|
||||
'PhabricatorSetting' => 'applications/settings/setting/PhabricatorSetting.php',
|
||||
'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php',
|
||||
'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php',
|
||||
'PhabricatorSettingsApplication' => 'applications/settings/application/PhabricatorSettingsApplication.php',
|
||||
'PhabricatorSettingsEditController' => 'applications/settings/controller/PhabricatorSettingsEditController.php',
|
||||
'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php',
|
||||
'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php',
|
||||
'PhabricatorSettingsMainMenuBarExtension' => 'applications/settings/extension/PhabricatorSettingsMainMenuBarExtension.php',
|
||||
'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php',
|
||||
|
@ -3363,6 +3382,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSetupIssueUIExample' => 'applications/uiexample/examples/PhabricatorSetupIssueUIExample.php',
|
||||
'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php',
|
||||
'PhabricatorShortSite' => 'aphront/site/PhabricatorShortSite.php',
|
||||
'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php',
|
||||
'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php',
|
||||
'PhabricatorSite' => 'aphront/site/PhabricatorSite.php',
|
||||
'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php',
|
||||
|
@ -3457,6 +3477,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorStorageSetupCheck' => 'applications/config/check/PhabricatorStorageSetupCheck.php',
|
||||
'PhabricatorStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php',
|
||||
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
||||
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
||||
'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
|
||||
'PhabricatorSubscribedToObjectEdgeType' => 'applications/transactions/edges/PhabricatorSubscribedToObjectEdgeType.php',
|
||||
'PhabricatorSubscribersEditField' => 'applications/transactions/editfield/PhabricatorSubscribersEditField.php',
|
||||
|
@ -3513,9 +3534,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTextAreaEditField' => 'applications/transactions/editfield/PhabricatorTextAreaEditField.php',
|
||||
'PhabricatorTextEditField' => 'applications/transactions/editfield/PhabricatorTextEditField.php',
|
||||
'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php',
|
||||
'PhabricatorTimeFormatSetting' => 'applications/settings/setting/PhabricatorTimeFormatSetting.php',
|
||||
'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php',
|
||||
'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php',
|
||||
'PhabricatorTimezoneSetting' => 'applications/settings/setting/PhabricatorTimezoneSetting.php',
|
||||
'PhabricatorTimezoneSetupCheck' => 'applications/config/check/PhabricatorTimezoneSetupCheck.php',
|
||||
'PhabricatorTitleGlyphsSetting' => 'applications/settings/setting/PhabricatorTitleGlyphsSetting.php',
|
||||
'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php',
|
||||
'PhabricatorTokenController' => 'applications/tokens/controller/PhabricatorTokenController.php',
|
||||
'PhabricatorTokenCount' => 'applications/tokens/storage/PhabricatorTokenCount.php',
|
||||
|
@ -3544,6 +3568,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTransactionsDestructionEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsDestructionEngineExtension.php',
|
||||
'PhabricatorTransactionsFulltextEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsFulltextEngineExtension.php',
|
||||
'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php',
|
||||
'PhabricatorTranslationSetting' => 'applications/settings/setting/PhabricatorTranslationSetting.php',
|
||||
'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php',
|
||||
'PhabricatorTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorTriggerAction.php',
|
||||
'PhabricatorTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorTriggerClock.php',
|
||||
|
@ -3568,12 +3593,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php',
|
||||
'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php',
|
||||
'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php',
|
||||
'PhabricatorUnifiedDiffsSetting' => 'applications/settings/setting/PhabricatorUnifiedDiffsSetting.php',
|
||||
'PhabricatorUnitTestContentSource' => 'infrastructure/contentsource/PhabricatorUnitTestContentSource.php',
|
||||
'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php',
|
||||
'PhabricatorUnknownContentSource' => 'infrastructure/contentsource/PhabricatorUnknownContentSource.php',
|
||||
'PhabricatorUnsubscribedFromObjectEdgeType' => 'applications/transactions/edges/PhabricatorUnsubscribedFromObjectEdgeType.php',
|
||||
'PhabricatorUser' => 'applications/people/storage/PhabricatorUser.php',
|
||||
'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php',
|
||||
'PhabricatorUserCache' => 'applications/people/storage/PhabricatorUserCache.php',
|
||||
'PhabricatorUserCacheType' => 'applications/people/cache/PhabricatorUserCacheType.php',
|
||||
'PhabricatorUserCardView' => 'applications/people/view/PhabricatorUserCardView.php',
|
||||
'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php',
|
||||
'PhabricatorUserConfiguredCustomField' => 'applications/people/customfield/PhabricatorUserConfiguredCustomField.php',
|
||||
|
@ -3592,6 +3620,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php',
|
||||
'PhabricatorUserPHIDResolver' => 'applications/phid/resolver/PhabricatorUserPHIDResolver.php',
|
||||
'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php',
|
||||
'PhabricatorUserPreferencesCacheType' => 'applications/people/cache/PhabricatorUserPreferencesCacheType.php',
|
||||
'PhabricatorUserPreferencesEditor' => 'applications/settings/editor/PhabricatorUserPreferencesEditor.php',
|
||||
'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php',
|
||||
'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php',
|
||||
'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php',
|
||||
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
|
||||
'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
|
||||
'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php',
|
||||
|
@ -3611,6 +3644,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorViewerDatasource' => 'applications/people/typeahead/PhabricatorViewerDatasource.php',
|
||||
'PhabricatorWatcherHasObjectEdgeType' => 'applications/transactions/edges/PhabricatorWatcherHasObjectEdgeType.php',
|
||||
'PhabricatorWebContentSource' => 'infrastructure/contentsource/PhabricatorWebContentSource.php',
|
||||
'PhabricatorWeekStartDaySetting' => 'applications/settings/setting/PhabricatorWeekStartDaySetting.php',
|
||||
'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php',
|
||||
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
|
||||
'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php',
|
||||
|
@ -3674,7 +3708,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php',
|
||||
'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php',
|
||||
'PhabricatorYoutubeRemarkupRule' => 'infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php',
|
||||
'Phame404Response' => 'applications/phame/site/Phame404Response.php',
|
||||
'PhameBlog' => 'applications/phame/storage/PhameBlog.php',
|
||||
'PhameBlog404Controller' => 'applications/phame/controller/blog/PhameBlog404Controller.php',
|
||||
'PhameBlogArchiveController' => 'applications/phame/controller/blog/PhameBlogArchiveController.php',
|
||||
'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php',
|
||||
'PhameBlogCreateCapability' => 'applications/phame/capability/PhameBlogCreateCapability.php',
|
||||
|
@ -6126,6 +6162,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAccessControlTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorAccessLog' => 'Phobject',
|
||||
'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorAccessibilitySetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorAccountSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorActionListView' => 'AphrontView',
|
||||
'PhabricatorActionView' => 'AphrontView',
|
||||
|
@ -6744,6 +6781,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDaemonsApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorDaemonsSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorDailyRoutineTriggerClock' => 'PhabricatorTriggerClock',
|
||||
'PhabricatorDarkConsoleSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorDashboard' => array(
|
||||
'PhabricatorDashboardDAO',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
|
@ -6819,6 +6857,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorDatasourceEditField' => 'PhabricatorTokenizerEditField',
|
||||
'PhabricatorDatasourceEditType' => 'PhabricatorPHIDListEditType',
|
||||
'PhabricatorDateFormatSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorDebugController' => 'PhabricatorController',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||
|
@ -6903,13 +6942,20 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEditPage' => 'Phobject',
|
||||
'PhabricatorEditType' => 'Phobject',
|
||||
'PhabricatorEditor' => 'Phobject',
|
||||
'PhabricatorEditorMultipleSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEditorSetting' => 'PhabricatorStringSetting',
|
||||
'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine',
|
||||
'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorEmailAddressesSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorEmailContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorEmailFormatSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEmailFormatSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
|
||||
'PhabricatorEmailNotificationsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEmailSelfActionsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorEmailVerificationController' => 'PhabricatorAuthController',
|
||||
'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||
'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule',
|
||||
|
@ -7307,6 +7353,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
|
||||
'PhabricatorMetaMTAWorker' => 'PhabricatorWorker',
|
||||
'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock',
|
||||
'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting',
|
||||
'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorMotivatorProfilePanel' => 'PhabricatorProfilePanel',
|
||||
'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
|
@ -7410,8 +7458,10 @@ phutil_register_library_map(array(
|
|||
'PhabricatorObjectSelectorDialog' => 'Phobject',
|
||||
'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery',
|
||||
'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorOneTimeTriggerClock' => 'PhabricatorTriggerClock',
|
||||
'PhabricatorOpcodeCacheSpec' => 'PhabricatorCacheSpec',
|
||||
'PhabricatorOptionGroupSetting' => 'PhabricatorSetting',
|
||||
'PhabricatorOwnerPathQuery' => 'Phobject',
|
||||
'PhabricatorOwnersApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorOwnersArchiveController' => 'PhabricatorOwnersController',
|
||||
|
@ -7815,6 +7865,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorPronounSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorProtocolAdapter' => 'Phobject',
|
||||
'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorQuery' => 'Phobject',
|
||||
|
@ -8061,11 +8112,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSelectEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorSelectSetting' => 'PhabricatorSetting',
|
||||
'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSetting' => 'Phobject',
|
||||
'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction',
|
||||
'PhabricatorSettingsAdjustController' => 'PhabricatorController',
|
||||
'PhabricatorSettingsApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorSettingsEditController' => 'PhabricatorController',
|
||||
'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine',
|
||||
'PhabricatorSettingsMainController' => 'PhabricatorController',
|
||||
'PhabricatorSettingsMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
|
||||
'PhabricatorSettingsPanel' => 'Phobject',
|
||||
|
@ -8076,6 +8131,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSetupIssueUIExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorSetupIssueView' => 'AphrontView',
|
||||
'PhabricatorShortSite' => 'PhabricatorSite',
|
||||
'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorSimpleEditType' => 'PhabricatorEditType',
|
||||
'PhabricatorSite' => 'AphrontSite',
|
||||
'PhabricatorSlowvoteApplication' => 'PhabricatorApplication',
|
||||
|
@ -8187,6 +8243,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter',
|
||||
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
||||
'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorSubscribersEditField' => 'PhabricatorTokenizerEditField',
|
||||
'PhabricatorSubscribersQuery' => 'PhabricatorQuery',
|
||||
|
@ -8242,9 +8299,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTextAreaEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorTextEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorTime' => 'Phobject',
|
||||
'PhabricatorTimeFormatSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorTimeGuard' => 'Phobject',
|
||||
'PhabricatorTimeTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorTimezoneSetting' => 'PhabricatorOptionGroupSetting',
|
||||
'PhabricatorTimezoneSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorTitleGlyphsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorToken' => array(
|
||||
'PhabricatorTokenDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -8278,6 +8338,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTransactionsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
|
||||
'PhabricatorTransactionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
|
||||
'PhabricatorTranslationSetting' => 'PhabricatorOptionGroupSetting',
|
||||
'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorTriggerAction' => 'Phobject',
|
||||
'PhabricatorTriggerClock' => 'Phobject',
|
||||
|
@ -8302,6 +8363,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUIExampleRenderController' => 'PhabricatorController',
|
||||
'PhabricatorUIExamplesApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorUSEnglishTranslation' => 'PhutilTranslation',
|
||||
'PhabricatorUnifiedDiffsSetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorUnitTestContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorUnitsTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorUnknownContentSource' => 'PhabricatorContentSource',
|
||||
|
@ -8319,6 +8381,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField',
|
||||
'PhabricatorUserCache' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserCacheType' => 'Phobject',
|
||||
'PhabricatorUserCardView' => 'AphrontTagView',
|
||||
'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorUserConfiguredCustomField' => array(
|
||||
|
@ -8342,7 +8406,17 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorUserLogView' => 'AphrontView',
|
||||
'PhabricatorUserPHIDResolver' => 'PhabricatorPHIDResolver',
|
||||
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserPreferences' => array(
|
||||
'PhabricatorUserDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'PhabricatorUserPreferencesCacheType' => 'PhabricatorUserCacheType',
|
||||
'PhabricatorUserPreferencesEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField',
|
||||
|
@ -8362,6 +8436,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorViewerDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorWatcherHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorWebContentSource' => 'PhabricatorContentSource',
|
||||
'PhabricatorWeekStartDaySetting' => 'PhabricatorSelectSetting',
|
||||
'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||
'PhabricatorWorker' => 'Phobject',
|
||||
'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask',
|
||||
|
@ -8435,6 +8510,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO',
|
||||
'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController',
|
||||
'PhabricatorYoutubeRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'Phame404Response' => 'AphrontHTMLResponse',
|
||||
'PhameBlog' => array(
|
||||
'PhameDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
|
@ -8446,6 +8522,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'PhameBlog404Controller' => 'PhameLiveController',
|
||||
'PhameBlogArchiveController' => 'PhameBlogController',
|
||||
'PhameBlogController' => 'PhameController',
|
||||
'PhameBlogCreateCapability' => 'PhabricatorPolicyCapability',
|
||||
|
|
|
@ -60,7 +60,7 @@ final class PhabricatorAuditApplication extends PhabricatorApplication {
|
|||
|
||||
$count = count($commits);
|
||||
if ($count >= $limit) {
|
||||
$count_str = pht('%s+ Problem Commit(s)', new PhutilNumber($limit - 1));
|
||||
$count_str = pht('%s+ Problem Commits', new PhutilNumber($limit - 1));
|
||||
} else {
|
||||
$count_str = pht('%s Problem Commit(s)', new PhutilNumber($count));
|
||||
}
|
||||
|
@ -80,9 +80,13 @@ final class PhabricatorAuditApplication extends PhabricatorApplication {
|
|||
|
||||
$count = count($commits);
|
||||
if ($count >= $limit) {
|
||||
$count_str = pht('%s+ Problem Commit(s)', new PhutilNumber($limit - 1));
|
||||
$count_str = pht(
|
||||
'%s+ Commits Awaiting Audit',
|
||||
new PhutilNumber($limit - 1));
|
||||
} else {
|
||||
$count_str = pht('%s Problem Commit(s)', new PhutilNumber($count));
|
||||
$count_str = pht(
|
||||
'%s Commit(s) Awaiting Audit',
|
||||
new PhutilNumber($count));
|
||||
}
|
||||
|
||||
$type = PhabricatorApplicationStatusView::TYPE_WARNING;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* @task hisec High Security
|
||||
* @task partial Partial Sessions
|
||||
* @task onetime One Time Login URIs
|
||||
* @task cache User Cache
|
||||
*/
|
||||
final class PhabricatorAuthSessionEngine extends Phobject {
|
||||
|
||||
|
@ -111,9 +112,8 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||
$conn_r = $session_table->establishConnection('r');
|
||||
$session_key = PhabricatorHash::digest($session_token);
|
||||
|
||||
// NOTE: We're being clever here because this happens on every page load,
|
||||
// and by joining we can save a query. This might be getting too clever
|
||||
// for its own good, though...
|
||||
$cache_parts = $this->getUserCacheQueryParts($conn_r);
|
||||
list($cache_selects, $cache_joins, $cache_map) = $cache_parts;
|
||||
|
||||
$info = queryfx_one(
|
||||
$conn_r,
|
||||
|
@ -125,12 +125,15 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||
s.isPartial AS s_isPartial,
|
||||
s.signedLegalpadDocuments as s_signedLegalpadDocuments,
|
||||
u.*
|
||||
%Q
|
||||
FROM %T u JOIN %T s ON u.phid = s.userPHID
|
||||
AND s.type = %s AND s.sessionKey = %s',
|
||||
AND s.type = %s AND s.sessionKey = %s %Q',
|
||||
$cache_selects,
|
||||
$user_table->getTableName(),
|
||||
$session_table->getTableName(),
|
||||
$session_type,
|
||||
$session_key);
|
||||
$session_key,
|
||||
$cache_joins);
|
||||
|
||||
if (!$info) {
|
||||
return null;
|
||||
|
@ -141,14 +144,26 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||
'sessionKey' => $session_key,
|
||||
'type' => $session_type,
|
||||
);
|
||||
|
||||
$cache_raw = array_fill_keys($cache_map, null);
|
||||
foreach ($info as $key => $value) {
|
||||
if (strncmp($key, 's_', 2) === 0) {
|
||||
unset($info[$key]);
|
||||
$session_dict[substr($key, 2)] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($cache_map[$key])) {
|
||||
unset($info[$key]);
|
||||
$cache_raw[$cache_map[$key]] = $value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$user = $user_table->loadFromArray($info);
|
||||
|
||||
$user->attachRawCacheData($cache_raw);
|
||||
|
||||
switch ($session_type) {
|
||||
case PhabricatorAuthSession::TYPE_WEB:
|
||||
// Explicitly prevent bots and mailing lists from establishing web
|
||||
|
@ -732,4 +747,68 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||
return PhabricatorHash::digest(implode(':', $parts));
|
||||
}
|
||||
|
||||
|
||||
/* -( User Cache )--------------------------------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* @task cache
|
||||
*/
|
||||
private function getUserCacheQueryParts(AphrontDatabaseConnection $conn) {
|
||||
$cache_selects = array();
|
||||
$cache_joins = array();
|
||||
$cache_map = array();
|
||||
|
||||
$keys = array();
|
||||
|
||||
$cache_types = PhabricatorUserCacheType::getAllCacheTypes();
|
||||
foreach ($cache_types as $cache_type) {
|
||||
foreach ($cache_type->getAutoloadKeys() as $autoload_key) {
|
||||
$keys[] = $autoload_key;
|
||||
}
|
||||
}
|
||||
|
||||
$cache_table = id(new PhabricatorUserCache())->getTableName();
|
||||
|
||||
$cache_idx = 1;
|
||||
foreach ($keys as $key) {
|
||||
$join_as = 'ucache_'.$cache_idx;
|
||||
$select_as = 'ucache_'.$cache_idx.'_v';
|
||||
|
||||
$cache_selects[] = qsprintf(
|
||||
$conn,
|
||||
'%T.cacheData %T',
|
||||
$join_as,
|
||||
$select_as);
|
||||
|
||||
$cache_joins[] = qsprintf(
|
||||
$conn,
|
||||
'LEFT JOIN %T AS %T ON u.phid = %T.userPHID
|
||||
AND %T.cacheIndex = %s',
|
||||
$cache_table,
|
||||
$join_as,
|
||||
$join_as,
|
||||
$join_as,
|
||||
PhabricatorHash::digestForIndex($key));
|
||||
|
||||
$cache_map[$select_as] = $key;
|
||||
|
||||
$cache_idx++;
|
||||
}
|
||||
|
||||
if ($cache_selects) {
|
||||
$cache_selects = ', '.implode(', ', $cache_selects);
|
||||
} else {
|
||||
$cache_selects = '';
|
||||
}
|
||||
|
||||
if ($cache_joins) {
|
||||
$cache_joins = implode(' ', $cache_joins);
|
||||
} else {
|
||||
$cache_joins = '';
|
||||
}
|
||||
|
||||
return array($cache_selects, $cache_joins, $cache_map);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,10 +106,9 @@ abstract class PhabricatorController extends AphrontController {
|
|||
|
||||
PhabricatorEnv::setLocaleCode($user->getTranslation());
|
||||
|
||||
$preferences = $user->loadPreferences();
|
||||
if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) {
|
||||
$dark_console = PhabricatorUserPreferences::PREFERENCE_DARK_CONSOLE;
|
||||
if ($preferences->getPreference($dark_console) ||
|
||||
$dark_console = PhabricatorDarkConsoleSetting::SETTINGKEY;
|
||||
if ($user->getUserSetting($dark_console) ||
|
||||
PhabricatorEnv::getEnvConfig('darkconsole.always-on')) {
|
||||
$console = new DarkConsoleCore();
|
||||
$request->getApplicationConfiguration()->setConsole($console);
|
||||
|
|
|
@ -4,7 +4,7 @@ final class CalendarTimeUtilTestCase extends PhabricatorTestCase {
|
|||
|
||||
public function testTimestampsAtMidnight() {
|
||||
$u = new PhabricatorUser();
|
||||
$u->setTimezoneIdentifier('America/Los_Angeles');
|
||||
$u->overrideTimezoneIdentifier('America/Los_Angeles');
|
||||
$days = $this->getAllDays();
|
||||
foreach ($days as $day) {
|
||||
$data = CalendarTimeUtil::getCalendarWidgetTimestamps(
|
||||
|
@ -19,7 +19,7 @@ final class CalendarTimeUtilTestCase extends PhabricatorTestCase {
|
|||
|
||||
public function testTimestampsStartDay() {
|
||||
$u = new PhabricatorUser();
|
||||
$u->setTimezoneIdentifier('America/Los_Angeles');
|
||||
$u->overrideTimezoneIdentifier('America/Los_Angeles');
|
||||
$days = $this->getAllDays();
|
||||
foreach ($days as $day) {
|
||||
$data = CalendarTimeUtil::getTimestamps(
|
||||
|
|
|
@ -151,10 +151,9 @@ final class PhabricatorCalendarEventSearchEngine
|
|||
$display_start = $start_day->format('U');
|
||||
$display_end = $next->format('U');
|
||||
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$pref_week_day = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
|
||||
$start_of_week = $viewer->getUserSetting(
|
||||
PhabricatorWeekStartDaySetting::SETTINGKEY);
|
||||
|
||||
$start_of_week = $preferences->getPreference($pref_week_day, 0);
|
||||
$end_of_week = ($start_of_week + 6) % 7;
|
||||
|
||||
$first_of_month = $start_day->format('w');
|
||||
|
|
|
@ -10,7 +10,7 @@ final class CelerityDefaultPostprocessor
|
|||
}
|
||||
|
||||
public function getPostprocessorName() {
|
||||
return pht('Use Default Colors');
|
||||
return pht('Use Standard Colors');
|
||||
}
|
||||
|
||||
public function buildDefaultPostprocessor() {
|
||||
|
|
|
@ -141,8 +141,14 @@ final class PhabricatorConfigWelcomeController
|
|||
$content);
|
||||
|
||||
$settings_href = PhabricatorEnv::getURI('/settings/');
|
||||
$prefs = $viewer->loadPreferences()->getPreferences();
|
||||
$have_settings = !empty($prefs);
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($viewer)
|
||||
->withUsers(array($viewer))
|
||||
->executeOne();
|
||||
|
||||
$have_settings = ($preferences && $preferences->getPreferences());
|
||||
|
||||
if ($have_settings) {
|
||||
$content = pht(
|
||||
"=== Adjust Account Settings ===\n\n".
|
||||
|
|
|
@ -533,13 +533,20 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
$to_phids = array();
|
||||
|
||||
$participants = $object->getParticipants();
|
||||
if (empty($participants)) {
|
||||
if (!$participants) {
|
||||
return $to_phids;
|
||||
}
|
||||
$preferences = id(new PhabricatorUserPreferences())
|
||||
->loadAllWhere('userPHID in (%Ls)', array_keys($participants));
|
||||
|
||||
$participant_phids = mpull($participants, 'getParticipantPHID');
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withUserPHIDs($participant_phids)
|
||||
->execute();
|
||||
$preferences = mpull($preferences, null, 'getUserPHID');
|
||||
|
||||
foreach ($participants as $phid => $participant) {
|
||||
$default = ConpherenceSettings::EMAIL_ALWAYS;
|
||||
$preference = idx($preferences, $phid);
|
||||
|
@ -557,6 +564,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$to_phids[] = $phid;
|
||||
}
|
||||
}
|
||||
|
||||
return $to_phids;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,14 +72,6 @@ final class ConpherenceThreadListView extends AphrontView {
|
|||
$epoch = $data['epoch'];
|
||||
$image = $data['image'];
|
||||
$dom_id = $thread->getPHID().'-nav-item';
|
||||
$glyph_pref = PhabricatorUserPreferences::PREFERENCE_TITLES;
|
||||
$preferences = $user->loadPreferences();
|
||||
if ($preferences->getPreference($glyph_pref) == 'glyph') {
|
||||
$glyph = id(new PhabricatorConpherenceApplication())
|
||||
->getTitleGlyph().' ';
|
||||
} else {
|
||||
$glyph = null;
|
||||
}
|
||||
|
||||
return id(new ConpherenceMenuItemView())
|
||||
->setUser($user)
|
||||
|
@ -93,7 +85,7 @@ final class ConpherenceThreadListView extends AphrontView {
|
|||
->addSigil('conpherence-menu-click')
|
||||
->setMetadata(
|
||||
array(
|
||||
'title' => $glyph.$data['title'],
|
||||
'title' => $data['title'],
|
||||
'id' => $dom_id,
|
||||
'threadID' => $thread->getID(),
|
||||
));
|
||||
|
|
|
@ -23,13 +23,34 @@ final class DifferentialInlineCommentEditController
|
|||
}
|
||||
|
||||
protected function createComment() {
|
||||
// Verify revision and changeset correspond to actual objects.
|
||||
// Verify revision and changeset correspond to actual objects, and are
|
||||
// connected to one another.
|
||||
$changeset_id = $this->getChangesetID();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$revision = $this->loadRevision();
|
||||
|
||||
if (!id(new DifferentialChangeset())->load($changeset_id)) {
|
||||
throw new Exception(pht('Invalid changeset ID!'));
|
||||
$changeset = id(new DifferentialChangesetQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($changeset_id))
|
||||
->executeOne();
|
||||
if (!$changeset) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Invalid changeset ID "%s"!',
|
||||
$changeset_id));
|
||||
}
|
||||
|
||||
$diff = $changeset->getDiff();
|
||||
if ($diff->getRevisionID() != $revision->getID()) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Changeset ID "%s" is part of diff ID "%s", but that diff '.
|
||||
'is attached to reivsion "%s", not revision "%s".',
|
||||
$changeset_id,
|
||||
$diff->getID(),
|
||||
$diff->getRevisionID(),
|
||||
$revision->getID()));
|
||||
}
|
||||
|
||||
return id(new DifferentialInlineComment())
|
||||
|
|
|
@ -93,7 +93,7 @@ final class DifferentialRevisionCloseDetailsController
|
|||
'href' => $obj_handle->getURI(),
|
||||
),
|
||||
$obj_handle->getName());
|
||||
$body_why = pht(
|
||||
$body_why[] = pht(
|
||||
'This commit and the active diff of %s had the same %s hash '.
|
||||
'(%s) so we linked this commit to %s.',
|
||||
$diff_link,
|
||||
|
|
|
@ -375,18 +375,19 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
$crumbs->addTextCrumb($object_id, '/'.$object_id);
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$prefs = $viewer->loadPreferences();
|
||||
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
|
||||
$filetree_on = $viewer->compareUserSetting(
|
||||
PhabricatorShowFiletreeSetting::SETTINGKEY,
|
||||
PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE);
|
||||
|
||||
$nav = null;
|
||||
if ($prefs->getPreference($pref_filetree)) {
|
||||
$collapsed = $prefs->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED,
|
||||
false);
|
||||
if ($filetree_on) {
|
||||
$collapsed_key = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
|
||||
$collapsed_value = $viewer->getUserSetting($collapsed_key);
|
||||
|
||||
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
|
||||
->setTitle('D'.$revision->getID())
|
||||
->setBaseURI(new PhutilURI('/D'.$revision->getID()))
|
||||
->setCollapsed((bool)$collapsed)
|
||||
->setCollapsed((bool)$collapsed_value)
|
||||
->build($changesets);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,11 +150,14 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
}
|
||||
|
||||
public static function getDefaultRendererForViewer(PhabricatorUser $viewer) {
|
||||
$prefs = $viewer->loadPreferences();
|
||||
$pref_unified = PhabricatorUserPreferences::PREFERENCE_DIFF_UNIFIED;
|
||||
if ($prefs->getPreference($pref_unified) == 'unified') {
|
||||
$is_unified = $viewer->compareUserSetting(
|
||||
PhabricatorUnifiedDiffsSetting::SETTINGKEY,
|
||||
PhabricatorUnifiedDiffsSetting::VALUE_ALWAYS_UNIFIED);
|
||||
|
||||
if ($is_unified) {
|
||||
return '1up';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -458,6 +461,10 @@ final class DifferentialChangesetParser extends Phobject {
|
|||
}
|
||||
|
||||
public function saveCache() {
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->highlightErrors) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -175,9 +175,10 @@ final class DifferentialInlineCommentQuery
|
|||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$pref = $viewer->loadPreferences()->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_DIFF_GHOSTS);
|
||||
if ($pref == 'disabled') {
|
||||
$no_ghosts = $viewer->compareUserSetting(
|
||||
PhabricatorOlderInlinesSetting::SETTINGKEY,
|
||||
PhabricatorOlderInlinesSetting::VALUE_GHOST_INLINES_DISABLED);
|
||||
if ($no_ghosts) {
|
||||
return $inlines;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,10 @@ final class DiffusionBranchQueryConduitAPIMethod
|
|||
} else {
|
||||
$refs = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsOriginBranch(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_BRANCH,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,10 @@ final class DiffusionTagsQueryConduitAPIMethod
|
|||
|
||||
$refs = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsTag(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_TAG,
|
||||
))
|
||||
->execute();
|
||||
|
||||
$tags = array();
|
||||
|
|
|
@ -325,14 +325,15 @@ final class DiffusionCommitController extends DiffusionController {
|
|||
|
||||
$add_comment = $this->renderAddCommentPanel($commit, $audit_requests);
|
||||
|
||||
$prefs = $viewer->loadPreferences();
|
||||
$pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
|
||||
$filetree_on = $viewer->compareUserSetting(
|
||||
PhabricatorShowFiletreeSetting::SETTINGKEY,
|
||||
PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE);
|
||||
|
||||
$pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
|
||||
$show_filetree = $prefs->getPreference($pref_filetree);
|
||||
$collapsed = $prefs->getPreference($pref_collapse);
|
||||
$collapsed = $viewer->getUserSetting($pref_collapse);
|
||||
|
||||
$nav = null;
|
||||
if ($show_changesets && $show_filetree) {
|
||||
if ($show_changesets && $filetree_on) {
|
||||
$nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
|
||||
->setTitle($commit->getDisplayName())
|
||||
->setBaseURI(new PhutilURI($commit->getURI()))
|
||||
|
|
|
@ -463,6 +463,8 @@ final class DiffusionURIEditor
|
|||
break;
|
||||
}
|
||||
|
||||
$was_hosted = $repository->isHosted();
|
||||
|
||||
if ($observe_uri) {
|
||||
$repository
|
||||
->setHosted(false)
|
||||
|
@ -477,6 +479,17 @@ final class DiffusionURIEditor
|
|||
|
||||
$repository->save();
|
||||
|
||||
$is_hosted = $repository->isHosted();
|
||||
|
||||
// If we've swapped the repository from hosted to observed or vice versa,
|
||||
// reset all the cluster version clocks.
|
||||
if ($was_hosted != $is_hosted) {
|
||||
$cluster_engine = id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($this->getActor())
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyAfterHostingChange();
|
||||
}
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,12 +137,28 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
$version = idx($versions, $device->getPHID());
|
||||
if ($version) {
|
||||
$version_number = $version->getRepositoryVersion();
|
||||
$version_number = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => "/diffusion/pushlog/view/{$version_number}/",
|
||||
),
|
||||
$version_number);
|
||||
|
||||
$href = null;
|
||||
if ($repository->isHosted()) {
|
||||
$href = "/diffusion/pushlog/view/{$version_number}/";
|
||||
} else {
|
||||
$commit = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($version_number))
|
||||
->executeOne();
|
||||
if ($commit) {
|
||||
$href = $commit->getURI();
|
||||
}
|
||||
}
|
||||
|
||||
if ($href) {
|
||||
$version_number = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $href,
|
||||
),
|
||||
$version_number);
|
||||
}
|
||||
} else {
|
||||
$version_number = '-';
|
||||
}
|
||||
|
|
|
@ -82,6 +82,53 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task sync
|
||||
*/
|
||||
public function synchronizeWorkingCopyAfterHostingChange() {
|
||||
if (!$this->shouldEnableSynchronization()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$repository_phid = $repository->getPHID();
|
||||
|
||||
$versions = PhabricatorRepositoryWorkingCopyVersion::loadVersions(
|
||||
$repository_phid);
|
||||
$versions = mpull($versions, null, 'getDevicePHID');
|
||||
|
||||
// After converting a hosted repository to observed, or vice versa, we
|
||||
// need to reset version numbers because the clocks for observed and hosted
|
||||
// repositories run on different units.
|
||||
|
||||
// We identify all the cluster leaders and reset their version to 0.
|
||||
// We identify all the cluster followers and demote them.
|
||||
|
||||
// This allows the cluter to start over again at version 0 but keep the
|
||||
// same leaders.
|
||||
|
||||
if ($versions) {
|
||||
$max_version = (int)max(mpull($versions, 'getRepositoryVersion'));
|
||||
foreach ($versions as $version) {
|
||||
$device_phid = $version->getDevicePHID();
|
||||
|
||||
if ($version->getRepositoryVersion() == $max_version) {
|
||||
PhabricatorRepositoryWorkingCopyVersion::updateVersion(
|
||||
$repository_phid,
|
||||
$device_phid,
|
||||
0);
|
||||
} else {
|
||||
PhabricatorRepositoryWorkingCopyVersion::demoteDevice(
|
||||
$repository_phid,
|
||||
$device_phid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task sync
|
||||
*/
|
||||
|
@ -149,14 +196,18 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
|
||||
$max_version = (int)max(mpull($versions, 'getRepositoryVersion'));
|
||||
if ($max_version > $this_version) {
|
||||
$fetchable = array();
|
||||
foreach ($versions as $version) {
|
||||
if ($version->getRepositoryVersion() == $max_version) {
|
||||
$fetchable[] = $version->getDevicePHID();
|
||||
if ($repository->isHosted()) {
|
||||
$fetchable = array();
|
||||
foreach ($versions as $version) {
|
||||
if ($version->getRepositoryVersion() == $max_version) {
|
||||
$fetchable[] = $version->getDevicePHID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->synchronizeWorkingCopyFromDevices($fetchable);
|
||||
$this->synchronizeWorkingCopyFromDevices($fetchable);
|
||||
} else {
|
||||
$this->synchornizeWorkingCopyFromRemote();
|
||||
}
|
||||
|
||||
PhabricatorRepositoryWorkingCopyVersion::updateVersion(
|
||||
$repository_phid,
|
||||
|
@ -329,6 +380,47 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
}
|
||||
|
||||
|
||||
public function synchronizeWorkingCopyAfterDiscovery($new_version) {
|
||||
if (!$this->shouldEnableSynchronization()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
$repository_phid = $repository->getPHID();
|
||||
if ($repository->isHosted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
$device_phid = $device->getPHID();
|
||||
|
||||
// NOTE: We are not holding a lock here because this method is only called
|
||||
// from PhabricatorRepositoryDiscoveryEngine, which already holds a device
|
||||
// lock. Even if we do race here and record an older version, the
|
||||
// consequences are mild: we only do extra work to correct it later.
|
||||
|
||||
$versions = PhabricatorRepositoryWorkingCopyVersion::loadVersions(
|
||||
$repository_phid);
|
||||
$versions = mpull($versions, null, 'getDevicePHID');
|
||||
|
||||
$this_version = idx($versions, $device_phid);
|
||||
if ($this_version) {
|
||||
$this_version = (int)$this_version->getRepositoryVersion();
|
||||
} else {
|
||||
$this_version = -1;
|
||||
}
|
||||
|
||||
if ($new_version > $this_version) {
|
||||
PhabricatorRepositoryWorkingCopyVersion::updateVersion(
|
||||
$repository_phid,
|
||||
$device_phid,
|
||||
$new_version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task sync
|
||||
*/
|
||||
|
@ -471,13 +563,6 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: It may eventually make sense to try to version and synchronize
|
||||
// observed repositories (so that daemons don't do reads against out-of
|
||||
// date hosts), but don't bother for now.
|
||||
if (!$repository->isHosted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
if (!$device) {
|
||||
return false;
|
||||
|
@ -487,6 +572,50 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task internal
|
||||
*/
|
||||
private function synchornizeWorkingCopyFromRemote() {
|
||||
$repository = $this->getRepository();
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
|
||||
$local_path = $repository->getLocalPath();
|
||||
$fetch_uri = $repository->getRemoteURIEnvelope();
|
||||
|
||||
if ($repository->isGit()) {
|
||||
$this->requireWorkingCopy();
|
||||
|
||||
$argv = array(
|
||||
'fetch --prune -- %P %s',
|
||||
$fetch_uri,
|
||||
'+refs/*:refs/*',
|
||||
);
|
||||
} else {
|
||||
throw new Exception(pht('Remote sync only supported for git!'));
|
||||
}
|
||||
|
||||
$future = DiffusionCommandEngine::newCommandEngine($repository)
|
||||
->setArgv($argv)
|
||||
->setSudoAsDaemon(true)
|
||||
->setCredentialPHID($repository->getCredentialPHID())
|
||||
->setProtocol($repository->getRemoteProtocol())
|
||||
->newFuture();
|
||||
|
||||
$future->setCWD($local_path);
|
||||
|
||||
try {
|
||||
$future->resolvex();
|
||||
} catch (Exception $ex) {
|
||||
$this->logLine(
|
||||
pht(
|
||||
'Synchronization of "%s" from remote failed: %s',
|
||||
$device->getName(),
|
||||
$ex->getMessage()));
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task internal
|
||||
*/
|
||||
|
@ -560,17 +689,7 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
$local_path = $repository->getLocalPath();
|
||||
|
||||
if ($repository->isGit()) {
|
||||
if (!Filesystem::pathExists($local_path)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Repository "%s" does not have a working copy on this device '.
|
||||
'yet, so it can not be synchronized. Wait for the daemons to '.
|
||||
'construct one or run `bin/repository update %s` on this host '.
|
||||
'("%s") to build it explicitly.',
|
||||
$repository->getDisplayName(),
|
||||
$repository->getMonogram(),
|
||||
$device->getName()));
|
||||
}
|
||||
$this->requireWorkingCopy();
|
||||
|
||||
$argv = array(
|
||||
'fetch --prune -- %s %s',
|
||||
|
@ -622,4 +741,24 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
|||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function requireWorkingCopy() {
|
||||
$repository = $this->getRepository();
|
||||
$local_path = $repository->getLocalPath();
|
||||
|
||||
if (!Filesystem::pathExists($local_path)) {
|
||||
$device = AlmanacKeys::getLiveDevice();
|
||||
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Repository "%s" does not have a working copy on this device '.
|
||||
'yet, so it can not be synchronized. Wait for the daemons to '.
|
||||
'construct one or run `bin/repository update %s` on this host '.
|
||||
'("%s") to build it explicitly.',
|
||||
$repository->getDisplayName(),
|
||||
$repository->getMonogram(),
|
||||
$device->getName()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,19 +67,23 @@ final class DiffusionLowLevelCommitFieldsQuery
|
|||
->withCommitHashes($hash_list)
|
||||
->execute();
|
||||
|
||||
if (!empty($revisions)) {
|
||||
if ($revisions) {
|
||||
$revision = $this->pickBestRevision($revisions);
|
||||
|
||||
$fields['revisionID'] = $revision->getID();
|
||||
$revision_hashes = $revision->getHashes();
|
||||
|
||||
$revision_hashes = DiffusionCommitHash::convertArrayToObjects(
|
||||
$revision_hashes);
|
||||
$revision_hashes = mpull($revision_hashes, 'getHashType');
|
||||
$revision_hashes = mpull($revision_hashes, null, 'getHashType');
|
||||
|
||||
// sort the hashes in the order the mighty
|
||||
// @{class:ArcanstDifferentialRevisionHash} does; probably unnecessary
|
||||
// but should future proof things nicely.
|
||||
$revision_hashes = array_select_keys(
|
||||
$revision_hashes,
|
||||
ArcanistDifferentialRevisionHash::getTypes());
|
||||
|
||||
foreach ($hashes as $hash) {
|
||||
$revision_hash = idx($revision_hashes, $hash->getHashType());
|
||||
if (!$revision_hash) {
|
||||
|
|
|
@ -6,30 +6,33 @@
|
|||
*/
|
||||
final class DiffusionLowLevelGitRefQuery extends DiffusionLowLevelQuery {
|
||||
|
||||
private $isTag;
|
||||
private $isOriginBranch;
|
||||
private $refTypes;
|
||||
|
||||
public function withIsTag($is_tag) {
|
||||
$this->isTag = $is_tag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withIsOriginBranch($is_origin_branch) {
|
||||
$this->isOriginBranch = $is_origin_branch;
|
||||
public function withRefTypes(array $ref_types) {
|
||||
$this->refTypes = $ref_types;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function executeQuery() {
|
||||
$ref_types = $this->refTypes;
|
||||
if ($ref_types) {
|
||||
$type_branch = PhabricatorRepositoryRefCursor::TYPE_BRANCH;
|
||||
$type_tag = PhabricatorRepositoryRefCursor::TYPE_TAG;
|
||||
|
||||
$ref_types = array_fuse($ref_types);
|
||||
|
||||
$with_branches = isset($ref_types[$type_branch]);
|
||||
$with_tags = isset($ref_types[$type_tag]);
|
||||
} else {
|
||||
$with_branches = true;
|
||||
$with_tags = true;
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$prefixes = array();
|
||||
|
||||
$any = ($this->isTag || $this->isOriginBranch);
|
||||
if (!$any) {
|
||||
throw new Exception(pht('Specify types of refs to query.'));
|
||||
}
|
||||
|
||||
if ($this->isOriginBranch) {
|
||||
if ($with_branches) {
|
||||
if ($repository->isWorkingCopyBare()) {
|
||||
$prefix = 'refs/heads/';
|
||||
} else {
|
||||
|
@ -39,7 +42,7 @@ final class DiffusionLowLevelGitRefQuery extends DiffusionLowLevelQuery {
|
|||
$prefixes[] = $prefix;
|
||||
}
|
||||
|
||||
if ($this->isTag) {
|
||||
if ($with_tags) {
|
||||
$prefixes[] = 'refs/tags/';
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,11 @@ final class DiffusionLowLevelResolveRefsQuery
|
|||
// First, resolve branches and tags.
|
||||
$ref_map = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsTag(true)
|
||||
->withIsOriginBranch(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_BRANCH,
|
||||
PhabricatorRepositoryRefCursor::TYPE_TAG,
|
||||
))
|
||||
->execute();
|
||||
$ref_map = mgroup($ref_map, 'getShortName');
|
||||
|
||||
|
|
|
@ -207,9 +207,10 @@ final class PhabricatorFeedStoryPublisher extends Phobject {
|
|||
|
||||
$tags = $this->getMailTags();
|
||||
if ($tags) {
|
||||
$all_prefs = id(new PhabricatorUserPreferences())->loadAllWhere(
|
||||
'userPHID in (%Ls)',
|
||||
$phids);
|
||||
$all_prefs = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withUserPHIDs($phids)
|
||||
->execute();
|
||||
$all_prefs = mpull($all_prefs, null, 'getUserPHID');
|
||||
}
|
||||
|
||||
|
|
|
@ -164,33 +164,6 @@ final class PhabricatorMetaMTAMail
|
|||
return $this->getParam('herald-force-recipients', array());
|
||||
}
|
||||
|
||||
public function getTranslation(array $objects) {
|
||||
$default_translation = PhabricatorEnv::getEnvConfig('translation.provider');
|
||||
$return = null;
|
||||
$recipients = array_merge(
|
||||
idx($this->parameters, 'to', array()),
|
||||
idx($this->parameters, 'cc', array()));
|
||||
foreach (array_select_keys($objects, $recipients) as $object) {
|
||||
$translation = null;
|
||||
if ($object instanceof PhabricatorUser) {
|
||||
$translation = $object->getTranslation();
|
||||
}
|
||||
if (!$translation) {
|
||||
$translation = $default_translation;
|
||||
}
|
||||
if ($return && $translation != $return) {
|
||||
return $default_translation;
|
||||
}
|
||||
$return = $translation;
|
||||
}
|
||||
|
||||
if (!$return) {
|
||||
$return = $default_translation;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function addPHIDHeaders($name, array $phids) {
|
||||
$phids = array_unique($phids);
|
||||
foreach ($phids as $phid) {
|
||||
|
@ -940,9 +913,10 @@ final class PhabricatorMetaMTAMail
|
|||
}
|
||||
}
|
||||
|
||||
$all_prefs = id(new PhabricatorUserPreferences())->loadAllWhere(
|
||||
'userPHID in (%Ls)',
|
||||
$actor_phids);
|
||||
$all_prefs = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withUserPHIDs($actor_phids)
|
||||
->execute();
|
||||
$all_prefs = mpull($all_prefs, null, 'getUserPHID');
|
||||
|
||||
$value_email = PhabricatorUserPreferences::MAILTAG_PREFERENCE_EMAIL;
|
||||
|
|
70
src/applications/people/cache/PhabricatorUserCacheType.php
vendored
Normal file
70
src/applications/people/cache/PhabricatorUserCacheType.php
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorUserCacheType extends Phobject {
|
||||
|
||||
final public function getViewer() {
|
||||
return PhabricatorUser::getOmnipotentUser();
|
||||
}
|
||||
|
||||
public function getAutoloadKeys() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function canManageKey($key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDefaultValue() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getValueFromStorage($value) {
|
||||
return phutil_json_decode($value);
|
||||
}
|
||||
|
||||
public function getValueForStorage($value) {
|
||||
return phutil_json_encode($value);
|
||||
}
|
||||
|
||||
public function newValueForUsers($key, array $users) {
|
||||
return array();
|
||||
}
|
||||
|
||||
final public function getUserCacheType() {
|
||||
return $this->getPhobjectClassConstant('CACHETYPE');
|
||||
}
|
||||
|
||||
public static function getAllCacheTypes() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->setUniqueMethod('getUserCacheType')
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function getCacheTypeForKey($key) {
|
||||
$all = self::getAllCacheTypes();
|
||||
|
||||
foreach ($all as $type) {
|
||||
if ($type->canManageKey($key)) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function requireCacheTypeForKey($key) {
|
||||
$type = self::getCacheTypeForKey($key);
|
||||
|
||||
if (!$type) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to load UserCacheType to manage key "%s". This cache type '.
|
||||
'is required.',
|
||||
$key));
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
}
|
31
src/applications/people/cache/PhabricatorUserPreferencesCacheType.php
vendored
Normal file
31
src/applications/people/cache/PhabricatorUserPreferencesCacheType.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesCacheType
|
||||
extends PhabricatorUserCacheType {
|
||||
|
||||
const CACHETYPE = 'preferences';
|
||||
|
||||
const KEY_PREFERENCES = 'user.preferences.v1';
|
||||
|
||||
public function getAutoloadKeys() {
|
||||
return array(
|
||||
self::KEY_PREFERENCES,
|
||||
);
|
||||
}
|
||||
|
||||
public function canManageKey($key) {
|
||||
return ($key === self::KEY_PREFERENCES);
|
||||
}
|
||||
|
||||
public function newValueForUsers($key, array $users) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(mpull($users, 'getPHID'))
|
||||
->execute();
|
||||
|
||||
return mpull($preferences, 'getPreferences', 'getUserPHID');
|
||||
}
|
||||
|
||||
}
|
|
@ -136,6 +136,10 @@ final class PhabricatorMentionRemarkupRule extends PhutilRemarkupRule {
|
|||
),
|
||||
'@'.$user->getUserName());
|
||||
} else {
|
||||
if ($engine->getConfig('uri.full')) {
|
||||
$user_href = PhabricatorEnv::getURI($user_href);
|
||||
}
|
||||
|
||||
$tag = id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_PERSON)
|
||||
->setPHID($user->getPHID())
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* @task image-cache Profile Image Cache
|
||||
* @task factors Multi-Factor Authentication
|
||||
* @task handles Managing Handles
|
||||
* @task settings Settings
|
||||
* @task cache User Cache
|
||||
*/
|
||||
final class PhabricatorUser
|
||||
extends PhabricatorUserDAO
|
||||
|
@ -25,15 +27,12 @@ final class PhabricatorUser
|
|||
|
||||
protected $userName;
|
||||
protected $realName;
|
||||
protected $sex;
|
||||
protected $translation;
|
||||
protected $passwordSalt;
|
||||
protected $passwordHash;
|
||||
protected $profileImagePHID;
|
||||
protected $profileImageCache;
|
||||
protected $availabilityCache;
|
||||
protected $availabilityCacheTTL;
|
||||
protected $timezoneIdentifier = '';
|
||||
|
||||
protected $consoleEnabled = 0;
|
||||
protected $consoleVisible = 0;
|
||||
|
@ -61,18 +60,16 @@ final class PhabricatorUser
|
|||
|
||||
private $alternateCSRFString = self::ATTACHABLE;
|
||||
private $session = self::ATTACHABLE;
|
||||
private $rawCacheData = array();
|
||||
private $usableCacheData = array();
|
||||
|
||||
private $authorities = array();
|
||||
private $handlePool;
|
||||
private $csrfSalt;
|
||||
private $timezoneOverride;
|
||||
|
||||
protected function readField($field) {
|
||||
switch ($field) {
|
||||
case 'timezoneIdentifier':
|
||||
// If the user hasn't set one, guess the server's time.
|
||||
return nonempty(
|
||||
$this->timezoneIdentifier,
|
||||
date_default_timezone_get());
|
||||
// Make sure these return booleans.
|
||||
case 'isAdmin':
|
||||
return (bool)$this->isAdmin;
|
||||
|
@ -188,8 +185,6 @@ final class PhabricatorUser
|
|||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'userName' => 'sort64',
|
||||
'realName' => 'text128',
|
||||
'sex' => 'text4?',
|
||||
'translation' => 'text64?',
|
||||
'passwordSalt' => 'text32?',
|
||||
'passwordHash' => 'text128?',
|
||||
'profileImagePHID' => 'phid?',
|
||||
|
@ -201,7 +196,6 @@ final class PhabricatorUser
|
|||
'isMailingList' => 'bool',
|
||||
'isDisabled' => 'bool',
|
||||
'isAdmin' => 'bool',
|
||||
'timezoneIdentifier' => 'text255',
|
||||
'isEmailVerified' => 'uint32',
|
||||
'isApproved' => 'uint32',
|
||||
'accountSecret' => 'bytes64',
|
||||
|
@ -258,11 +252,6 @@ final class PhabricatorUser
|
|||
return $this;
|
||||
}
|
||||
|
||||
// To satisfy PhutilPerson.
|
||||
public function getSex() {
|
||||
return $this->sex;
|
||||
}
|
||||
|
||||
public function getMonogram() {
|
||||
return '@'.$this->getUsername();
|
||||
}
|
||||
|
@ -487,6 +476,71 @@ final class PhabricatorUser
|
|||
'(isPrimary = 1)');
|
||||
}
|
||||
|
||||
|
||||
/* -( Settings )----------------------------------------------------------- */
|
||||
|
||||
|
||||
public function getUserSetting($key) {
|
||||
$settings_key = PhabricatorUserPreferencesCacheType::KEY_PREFERENCES;
|
||||
$settings = $this->requireCacheData($settings_key);
|
||||
|
||||
if (array_key_exists($key, $settings)) {
|
||||
return $settings[$key];
|
||||
}
|
||||
|
||||
$defaults = PhabricatorSetting::getAllEnabledSettings($this);
|
||||
if (isset($defaults[$key])) {
|
||||
return $defaults[$key]->getSettingDefaultValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if a given setting is set to a particular value.
|
||||
*
|
||||
* @param const Setting key.
|
||||
* @param wild Value to compare.
|
||||
* @return bool True if the setting has the specified value.
|
||||
* @task settings
|
||||
*/
|
||||
public function compareUserSetting($key, $value) {
|
||||
$actual = $this->getUserSetting($key);
|
||||
return ($actual == $value);
|
||||
}
|
||||
|
||||
public function getTranslation() {
|
||||
return $this->getUserSetting(PhabricatorTranslationSetting::SETTINGKEY);
|
||||
}
|
||||
|
||||
public function getTimezoneIdentifier() {
|
||||
if ($this->timezoneOverride) {
|
||||
return $this->timezoneOverride;
|
||||
}
|
||||
|
||||
return $this->getUserSetting(PhabricatorTimezoneSetting::SETTINGKEY);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override the user's timezone identifier.
|
||||
*
|
||||
* This is primarily useful for unit tests.
|
||||
*
|
||||
* @param string New timezone identifier.
|
||||
* @return this
|
||||
* @task settings
|
||||
*/
|
||||
public function overrideTimezoneIdentifier($identifier) {
|
||||
$this->timezoneOverride = $identifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSex() {
|
||||
return $this->getUserSetting(PhabricatorPronounSetting::SETTINGKEY);
|
||||
}
|
||||
|
||||
public function loadPreferences() {
|
||||
if ($this->preferences) {
|
||||
return $this->preferences;
|
||||
|
@ -494,14 +548,16 @@ final class PhabricatorUser
|
|||
|
||||
$preferences = null;
|
||||
if ($this->getPHID()) {
|
||||
$preferences = id(new PhabricatorUserPreferences())->loadOneWhere(
|
||||
'userPHID = %s',
|
||||
$this->getPHID());
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($this)
|
||||
->withUsers(array($this))
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
if (!$preferences) {
|
||||
$preferences = new PhabricatorUserPreferences();
|
||||
$preferences->setUserPHID($this->getPHID());
|
||||
$preferences->attachUser($this);
|
||||
|
||||
$default_dict = array(
|
||||
PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph',
|
||||
|
@ -968,6 +1024,10 @@ final class PhabricatorUser
|
|||
* @task availability
|
||||
*/
|
||||
public function writeAvailabilityCache(array $availability, $ttl) {
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
queryfx(
|
||||
$this->establishConnection('w'),
|
||||
|
@ -1289,11 +1349,12 @@ final class PhabricatorUser
|
|||
$external->delete();
|
||||
}
|
||||
|
||||
$prefs = id(new PhabricatorUserPreferences())->loadAllWhere(
|
||||
'userPHID = %s',
|
||||
$this->getPHID());
|
||||
$prefs = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($engine->getViewer())
|
||||
->withUsers(array($this))
|
||||
->execute();
|
||||
foreach ($prefs as $pref) {
|
||||
$pref->delete();
|
||||
$engine->destroyObject($pref);
|
||||
}
|
||||
|
||||
$profiles = id(new PhabricatorUserProfile())->loadAllWhere(
|
||||
|
@ -1454,4 +1515,68 @@ final class PhabricatorUser
|
|||
}
|
||||
|
||||
|
||||
/* -( User Cache )--------------------------------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* @task cache
|
||||
*/
|
||||
public function attachRawCacheData(array $data) {
|
||||
$this->rawCacheData = $data + $this->rawCacheData;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task cache
|
||||
*/
|
||||
protected function requireCacheData($key) {
|
||||
if (isset($this->usableCacheData[$key])) {
|
||||
return $this->usableCacheData[$key];
|
||||
}
|
||||
|
||||
$type = PhabricatorUserCacheType::requireCacheTypeForKey($key);
|
||||
|
||||
if (isset($this->rawCacheData[$key])) {
|
||||
$raw_value = $this->rawCacheData[$key];
|
||||
|
||||
$usable_value = $type->getValueFromStorage($raw_value);
|
||||
$this->usableCacheData[$key] = $usable_value;
|
||||
|
||||
return $usable_value;
|
||||
}
|
||||
|
||||
$usable_value = $type->getDefaultValue();
|
||||
|
||||
$user_phid = $this->getPHID();
|
||||
if ($user_phid) {
|
||||
$map = $type->newValueForUsers($key, array($this));
|
||||
if (array_key_exists($user_phid, $map)) {
|
||||
$usable_value = $map[$user_phid];
|
||||
$raw_value = $type->getValueForStorage($usable_value);
|
||||
|
||||
$this->rawCacheData[$key] = $raw_value;
|
||||
PhabricatorUserCache::writeCache(
|
||||
$type,
|
||||
$key,
|
||||
$user_phid,
|
||||
$raw_value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->usableCacheData[$key] = $usable_value;
|
||||
|
||||
return $usable_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task cache
|
||||
*/
|
||||
public function clearCacheData($key) {
|
||||
unset($this->rawCacheData[$key]);
|
||||
unset($this->usableCacheData[$key]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
110
src/applications/people/storage/PhabricatorUserCache.php
Normal file
110
src/applications/people/storage/PhabricatorUserCache.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserCache extends PhabricatorUserDAO {
|
||||
|
||||
protected $userPHID;
|
||||
protected $cacheIndex;
|
||||
protected $cacheKey;
|
||||
protected $cacheData;
|
||||
protected $cacheType;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'cacheIndex' => 'bytes12',
|
||||
'cacheKey' => 'text255',
|
||||
'cacheData' => 'text',
|
||||
'cacheType' => 'text32',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_usercache' => array(
|
||||
'columns' => array('userPHID', 'cacheIndex'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_cachekey' => array(
|
||||
'columns' => array('cacheIndex'),
|
||||
),
|
||||
'key_cachetype' => array(
|
||||
'columns' => array('cacheType'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function save() {
|
||||
$this->cacheIndex = Filesystem::digestForIndex($this->getCacheKey());
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
public static function writeCache(
|
||||
PhabricatorUserCacheType $type,
|
||||
$key,
|
||||
$user_phid,
|
||||
$raw_value) {
|
||||
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = new self();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (userPHID, cacheIndex, cacheKey, cacheData, cacheType)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE cacheData = VALUES(cacheData)',
|
||||
$table->getTableName(),
|
||||
$user_phid,
|
||||
PhabricatorHash::digestForIndex($key),
|
||||
$key,
|
||||
$raw_value,
|
||||
$type->getUserCacheType());
|
||||
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
public static function clearCache($key, $user_phid) {
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = new self();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE cacheIndex = %s AND userPHID = %s',
|
||||
$table->getTableName(),
|
||||
PhabricatorHash::digestForIndex($key),
|
||||
$user_phid);
|
||||
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
|
||||
public static function clearCacheForAllUsers($key) {
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = new self();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE cacheIndex = %s',
|
||||
$table->getTableName(),
|
||||
PhabricatorHash::digestForIndex($key));
|
||||
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
}
|
|
@ -93,7 +93,9 @@ final class PhabricatorPhameApplication extends PhabricatorApplication {
|
|||
'/' => array(
|
||||
'' => 'PhameBlogViewController',
|
||||
'post/(?P<id>\d+)/(?:(?P<slug>[^/]+)/)?' => 'PhamePostViewController',
|
||||
'.*' => 'PhameBlog404Controller',
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,8 @@ abstract class PhameLiveController extends PhameController {
|
|||
|
||||
$blog = $blog_query->executeOne();
|
||||
if (!$blog) {
|
||||
$this->isExternal = $is_external;
|
||||
$this->isLive = $is_live;
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
|
@ -81,6 +83,9 @@ abstract class PhameLiveController extends PhameController {
|
|||
$blog = null;
|
||||
}
|
||||
|
||||
$this->isExternal = $is_external;
|
||||
$this->isLive = $is_live;
|
||||
|
||||
if ($post_id) {
|
||||
$post_query = id(new PhamePostQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -109,8 +114,6 @@ abstract class PhameLiveController extends PhameController {
|
|||
$post = null;
|
||||
}
|
||||
|
||||
$this->isExternal = $is_external;
|
||||
$this->isLive = $is_live;
|
||||
$this->blog = $blog;
|
||||
$this->post = $post;
|
||||
|
||||
|
@ -188,4 +191,30 @@ abstract class PhameLiveController extends PhameController {
|
|||
return $crumbs;
|
||||
}
|
||||
|
||||
public function willSendResponse(AphrontResponse $response) {
|
||||
if ($this->getIsExternal()) {
|
||||
if ($response instanceof Aphront404Response) {
|
||||
$page = $this->newPage()
|
||||
->setCrumbs($this->buildApplicationCrumbs());
|
||||
|
||||
$response = id(new Phame404Response())
|
||||
->setPage($page);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::willSendResponse($response);
|
||||
}
|
||||
|
||||
public function newPage() {
|
||||
$page = parent::newPage();
|
||||
|
||||
if ($this->getIsLive()) {
|
||||
$page
|
||||
->setShowChrome(false)
|
||||
->setShowFooter(false);
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
final class PhameBlog404Controller extends PhameLiveController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->setupLiveEnvironment();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
}
|
|
@ -108,12 +108,6 @@ final class PhameBlogViewController extends PhameLiveController {
|
|||
$about,
|
||||
));
|
||||
|
||||
if ($is_live) {
|
||||
$page
|
||||
->setShowChrome(false)
|
||||
->setShowFooter(false);
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,10 +78,14 @@ final class PhamePostViewController
|
|||
->executeOne();
|
||||
$blogger_profile = $blogger->loadUserProfile();
|
||||
|
||||
|
||||
$author_uri = '/p/'.$blogger->getUsername().'/';
|
||||
$author_uri = PhabricatorEnv::getURI($author_uri);
|
||||
|
||||
$author = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/p/'.$blogger->getUsername().'/',
|
||||
'href' => $author_uri,
|
||||
),
|
||||
$blogger->getUsername());
|
||||
|
||||
|
@ -105,7 +109,7 @@ final class PhamePostViewController
|
|||
$blogger_profile->getTitle(),
|
||||
))
|
||||
->setImage($blogger->getProfileImageURI())
|
||||
->setImageHref('/p/'.$blogger->getUsername());
|
||||
->setImageHref($author_uri);
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$post,
|
||||
|
@ -128,10 +132,10 @@ final class PhamePostViewController
|
|||
|
||||
$next_view = new PhameNextPostView();
|
||||
if ($next) {
|
||||
$next_view->setNext($next->getTitle(), $next->getViewURI());
|
||||
$next_view->setNext($next->getTitle(), $next->getLiveURI());
|
||||
}
|
||||
if ($prev) {
|
||||
$next_view->setPrevious($prev->getTitle(), $prev->getViewURI());
|
||||
$next_view->setPrevious($prev->getTitle(), $prev->getLiveURI());
|
||||
}
|
||||
|
||||
$document->setFoot($next_view);
|
||||
|
|
43
src/applications/phame/site/Phame404Response.php
Normal file
43
src/applications/phame/site/Phame404Response.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
final class Phame404Response extends AphrontHTMLResponse {
|
||||
|
||||
private $page;
|
||||
|
||||
public function setPage(AphrontPageView $page) {
|
||||
$this->page = $page;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPage() {
|
||||
return $this->page;
|
||||
}
|
||||
|
||||
public function getHTTPResponseCode() {
|
||||
return 404;
|
||||
}
|
||||
|
||||
public function buildResponseString() {
|
||||
require_celerity_resource('phame-css');
|
||||
|
||||
$not_found = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phame-404',
|
||||
),
|
||||
array(
|
||||
phutil_tag('strong', array(), pht('404 Not Found')),
|
||||
phutil_tag('br'),
|
||||
pht('Wherever you go, there you are.'),
|
||||
phutil_tag('br'),
|
||||
pht('But the page you seek is elsewhere.'),
|
||||
));
|
||||
|
||||
$page = $this->getPage()
|
||||
->setTitle(pht('404 Not Found'))
|
||||
->appendChild($not_found);
|
||||
|
||||
return $page->render();
|
||||
}
|
||||
|
||||
}
|
|
@ -62,8 +62,19 @@ final class PhamePostListView extends AphrontTagView {
|
|||
|
||||
$list = array();
|
||||
foreach ($posts as $post) {
|
||||
$blogger = $handles[$post->getBloggerPHID()]->renderLink();
|
||||
$blogger_name = $handles[$post->getBloggerPHID()]->getName();
|
||||
$blogger_uri = $handles[$post->getBloggerPHID()]->getURI();
|
||||
$blogger_uri = PhabricatorEnv::getURI($blogger_uri);
|
||||
|
||||
// Render a link manually to make sure we point at the correct domain.
|
||||
$blogger = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $blogger_uri,
|
||||
),
|
||||
$blogger_name);
|
||||
$blogger = phutil_tag('strong', array(), $blogger);
|
||||
|
||||
$blogger_image = $handles[$post->getBloggerPHID()]->getImageURI();
|
||||
|
||||
$phame_post = null;
|
||||
|
@ -74,7 +85,6 @@ final class PhamePostListView extends AphrontTagView {
|
|||
$phame_post = phutil_tag('em', array(), pht('(Empty Post)'));
|
||||
}
|
||||
|
||||
$blogger = phutil_tag('strong', array(), $blogger);
|
||||
$date = phabricator_datetime($post->getDatePublished(), $viewer);
|
||||
|
||||
$blog = $post->getBlog();
|
||||
|
|
|
@ -201,8 +201,7 @@ final class PhabricatorPolicyQuery
|
|||
$default_limit = 5;
|
||||
|
||||
// If possible, show the user's 10 most recently used projects.
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$favorites = $preferences->getPreference($pref_key);
|
||||
$favorites = $viewer->getUserSetting($pref_key);
|
||||
if (!is_array($favorites)) {
|
||||
$favorites = array();
|
||||
}
|
||||
|
|
|
@ -21,12 +21,17 @@ final class PhabricatorProjectMembersAddController
|
|||
}
|
||||
|
||||
$this->setProject($project);
|
||||
$done_uri = "/project/members/{$id}/";
|
||||
|
||||
if (!$project->supportsEditMembers()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$copy = pht('Parent projects and milestones do not support adding '.
|
||||
'members. You can add members directly to any non-parent subproject.');
|
||||
|
||||
$done_uri = "/project/members/{$id}/";
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Unsupported Project'))
|
||||
->appendParagraph($copy)
|
||||
->addCancelButton($done_uri);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$member_phids = $request->getArr('memberPHIDs');
|
||||
|
|
|
@ -32,12 +32,18 @@ final class PhabricatorProjectUpdateController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (!$project->supportsEditMembers()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$done_uri = "/project/members/{$id}/";
|
||||
|
||||
if (!$project->supportsEditMembers()) {
|
||||
$copy = pht('Parent projects and milestones do not support adding '.
|
||||
'members. You can add members directly to any non-parent subproject.');
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Unsupported Project'))
|
||||
->appendParagraph($copy)
|
||||
->addCancelButton($done_uri);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$edge_action = null;
|
||||
switch ($action) {
|
||||
|
|
|
@ -63,6 +63,7 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
|
||||
private function discoverCommitsWithLock() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$vcs = $repository->getVersionControlSystem();
|
||||
switch ($vcs) {
|
||||
|
@ -104,6 +105,14 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
$this->commitCache[$ref->getIdentifier()] = true;
|
||||
}
|
||||
|
||||
$version = $this->getObservedVersion($repository);
|
||||
if ($version !== null) {
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyAfterDiscovery($version);
|
||||
}
|
||||
|
||||
return $refs;
|
||||
}
|
||||
|
||||
|
@ -121,9 +130,15 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
$this->verifyGitOrigin($repository);
|
||||
}
|
||||
|
||||
// TODO: This should also import tags, but some of the logic is still
|
||||
// branch-specific today.
|
||||
|
||||
$branches = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsOriginBranch(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_BRANCH,
|
||||
))
|
||||
->execute();
|
||||
|
||||
if (!$branches) {
|
||||
|
@ -642,4 +657,49 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
private function getObservedVersion(PhabricatorRepository $repository) {
|
||||
if ($repository->isHosted()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($repository->isGit()) {
|
||||
return $this->getGitObservedVersion($repository);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getGitObservedVersion(PhabricatorRepository $repository) {
|
||||
$refs = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->execute();
|
||||
if (!$refs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// In Git, the observed version is the most recently discovered commit
|
||||
// at any repository HEAD. It's possible for this to regress temporarily
|
||||
// if a branch is pushed and then deleted. This is acceptable because it
|
||||
// doesn't do anything meaningfully bad and will fix itself on the next
|
||||
// push.
|
||||
|
||||
$ref_identifiers = mpull($refs, 'getCommitIdentifier');
|
||||
$ref_identifiers = array_fuse($ref_identifiers);
|
||||
|
||||
$version = queryfx_one(
|
||||
$repository->establishConnection('w'),
|
||||
'SELECT MAX(id) version FROM %T WHERE repositoryID = %d
|
||||
AND commitIdentifier IN (%Ls)',
|
||||
id(new PhabricatorRepositoryCommit())->getTableName(),
|
||||
$repository->getID(),
|
||||
$ref_identifiers);
|
||||
|
||||
if (!$version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int)$version['version'];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,27 +108,27 @@ final class PhabricatorRepositoryPullEngine
|
|||
} else {
|
||||
$this->executeSubversionCreate();
|
||||
}
|
||||
} else {
|
||||
if (!$repository->isHosted()) {
|
||||
$this->logPull(
|
||||
pht(
|
||||
'Updating the working copy for repository "%s".',
|
||||
$repository->getDisplayName()));
|
||||
if ($is_git) {
|
||||
$this->verifyGitOrigin($repository);
|
||||
$this->executeGitUpdate();
|
||||
} else if ($is_hg) {
|
||||
$this->executeMercurialUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
|
||||
if (!$repository->isHosted()) {
|
||||
$this->logPull(
|
||||
pht(
|
||||
'Updating the working copy for repository "%s".',
|
||||
$repository->getDisplayName()));
|
||||
if ($is_git) {
|
||||
$this->verifyGitOrigin($repository);
|
||||
$this->executeGitUpdate();
|
||||
} else if ($is_hg) {
|
||||
$this->executeMercurialUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
if ($repository->isHosted()) {
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
|
||||
if ($is_git) {
|
||||
$this->installGitHook();
|
||||
} else if ($is_svn) {
|
||||
|
|
|
@ -452,7 +452,10 @@ final class PhabricatorRepositoryRefEngine
|
|||
private function loadGitBranchPositions(PhabricatorRepository $repository) {
|
||||
return id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsOriginBranch(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_BRANCH,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
@ -463,7 +466,10 @@ final class PhabricatorRepositoryRefEngine
|
|||
private function loadGitTagPositions(PhabricatorRepository $repository) {
|
||||
return id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsTag(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_TAG,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -2061,7 +2061,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
$clone[] = $uri;
|
||||
}
|
||||
|
||||
return msort($clone, 'getURIScore');
|
||||
$clone = msort($clone, 'getURIScore');
|
||||
$clone = array_reverse($clone);
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -598,18 +598,25 @@ final class PhabricatorRepositoryURI
|
|||
$score = 0;
|
||||
|
||||
$io_points = array(
|
||||
self::IO_READWRITE => 20,
|
||||
self::IO_READ => 10,
|
||||
self::IO_READWRITE => 200,
|
||||
self::IO_READ => 100,
|
||||
);
|
||||
$score += idx($io_points, $this->getEffectiveIoType(), 0);
|
||||
|
||||
$protocol_points = array(
|
||||
self::BUILTIN_PROTOCOL_SSH => 3,
|
||||
self::BUILTIN_PROTOCOL_HTTPS => 2,
|
||||
self::BUILTIN_PROTOCOL_HTTP => 1,
|
||||
self::BUILTIN_PROTOCOL_SSH => 30,
|
||||
self::BUILTIN_PROTOCOL_HTTPS => 20,
|
||||
self::BUILTIN_PROTOCOL_HTTP => 10,
|
||||
);
|
||||
$score += idx($protocol_points, $this->getBuiltinProtocol(), 0);
|
||||
|
||||
$identifier_points = array(
|
||||
self::BUILTIN_IDENTIFIER_SHORTNAME => 3,
|
||||
self::BUILTIN_IDENTIFIER_CALLSIGN => 2,
|
||||
self::BUILTIN_IDENTIFIER_ID => 1,
|
||||
);
|
||||
$score += idx($identifier_points, $this->getBuiltinIdentifier(), 0);
|
||||
|
||||
return $score;
|
||||
}
|
||||
|
||||
|
|
|
@ -385,8 +385,7 @@ abstract class PhabricatorProfilePanelEngine extends Phobject {
|
|||
$collapse_key =
|
||||
PhabricatorUserPreferences::PREFERENCE_PROFILE_MENU_COLLAPSED;
|
||||
|
||||
$preferences = $viewer->loadPreferences();
|
||||
$is_collapsed = $preferences->getPreference($collapse_key, false);
|
||||
$is_collapsed = $viewer->getUserSetting($collapse_key);
|
||||
|
||||
if ($is_collapsed) {
|
||||
$nav->addClass('phui-profile-menu-collapsed');
|
||||
|
|
|
@ -68,7 +68,7 @@ abstract class PhabricatorSearchEngineAPIMethod
|
|||
'This is a standard **ApplicationSearch** method which will let you '.
|
||||
'list, query, or search for objects. For documentation on these '.
|
||||
'endpoints, see **[[ %s | Conduit API: Using Search Endpoints ]]**.',
|
||||
PhabricatorEnv::getDoclink('Conduit API: Using Edit Endpoints'));
|
||||
PhabricatorEnv::getDoclink('Conduit API: Using Search Endpoints'));
|
||||
}
|
||||
|
||||
final public function getMethodDocumentation() {
|
||||
|
|
|
@ -34,6 +34,8 @@ final class PhabricatorSettingsApplication extends PhabricatorApplication {
|
|||
'adjust/' => 'PhabricatorSettingsAdjustController',
|
||||
'timezone/(?P<offset>[^/]+)/'
|
||||
=> 'PhabricatorSettingsTimezoneController',
|
||||
'(?P<type>user)/(?P<username>[^/]+)/(?:panel/(?P<key>[^/]+)/)?'
|
||||
=> 'PhabricatorSettingsEditController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSettingsEditController
|
||||
extends PhabricatorController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$engine = id(new PhabricatorSettingsEditEngine())
|
||||
->setController($this);
|
||||
|
||||
switch ($request->getURIData('type')) {
|
||||
case 'user':
|
||||
$user = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($viewer)
|
||||
->withUsernames(array($request->getURIData('username')))
|
||||
->executeOne();
|
||||
|
||||
$preferences = $user->loadPreferences();
|
||||
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$viewer,
|
||||
$preferences,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$engine->setTargetObject($preferences);
|
||||
break;
|
||||
default:
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
return $engine->buildResponse();
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ final class PhabricatorSettingsTimezoneController
|
|||
$timezone = $request->getStr('timezone');
|
||||
|
||||
$pref_ignore = PhabricatorUserPreferences::PREFERENCE_IGNORE_OFFSET;
|
||||
$pref_timezone = PhabricatorTimezoneSetting::SETTINGKEY;
|
||||
|
||||
$preferences = $viewer->loadPreferences();
|
||||
|
||||
|
@ -52,11 +53,11 @@ final class PhabricatorSettingsTimezoneController
|
|||
if (isset($options[$timezone])) {
|
||||
$preferences
|
||||
->setPreference($pref_ignore, null)
|
||||
->setPreference($pref_timezone, $timezone)
|
||||
->save();
|
||||
|
||||
$viewer
|
||||
->setTimezoneIdentifier($timezone)
|
||||
->save();
|
||||
$viewer->clearCacheData(
|
||||
PhabricatorUserPreferencesCacheType::KEY_PREFERENCES);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,9 +116,9 @@ final class PhabricatorSettingsTimezoneController
|
|||
$offset = $offset / 60;
|
||||
|
||||
if ($offset >= 0) {
|
||||
return pht('GMT-%d', $offset);
|
||||
return pht('UTC-%d', $offset);
|
||||
} else {
|
||||
return pht('GMT+%d', -$offset);
|
||||
return pht('UTC+%d', -$offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSettingsEditEngine
|
||||
extends PhabricatorEditEngine {
|
||||
|
||||
const ENGINECONST = 'settings.settings';
|
||||
|
||||
public function isEngineConfigurable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getEngineName() {
|
||||
return pht('Settings');
|
||||
}
|
||||
|
||||
public function getSummaryHeader() {
|
||||
return pht('Edit Settings Configurations');
|
||||
}
|
||||
|
||||
public function getSummaryText() {
|
||||
return pht('This engine is used to edit settings.');
|
||||
}
|
||||
|
||||
public function getEngineApplicationClass() {
|
||||
return 'PhabricatorSettingsApplication';
|
||||
}
|
||||
|
||||
protected function newEditableObject() {
|
||||
return new PhabricatorUserPreferences();
|
||||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
return new PhabricatorUserPreferencesQuery();
|
||||
}
|
||||
|
||||
protected function getObjectCreateTitleText($object) {
|
||||
return pht('Create Settings');
|
||||
}
|
||||
|
||||
protected function getObjectCreateButtonText($object) {
|
||||
return pht('Create Settings');
|
||||
}
|
||||
|
||||
protected function getObjectEditTitleText($object) {
|
||||
return pht('Edit Settings');
|
||||
}
|
||||
|
||||
protected function getObjectEditShortText($object) {
|
||||
return pht('Edit Settings');
|
||||
}
|
||||
|
||||
protected function getObjectCreateShortText() {
|
||||
return pht('Create Settings');
|
||||
}
|
||||
|
||||
protected function getObjectName() {
|
||||
return pht('Settings');
|
||||
}
|
||||
|
||||
protected function getEditorURI() {
|
||||
return '/settings/edit/';
|
||||
}
|
||||
|
||||
protected function getObjectCreateCancelURI($object) {
|
||||
return '/settings/';
|
||||
}
|
||||
|
||||
protected function getObjectViewURI($object) {
|
||||
// TODO: This isn't correct...
|
||||
return '/settings/user/'.$this->getViewer()->getUsername().'/';
|
||||
}
|
||||
|
||||
protected function getCreateNewObjectPolicy() {
|
||||
return PhabricatorPolicies::POLICY_ADMIN;
|
||||
}
|
||||
|
||||
protected function buildCustomEditFields($object) {
|
||||
$viewer = $this->getViewer();
|
||||
$settings = PhabricatorSetting::getAllEnabledSettings($viewer);
|
||||
|
||||
foreach ($settings as $key => $setting) {
|
||||
$setting = clone $setting;
|
||||
$setting->setViewer($viewer);
|
||||
$settings[$key] = $setting;
|
||||
}
|
||||
|
||||
$fields = array();
|
||||
foreach ($settings as $setting) {
|
||||
foreach ($setting->newCustomEditFields($object) as $field) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getEditorApplicationClass() {
|
||||
return 'PhabricatorSettingsApplication';
|
||||
}
|
||||
|
||||
public function getEditorObjectsDescription() {
|
||||
return pht('Settings');
|
||||
}
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorUserPreferencesTransaction::TYPE_SETTING;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
$setting_key = $xaction->getMetadataValue(
|
||||
PhabricatorUserPreferencesTransaction::PROPERTY_SETTING);
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorUserPreferencesTransaction::TYPE_SETTING:
|
||||
return $object->getPreference($setting_key);
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
$actor = $this->getActor();
|
||||
|
||||
$setting_key = $xaction->getMetadataValue(
|
||||
PhabricatorUserPreferencesTransaction::PROPERTY_SETTING);
|
||||
|
||||
$settings = PhabricatorSetting::getAllEnabledSettings($actor);
|
||||
$setting = $settings[$setting_key];
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorUserPreferencesTransaction::TYPE_SETTING:
|
||||
$value = $xaction->getNewValue();
|
||||
$value = $setting->getTransactionNewValue($value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
$setting_key = $xaction->getMetadataValue(
|
||||
PhabricatorUserPreferencesTransaction::PROPERTY_SETTING);
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorUserPreferencesTransaction::TYPE_SETTING:
|
||||
$new_value = $xaction->getNewValue();
|
||||
if ($new_value === null) {
|
||||
$object->unsetPreference($setting_key);
|
||||
} else {
|
||||
$object->setPreference($setting_key, $new_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorUserPreferencesTransaction::TYPE_SETTING:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
|
||||
$actor = $this->getActor();
|
||||
$settings = PhabricatorSetting::getAllEnabledSettings($actor);
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorUserPreferencesTransaction::TYPE_SETTING:
|
||||
foreach ($xactions as $xaction) {
|
||||
$setting_key = $xaction->getMetadataValue(
|
||||
PhabricatorUserPreferencesTransaction::PROPERTY_SETTING);
|
||||
|
||||
$setting = idx($settings, $setting_key);
|
||||
if (!$setting) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
pht(
|
||||
'There is no known application setting with key "%s".',
|
||||
$setting_key),
|
||||
$xaction);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$setting->validateTransactionValue($xaction->getNewValue());
|
||||
} catch (Exception $ex) {
|
||||
$errors[] = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Invalid'),
|
||||
$ex->getMessage(),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
protected function applyFinalEffects(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$user_phid = $object->getUserPHID();
|
||||
if ($user_phid) {
|
||||
PhabricatorUserCache::clearCache(
|
||||
PhabricatorUserPreferencesCacheType::KEY_PREFERENCES,
|
||||
$user_phid);
|
||||
} else {
|
||||
PhabricatorUserCache::clearCacheForAllUsers(
|
||||
PhabricatorUserPreferencesCacheType::KEY_PREFERENCES);
|
||||
}
|
||||
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,21 +23,29 @@ final class PhabricatorAccountSettingsPanel extends PhabricatorSettingsPanel {
|
|||
$user = $this->getUser();
|
||||
$username = $user->getUsername();
|
||||
|
||||
$preferences = $user->loadPreferences();
|
||||
|
||||
$errors = array();
|
||||
if ($request->isFormPost()) {
|
||||
$sex = $request->getStr('sex');
|
||||
$sexes = array(PhutilPerson::SEX_MALE, PhutilPerson::SEX_FEMALE);
|
||||
if (in_array($sex, $sexes)) {
|
||||
$user->setSex($sex);
|
||||
$new_value = $sex;
|
||||
} else {
|
||||
$user->setSex(null);
|
||||
$new_value = null;
|
||||
}
|
||||
|
||||
// Checked in runtime.
|
||||
$user->setTranslation($request->getStr('translation'));
|
||||
$preferences->setPreference(
|
||||
PhabricatorPronounSetting::SETTINGKEY,
|
||||
$new_value);
|
||||
|
||||
$preferences->setPreference(
|
||||
PhabricatorTranslationSetting::SETTINGKEY,
|
||||
$request->getStr('translation'));
|
||||
|
||||
if (!$errors) {
|
||||
$user->save();
|
||||
$preferences->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI('?saved=true'));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
|
|||
$user = $request->getUser();
|
||||
$username = $user->getUsername();
|
||||
|
||||
$pref_timezone = PhabricatorTimezoneSetting::SETTINGKEY;
|
||||
$pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT;
|
||||
$pref_date = PhabricatorUserPreferences::PREFERENCE_DATE_FORMAT;
|
||||
$pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
|
||||
|
@ -27,13 +28,12 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
|
|||
$errors = array();
|
||||
if ($request->isFormPost()) {
|
||||
$new_timezone = $request->getStr('timezone');
|
||||
if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
|
||||
$user->setTimezoneIdentifier($new_timezone);
|
||||
} else {
|
||||
if (!in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) {
|
||||
$errors[] = pht('The selected timezone is not a valid timezone.');
|
||||
}
|
||||
|
||||
$preferences
|
||||
->setPreference($pref_timezone, $new_timezone)
|
||||
->setPreference(
|
||||
$pref_time,
|
||||
$request->getStr($pref_time))
|
||||
|
@ -47,7 +47,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel {
|
|||
|
||||
if (!$errors) {
|
||||
$preferences->save();
|
||||
$user->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI('?saved=true'));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesPHIDType extends PhabricatorPHIDType {
|
||||
|
||||
const TYPECONST = 'PSET';
|
||||
|
||||
public function getTypeName() {
|
||||
return pht('Settings');
|
||||
}
|
||||
|
||||
public function newObject() {
|
||||
return new PhabricatorUserPreferences();
|
||||
}
|
||||
|
||||
public function getPHIDTypeApplicationClass() {
|
||||
return 'PhabricatorSettingsApplication';
|
||||
}
|
||||
|
||||
protected function buildQueryForObjects(
|
||||
PhabricatorObjectQuery $query,
|
||||
array $phids) {
|
||||
|
||||
return id(new PhabricatorUserPreferencesQuery())
|
||||
->withPHIDs($phids);
|
||||
}
|
||||
|
||||
public function loadHandles(
|
||||
PhabricatorHandleQuery $query,
|
||||
array $handles,
|
||||
array $objects) {
|
||||
|
||||
$viewer = $query->getViewer();
|
||||
foreach ($handles as $phid => $handle) {
|
||||
$preferences = $objects[$phid];
|
||||
$handle->setName(pht('Settings %d', $preferences->getID()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $userPHIDs;
|
||||
private $users = array();
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHIDs(array $phids) {
|
||||
$this->phids = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withUserPHIDs(array $phids) {
|
||||
$this->userPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withUsers(array $users) {
|
||||
assert_instances_of($users, 'PhabricatorUser');
|
||||
$this->users = mpull($users, null, 'getPHID');
|
||||
$this->withUserPHIDs(array_keys($this->users));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorUserPreferences();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $prefs) {
|
||||
$user_phids = mpull($prefs, 'getUserPHID');
|
||||
$user_phids = array_filter($user_phids);
|
||||
|
||||
// If some of the preferences are attached to users, try to use any objects
|
||||
// we were handed first. If we're missing some, load them.
|
||||
|
||||
if ($user_phids) {
|
||||
$users = $this->users;
|
||||
|
||||
$user_phids = array_fuse($user_phids);
|
||||
$load_phids = array_diff_key($user_phids, $users);
|
||||
$load_phids = array_keys($load_phids);
|
||||
|
||||
if ($load_phids) {
|
||||
$load_users = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($load_phids)
|
||||
->execute();
|
||||
$load_users = mpull($load_users, null, 'getPHID');
|
||||
$users += $load_users;
|
||||
}
|
||||
} else {
|
||||
$users = array();
|
||||
}
|
||||
|
||||
foreach ($prefs as $key => $pref) {
|
||||
$user_phid = $pref->getUserPHID();
|
||||
if (!$user_phid) {
|
||||
$pref->attachUser(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
$user = idx($users, $user_phid);
|
||||
if (!$user) {
|
||||
$this->didRejectResult($pref);
|
||||
unset($prefs[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$pref->attachUser($user);
|
||||
}
|
||||
|
||||
return $prefs;
|
||||
}
|
||||
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->userPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'userPHID IN (%Ls)',
|
||||
$this->userPHIDs);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorSettingsApplication';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAccessibilitySetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'resource-postprocessor';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Accessibility');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'If you have difficulty reading the Phabricator UI, these settings '.
|
||||
'may make Phabricator more accessible.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return CelerityDefaultPostprocessor::POSTPROCESSOR_KEY;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
$postprocessor_map = CelerityPostprocessor::getAllPostprocessors();
|
||||
|
||||
$postprocessor_map = mpull($postprocessor_map, 'getPostprocessorName');
|
||||
asort($postprocessor_map);
|
||||
|
||||
$postprocessor_order = array(
|
||||
CelerityDefaultPostprocessor::POSTPROCESSOR_KEY,
|
||||
);
|
||||
|
||||
$postprocessor_map = array_select_keys(
|
||||
$postprocessor_map,
|
||||
$postprocessor_order) + $postprocessor_map;
|
||||
|
||||
return $postprocessor_map;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDarkConsoleSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'dark_console';
|
||||
|
||||
const VALUE_DARKCONSOLE_DISABLED = '0';
|
||||
const VALUE_DARKCONSOLE_ENABLED = '1';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('DarkConsole');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'DarkConsole is a debugging console for developing and troubleshooting '.
|
||||
'Phabricator applications. After enabling DarkConsole, press the '.
|
||||
'{nav `} key on your keyboard to toggle it on or off.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_DARKCONSOLE_DISABLED;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_DARKCONSOLE_DISABLED => pht('Disable DarkConsole'),
|
||||
self::VALUE_DARKCONSOLE_ENABLED => pht('Enable DarkConsole'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDateFormatSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'date-format';
|
||||
|
||||
const VALUE_FORMAT_ISO = 'Y-m-d';
|
||||
const VALUE_FORMAT_US = 'n/j/Y';
|
||||
const VALUE_FORMAT_EUROPE = 'd-m-Y';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Date Format');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Select the format you prefer for editing dates.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_FORMAT_ISO;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_FORMAT_ISO => pht('ISO 8601: 2000-02-28'),
|
||||
self::VALUE_FORMAT_US => pht('US: 2/28/2000'),
|
||||
self::VALUE_FORMAT_EUROPE => pht('Europe: 28-02-2000'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEditorMultipleSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'multiedit';
|
||||
|
||||
const VALUE_SPACES = 'spaces';
|
||||
const VALUE_SINGLE = 'disable';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Edit Mulitple Files');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Some editors support opening multiple files with a single URI. You '.
|
||||
'can specify the behavior of your editor here.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_SPACES;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_SPACES => pht('Supported, Separated by Spaces'),
|
||||
self::VALUE_SINGLE => pht('Not Supported'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEditorSetting
|
||||
extends PhabricatorStringSetting {
|
||||
|
||||
const SETTINGKEY = 'editor';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Editor Link');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
"Many text editors can be configured as URI handlers for special ".
|
||||
"protocols like `editor://`. If you have such an editor, Phabricator ".
|
||||
"can generate links that you can click to open files locally.".
|
||||
"\n\n".
|
||||
"These special variables are supported:".
|
||||
"\n\n".
|
||||
"| Value | Replaced With |\n".
|
||||
"|-------|---------------|\n".
|
||||
"| `%%f` | Filename |\n".
|
||||
"| `%%l` | Line Number |\n".
|
||||
"| `%%r` | Repository Callsign |\n".
|
||||
"| `%%%%` | Literal `%%` |\n".
|
||||
"\n\n".
|
||||
"For complete instructions on editor configuration, ".
|
||||
"see **[[ %s | %s ]]**.",
|
||||
PhabricatorEnv::getDoclink('User Guide: Configuring an External Editor'),
|
||||
pht('User Guide: Configuring an External Editor'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEmailFormatSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'html-emails';
|
||||
|
||||
const VALUE_HTML_EMAIL = 'true';
|
||||
const VALUE_TEXT_EMAIL = 'false';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('HTML Email');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'You can opt to receive plain text email from Phabricator instead '.
|
||||
'of HTML email. Plain text email works better with some clients.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_HTML_EMAIL;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_HTML_EMAIL => pht('Send HTML Email'),
|
||||
self::VALUE_TEXT_EMAIL => pht('Send Plain Text Email'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEmailNotificationsSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'no-mail';
|
||||
|
||||
const VALUE_SEND_MAIL = '0';
|
||||
const VALUE_NO_MAIL = '1';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Email Notifications');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'If you disable **Email Notifications**, Phabricator will never '.
|
||||
'send email to notify you about events. This preference overrides '.
|
||||
'all your other settings.'.
|
||||
"\n\n".
|
||||
"//You will still receive some administrative email, like password ".
|
||||
"reset email.//");
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_SEND_MAIL;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_SEND_MAIL => pht('Enable Email Notifications'),
|
||||
self::VALUE_NO_MAIL => pht('Disable Email Notifications'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEmailRePrefixSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 're-prefix';
|
||||
|
||||
const VALUE_RE_PREFIX = 'true';
|
||||
const VALUE_NO_PREFIX = 'false';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Add "Re:" Prefix');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'The **Add "Re:" Prefix** setting adds "Re:" in front of all messages, '.
|
||||
'even if they are not replies. If you use **Mail.app** on Mac OS X, '.
|
||||
'this may improve mail threading.'.
|
||||
"\n\n".
|
||||
"| Setting | Example Mail Subject\n".
|
||||
"|------------------------|----------------\n".
|
||||
"| Enable \"Re:\" Prefix | ".
|
||||
"`Re: [Differential] [Accepted] D123: Example Revision`\n".
|
||||
"| Disable \"Re:\" Prefix | ".
|
||||
"`[Differential] [Accepted] D123: Example Revision`");
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_RE_PREFIX;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_RE_PREFIX => pht('Enable "Re:" Prefix'),
|
||||
self::VALUE_NO_PREFIX => pht('Disable "Re:" Prefix'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEmailSelfActionsSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'self-mail';
|
||||
|
||||
const VALUE_SEND_SELF = '0';
|
||||
const VALUE_NO_SELF = '1';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Self Actions');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'If you disable **Self Actions**, Phabricator will not notify '.
|
||||
'you about actions you take.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_SEND_SELF;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_SEND_SELF => pht('Enable Self Action Mail'),
|
||||
self::VALUE_NO_SELF => pht('Disable Self Action Mail'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorEmailVarySubjectsSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'vary-subjects';
|
||||
|
||||
const VALUE_VARY_SUBJECTS = 'true';
|
||||
const VALUE_STATIC_SUBJECTS = 'false';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Vary Subjects');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'With **Vary Subjects** enabled, most mail subject lines will include '.
|
||||
'a brief description of their content, like `[Closed]` for a '.
|
||||
'notification about someone closing a task.'.
|
||||
"\n\n".
|
||||
"| Setting | Example Mail Subject\n".
|
||||
"|----------------------|----------------\n".
|
||||
"| Vary Subjects | ".
|
||||
"`[Maniphest] [Closed] T123: Example Task`\n".
|
||||
"| Do Not Vary Subjects | ".
|
||||
"`[Maniphest] T123: Example Task`\n".
|
||||
"\n".
|
||||
'This can make mail more useful, but some clients have difficulty '.
|
||||
'threading these messages. Disabling this option may improve '.
|
||||
'threading at the cost of making subject lines less useful.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_VARY_SUBJECTS;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_VARY_SUBJECTS => pht('Enable "Re:" Prefix'),
|
||||
self::VALUE_STATIC_SUBJECTS => pht('Disable "Re:" Prefix'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMonospacedFontSetting
|
||||
extends PhabricatorStringSetting {
|
||||
|
||||
const SETTINGKEY = 'monospaced';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Monospaced Font');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'You can customize the font used when showing monospaced text, '.
|
||||
'including source code. You should enter a valid CSS font declaration '.
|
||||
'like: `13px Consolas`');
|
||||
}
|
||||
|
||||
public function validateTransactionValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filtered = self::filterMonospacedCSSRule($value);
|
||||
if ($filtered !== $value) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Monospaced font value "%s" is unsafe. You may only enter '.
|
||||
'letters, numbers, spaces, commas, periods, forward slashes '.
|
||||
'and double quotes.',
|
||||
$value));
|
||||
}
|
||||
}
|
||||
|
||||
public static function filterMonospacedCSSRule($monospaced) {
|
||||
// Prevent the user from doing dangerous things.
|
||||
return preg_replace('([^a-z0-9 ,"./]+)i', '', $monospaced);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMonospacedTextareasSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'monospaced-textareas';
|
||||
|
||||
const VALUE_TEXT_VARIABLE_WIDTH = 'disabled';
|
||||
const VALUE_TEXT_MONOSPACED = 'enabled';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Monospaced Textareas');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'You can choose to use either a monospaced or variable-width font '.
|
||||
'in textareas in the UI. Textareas are used for editing descriptions '.
|
||||
'and writing comments, among other things.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_TEXT_VARIABLE_WIDTH;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_TEXT_VARIABLE_WIDTH => pht('Use Variable-Width Font'),
|
||||
self::VALUE_TEXT_MONOSPACED => pht('Use Monospaced Font'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorOlderInlinesSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'diff-ghosts';
|
||||
|
||||
const VALUE_GHOST_INLINES_ENABLED = 'default';
|
||||
const VALUE_GHOST_INLINES_DISABLED = 'disabled';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Show Older Inlines');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'When a revision is updated, Phabricator attempts to bring inline '.
|
||||
'comments on the older version forward to the new changes. You can '.
|
||||
'disable this behavior if you prefer comments stay anchored in one '.
|
||||
'place.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_GHOST_INLINES_ENABLED;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_GHOST_INLINES_ENABLED => pht('Enabled'),
|
||||
self::VALUE_GHOST_INLINES_DISABLED => pht('Disabled'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorOptionGroupSetting
|
||||
extends PhabricatorSetting {
|
||||
|
||||
abstract protected function getSelectOptionGroups();
|
||||
|
||||
final protected function getSelectOptionMap() {
|
||||
$groups = $this->getSelectOptionGroups();
|
||||
|
||||
$map = array();
|
||||
foreach ($groups as $group) {
|
||||
$map += $group['options'];
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
final protected function newCustomEditField($object) {
|
||||
$setting_key = $this->getSettingKey();
|
||||
$default_value = $object->getDefaultValue($setting_key);
|
||||
|
||||
$options = $this->getSelectOptionGroups();
|
||||
|
||||
$map = $this->getSelectOptionMap();
|
||||
if (isset($map[$default_value])) {
|
||||
$default_label = pht('Default (%s)', $map[$default_value]);
|
||||
} else {
|
||||
$default_label = pht('Default (Unknown, "%s")', $default_value);
|
||||
}
|
||||
|
||||
$head_key = head_key($options);
|
||||
$options[$head_key]['options'] = array(
|
||||
'' => $default_label,
|
||||
) + $options[$head_key]['options'];
|
||||
|
||||
$flat_options = array();
|
||||
foreach ($options as $group) {
|
||||
$flat_options[$group['label']] = $group['options'];
|
||||
}
|
||||
|
||||
return $this->newEditField($object, new PhabricatorSelectEditField())
|
||||
->setOptions($flat_options);
|
||||
}
|
||||
|
||||
final public function validateTransactionValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$map = $this->getSelectOptionMap();
|
||||
|
||||
if (!isset($map[$value])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Value "%s" is not valid for setting "%s": valid values are %s.',
|
||||
$value,
|
||||
$this->getSettingName(),
|
||||
implode(', ', array_keys($map))));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function getTransactionNewValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPronounSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'pronoun';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Pronoun');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht('Choose the pronoun you prefer.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return PhutilPerson::SEX_UNKNOWN;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
$viewer = $this->getViewer();
|
||||
$username = $viewer->getUsername();
|
||||
|
||||
$label_unknown = pht('%s updated their profile', $username);
|
||||
$label_her = pht('%s updated her profile', $username);
|
||||
$label_his = pht('%s updated his profile', $username);
|
||||
|
||||
return array(
|
||||
PhutilPerson::SEX_UNKNOWN => $label_unknown,
|
||||
PhutilPerson::SEX_MALE => $label_his,
|
||||
PhutilPerson::SEX_FEMALE => $label_her,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorSelectSetting
|
||||
extends PhabricatorSetting {
|
||||
|
||||
abstract protected function getSelectOptions();
|
||||
|
||||
final protected function newCustomEditField($object) {
|
||||
$setting_key = $this->getSettingKey();
|
||||
$default_value = $object->getDefaultValue($setting_key);
|
||||
|
||||
$options = $this->getSelectOptions();
|
||||
|
||||
if (isset($options[$default_value])) {
|
||||
$default_label = pht('Default (%s)', $options[$default_value]);
|
||||
} else {
|
||||
$default_label = pht('Default (Unknown, "%s")', $default_value);
|
||||
}
|
||||
|
||||
if (empty($options[''])) {
|
||||
$options = array(
|
||||
'' => $default_label,
|
||||
) + $options;
|
||||
}
|
||||
|
||||
return $this->newEditField($object, new PhabricatorSelectEditField())
|
||||
->setOptions($options);
|
||||
}
|
||||
|
||||
final public function validateTransactionValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$options = $this->getSelectOptions();
|
||||
|
||||
if (!isset($options[$value])) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Value "%s" is not valid for setting "%s": valid values are %s.',
|
||||
$value,
|
||||
$this->getSettingName(),
|
||||
implode(', ', array_keys($options))));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function getTransactionNewValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
}
|
96
src/applications/settings/setting/PhabricatorSetting.php
Normal file
96
src/applications/settings/setting/PhabricatorSetting.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorSetting extends Phobject {
|
||||
|
||||
private $viewer;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
abstract public function getSettingName();
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function isEnabledForViewer(PhabricatorUser $viewer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function getSettingKey() {
|
||||
return $this->getPhobjectClassConstant('SETTINGKEY');
|
||||
}
|
||||
|
||||
public static function getAllSettings() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->setUniqueMethod('getSettingKey')
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function getAllEnabledSettings(PhabricatorUser $viewer) {
|
||||
$settings = self::getAllSettings();
|
||||
foreach ($settings as $key => $setting) {
|
||||
if (!$setting->isEnabledForViewer($viewer)) {
|
||||
unset($settings[$key]);
|
||||
}
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
final public function newCustomEditFields($object) {
|
||||
$fields = array();
|
||||
|
||||
$field = $this->newCustomEditField($object);
|
||||
if ($field) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function newCustomEditField($object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function newEditField($object, PhabricatorEditField $template) {
|
||||
$setting_property = PhabricatorUserPreferencesTransaction::PROPERTY_SETTING;
|
||||
$setting_key = $this->getSettingKey();
|
||||
$value = $object->getPreference($setting_key);
|
||||
$xaction_type = PhabricatorUserPreferencesTransaction::TYPE_SETTING;
|
||||
$label = $this->getSettingName();
|
||||
|
||||
$template
|
||||
->setKey($setting_key)
|
||||
->setLabel($label)
|
||||
->setValue($value)
|
||||
->setTransactionType($xaction_type)
|
||||
->setMetadataValue($setting_property, $setting_key);
|
||||
|
||||
$instructions = $this->getControlInstructions();
|
||||
if (strlen($instructions)) {
|
||||
$template->setControlInstructions($instructions);
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
public function validateTransactionValue($value) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function getTransactionNewValue($value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorShowFiletreeSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'diff-filetree';
|
||||
|
||||
const VALUE_DISABLE_FILETREE = 0;
|
||||
const VALUE_ENABLE_FILETREE = 1;
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Show Filetree');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'When viewing a revision or commit, you can enable a sidebar showing '.
|
||||
'affected files. When this option is enabled, press {nav %s} to show '.
|
||||
'or hide the sidebar.',
|
||||
'f');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_DISABLE_FILETREE;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_DISABLE_FILETREE => pht('Disable Filetree'),
|
||||
self::VALUE_ENABLE_FILETREE => pht('Enable Filetree'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorStringSetting
|
||||
extends PhabricatorSetting {
|
||||
|
||||
final protected function newCustomEditField($object) {
|
||||
return $this->newEditField($object, new PhabricatorTextEditField());
|
||||
}
|
||||
|
||||
public function getTransactionNewValue($value) {
|
||||
if (!strlen($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string)$value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorTimeFormatSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'time-format';
|
||||
|
||||
const VALUE_FORMAT_12HOUR = 'g:i A';
|
||||
const VALUE_FORMAT_24HOUR = 'H:i';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Time Format');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Select the format you prefer for editing and displaying time.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_FORMAT_12HOUR;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_FORMAT_12HOUR => pht('12 Hour, 2:34 PM'),
|
||||
self::VALUE_FORMAT_24HOUR => pht('24 Hour, 14:34'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorTimezoneSetting
|
||||
extends PhabricatorOptionGroupSetting {
|
||||
|
||||
const SETTINGKEY = 'timezone';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Timezone');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return date_default_timezone_get();
|
||||
}
|
||||
|
||||
protected function getSelectOptionGroups() {
|
||||
$timezones = DateTimeZone::listIdentifiers();
|
||||
$now = new DateTime('@'.PhabricatorTime::getNow());
|
||||
|
||||
$groups = array();
|
||||
foreach ($timezones as $timezone) {
|
||||
$zone = new DateTimeZone($timezone);
|
||||
$offset = -($zone->getOffset($now) / (60 * 60));
|
||||
$groups[$offset][] = $timezone;
|
||||
}
|
||||
|
||||
krsort($groups);
|
||||
|
||||
$option_groups = array(
|
||||
array(
|
||||
'label' => pht('Default'),
|
||||
'options' => array(),
|
||||
),
|
||||
);
|
||||
|
||||
foreach ($groups as $offset => $group) {
|
||||
if ($offset >= 0) {
|
||||
$label = pht('UTC-%d', $offset);
|
||||
} else {
|
||||
$label = pht('UTC+%d', -$offset);
|
||||
}
|
||||
|
||||
sort($group);
|
||||
$option_groups[] = array(
|
||||
'label' => $label,
|
||||
'options' => array_fuse($group),
|
||||
);
|
||||
}
|
||||
|
||||
return $option_groups;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorTitleGlyphsSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'titles';
|
||||
|
||||
const VALUE_TITLE_GLYPHS = 'glyph';
|
||||
const VALUE_TITLE_TEXT = 'text';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Page Titles');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Phabricator uses unicode glyphs in page titles to provide a compact '.
|
||||
'representation of the current application. You can substitute plain '.
|
||||
'text instead if these glyphs do not display on your system.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_TITLE_GLYPHS;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_TITLE_GLYPHS => pht("Use Unicode Glyphs: \xE2\x9A\x99"),
|
||||
self::VALUE_TITLE_TEXT => pht('Use Plain Text: [Differential]'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorTranslationSetting
|
||||
extends PhabricatorOptionGroupSetting {
|
||||
|
||||
const SETTINGKEY = 'translation';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Translation');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return 'en_US';
|
||||
}
|
||||
|
||||
protected function getSelectOptionGroups() {
|
||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||
$locales = PhutilLocale::loadAllLocales();
|
||||
|
||||
$group_labels = array(
|
||||
'normal' => pht('Translations'),
|
||||
'limited' => pht('Limited Translations'),
|
||||
'silly' => pht('Silly Translations'),
|
||||
'test' => pht('Developer/Test Translations'),
|
||||
);
|
||||
|
||||
$groups = array_fill_keys(array_keys($group_labels), array());
|
||||
|
||||
$translations = array();
|
||||
foreach ($locales as $locale) {
|
||||
$code = $locale->getLocaleCode();
|
||||
|
||||
// Get the locale's localized name if it's available. For example,
|
||||
// "Deutsch" instead of "German". This helps users who do not speak the
|
||||
// current language to find the correct setting.
|
||||
$raw_scope = PhabricatorEnv::beginScopedLocale($code);
|
||||
$name = $locale->getLocaleName();
|
||||
unset($raw_scope);
|
||||
|
||||
if ($locale->isSillyLocale()) {
|
||||
if ($is_serious) {
|
||||
// Omit silly locales on serious business installs.
|
||||
continue;
|
||||
}
|
||||
$groups['silly'][$code] = $name;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($locale->isTestLocale()) {
|
||||
$groups['test'][$code] = $name;
|
||||
continue;
|
||||
}
|
||||
|
||||
$strings = PhutilTranslation::getTranslationMapForLocale($code);
|
||||
$size = count($strings);
|
||||
|
||||
// If a translation is English, assume it can fall back to the default
|
||||
// strings and don't caveat its completeness.
|
||||
$is_english = (substr($code, 0, 3) == 'en_');
|
||||
|
||||
// Arbitrarily pick some number of available strings to promote a
|
||||
// translation out of the "limited" group. The major goal is just to
|
||||
// keep locales with very few strings out of the main group, so users
|
||||
// aren't surprised if a locale has no upstream translations available.
|
||||
if ($size > 512 || $is_english) {
|
||||
$type = 'normal';
|
||||
} else {
|
||||
$type = 'limited';
|
||||
}
|
||||
|
||||
$groups[$type][$code] = $name;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
foreach ($groups as $key => $group) {
|
||||
$label = $group_labels[$key];
|
||||
if (!$group) {
|
||||
continue;
|
||||
}
|
||||
|
||||
asort($group);
|
||||
|
||||
$results[] = array(
|
||||
'label' => $label,
|
||||
'options' => $group,
|
||||
);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUnifiedDiffsSetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'diff-unified';
|
||||
|
||||
const VALUE_ON_SMALL_SCREENS = 'default';
|
||||
const VALUE_ALWAYS_UNIFIED = 'unified';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Show Unified Diffs');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Phabricator normally shows diffs in a side-by-side layout on large '.
|
||||
'screens and automatically switches to a unified view on small '.
|
||||
'screens (like mobile phones). If you prefer unified diffs even on '.
|
||||
'large screens, you can select them for use on all displays.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return self::VALUE_ON_SMALL_SCREENS;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
self::VALUE_ON_SMALL_SCREENS => pht('On Small Screens'),
|
||||
self::VALUE_ALWAYS_UNIFIED => pht('Always'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorWeekStartDaySetting
|
||||
extends PhabricatorSelectSetting {
|
||||
|
||||
const SETTINGKEY = 'week-start-day';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Week Starts On');
|
||||
}
|
||||
|
||||
protected function getControlInstructions() {
|
||||
return pht(
|
||||
'Choose which day a calendar week should begin on.');
|
||||
}
|
||||
|
||||
public function getSettingDefaultValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return array(
|
||||
0 => pht('Sunday'),
|
||||
1 => pht('Monday'),
|
||||
2 => pht('Tuesday'),
|
||||
3 => pht('Wednesday'),
|
||||
4 => pht('Thursday'),
|
||||
5 => pht('Friday'),
|
||||
6 => pht('Saturday'),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
||||
final class PhabricatorUserPreferences
|
||||
extends PhabricatorUserDAO
|
||||
implements
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorDestructibleInterface,
|
||||
PhabricatorApplicationTransactionInterface {
|
||||
|
||||
const PREFERENCE_MONOSPACED = 'monospaced';
|
||||
const PREFERENCE_DARK_CONSOLE = 'dark_console';
|
||||
|
@ -51,12 +56,14 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
|||
protected $userPHID;
|
||||
protected $preferences = array();
|
||||
|
||||
private $user = self::ATTACHABLE;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'preferences' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'userPHID' => array(
|
||||
'columns' => array('userPHID'),
|
||||
|
@ -66,6 +73,11 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
|||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorUserPreferencesPHIDType::TYPECONST);
|
||||
}
|
||||
|
||||
public function getPreference($key, $default = null) {
|
||||
return idx($this->preferences, $key, $default);
|
||||
}
|
||||
|
@ -80,6 +92,21 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getDefaultValue($key) {
|
||||
$setting = self::getSettingObject($key);
|
||||
|
||||
if (!$setting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $setting->getSettingDefaultValue();
|
||||
}
|
||||
|
||||
private static function getSettingObject($key) {
|
||||
$settings = PhabricatorSetting::getAllSettings();
|
||||
return idx($settings, $key);
|
||||
}
|
||||
|
||||
public function getPinnedApplications(array $apps, PhabricatorUser $viewer) {
|
||||
$pref_pinned = self::PREFERENCE_APP_PINNED;
|
||||
$pinned = $this->getPreference($pref_pinned);
|
||||
|
@ -115,4 +142,117 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
|||
return preg_replace('([^a-z0-9 ,"./]+)i', '', $monospaced);
|
||||
}
|
||||
|
||||
public function attachUser(PhabricatorUser $user = null) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUser() {
|
||||
return $this->assertAttached($this->user);
|
||||
}
|
||||
|
||||
public function hasManagedUser() {
|
||||
$user_phid = $this->getUserPHID();
|
||||
if (!$user_phid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getUser();
|
||||
if ($user->getIsSystemAgent() || $user->getIsMailingList()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Remove this once all edits go through the Editor. For now, some
|
||||
// old edits just do direct saves so make sure we nuke the cache.
|
||||
public function save() {
|
||||
PhabricatorUserCache::clearCache(
|
||||
PhabricatorUserPreferencesCacheType::KEY_PREFERENCES,
|
||||
$this->getUserPHID());
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
$user_phid = $this->getUserPHID();
|
||||
if ($user_phid) {
|
||||
return $user_phid;
|
||||
}
|
||||
|
||||
return PhabricatorPolicies::getMostOpenPolicy();
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
if ($this->hasManagedUser()) {
|
||||
return PhabricatorPolicies::POLICY_ADMIN;
|
||||
}
|
||||
|
||||
$user_phid = $this->getUserPHID();
|
||||
if ($user_phid) {
|
||||
return $user_phid;
|
||||
}
|
||||
|
||||
return PhabricatorPolicies::POLICY_ADMIN;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if ($this->hasManagedUser()) {
|
||||
if ($viewer->getIsAdmin()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||
|
||||
|
||||
public function destroyObjectPermanently(
|
||||
PhabricatorDestructionEngine $engine) {
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
||||
public function getApplicationTransactionEditor() {
|
||||
return new PhabricatorUserPreferencesEditor();
|
||||
}
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionTemplate() {
|
||||
return new PhabricatorUserPreferencesTransaction();
|
||||
}
|
||||
|
||||
public function willRenderTimeline(
|
||||
PhabricatorApplicationTransactionView $timeline,
|
||||
AphrontRequest $request) {
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_SETTING = 'setting';
|
||||
|
||||
const PROPERTY_SETTING = 'setting.key';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionCommentObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorUserPreferencesPHIDType::TYPECONST;
|
||||
}
|
||||
|
||||
}
|
|
@ -216,39 +216,3 @@ Finally, edit `/etc/mail/virtusertable` and add an entry like this:
|
|||
That will forward all mail to @yourdomain.com to the Phabricator processing
|
||||
script. Run `sudo /etc/mail/make` or similar and then restart sendmail with
|
||||
`sudo /etc/init.d/sendmail restart`.
|
||||
|
||||
= Local MTA: Configuring Lamson =
|
||||
|
||||
Before you can configure Lamson, you need to install Mailparse. See the section
|
||||
"Installing Mailparse" above.
|
||||
|
||||
In contrast to Sendmail, Lamson is relatively easy to configure. It is fairly
|
||||
minimal, and is suitable for a development or testing environment. Lamson
|
||||
listens for incoming SMTP mails and passes the content directly to Phabricator.
|
||||
|
||||
To get started, follow the provided instructions
|
||||
(<http://lamsonproject.org/docs/getting_started.html>) to set up an instance.
|
||||
One likely deployment issue is that binding to port 25 requires root
|
||||
privileges. Lamson is capable of starting as root then dropping privileges, but
|
||||
you must supply `-uid` and `-gid` arguments to do so, as demonstrated by
|
||||
Step 8 in Lamson's deployment tutorial (located here:
|
||||
<http://lamsonproject.org/docs/deploying_oneshotblog.html>).
|
||||
|
||||
The Lamson handler code itself is very concise; it merely needs to pass the
|
||||
content of the email to Phabricator:
|
||||
|
||||
import logging, subprocess
|
||||
from lamson.routing import route, stateless
|
||||
from lamson import view
|
||||
|
||||
PHABRICATOR_ROOT = "/path/to/phabricator"
|
||||
PHABRICATOR_ENV = "custom/myconf"
|
||||
LOGGING_ENABLED = True
|
||||
|
||||
@route("(address)@(host)", address=".+")
|
||||
@stateless
|
||||
def START(message, address=None, host=None):
|
||||
if LOGGING_ENABLED:
|
||||
logging.debug("%s", message.original)
|
||||
process = subprocess.Popen([PHABRICATOR_ROOT + "scripts/mail/mail_handler.php",PHABRICATOR_ENV],stdin=subprocess.PIPE)
|
||||
process.communicate(message.original)
|
||||
|
|
|
@ -351,10 +351,13 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
* @task engine
|
||||
*/
|
||||
public static function newPhameMarkupEngine() {
|
||||
return self::newMarkupEngine(array(
|
||||
'macros' => false,
|
||||
'uri.full' => true,
|
||||
));
|
||||
return self::newMarkupEngine(
|
||||
array(
|
||||
'macros' => false,
|
||||
'uri.full' => true,
|
||||
'uri.same-window' => true,
|
||||
'uri.base' => PhabricatorEnv::getURI('/'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
@ -487,6 +490,14 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
|
||||
$engine->setConfig('uri.full', $options['uri.full']);
|
||||
|
||||
if (isset($options['uri.base'])) {
|
||||
$engine->setConfig('uri.base', $options['uri.base']);
|
||||
}
|
||||
|
||||
if (isset($options['uri.same-window'])) {
|
||||
$engine->setConfig('uri.same-window', $options['uri.same-window']);
|
||||
}
|
||||
|
||||
$rules = array();
|
||||
$rules[] = new PhutilRemarkupEscapeRemarkupRule();
|
||||
$rules[] = new PhutilRemarkupMonospaceRule();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue