1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-15 18:10:53 +01:00

(stable) Promote 2017 Week 16

This commit is contained in:
epriestley 2017-04-21 16:55:46 -07:00
commit 7c3158138a
149 changed files with 1978 additions and 3023 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 993 B

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

View file

@ -46,6 +46,7 @@ return array(
'javelin-behavior-toggle-class',
'javelin-behavior-lightbox-attachments',
'phabricator-busy',
'javelin-sound',
'javelin-aphlict',
'phabricator-notification',
'javelin-behavior-aphlict-listen',
@ -160,6 +161,7 @@ return array(
'conpherence.pkg.css' => array(
'conpherence-durable-column-view',
'conpherence-menu-css',
'conpherence-color-css',
'conpherence-message-pane-css',
'conpherence-notification-css',
'conpherence-transaction-css',

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_file.file_filename_ngrams (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectID INT UNSIGNED NOT NULL,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
KEY `key_object` (objectID),
KEY `key_ngram` (ngram, objectID)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_application.application_applicationtransaction (
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};

View file

@ -0,0 +1,16 @@
CREATE TABLE {$NAMESPACE}_application.edge (
src VARBINARY(64) NOT NULL,
type INT UNSIGNED NOT NULL,
dst VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
seq INT UNSIGNED NOT NULL,
dataID INT UNSIGNED,
PRIMARY KEY (src, type, dst),
KEY `src` (src, type, dateCreated, seq),
UNIQUE KEY `key_dst` (dst, type, src)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
CREATE TABLE {$NAMESPACE}_application.edgedata (
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_file.file
ADD isDeleted BOOL NOT NULL DEFAULT 0;

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_application.application_application (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (phid)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
DROP behindTransactionPHID;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
DROP participationStatus;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
DROP dateTouched;

View file

@ -305,12 +305,13 @@ phutil_register_library_map(array(
'ConpherenceParticipantCountQuery' => 'applications/conpherence/query/ConpherenceParticipantCountQuery.php',
'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php',
'ConpherenceParticipantView' => 'applications/conpherence/view/ConpherenceParticipantView.php',
'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php',
'ConpherenceQueryThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php',
'ConpherenceQueryTransactionConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php',
'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php',
'ConpherenceRoomListController' => 'applications/conpherence/controller/ConpherenceRoomListController.php',
'ConpherenceRoomPictureController' => 'applications/conpherence/controller/ConpherenceRoomPictureController.php',
'ConpherenceRoomPreferencesController' => 'applications/conpherence/controller/ConpherenceRoomPreferencesController.php',
'ConpherenceRoomSettings' => 'applications/conpherence/constants/ConpherenceRoomSettings.php',
'ConpherenceRoomTestCase' => 'applications/conpherence/__tests__/ConpherenceRoomTestCase.php',
'ConpherenceSchemaSpec' => 'applications/conpherence/storage/ConpherenceSchemaSpec.php',
'ConpherenceTestCase' => 'applications/conpherence/__tests__/ConpherenceTestCase.php',
@ -321,6 +322,7 @@ phutil_register_library_map(array(
'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php',
'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php',
'ConpherenceThreadMembersPolicyRule' => 'applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php',
'ConpherenceThreadParticipantsTransaction' => 'applications/conpherence/xaction/ConpherenceThreadParticipantsTransaction.php',
'ConpherenceThreadPictureTransaction' => 'applications/conpherence/xaction/ConpherenceThreadPictureTransaction.php',
'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php',
'ConpherenceThreadRemarkupRule' => 'applications/conpherence/remarkup/ConpherenceThreadRemarkupRule.php',
@ -349,6 +351,7 @@ phutil_register_library_map(array(
'DarkConsoleEventPlugin' => 'applications/console/plugin/DarkConsoleEventPlugin.php',
'DarkConsoleEventPluginAPI' => 'applications/console/plugin/event/DarkConsoleEventPluginAPI.php',
'DarkConsolePlugin' => 'applications/console/plugin/DarkConsolePlugin.php',
'DarkConsoleRealtimePlugin' => 'applications/console/plugin/DarkConsoleRealtimePlugin.php',
'DarkConsoleRequestPlugin' => 'applications/console/plugin/DarkConsoleRequestPlugin.php',
'DarkConsoleServicesPlugin' => 'applications/console/plugin/DarkConsoleServicesPlugin.php',
'DarkConsoleStartupPlugin' => 'applications/console/plugin/DarkConsoleStartupPlugin.php',
@ -1097,6 +1100,7 @@ phutil_register_library_map(array(
'FileAllocateConduitAPIMethod' => 'applications/files/conduit/FileAllocateConduitAPIMethod.php',
'FileConduitAPIMethod' => 'applications/files/conduit/FileConduitAPIMethod.php',
'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php',
'FileDeletionWorker' => 'applications/files/worker/FileDeletionWorker.php',
'FileDownloadConduitAPIMethod' => 'applications/files/conduit/FileDownloadConduitAPIMethod.php',
'FileInfoConduitAPIMethod' => 'applications/files/conduit/FileInfoConduitAPIMethod.php',
'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php',
@ -1835,6 +1839,8 @@ phutil_register_library_map(array(
'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php',
'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php',
'PhabricatorApplicationApplicationPHIDType' => 'applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php',
'PhabricatorApplicationApplicationTransaction' => 'applications/meta/storage/PhabricatorApplicationApplicationTransaction.php',
'PhabricatorApplicationApplicationTransactionQuery' => 'applications/meta/query/PhabricatorApplicationApplicationTransactionQuery.php',
'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php',
'PhabricatorApplicationConfigurationPanel' => 'applications/meta/panel/PhabricatorApplicationConfigurationPanel.php',
'PhabricatorApplicationConfigurationPanelTestCase' => 'applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php',
@ -1846,6 +1852,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php',
'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php',
'PhabricatorApplicationSchemaSpec' => 'applications/meta/storage/PhabricatorApplicationSchemaSpec.php',
'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php',
'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php',
'PhabricatorApplicationSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php',
@ -1878,6 +1885,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationTransactionTemplatedCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionTemplatedCommentQuery.php',
'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php',
'PhabricatorApplicationTransactionTransactionPHIDType' => 'applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php',
'PhabricatorApplicationTransactionType' => 'applications/meta/xactions/PhabricatorApplicationTransactionType.php',
'PhabricatorApplicationTransactionValidationError' => 'applications/transactions/error/PhabricatorApplicationTransactionValidationError.php',
'PhabricatorApplicationTransactionValidationException' => 'applications/transactions/exception/PhabricatorApplicationTransactionValidationException.php',
'PhabricatorApplicationTransactionValidationResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionValidationResponse.php',
@ -2081,20 +2089,6 @@ phutil_register_library_map(array(
'PhabricatorBoardRenderingEngine' => 'applications/project/engine/PhabricatorBoardRenderingEngine.php',
'PhabricatorBoardResponseEngine' => 'applications/project/engine/PhabricatorBoardResponseEngine.php',
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php',
'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php',
'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php',
'PhabricatorBotFeedNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotFeedNotificationHandler.php',
'PhabricatorBotFlowdockProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php',
'PhabricatorBotHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotHandler.php',
'PhabricatorBotLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php',
'PhabricatorBotMacroHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php',
'PhabricatorBotMessage' => 'infrastructure/daemon/bot/PhabricatorBotMessage.php',
'PhabricatorBotObjectNameHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php',
'PhabricatorBotSymbolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotSymbolHandler.php',
'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php',
'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php',
'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php',
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
@ -2253,7 +2247,6 @@ phutil_register_library_map(array(
'PhabricatorCalendarRemarkupRule' => 'applications/calendar/remarkup/PhabricatorCalendarRemarkupRule.php',
'PhabricatorCalendarReplyHandler' => 'applications/calendar/mail/PhabricatorCalendarReplyHandler.php',
'PhabricatorCalendarSchemaSpec' => 'applications/calendar/storage/PhabricatorCalendarSchemaSpec.php',
'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php',
'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php',
'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php',
'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php',
@ -2396,6 +2389,7 @@ phutil_register_library_map(array(
'PhabricatorConpherenceNotificationsSetting' => 'applications/settings/setting/PhabricatorConpherenceNotificationsSetting.php',
'PhabricatorConpherencePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php',
'PhabricatorConpherenceProfileMenuItem' => 'applications/search/menuitem/PhabricatorConpherenceProfileMenuItem.php',
'PhabricatorConpherenceSoundSetting' => 'applications/settings/setting/PhabricatorConpherenceSoundSetting.php',
'PhabricatorConpherenceThreadPHIDType' => 'applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php',
'PhabricatorConpherenceWidgetVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceWidgetVisibleSetting.php',
'PhabricatorConsoleApplication' => 'applications/console/application/PhabricatorConsoleApplication.php',
@ -2762,6 +2756,7 @@ phutil_register_library_map(array(
'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php',
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php',
'PhabricatorFileDeleteTransaction' => 'applications/files/xaction/PhabricatorFileDeleteTransaction.php',
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php',
'PhabricatorFileEditEngine' => 'applications/files/editor/PhabricatorFileEditEngine.php',
@ -2780,6 +2775,7 @@ phutil_register_library_map(array(
'PhabricatorFileLightboxController' => 'applications/files/controller/PhabricatorFileLightboxController.php',
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
'PhabricatorFileNameNgrams' => 'applications/files/storage/PhabricatorFileNameNgrams.php',
'PhabricatorFileNameTransaction' => 'applications/files/xaction/PhabricatorFileNameTransaction.php',
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
'PhabricatorFileROT13StorageFormat' => 'applications/files/format/PhabricatorFileROT13StorageFormat.php',
@ -2910,7 +2906,6 @@ phutil_register_library_map(array(
'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php',
'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php',
'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php',
'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php',
'PhabricatorIconDatasource' => 'applications/files/typeahead/PhabricatorIconDatasource.php',
'PhabricatorIconRemarkupRule' => 'applications/macro/markup/PhabricatorIconRemarkupRule.php',
'PhabricatorIconSet' => 'applications/files/iconset/PhabricatorIconSet.php',
@ -2924,6 +2919,7 @@ phutil_register_library_map(array(
'PhabricatorIndexEngine' => 'applications/search/index/PhabricatorIndexEngine.php',
'PhabricatorIndexEngineExtension' => 'applications/search/index/PhabricatorIndexEngineExtension.php',
'PhabricatorIndexEngineExtensionModule' => 'applications/search/index/PhabricatorIndexEngineExtensionModule.php',
'PhabricatorIndexableInterface' => 'applications/search/interface/PhabricatorIndexableInterface.php',
'PhabricatorInfrastructureTestCase' => '__tests__/PhabricatorInfrastructureTestCase.php',
'PhabricatorInlineCommentController' => 'infrastructure/diff/PhabricatorInlineCommentController.php',
'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php',
@ -3445,7 +3441,6 @@ phutil_register_library_map(array(
'PhabricatorPhurlURL' => 'applications/phurl/storage/PhabricatorPhurlURL.php',
'PhabricatorPhurlURLAccessController' => 'applications/phurl/controller/PhabricatorPhurlURLAccessController.php',
'PhabricatorPhurlURLAliasTransaction' => 'applications/phurl/xaction/PhabricatorPhurlURLAliasTransaction.php',
'PhabricatorPhurlURLCommentController' => 'applications/phurl/controller/PhabricatorPhurlURLCommentController.php',
'PhabricatorPhurlURLCreateCapability' => 'applications/phurl/capability/PhabricatorPhurlURLCreateCapability.php',
'PhabricatorPhurlURLDatasource' => 'applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php',
'PhabricatorPhurlURLDescriptionTransaction' => 'applications/phurl/xaction/PhabricatorPhurlURLDescriptionTransaction.php',
@ -3643,7 +3638,6 @@ phutil_register_library_map(array(
'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',
'PhabricatorQueryConstraint' => 'infrastructure/query/constraint/PhabricatorQueryConstraint.php',
@ -3967,7 +3961,6 @@ phutil_register_library_map(array(
'PhabricatorStoragePatch' => 'infrastructure/storage/management/PhabricatorStoragePatch.php',
'PhabricatorStorageSchemaSpec' => 'infrastructure/storage/schema/PhabricatorStorageSchemaSpec.php',
'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',
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
@ -5093,12 +5086,13 @@ phutil_register_library_map(array(
'ConpherenceParticipantCountQuery' => 'PhabricatorOffsetPagedQuery',
'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery',
'ConpherenceParticipantView' => 'AphrontView',
'ConpherenceParticipationStatus' => 'ConpherenceConstants',
'ConpherenceQueryThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
'ConpherenceQueryTransactionConduitAPIMethod' => 'ConpherenceConduitAPIMethod',
'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler',
'ConpherenceRoomListController' => 'ConpherenceController',
'ConpherenceRoomPictureController' => 'ConpherenceController',
'ConpherenceRoomPreferencesController' => 'ConpherenceController',
'ConpherenceRoomSettings' => 'ConpherenceConstants',
'ConpherenceRoomTestCase' => 'ConpherenceTestCase',
'ConpherenceSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'ConpherenceTestCase' => 'PhabricatorTestCase',
@ -5116,6 +5110,7 @@ phutil_register_library_map(array(
'ConpherenceThreadListView' => 'AphrontView',
'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver',
'ConpherenceThreadMembersPolicyRule' => 'PhabricatorPolicyRule',
'ConpherenceThreadParticipantsTransaction' => 'ConpherenceThreadTransactionType',
'ConpherenceThreadPictureTransaction' => 'ConpherenceThreadTransactionType',
'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'ConpherenceThreadRemarkupRule' => 'PhabricatorObjectRemarkupRule',
@ -5144,6 +5139,7 @@ phutil_register_library_map(array(
'DarkConsoleEventPlugin' => 'DarkConsolePlugin',
'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener',
'DarkConsolePlugin' => 'Phobject',
'DarkConsoleRealtimePlugin' => 'DarkConsolePlugin',
'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
'DarkConsoleStartupPlugin' => 'DarkConsolePlugin',
@ -5974,6 +5970,7 @@ phutil_register_library_map(array(
'FileAllocateConduitAPIMethod' => 'FileConduitAPIMethod',
'FileConduitAPIMethod' => 'ConduitAPIMethod',
'FileCreateMailReceiver' => 'PhabricatorMailReceiver',
'FileDeletionWorker' => 'PhabricatorWorker',
'FileDownloadConduitAPIMethod' => 'FileConduitAPIMethod',
'FileInfoConduitAPIMethod' => 'FileConduitAPIMethod',
'FileMailReceiver' => 'PhabricatorObjectMailReceiver',
@ -6838,10 +6835,13 @@ phutil_register_library_map(array(
'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase',
'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorApplication' => array(
'Phobject',
'PhabricatorLiskDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
),
'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType',
'PhabricatorApplicationApplicationTransaction' => 'PhabricatorModularTransaction',
'PhabricatorApplicationApplicationTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorApplicationConfigOptions' => 'Phobject',
'PhabricatorApplicationConfigurationPanel' => 'Phobject',
'PhabricatorApplicationConfigurationPanelTestCase' => 'PhabricatorTestCase',
@ -6853,6 +6853,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorApplicationSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController',
'PhabricatorApplicationSearchEngine' => 'Phobject',
'PhabricatorApplicationSearchEngineTestCase' => 'PhabricatorTestCase',
@ -6893,6 +6894,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationTransactionTemplatedCommentQuery' => 'PhabricatorApplicationTransactionCommentQuery',
'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView',
'PhabricatorApplicationTransactionTransactionPHIDType' => 'PhabricatorPHIDType',
'PhabricatorApplicationTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorApplicationTransactionValidationError' => 'Phobject',
'PhabricatorApplicationTransactionValidationException' => 'Exception',
'PhabricatorApplicationTransactionValidationResponse' => 'AphrontProxyResponse',
@ -7130,20 +7132,6 @@ phutil_register_library_map(array(
'PhabricatorBoardRenderingEngine' => 'Phobject',
'PhabricatorBoardResponseEngine' => 'Phobject',
'PhabricatorBoolEditField' => 'PhabricatorEditField',
'PhabricatorBot' => 'PhabricatorDaemon',
'PhabricatorBotChannel' => 'PhabricatorBotTarget',
'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler',
'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler',
'PhabricatorBotFlowdockProtocolAdapter' => 'PhabricatorStreamingProtocolAdapter',
'PhabricatorBotHandler' => 'Phobject',
'PhabricatorBotLogHandler' => 'PhabricatorBotHandler',
'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler',
'PhabricatorBotMessage' => 'Phobject',
'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler',
'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler',
'PhabricatorBotTarget' => 'Phobject',
'PhabricatorBotUser' => 'PhabricatorBotTarget',
'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler',
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
@ -7338,7 +7326,6 @@ phutil_register_library_map(array(
'PhabricatorCalendarRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorCalendarReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'PhabricatorCalendarSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorCampfireProtocolAdapter' => 'PhabricatorStreamingProtocolAdapter',
'PhabricatorCelerityApplication' => 'PhabricatorApplication',
'PhabricatorCelerityTestCase' => 'PhabricatorTestCase',
'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase',
@ -7499,6 +7486,7 @@ phutil_register_library_map(array(
'PhabricatorConpherenceNotificationsSetting' => 'PhabricatorSelectSetting',
'PhabricatorConpherencePreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel',
'PhabricatorConpherenceProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorConpherenceSoundSetting' => 'PhabricatorSelectSetting',
'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType',
'PhabricatorConpherenceWidgetVisibleSetting' => 'PhabricatorInternalSetting',
'PhabricatorConsoleApplication' => 'PhabricatorApplication',
@ -7906,6 +7894,8 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
'PhabricatorConduitResultInterface',
'PhabricatorIndexableInterface',
'PhabricatorNgramsInterface',
),
'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat',
'PhabricatorFileBundleLoader' => 'Phobject',
@ -7924,6 +7914,7 @@ phutil_register_library_map(array(
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileDataController' => 'PhabricatorFileController',
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
'PhabricatorFileDeleteTransaction' => 'PhabricatorFileTransactionType',
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
'PhabricatorFileEditController' => 'PhabricatorFileController',
'PhabricatorFileEditEngine' => 'PhabricatorEditEngine',
@ -7952,6 +7943,7 @@ phutil_register_library_map(array(
'PhabricatorFileLightboxController' => 'PhabricatorFileController',
'PhabricatorFileLinkView' => 'AphrontTagView',
'PhabricatorFileListController' => 'PhabricatorFileController',
'PhabricatorFileNameNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorFileNameTransaction' => 'PhabricatorFileTransactionType',
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorFileROT13StorageFormat' => 'PhabricatorFileStorageFormat',
@ -8026,6 +8018,7 @@ phutil_register_library_map(array(
'PhabricatorFulltextEngineExtension' => 'Phobject',
'PhabricatorFulltextEngineExtensionModule' => 'PhabricatorConfigModule',
'PhabricatorFulltextIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorFulltextInterface' => 'PhabricatorIndexableInterface',
'PhabricatorFulltextResultSet' => 'Phobject',
'PhabricatorFulltextStorageEngine' => 'Phobject',
'PhabricatorFulltextToken' => 'Phobject',
@ -8089,7 +8082,6 @@ phutil_register_library_map(array(
'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule',
'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorIDsSearchField' => 'PhabricatorSearchField',
'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter',
'PhabricatorIconDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorIconSet' => 'Phobject',
@ -8300,6 +8292,7 @@ phutil_register_library_map(array(
'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock',
'PhabricatorNgramsIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorNgramsInterface' => 'PhabricatorIndexableInterface',
'PhabricatorNotificationBuilder' => 'Phobject',
'PhabricatorNotificationClearController' => 'PhabricatorNotificationController',
'PhabricatorNotificationClient' => 'Phobject',
@ -8711,7 +8704,6 @@ phutil_register_library_map(array(
),
'PhabricatorPhurlURLAccessController' => 'PhabricatorPhurlController',
'PhabricatorPhurlURLAliasTransaction' => 'PhabricatorPhurlURLTransactionType',
'PhabricatorPhurlURLCommentController' => 'PhabricatorPhurlController',
'PhabricatorPhurlURLCreateCapability' => 'PhabricatorPolicyCapability',
'PhabricatorPhurlURLDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorPhurlURLDescriptionTransaction' => 'PhabricatorPhurlURLTransactionType',
@ -8947,7 +8939,6 @@ phutil_register_library_map(array(
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorPronounSetting' => 'PhabricatorSelectSetting',
'PhabricatorProtocolAdapter' => 'Phobject',
'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorQuery' => 'Phobject',
'PhabricatorQueryConstraint' => 'Phobject',
@ -9351,7 +9342,6 @@ phutil_register_library_map(array(
'PhabricatorStoragePatch' => 'Phobject',
'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter',
'PhabricatorStringListEditField' => 'PhabricatorEditField',
'PhabricatorStringSetting' => 'PhabricatorSetting',
'PhabricatorSubmitEditField' => 'PhabricatorEditField',

View file

@ -139,4 +139,29 @@ final class AphrontFileResponse extends AphrontResponse {
return $this->getCompressResponse();
}
public function parseHTTPRange($range) {
$begin = null;
$end = null;
$matches = null;
if (preg_match('/^bytes=(\d+)-(\d*)$/', $range, $matches)) {
// Note that the "Range" header specifies bytes differently than
// we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1).
$begin = (int)$matches[1];
// The "Range" may be "200-299" or "200-", meaning "until end of file".
if (strlen($matches[2])) {
$range_end = (int)$matches[2];
$end = $range_end + 1;
} else {
$range_end = null;
}
$this->setHTTPResponseCode(206);
$this->setRange($begin, $range_end);
}
return array($begin, $end);
}
}

View file

@ -9,8 +9,10 @@
* @task meta Application Management
*/
abstract class PhabricatorApplication
extends Phobject
implements PhabricatorPolicyInterface {
extends PhabricatorLiskDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface {
const GROUP_CORE = 'core';
const GROUP_UTILITIES = 'util';
@ -26,6 +28,30 @@ abstract class PhabricatorApplication
);
}
final public function getApplicationName() {
return 'application';
}
final public function getTableName() {
return 'application_application';
}
final protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
final public function generatePHID() {
return $this->getPHID();
}
final public function save() {
// When "save()" is called on applications, we just return without
// actually writing anything to the database.
return $this;
}
/* -( Application Information )-------------------------------------------- */
@ -613,4 +639,25 @@ abstract class PhabricatorApplication
);
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PhutilMethodNotImplementedException(pht('Coming Soon!'));
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new PhabricatorApplicationApplicationTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
}

View file

@ -104,9 +104,30 @@ abstract class CelerityResourceController extends PhabricatorController {
}
$response = id(new AphrontFileResponse())
->setContent($data)
->setMimeType($type_map[$type])
->setCompressResponse(true);
->setMimeType($type_map[$type]);
$range = AphrontRequest::getHTTPHeader('Range');
if (strlen($range)) {
$response->setContentLength(strlen($data));
list($range_begin, $range_end) = $response->parseHTTPRange($range);
if ($range_begin !== null) {
if ($range_end !== null) {
$data = substr($data, $range_begin, ($range_end - $range_begin));
} else {
$data = substr($data, $range_begin);
}
}
$response->setContentIterator(array($data));
} else {
$response
->setContent($data)
->setCompressResponse(true);
}
// NOTE: This is a piece of magic required to make WOFF fonts work in
// Firefox and IE. Possibly we should generalize this more.

View file

@ -103,10 +103,20 @@ final class PhabricatorConfigClusterNotificationsController
new PhutilNumber(idx($details, 'messages.in')),
new PhutilNumber(idx($details, 'messages.out')));
if (idx($details, 'history.size')) {
$history = pht(
'%s Held / %sms',
new PhutilNumber(idx($details, 'history.size')),
new PhutilNumber(idx($details, 'history.age')));
} else {
$history = pht('No Messages');
}
} else {
$uptime = null;
$clients = null;
$stats = null;
$history = null;
}
$status_view = array(
@ -126,6 +136,7 @@ final class PhabricatorConfigClusterNotificationsController
$uptime,
$clients,
$stats,
$history,
$messages,
);
}
@ -143,6 +154,7 @@ final class PhabricatorConfigClusterNotificationsController
pht('Uptime'),
pht('Clients'),
pht('Messages'),
pht('History'),
null,
))
->setColumnClasses(
@ -155,6 +167,7 @@ final class PhabricatorConfigClusterNotificationsController
null,
null,
null,
null,
'wide',
));

View file

@ -11,6 +11,13 @@ final class PhabricatorConfigDatabaseSchema
public function addTable(PhabricatorConfigTableSchema $table) {
$key = $table->getName();
if (isset($this->tables[$key])) {
if ($key == 'application_application') {
// NOTE: This is a terrible hack to allow Application subclasses to
// extend LiskDAO so we can apply transactions to them.
return $this;
}
throw new Exception(
pht('Trying to add duplicate table "%s"!', $key));
}

View file

@ -107,7 +107,8 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
$xactions = array();
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $participant_phids));
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(

View file

@ -9,7 +9,8 @@ abstract class ConpherenceTestCase extends PhabricatorTestCase {
$xactions = array(
id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $participant_phids)),
);
$editor = id(new ConpherenceEditor())
@ -26,7 +27,8 @@ abstract class ConpherenceTestCase extends PhabricatorTestCase {
$xactions = array(
id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('-' => $participant_phids)),
);
$editor = id(new ConpherenceEditor())

View file

@ -55,6 +55,8 @@ final class PhabricatorConpherenceApplication extends PhabricatorApplication {
=> 'ConpherenceNotificationPanelController',
'participant/(?P<id>[1-9]\d*)/'
=> 'ConpherenceParticipantController',
'preferences/(?P<id>[1-9]\d*)/'
=> 'ConpherenceRoomPreferencesController',
'update/(?P<id>[1-9]\d*)/'
=> 'ConpherenceUpdateController',
),

View file

@ -36,8 +36,7 @@ final class ConpherenceQueryThreadConduitAPIMethod
$offset = $request->getValue('offset');
$query = id(new ConpherenceThreadQuery())
->setViewer($user)
->needParticipantCache(true);
->setViewer($user);
if ($ids) {
$conpherences = $query
@ -57,7 +56,7 @@ final class ConpherenceQueryThreadConduitAPIMethod
->setLimit($limit)
->setOffset($offset)
->execute();
$conpherence_phids = array_keys($participation);
$conpherence_phids = mpull($participation, 'getConpherencePHID');
$query->withPHIDs($conpherence_phids);
$conpherences = $query->execute();
$conpherences = array_select_keys($conpherences, $conpherence_phids);

View file

@ -69,7 +69,7 @@ final class ConpherenceUpdateThreadConduitAPIMethod
if ($add_participant_phids) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransaction::TYPE_PARTICIPANTS)
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $add_participant_phids));
}
if ($remove_participant_phid) {
@ -78,7 +78,7 @@ final class ConpherenceUpdateThreadConduitAPIMethod
}
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransaction::TYPE_PARTICIPANTS)
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('-' => array($remove_participant_phid)));
}
if ($title) {

View file

@ -1,8 +0,0 @@
<?php
final class ConpherenceParticipationStatus extends ConpherenceConstants {
const UP_TO_DATE = 0;
const BEHIND = 1;
}

View file

@ -0,0 +1,69 @@
<?php
final class ConpherenceRoomSettings extends ConpherenceConstants {
const SOUND_RECEIVE = 'receive';
const SOUND_MENTION = 'mention';
const DEFAULT_RECEIVE_SOUND = 'tap';
const DEFAULT_MENTION_SOUND = 'alert';
const DEFAULT_NO_SOUND = 'none';
const COLOR_LIGHT = 'light';
const COLOR_BLUE = 'blue';
const COLOR_INDIGO = 'indigo';
const COLOR_PEACH = 'peach';
const COLOR_GREEN = 'green';
const COLOR_PINK = 'pink';
public static function getSoundMap() {
return array(
'none' => array(
'name' => pht('No Sound'),
'rsrc' => '',
),
'alert' => array(
'name' => pht('Alert'),
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/alert.mp3'),
),
'bing' => array(
'name' => pht('Bing'),
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/bing.mp3'),
),
'pock' => array(
'name' => pht('Pock'),
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/pock.mp3'),
),
'tap' => array(
'name' => pht('Tap'),
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/tap.mp3'),
),
'ting' => array(
'name' => pht('Ting'),
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/ting.mp3'),
),
);
}
public static function getDropdownSoundMap() {
$map = self::getSoundMap();
return ipull($map, 'name');
}
public static function getThemeMap() {
return array(
self::COLOR_LIGHT => pht('Light'),
self::COLOR_BLUE => pht('Blue'),
self::COLOR_INDIGO => pht('Indigo'),
self::COLOR_PEACH => pht('Peach'),
self::COLOR_GREEN => pht('Green'),
self::COLOR_PINK => pht('Pink'),
);
}
public static function getThemeClass($theme) {
return 'conpherence-theme-'.$theme;
}
}

View file

@ -8,7 +8,6 @@ final class ConpherenceUpdateActions extends ConpherenceConstants {
const JOIN_ROOM = 'join_room';
const ADD_PERSON = 'add_person';
const REMOVE_PERSON = 'remove_person';
const NOTIFICATIONS = 'notifications';
const ADD_STATUS = 'add_status';
const LOAD = 'load';
}

View file

@ -67,7 +67,7 @@ final class ConpherenceColumnViewController extends
$transactions = $conpherence->getTransactions();
$latest_transaction = head($transactions);
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
$participant->markUpToDate($conpherence, $latest_transaction);
$participant->markUpToDate($conpherence);
unset($write_guard);
$draft = PhabricatorDraft::newFromUserAndKey(

View file

@ -54,19 +54,29 @@ abstract class ConpherenceController extends PhabricatorController {
}
protected function buildHeaderPaneContent(
ConpherenceThread $conpherence,
array $policy_objects) {
assert_instances_of($policy_objects, 'PhabricatorPolicy');
ConpherenceThread $conpherence) {
$viewer = $this->getViewer();
$header = null;
$id = $conpherence->getID();
if ($conpherence->getID()) {
if ($id) {
$data = $conpherence->getDisplayData($this->getViewer());
$header = id(new PHUIHeaderView())
->setViewer($viewer)
->setHeader($data['title'])
->setSubheader($data['topic'])
->setPolicyObject($conpherence)
->setImage($data['image']);
if (strlen($data['topic'])) {
$topic = id(new PHUITagView())
->setName($data['topic'])
->setShade(PHUITagView::COLOR_VIOLET)
->setType(PHUITagView::TYPE_SHADE)
->addClass('conpherence-header-topic');
$header->addTag($topic);
}
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$conpherence,
@ -74,15 +84,14 @@ abstract class ConpherenceController extends PhabricatorController {
if ($can_edit) {
$header->setImageURL(
$this->getApplicationURI('picture/'.$conpherence->getID().'/'));
$this->getApplicationURI("picture/{$id}/"));
}
$participating = $conpherence->getParticipantIfExists($viewer->getPHID());
$header->addActionItem(
id(new PHUIIconCircleView())
->setHref(
$this->getApplicationURI('update/'.$conpherence->getID()).'/')
->setHref($this->getApplicationURI("update/{$id}/"))
->setIcon('fa-pencil')
->addClass('hide-on-device')
->setColor('violet')
@ -90,9 +99,7 @@ abstract class ConpherenceController extends PhabricatorController {
$header->addActionItem(
id(new PHUIIconCircleView())
->setHref(
$this->getApplicationURI('update/'.$conpherence->getID()).'/'.
'?action='.ConpherenceUpdateActions::NOTIFICATIONS)
->setHref($this->getApplicationURI("preferences/{$id}/"))
->setIcon('fa-gear')
->addClass('hide-on-device')
->setColor('pink')
@ -127,7 +134,7 @@ abstract class ConpherenceController extends PhabricatorController {
if (!$participating) {
$action = ConpherenceUpdateActions::JOIN_ROOM;
$uri = $this->getApplicationURI('update/'.$conpherence->getID().'/');
$uri = $this->getApplicationURI("update/{$id}/");
$button = phutil_tag(
'button',
array(

View file

@ -34,7 +34,7 @@ final class ConpherenceListController extends ConpherenceController {
$title = pht('Conpherence');
$conpherence = null;
$limit = (ConpherenceThreadListView::SEE_MORE_LIMIT * 2) + 1;
$limit = ConpherenceThreadListView::SEE_ALL_LIMIT + 1;
$all_participation = array();
$mode = $this->determineMode();
@ -64,7 +64,7 @@ final class ConpherenceListController extends ConpherenceController {
}
// check to see if the loaded conpherence is going to show up
// within the SEE_MORE_LIMIT amount of conpherences.
// within the SEE_ALL_LIMIT amount of conpherences.
// If its not there, then we just pre-pend it as the "first"
// conpherence so folks have a navigation item in the menu.
$count = 0;
@ -75,7 +75,7 @@ final class ConpherenceListController extends ConpherenceController {
break;
}
$count++;
if ($count > ConpherenceThreadListView::SEE_MORE_LIMIT) {
if ($count > ConpherenceThreadListView::SEE_ALL_LIMIT) {
break;
}
}
@ -89,11 +89,19 @@ final class ConpherenceListController extends ConpherenceController {
default:
$data = $this->loadDefaultParticipation($limit);
$all_participation = $data['all_participation'];
if ($all_participation) {
$conpherence_id = head($all_participation)->getConpherencePHID();
$conpherence = id(new ConpherenceThreadQuery())
->setViewer($user)
->withPHIDs(array($conpherence_id))
->needProfileImage(true)
->executeOne();
}
// If $conpherence is null, NUX state will render
break;
}
$threads = $this->loadConpherenceThreadData(
$all_participation);
$threads = $this->loadConpherenceThreadData($all_participation);
$thread_view = id(new ConpherenceThreadListView())
->setUser($user)
@ -144,6 +152,7 @@ final class ConpherenceListController extends ConpherenceController {
->withParticipantPHIDs(array($viewer->getPHID()))
->setLimit($limit)
->execute();
$all_participation = mpull($all_participation, null, 'getConpherencePHID');
return array(
'all_participation' => $all_participation,

View file

@ -23,7 +23,8 @@ final class ConpherenceNewRoomController extends ConpherenceController {
$participants[] = $user->getPHID();
$participants = array_unique($participants);
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $participants));
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceThreadTopicTransaction::TRANSACTIONTYPE)

View file

@ -7,12 +7,12 @@ final class ConpherenceNotificationPanelController
$user = $request->getUser();
$conpherences = array();
require_celerity_resource('conpherence-notification-css');
$unread_status = ConpherenceParticipationStatus::BEHIND;
$participant_data = id(new ConpherenceParticipantQuery())
->withParticipantPHIDs(array($user->getPHID()))
->setLimit(5)
->execute();
$participant_data = mpull($participant_data, null, 'getConpherencePHID');
if ($participant_data) {
$conpherences = id(new ConpherenceThreadQuery())
@ -37,7 +37,7 @@ final class ConpherenceNotificationPanelController
'conpherence-notification',
);
if ($p_data->getParticipationStatus() == $unread_status) {
if (!$p_data->isUpToDate($conpherence)) {
$classes[] = 'phabricator-notification-unread';
}
$uri = $this->getApplicationURI($conpherence->getID().'/');
@ -95,7 +95,7 @@ final class ConpherenceNotificationPanelController
$unread = id(new ConpherenceParticipantCountQuery())
->withParticipantPHIDs(array($user->getPHID()))
->withParticipationStatus($unread_status)
->withUnread(true)
->execute();
$unread_count = idx($unread, $user->getPHID(), 0);

View file

@ -0,0 +1,113 @@
<?php
final class ConpherenceRoomPreferencesController
extends ConpherenceController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$conpherence_id = $request->getURIData('id');
$conpherence = id(new ConpherenceThreadQuery())
->setViewer($viewer)
->withIDs(array($conpherence_id))
->executeOne();
if (!$conpherence) {
return new Aphront404Response();
}
$view_uri = $conpherence->getURI();
$participant = $conpherence->getParticipantIfExists($viewer->getPHID());
if (!$participant) {
if ($viewer->isLoggedIn()) {
$text = pht(
'Notification settings are available after joining the room.');
} else {
$text = pht(
'Notification settings are available after logging in and joining '.
'the room.');
}
return $this->newDialog()
->setTitle(pht('Room Preferences'))
->addCancelButton($view_uri)
->appendParagraph($text);
}
// Save the data and redirect
if ($request->isFormPost()) {
$notifications = $request->getStr('notifications');
$sounds = $request->getArr('sounds');
$theme = $request->getStr('theme');
$participant->setSettings(array(
'notifications' => $notifications,
'sounds' => $sounds,
'theme' => $theme,
));
$participant->save();
return id(new AphrontRedirectResponse())
->setURI($view_uri);
}
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
$notification_default = $viewer->getUserSetting($notification_key);
$sound_key = PhabricatorConpherenceSoundSetting::SETTINGKEY;
$sound_default = $viewer->getUserSetting($sound_key);
$settings = $participant->getSettings();
$notifications = idx($settings, 'notifications', $notification_default);
$theme = idx($settings, 'theme', ConpherenceRoomSettings::COLOR_LIGHT);
$sounds = idx($settings, 'sounds', array());
$map = PhabricatorConpherenceSoundSetting::getDefaultSound($sound_default);
$receive = idx($sounds,
ConpherenceRoomSettings::SOUND_RECEIVE,
$map[ConpherenceRoomSettings::SOUND_RECEIVE]);
$mention = idx($sounds,
ConpherenceRoomSettings::SOUND_MENTION,
$map[ConpherenceRoomSettings::SOUND_MENTION]);
$form = id(new AphrontFormView())
->setUser($viewer)
->appendControl(
id(new AphrontFormRadioButtonControl())
->setLabel(pht('Notify'))
->addButton(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
'')
->addButton(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
'')
->setName('notifications')
->setValue($notifications))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('New Message'))
->setName('sounds['.ConpherenceRoomSettings::SOUND_RECEIVE.']')
->setOptions(ConpherenceRoomSettings::getDropdownSoundMap())
->setValue($receive))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Theme'))
->setName('theme')
->setOptions(ConpherenceRoomSettings::getThemeMap())
->setValue($theme));
return $this->newDialog()
->setTitle(pht('Room Preferences'))
->appendForm($form)
->addCancelButton($view_uri)
->addSubmitButton(pht('Save'));
}
}

View file

@ -24,9 +24,6 @@ final class ConpherenceUpdateController
case ConpherenceUpdateActions::METADATA:
$needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT;
break;
case ConpherenceUpdateActions::NOTIFICATIONS:
$need_participants = true;
break;
case ConpherenceUpdateActions::LOAD:
break;
}
@ -61,7 +58,7 @@ final class ConpherenceUpdateController
case ConpherenceUpdateActions::JOIN_ROOM:
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransaction::TYPE_PARTICIPANTS)
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => array($user->getPHID())));
$delete_draft = true;
$message = $request->getStr('text');
@ -95,7 +92,7 @@ final class ConpherenceUpdateController
if (!empty($person_phids)) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransaction::TYPE_PARTICIPANTS)
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $person_phids));
}
break;
@ -108,22 +105,10 @@ final class ConpherenceUpdateController
if ($person_phid) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(
ConpherenceTransaction::TYPE_PARTICIPANTS)
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('-' => array($person_phid)));
$response_mode = 'go-home';
}
break;
case ConpherenceUpdateActions::NOTIFICATIONS:
$notifications = $request->getStr('notifications');
$participant = $conpherence->getParticipantIfExists($user->getPHID());
if (!$participant) {
return id(new Aphront404Response());
}
$participant->setSettings(array('notifications' => $notifications));
$participant->save();
return id(new AphrontRedirectResponse())
->setURI('/'.$conpherence->getMonogram());
break;
case ConpherenceUpdateActions::METADATA:
$title = $request->getStr('title');
@ -217,9 +202,6 @@ final class ConpherenceUpdateController
}
switch ($action) {
case ConpherenceUpdateActions::NOTIFICATIONS:
$dialog = $this->renderPreferencesDialog($conpherence);
break;
case ConpherenceUpdateActions::ADD_PERSON:
$dialog = $this->renderAddPersonDialog($conpherence);
break;
@ -242,64 +224,6 @@ final class ConpherenceUpdateController
}
private function renderPreferencesDialog(
ConpherenceThread $conpherence) {
$request = $this->getRequest();
$user = $request->getUser();
$participant = $conpherence->getParticipantIfExists($user->getPHID());
if (!$participant) {
if ($user->isLoggedIn()) {
$text = pht(
'Notification settings are available after joining the room.');
} else {
$text = pht(
'Notification settings are available after logging in and joining '.
'the room.');
}
return id(new AphrontDialogView())
->setTitle(pht('Room Preferences'))
->appendParagraph($text);
}
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
$notification_default = $user->getUserSetting($notification_key);
$settings = $participant->getSettings();
$notifications = idx(
$settings,
'notifications',
$notification_default);
$form = id(new AphrontFormView())
->setUser($user)
->setFullWidth(true)
->appendControl(
id(new AphrontFormRadioButtonControl())
->addButton(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
'')
->addButton(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
'')
->setName('notifications')
->setValue($notifications));
return id(new AphrontDialogView())
->setTitle(pht('Room Preferences'))
->addHiddenInput('action', 'notifications')
->addHiddenInput(
'latest_transaction_id',
$request->getInt('latest_transaction_id'))
->appendForm($form);
}
private function renderAddPersonDialog(
ConpherenceThread $conpherence) {
@ -360,9 +284,9 @@ final class ConpherenceUpdateController
$body[] = pht(
'Are you sure you want to leave this room?');
} else {
$title = pht('Banish User');
$title = pht('Remove Participant');
$body[] = pht(
'Banish %s from the realm?',
'Remove %s from this room?',
phutil_tag('strong', array(), $removed_user->getUsername()));
}
@ -372,7 +296,7 @@ final class ConpherenceUpdateController
'You will be able to rejoin the room later.');
} else {
$body[] = pht(
'This user will be able to rejoin the room later.');
'They will be able to rejoin the room later.');
}
} else {
if ($is_self) {
@ -387,7 +311,7 @@ final class ConpherenceUpdateController
}
} else {
$body[] = pht(
'This user will not be able to rejoin the room unless invited '.
'They will not be able to rejoin the room unless invited '.
'again.');
}
}
@ -480,7 +404,6 @@ final class ConpherenceUpdateController
$need_transactions = true;
break;
case ConpherenceUpdateActions::REMOVE_PERSON:
case ConpherenceUpdateActions::NOTIFICATIONS:
default:
break;
@ -496,6 +419,8 @@ final class ConpherenceUpdateController
->executeOne();
$non_update = false;
$participant = $conpherence->getParticipant($user->getPHID());
if ($need_transactions && $conpherence->getTransactions()) {
$data = ConpherenceTransactionRenderer::renderTransactions(
$user,
@ -503,9 +428,7 @@ final class ConpherenceUpdateController
$key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY;
$minimized = $user->getUserSetting($key);
if (!$minimized) {
$participant_obj = $conpherence->getParticipant($user->getPHID());
$participant_obj
->markUpToDate($conpherence, $data['latest_transaction']);
$participant->markUpToDate($conpherence);
}
} else if ($need_transactions) {
$non_update = true;
@ -522,18 +445,12 @@ final class ConpherenceUpdateController
$people_widget = null;
switch ($action) {
case ConpherenceUpdateActions::METADATA:
$policy_objects = id(new PhabricatorPolicyQuery())
->setViewer($user)
->setObject($conpherence)
->execute();
$header = $this->buildHeaderPaneContent(
$conpherence,
$policy_objects);
$header = $this->buildHeaderPaneContent($conpherence);
$header = hsprintf('%s', $header);
$nav_item = id(new ConpherenceThreadListView())
->setUser($user)
->setBaseURI($this->getApplicationURI())
->renderSingleThread($conpherence, $policy_objects);
->renderThreadItem($conpherence);
$nav_item = hsprintf('%s', $nav_item);
break;
case ConpherenceUpdateActions::ADD_PERSON:
@ -544,7 +461,6 @@ final class ConpherenceUpdateController
$people_widget = hsprintf('%s', $people_widget->render());
break;
case ConpherenceUpdateActions::REMOVE_PERSON:
case ConpherenceUpdateActions::NOTIFICATIONS:
default:
break;
}
@ -552,6 +468,11 @@ final class ConpherenceUpdateController
$dropdown_query = id(new AphlictDropdownDataQuery())
->setViewer($user);
$dropdown_query->execute();
$sounds = $this->getSoundForParticipant($user, $participant);
$receive_sound = $sounds[ConpherenceRoomSettings::SOUND_RECEIVE];
$mention_sound = $sounds[ConpherenceRoomSettings::SOUND_MENTION];
$content = array(
'non_update' => $non_update,
'transactions' => hsprintf('%s', $rendered_transactions),
@ -565,9 +486,40 @@ final class ConpherenceUpdateController
$dropdown_query->getNotificationData(),
$dropdown_query->getConpherenceData(),
),
'sound' => array(
'receive' => $receive_sound,
'mention' => $mention_sound,
),
);
return $content;
}
protected function getSoundForParticipant(
PhabricatorUser $user,
ConpherenceParticipant $participant) {
$sound_key = PhabricatorConpherenceSoundSetting::SETTINGKEY;
$sound_default = $user->getUserSetting($sound_key);
$settings = $participant->getSettings();
$sounds = idx($settings, 'sounds', array());
$map = PhabricatorConpherenceSoundSetting::getDefaultSound($sound_default);
$receive = idx($sounds,
ConpherenceRoomSettings::SOUND_RECEIVE,
$map[ConpherenceRoomSettings::SOUND_RECEIVE]);
$mention = idx($sounds,
ConpherenceRoomSettings::SOUND_MENTION,
$map[ConpherenceRoomSettings::SOUND_MENTION]);
$sound_map = ConpherenceRoomSettings::getSoundMap();
return array(
ConpherenceRoomSettings::SOUND_RECEIVE => $sound_map[$receive]['rsrc'],
ConpherenceRoomSettings::SOUND_MENTION => $sound_map[$mention]['rsrc'],
);
}
}

View file

@ -55,15 +55,15 @@ final class ConpherenceViewController extends
}
$this->setConpherence($conpherence);
$transactions = $this->getNeededTransactions(
$conpherence,
$old_message_id);
$latest_transaction = head($transactions);
$participant = $conpherence->getParticipantIfExists($user->getPHID());
$theme = ConpherenceRoomSettings::COLOR_LIGHT;
if ($participant) {
$settings = $participant->getSettings();
$theme = idx($settings, 'theme', ConpherenceRoomSettings::COLOR_LIGHT);
if (!$participant->isUpToDate($conpherence)) {
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
$participant->markUpToDate($conpherence, $latest_transaction);
$participant->markUpToDate($conpherence);
$user->clearCacheData(PhabricatorUserMessageCountCacheType::KEY_COUNT);
unset($write_guard);
}
@ -82,11 +82,7 @@ final class ConpherenceViewController extends
$form = null;
$content = array('transactions' => $messages);
} else {
$policy_objects = id(new PhabricatorPolicyQuery())
->setViewer($user)
->setObject($conpherence)
->execute();
$header = $this->buildHeaderPaneContent($conpherence, $policy_objects);
$header = $this->buildHeaderPaneContent($conpherence);
$search = $this->buildSearchForm();
$form = $this->renderFormContent();
$content = array(
@ -126,6 +122,7 @@ final class ConpherenceViewController extends
->setSearch($search)
->setMessages($messages)
->setReplyForm($form)
->setTheme($theme)
->setLatestTransactionID($data['latest_transaction_id'])
->setRole('thread');
@ -203,33 +200,6 @@ final class ConpherenceViewController extends
}
}
private function getNeededTransactions(
ConpherenceThread $conpherence,
$message_id) {
if ($message_id) {
$newer_transactions = $conpherence->getTransactions();
$query = id(new ConpherenceTransactionQuery())
->setViewer($this->getRequest()->getUser())
->withObjectPHIDs(array($conpherence->getPHID()))
->setAfterID($message_id)
->needHandles(true)
->setLimit(self::OLDER_FETCH_LIMIT);
$older_transactions = $query->execute();
$handles = array();
foreach ($older_transactions as $transaction) {
$handles += $transaction->getHandles();
}
$conpherence->attachHandles($conpherence->getHandles() + $handles);
$transactions = array_merge($newer_transactions, $older_transactions);
$conpherence->attachTransactions($transactions);
} else {
$transactions = $conpherence->getTransactions();
}
return $transactions;
}
private function getMainQueryLimit() {
$request = $this->getRequest();
$base_limit = ConpherenceThreadQuery::TRANSACTION_LIMIT;

View file

@ -37,7 +37,8 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
if (!$errors) {
$xactions = array();
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $participant_phids));
if ($title) {
$xactions[] = id(new ConpherenceTransaction())
@ -87,8 +88,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
$types[] = PhabricatorTransactions::TYPE_COMMENT;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@ -100,29 +99,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
return pht('%s created this room.', $author);
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
if ($this->getIsNewObject()) {
return array();
}
return $object->getParticipantPHIDs();
}
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
return $this->getPHIDTransactionNewValue($xaction);
}
}
/**
* We really only need a read lock if we have a comment. In that case, we
* must update the messagesCount field on the conpherence and
@ -142,72 +118,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
return $lock;
}
/**
* We need to apply initial effects IFF the conpherence is new. We must
* save the conpherence first thing to make sure we have an id and a phid, as
* well as create the initial set of participants so that we pass policy
* checks.
*/
protected function shouldApplyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
return $this->getIsNewObject();
}
protected function applyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
$object->save();
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
// Since this is a new ConpherenceThread, we have to create the
// participation data asap to pass policy checks. For existing
// ConpherenceThreads, the existing participation is correct
// at this stage. Note that later in applyCustomExternalTransaction
// this participation data will be updated, particularly the
// behindTransactionPHID which is just a generated dummy for now.
$participants = array();
$phids = $this->getPHIDTransactionNewValue($xaction, array());
foreach ($phids as $phid) {
if ($phid == $this->getActor()->getPHID()) {
$status = ConpherenceParticipationStatus::UP_TO_DATE;
$message_count = 1;
} else {
$status = ConpherenceParticipationStatus::BEHIND;
$message_count = 0;
}
$participants[$phid] =
id(new ConpherenceParticipant())
->setConpherencePHID($object->getPHID())
->setParticipantPHID($phid)
->setParticipationStatus($status)
->setDateTouched(time())
->setBehindTransactionPHID($xaction->generatePHID())
->setSeenMessageCount($message_count)
->save();
$object->attachParticipants($participants);
}
break;
}
}
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
if (!$this->getIsNewObject()) {}
break;
}
}
protected function applyBuiltinInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
@ -221,96 +131,23 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
return parent::applyBuiltinInternalTransaction($object, $xaction);
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
if ($this->getIsNewObject()) {
continue;
}
$participants = $object->getParticipants();
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
$remove = array_keys(array_diff_key($old_map, $new_map));
foreach ($remove as $phid) {
$remove_participant = $participants[$phid];
$remove_participant->delete();
unset($participants[$phid]);
}
$add = array_keys(array_diff_key($new_map, $old_map));
foreach ($add as $phid) {
if ($phid == $this->getActor()->getPHID()) {
$status = ConpherenceParticipationStatus::UP_TO_DATE;
$message_count = $object->getMessageCount();
} else {
$status = ConpherenceParticipationStatus::BEHIND;
$message_count = 0;
}
$participants[$phid] =
id(new ConpherenceParticipant())
->setConpherencePHID($object->getPHID())
->setParticipantPHID($phid)
->setParticipationStatus($status)
->setDateTouched(time())
->setBehindTransactionPHID($xaction->getPHID())
->setSeenMessageCount($message_count)
->save();
}
$object->attachParticipants($participants);
break;
}
}
protected function applyFinalEffects(
PhabricatorLiskDAO $object,
array $xactions) {
if (!$xactions) {
return $xactions;
$acting_phid = $this->getActingAsPHID();
$participants = $object->getParticipants();
foreach ($participants as $participant) {
if ($participant->getParticipantPHID() == $acting_phid) {
$participant->markUpToDate($object);
}
}
$message_count = 0;
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
$message_count++;
// update everyone's participation status on a message -only-
$xaction_phid = $xaction->getPHID();
$behind = ConpherenceParticipationStatus::BEHIND;
$up_to_date = ConpherenceParticipationStatus::UP_TO_DATE;
$participants = $object->getParticipants();
$user = $this->getActor();
$time = time();
foreach ($participants as $phid => $participant) {
if ($phid != $user->getPHID()) {
if ($participant->getParticipationStatus() != $behind) {
$participant->setBehindTransactionPHID($xaction_phid);
$participant->setSeenMessageCount(
$object->getMessageCount() - $message_count);
}
$participant->setParticipationStatus($behind);
$participant->setDateTouched($time);
} else {
$participant->setSeenMessageCount($object->getMessageCount());
$participant->setBehindTransactionPHID($xaction_phid);
$participant->setParticipationStatus($up_to_date);
$participant->setDateTouched($time);
}
$participant->save();
}
PhabricatorUserCache::clearCaches(
PhabricatorUserMessageCountCacheType::KEY_COUNT,
array_keys($participants));
break;
}
if ($participants) {
PhabricatorUserCache::clearCaches(
PhabricatorUserMessageCountCacheType::KEY_COUNT,
array_keys($participants));
}
if ($xactions) {
@ -334,7 +171,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
parent::requireCapabilities($object, $xaction);
switch ($xaction->getTransactionType()) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
case ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE:
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
@ -359,6 +196,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
PhabricatorPolicyCapability::CAN_EDIT);
}
break;
case ConpherenceThreadTitleTransaction::TRANSACTIONTYPE:
case ConpherenceThreadTopicTransaction::TRANSACTIONTYPE:
PhabricatorPolicyFilter::requireCapability(
@ -369,19 +207,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
}
}
protected function mergeTransactions(
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
$type = $u->getTransactionType();
switch ($type) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
return $this->mergePHIDOrEdgeTransactions($u, $v);
}
return parent::mergeTransactions($u, $v);
}
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
@ -484,43 +309,4 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
return true;
}
protected function validateTransaction(
PhabricatorLiskDAO $object,
$type,
array $xactions) {
$errors = parent::validateTransaction($object, $type, $xactions);
switch ($type) {
case ConpherenceTransaction::TYPE_PARTICIPANTS:
foreach ($xactions as $xaction) {
$new_phids = $this->getPHIDTransactionNewValue($xaction, array());
$old_phids = nonempty($object->getParticipantPHIDs(), array());
$phids = array_diff($new_phids, $old_phids);
if (!$phids) {
continue;
}
$users = id(new PhabricatorPeopleQuery())
->setViewer($this->requireActor())
->withPHIDs($phids)
->execute();
$users = mpull($users, null, 'getPHID');
foreach ($phids as $phid) {
if (isset($users[$phid])) {
continue;
}
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht('New room participant "%s" is not a valid user.', $phid),
$xaction);
}
}
break;
}
return $errors;
}
}

View file

@ -55,7 +55,8 @@ final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
$xactions = array();
if ($this->getMailAddedParticipantPHIDs()) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
->setTransactionType(
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
->setNewValue(array('+' => $this->getMailAddedParticipantPHIDs()));
}

View file

@ -1,73 +1,69 @@
<?php
/**
* Query class that answers the question:
*
* - Q: How many unread conpherences am I participating in?
* - A:
* id(new ConpherenceParticipantCountQuery())
* ->withParticipantPHIDs(array($my_phid))
* ->withParticipationStatus(ConpherenceParticipationStatus::BEHIND)
* ->execute();
*/
final class ConpherenceParticipantCountQuery
extends PhabricatorOffsetPagedQuery {
private $participantPHIDs;
private $participationStatus;
private $unread;
public function withParticipantPHIDs(array $phids) {
$this->participantPHIDs = $phids;
return $this;
}
public function withParticipationStatus($participation_status) {
$this->participationStatus = $participation_status;
public function withUnread($unread) {
$this->unread = $unread;
return $this;
}
public function execute() {
$thread = new ConpherenceThread();
$table = new ConpherenceParticipant();
$conn_r = $table->establishConnection('r');
$conn = $table->establishConnection('r');
$rows = queryfx_all(
$conn_r,
'SELECT COUNT(*) as count, participantPHID '.
'FROM %T participant %Q %Q %Q',
$conn,
'SELECT COUNT(*) as count, participantPHID
FROM %T participant JOIN %T thread
ON participant.conpherencePHID = thread.phid %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildGroupByClause($conn_r),
$this->buildLimitClause($conn_r));
$thread->getTableName(),
$this->buildWhereClause($conn),
$this->buildGroupByClause($conn),
$this->buildLimitClause($conn));
return ipull($rows, 'count', 'participantPHID');
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
$where = array();
if ($this->participantPHIDs) {
if ($this->participantPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'participantPHID IN (%Ls)',
$conn,
'participant.participantPHID IN (%Ls)',
$this->participantPHIDs);
}
if ($this->participationStatus !== null) {
$where[] = qsprintf(
$conn_r,
'participationStatus = %d',
$this->participationStatus);
if ($this->unread !== null) {
if ($this->unread) {
$where[] = qsprintf(
$conn,
'participant.seenMessageCount < thread.messageCount');
} else {
$where[] = qsprintf(
$conn,
'participant.seenMessageCount >= thread.messageCount');
}
}
return $this->formatWhereClause($where);
}
private function buildGroupByClause(AphrontDatabaseConnection $conn_r) {
$group_by = qsprintf(
$conn_r,
private function buildGroupByClause(AphrontDatabaseConnection $conn) {
return qsprintf(
$conn,
'GROUP BY participantPHID');
return $group_by;
}
}

View file

@ -1,128 +1,50 @@
<?php
/**
* Query class that answers these questions:
*
* - Q: What are the conpherences to show when I land on /conpherence/ ?
* - A:
*
* id(new ConpherenceParticipantQuery())
* ->withParticipantPHIDs(array($my_phid))
* ->execute();
*
* - Q: What are the next set of conpherences as I scroll up (more recent) or
* down (less recent) this list of conpherences?
* - A:
*
* id(new ConpherenceParticipantQuery())
* ->withParticipantPHIDs(array($my_phid))
* ->withParticipantCursor($top_participant)
* ->setOrder(ConpherenceParticipantQuery::ORDER_NEWER)
* ->execute();
*
* -or-
*
* id(new ConpherenceParticipantQuery())
* ->withParticipantPHIDs(array($my_phid))
* ->withParticipantCursor($bottom_participant)
* ->setOrder(ConpherenceParticipantQuery::ORDER_OLDER)
* ->execute();
*
* For counts of read, un-read, or all conpherences by participant, see
* @{class:ConpherenceParticipantCountQuery}.
*/
final class ConpherenceParticipantQuery extends PhabricatorOffsetPagedQuery {
const LIMIT = 100;
const ORDER_NEWER = 'newer';
const ORDER_OLDER = 'older';
private $participantPHIDs;
private $participantCursor;
private $order = self::ORDER_OLDER;
public function withParticipantPHIDs(array $phids) {
$this->participantPHIDs = $phids;
return $this;
}
public function withParticipantCursor(ConpherenceParticipant $participant) {
$this->participantCursor = $participant;
return $this;
}
public function setOrder($order) {
$this->order = $order;
return $this;
}
public function execute() {
$table = new ConpherenceParticipant();
$conn_r = $table->establishConnection('r');
$thread = new ConpherenceThread();
$conn = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T participant %Q %Q %Q',
$conn,
'SELECT * FROM %T participant JOIN %T thread
ON participant.conpherencePHID = thread.phid %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
$thread->getTableName(),
$this->buildWhereClause($conn),
$this->buildOrderClause($conn),
$this->buildLimitClause($conn));
$participants = $table->loadAllFromArray($data);
$participants = mpull($participants, null, 'getConpherencePHID');
if ($this->order == self::ORDER_NEWER) {
$participants = array_reverse($participants);
}
return $participants;
return $table->loadAllFromArray($data);
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
$where = array();
if ($this->participantPHIDs) {
if ($this->participantPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'participantPHID IN (%Ls)',
$this->participantPHIDs);
}
if ($this->participantCursor) {
$date_touched = $this->participantCursor->getDateTouched();
$id = $this->participantCursor->getID();
if ($this->order == self::ORDER_OLDER) {
$compare_date = '<';
$compare_id = '<=';
} else {
$compare_date = '>';
$compare_id = '>=';
}
$where[] = qsprintf(
$conn_r,
'(dateTouched %Q %d OR (dateTouched = %d AND id %Q %d))',
$compare_date,
$date_touched,
$date_touched,
$compare_id,
$id);
}
return $this->formatWhereClause($where);
}
private function buildOrderClause(AphrontDatabaseConnection $conn_r) {
$order_word = ($this->order == self::ORDER_OLDER) ? 'DESC' : 'ASC';
// if these are different direction we won't get as efficient a query
// see http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html
$order = qsprintf(
$conn_r,
'ORDER BY dateTouched %Q, id %Q',
$order_word,
$order_word);
return $order;
private function buildOrderClause(AphrontDatabaseConnection $conn) {
return qsprintf(
$conn,
'ORDER BY thread.dateModified DESC, thread.id DESC, participant.id DESC');
}
}

View file

@ -4,10 +4,7 @@ final class ConpherenceParticipant extends ConpherenceDAO {
protected $participantPHID;
protected $conpherencePHID;
protected $participationStatus;
protected $behindTransactionPHID;
protected $seenMessageCount;
protected $dateTouched;
protected $settings = array();
protected function getConfiguration() {
@ -16,8 +13,6 @@ final class ConpherenceParticipant extends ConpherenceDAO {
'settings' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'participationStatus' => 'uint32',
'dateTouched' => 'epoch',
'seenMessageCount' => 'uint64',
),
self::CONFIG_KEY_SCHEMA => array(
@ -25,11 +20,8 @@ final class ConpherenceParticipant extends ConpherenceDAO {
'columns' => array('conpherencePHID', 'participantPHID'),
'unique' => true,
),
'unreadCount' => array(
'columns' => array('participantPHID', 'participationStatus'),
),
'participationIndex' => array(
'columns' => array('participantPHID', 'dateTouched', 'id'),
'key_thread' => array(
'columns' => array('participantPHID', 'conpherencePHID'),
),
),
) + parent::getConfiguration();
@ -39,12 +31,9 @@ final class ConpherenceParticipant extends ConpherenceDAO {
return nonempty($this->settings, array());
}
public function markUpToDate(
ConpherenceThread $conpherence,
ConpherenceTransaction $xaction) {
public function markUpToDate(ConpherenceThread $conpherence) {
if (!$this->isUpToDate($conpherence)) {
$this->setParticipationStatus(ConpherenceParticipationStatus::UP_TO_DATE);
$this->setBehindTransactionPHID($xaction->getPHID());
$this->setSeenMessageCount($conpherence->getMessageCount());
$this->save();
@ -57,11 +46,7 @@ final class ConpherenceParticipant extends ConpherenceDAO {
}
public function isUpToDate(ConpherenceThread $conpherence) {
return
($this->getSeenMessageCount() == $conpherence->getMessageCount())
&&
($this->getParticipationStatus() ==
ConpherenceParticipationStatus::UP_TO_DATE);
return ($this->getSeenMessageCount() == $conpherence->getMessageCount());
}
}

View file

@ -72,6 +72,10 @@ final class ConpherenceThread extends ConpherenceDAO
return 'Z'.$this->getID();
}
public function getURI() {
return '/'.$this->getMonogram();
}
public function attachParticipants(array $participants) {
assert_instances_of($participants, 'ConpherenceParticipant');
$this->participants = $participants;
@ -200,8 +204,13 @@ final class ConpherenceThread extends ConpherenceDAO
}
$user_participation = $this->getParticipantIfExists($viewer->getPHID());
$theme = ConpherenceRoomSettings::COLOR_LIGHT;
if ($user_participation) {
$user_seen_count = $user_participation->getSeenMessageCount();
$participant = $this->getParticipant($viewer->getPHID());
$settings = $participant->getSettings();
$theme = idx($settings, 'theme', $theme);
$theme_class = ConpherenceRoomSettings::getThemeClass($theme);
} else {
$user_seen_count = 0;
}
@ -217,6 +226,7 @@ final class ConpherenceThread extends ConpherenceDAO
'unread_count' => $unread_count,
'epoch' => $this->getDateModified(),
'image' => $img_src,
'theme' => $theme_class,
);
}

View file

@ -3,8 +3,6 @@
final class ConpherenceTransaction
extends PhabricatorModularTransaction {
const TYPE_PARTICIPANTS = 'participants';
public function getApplicationName() {
return 'conpherence';
}
@ -21,81 +19,4 @@ final class ConpherenceTransaction
return 'ConpherenceThreadTransactionType';
}
public function getNoEffectDescription() {
switch ($this->getTransactionType()) {
case self::TYPE_PARTICIPANTS:
return pht(
'You can not add a participant who has already been added.');
break;
}
return parent::getNoEffectDescription();
}
public function shouldHide() {
$old = $this->getOldValue();
switch ($this->getTransactionType()) {
case self::TYPE_PARTICIPANTS:
return ($old === null);
}
return parent::shouldHide();
}
public function getTitle() {
$author_phid = $this->getAuthorPHID();
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case self::TYPE_PARTICIPANTS:
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && $rem) {
$title = pht(
'%s edited participant(s), added %d: %s; removed %d: %s.',
$this->renderHandleLink($author_phid),
count($add),
$this->renderHandleList($add),
count($rem),
$this->renderHandleList($rem));
} else if ($add) {
$title = pht(
'%s added %d participant(s): %s.',
$this->renderHandleLink($author_phid),
count($add),
$this->renderHandleList($add));
} else {
$title = pht(
'%s removed %d participant(s): %s.',
$this->renderHandleLink($author_phid),
count($rem),
$this->renderHandleList($rem));
}
return $title;
break;
}
return parent::getTitle();
}
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();
$old = $this->getOldValue();
$new = $this->getNewValue();
$phids[] = $this->getAuthorPHID();
switch ($this->getTransactionType()) {
case self::TYPE_PARTICIPANTS:
$phids = array_merge($phids, $this->getOldValue());
$phids = array_merge($phids, $this->getNewValue());
break;
}
return $phids;
}
}

View file

@ -10,6 +10,7 @@ final class ConpherenceLayoutView extends AphrontTagView {
private $search;
private $messages;
private $replyForm;
private $theme = ConpherenceRoomSettings::COLOR_LIGHT;
private $latestTransactionID;
public function setMessages($messages) {
@ -56,6 +57,11 @@ final class ConpherenceLayoutView extends AphrontTagView {
return $this;
}
public function setTheme($theme) {
$this->theme = $theme;
return $this;
}
public function setLatestTransactionID($id) {
$this->latestTransactionID = $id;
return $this;
@ -66,6 +72,7 @@ final class ConpherenceLayoutView extends AphrontTagView {
$classes[] = 'conpherence-layout';
$classes[] = 'hide-widgets';
$classes[] = 'conpherence-role-'.$this->role;
$classes[] = ConpherenceRoomSettings::getThemeClass($this->theme);
return array(
'id' => 'conpherence-main-layout',
@ -105,6 +112,7 @@ final class ConpherenceLayoutView extends AphrontTagView {
'canEditSelectedThread' => $can_edit_selected,
'latestTransactionID' => $this->latestTransactionID,
'role' => $this->role,
'theme' => ConpherenceRoomSettings::getThemeClass($this->theme),
'hasThreadList' => (bool)$this->threadView,
'hasThread' => (bool)$this->messages,
'hasWidgets' => false,

View file

@ -2,7 +2,7 @@
final class ConpherenceThreadListView extends AphrontView {
const SEE_MORE_LIMIT = 15;
const SEE_ALL_LIMIT = 16;
private $baseURI;
private $threads;
@ -25,84 +25,11 @@ final class ConpherenceThreadListView extends AphrontView {
->addClass('conpherence-menu')
->setID('conpherence-menu');
$policy_objects = ConpherenceThread::loadViewPolicyObjects(
$this->getUser(),
$this->threads);
$this->addRoomsToMenu($menu, $this->threads, $policy_objects);
$menu = phutil_tag_div('phabricator-side-menu', $menu);
$menu = phutil_tag_div('phui-basic-nav', $menu);
return $menu;
}
public function renderSingleThread(
ConpherenceThread $thread,
array $policy_objects) {
assert_instances_of($policy_objects, 'PhabricatorPolicy');
return $this->renderThread($thread, $policy_objects);
}
private function renderThreadItem(
ConpherenceThread $thread,
array $policy_objects) {
return id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_CUSTOM)
->setName($this->renderThread($thread, $policy_objects));
}
private function renderThread(
ConpherenceThread $thread,
array $policy_objects) {
$user = $this->getUser();
$uri = '/'.$thread->getMonogram();
$data = $thread->getDisplayData($user);
$icon = id(new PHUIIconView())
->addClass('msr')
->setIcon($thread->getPolicyIconName($policy_objects));
$title = phutil_tag(
'span',
array(),
array(
$icon,
$data['title'],
));
$subtitle = $data['subtitle'];
$unread_count = $data['unread_count'];
$epoch = $data['epoch'];
$image = $data['image'];
$dom_id = $thread->getPHID().'-nav-item';
return id(new ConpherenceMenuItemView())
->setUser($user)
->setTitle($title)
->setSubtitle($subtitle)
->setHref($uri)
->setEpoch($epoch)
->setImageURI($image)
->setUnreadCount($unread_count)
->setID($thread->getPHID().'-nav-item')
->addSigil('conpherence-menu-click')
->setMetadata(
array(
'title' => $data['title'],
'id' => $dom_id,
'threadID' => $thread->getID(),
));
}
private function addRoomsToMenu(
PHUIListView $menu,
array $rooms,
array $policy_objects) {
$header = $this->renderMenuItemHeader();
$header = $this->buildHeaderItemView();
$menu->addMenuItem($header);
if (empty($rooms)) {
// Blank State NUX
if (empty($this->threads)) {
$join_item = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LINK)
->setHref('/conpherence/search/')
@ -115,79 +42,70 @@ final class ConpherenceThreadListView extends AphrontView {
->setWorkflow(true)
->setName(pht('Create a Room'));
$menu->addMenuItem($create_item);
return $menu;
}
$this->addThreadsToMenu($menu, $rooms, $policy_objects);
$rooms = $this->buildRoomItems($this->threads);
foreach ($rooms as $room) {
$menu->addMenuItem($room);
}
$menu = phutil_tag_div('phabricator-side-menu', $menu);
$menu = phutil_tag_div('phui-basic-nav', $menu);
return $menu;
}
private function addThreadsToMenu(
PHUIListView $menu,
array $threads,
array $policy_objects) {
private function renderThreadItem(
ConpherenceThread $thread) {
// If we have self::SEE_MORE_LIMIT or less, we can just render
// all the threads at once. Otherwise, we render a "See more"
// UI element, which toggles a show / hide on the remaining rooms
$user = $this->getUser();
$data = $thread->getDisplayData($user);
$dom_id = $thread->getPHID().'-nav-item';
return id(new PHUIListItemView())
->setName($data['title'])
->setHref('/'.$thread->getMonogram())
->setProfileImage($data['image'])
->setCount($data['unread_count'])
->setType(PHUIListItemView::TYPE_CUSTOM)
->setID($thread->getPHID().'-nav-item')
->addSigil('conpherence-menu-click')
->setMetadata(
array(
'title' => $data['title'],
'id' => $dom_id,
'threadID' => $thread->getID(),
'theme' => $data['theme'],
));
}
private function buildRoomItems(array $threads) {
$items = array();
$show_threads = $threads;
$more_threads = array();
if (count($threads) > self::SEE_MORE_LIMIT) {
$show_threads = array_slice($threads, 0, self::SEE_MORE_LIMIT);
$more_threads = array_slice($threads, self::SEE_MORE_LIMIT);
$all_threads = false;
if (count($threads) > self::SEE_ALL_LIMIT) {
$show_threads = array_slice($threads, 0, self::SEE_ALL_LIMIT);
$all_threads = true;
}
foreach ($show_threads as $thread) {
$item = $this->renderThreadItem($thread, $policy_objects);
$menu->addMenuItem($item);
$items[] = $this->renderThreadItem($thread);
}
if ($more_threads) {
$search_uri = '/conpherence/search/query/participant/';
$sigil = 'more-room';
$more_item = id(new PHUIListItemView())
// Send them to application search here
if ($all_threads) {
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LINK)
->setHref($search_uri)
->addSigil('conpherence-menu-see-more')
->setMetadata(array('moreSigil' => $sigil))
->setName(pht('See More'));
$menu->addMenuItem($more_item);
$show_more_threads = $more_threads;
$even_more_threads = array();
if (count($more_threads) > self::SEE_MORE_LIMIT) {
$show_more_threads = array_slice(
$more_threads,
0,
self::SEE_MORE_LIMIT);
$even_more_threads = array_slice(
$more_threads,
self::SEE_MORE_LIMIT);
}
foreach ($show_more_threads as $thread) {
$item = $this->renderThreadItem($thread, $policy_objects)
->addSigil($sigil)
->addClass('hidden');
$menu->addMenuItem($item);
}
if ($even_more_threads) {
// kick them to application search here
$even_more_item = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LINK)
->setHref($search_uri)
->addSigil($sigil)
->addClass('hidden')
->setName(pht('See More'));
$menu->addMenuItem($even_more_item);
}
->setHref('/conpherence/search/query/participant/')
->setIcon('fa-external-link')
->setName(pht('See All Joined'));
}
return $menu;
return $items;
}
private function renderMenuItemHeader() {
private function buildHeaderItemView() {
$rooms = phutil_tag(
'a',
array(

View file

@ -0,0 +1,117 @@
<?php
final class ConpherenceThreadParticipantsTransaction
extends ConpherenceThreadTransactionType {
const TRANSACTIONTYPE = 'participants';
public function generateOldValue($object) {
return $object->getParticipantPHIDs();
}
public function generateNewValue($object, $value) {
$old = $this->generateOldValue($object);
return $this->getPHIDList($old, $value);
}
public function applyExternalEffects($object, $value) {
$participants = $object->getParticipants();
$old = array_keys($participants);
$new = $value;
$add_map = array_fuse(array_diff($new, $old));
$rem_map = array_fuse(array_diff($old, $new));
foreach ($rem_map as $phid) {
$remove_participant = $participants[$phid];
$remove_participant->delete();
unset($participants[$phid]);
}
foreach ($add_map as $phid) {
if (isset($participants[$phid])) {
continue;
}
$participants[$phid] = id(new ConpherenceParticipant())
->setConpherencePHID($object->getPHID())
->setParticipantPHID($phid)
->setSeenMessageCount(0)
->save();
}
$object->attachParticipants($participants);
}
public function getTitle() {
$old = $this->getOldValue();
$new = $this->getNewValue();
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
$author_phid = $this->getAuthorPHID();
if ($add && $rem) {
return pht(
'%s edited participant(s), added %d: %s; removed %d: %s.',
$this->renderAuthor(),
count($add),
$this->renderHandleList($add),
count($rem),
$this->renderHandleList($rem));
} else if ((in_array($author_phid, $add)) && (count($add) == 1)) {
return pht(
'%s joined the room.',
$this->renderAuthor());
} else if ((in_array($author_phid, $rem)) && (count($rem) == 1)) {
return pht(
'%s left the room.',
$this->renderAuthor());
} else if ($add) {
return pht(
'%s added %d participant(s): %s.',
$this->renderAuthor(),
count($add),
$this->renderHandleList($add));
} else {
return pht(
'%s removed %d participant(s): %s.',
$this->renderAuthor(),
count($rem),
$this->renderHandleList($rem));
}
}
public function validateTransactions($object, array $xactions) {
$errors = array();
foreach ($xactions as $xaction) {
$old = $object->getParticipantPHIDs();
$new = $xaction->getNewValue();
$new = $this->getPHIDList($old, $new);
$add_map = array_fuse(array_diff($new, $old));
$rem_map = array_fuse(array_diff($old, $new));
foreach ($add_map as $user_phid) {
$user = id(new PhabricatorPeopleQuery())
->setViewer($this->getActor())
->withPHIDs(array($user_phid))
->executeOne();
if (!$user) {
$errors[] = $this->newInvalidError(
pht(
'Participant PHID "%s" is not a valid user PHID.',
$user_phid));
continue;
}
}
}
return $errors;
}
}

View file

@ -0,0 +1,78 @@
<?php
final class DarkConsoleRealtimePlugin extends DarkConsolePlugin {
public function getName() {
return pht('Realtime');
}
public function getColor() {
return null;
}
public function getDescription() {
return pht('Debugging console for real-time notifications.');
}
public function renderPanel() {
$frame = phutil_tag(
'div',
array(
'id' => 'dark-console-realtime-log',
'class' => 'dark-console-log-frame',
));
$reconnect_label = pht('Reconnect');
$replay_label = pht('Replay');
$repaint_label = pht('Repaint');
$buttons = phutil_tag(
'div',
array(
'class' => 'dark-console-realtime-actions',
),
array(
id(new PHUIButtonView())
->setIcon('fa-refresh')
->setColor(PHUIButtonView::GREY)
->setText($reconnect_label)
->addSigil('dark-console-realtime-action')
->setMetadata(
array(
'action' => 'reconnect',
'label' => $reconnect_label,
)),
id(new PHUIButtonView())
->setIcon('fa-backward')
->setColor(PHUIButtonView::GREY)
->setText($replay_label)
->addSigil('dark-console-realtime-action')
->setMetadata(
array(
'action' => 'replay',
'label' => $replay_label,
)),
id(new PHUIButtonView())
->setIcon('fa-paint-brush')
->setColor(PHUIButtonView::GREY)
->setText($repaint_label)
->addSigil('dark-console-realtime-action')
->setMetadata(
array(
'action' => 'repaint',
'label' => $repaint_label,
)),
));
return phutil_tag(
'div',
array(
'class' => 'dark-console-realtime',
),
array(
$buttons,
$frame,
));
}
}

View file

@ -55,80 +55,101 @@ final class DifferentialReviewersView extends AphrontView {
$item->setHighlighted($reviewer->hasAuthority($viewer));
// If someone other than the reviewer acted on the reviewer's behalf,
// show who is responsible for the current state. This is usually a
// user accepting for a package or project.
$authority_phid = $reviewer->getLastActorPHID();
if ($authority_phid && ($authority_phid !== $phid)) {
$authority_name = $viewer->renderHandle($authority_phid)
->setAsText(true);
} else {
$authority_name = null;
}
switch ($reviewer->getReviewerStatus()) {
case DifferentialReviewerStatus::STATUS_ADDED:
if ($comment_phid) {
if ($is_current_comment) {
$item->setIcon(
'fa-comment',
'blue',
pht('Commented'));
$icon = 'fa-comment';
$color = 'blue';
$label = pht('Commented');
} else {
$item->setIcon(
'fa-comment-o',
'bluegrey',
pht('Commented Previously'));
$icon = 'fa-comment-o';
$color = 'bluegrey';
$label = pht('Commented Previously');
}
} else {
$item->setIcon(
PHUIStatusItemView::ICON_OPEN,
'bluegrey',
pht('Review Requested'));
$icon = PHUIStatusItemView::ICON_OPEN;
$color = 'bluegrey';
$label = pht('Review Requested');
}
break;
case DifferentialReviewerStatus::STATUS_ACCEPTED:
if ($is_current_action) {
$item->setIcon(
PHUIStatusItemView::ICON_ACCEPT,
'green',
pht('Accepted'));
$icon = PHUIStatusItemView::ICON_ACCEPT;
$color = 'green';
if ($authority_name !== null) {
$label = pht('Accepted (by %s)', $authority_name);
} else {
$label = pht('Accepted');
}
} else {
$item->setIcon(
'fa-check-circle-o',
'bluegrey',
pht('Accepted Prior Diff'));
$icon = 'fa-check-circle-o';
$color = 'bluegrey';
if ($authority_name !== null) {
$label = pht('Accepted Prior Diff (by %s)', $authority_name);
} else {
$label = pht('Accepted Prior Diff');
}
}
break;
case DifferentialReviewerStatus::STATUS_REJECTED:
if ($is_current_action) {
$item->setIcon(
PHUIStatusItemView::ICON_REJECT,
'red',
pht('Requested Changes'));
$icon = PHUIStatusItemView::ICON_REJECT;
$color = 'red';
if ($authority_name !== null) {
$label = pht('Requested Changes (by %s)', $authority_name);
} else {
$label = pht('Requested Changes');
}
} else {
$item->setIcon(
'fa-times-circle-o',
'bluegrey',
pht('Requested Changes to Prior Diff'));
$icon = 'fa-times-circle-o';
$color = 'bluegrey';
if ($authority_name !== null) {
$label = pht(
'Requested Changes to Prior Diff (by %s)',
$authority_name);
} else {
$label = pht('Requested Changes to Prior Diff');
}
}
break;
case DifferentialReviewerStatus::STATUS_BLOCKING:
$item->setIcon(
PHUIStatusItemView::ICON_MINUS,
'red',
pht('Blocking Review'));
$icon = PHUIStatusItemView::ICON_MINUS;
$color = 'red';
$label = pht('Blocking Review');
break;
case DifferentialReviewerStatus::STATUS_RESIGNED:
$item->setIcon(
'fa-times',
'grey',
pht('Resigned'));
$icon = 'fa-times';
$color = 'grey';
$label = pht('Resigned');
break;
default:
$item->setIcon(
PHUIStatusItemView::ICON_QUESTION,
'bluegrey',
pht('%s?', $reviewer->getReviewerStatus()));
$icon = PHUIStatusItemView::ICON_QUESTION;
$color = 'bluegrey';
$label = pht('Unknown ("%s")', $reviewer->getReviewerStatus());
break;
}
$item->setIcon($icon, $color, $label);
$item->setTarget($handle->renderHovercardLink());
$view->addItem($item);
}

View file

@ -57,7 +57,8 @@ final class DiffusionBranchTableController extends DiffusionController {
$content = id(new PHUIObjectBoxView())
->setHeaderText($repository->getName())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
->setTable($table)
->setPager($pager);
}
$crumbs = $this->buildCrumbs(
@ -66,8 +67,6 @@ final class DiffusionBranchTableController extends DiffusionController {
));
$crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager);
$header = id(new PHUIHeaderView())
->setHeader(pht('Branches'))
->setHeaderIcon('fa-code-fork');
@ -76,7 +75,6 @@ final class DiffusionBranchTableController extends DiffusionController {
->setHeader($header)
->setFooter(array(
$content,
$pager_box,
));
return $this->newPage()

View file

@ -370,7 +370,8 @@ final class DiffusionBrowseController extends DiffusionController {
$browse_panel = id(new PHUIObjectBoxView())
->setHeader($browse_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($browse_table);
->setTable($browse_table)
->setPager($pager);
$browse_panel->setShowHide(
array(pht('Show Search')),
@ -395,7 +396,6 @@ final class DiffusionBrowseController extends DiffusionController {
'view' => 'browse',
));
$pager_box = $this->renderTablePagerBox($pager);
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
@ -411,7 +411,6 @@ final class DiffusionBrowseController extends DiffusionController {
array(
$open_revisions,
$readme,
$pager_box,
));
if ($details) {
@ -489,14 +488,12 @@ final class DiffusionBrowseController extends DiffusionController {
nonempty($drequest->getPath(), '/'));
}
$box = id(new PHUIObjectBoxView())
return id(new PHUIObjectBoxView())
->setHeaderText($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
->setTable($table)
->setPager($pager);
$pager_box = $this->renderTablePagerBox($pager);
return array($box, $pager_box);
}
private function renderGrepResults(array $results, $pattern) {
@ -1775,9 +1772,8 @@ final class DiffusionBrowseController extends DiffusionController {
}
$header = id(new PHUIHeaderView())
->setHeader(pht('Open Revisions'))
->setSubheader(
pht('Recently updated open revisions affecting this file.'));
->setHeader(pht('Recently Open Revisions'))
->setHeaderIcon('fa-gear');
$view = id(new DifferentialRevisionListView())
->setHeader($header)

View file

@ -92,6 +92,7 @@ final class DiffusionCompareController extends DiffusionController {
array(
'view' => 'compare',
));
$crumbs->setBorder(true);
$pager = id(new PHUIPagerView())
->readFromRequest($request);
@ -310,16 +311,11 @@ final class DiffusionCompareController extends DiffusionController {
$header = id(new PHUIHeaderView())
->setHeader(pht('Commits'));
$object_box = id(new PHUIObjectBoxView())
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table);
->setTable($history_table)
->setPager($pager);
$pager_box = $this->renderTablePagerBox($pager);
return array(
$object_box,
$pager_box,
);
}
}

View file

@ -317,12 +317,6 @@ abstract class DiffusionController extends PhabricatorController {
->appendChild($body);
}
protected function renderTablePagerBox(PHUIPagerView $pager) {
return id(new PHUIBoxView())
->addMargin(PHUI::MARGIN_LARGE)
->appendChild($pager);
}
protected function renderCommitHashTag(DiffusionRequest $drequest) {
$stable_commit = $drequest->getStableCommit();
$commit = phutil_tag(

View file

@ -57,7 +57,8 @@ final class DiffusionHistoryController extends DiffusionController {
$history_panel = id(new PHUIObjectBoxView())
->setHeader($history_header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($history_table);
->setTable($history_table)
->setPager($pager);
$header = $this->buildHeader($drequest);
@ -69,13 +70,10 @@ final class DiffusionHistoryController extends DiffusionController {
));
$crumbs->setBorder(true);
$pager_box = $this->renderTablePagerBox($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$history_panel,
$pager_box,
));
return $this->newPage()

View file

@ -456,7 +456,8 @@ final class DiffusionLintController extends DiffusionController {
$content[] = id(new PHUIObjectBoxView())
->setHeaderText(pht('Lint Details'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($table);
->setTable($table)
->setPager($pager);
$crumbs = $this->buildCrumbs(
array(
@ -465,7 +466,6 @@ final class DiffusionLintController extends DiffusionController {
'view' => 'lint',
));
$pager_box = $this->renderTablePagerBox($pager);
$header = id(new PHUIHeaderView())
->setHeader(pht('Lint: %s', $drequest->getRepository()->getDisplayName()))
->setHeaderIcon('fa-code');
@ -474,7 +474,6 @@ final class DiffusionLintController extends DiffusionController {
->setHeader($header)
->setFooter(array(
$content,
$pager_box,
));
return $this->newPage()

View file

@ -354,9 +354,9 @@ final class DiffusionRepositoryController extends DiffusionController {
}
if ($repository->isSVN()) {
$label = pht('Checkout');
$label = phutil_tag_div('diffusion-clone-label', pht('Checkout'));
} else {
$label = pht('Clone');
$label = phutil_tag_div('diffusion-clone-label', pht('Clone'));
}
$view->addProperty(
@ -686,15 +686,10 @@ final class DiffusionRepositoryController extends DiffusionController {
$pager->setURI($browse_uri, 'offset');
if ($pager->willShowPagingControls()) {
$pager_box = $this->renderTablePagerBox($pager);
} else {
$pager_box = null;
$browse_panel->setPager($pager);
}
return array(
$browse_panel,
$pager_box,
);
return $browse_panel;
}
private function renderCloneURI(

View file

@ -87,15 +87,13 @@ final class DiffusionTagListController extends DiffusionController {
$box = id(new PHUIObjectBoxView())
->setHeaderText($repository->getDisplayName())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setTable($view);
$pager_box = $this->renderTablePagerBox($pager);
->setTable($view)
->setPager($pager);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$box,
$pager_box,
));
return $this->newPage()

View file

@ -73,18 +73,6 @@ final class DiffusionReadmeView extends DiffusionView {
->getOutput($markup_object, $markup_field);
$engine = $markup_object->newMarkupEngine($markup_field);
$toc = PhutilRemarkupHeaderBlockRule::renderTableOfContents($engine);
if ($toc) {
$toc = phutil_tag_div(
'phabricator-remarkup-toc',
array(
phutil_tag_div(
'phabricator-remarkup-toc-header',
pht('Table of Contents')),
$toc,
));
$content = array($toc, $content);
}
$readme_content = $content;
$class = null;
@ -106,15 +94,13 @@ final class DiffusionReadmeView extends DiffusionView {
}
$readme_content = phutil_tag_div($class, $readme_content);
$header = id(new PHUIHeaderView())
->setHeader($readme_name);
$document = id(new PHUIDocumentViewPro())
->setFluid(true)
->appendChild($readme_content);
return id(new PHUIObjectBoxView())
->setHeader($header)
->setHeaderText($readme_name)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($document)
->addClass('diffusion-readme-view');
}

View file

@ -62,24 +62,8 @@ final class PhabricatorFileDataController extends PhabricatorFileController {
// an initial request for bytes 0-1 of the audio file, and things go south
// if we can't respond with a 206 Partial Content.
$range = $request->getHTTPHeader('range');
if ($range) {
$matches = null;
if (preg_match('/^bytes=(\d+)-(\d*)$/', $range, $matches)) {
// Note that the "Range" header specifies bytes differently than
// we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1).
$begin = (int)$matches[1];
// The "Range" may be "200-299" or "200-", meaning "until end of file".
if (strlen($matches[2])) {
$range_end = (int)$matches[2];
$end = $range_end + 1;
} else {
$range_end = null;
}
$response->setHTTPResponseCode(206);
$response->setRange($begin, $range_end);
}
if (strlen($range)) {
list($begin, $end) = $response->parseHTTPRange($range);
}
$is_viewable = $file->isViewableInBrowser();
@ -143,6 +127,7 @@ final class PhabricatorFileDataController extends PhabricatorFileController {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($this->phid))
->withIsDeleted(false)
->executeOne();
if (!$file) {

View file

@ -9,6 +9,7 @@ final class PhabricatorFileDeleteController extends PhabricatorFileController {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withIDs(array($id))
->withIsDeleted(false)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
@ -25,7 +26,19 @@ final class PhabricatorFileDeleteController extends PhabricatorFileController {
}
if ($request->isFormPost()) {
$file->delete();
$xactions = array();
$xactions[] = id(new PhabricatorFileTransaction())
->setTransactionType(PhabricatorFileDeleteTransaction::TRANSACTIONTYPE)
->setNewValue(true);
id(new PhabricatorFileEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($file, $xactions);
return id(new AphrontRedirectResponse())->setURI('/file/');
}

View file

@ -15,6 +15,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($phid))
->withIsDeleted(false)
->executeOne();
if (!$file) {
@ -25,6 +26,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withIDs(array($id))
->withIsDeleted(false)
->executeOne();
if (!$file) {
return new Aphront404Response();

View file

@ -36,7 +36,9 @@ final class PhabricatorFileEditEngine
}
protected function newObjectQuery() {
return new PhabricatorFileQuery();
$query = new PhabricatorFileQuery();
$query->withIsDeleted(false);
return $query;
}
protected function getObjectCreateTitleText($object) {

View file

@ -71,7 +71,7 @@ final class PhabricatorFileEditor
}
protected function supportsSearch() {
return false;
return true;
}
}

View file

@ -129,7 +129,7 @@ final class PhabricatorChunkedFileStorageEngine
foreach ($chunks as $chunk) {
$chunk->save();
}
$file->save();
$file->saveAndIndex();
$file->saveTransaction();
return $file;

View file

@ -18,8 +18,10 @@ final class PhabricatorFileTemporaryGarbageCollector
'ttl < %d LIMIT 100',
PhabricatorTime::getNow());
$engine = new PhabricatorDestructionEngine();
foreach ($files as $file) {
$file->delete();
$engine->destroyObject($file);
}
return (count($files) == 100);

View file

@ -15,6 +15,7 @@ final class PhabricatorFileQuery
private $maxLength;
private $names;
private $isPartial;
private $isDeleted;
private $needTransforms;
private $builtinKeys;
@ -119,6 +120,17 @@ final class PhabricatorFileQuery
return $this;
}
public function withIsDeleted($deleted) {
$this->isDeleted = $deleted;
return $this;
}
public function withNameNgrams($ngrams) {
return $this->withNgramsConstraint(
id(new PhabricatorFileNameNgrams()),
$ngrams);
}
public function showOnlyExplicitUploads($explicit_uploads) {
$this->explicitUploads = $explicit_uploads;
return $this;
@ -390,6 +402,13 @@ final class PhabricatorFileQuery
(int)$this->isPartial);
}
if ($this->isDeleted !== null) {
$where[] = qsprintf(
$conn,
'isDeleted = %d',
(int)$this->isDeleted);
}
if ($this->builtinKeys !== null) {
$where[] = qsprintf(
$conn,

View file

@ -16,7 +16,9 @@ final class PhabricatorFileSearchEngine
}
public function newQuery() {
return new PhabricatorFileQuery();
$query = new PhabricatorFileQuery();
$query->withIsDeleted(false);
return $query;
}
protected function buildCustomSearchFields() {
@ -38,6 +40,10 @@ final class PhabricatorFileSearchEngine
id(new PhabricatorSearchDateField())
->setKey('createdEnd')
->setLabel(pht('Created Before')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('name')
->setDescription(pht('Search for files by name substring.')),
);
}
@ -68,6 +74,10 @@ final class PhabricatorFileSearchEngine
$query->withDateCreatedBefore($map['createdEnd']);
}
if ($map['name'] !== null) {
$query->withNameNgrams($map['name']);
}
return $query;
}

View file

@ -28,7 +28,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface,
PhabricatorConduitResultInterface {
PhabricatorConduitResultInterface,
PhabricatorIndexableInterface,
PhabricatorNgramsInterface {
const METADATA_IMAGE_WIDTH = 'width';
const METADATA_IMAGE_HEIGHT = 'height';
@ -39,6 +41,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
const METADATA_STORAGE = 'storage';
const METADATA_INTEGRITY = 'integrity';
const STATUS_ACTIVE = 'active';
const STATUS_DELETED = 'deleted';
protected $name;
protected $mimeType;
protected $byteSize;
@ -57,6 +62,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
protected $isExplicitUpload = 1;
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
protected $isPartial = 0;
protected $isDeleted = 0;
private $objects = self::ATTACHABLE;
private $objectPHIDs = self::ATTACHABLE;
@ -87,7 +93,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
'metadata' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text255?',
'name' => 'sort255?',
'mimeType' => 'text255?',
'byteSize' => 'uint64',
'storageEngine' => 'text32',
@ -101,6 +107,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
'mailKey' => 'bytes20',
'isPartial' => 'bool',
'builtinKey' => 'text64?',
'isDeleted' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@ -146,6 +153,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
return parent::save();
}
public function saveAndIndex() {
$this->save();
PhabricatorSearchWorker::queueDocumentForIndexing($this->getPHID());
return $this;
}
public function getMonogram() {
return 'F'.$this->getID();
}
@ -232,7 +245,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
$new_file->readPropertiesFromParameters($params);
$new_file->save();
$new_file->saveAndIndex();
return $new_file;
}
@ -388,7 +401,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
// Do nothing
}
$file->save();
$file->saveAndIndex();
return $file;
}
@ -1585,4 +1598,14 @@ final class PhabricatorFile extends PhabricatorFileDAO
return array();
}
/* -( PhabricatorNgramInterface )------------------------------------------ */
public function newNgrams() {
return array(
id(new PhabricatorFileNameNgrams())
->setValue($this->getName()),
);
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorFileNameNgrams
extends PhabricatorSearchNgrams {
public function getNgramKey() {
return 'filename';
}
public function getColumnName() {
return 'name';
}
public function getApplicationName() {
return 'file';
}
}

View file

@ -145,7 +145,7 @@ abstract class PhabricatorFileUploadSource
}
$file = PhabricatorFile::newChunkedFile($engine, $length, $parameters);
$file->save();
$file->saveAndIndex();
$rope = $this->getRope();

View file

@ -0,0 +1,31 @@
<?php
final class FileDeletionWorker extends PhabricatorWorker {
private function loadFile() {
$phid = idx($this->getTaskData(), 'objectPHID');
if (!$phid) {
throw new PhabricatorWorkerPermanentFailureException(
pht('No "%s" in task data.', 'objectPHID'));
}
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($phid))
->executeOne();
if (!$file) {
throw new PhabricatorWorkerPermanentFailureException(
pht('File "%s" does not exist.', $phid));
}
return $file;
}
protected function doWork() {
$file = $this->loadFile();
$engine = new PhabricatorDestructionEngine();
$engine->destroyObject($file);
}
}

View file

@ -0,0 +1,45 @@
<?php
final class PhabricatorFileDeleteTransaction
extends PhabricatorFileTransactionType {
const TRANSACTIONTYPE = 'file:delete';
public function generateOldValue($object) {
return PhabricatorFile::STATUS_ACTIVE;
}
public function applyInternalEffects($object, $value) {
$file = $object;
// Mark the file for deletion, save it, and schedule a worker to
// sweep by later and pick it up.
$file->setIsDeleted(true);
PhabricatorWorker::scheduleTask(
'FileDeletionWorker',
array('objectPHID' => $file->getPHID()),
array('priority' => PhabricatorWorker::PRIORITY_BULK));
}
public function getIcon() {
return 'fa-ban';
}
public function getColor() {
return 'red';
}
public function getTitle() {
return pht(
'%s deleted this file.',
$this->renderAuthor());
}
public function getTitleForFeed() {
return pht(
'%s deleted %s.',
$this->renderAuthor(),
$this->renderObject());
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorApplicationApplicationTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhabricatorApplicationApplicationTransaction();
}
}

View file

@ -0,0 +1,22 @@
<?php
final class PhabricatorApplicationApplicationTransaction
extends PhabricatorModularTransaction {
public function getApplicationName() {
return 'application';
}
public function getApplicationTransactionType() {
return PhabricatorApplicationApplicationPHIDType::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
return new PhabricatorApplicationTransactionComment();
}
public function getBaseTransactionClass() {
return 'PhabricatorApplicationTransactionType';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorApplicationSchemaSpec
extends PhabricatorConfigSchemaSpec {
public function buildSchemata() {
$this->buildEdgeSchemata(new PhabricatorApplicationsApplication());
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorApplicationTransactionType
extends PhabricatorModularTransactionType {}

View file

@ -37,6 +37,15 @@ final class PhabricatorMailManagementShowOutboundWorkflow
'--id'));
}
foreach ($ids as $id) {
if (!ctype_digit($id)) {
throw new PhutilArgumentUsageException(
pht(
'Argument "%s" is not a valid message ID.',
$id));
}
}
$messages = id(new PhabricatorMetaMTAMail())->loadAllWhere(
'id IN (%Ld)',
$ids);

View file

@ -18,6 +18,11 @@ final class PhabricatorNotificationClient extends Phobject {
}
public static function tryToPostMessage(array $data) {
$unique_id = Filesystem::readRandomCharacters(32);
$data = $data + array(
'uniqueID' => $unique_id,
);
$servers = PhabricatorNotificationServerRef::getEnabledAdminServers();
shuffle($servers);

View file

@ -47,6 +47,7 @@ final class PhabricatorNotificationIndividualController
'title' => $data['title'],
'body' => $data['body'],
'content' => hsprintf('%s', $content),
'uniqueID' => 'story/'.$story->getChronologicalKey(),
);
return id(new AphrontAjaxResponse())->setContent($response);

View file

@ -4,7 +4,7 @@ abstract class PhabricatorPackagesEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorPasteApplication';
return 'PhabricatorPackagesApplication';
}
protected function supportsSearch() {

View file

@ -28,10 +28,9 @@ final class PhabricatorUserMessageCountCacheType
$user_phids = mpull($users, 'getPHID');
$unread_status = ConpherenceParticipationStatus::BEHIND;
$unread = id(new ConpherenceParticipantCountQuery())
->withParticipantPHIDs($user_phids)
->withParticipationStatus($unread_status)
->withUnread(true)
->execute();
$empty = array_fill_keys($user_phids, 0);

View file

@ -48,8 +48,6 @@ final class PhabricatorPhurlApplication extends PhabricatorApplication {
'url/' => array(
$this->getEditRoutePattern('edit/')
=> 'PhabricatorPhurlURLEditController',
'comment/(?P<id>[1-9]\d*)/'
=> 'PhabricatorPhurlURLCommentController',
),
),
);

View file

@ -1,63 +0,0 @@
<?php
final class PhabricatorPhurlURLCommentController
extends PhabricatorPhurlController {
public function handleRequest(AphrontRequest $request) {
if (!$request->isFormPost()) {
return new Aphront400Response();
}
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$is_preview = $request->isPreviewRequest();
$draft = PhabricatorDraft::buildFromRequest($request);
$phurl = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$phurl) {
return new Aphront404Response();
}
$view_uri = '/'.$phurl->getMonogram();
$xactions = array();
$xactions[] = id(new PhabricatorPhurlURLTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PhabricatorPhurlURLTransactionComment())
->setContent($request->getStr('comment')));
$editor = id(new PhabricatorPhurlURLEditor())
->setActor($viewer)
->setContinueOnNoEffect($request->isContinueRequest())
->setContentSourceFromRequest($request)
->setIsPreview($is_preview);
try {
$xactions = $editor->applyTransactions($phurl, $xactions);
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
return id(new PhabricatorApplicationTransactionNoEffectResponse())
->setCancelURI($view_uri)
->setException($ex);
}
if ($draft) {
$draft->replaceOrDelete();
}
if ($request->isAjax() && $is_preview) {
return id(new PhabricatorApplicationTransactionResponse())
->setViewer($viewer)
->setTransactions($xactions)
->setIsPreview($is_preview);
} else {
return id(new AphrontRedirectResponse())
->setURI($view_uri);
}
}
}

View file

@ -30,6 +30,7 @@ final class PhabricatorPhurlURLViewController
$timeline = $this->buildTransactionTimeline(
$url,
new PhabricatorPhurlURLTransactionQuery());
$timeline->setQuoteRef($url->getMonogram());
$header = $this->buildHeaderView($url);
$curtain = $this->buildCurtain($url);
@ -39,20 +40,7 @@ final class PhabricatorPhurlURLViewController
->setErrors(array(pht('This URL is invalid due to a bad protocol.')))
->setIsHidden($url->isValid());
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$add_comment_header = $is_serious
? pht('Add Comment')
: pht('More Cowbell');
$draft = PhabricatorDraft::newFromUserAndKey($viewer, $url->getPHID());
$comment_uri = $this->getApplicationURI(
'/url/comment/'.$url->getID().'/');
$add_comment_form = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($url->getPHID())
->setDraft($draft)
->setHeaderText($add_comment_header)
->setAction($comment_uri)
->setSubmitButtonName(pht('Add Comment'));
$add_comment_form = $this->buildCommentForm($url, $timeline);
$view = id(new PHUITwoColumnView())
->setHeader($header)
@ -72,7 +60,16 @@ final class PhabricatorPhurlURLViewController
array(
$view,
));
}
private function buildCommentForm(PhabricatorPhurlURL $url, $timeline) {
$viewer = $this->getViewer();
$box = id(new PhabricatorPhurlURLEditEngine())
->setViewer($viewer)
->buildEditEngineCommentView($url)
->setTransactionTimeline($timeline);
return $box;
}
private function buildHeaderView(PhabricatorPhurlURL $url) {

View file

@ -1,6 +1,7 @@
<?php
interface PhabricatorFulltextInterface {
interface PhabricatorFulltextInterface
extends PhabricatorIndexableInterface {
public function newFulltextEngine();

View file

@ -0,0 +1,3 @@
<?php
interface PhabricatorIndexableInterface {}

View file

@ -1,6 +1,7 @@
<?php
interface PhabricatorNgramsInterface {
interface PhabricatorNgramsInterface
extends PhabricatorIndexableInterface {
public function newNgrams();

View file

@ -213,7 +213,7 @@ final class PhabricatorSearchManagementIndexWorkflow
private function loadPHIDsByTypes($type) {
$objects = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorFulltextInterface')
->setAncestorClass('PhabricatorIndexableInterface')
->execute();
$normalized_type = phutil_utf8_strtolower($type);

View file

@ -0,0 +1,81 @@
<?php
final class PhabricatorConpherenceSoundSetting
extends PhabricatorSelectSetting {
const SETTINGKEY = 'conpherence-sound';
const VALUE_CONPHERENCE_SILENT = '0';
const VALUE_CONPHERENCE_MENTION = '1';
const VALUE_CONPHERENCE_ALL = '2';
public function getSettingName() {
return pht('Conpherence Sound');
}
public function getSettingPanelKey() {
return PhabricatorConpherencePreferencesSettingsPanel::PANELKEY;
}
protected function getControlInstructions() {
return pht(
'Choose the default sound behavior for new Conpherence rooms.');
}
protected function isEnabledForViewer(PhabricatorUser $viewer) {
return PhabricatorApplication::isClassInstalledForViewer(
'PhabricatorConpherenceApplication',
$viewer);
}
public function getSettingDefaultValue() {
return self::VALUE_CONPHERENCE_ALL;
}
protected function getSelectOptions() {
return self::getOptionsMap();
}
public static function getSettingLabel($key) {
$labels = self::getOptionsMap();
return idx($labels, $key, pht('Unknown ("%s")', $key));
}
public static function getDefaultSound($value) {
switch ($value) {
case self::VALUE_CONPHERENCE_ALL:
return array(
ConpherenceRoomSettings::SOUND_RECEIVE =>
ConpherenceRoomSettings::DEFAULT_RECEIVE_SOUND,
ConpherenceRoomSettings::SOUND_MENTION =>
ConpherenceRoomSettings::DEFAULT_MENTION_SOUND,
);
break;
case self::VALUE_CONPHERENCE_MENTION:
return array(
ConpherenceRoomSettings::SOUND_RECEIVE =>
ConpherenceRoomSettings::DEFAULT_NO_SOUND,
ConpherenceRoomSettings::SOUND_MENTION =>
ConpherenceRoomSettings::DEFAULT_MENTION_SOUND,
);
break;
case self::VALUE_CONPHERENCE_SILENT:
return array(
ConpherenceRoomSettings::SOUND_RECEIVE =>
ConpherenceRoomSettings::DEFAULT_NO_SOUND,
ConpherenceRoomSettings::SOUND_MENTION =>
ConpherenceRoomSettings::DEFAULT_NO_SOUND,
);
break;
}
}
private static function getOptionsMap() {
return array(
self::VALUE_CONPHERENCE_SILENT => pht('No Sounds'),
// self::VALUE_CONPHERENCE_MENTION => pht('Mentions Only'),
self::VALUE_CONPHERENCE_ALL => pht('All Messages'),
);
}
}

View file

@ -1801,7 +1801,10 @@ abstract class PhabricatorApplicationTransactionEditor
$old = array_fuse($xaction->getOldValue());
}
$new = $xaction->getNewValue();
return $this->getPHIDList($old, $xaction->getNewValue());
}
public function getPHIDList(array $old, array $new) {
$new_add = idx($new, '+', array());
unset($new['+']);
$new_rem = idx($new, '-', array());

View file

@ -309,4 +309,10 @@ abstract class PhabricatorModularTransactionType
return $this->getStorage()->getIsCreateTransaction();
}
final protected function getPHIDList(array $old, array $new) {
$editor = $this->getEditor();
return $editor->getPHIDList($old, $new);
}
}

View file

@ -10,7 +10,7 @@ Database System
Phabricator uses MySQL or another MySQL-compatible database (like MariaDB
or Amazon RDS).
Phabricator the InnoDB table engine. The only exception is the
Phabricator uses the InnoDB table engine. The only exception is the
`search_documentfield` table which uses MyISAM because MySQL doesn't support
fulltext search in InnoDB (recent versions do, but we haven't added support
yet).
@ -102,7 +102,7 @@ An example of such usage can be found in column
Primary Keys
============
Most tables have auto-increment column named `id`. Adding an ID column is
Most tables have an auto-increment column named `id`. Adding an ID column is
appropriate for most tables (even tables that have another natural unique key),
as it improves consistency and makes it easier to perform generic operations
on objects.
@ -134,12 +134,12 @@ eventually, but there isn't a strong case for them at the present time.
PHIDs
=====
Each globally referencable object in Phabricator has its associated PHID
Each globally referencable object in Phabricator has an associated PHID
("Phabricator ID") which serves as a global identifier, similar to a GUID.
We use PHIDs for referencing data in different databases.
We use both autoincrementing IDs and global PHIDs because each is useful in
different contexts. Autoincrementing IDs are meaningfully ordered and allow
We use both auto-incrementing IDs and global PHIDs because each is useful in
different contexts. Auto-incrementing IDs are meaningfully ordered and allow
us to construct short, human-readable object names (like `D2258`) and URIs.
Global PHIDs allow us to represent relationships between different types of
objects in a homogeneous way.
@ -154,7 +154,7 @@ Transactions
============
Transactional code should be written using transactions. Example of such code is
inserting multiple records where one doesn't make sense without the other or
inserting multiple records where one doesn't make sense without the other, or
selecting data later used for update. See chapter in @{class:LiskDAO}.
Advanced Features
@ -195,12 +195,12 @@ set names:
| Variable | Meaning | Notes |
|---|---|---|
| {$NAMESPACE} | Storage Namespace | Defaults to `phabricator` |
| {$CHARSET} | Default Charset | Mostly used to specify table charset |
| {$COLLATE_TEXT} | Text Collation | For most text (case-sensitive) |
| {$COLLATE_SORT} | Sort Collation | For sortable text (case-insensitive) |
| {$CHARSET_FULLTEXT} | Fulltext Charset | Specify explicitly for fulltext |
| {$COLLATE_FULLTEXT} | Fulltext Collate | Specify explicitly for fulltext |
| `{$NAMESPACE}` | Storage Namespace | Defaults to `phabricator` |
| `{$CHARSET}` | Default Charset | Mostly used to specify table charset |
| `{$COLLATE_TEXT}` | Text Collation | For most text (case-sensitive) |
| `{$COLLATE_SORT}` | Sort Collation | For sortable text (case-insensitive) |
| `{$CHARSET_FULLTEXT}` | Fulltext Charset | Specify explicitly for fulltext |
| `{$COLLATE_FULLTEXT}` | Fulltext Collate | Specify explicitly for fulltext |
**Test your patch**. Run `bin/storage upgrade` to test your patch.

View file

@ -52,9 +52,9 @@ problems.
I joined the new Dev Tools team around February 2010 and took over Diffcamp. I
renamed it to Differential, moved it to a new Alite-based infrastructure with
Javelin, and started making it somewhat less terrible. I eventually wrote
Diffusion and build Herald to replace a very difficult-to-use predecessor. These
Diffusion and built Herald to replace a very difficult-to-use predecessor. These
tools were less negatively received than the older versions. By December 2010 I
started open sourcing them; Haste became //Celerity// and Alite became
//Aphront//. I wrote Maniphest to track open issues with the project in January
or February and we open sourced Phabricator in late April, shortly after I left
Facebook.
or February, left Facebook in April, and shortly after, we open sourced
Phabricator.

View file

@ -134,5 +134,5 @@ query escaping system the rest of the application does.
Hopefully, whatever language you're writing in has good query libraries that
can handle escaping for you. If so, use them. If you're using PHP and don't have
a solution in place yet, the Phabricator implementation of qsprintf() is similar
to Facebook's system and was successful there.
a solution in place yet, the Phabricator implementation of `qsprintf()` is
similar to Facebook's system and was successful there.

View file

@ -1,87 +0,0 @@
@title Chat Bot Technical Documentation
@group bot
Configuring and extending the chat bot.
= Overview =
Phabricator includes a simple chat bot daemon, which is primarily intended as
an example of how you can write an external script that interfaces with
Phabricator over Conduit and does some kind of useful work. If you use IRC or
another supported chat protocol, you can also have the bot hang out in your
channel.
NOTE: The chat bot is somewhat experimental and not very mature.
= Configuring the Bot =
The bot reads a JSON configuration file. You can find an example in:
resources/chatbot/example_config.json
These are the configuration values it reads:
- `server` String, required, the server to connect to.
- `port` Int, optional, the port to connect to (defaults to 6667).
- `ssl` Bool, optional, whether to connect via SSL or not (defaults to
false).
- `nick` String, nickname to use.
- `user` String, optional, username to use (defaults to `nick`).
- `pass` String, optional, password for server.
- `nickpass` String, optional, password for NickServ.
- `join` Array, list of channels to join.
- `handlers` Array, list of handlers to run. These are like plugins for the
bot.
- `conduit.uri`, `conduit.token` Conduit configuration,
see below.
- `notification.channels` Notification configuration, see below.
= Handlers =
You specify a list of "handlers", which are basically plugins or modules for
the bot. These are the default handlers available:
- @{class:PhabricatorBotObjectNameHandler} This handler looks for users
mentioning Phabricator objects like "T123" and "D345" in chat, looks them
up, and says their name with a link to the object. Requires conduit.
- @{class:PhabricatorBotFeedNotificationHandler} This handler posts
notifications about changes to revisions to the channels listed in
`notification.channels`.
- @{class:PhabricatorBotLogHandler} This handler records chatlogs which can
be browsed in the Phabricator web interface.
- @{class:PhabricatorBotSymbolHandler} This handler posts responses to lookups
for symbols in Diffusion
- @{class:PhabricatorBotMacroHandler} This handler looks for users mentioning
macros, if found will convert image to ASCII and output in chat. Configure
with `macro.size` and `macro.aspect`
You can also write your own handlers, by extending
@{class:PhabricatorBotHandler}.
= Conduit =
Some handlers (e.g., @{class:PhabricatorBotObjectNameHandler}) need to read data
from Phabricator over Conduit, Phabricator's HTTP API. You can use this method
to allow other scripts or programs to access Phabricator's data from different
servers and in different languages.
To allow the bot to access Conduit, you need to create a user that it can login
with. To do this, login to Phabricator as an administrator and go to
`People -> Create New Account`. Create a new account and flag them as a
"Bot/Script". Then in your configuration file, set these parameters:
- `conduit.uri` The URI for your Phabricator install, like
`http://phabricator.example.com/`
- `conduit.token` The user's conduit API token, from the "Conduit API Tokens"
tab in the user's administrative view.
Now the bot should be able to connect to Phabricator via Conduit.
= Starting the Bot =
The bot is a Phabricator daemon, so start it with `phd`:
./bin/phd launch phabricatorbot <absolute_path_to_config_file>
If you have issues you can try `debug` instead of `launch`, see
@{article:Managing Daemons with phd} for more information.

View file

@ -1,170 +0,0 @@
<?php
/**
* Simple IRC bot which runs as a Phabricator daemon. Although this bot is
* somewhat useful, it is also intended to serve as a demo of how to write
* "system agents" which communicate with Phabricator over Conduit, so you can
* script system interactions and integrate with other systems.
*
* NOTE: This is super janky and experimental right now.
*/
final class PhabricatorBot extends PhabricatorDaemon {
private $handlers;
private $conduit;
private $config;
private $pollFrequency;
private $protocolAdapter;
protected function run() {
$argv = $this->getArgv();
if (count($argv) !== 1) {
throw new Exception(
pht(
'Usage: %s %s',
__CLASS__,
'<json_config_file>'));
}
$json_raw = Filesystem::readFile($argv[0]);
try {
$config = phutil_json_decode($json_raw);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
pht("File '%s' is not valid JSON!", $argv[0]),
$ex);
}
$nick = idx($config, 'nick', 'phabot');
$handlers = idx($config, 'handlers', array());
$protocol_adapter_class = idx(
$config,
'protocol-adapter',
'PhabricatorIRCProtocolAdapter');
$this->pollFrequency = idx($config, 'poll-frequency', 1);
$this->config = $config;
foreach ($handlers as $handler) {
$obj = newv($handler, array($this));
$this->handlers[] = $obj;
}
$ca_bundle = idx($config, 'https.cabundle');
if ($ca_bundle) {
HTTPSFuture::setGlobalCABundleFromPath($ca_bundle);
}
$conduit_uri = idx($config, 'conduit.uri');
if ($conduit_uri) {
$conduit_token = idx($config, 'conduit.token');
// Normalize the path component of the URI so users can enter the
// domain without the "/api/" part.
$conduit_uri = new PhutilURI($conduit_uri);
$conduit_host = (string)$conduit_uri->setPath('/');
$conduit_uri = (string)$conduit_uri->setPath('/api/');
$conduit = new ConduitClient($conduit_uri);
if ($conduit_token) {
$conduit->setConduitToken($conduit_token);
} else {
$conduit_user = idx($config, 'conduit.user');
$conduit_cert = idx($config, 'conduit.cert');
$response = $conduit->callMethodSynchronous(
'conduit.connect',
array(
'client' => __CLASS__,
'clientVersion' => '1.0',
'clientDescription' => php_uname('n').':'.$nick,
'host' => $conduit_host,
'user' => $conduit_user,
'certificate' => $conduit_cert,
));
}
$this->conduit = $conduit;
}
// Instantiate Protocol Adapter, for now follow same technique as
// handler instantiation
$this->protocolAdapter = newv($protocol_adapter_class, array());
$this->protocolAdapter
->setConfig($this->config)
->connect();
$this->runLoop();
$this->protocolAdapter->disconnect();
}
public function getConfig($key, $default = null) {
return idx($this->config, $key, $default);
}
private function runLoop() {
do {
PhabricatorCaches::destroyRequestCache();
$this->stillWorking();
$messages = $this->protocolAdapter->getNextMessages($this->pollFrequency);
if (count($messages) > 0) {
foreach ($messages as $message) {
$this->routeMessage($message);
}
}
foreach ($this->handlers as $handler) {
$handler->runBackgroundTasks();
}
} while (!$this->shouldExit());
}
public function writeMessage(PhabricatorBotMessage $message) {
return $this->protocolAdapter->writeMessage($message);
}
private function routeMessage(PhabricatorBotMessage $message) {
$ignore = $this->getConfig('ignore');
if ($ignore) {
$sender = $message->getSender();
if ($sender && in_array($sender->getName(), $ignore)) {
return;
}
}
if ($message->getCommand() == 'LOG') {
$this->log('[LOG] '.$message->getBody());
}
foreach ($this->handlers as $handler) {
try {
$handler->receiveMessage($message);
} catch (Exception $ex) {
phlog($ex);
}
}
}
public function getAdapter() {
return $this->protocolAdapter;
}
public function getConduit() {
if (empty($this->conduit)) {
throw new Exception(
pht(
"This bot is not configured with a Conduit uplink. Set '%s' and ".
"'%s' in the configuration to connect.",
'conduit.uri',
'conduit.token'));
}
return $this->conduit;
}
}

View file

@ -1,52 +0,0 @@
<?php
final class PhabricatorBotMessage extends Phobject {
private $sender;
private $command;
private $body;
private $target;
private $public;
public function __construct() {
// By default messages are public
$this->public = true;
}
public function setSender(PhabricatorBotTarget $sender = null) {
$this->sender = $sender;
return $this;
}
public function getSender() {
return $this->sender;
}
public function setCommand($command) {
$this->command = $command;
return $this;
}
public function getCommand() {
return $this->command;
}
public function setBody($body) {
$this->body = $body;
return $this;
}
public function getBody() {
return $this->body;
}
public function setTarget(PhabricatorBotTarget $target = null) {
$this->target = $target;
return $this;
}
public function getTarget() {
return $this->target;
}
}

View file

@ -1,93 +0,0 @@
<?php
final class PhabricatorBotFlowdockProtocolAdapter
extends PhabricatorStreamingProtocolAdapter {
public function getServiceType() {
return 'Flowdock';
}
protected function buildStreamingUrl($channel) {
$organization = $this->getConfig('flowdock.organization');
if (empty($organization)) {
$this->getConfig('organization');
}
if (empty($organization)) {
throw new Exception(
'"flowdock.organization" configuration variable not set');
}
$ssl = $this->getConfig('ssl');
$url = ($ssl) ? 'https://' : 'http://';
$url .= "{$this->authtoken}@stream.flowdock.com";
$url .= "/flows/{$organization}/{$channel}";
return $url;
}
protected function processMessage(array $m_obj) {
$command = null;
switch ($m_obj['event']) {
case 'message':
$command = 'MESSAGE';
break;
default:
// For now, ignore anything which we don't otherwise know about.
break;
}
if ($command === null) {
return false;
}
// TODO: These should be usernames, not user IDs.
$sender = id(new PhabricatorBotUser())
->setName($m_obj['user']);
$target = id(new PhabricatorBotChannel())
->setName($m_obj['flow']);
return id(new PhabricatorBotMessage())
->setCommand($command)
->setSender($sender)
->setTarget($target)
->setBody($m_obj['content']);
}
public function writeMessage(PhabricatorBotMessage $message) {
switch ($message->getCommand()) {
case 'MESSAGE':
$this->speak(
$message->getBody(),
$message->getTarget());
break;
}
}
private function speak(
$body,
PhabricatorBotTarget $flow) {
// The $flow->getName() returns the flow's UUID,
// as such, the Flowdock API does not require the organization
// to be specified in the URI
$this->performPost(
'/messages',
array(
'flow' => $flow->getName(),
'event' => 'message',
'content' => $body,
));
}
public function __destruct() {
if ($this->readHandles) {
foreach ($this->readHandles as $read_handle) {
curl_multi_remove_handle($this->multiHandle, $read_handle);
curl_close($read_handle);
}
}
curl_multi_close($this->multiHandle);
}
}

View file

@ -1,114 +0,0 @@
<?php
final class PhabricatorCampfireProtocolAdapter
extends PhabricatorStreamingProtocolAdapter {
public function getServiceType() {
return 'Campfire';
}
protected function buildStreamingUrl($channel) {
$ssl = $this->getConfig('ssl');
$url = ($ssl) ? 'https://' : 'http://';
$url .= "streaming.campfirenow.com/room/{$channel}/live.json";
return $url;
}
protected function processMessage(array $m_obj) {
$command = null;
switch ($m_obj['type']) {
case 'TextMessage':
$command = 'MESSAGE';
break;
case 'PasteMessage':
$command = 'PASTE';
break;
default:
// For now, ignore anything which we don't otherwise know about.
break;
}
if ($command === null) {
return false;
}
// TODO: These should be usernames, not user IDs.
$sender = id(new PhabricatorBotUser())
->setName($m_obj['user_id']);
$target = id(new PhabricatorBotChannel())
->setName($m_obj['room_id']);
return id(new PhabricatorBotMessage())
->setCommand($command)
->setSender($sender)
->setTarget($target)
->setBody($m_obj['body']);
}
public function writeMessage(PhabricatorBotMessage $message) {
switch ($message->getCommand()) {
case 'MESSAGE':
$this->speak(
$message->getBody(),
$message->getTarget());
break;
case 'SOUND':
$this->speak(
$message->getBody(),
$message->getTarget(),
'SoundMessage');
break;
case 'PASTE':
$this->speak(
$message->getBody(),
$message->getTarget(),
'PasteMessage');
break;
}
}
protected function joinRoom($room_id) {
$this->performPost("/room/{$room_id}/join.json");
$this->inRooms[$room_id] = true;
}
private function leaveRoom($room_id) {
$this->performPost("/room/{$room_id}/leave.json");
unset($this->inRooms[$room_id]);
}
private function speak(
$message,
PhabricatorBotTarget $channel,
$type = 'TextMessage') {
$room_id = $channel->getName();
$this->performPost(
"/room/{$room_id}/speak.json",
array(
'message' => array(
'type' => $type,
'body' => $message,
),
));
}
public function __destruct() {
foreach ($this->inRooms as $room_id => $ignored) {
$this->leaveRoom($room_id);
}
if ($this->readHandles) {
foreach ($this->readHandles as $read_handle) {
curl_multi_remove_handle($this->multiHandle, $read_handle);
curl_close($read_handle);
}
}
curl_multi_close($this->multiHandle);
}
}

Some files were not shown because too many files have changed in this diff Show more