mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +01:00
Modernize Conpherence access to user preferences
Summary: Ref T4103. Conpherence is doing some weird stuff and has its own redudnant settings object. - Get rid of `ConpherenceSettings`. - Use `getUserSetting()` instead of `loadPreferences()`. - When applying transactions, add a new mechanism to efficiently prefill caches (this will still work anyway, but it's slower if we don't bulk-fetch). Test Plan: - Changed global Conpherence setting. - Created a new Conpherence, saw setting set to global default. - Changed local room setting. - Submitted messages. - Saw cache prefill for all particpiants in database. Reviewers: chad Reviewed By: chad Maniphest Tasks: T4103 Differential Revision: https://secure.phabricator.com/D16025
This commit is contained in:
parent
9a076b71a3
commit
1e17fd31a4
10 changed files with 200 additions and 79 deletions
|
@ -312,7 +312,6 @@ phutil_register_library_map(array(
|
|||
'ConpherenceRoomListController' => 'applications/conpherence/controller/ConpherenceRoomListController.php',
|
||||
'ConpherenceRoomTestCase' => 'applications/conpherence/__tests__/ConpherenceRoomTestCase.php',
|
||||
'ConpherenceSchemaSpec' => 'applications/conpherence/storage/ConpherenceSchemaSpec.php',
|
||||
'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php',
|
||||
'ConpherenceTestCase' => 'applications/conpherence/__tests__/ConpherenceTestCase.php',
|
||||
'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php',
|
||||
'ConpherenceThreadIndexEngineExtension' => 'applications/conpherence/engineextension/ConpherenceThreadIndexEngineExtension.php',
|
||||
|
@ -3636,6 +3635,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUserPreferencesPHIDType' => 'applications/settings/phid/PhabricatorUserPreferencesPHIDType.php',
|
||||
'PhabricatorUserPreferencesQuery' => 'applications/settings/query/PhabricatorUserPreferencesQuery.php',
|
||||
'PhabricatorUserPreferencesTransaction' => 'applications/settings/storage/PhabricatorUserPreferencesTransaction.php',
|
||||
'PhabricatorUserPreferencesTransactionQuery' => 'applications/settings/query/PhabricatorUserPreferencesTransactionQuery.php',
|
||||
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
|
||||
'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
|
||||
'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php',
|
||||
|
@ -4565,7 +4565,6 @@ phutil_register_library_map(array(
|
|||
'ConpherenceRoomListController' => 'ConpherenceController',
|
||||
'ConpherenceRoomTestCase' => 'ConpherenceTestCase',
|
||||
'ConpherenceSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'ConpherenceSettings' => 'ConpherenceConstants',
|
||||
'ConpherenceTestCase' => 'PhabricatorTestCase',
|
||||
'ConpherenceThread' => array(
|
||||
'ConpherenceDAO',
|
||||
|
@ -8439,6 +8438,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorUserPreferencesPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorUserPreferencesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorUserPreferencesTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorUserPreferencesTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
|
||||
'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField',
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ConpherenceSettings extends ConpherenceConstants {
|
||||
|
||||
const EMAIL_ALWAYS = 0;
|
||||
const NOTIFICATIONS_ONLY = 1;
|
||||
|
||||
public static function getHumanString($constant) {
|
||||
$string = pht('Unknown setting.');
|
||||
|
||||
switch ($constant) {
|
||||
case self::EMAIL_ALWAYS:
|
||||
$string = pht('Email me every update.');
|
||||
break;
|
||||
case self::NOTIFICATIONS_ONLY:
|
||||
$string = pht('Notifications only.');
|
||||
break;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
|
@ -127,9 +127,14 @@ final class ConpherenceUpdateController
|
|||
}
|
||||
$participant->setSettings(array('notifications' => $notifications));
|
||||
$participant->save();
|
||||
|
||||
$label = PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
$notifications);
|
||||
|
||||
$result = pht(
|
||||
'Updated notification settings to "%s".',
|
||||
ConpherenceSettings::getHumanString($notifications));
|
||||
$label);
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent($result);
|
||||
break;
|
||||
|
|
|
@ -2,17 +2,6 @@
|
|||
|
||||
final class ConpherenceWidgetController extends ConpherenceController {
|
||||
|
||||
private $userPreferences;
|
||||
|
||||
public function setUserPreferences(PhabricatorUserPreferences $pref) {
|
||||
$this->userPreferences = $pref;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUserPreferences() {
|
||||
return $this->userPreferences;
|
||||
}
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
@ -35,8 +24,6 @@ final class ConpherenceWidgetController extends ConpherenceController {
|
|||
}
|
||||
$this->setConpherence($conpherence);
|
||||
|
||||
$this->setUserPreferences($user->loadPreferences());
|
||||
|
||||
switch ($request->getStr('widget')) {
|
||||
case 'widgets-people':
|
||||
$content = $this->renderPeopleWidgetPaneContent();
|
||||
|
@ -143,28 +130,24 @@ final class ConpherenceWidgetController extends ConpherenceController {
|
|||
),
|
||||
$text);
|
||||
}
|
||||
$default = ConpherenceSettings::EMAIL_ALWAYS;
|
||||
$preference = $this->getUserPreferences();
|
||||
if ($preference) {
|
||||
$default = $preference->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS,
|
||||
ConpherenceSettings::EMAIL_ALWAYS);
|
||||
}
|
||||
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
||||
$notification_default = $viewer->getUserSetting($notification_key);
|
||||
|
||||
$settings = $participant->getSettings();
|
||||
$notifications = idx(
|
||||
$settings,
|
||||
'notifications',
|
||||
$default);
|
||||
$notification_default);
|
||||
$options = id(new AphrontFormRadioButtonControl())
|
||||
->addButton(
|
||||
ConpherenceSettings::EMAIL_ALWAYS,
|
||||
ConpherenceSettings::getHumanString(
|
||||
ConpherenceSettings::EMAIL_ALWAYS),
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
|
||||
'')
|
||||
->addButton(
|
||||
ConpherenceSettings::NOTIFICATIONS_ONLY,
|
||||
ConpherenceSettings::getHumanString(
|
||||
ConpherenceSettings::NOTIFICATIONS_ONLY),
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
|
||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
|
||||
'')
|
||||
->setName('notifications')
|
||||
->setValue($notifications);
|
||||
|
|
|
@ -541,26 +541,29 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
|
||||
$participant_phids = mpull($participants, 'getParticipantPHID');
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
$users = id(new PhabricatorPeopleQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withUserPHIDs($participant_phids)
|
||||
->withPHIDs($participant_phids)
|
||||
->needUserSettings(true)
|
||||
->execute();
|
||||
$preferences = mpull($preferences, null, 'getUserPHID');
|
||||
$users = mpull($users, null, 'getPHID');
|
||||
|
||||
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
||||
$notification_email =
|
||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL;
|
||||
|
||||
foreach ($participants as $phid => $participant) {
|
||||
$default = ConpherenceSettings::EMAIL_ALWAYS;
|
||||
$preference = idx($preferences, $phid);
|
||||
if ($preference) {
|
||||
$default = $preference->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS,
|
||||
ConpherenceSettings::EMAIL_ALWAYS);
|
||||
$user = idx($users, $phid);
|
||||
if ($user) {
|
||||
$default = $user->getUserSetting($notification_key);
|
||||
} else {
|
||||
$default = $notification_email;
|
||||
}
|
||||
|
||||
$settings = $participant->getSettings();
|
||||
$notifications = idx(
|
||||
$settings,
|
||||
'notifications',
|
||||
$default);
|
||||
if ($notifications == ConpherenceSettings::EMAIL_ALWAYS) {
|
||||
$notifications = idx($settings, 'notifications', $default);
|
||||
|
||||
if ($notifications == $notification_email) {
|
||||
$to_phids[] = $phid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,16 @@ final class PhabricatorUserPreferencesCacheType
|
|||
public function newValueForUsers($key, array $users) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$user_phids = mpull($users, 'getPHID');
|
||||
|
||||
$preferences = id(new PhabricatorUserPreferencesQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(mpull($users, 'getPHID'))
|
||||
->withUserPHIDs($user_phids)
|
||||
->execute();
|
||||
|
||||
return mpull($preferences, 'getPreferences', 'getUserPHID');
|
||||
$empty = array_fill_keys($user_phids, array());
|
||||
|
||||
return mpull($preferences, 'getPreferences', 'getUserPHID') + $empty;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ final class PhabricatorPeopleQuery
|
|||
private $needProfileImage;
|
||||
private $needAvailability;
|
||||
private $needBadges;
|
||||
private $cacheKeys = array();
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -119,6 +120,18 @@ final class PhabricatorPeopleQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function needUserSettings($need) {
|
||||
$cache_key = PhabricatorUserPreferencesCacheType::KEY_PREFERENCES;
|
||||
|
||||
if ($need) {
|
||||
$this->cacheKeys[$cache_key] = true;
|
||||
} else {
|
||||
unset($this->cacheKeys[$cache_key]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorUser();
|
||||
}
|
||||
|
@ -238,6 +251,8 @@ final class PhabricatorPeopleQuery
|
|||
}
|
||||
}
|
||||
|
||||
$this->fillUserCaches($users);
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
|
@ -481,4 +496,91 @@ final class PhabricatorPeopleQuery
|
|||
}
|
||||
}
|
||||
|
||||
private function fillUserCaches(array $users) {
|
||||
if (!$this->cacheKeys) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user_map = mpull($users, null, 'getPHID');
|
||||
$keys = array_keys($this->cacheKeys);
|
||||
|
||||
$hashes = array();
|
||||
foreach ($keys as $key) {
|
||||
$hashes[] = PhabricatorHash::digestForIndex($key);
|
||||
}
|
||||
|
||||
// First, pull any available caches. If we wanted to be particularly clever
|
||||
// we could do this with JOINs in the main query.
|
||||
|
||||
$cache_table = new PhabricatorUserCache();
|
||||
$cache_conn = $cache_table->establishConnection('r');
|
||||
|
||||
$cache_data = queryfx_all(
|
||||
$cache_conn,
|
||||
'SELECT cacheKey, userPHID, cacheData FROM %T
|
||||
WHERE cacheIndex IN (%Ls) AND userPHID IN (%Ls)',
|
||||
$cache_table->getTableName(),
|
||||
$hashes,
|
||||
array_keys($user_map));
|
||||
|
||||
$need = array();
|
||||
|
||||
$cache_data = igroup($cache_data, 'userPHID');
|
||||
foreach ($user_map as $user_phid => $user) {
|
||||
$raw_rows = idx($cache_data, $user_phid, array());
|
||||
if (!$raw_rows) {
|
||||
continue;
|
||||
}
|
||||
$raw_data = ipull($raw_rows, 'cacheData', 'cacheKey');
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (isset($raw_data[$key]) || array_key_exists($key, $raw_data)) {
|
||||
continue;
|
||||
}
|
||||
$need[$key][$user_phid] = $user;
|
||||
}
|
||||
|
||||
$user->attachRawCacheData($raw_data);
|
||||
}
|
||||
|
||||
// If we missed any cache values, bulk-construct them now. This is
|
||||
// usually much cheaper than generating them on-demand for each user
|
||||
// record.
|
||||
|
||||
if (!$need) {
|
||||
return;
|
||||
}
|
||||
|
||||
$writes = array();
|
||||
foreach ($need as $cache_key => $need_users) {
|
||||
$type = PhabricatorUserCacheType::getCacheTypeForKey($cache_key);
|
||||
if (!$type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $type->newValueForUsers($cache_key, $need_users);
|
||||
|
||||
foreach ($data as $user_phid => $value) {
|
||||
$raw_value = $type->getValueForStorage($value);
|
||||
$data[$user_phid] = $raw_value;
|
||||
$writes[] = array(
|
||||
'userPHID' => $user_phid,
|
||||
'key' => $cache_key,
|
||||
'type' => $type,
|
||||
'value' => $raw_value,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($need_users as $user_phid => $user) {
|
||||
if (isset($data[$user_phid]) || array_key_exists($user_phid, $data)) {
|
||||
$user->attachRawCacheData(
|
||||
array(
|
||||
$cache_key => $data[$user_phid],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PhabricatorUserCache::writeCaches($writes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,27 +42,54 @@ final class PhabricatorUserCache extends PhabricatorUserDAO {
|
|||
$key,
|
||||
$user_phid,
|
||||
$raw_value) {
|
||||
self::writeCaches(
|
||||
array(
|
||||
array(
|
||||
'type' => $type,
|
||||
'key' => $key,
|
||||
'userPHID' => $user_phid,
|
||||
'value' => $raw_value,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public static function writeCaches(array $values) {
|
||||
if (PhabricatorEnv::isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$values) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = new self();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$sql = array();
|
||||
foreach ($values as $value) {
|
||||
$key = $value['key'];
|
||||
|
||||
$sql[] = qsprintf(
|
||||
$conn_w,
|
||||
'(%s, %s, %s, %s, %s)',
|
||||
$value['userPHID'],
|
||||
PhabricatorHash::digestForIndex($key),
|
||||
$key,
|
||||
$value['value'],
|
||||
$value['type']->getUserCacheType());
|
||||
}
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (userPHID, cacheIndex, cacheKey, cacheData, cacheType)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
VALUES %Q
|
||||
ON DUPLICATE KEY UPDATE cacheData = VALUES(cacheData)',
|
||||
$table->getTableName(),
|
||||
$user_phid,
|
||||
PhabricatorHash::digestForIndex($key),
|
||||
$key,
|
||||
$raw_value,
|
||||
$type->getUserCacheType());
|
||||
$chunk);
|
||||
}
|
||||
|
||||
unset($unguarded);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorUserPreferencesTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorUserPreferencesTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,15 @@ final class PhabricatorConpherenceNotificationsSetting
|
|||
}
|
||||
|
||||
protected function getSelectOptions() {
|
||||
return self::getOptionsMap();
|
||||
}
|
||||
|
||||
public static function getSettingLabel($key) {
|
||||
$labels = self::getOptionsMap();
|
||||
return idx($labels, $key, pht('Unknown ("%s")', $key));
|
||||
}
|
||||
|
||||
private static function getOptionsMap() {
|
||||
return array(
|
||||
self::VALUE_CONPHERENCE_EMAIL => pht('Send Email'),
|
||||
self::VALUE_CONPHERENCE_NOTIFY => pht('Send Notifications'),
|
||||
|
|
Loading…
Reference in a new issue