@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator

Remove Chatlog entirely

Summary:
This commit removes ChatLog entirely. All of the application files are removed, and the migrations used are stubbed out. I stubbed the migrations as that allows for existing installs to make no changes, but new installs will not create the database.

Fixes T15126

Test Plan: Loaded up http://phorge.local/chatlog and confirmed the 404. Loaded up http://phorge.local/applications/view/PhabricatorChatLogApplication and confirmed the 404. Created a new database prefix and ran `bin/storage upgrade` against it, confirmed that the chatlog database was not created. Restored another prefix (an old one) and ran `bin/storage upgrade` and confirmed database was not deleted.

Reviewers: O1 Blessed Committers, avivey

Reviewed By: O1 Blessed Committers, avivey

Subscribers: avivey, tobiaswiese, valerio.bozzolan, Cigaryno

Maniphest Tasks: T15126

Differential Revision: https://we.phorge.it/D25480

+5 -1080
-2
resources/celerity/map.php
··· 42 42 'rsrc/css/application/base/notification-menu.css' => '4df1ee30', 43 43 'rsrc/css/application/base/phui-theme.css' => '35883b37', 44 44 'rsrc/css/application/base/standard-page-view.css' => 'e08c7462', 45 - 'rsrc/css/application/chatlog/chatlog.css' => 'abdc76ee', 46 45 'rsrc/css/application/conduit/conduit-api.css' => 'ce2cfc41', 47 46 'rsrc/css/application/config/config-options.css' => '16c920ae', 48 47 'rsrc/css/application/config/config-template.css' => 'e689dbbd', ··· 770 769 'people-profile-css' => '2ea2daa1', 771 770 'phabricator-action-list-view-css' => '1b0085b2', 772 771 'phabricator-busy' => '5202e831', 773 - 'phabricator-chatlog-css' => 'abdc76ee', 774 772 'phabricator-content-source-view-css' => 'cdf0d579', 775 773 'phabricator-core-css' => 'b3a5928e', 776 774 'phabricator-countdown-css' => 'bff8012f',
-1
resources/sql/autopatches/20140722.appname.php
··· 4 4 'Audit', 5 5 'Auth', 6 6 'Calendar', 7 - 'ChatLog', 8 7 'Conduit', 9 8 'Config', 10 9 'Conpherence',
+1 -10
resources/sql/patches/106.chatlog.sql
··· 1 - CREATE TABLE {$NAMESPACE}_chatlog.chatlog_event ( 2 - id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 3 - channel VARCHAR(64) BINARY NOT NULL, 4 - epoch INT UNSIGNED NOT NULL, 5 - author VARCHAR(64) BINARY NOT NULL, 6 - type VARCHAR(4) NOT NULL, 7 - message LONGBLOB NOT NULL, 8 - loggedByPHID VARCHAR(64) BINARY NOT NULL, 9 - KEY (channel, epoch) 10 - ); 1 + /* This file is intentionally left empty, see T15126 */
-18
resources/sql/patches/116.utf8-backup-first-expect-wait.sql
··· 16 16 17 17 18 18 19 - ALTER DATABASE `{$NAMESPACE}_chatlog` COLLATE utf8_general_ci; 20 - 21 - ALTER TABLE `{$NAMESPACE}_chatlog`.`chatlog_event` 22 - MODIFY `channel` varchar(64) CHARACTER SET binary, 23 - MODIFY `author` varchar(64) CHARACTER SET binary, 24 - MODIFY `type` varchar(4) CHARACTER SET binary, 25 - MODIFY `message` longtext CHARACTER SET binary, 26 - MODIFY `loggedByPHID` varchar(64) CHARACTER SET binary; 27 - ALTER TABLE `{$NAMESPACE}_chatlog`.`chatlog_event` 28 - COLLATE utf8_general_ci, 29 - MODIFY `channel` varchar(64) COLLATE utf8_bin NOT NULL, 30 - MODIFY `author` varchar(64) COLLATE utf8_bin NOT NULL, 31 - MODIFY `type` varchar(4) COLLATE utf8_general_ci NOT NULL, 32 - MODIFY `message` longtext COLLATE utf8_bin NOT NULL, 33 - MODIFY `loggedByPHID` varchar(64) COLLATE utf8_bin NOT NULL; 34 - 35 - 36 - 37 19 ALTER DATABASE `{$NAMESPACE}_conduit` COLLATE utf8_general_ci; 38 20 39 21 ALTER TABLE `{$NAMESPACE}_conduit`.`conduit_certificatetoken`
+1 -11
resources/sql/patches/20130214.chatlogchannel.sql
··· 1 - CREATE TABLE {$NAMESPACE}_chatlog.chatlog_channel ( 2 - id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 3 - serviceName VARCHAR(64) COLLATE utf8_bin NOT NULL, 4 - serviceType VARCHAR(32) COLLATE utf8_bin NOT NULL, 5 - channelName VARCHAR(64) COLLATE utf8_bin NOT NULL, 6 - viewPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL, 7 - editPolicy VARCHAR(64) COLLATE utf8_bin NOT NULL, 8 - dateCreated INT UNSIGNED NOT NULL, 9 - dateModified INT UNSIGNED NOT NULL, 10 - UNIQUE KEY `key_channel` (channelName, serviceType, serviceName) 11 - )ENGINE=InnoDB DEFAULT CHARSET=utf8; 1 + /* This file is intentionally left empty, see T15126 */
+1 -2
resources/sql/patches/20130214.chatlogchannelid.sql
··· 1 - ALTER TABLE `{$NAMESPACE}_chatlog`.`chatlog_event` 2 - ADD `channelID` INT UNSIGNED NOT NULL; 1 + /* This file is intentionally left empty, see T15126 */
+1 -62
resources/sql/patches/20130218.updatechannelid.php
··· 1 1 <?php 2 2 3 - echo pht('Updating channel IDs of previous chatlog events...')."\n"; 4 - $event_table = new PhabricatorChatLogEvent(); 5 - $channel_table = new PhabricatorChatLogChannel(); 6 - 7 - $event_table->openTransaction(); 8 - $channel_table->openTransaction(); 9 - 10 - $event_table->beginReadLocking(); 11 - $channel_table->beginReadLocking(); 12 - 13 - $events = new LiskMigrationIterator($event_table); 14 - $conn_w = $channel_table->establishConnection('w'); 15 - 16 - foreach ($events as $event) { 17 - if ($event->getChannelID()) { 18 - continue; 19 - } 20 - 21 - $event_row = queryfx_one( 22 - $conn_w, 23 - 'SELECT channel FROM %T WHERE id = %d', 24 - $event->getTableName(), 25 - $event->getID()); 26 - $event_channel = $event_row['channel']; 27 - 28 - $matched = queryfx_one( 29 - $conn_w, 30 - 'SELECT * FROM %T WHERE 31 - channelName = %s AND serviceName = %s AND serviceType = %s', 32 - $channel_table->getTableName(), 33 - $event_channel, 34 - '', 35 - ''); 36 - 37 - if (!$matched) { 38 - $matched = id(new PhabricatorChatLogChannel()) 39 - ->setChannelName($event_channel) 40 - ->setServiceType('') 41 - ->setServiceName('') 42 - ->setViewPolicy(PhabricatorPolicies::POLICY_USER) 43 - ->setEditPolicy(PhabricatorPolicies::POLICY_USER) 44 - ->save(); 45 - $matched_id = $matched->getID(); 46 - } else { 47 - $matched_id = $matched['id']; 48 - } 49 - 50 - queryfx( 51 - $event->establishConnection('w'), 52 - 'UPDATE %T SET channelID = %d WHERE id = %d', 53 - $event->getTableName(), 54 - $matched_id, 55 - $event->getID()); 56 - } 57 - 58 - $event_table->endReadLocking(); 59 - $channel_table->endReadLocking(); 60 - 61 - $event_table->saveTransaction(); 62 - $channel_table->saveTransaction(); 63 - 64 - echo "\n".pht('Done.')."\n"; 3 + /* This file is intentionally left empty, see T15126 */
+1 -2
resources/sql/patches/20130222.dropchannel.sql
··· 1 - ALTER TABLE `{$NAMESPACE}_chatlog`.`chatlog_event` 2 - DROP channel; 1 + /* This file is intentionally left empty, see T15126 */
-39
resources/sql/quickstart.sql
··· 1477 1477 PRIMARY KEY (`id`) 1478 1478 ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; 1479 1479 1480 - CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_chatlog` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; 1481 - 1482 - USE `{$NAMESPACE}_chatlog`; 1483 - 1484 - SET NAMES utf8 ; 1485 - 1486 - SET character_set_client = {$CHARSET} ; 1487 - 1488 - CREATE TABLE `chatlog_channel` ( 1489 - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 1490 - `serviceName` varchar(64) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1491 - `serviceType` varchar(32) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1492 - `channelName` varchar(64) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1493 - `viewPolicy` varbinary(64) NOT NULL, 1494 - `editPolicy` varbinary(64) NOT NULL, 1495 - `dateCreated` int(10) unsigned NOT NULL, 1496 - `dateModified` int(10) unsigned NOT NULL, 1497 - PRIMARY KEY (`id`), 1498 - UNIQUE KEY `key_channel` (`channelName`,`serviceType`,`serviceName`) 1499 - ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; 1500 - 1501 - USE `{$NAMESPACE}_chatlog`; 1502 - 1503 - SET NAMES utf8 ; 1504 - 1505 - SET character_set_client = {$CHARSET} ; 1506 - 1507 - CREATE TABLE `chatlog_event` ( 1508 - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 1509 - `epoch` int(10) unsigned NOT NULL, 1510 - `author` varchar(64) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1511 - `type` varchar(4) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1512 - `message` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL, 1513 - `loggedByPHID` varbinary(64) NOT NULL, 1514 - `channelID` int(10) unsigned NOT NULL, 1515 - PRIMARY KEY (`id`), 1516 - KEY `channel` (`epoch`) 1517 - ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; 1518 - 1519 1480 CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_conduit` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; 1520 1481 1521 1482 USE `{$NAMESPACE}_conduit`;
-30
src/__phutil_library_map__.php
··· 339 339 'CelerityResourcesOnDisk' => 'applications/celerity/resources/CelerityResourcesOnDisk.php', 340 340 'CeleritySpriteGenerator' => 'applications/celerity/CeleritySpriteGenerator.php', 341 341 'CelerityStaticResourceResponse' => 'applications/celerity/CelerityStaticResourceResponse.php', 342 - 'ChatLogConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogConduitAPIMethod.php', 343 - 'ChatLogQueryConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php', 344 - 'ChatLogRecordConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php', 345 342 'ConduitAPIDocumentationPage' => 'applications/conduit/data/ConduitAPIDocumentationPage.php', 346 343 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', 347 344 'ConduitAPIMethodTestCase' => 'applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php', ··· 2808 2805 'PhabricatorChartInterval' => 'applications/fact/chart/PhabricatorChartInterval.php', 2809 2806 'PhabricatorChartRenderingEngine' => 'applications/fact/engine/PhabricatorChartRenderingEngine.php', 2810 2807 'PhabricatorChartStackedAreaDataset' => 'applications/fact/chart/PhabricatorChartStackedAreaDataset.php', 2811 - 'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php', 2812 - 'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php', 2813 - 'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/PhabricatorChatLogChannelListController.php', 2814 - 'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/PhabricatorChatLogChannelLogController.php', 2815 - 'PhabricatorChatLogChannelQuery' => 'applications/chatlog/query/PhabricatorChatLogChannelQuery.php', 2816 - 'PhabricatorChatLogController' => 'applications/chatlog/controller/PhabricatorChatLogController.php', 2817 - 'PhabricatorChatLogDAO' => 'applications/chatlog/storage/PhabricatorChatLogDAO.php', 2818 - 'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php', 2819 - 'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php', 2820 2808 'PhabricatorCheckboxesEditField' => 'applications/transactions/editfield/PhabricatorCheckboxesEditField.php', 2821 2809 'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php', 2822 2810 'PhabricatorClassConfigType' => 'applications/config/type/PhabricatorClassConfigType.php', ··· 6339 6327 'CelerityResourcesOnDisk' => 'CelerityPhysicalResources', 6340 6328 'CeleritySpriteGenerator' => 'Phobject', 6341 6329 'CelerityStaticResourceResponse' => 'Phobject', 6342 - 'ChatLogConduitAPIMethod' => 'ConduitAPIMethod', 6343 - 'ChatLogQueryConduitAPIMethod' => 'ChatLogConduitAPIMethod', 6344 - 'ChatLogRecordConduitAPIMethod' => 'ChatLogConduitAPIMethod', 6345 6330 'ConduitAPIDocumentationPage' => 'Phobject', 6346 6331 'ConduitAPIMethod' => array( 6347 6332 'Phobject', ··· 9191 9176 'PhabricatorChartInterval' => 'Phobject', 9192 9177 'PhabricatorChartRenderingEngine' => 'Phobject', 9193 9178 'PhabricatorChartStackedAreaDataset' => 'PhabricatorChartDataset', 9194 - 'PhabricatorChatLogApplication' => 'PhabricatorApplication', 9195 - 'PhabricatorChatLogChannel' => array( 9196 - 'PhabricatorChatLogDAO', 9197 - 'PhabricatorPolicyInterface', 9198 - ), 9199 - 'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController', 9200 - 'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController', 9201 - 'PhabricatorChatLogChannelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 9202 - 'PhabricatorChatLogController' => 'PhabricatorController', 9203 - 'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO', 9204 - 'PhabricatorChatLogEvent' => array( 9205 - 'PhabricatorChatLogDAO', 9206 - 'PhabricatorPolicyInterface', 9207 - ), 9208 - 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 9209 9179 'PhabricatorCheckboxesEditField' => 'PhabricatorEditField', 9210 9180 'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine', 9211 9181 'PhabricatorClassConfigType' => 'PhabricatorTextConfigType',
-47
src/applications/chatlog/application/PhabricatorChatLogApplication.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogApplication extends PhabricatorApplication { 4 - 5 - public function getBaseURI() { 6 - return '/chatlog/'; 7 - } 8 - 9 - public function getName() { 10 - return pht('ChatLog'); 11 - } 12 - 13 - public function getShortDescription() { 14 - return pht('IRC Logs'); 15 - } 16 - 17 - public function getIcon() { 18 - return 'fa-coffee'; 19 - } 20 - 21 - public function isPrototype() { 22 - return true; 23 - } 24 - 25 - public function isDeprecated() { 26 - return true; 27 - } 28 - 29 - public function getTitleGlyph() { 30 - return "\xE0\xBC\x84"; 31 - } 32 - 33 - public function getApplicationGroup() { 34 - return self::GROUP_UTILITIES; 35 - } 36 - 37 - public function getRoutes() { 38 - return array( 39 - '/chatlog/' => array( 40 - '' => 'PhabricatorChatLogChannelListController', 41 - 'channel/(?P<channelID>[^/]+)/' 42 - => 'PhabricatorChatLogChannelLogController', 43 - ), 44 - ); 45 - } 46 - 47 - }
-9
src/applications/chatlog/conduit/ChatLogConduitAPIMethod.php
··· 1 - <?php 2 - 3 - abstract class ChatLogConduitAPIMethod extends ConduitAPIMethod { 4 - 5 - final public function getApplication() { 6 - return PhabricatorApplication::getByClass('PhabricatorChatLogApplication'); 7 - } 8 - 9 - }
-59
src/applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php
··· 1 - <?php 2 - 3 - final class ChatLogQueryConduitAPIMethod extends ChatLogConduitAPIMethod { 4 - 5 - public function getAPIMethodName() { 6 - return 'chatlog.query'; 7 - } 8 - 9 - public function getMethodStatus() { 10 - return self::METHOD_STATUS_UNSTABLE; 11 - } 12 - 13 - public function getMethodDescription() { 14 - return pht('Retrieve chatter.'); 15 - } 16 - 17 - protected function defineParamTypes() { 18 - return array( 19 - 'channels' => 'optional list<string>', 20 - 'limit' => 'optional int (default = 100)', 21 - ); 22 - } 23 - 24 - protected function defineReturnType() { 25 - return 'nonempty list<dict>'; 26 - } 27 - 28 - protected function execute(ConduitAPIRequest $request) { 29 - $query = new PhabricatorChatLogQuery(); 30 - 31 - $channel_ids = $request->getValue('channelIDs'); 32 - if ($channel_ids) { 33 - $query->withChannelIDs($channel_ids); 34 - } 35 - 36 - $limit = $request->getValue('limit'); 37 - if (!$limit) { 38 - $limit = 100; 39 - } 40 - $query->setLimit($limit); 41 - 42 - $logs = $query->execute(); 43 - 44 - $results = array(); 45 - foreach ($logs as $log) { 46 - $results[] = array( 47 - 'channelID' => $log->getChannelID(), 48 - 'epoch' => $log->getEpoch(), 49 - 'author' => $log->getAuthor(), 50 - 'type' => $log->getType(), 51 - 'message' => $log->getMessage(), 52 - 'loggedByPHID' => $log->getLoggedByPHID(), 53 - ); 54 - } 55 - 56 - return $results; 57 - } 58 - 59 - }
-72
src/applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php
··· 1 - <?php 2 - 3 - final class ChatLogRecordConduitAPIMethod extends ChatLogConduitAPIMethod { 4 - 5 - public function getAPIMethodName() { 6 - return 'chatlog.record'; 7 - } 8 - 9 - public function getMethodStatus() { 10 - return self::METHOD_STATUS_UNSTABLE; 11 - } 12 - 13 - public function getMethodDescription() { 14 - return pht('Record chatter.'); 15 - } 16 - 17 - protected function defineParamTypes() { 18 - return array( 19 - 'logs' => 'required list<dict>', 20 - ); 21 - } 22 - 23 - protected function defineReturnType() { 24 - return 'list<id>'; 25 - } 26 - 27 - protected function execute(ConduitAPIRequest $request) { 28 - $logs = $request->getValue('logs'); 29 - if (!is_array($logs)) { 30 - $logs = array(); 31 - } 32 - 33 - $template = new PhabricatorChatLogEvent(); 34 - $template->setLoggedByPHID($request->getUser()->getPHID()); 35 - 36 - $objs = array(); 37 - foreach ($logs as $log) { 38 - $channel_name = idx($log, 'channel'); 39 - $service_name = idx($log, 'serviceName'); 40 - $service_type = idx($log, 'serviceType'); 41 - 42 - $channel = id(new PhabricatorChatLogChannel())->loadOneWhere( 43 - 'channelName = %s AND serviceName = %s AND serviceType = %s', 44 - $channel_name, 45 - $service_name, 46 - $service_type); 47 - 48 - if (!$channel) { 49 - $channel = id(new PhabricatorChatLogChannel()) 50 - ->setChannelName($channel_name) 51 - ->setserviceName($service_name) 52 - ->setServiceType($service_type) 53 - ->setViewPolicy(PhabricatorPolicies::POLICY_USER) 54 - ->setEditPolicy(PhabricatorPolicies::POLICY_USER) 55 - ->save(); 56 - } 57 - 58 - $obj = clone $template; 59 - $obj->setChannelID($channel->getID()); 60 - $obj->setType(idx($log, 'type')); 61 - $obj->setAuthor(idx($log, 'author')); 62 - $obj->setEpoch(idx($log, 'epoch')); 63 - $obj->setMessage(idx($log, 'message')); 64 - $obj->save(); 65 - 66 - $objs[] = $obj; 67 - } 68 - 69 - return array_values(mpull($objs, 'getID')); 70 - } 71 - 72 - }
-41
src/applications/chatlog/controller/PhabricatorChatLogChannelListController.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogChannelListController 4 - extends PhabricatorChatLogController { 5 - 6 - public function shouldAllowPublic() { 7 - return true; 8 - } 9 - 10 - public function handleRequest(AphrontRequest $request) { 11 - $viewer = $request->getViewer(); 12 - 13 - $channels = id(new PhabricatorChatLogChannelQuery()) 14 - ->setViewer($viewer) 15 - ->execute(); 16 - 17 - $list = new PHUIObjectItemListView(); 18 - foreach ($channels as $channel) { 19 - $item = id(new PHUIObjectItemView()) 20 - ->setHeader($channel->getChannelName()) 21 - ->setHref('/chatlog/channel/'.$channel->getID().'/') 22 - ->addAttribute($channel->getServiceName()) 23 - ->addAttribute($channel->getServiceType()); 24 - $list->addItem($item); 25 - } 26 - 27 - $crumbs = $this 28 - ->buildApplicationCrumbs() 29 - ->addTextCrumb(pht('Channel List'), $this->getApplicationURI()); 30 - 31 - $box = id(new PHUIObjectBoxView()) 32 - ->setHeaderText('Channel List') 33 - ->setObjectList($list); 34 - 35 - return $this->newPage() 36 - ->setTitle(pht('Channel List')) 37 - ->setCrumbs($crumbs) 38 - ->appendChild($box); 39 - 40 - } 41 - }
-320
src/applications/chatlog/controller/PhabricatorChatLogChannelLogController.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogChannelLogController 4 - extends PhabricatorChatLogController { 5 - 6 - public function shouldAllowPublic() { 7 - return true; 8 - } 9 - 10 - public function handleRequest(AphrontRequest $request) { 11 - $viewer = $request->getViewer(); 12 - $id = $request->getURIData('channelID'); 13 - 14 - $uri = new PhutilURI($request->getPath()); 15 - 16 - $pager = new AphrontCursorPagerView(); 17 - $pager->setURI($uri); 18 - $pager->setPageSize(250); 19 - 20 - $query = id(new PhabricatorChatLogQuery()) 21 - ->setViewer($viewer) 22 - ->withChannelIDs(array($id)); 23 - 24 - $channel = id(new PhabricatorChatLogChannelQuery()) 25 - ->setViewer($viewer) 26 - ->withIDs(array($id)) 27 - ->executeOne(); 28 - 29 - if (!$channel) { 30 - return new Aphront404Response(); 31 - } 32 - 33 - list($after, $before, $map) = $this->getPagingParameters($request, $query); 34 - 35 - $pager->setAfterID($after); 36 - $pager->setBeforeID($before); 37 - 38 - $logs = $query->executeWithCursorPager($pager); 39 - 40 - // Show chat logs oldest-first. 41 - $logs = array_reverse($logs); 42 - 43 - 44 - // Divide all the logs into blocks, where a block is the same author saying 45 - // several things in a row. A block ends when another user speaks, or when 46 - // two minutes pass without the author speaking. 47 - 48 - $blocks = array(); 49 - $block = null; 50 - 51 - $last_author = null; 52 - $last_epoch = null; 53 - foreach ($logs as $log) { 54 - $this_author = $log->getAuthor(); 55 - $this_epoch = $log->getEpoch(); 56 - 57 - // Decide whether we should start a new block or not. 58 - $new_block = ($this_author !== $last_author) || 59 - ($this_epoch - (60 * 2) > $last_epoch); 60 - 61 - if ($new_block) { 62 - if ($block) { 63 - $blocks[] = $block; 64 - } 65 - $block = array( 66 - 'id' => $log->getID(), 67 - 'epoch' => $this_epoch, 68 - 'author' => $this_author, 69 - 'logs' => array($log), 70 - ); 71 - } else { 72 - $block['logs'][] = $log; 73 - } 74 - 75 - $last_author = $this_author; 76 - $last_epoch = $this_epoch; 77 - } 78 - if ($block) { 79 - $blocks[] = $block; 80 - } 81 - 82 - // Figure out CSS classes for the blocks. We alternate colors between 83 - // lines, and highlight the entire block which contains the target ID or 84 - // date, if applicable. 85 - 86 - foreach ($blocks as $key => $block) { 87 - $classes = array(); 88 - if ($key % 2) { 89 - $classes[] = 'alternate'; 90 - } 91 - $ids = mpull($block['logs'], 'getID', 'getID'); 92 - if (array_intersect_key($ids, $map)) { 93 - $classes[] = 'highlight'; 94 - } 95 - $blocks[$key]['class'] = $classes ? implode(' ', $classes) : null; 96 - } 97 - 98 - 99 - require_celerity_resource('phabricator-chatlog-css'); 100 - 101 - $out = array(); 102 - foreach ($blocks as $block) { 103 - $author = $block['author']; 104 - $author = id(new PhutilUTF8StringTruncator()) 105 - ->setMaximumGlyphs(18) 106 - ->truncateString($author); 107 - $author = phutil_tag('td', array('class' => 'author'), $author); 108 - 109 - $href = $uri->alter('at', $block['id']); 110 - $timestamp = $block['epoch']; 111 - $timestamp = phabricator_datetime($timestamp, $viewer); 112 - $timestamp = phutil_tag( 113 - 'a', 114 - array( 115 - 'href' => $href, 116 - 'class' => 'timestamp', 117 - ), 118 - $timestamp); 119 - 120 - $message = mpull($block['logs'], 'getMessage'); 121 - $message = implode("\n", $message); 122 - $message = phutil_tag( 123 - 'td', 124 - array( 125 - 'class' => 'message', 126 - ), 127 - array( 128 - $timestamp, 129 - $message, 130 - )); 131 - 132 - $out[] = phutil_tag( 133 - 'tr', 134 - array( 135 - 'class' => $block['class'], 136 - ), 137 - array( 138 - $author, 139 - $message, 140 - )); 141 - } 142 - 143 - $links = array(); 144 - 145 - $first_uri = $pager->getFirstPageURI(); 146 - if ($first_uri) { 147 - $links[] = phutil_tag( 148 - 'a', 149 - array( 150 - 'href' => $first_uri, 151 - ), 152 - "\xC2\xAB ".pht('Newest')); 153 - } 154 - 155 - $prev_uri = $pager->getPrevPageURI(); 156 - if ($prev_uri) { 157 - $links[] = phutil_tag( 158 - 'a', 159 - array( 160 - 'href' => $prev_uri, 161 - ), 162 - "\xE2\x80\xB9 ".pht('Newer')); 163 - } 164 - 165 - $next_uri = $pager->getNextPageURI(); 166 - if ($next_uri) { 167 - $links[] = phutil_tag( 168 - 'a', 169 - array( 170 - 'href' => $next_uri, 171 - ), 172 - pht('Older')." \xE2\x80\xBA"); 173 - } 174 - 175 - $pager_bottom = phutil_tag( 176 - 'div', 177 - array('class' => 'phabricator-chat-log-pager-bottom'), 178 - $links); 179 - 180 - $crumbs = $this 181 - ->buildApplicationCrumbs() 182 - ->addTextCrumb($channel->getChannelName(), $uri); 183 - 184 - $form = id(new AphrontFormView()) 185 - ->setUser($viewer) 186 - ->setMethod('GET') 187 - ->setAction($uri) 188 - ->appendChild( 189 - id(new AphrontFormTextControl()) 190 - ->setLabel(pht('Date')) 191 - ->setName('date') 192 - ->setValue($request->getStr('date'))) 193 - ->appendChild( 194 - id(new AphrontFormSubmitControl()) 195 - ->setValue(pht('Jump'))); 196 - 197 - $table = phutil_tag( 198 - 'table', 199 - array( 200 - 'class' => 'phabricator-chat-log', 201 - ), 202 - $out); 203 - 204 - $log = phutil_tag( 205 - 'div', 206 - array( 207 - 'class' => 'phabricator-chat-log-panel', 208 - ), 209 - $table); 210 - 211 - $jump_link = id(new PHUIButtonView()) 212 - ->setTag('a') 213 - ->setHref('#latest') 214 - ->setText(pht('Jump to Bottom')) 215 - ->setIcon('fa-arrow-circle-down'); 216 - 217 - $jump_target = phutil_tag( 218 - 'div', 219 - array( 220 - 'id' => 'latest', 221 - )); 222 - 223 - $content = phutil_tag( 224 - 'div', 225 - array( 226 - 'class' => 'phabricator-chat-log-wrap', 227 - ), 228 - array( 229 - $log, 230 - $jump_target, 231 - $pager_bottom, 232 - )); 233 - 234 - $header = id(new PHUIHeaderView()) 235 - ->setHeader($channel->getChannelName()) 236 - ->setSubHeader($channel->getServiceName()) 237 - ->addActionLink($jump_link); 238 - 239 - $box = id(new PHUIObjectBoxView()) 240 - ->setHeader($header) 241 - ->setCollapsed(true) 242 - ->appendChild($content); 243 - 244 - $box->setShowHide( 245 - pht('Search Dates'), 246 - pht('Hide Dates'), 247 - $form, 248 - '#'); 249 - 250 - return $this->newPage() 251 - ->setTitle(pht('Channel Log')) 252 - ->setCrumbs($crumbs) 253 - ->appendChild($box); 254 - 255 - } 256 - 257 - /** 258 - * From request parameters, figure out where we should jump to in the log. 259 - * We jump to either a date or log ID, but load a few lines of context before 260 - * it so the user can see the nearby conversation. 261 - */ 262 - private function getPagingParameters( 263 - AphrontRequest $request, 264 - PhabricatorChatLogQuery $query) { 265 - 266 - $viewer = $request->getViewer(); 267 - 268 - $at_id = $request->getInt('at'); 269 - $at_date = $request->getStr('date'); 270 - 271 - $context_log = null; 272 - $map = array(); 273 - 274 - $query = clone $query; 275 - $query->setLimit(8); 276 - 277 - if ($at_id) { 278 - // Jump to the log in question, and load a few lines of context before 279 - // it. 280 - $context_logs = $query 281 - ->setAfterID($at_id) 282 - ->execute(); 283 - 284 - $context_log = last($context_logs); 285 - 286 - $map = array( 287 - $at_id => true, 288 - ); 289 - 290 - } else if ($at_date) { 291 - $timestamp = PhabricatorTime::parseLocalTime($at_date, $viewer); 292 - 293 - if ($timestamp) { 294 - $context_logs = $query 295 - ->withMaximumEpoch($timestamp) 296 - ->execute(); 297 - 298 - $context_log = last($context_logs); 299 - 300 - $target_log = head($context_logs); 301 - if ($target_log) { 302 - $map = array( 303 - $target_log->getID() => true, 304 - ); 305 - } 306 - } 307 - } 308 - 309 - if ($context_log) { 310 - $after = null; 311 - $before = $context_log->getID() - 1; 312 - } else { 313 - $after = $request->getInt('after'); 314 - $before = $request->getInt('before'); 315 - } 316 - 317 - return array($after, $before, $map); 318 - } 319 - 320 - }
-3
src/applications/chatlog/controller/PhabricatorChatLogController.php
··· 1 - <?php 2 - 3 - abstract class PhabricatorChatLogController extends PhabricatorController {}
-63
src/applications/chatlog/query/PhabricatorChatLogChannelQuery.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogChannelQuery 4 - extends PhabricatorCursorPagedPolicyAwareQuery { 5 - 6 - private $channels; 7 - private $channelIDs; 8 - 9 - public function withChannelNames(array $channels) { 10 - $this->channels = $channels; 11 - return $this; 12 - } 13 - 14 - public function withIDs(array $channel_ids) { 15 - $this->channelIDs = $channel_ids; 16 - return $this; 17 - } 18 - 19 - protected function loadPage() { 20 - $table = new PhabricatorChatLogChannel(); 21 - $conn_r = $table->establishConnection('r'); 22 - 23 - $data = queryfx_all( 24 - $conn_r, 25 - 'SELECT * FROM %T c %Q %Q %Q', 26 - $table->getTableName(), 27 - $this->buildWhereClause($conn_r), 28 - $this->buildOrderClause($conn_r), 29 - $this->buildLimitClause($conn_r)); 30 - 31 - $logs = $table->loadAllFromArray($data); 32 - 33 - return $logs; 34 - } 35 - 36 - protected function buildWhereClause(AphrontDatabaseConnection $conn) { 37 - $where = array(); 38 - 39 - $where[] = $this->buildPagingClause($conn); 40 - 41 - if ($this->channelIDs) { 42 - $where[] = qsprintf( 43 - $conn, 44 - 'id IN (%Ld)', 45 - $this->channelIDs); 46 - 47 - } 48 - 49 - if ($this->channels) { 50 - $where[] = qsprintf( 51 - $conn, 52 - 'channelName IN (%Ls)', 53 - $this->channels); 54 - } 55 - 56 - return $this->formatWhereClause($conn, $where); 57 - } 58 - 59 - public function getQueryApplicationClass() { 60 - return 'PhabricatorChatLogApplication'; 61 - } 62 - 63 - }
-84
src/applications/chatlog/query/PhabricatorChatLogQuery.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogQuery 4 - extends PhabricatorCursorPagedPolicyAwareQuery { 5 - 6 - private $channelIDs; 7 - private $maximumEpoch; 8 - 9 - public function withChannelIDs(array $channel_ids) { 10 - $this->channelIDs = $channel_ids; 11 - return $this; 12 - } 13 - 14 - public function withMaximumEpoch($epoch) { 15 - $this->maximumEpoch = $epoch; 16 - return $this; 17 - } 18 - 19 - protected function loadPage() { 20 - $table = new PhabricatorChatLogEvent(); 21 - $conn_r = $table->establishConnection('r'); 22 - 23 - $data = queryfx_all( 24 - $conn_r, 25 - 'SELECT * FROM %T e %Q %Q %Q', 26 - $table->getTableName(), 27 - $this->buildWhereClause($conn_r), 28 - $this->buildOrderClause($conn_r), 29 - $this->buildLimitClause($conn_r)); 30 - 31 - $logs = $table->loadAllFromArray($data); 32 - 33 - return $logs; 34 - } 35 - 36 - protected function willFilterPage(array $events) { 37 - $channel_ids = mpull($events, 'getChannelID', 'getChannelID'); 38 - 39 - $channels = id(new PhabricatorChatLogChannelQuery()) 40 - ->setViewer($this->getViewer()) 41 - ->withIDs($channel_ids) 42 - ->execute(); 43 - $channels = mpull($channels, null, 'getID'); 44 - 45 - foreach ($events as $key => $event) { 46 - $channel = idx($channels, $event->getChannelID()); 47 - if (!$channel) { 48 - unset($events[$key]); 49 - continue; 50 - } 51 - 52 - $event->attachChannel($channel); 53 - } 54 - 55 - return $events; 56 - } 57 - 58 - protected function buildWhereClause(AphrontDatabaseConnection $conn) { 59 - $where = array(); 60 - 61 - $where[] = $this->buildPagingClause($conn); 62 - 63 - if ($this->maximumEpoch !== null) { 64 - $where[] = qsprintf( 65 - $conn, 66 - 'epoch <= %d', 67 - $this->maximumEpoch); 68 - } 69 - 70 - if ($this->channelIDs !== null) { 71 - $where[] = qsprintf( 72 - $conn, 73 - 'channelID IN (%Ld)', 74 - $this->channelIDs); 75 - } 76 - 77 - return $this->formatWhereClause($conn, $where); 78 - } 79 - 80 - public function getQueryApplicationClass() { 81 - return 'PhabricatorChatLogApplication'; 82 - } 83 - 84 - }
-51
src/applications/chatlog/storage/PhabricatorChatLogChannel.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogChannel 4 - extends PhabricatorChatLogDAO 5 - implements PhabricatorPolicyInterface { 6 - 7 - protected $serviceName; 8 - protected $serviceType; 9 - protected $channelName; 10 - protected $viewPolicy; 11 - protected $editPolicy; 12 - 13 - protected function getConfiguration() { 14 - return array( 15 - self::CONFIG_COLUMN_SCHEMA => array( 16 - 'serviceName' => 'text64', 17 - 'serviceType' => 'text32', 18 - 'channelName' => 'text64', 19 - ), 20 - self::CONFIG_KEY_SCHEMA => array( 21 - 'key_channel' => array( 22 - 'columns' => array('channelName', 'serviceType', 'serviceName'), 23 - 'unique' => true, 24 - ), 25 - ), 26 - ) + parent::getConfiguration(); 27 - } 28 - 29 - public function getCapabilities() { 30 - return array( 31 - PhabricatorPolicyCapability::CAN_VIEW, 32 - PhabricatorPolicyCapability::CAN_EDIT, 33 - ); 34 - } 35 - 36 - public function getPolicy($capability) { 37 - switch ($capability) { 38 - case PhabricatorPolicyCapability::CAN_VIEW: 39 - return $this->viewPolicy; 40 - break; 41 - case PhabricatorPolicyCapability::CAN_EDIT: 42 - return $this->editPolicy; 43 - break; 44 - } 45 - } 46 - 47 - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 48 - return false; 49 - } 50 - 51 - }
-9
src/applications/chatlog/storage/PhabricatorChatLogDAO.php
··· 1 - <?php 2 - 3 - abstract class PhabricatorChatLogDAO extends PhabricatorLiskDAO { 4 - 5 - public function getApplicationName() { 6 - return 'chatlog'; 7 - } 8 - 9 - }
-59
src/applications/chatlog/storage/PhabricatorChatLogEvent.php
··· 1 - <?php 2 - 3 - final class PhabricatorChatLogEvent 4 - extends PhabricatorChatLogDAO 5 - implements PhabricatorPolicyInterface { 6 - 7 - protected $channelID; 8 - protected $epoch; 9 - protected $author; 10 - protected $type; 11 - protected $message; 12 - protected $loggedByPHID; 13 - 14 - private $channel = self::ATTACHABLE; 15 - 16 - protected function getConfiguration() { 17 - return array( 18 - self::CONFIG_TIMESTAMPS => false, 19 - self::CONFIG_COLUMN_SCHEMA => array( 20 - 'author' => 'text64', 21 - 'type' => 'text4', 22 - 'message' => 'text', 23 - ), 24 - self::CONFIG_KEY_SCHEMA => array( 25 - 'channel' => array( 26 - 'columns' => array('epoch'), 27 - ), 28 - ), 29 - ) + parent::getConfiguration(); 30 - } 31 - 32 - public function attachChannel(PhabricatorChatLogChannel $channel) { 33 - $this->channel = $channel; 34 - return $this; 35 - } 36 - 37 - public function getChannel() { 38 - return $this->assertAttached($this->channel); 39 - } 40 - 41 - 42 - /* -( PhabricatorPolicyInterface )----------------------------------------- */ 43 - 44 - 45 - public function getCapabilities() { 46 - return array( 47 - PhabricatorPolicyCapability::CAN_VIEW, 48 - ); 49 - } 50 - 51 - public function getPolicy($capability) { 52 - return $this->getChannel()->getPolicy($capability); 53 - } 54 - 55 - public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 56 - return $this->getChannel()->hasAutomaticCapability($capability, $viewer); 57 - } 58 - 59 - }
-4
src/docs/book/phorge.book
··· 57 57 "name": "Celerity", 58 58 "include": "(^src/applications/celerity/)" 59 59 }, 60 - "chatlog": { 61 - "name": "Chatlog", 62 - "include": "(^src/applications/chatlog/)" 63 - }, 64 60 "conduit": { 65 61 "name": "Conduit", 66 62 "include": "(^src/applications/conduit/)"
-1
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 50 50 'after' => array( /* First Patch */ ), 51 51 ), 52 52 'db.calendar' => array(), 53 - 'db.chatlog' => array(), 54 53 'db.conduit' => array(), 55 54 'db.countdown' => array(), 56 55 'db.daemon' => array(),
-81
webroot/rsrc/css/application/chatlog/chatlog.css
··· 1 - /** 2 - * @provides phabricator-chatlog-css 3 - */ 4 - 5 - .device-phone .phabricator-chat-log-wrap { 6 - padding: 0; 7 - } 8 - 9 - .phabricator-chat-log-pager-bottom { 10 - padding: 8px 4px 16px; 11 - font-weight: bold; 12 - float: right; 13 - } 14 - 15 - .phabricator-chat-log-pager-bottom a { 16 - padding: 2px 3px; 17 - } 18 - 19 - .phabricator-chat-log-panel { 20 - clear: both; 21 - } 22 - 23 - .phabricator-chat-log { 24 - width: 100%; 25 - } 26 - 27 - .phabricator-chat-log td { 28 - padding: 8px; 29 - line-height: 18px; 30 - } 31 - 32 - .phabricator-chat-log tr { 33 - background: #fff; 34 - } 35 - 36 - .phabricator-chat-log tr td.author { 37 - background: {$greybackground}; 38 - } 39 - 40 - .phabricator-chat-log tr.alternate { 41 - border-top: 1px solid {$thinblueborder}; 42 - border-bottom: 1px solid {$thinblueborder}; 43 - } 44 - 45 - .phabricator-chat-log tr.alternate td.author { 46 - background: {$lightgreybackground}; 47 - } 48 - 49 - .phabricator-chat-log tr.highlight td { 50 - background: {$lightyellow}; 51 - } 52 - 53 - .phabricator-chat-log td.timestamp { 54 - white-space: nowrap; 55 - text-align: right; 56 - width: 12em; 57 - } 58 - 59 - .phabricator-chat-log td.message .timestamp { 60 - color: {$bluetext}; 61 - font-size: {$smallestfontsize}; 62 - float: right; 63 - margin-left: 5px; 64 - } 65 - 66 - .phabricator-chat-log td.author { 67 - white-space: nowrap; 68 - text-align: right; 69 - font-weight: bold; 70 - width: 140px; 71 - color: {$darkbluetext}; 72 - } 73 - 74 - .device-phone .phabricator-chat-log td.author { 75 - width: 80px; 76 - } 77 - 78 - .phabricator-chat-log td.message { 79 - white-space: pre-wrap; 80 - word-break: break-word; 81 - }