Include XEP-0172 nick in all outgoing presence subscribe stanzas
This commit is contained in:
parent
3530ccc35d
commit
fde55bea2c
|
@ -1,3 +1,4 @@
|
|||
import '@converse/headless/plugins/status/api.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
import { getOpenPromise } from '@converse/openpromise';
|
||||
|
@ -93,21 +94,12 @@ const RosterContact = Model.extend({
|
|||
|
||||
/**
|
||||
* Send a presence subscription request to this roster contact
|
||||
* @private
|
||||
* @method _converse.RosterContacts#subscribe
|
||||
* @param { String } message - An optional message to explain the
|
||||
* reason for the subscription request.
|
||||
*/
|
||||
subscribe (message) {
|
||||
const pres = $pres({to: this.get('jid'), type: "subscribe"});
|
||||
if (message && message !== "") {
|
||||
pres.c("status").t(message).up();
|
||||
}
|
||||
const nick = _converse.xmppstatus.getNickname() || _converse.xmppstatus.getFullname();
|
||||
if (nick) {
|
||||
pres.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick).up();
|
||||
}
|
||||
api.send(pres);
|
||||
api.user.presence.send('subscribe', this.get('jid'), message);
|
||||
this.save('ask', "subscribe"); // ask === 'subscribe' Means we have asked to subscribe to them.
|
||||
return this;
|
||||
},
|
||||
|
@ -135,7 +127,6 @@ const RosterContact = Model.extend({
|
|||
* send notification of the subscription state change to the user.
|
||||
* @private
|
||||
* @method _converse.RosterContacts#ackUnsubscribe
|
||||
* @param { String } jid - The Jabber ID of the user who is unsubscribing
|
||||
*/
|
||||
ackUnsubscribe () {
|
||||
api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
|
||||
|
|
|
@ -112,7 +112,7 @@ const RosterContacts = Collection.extend({
|
|||
* @method _converse.RosterContacts#addAndSubscribe
|
||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||
* @param { String } message - An optional message to explain the reason for the subscription request.
|
||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
|
@ -128,9 +128,7 @@ const RosterContacts = Collection.extend({
|
|||
* @method _converse.RosterContacts#sendContactAddIQ
|
||||
* @param { String } jid - The Jabber ID of the user being added
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { Function } callback - A function to call once the IQ is returned
|
||||
* @param { Function } errback - A function to call if an error occurred
|
||||
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||
*/
|
||||
sendContactAddIQ (jid, name, groups) {
|
||||
name = name ? name : null;
|
||||
|
@ -148,7 +146,7 @@ const RosterContacts = Collection.extend({
|
|||
* @method _converse.RosterContacts#addContactToRoster
|
||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
async addContactToRoster (jid, name, groups, attributes) {
|
||||
|
@ -190,7 +188,7 @@ const RosterContacts = Collection.extend({
|
|||
* Handle roster updates from the XMPP server.
|
||||
* See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
||||
* @method _converse.RosterContacts#onRosterPush
|
||||
* @param { Element } IQ - The IQ stanza received from the XMPP server.
|
||||
* @param { Element } iq - The IQ stanza received from the XMPP server.
|
||||
*/
|
||||
onRosterPush (iq) {
|
||||
const id = iq.getAttribute('id');
|
||||
|
|
|
@ -13,7 +13,7 @@ export default {
|
|||
* @param { String } type
|
||||
* @param { String } to
|
||||
* @param { String } [status] - An optional status message
|
||||
* @param { Element[]|Strophe.Builder[]|Element|Strophe.Builder } [child_nodes]
|
||||
* @param { Array<Element>|Array<Strophe.Builder>|Element|Strophe.Builder } [child_nodes]
|
||||
* Nodes(s) to be added as child nodes of the `presence` XML element.
|
||||
*/
|
||||
async send (type, to, status, child_nodes) {
|
||||
|
@ -85,7 +85,7 @@ export default {
|
|||
/**
|
||||
* @async
|
||||
* @method _converse.api.user.status.message.get
|
||||
* @returns {string} The status message
|
||||
* @returns { Promise<string> } The status message
|
||||
* @example const message = _converse.api.user.status.message.get()
|
||||
*/
|
||||
async get () {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { _converse, api, converse } from '@converse/headless/core';
|
|||
const { Strophe, $pres } = converse.env;
|
||||
|
||||
const XMPPStatus = Model.extend({
|
||||
|
||||
defaults () {
|
||||
return { "status": api.settings.get("default_state") }
|
||||
},
|
||||
|
@ -30,40 +31,57 @@ const XMPPStatus = Model.extend({
|
|||
return '';
|
||||
},
|
||||
|
||||
/** Constructs a presence stanza
|
||||
* @param { string } [type]
|
||||
* @param { string } [to] - The JID to which this presence should be sent
|
||||
* @param { string } [status_message]
|
||||
*/
|
||||
async constructPresence (type, to=null, status_message) {
|
||||
type = typeof type === 'string' ? type : (this.get('status') || api.settings.get("default_state"));
|
||||
status_message = typeof status_message === 'string' ? status_message : this.get('status_message');
|
||||
|
||||
let presence;
|
||||
const attrs = {to};
|
||||
if ((type === 'unavailable') ||
|
||||
|
||||
if (type === 'subscribe') {
|
||||
presence = $pres({ to, type });
|
||||
const { xmppstatus } = _converse;
|
||||
const nick = xmppstatus.getNickname();
|
||||
if (nick) presence.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick).up();
|
||||
|
||||
} else if ((type === 'unavailable') ||
|
||||
(type === 'probe') ||
|
||||
(type === 'error') ||
|
||||
(type === 'unsubscribe') ||
|
||||
(type === 'unsubscribed') ||
|
||||
(type === 'subscribe') ||
|
||||
(type === 'subscribed')) {
|
||||
attrs['type'] = type;
|
||||
presence = $pres(attrs);
|
||||
presence = $pres({ to, type });
|
||||
|
||||
} else if (type === 'offline') {
|
||||
attrs['type'] = 'unavailable';
|
||||
presence = $pres(attrs);
|
||||
presence = $pres({ to, type: 'unavailable' });
|
||||
|
||||
} else if (type === 'online') {
|
||||
presence = $pres(attrs);
|
||||
presence = $pres({ to });
|
||||
|
||||
} else {
|
||||
presence = $pres(attrs).c('show').t(type).up();
|
||||
presence = $pres({ to }).c('show').t(type).up();
|
||||
}
|
||||
|
||||
if (status_message) {
|
||||
presence.c('status').t(status_message).up();
|
||||
}
|
||||
if (status_message) presence.c('status').t(status_message).up();
|
||||
|
||||
const priority = api.settings.get("priority");
|
||||
presence.c('priority').t(isNaN(Number(priority)) ? 0 : priority).up();
|
||||
if (_converse.idle) {
|
||||
|
||||
const { idle, idle_seconds } = _converse;
|
||||
if (idle) {
|
||||
const idle_since = new Date();
|
||||
idle_since.setSeconds(idle_since.getSeconds() - _converse.idle_seconds);
|
||||
presence.c('idle', {xmlns: Strophe.NS.IDLE, since: idle_since.toISOString()});
|
||||
idle_since.setSeconds(idle_since.getSeconds() - idle_seconds);
|
||||
presence.c('idle', { xmlns: Strophe.NS.IDLE, since: idle_since.toISOString() });
|
||||
}
|
||||
|
||||
/**
|
||||
* *Hook* which allows plugins to modify a presence stanza
|
||||
* @event _converse#constructedPresence
|
||||
*/
|
||||
presence = await api.hook('constructedPresence', null, presence);
|
||||
return presence;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ describe("A Message", function () {
|
|||
message = '/me is as well';
|
||||
await mock.sendMessage(view, message);
|
||||
expect(view.querySelectorAll('.chat-msg--action').length).toBe(2);
|
||||
await u.waitUntil(() => sizzle('.chat-msg__author:last', view).pop().textContent.trim() === '**Romeo Montague');
|
||||
await u.waitUntil(() => sizzle('.chat-msg__author:last', view).pop().textContent.trim() === '**Romeo');
|
||||
const last_el = sizzle('.chat-msg__text:last', view).pop();
|
||||
await u.waitUntil(() => last_el.textContent === 'is as well');
|
||||
expect(u.hasClass('chat-msg--followup', last_el)).toBe(false);
|
||||
|
|
|
@ -651,7 +651,7 @@ describe("A Chat Message", function () {
|
|||
const msg_object = chatbox.messages.models[0];
|
||||
|
||||
const msg_author = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
|
||||
expect(msg_author.textContent.trim()).toBe('Romeo Montague');
|
||||
expect(msg_author.textContent.trim()).toBe('Romeo');
|
||||
|
||||
const msg_time = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
|
||||
const time = dayjs(msg_object.get('time')).format(api.settings.get('time_format'));
|
||||
|
|
|
@ -139,7 +139,7 @@ describe("A spoiler message", function () {
|
|||
expect(body_el.textContent).toBe(spoiler);
|
||||
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo');
|
||||
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
|
@ -219,7 +219,7 @@ describe("A spoiler message", function () {
|
|||
const body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe(spoiler);
|
||||
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo');
|
||||
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("Groupchats", function () {
|
|||
describe("An instant groupchat", function () {
|
||||
|
||||
it("will be created when muc_instant_rooms is set to true",
|
||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||
mock.initConverse(['chatBoxesFetched'], { vcard: { nickname: '' } }, async function (_converse) {
|
||||
|
||||
let IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
|
@ -110,10 +110,11 @@ describe("Groupchats", function () {
|
|||
it("Can be configured to show cached messages before being joined",
|
||||
mock.initConverse(['discoInitialized'],
|
||||
{
|
||||
'muc_show_logs_before_join': true,
|
||||
'archived_messages_page_size': 2,
|
||||
'muc_nickname_from_jid': false,
|
||||
'muc_clear_messages_on_leave': false,
|
||||
muc_show_logs_before_join: true,
|
||||
archived_messages_page_size: 2,
|
||||
muc_nickname_from_jid: false,
|
||||
muc_clear_messages_on_leave: false,
|
||||
vcard: { nickname: '' },
|
||||
}, async function (_converse) {
|
||||
|
||||
const { api } = _converse;
|
||||
|
|
|
@ -281,7 +281,7 @@ describe("A MUC", function () {
|
|||
}));
|
||||
|
||||
it("will render a nickname form if a nickname conflict happens and muc_nickname_from_jid=false",
|
||||
mock.initConverse([], {}, async function (_converse) {
|
||||
mock.initConverse([], { vcard: { nickname: '' }}, async function (_converse) {
|
||||
|
||||
const muc_jid = 'conflicted@muc.montague.lit';
|
||||
await mock.openChatRoomViaModal(_converse, muc_jid, 'romeo');
|
||||
|
@ -322,7 +322,7 @@ describe("A MUC", function () {
|
|||
|
||||
|
||||
it("will automatically choose a new nickname if a nickname conflict happens and muc_nickname_from_jid=true",
|
||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||
mock.initConverse(['chatBoxesFetched'], {vcard: { nickname: '' }}, async function (_converse) {
|
||||
|
||||
const { api } = _converse;
|
||||
const muc_jid = 'conflicting@muc.montague.lit'
|
||||
|
@ -417,7 +417,11 @@ describe("A MUC", function () {
|
|||
}));
|
||||
|
||||
it("doesn't show the nickname field if locked_muc_nickname is true",
|
||||
mock.initConverse(['chatBoxesFetched'], {'locked_muc_nickname': true, 'muc_nickname_from_jid': true}, async function (_converse) {
|
||||
mock.initConverse(['chatBoxesFetched'], {
|
||||
locked_muc_nickname: true,
|
||||
muc_nickname_from_jid: true,
|
||||
vcard: { nickname: '' },
|
||||
}, async function (_converse) {
|
||||
|
||||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current', 0);
|
||||
|
|
|
@ -308,7 +308,7 @@ describe("Message Retractions", function () {
|
|||
|
||||
describe("A Sent Chat Message", function () {
|
||||
|
||||
it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||
it("can be retracted by its author", mock.initConverse(['chatBoxesFetched'], { vcard: { nickname: ''} }, async function (_converse) {
|
||||
await mock.waitForRoster(_converse, 'current', 1);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
const view = await mock.openChatBoxFor(_converse, contact_jid);
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
// See: https://xmpp.org/rfcs/rfc3921.html
|
||||
|
||||
const Strophe = converse.env.Strophe;
|
||||
const { Strophe, stx } = converse.env;
|
||||
|
||||
describe("The Protocol", function () {
|
||||
|
||||
beforeEach(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));
|
||||
|
||||
describe("Integration of Roster Items and Presence Subscriptions", function () {
|
||||
/* Some level of integration between roster items and presence
|
||||
* subscriptions is normally expected by an instant messaging user
|
||||
|
@ -163,11 +165,13 @@ describe("The Protocol", function () {
|
|||
* <presence to='contact@example.org' type='subscribe'/>
|
||||
*/
|
||||
const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('presence')).pop());
|
||||
expect(Strophe.serialize(sent_presence)).toBe(
|
||||
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">`+
|
||||
`<nick xmlns="http://jabber.org/protocol/nick">Romeo Montague</nick>`+
|
||||
`</presence>`
|
||||
);
|
||||
expect(sent_presence).toEqualStanza(stx`
|
||||
<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">
|
||||
<nick xmlns="http://jabber.org/protocol/nick">Romeo</nick>
|
||||
<priority>0</priority>
|
||||
<c hash="sha-1" node="https://conversejs.org" ver="TfHz9vOOfqIG0Z9lW5CuPaWGnrQ=" xmlns="http://jabber.org/protocol/caps"/>
|
||||
</presence>
|
||||
`);
|
||||
|
||||
/* As a result, the user's server MUST initiate a second roster
|
||||
* push to all of the user's available resources that have
|
||||
|
|
|
@ -12,7 +12,9 @@ jasmine.toEqualStanza = function toEqualStanza () {
|
|||
compare (actual, expected) {
|
||||
const result = { pass: u.isEqualNode(actual, expected) };
|
||||
if (!result.pass) {
|
||||
result.message = `Stanzas don't match:\nActual:\n${actual.outerHTML}\nExpected:\n${expected.outerHTML}`;
|
||||
result.message = `Stanzas don't match:\n`+
|
||||
`Actual:\n${(actual.tree?.() ?? actual).outerHTML}\n`+
|
||||
`Expected:\n${expected.tree().outerHTML}`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -672,10 +674,13 @@ async function _initConverse (settings) {
|
|||
} else if (!model.get('vcard_updated') || force) {
|
||||
jid = model.get('jid') || model.get('muc_jid');
|
||||
}
|
||||
|
||||
let fullname;
|
||||
let nickname;
|
||||
if (!jid || jid == 'romeo@montague.lit') {
|
||||
jid = 'romeo@montague.lit';
|
||||
fullname = 'Romeo Montague' ;
|
||||
jid = settings?.vcard?.jid ?? 'romeo@montague.lit';
|
||||
fullname = settings?.vcard?.display_name ?? 'Romeo Montague' ;
|
||||
nickname = settings?.vcard?.nickname ?? 'Romeo';
|
||||
} else {
|
||||
const name = jid.split('@')[0].replace(/\./g, ' ').split(' ');
|
||||
const last = name.length-1;
|
||||
|
@ -683,13 +688,17 @@ async function _initConverse (settings) {
|
|||
name[last] = name[last].charAt(0).toUpperCase()+name[last].slice(1);
|
||||
fullname = name.join(' ');
|
||||
}
|
||||
const vcard = $iq().c('vCard').c('FN').t(fullname).tree();
|
||||
const vcard = $iq().c('vCard').c('FN').t(fullname).up();
|
||||
if (nickname) vcard.c('NICKNAME').t(nickname);
|
||||
const vcard_el = vcard.tree();
|
||||
|
||||
return {
|
||||
'stanza': vcard,
|
||||
'fullname': vcard.querySelector('FN')?.textContent,
|
||||
'image': vcard.querySelector('PHOTO BINVAL')?.textContent,
|
||||
'image_type': vcard.querySelector('PHOTO TYPE')?.textContent,
|
||||
'url': vcard.querySelector('URL')?.textContent,
|
||||
'stanza': vcard_el,
|
||||
'fullname': vcard_el.querySelector('FN')?.textContent,
|
||||
'nickname': vcard_el.querySelector('NICKNAME')?.textContent,
|
||||
'image': vcard_el.querySelector('PHOTO BINVAL')?.textContent,
|
||||
'image_type': vcard_el.querySelector('PHOTO TYPE')?.textContent,
|
||||
'url': vcard_el.querySelector('URL')?.textContent,
|
||||
'vcard_updated': dayjs().format(),
|
||||
'vcard_error': undefined
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user