slash commands: Add /ping command (via zcommand).

This adds a /ping command that will be useful for users
to see what the round trip to the Zulip server is (including
only a tiny bit of actual server time to basically give a
200).

It also introduce the "/zcommand" endpoint and zcommand.js
module.
This commit is contained in:
Steve Howell 2018-06-02 11:59:02 +00:00 committed by Tim Abbott
parent 87ba752758
commit 4b2e8b83c4
8 changed files with 119 additions and 1 deletions

View File

@ -74,6 +74,7 @@
"typing_status": false, "typing_status": false,
"sent_messages": false, "sent_messages": false,
"transmit": false, "transmit": false,
"zcommand": false,
"compose": false, "compose": false,
"compose_actions": false, "compose_actions": false,
"compose_state": false, "compose_state": false,

View File

@ -55,6 +55,7 @@ set_global('reminder', {
global.document.location.protocol = 'https:'; global.document.location.protocol = 'https:';
global.document.location.host = 'foo.com'; global.document.location.host = 'foo.com';
zrequire('zcommand');
zrequire('compose_ui'); zrequire('compose_ui');
zrequire('util'); zrequire('util');
zrequire('common'); zrequire('common');

View File

@ -299,11 +299,21 @@ exports.finish = function () {
exports.clear_private_stream_alert(); exports.clear_private_stream_alert();
notifications.clear_compose_notifications(); notifications.clear_compose_notifications();
var message_content = compose_state.message_content();
// Skip normal validation for zcommands, since they aren't
// actual messages with recipients; users only send them
// from the compose box for convenience sake.
if (zcommand.process(message_content)) {
exports.do_post_send_tasks();
clear_compose_box();
return;
}
if (! compose.validate()) { if (! compose.validate()) {
return false; return false;
} }
var message_content = compose_state.message_content();
if (reminder.is_deferred_delivery(message_content)) { if (reminder.is_deferred_delivery(message_content)) {
reminder.schedule_message(); reminder.schedule_message();
} else { } else {

82
static/js/zcommand.js Normal file
View File

@ -0,0 +1,82 @@
var zcommand = (function () {
var exports = {};
/*
What in the heck is a zcommand?
A zcommand is basically a specific type of slash
command where the client does almost no work and
the server just does something pretty simple like
flip a setting.
The first zcommand we wrote is for "/ping", and
the server just responds with a 200 for that.
Not all slash commands use zcommand under the hood.
For more exotic things like /poll see submessage.js
and widgetize.js
*/
exports.send = function (opts) {
var command = opts.command;
var on_success = opts.on_success;
var data = {
command: command,
};
channel.post({
url: '/json/zcommand',
data: data,
success: function (data) {
on_success(data);
},
error: function () {
exports.tell_user('server did not respond');
},
});
};
exports.tell_user = function (msg) {
// This is a bit hacky, but we don't have a super easy API now
// for just telling users stuff.
$('#compose-send-status').removeClass(common.status_classes)
.addClass('alert-error')
.stop(true).fadeTo(0, 1);
$('#compose-error-msg').text(msg);
};
exports.process = function (message_content) {
var content = message_content.trim();
if (content === '/ping') {
var start_time = new Date();
exports.send({
command: 'ping',
on_success: function () {
var end_time = new Date();
var diff = end_time - start_time;
diff = Math.round(diff);
var msg = "ping time: " + diff + "ms";
exports.tell_user(msg);
},
});
return true;
}
// It is incredibly important here to return false
// if we don't see an actual zcommand, so that compose.js
// knows this is a normal message.
return false;
};
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = zcommand;
}

View File

@ -999,6 +999,17 @@ class SewMessageAndReactionTest(ZulipTestCase):
class MessagePOSTTest(ZulipTestCase): class MessagePOSTTest(ZulipTestCase):
def test_zcommand(self) -> None:
self.login(self.example_email("hamlet"))
payload = dict(command="boil-ocean")
result = self.client_post("/json/zcommand", payload)
self.assert_json_error(result, "No such command: boil-ocean")
payload = dict(command="ping")
result = self.client_post("/json/zcommand", payload)
self.assert_json_success(result)
def test_message_to_self(self) -> None: def test_message_to_self(self) -> None:
""" """
Sending a message to a stream to which you are subscribed is Sending a message to a stream to which you are subscribed is

View File

@ -681,6 +681,15 @@ def find_first_unread_anchor(sa_conn: Any,
return anchor return anchor
@has_request_variables
def zcommand_backend(request: HttpRequest, user_profile: UserProfile,
command: str=REQ('command')) -> HttpResponse:
if command == 'ping':
ret = dict() # type: Dict[str, Any]
return json_success(ret)
raise JsonableError(_('No such command: %s') % (command,))
@has_request_variables @has_request_variables
def get_messages_backend(request: HttpRequest, user_profile: UserProfile, def get_messages_backend(request: HttpRequest, user_profile: UserProfile,
anchor: int=REQ(converter=int), anchor: int=REQ(converter=int),

View File

@ -968,6 +968,7 @@ JS_SPECS = {
'js/compose_state.js', 'js/compose_state.js',
'js/compose_actions.js', 'js/compose_actions.js',
'js/transmit.js', 'js/transmit.js',
'js/zcommand.js',
'js/compose.js', 'js/compose.js',
'js/upload.js', 'js/upload.js',
'js/stream_color.js', 'js/stream_color.js',

View File

@ -162,6 +162,9 @@ v1_api_and_json_patterns = [
url(r'^mark_topic_as_read$', rest_dispatch, url(r'^mark_topic_as_read$', rest_dispatch,
{'POST': 'zerver.views.messages.mark_topic_as_read'}), {'POST': 'zerver.views.messages.mark_topic_as_read'}),
url(r'^zcommand$', rest_dispatch,
{'POST': 'zerver.views.messages.zcommand_backend'}),
# messages -> zerver.views.messages # messages -> zerver.views.messages
# GET returns messages, possibly filtered, POST sends a message # GET returns messages, possibly filtered, POST sends a message
url(r'^messages$', rest_dispatch, url(r'^messages$', rest_dispatch,