From 77a51cc2a6dd5b48810f6600e146c487dd83cccb Mon Sep 17 00:00:00 2001 From: JC Brand Date: Wed, 28 Mar 2018 18:38:22 +0200 Subject: [PATCH] Initial work on XEP-0363: HTTP File Upload --- spec/disco.js | 1 + spec/http-file-upload.js | 152 +++++++++++++++++++++++++++++++ src/config.js | 1 + src/converse-core.js | 1 + src/converse-http-file-upload.js | 16 ++++ src/converse-otr.js | 1 - tests/runner.js | 3 +- 7 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 spec/http-file-upload.js create mode 100644 src/converse-http-file-upload.js diff --git a/spec/disco.js b/spec/disco.js index 17c1598e2..1d216b316 100644 --- a/spec/disco.js +++ b/spec/disco.js @@ -14,6 +14,7 @@ describe("Service Discovery", function () { describe("Whenever converse.js queries a server for its features", function () { + it("stores the features it receives", mock.initConverseWithAsync(function (done, _converse) { var IQ_stanzas = _converse.connection.IQ_stanzas; var IQ_ids = _converse.connection.IQ_ids; diff --git a/spec/http-file-upload.js b/spec/http-file-upload.js new file mode 100644 index 000000000..61cb34622 --- /dev/null +++ b/spec/http-file-upload.js @@ -0,0 +1,152 @@ +(function (root, factory) { + define([ + "jasmine", + "jquery", + "converse-core", + "mock", + "test-utils"], factory); +} (this, function (jasmine, $, converse, mock, test_utils) { + "use strict"; + var Strophe = converse.env.Strophe; + var $iq = converse.env.$iq; + var _ = converse.env._; + + describe("XEP-0363: HTTP File Upload", function () { + + describe("Discovering support", function () { + + it("is done automatically", mock.initConverseWithAsync(function (done, _converse) { + var IQ_stanzas = _converse.connection.IQ_stanzas; + var IQ_ids = _converse.connection.IQ_ids; + test_utils.waitUntil(function () { + return _.filter(IQ_stanzas, function (iq) { + return iq.nodeTree.querySelector('query[xmlns="http://jabber.org/protocol/disco#info"]'); + }).length > 0; + }, 300).then(function () { + /* + * + * + * + * + * + * + */ + var info_IQ_id = IQ_ids[0]; + var stanza = $iq({ + 'type': 'result', + 'from': 'localhost', + 'to': 'dummy@localhost/resource', + 'id': info_IQ_id + }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'}) + .c('identity', { + 'category': 'server', + 'type': 'im'}).up() + .c('feature', { + 'var': 'http://jabber.org/protocol/disco#info'}).up() + .c('feature', { + 'var': 'http://jabber.org/protocol/disco#items'}); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + + var entities = _converse.disco_entities; + expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID + expect(entities.get(_converse.domain).features.length).toBe(2); + expect(entities.get(_converse.domain).identities.length).toBe(1); + + return test_utils.waitUntil(function () { + // Converse.js sees that the entity has a disco#items feature, + // so it will make a query for it. + return _.filter(IQ_stanzas, function (iq) { + return iq.nodeTree.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]'); + }).length > 0; + }, 300); + }).then(function () { + /* + * + * + * + * + * + */ + var items_IQ_id = IQ_ids[IQ_ids.length-1]; + var stanza = $iq({ + 'type': 'result', + 'from': 'localhost', + 'to': 'dummy@localhost/resource', + 'id': items_IQ_id + }).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'}) + .c('item', { + 'jid': 'upload.localhost', + 'name': 'HTTP File Upload'}).up() + .c('item', { + 'jid': 'conference.localhost', + 'name': 'Chatrooms Service'}); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + + var entities = _converse.disco_entities; + expect(entities.length).toBe(4); // We have an extra entity, which is the user's JID + + return test_utils.waitUntil(function () { + // Converse.js sees that the entity has a disco#items feature, + // so it will make a query for it. + return _.filter(IQ_stanzas, function (iq) { + return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); + }).length > 0; + }, 300); + }).then(function () { + var stanza = _.filter(IQ_stanzas, function (iq) { + return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]'); + })[0]; + var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)]; + expect(stanza.toLocaleString()).toBe( + ""+ + ""+ + ""); + + // Upload service responds and reports a maximum file size of 5MiB + /* + * + * + * + * + * + * urn:xmpp:http:upload:0 + * + * + * 5242880 + * + * + * + * + */ + stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'}) + .c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'}) + .c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up() + .c('feature', {'var':'urn:xmpp:http:upload:0'}).up() + .c('x', {'type':'result', 'xmlns':'jabber:x:data'}) + .c('field', {'var':'FORM_TYPE', 'type':'hidden'}) + .c('value').t('urn:xmpp:http:upload:0').up().up() + .c('field', {'var':'max-file-size'}) + .c('value').t('5242880'); + _converse.connection._dataRecv(test_utils.createRequest(stanza)); + + var entities = _converse.disco_entities; + expect(entities.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1); + done(); + }) + })); + }); + }); +})); diff --git a/src/config.js b/src/config.js index ef89f5cc0..18f4073fa 100644 --- a/src/config.js +++ b/src/config.js @@ -74,6 +74,7 @@ require.config({ "converse-dragresize": "src/converse-dragresize", "converse-fullscreen": "src/converse-fullscreen", "converse-headline": "src/converse-headline", + "converse-http-file-upload":"src/converse-http-file-upload", "converse-mam": "src/converse-mam", "converse-minimize": "src/converse-minimize", "converse-modal": "src/converse-modal", diff --git a/src/converse-core.js b/src/converse-core.js index 2c738c2b1..2e827918f 100644 --- a/src/converse-core.js +++ b/src/converse-core.js @@ -78,6 +78,7 @@ 'converse-dropdown', 'converse-fullscreen', 'converse-headline', + 'converse-http-file-upload', 'converse-mam', 'converse-minimize', 'converse-modal', diff --git a/src/converse-http-file-upload.js b/src/converse-http-file-upload.js new file mode 100644 index 000000000..f380365a4 --- /dev/null +++ b/src/converse-http-file-upload.js @@ -0,0 +1,16 @@ +(function (root, factory) { + define(["converse-http-file-upload"], factory); +}(this, function (converse) { + "use strict"; + + converse.plugins.add('converse-http-file-upload', { + + initialize () { + /* The initialize function gets called as soon as the plugin is + * loaded by converse.js's plugin machinery. + */ + const { _converse } = this; + + } + }); +})); diff --git a/src/converse-otr.js b/src/converse-otr.js index c60da608a..bc60731b9 100644 --- a/src/converse-otr.js +++ b/src/converse-otr.js @@ -10,7 +10,6 @@ * encryption of one-on-one chat messages. */ (function (root, factory) { - define([ "converse-chatview", "bootstrap", "tpl!toolbar_otr", diff --git a/tests/runner.js b/tests/runner.js index 72887b320..80670b3c1 100644 --- a/tests/runner.js +++ b/tests/runner.js @@ -54,7 +54,8 @@ var specs = [ "spec/chatroom", "spec/minchats", "spec/notification", - "spec/register" + "spec/register", + "spec/http-file-upload" ]; require(['console-reporter', 'mock', 'sinon', 'wait-until-promise', 'pluggable'],