1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 08:42:41 +01:00

Add a basic chatlog

Summary:
This is pretty simple and unpolished, but it's getting pretty big and it seems
like a reasonable starting point.

  - Log chat in various "channels".
  - Conduit record and query methods.
  - IRCBot integration for IRC logging

Major TODO:

  - Web UI is really unpolished and has no search, paging, anchor-linking, etc.
Basically all presentation stuff, though.
  - I think the bot should have a map of channels to log with channel aliases?
  - The "channels" should probably be in a separate table.
  - The "authors" should probably be correlated to Phabricator accounts somehow,
where possible.

Test Plan: Used phabotlocal to log #phabricator.

Reviewers: kdeggelman, btrahan, Koolvin

Reviewed By: btrahan

CC: aran, epriestley

Maniphest Tasks: T837

Differential Revision: https://secure.phabricator.com/D1625
This commit is contained in:
epriestley 2012-02-17 10:21:38 -08:00
parent 50363695bb
commit 7200040479
35 changed files with 911 additions and 12 deletions

View file

@ -8,6 +8,7 @@
"handlers" : [ "handlers" : [
"PhabricatorIRCProtocolHandler", "PhabricatorIRCProtocolHandler",
"PhabricatorIRCObjectNameHandler", "PhabricatorIRCObjectNameHandler",
"PhabricatorIRCLogHandler",
"PhabricatorIRCDifferentialNotificationHandler" "PhabricatorIRCDifferentialNotificationHandler"
], ],

View file

@ -0,0 +1,11 @@
CREATE DATABASE IF NOT EXISTS phabricator_chatlog;
CREATE TABLE phabricator_chatlog.chatlog_event (
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
channel VARCHAR(64) BINARY NOT NULL,
epoch INT UNSIGNED NOT NULL,
author VARCHAR(64) BINARY NOT NULL,
type VARCHAR(4) NOT NULL,
message LONGBLOB NOT NULL,
loggedByPHID VARCHAR(64) BINARY NOT NULL,
KEY (channel, epoch)
);

View file

@ -1330,6 +1330,15 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/herald/PathTypeahead.js', 'disk' => '/rsrc/js/application/herald/PathTypeahead.js',
), ),
'phabricator-chatlog-css' =>
array(
'uri' => '/res/a5aa9eef/rsrc/css/application/chatlog/chatlog.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/chatlog/chatlog.css',
),
'phabricator-content-source-view-css' => 'phabricator-content-source-view-css' =>
array( array(
'uri' => '/res/8c738a93/rsrc/css/application/contentsource/content-source-view.css', 'uri' => '/res/8c738a93/rsrc/css/application/contentsource/content-source-view.css',
@ -1508,6 +1517,17 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/css/core/remarkup.css', 'disk' => '/rsrc/css/core/remarkup.css',
), ),
0 =>
array(
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-uri',
1 => 'javelin-php-serializer',
),
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
),
'phabricator-search-results-css' => 'phabricator-search-results-css' =>
array( array(
'uri' => '/res/f8a86e27/rsrc/css/application/search/search-results.css', 'uri' => '/res/f8a86e27/rsrc/css/application/search/search-results.css',
@ -1529,17 +1549,6 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/core/ShapedRequest.js', 'disk' => '/rsrc/js/application/core/ShapedRequest.js',
), ),
0 =>
array(
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-uri',
1 => 'javelin-php-serializer',
),
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
),
'phabricator-slowvote-css' => 'phabricator-slowvote-css' =>
array( array(
'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css', 'uri' => '/res/94d20443/rsrc/css/application/slowvote/slowvote.css',

View file

@ -104,6 +104,9 @@ phutil_register_library_map(array(
'ConduitAPIResponse' => 'applications/conduit/protocol/response', 'ConduitAPIResponse' => 'applications/conduit/protocol/response',
'ConduitAPI_arcanist_Method' => 'applications/conduit/method/arcanist/base', 'ConduitAPI_arcanist_Method' => 'applications/conduit/method/arcanist/base',
'ConduitAPI_arcanist_projectinfo_Method' => 'applications/conduit/method/arcanist/projectinfo', 'ConduitAPI_arcanist_projectinfo_Method' => 'applications/conduit/method/arcanist/projectinfo',
'ConduitAPI_chatlog_Method' => 'applications/conduit/method/chatlog/base',
'ConduitAPI_chatlog_query_Method' => 'applications/conduit/method/chatlog/query',
'ConduitAPI_chatlog_record_Method' => 'applications/conduit/method/chatlog/record',
'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/conduit/getcertificate', 'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/conduit/getcertificate',
'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping', 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping',
@ -437,6 +440,14 @@ phutil_register_library_map(array(
'PhabricatorAuthController' => 'applications/auth/controller/base', 'PhabricatorAuthController' => 'applications/auth/controller/base',
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse', 'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse',
'PhabricatorCalendarController' => 'applications/calendar/controller/base', 'PhabricatorCalendarController' => 'applications/calendar/controller/base',
'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/channellist',
'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/channellog',
'PhabricatorChatLogConstants' => 'applications/chatlog/constants/base',
'PhabricatorChatLogController' => 'applications/chatlog/controller/base',
'PhabricatorChatLogDAO' => 'applications/chatlog/storage/base',
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/event',
'PhabricatorChatLogEventType' => 'applications/chatlog/constants/eventtype',
'PhabricatorChatLogQuery' => 'applications/chatlog/query',
'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token',
'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
@ -544,6 +555,7 @@ phutil_register_library_map(array(
'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot', 'PhabricatorIRCBot' => 'infrastructure/daemon/irc/bot',
'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/differentialnotification', 'PhabricatorIRCDifferentialNotificationHandler' => 'infrastructure/daemon/irc/handler/differentialnotification',
'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base', 'PhabricatorIRCHandler' => 'infrastructure/daemon/irc/handler/base',
'PhabricatorIRCLogHandler' => 'infrastructure/daemon/irc/handler/log',
'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message', 'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname', 'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol', 'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
@ -919,6 +931,9 @@ phutil_register_library_map(array(
'CelerityResourceGraph' => 'AbstractDirectedGraph', 'CelerityResourceGraph' => 'AbstractDirectedGraph',
'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod', 'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod',
'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method', 'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method',
'ConduitAPI_chatlog_Method' => 'ConduitAPIMethod',
'ConduitAPI_chatlog_query_Method' => 'ConduitAPI_chatlog_Method',
'ConduitAPI_chatlog_record_Method' => 'ConduitAPI_chatlog_Method',
'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod',
'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod',
@ -1177,6 +1192,12 @@ phutil_register_library_map(array(
'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController',
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController', 'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
'PhabricatorCalendarController' => 'PhabricatorController', 'PhabricatorCalendarController' => 'PhabricatorController',
'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController',
'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController',
'PhabricatorChatLogController' => 'PhabricatorController',
'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO',
'PhabricatorChatLogEvent' => 'PhabricatorChatLogDAO',
'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants',
'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
@ -1267,6 +1288,7 @@ phutil_register_library_map(array(
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
'PhabricatorIRCBot' => 'PhabricatorDaemon', 'PhabricatorIRCBot' => 'PhabricatorDaemon',
'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCDifferentialNotificationHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler', 'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase', 'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase',

View file

@ -401,6 +401,13 @@ class AphrontDefaultApplicationConfiguration
), ),
'lease/$' => 'DrydockLeaseListController', 'lease/$' => 'DrydockLeaseListController',
), ),
'/chatlog/' => array(
'$' =>
'PhabricatorChatLogChannelListController',
'channel/(?P<channel>[^/]+)/$' =>
'PhabricatorChatLogChannelLogController',
),
); );
} }

View file

@ -0,0 +1,21 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class PhabricatorChatLogConstants {
}

View file

@ -0,0 +1,10 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_source('PhabricatorChatLogConstants.php');

View file

@ -0,0 +1,24 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorChatLogEventType
extends PhabricatorChatLogConstants {
const TYPE_MESSAGE = 'mesg';
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/constants/base');
phutil_require_source('PhabricatorChatLogEventType.php');

View file

@ -0,0 +1,34 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class PhabricatorChatLogController extends PhabricatorController {
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName('Chat Log');
$page->setBaseURI('/chatlog/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph('#');
$page->appendChild($view);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
}

View file

@ -0,0 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/webpage');
phutil_require_module('phabricator', 'applications/base/controller/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorChatLogController.php');

View file

@ -0,0 +1,62 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorChatLogChannelListController
extends PhabricatorChatLogController {
public function processRequest() {
$table = new PhabricatorChatLogEvent();
$channels = queryfx_all(
$table->establishConnection('r'),
'SELECT DISTINCT channel FROM %T',
$table->getTableName());
$rows = array();
foreach ($channels as $channel) {
$name = $channel['channel'];
$rows[] = array(
phutil_render_tag(
'a',
array(
'href' => '/chatlog/channel/'.phutil_escape_uri($name).'/',
),
phutil_escape_html($name)));
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'Channel',
));
$table->setColumnClasses(
array(
'pri wide',
));
$panel = new AphrontPanelView();
$panel->appendChild($table);
return $this->buildStandardPageResponse(
$panel,
array(
'title' => 'Channel List',
));
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/controller/base');
phutil_require_module('phabricator', 'applications/chatlog/storage/event');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phutil', 'markup');
phutil_require_source('PhabricatorChatLogChannelListController.php');

View file

@ -0,0 +1,86 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorChatLogChannelLogController
extends PhabricatorChatLogController {
private $channel;
public function willProcessRequest(array $data) {
$this->channel = $data['channel'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$query = new PhabricatorChatLogQuery();
$query->withChannels(array($this->channel));
$query->setLimit(1000);
$logs = $query->execute();
require_celerity_resource('phabricator-chatlog-css');
$last_author = null;
$last_epoch = null;
$row_idx = 0;
$row_colors = array(
'normal',
'alternate',
);
$out = array();
$out[] = '<table class="phabricator-chat-log">';
foreach ($logs as $log) {
$this_author = $log->getAuthor();
$this_epoch = $log->getEpoch();
if (($this_author !== $last_author) ||
($this_epoch - (60 * 5) > $last_epoch)) {
++$row_idx;
$out[] = '<tr class="initial '.$row_colors[$row_idx % 2].'">';
$out[] = '<td class="timestamp">'.
phabricator_datetime($log->getEpoch(), $user).'</td>';
$author = $log->getAuthor();
$author = phutil_utf8_shorten($author, 18);
$out[] = '<td class="author">'.
phutil_escape_html($author).'</td>';
} else {
$out[] = '<tr class="'.$row_colors[$row_idx % 2].'">';
$out[] = '<td class="similar" colspan="2"></td>';
}
$out[] = '<td class="message">'.
phutil_escape_html($log->getMessage()).'</td>';
$out[] = '</tr>';
$last_author = $this_author;
$last_epoch = $this_epoch;
}
$out[] = '</table>';
return $this->buildStandardPageResponse(
implode("\n", $out),
array(
'title' => 'Channel Log',
));
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/controller/base');
phutil_require_module('phabricator', 'applications/chatlog/query');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorChatLogChannelLogController.php');

View file

@ -0,0 +1,80 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorChatLogQuery {
private $channels;
private $limit;
public function withChannels(array $channels) {
$this->channels = $channels;
return $this;
}
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
public function execute() {
$table = new PhabricatorChatLogEvent();
$conn_r = $table->establishConnection('r');
$where_clause = $this->buildWhereClause($conn_r);
$limit_clause = '';
if ($this->limit) {
$limit_clause = qsprintf(
$conn_r,
'LIMIT %d',
$this->limit);
}
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T e %Q ORDER BY epoch ASC %Q',
$table->getTableName(),
$where_clause,
$limit_clause);
$logs = $table->loadAllFromArray($data);
return $logs;
}
private function buildWhereClause($conn_r) {
$where = array();
if ($this->channels) {
$where[] = qsprintf(
$conn_r,
'channel IN (%Ls)',
$this->channels);
}
if ($where) {
$where = 'WHERE ('.implode(') AND (', $where).')';
} else {
$where = '';
}
return $where;
}
}

View file

@ -0,0 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/storage/event');
phutil_require_module('phabricator', 'storage/qsprintf');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_source('PhabricatorChatLogQuery.php');

View file

@ -0,0 +1,25 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class PhabricatorChatLogDAO extends PhabricatorLiskDAO {
public function getApplicationName() {
return 'chatlog';
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/base/storage/lisk');
phutil_require_source('PhabricatorChatLogDAO.php');

View file

@ -0,0 +1,34 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorChatLogEvent extends PhabricatorChatLogDAO {
protected $channel;
protected $epoch;
protected $author;
protected $type;
protected $message;
protected $loggedByPHID;
public function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
) + parent::getConfiguration();
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/storage/base');
phutil_require_source('PhabricatorChatLogEvent.php');

View file

@ -0,0 +1,24 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group conduit
*/
abstract class ConduitAPI_chatlog_Method extends ConduitAPIMethod {
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/conduit/method/base');
phutil_require_source('ConduitAPI_chatlog_Method.php');

View file

@ -0,0 +1,76 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group conduit
*/
final class ConduitAPI_chatlog_query_Method
extends ConduitAPI_chatlog_Method {
public function getMethodDescription() {
return "(Unstable!) Retrieve chatter.";
}
public function defineParamTypes() {
return array(
'channels' => 'optional list<string>',
'limit' => 'optional int (default = 100)',
);
}
public function defineReturnType() {
return 'nonempty list<dict>';
}
public function defineErrorTypes() {
return array();
}
protected function execute(ConduitAPIRequest $request) {
$query = new PhabricatorChatLogQuery();
$channels = $request->getValue('channels');
if ($channels) {
$query->withChannels($channels);
}
$limit = $request->getValue('limit');
if (!$limit) {
$limit = 100;
}
$query->setLimit($limit);
$logs = $query->execute();
$results = array();
foreach ($logs as $log) {
$results[] = array(
'channel' => $log->getChannel(),
'epoch' => $log->getEpoch(),
'author' => $log->getAuthor(),
'type' => $log->getType(),
'message' => $log->getMessage(),
'loggedByPHID' => $log->getLoggedByPHID(),
);
}
return $results;
}
}

View file

@ -0,0 +1,13 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/query');
phutil_require_module('phabricator', 'applications/conduit/method/chatlog/base');
phutil_require_source('ConduitAPI_chatlog_query_Method.php');

View file

@ -0,0 +1,69 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group conduit
*/
final class ConduitAPI_chatlog_record_Method
extends ConduitAPI_chatlog_Method {
public function getMethodDescription() {
return "(Unstable!) Record chatter.";
}
public function defineParamTypes() {
return array(
'logs' => 'required list<dict>',
);
}
public function defineReturnType() {
return 'list<id>';
}
public function defineErrorTypes() {
return array(
);
}
protected function execute(ConduitAPIRequest $request) {
$logs = $request->getValue('logs');
if (!is_array($logs)) {
$logs = array();
}
$template = new PhabricatorChatLogEvent();
$template->setLoggedByPHID($request->getUser()->getPHID());
$objs = array();
foreach ($logs as $log) {
$obj = clone $template;
$obj->setChannel(idx($log, 'channel'));
$obj->setType(idx($log, 'type'));
$obj->setAuthor(idx($log, 'author'));
$obj->setEpoch(idx($log, 'epoch'));
$obj->setMessage(idx($log, 'message'));
$obj->save();
$objs[] = $obj;
}
return array_values(mpull($objs, 'getID'));
}
}

View file

@ -0,0 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/chatlog/storage/event');
phutil_require_module('phabricator', 'applications/conduit/method/chatlog/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('ConduitAPI_chatlog_record_Method.php');

View file

@ -50,6 +50,8 @@ the IRC bot. These are the default handlers available:
- @{class:PhabricatorIRCDifferentialNotificationHandler} This handler posts - @{class:PhabricatorIRCDifferentialNotificationHandler} This handler posts
notifications about changes to revisions to IRC to the channels listed in notifications about changes to revisions to IRC to the channels listed in
##notification.channels##. ##notification.channels##.
- @{class:PhabricatorIRCLogHandler} This handler records chatlogs which can
be browsed in the Phabricator web interface.
You can also write your own handlers, by extending You can also write your own handlers, by extending
@{class:PhabricatorIRCHandler}. @{class:PhabricatorIRCHandler}.

View file

@ -44,7 +44,9 @@ abstract class PhabricatorIRCHandler {
} }
final protected function getURI($path) { final protected function getURI($path) {
return $this->bot->getConfig('conduit.uri').$path; $base_uri = new PhutilURI($this->bot->getConfig('conduit.uri'));
$base_uri->setPath($path);
return (string)$base_uri;
} }
final protected function isChannelName($name) { final protected function isChannelName($name) {

View file

@ -6,5 +6,7 @@
phutil_require_module('phutil', 'parser/uri');
phutil_require_source('PhabricatorIRCHandler.php'); phutil_require_source('PhabricatorIRCHandler.php');

View file

@ -0,0 +1,94 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Looks for Dxxxx, Txxxx and links to them.
*
* @group irc
*/
final class PhabricatorIRCLogHandler extends PhabricatorIRCHandler {
private $futures = array();
public function receiveMessage(PhabricatorIRCMessage $message) {
switch ($message->getCommand()) {
case 'PRIVMSG':
$reply_to = $message->getReplyTo();
if (!$reply_to) {
break;
}
if (!$this->isChannelName($reply_to)) {
// Don't log private messages, although maybe we should for debugging?
break;
}
$logs = array(
array(
'channel' => $reply_to,
'type' => 'mesg',
'epoch' => time(),
'author' => $message->getSenderNickname(),
'message' => $message->getMessageText(),
),
);
$this->futures[] = $this->getConduit()->callMethod(
'chatlog.record',
array(
'logs' => $logs,
));
$prompts = array(
'/where is the (chat)?log\?/i',
'/where am i\?/i',
'/what year is (this|it)\?/i',
);
$tell = false;
foreach ($prompts as $prompt) {
if (preg_match($prompt, $message->getMessageText())) {
$tell = true;
break;
}
}
if ($tell) {
$response = $this->getURI(
'/chatlog/channel/'.phutil_escape_uri($reply_to).'/');
$this->write('PRIVMSG', "{$reply_to} :{$response}");
}
break;
}
}
public function runBackgroundTasks() {
foreach ($this->futures as $key => $future) {
try {
if ($future->isReady()) {
unset($this->futures[$key]);
}
} catch (Exception $ex) {
unset($this->futures[$key]);
phlog($ex);
}
}
}
}

View file

@ -0,0 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'infrastructure/daemon/irc/handler/base');
phutil_require_module('phutil', 'error');
phutil_require_module('phutil', 'markup');
phutil_require_source('PhabricatorIRCLogHandler.php');

View file

@ -57,6 +57,13 @@ final class PhabricatorIRCMessage {
return null; return null;
} }
public function getSenderNickname() {
$nick = $this->getRawSender();
$nick = ltrim($nick, ':');
$nick = head(explode('!', $nick));
return $nick;
}
public function getTarget() { public function getTarget() {
switch ($this->getCommand()) { switch ($this->getCommand()) {
case 'PRIVMSG': case 'PRIVMSG':

View file

@ -6,5 +6,7 @@
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorIRCMessage.php'); phutil_require_source('PhabricatorIRCMessage.php');

View file

@ -0,0 +1,39 @@
/**
* @provides phabricator-chatlog-css
*/
.phabricator-chat-log {
margin: 1em 2em;
font-size: 12px;
}
.phabricator-chat-log tr.initial {
border-top: 4px solid white;
}
.phabricator-chat-log tr.normal {
background: #e9e9e9;
}
.phabricator-chat-log tr.alternate {
background: #f6f6f6;
}
.phabricator-chat-log td {
padding: 2px 4px;
}
.phabricator-chat-log td.timestamp {
white-space: nowrap;
color: #666666;
}
.phabricator-chat-log td.author {
white-space: nowrap;
text-align: right;
font-weight: bold;
}
.phabricator-chat-log td.message {
width: 100%;
}