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