Skip to content

Commit

Permalink
Use stx to create message stanza
Browse files Browse the repository at this point in the history
  • Loading branch information
jcbrand committed Jan 17, 2025
1 parent 0e26e21 commit e5d7799
Show file tree
Hide file tree
Showing 19 changed files with 165 additions and 203 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/headless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"pluggable.js": "3.0.1",
"sizzle": "^2.3.5",
"sprintf-js": "^1.1.2",
"strophe.js": "strophe/strophejs#b4f3369ba07dee4f04750de6709ea8ebe8adf9a5",
"strophe.js": "strophe/strophejs#f54d83199ec62272ee8b4987b2e63f188e1b2e29",
"urijs": "^1.19.10"
},
"devDependencies": {}
Expand Down
6 changes: 6 additions & 0 deletions src/headless/plugins/chat/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class Message extends ModelWithContact(ColorAwareModel(Model)) {
constructor (models, options) {
super(models, options);
this.file = null;

/** @type {import('./types').MessageAttributes} */
this.attributes;
}

async initialize () {
Expand Down Expand Up @@ -209,6 +212,9 @@ class Message extends ModelWithContact(ColorAwareModel(Model)) {
return api.sendIQ(iq);
}

/**
* @param {Element} stanza
*/
getUploadRequestMetadata (stanza) { // eslint-disable-line class-methods-use-this
const headers = sizzle(`slot[xmlns="${Strophe.NS.HTTPUPLOAD}"] put header`, stanza);
// https://xmpp.org/extensions/xep-0363.html#request
Expand Down
10 changes: 9 additions & 1 deletion src/headless/plugins/chat/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import {EncryptionAttrs} from "../../shared/types";

// Represents a XEP-0372 reference
export type Reference = {
begin: number;
end: number;
type: string;
uri: string;
}

export type MessageErrorAttributes = {
is_error: boolean; // Whether an error was received for this message
error: string; // The error name
Expand Down Expand Up @@ -41,7 +49,7 @@ export type MessageAttributes = EncryptionAttrs & MessageErrorAttributes & {
plaintext: string; // The decrypted text of this message, in case it was encrypted.
receipt_id: string; // The `id` attribute of a XEP-0184 <receipt> element
received: string; // An ISO8601 string recording the time that the message was received
references: Array<Object>; // A list of objects representing XEP-0372 references
references: Array<Reference>; // A list of objects representing XEP-0372 references
replace_id: string; // The `id` attribute of a XEP-0308 <replace> element
retracted: string; // An ISO8601 string recording the time that the message was retracted
retracted_id: string; // The `id` attribute of a XEP-424 <retracted> element
Expand Down
1 change: 1 addition & 0 deletions src/headless/plugins/muc/occupant.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class MUCOccupant extends ModelWithMessages(ColorAwareModel(Model)) {
states: [],
hidden: true,
num_unread: 0,
message_type: 'chat',
};
}

Expand Down
6 changes: 3 additions & 3 deletions src/headless/plugins/muc/tests/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ describe("A MUC message", function () {

const muc_jid = '[email protected]';
const model = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const received_stanza = u.toStanza(`
<message to='${_converse.jid}' from='${muc_jid}/mallory' type='groupchat' id='${_converse.api.connection.get().getUniqueId()}' >
const received_stanza = stx`
<message xmlns="jabber:client" to='${_converse.jid}' from='${muc_jid}/mallory' type='groupchat' id='${_converse.api.connection.get().getUniqueId()}' >
<reply xmlns='urn:xmpp:reply:0' id='${_converse.api.connection.get().getUniqueId()}' to='${_converse.jid}'/>
<fallback xmlns='urn:xmpp:feature-fallback:0' for='urn:xmpp:reply:0'>
<body start='0' end='10'/>
Expand All @@ -139,7 +139,7 @@ describe("A MUC message", function () {
pong</body>
<request xmlns='urn:xmpp:receipts'/>
</message>
`);
`;
await model.handleMessageStanza(received_stanza);
await u.waitUntil(() => model.messages.last());
expect(model.messages.last().get('body')).toBe('> ping\n pong');
Expand Down
98 changes: 41 additions & 57 deletions src/headless/shared/model-with-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { MethodNotImplementedError } from './errors.js';
import { sendMarker, sendReceiptStanza, sendRetractionMessage } from './actions.js';
import { parseMessage } from '../plugins/chat/parsers';

const { Strophe, $msg, u } = converse.env;
const { Strophe, stx, u } = converse.env;

/**
* Adds a messages collection to a model and various methods related to sending
Expand Down Expand Up @@ -155,9 +155,9 @@ export default function ModelWithMessages(BaseModel) {
}

/**
* @param {MessageAttributes|Error} attrs_or_error
* @param {MessageAttributes|Error} _attrs_or_error
*/
async onMessage(attrs_or_error) {
async onMessage(_attrs_or_error) {
throw new MethodNotImplementedError('onMessage is not implemented');
}

Expand Down Expand Up @@ -889,64 +889,48 @@ export default function ModelWithMessages(BaseModel) {
/**
* Given a {@link Message} return the XML stanza that represents it.
* @method ChatBox#createMessageStanza
* @param { Message } message - The message object
* @param {Message} message - The message object
*/
async createMessageStanza(message) {
const stanza = $msg({
'from': message.get('from') || api.connection.get().jid,
'to': message.get('to') || this.get('jid'),
'type': this.get('message_type'),
'id': (message.get('edited') && u.getUniqueId()) || message.get('msgid'),
})
.c('body')
.t(message.get('body'))
.up()
.c(constants.ACTIVE, { 'xmlns': Strophe.NS.CHATSTATES })
.root();

if (message.get('type') === 'chat') {
stanza.c('request', { 'xmlns': Strophe.NS.RECEIPTS }).root();
}

if (!message.get('is_encrypted')) {
if (message.get('is_spoiler')) {
if (message.get('spoiler_hint')) {
stanza.c('spoiler', { 'xmlns': Strophe.NS.SPOILER }, message.get('spoiler_hint')).root();
} else {
stanza.c('spoiler', { 'xmlns': Strophe.NS.SPOILER }).root();
}
}
(message.get('references') || []).forEach((reference) => {
const attrs = {
'xmlns': Strophe.NS.REFERENCE,
'begin': reference.begin,
'end': reference.end,
'type': reference.type,
};
if (reference.uri) {
attrs.uri = reference.uri;
const {
body,
edited,
is_encrypted,
is_spoiler,
msgid,
oob_url,
origin_id,
references,
spoiler_hint,
type,
} = message.attributes;

const stanza = stx`
<message xmlns="jabber:client"
from="${message.get('from') || api.connection.get().jid}"
to="${message.get('to') || this.get('jid')}"
type="${this.get('message_type')}"
id="${(edited && u.getUniqueId()) || msgid}">
${body ? stx`<body>${body}</body>` : ''}
<active xmlns="${Strophe.NS.CHATSTATES}"/>
${type === 'chat' ? stx`<request xmlns="${Strophe.NS.RECEIPTS}"></request>` : ''}
${!is_encrypted && oob_url ? stx`<x xmlns="${Strophe.NS.OUTOFBAND}"><url>${oob_url}</url></x>` : ''}
${!is_encrypted && is_spoiler ? stx`<spoiler xmlns="${Strophe.NS.SPOILER}">${spoiler_hint ?? ''}</spoiler>` : ''}
${
!is_encrypted
? references?.map(
(ref) => stx`<reference xmlns="${Strophe.NS.REFERENCE}"
begin="${ref.begin}"
end="${ref.end}"
type="${ref.type}"
uri="${ref.uri}"></reference>`
)
: ''
}
stanza.c('reference', attrs).root();
});

if (message.get('oob_url')) {
stanza.c('x', { 'xmlns': Strophe.NS.OUTOFBAND }).c('url').t(message.get('oob_url')).root();
}
}
${edited ? stx`<replace xmlns="${Strophe.NS.MESSAGE_CORRECT}" id="${msgid}"></replace>` : ''}
${origin_id ? stx`<origin-id xmlns="${Strophe.NS.SID}" id="${origin_id}"></origin-id>` : ''}
</message>`;

if (message.get('edited')) {
stanza
.c('replace', {
'xmlns': Strophe.NS.MESSAGE_CORRECT,
'id': message.get('msgid'),
})
.root();
}

if (message.get('origin_id')) {
stanza.c('origin-id', { 'xmlns': Strophe.NS.SID, 'id': message.get('origin_id') }).root();
}
stanza.root();
/**
* *Hook* which allows plugins to update an outgoing message stanza
* @event _converse#createMessageStanza
Expand Down
7 changes: 6 additions & 1 deletion src/headless/types/plugins/chat/message.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ declare class Message extends Message_base {
is_ephemeral: boolean;
};
file: any;
/** @type {import('./types').MessageAttributes} */
attributes: import("./types").MessageAttributes;
initialize(): Promise<void>;
chatbox: any;
initialized: any;
Expand Down Expand Up @@ -204,7 +206,10 @@ declare class Message extends Message_base {
* @method _converse.Message#sendSlotRequestStanza
*/
private sendSlotRequestStanza;
getUploadRequestMetadata(stanza: any): {
/**
* @param {Element} stanza
*/
getUploadRequestMetadata(stanza: Element): {
headers: {
name: string;
value: string;
Expand Down
2 changes: 1 addition & 1 deletion src/headless/types/plugins/chat/model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ declare const ChatBox_base: {
messages: any;
fetchMessages(): any;
afterMessagesFetched(): void;
onMessage(attrs_or_error: import("./types").MessageAttributes | Error): Promise<void>;
onMessage(_attrs_or_error: import("./types").MessageAttributes | Error): Promise<void>;
getUpdatedMessageAttributes(message: import("./message.js").default, attrs: import("./types").MessageAttributes): object;
updateMessage(message: import("./message.js").default, attrs: import("./types").MessageAttributes): void;
handleCorrection(attrs: import("./types").MessageAttributes | import("../muc/types.js").MUCMessageAttributes): Promise<import("./message.js").default | void>;
Expand Down
8 changes: 7 additions & 1 deletion src/headless/types/plugins/chat/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { EncryptionAttrs } from "../../shared/types";
export type Reference = {
begin: number;
end: number;
type: string;
uri: string;
};
export type MessageErrorAttributes = {
is_error: boolean;
error: string;
Expand Down Expand Up @@ -42,7 +48,7 @@ export type MessageAttributes = EncryptionAttrs & MessageErrorAttributes & {
plaintext: string;
receipt_id: string;
received: string;
references: Array<Object>;
references: Array<Reference>;
replace_id: string;
retracted: string;
retracted_id: string;
Expand Down
2 changes: 1 addition & 1 deletion src/headless/types/plugins/muc/muc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ declare const MUC_base: {
messages: any;
fetchMessages(): any;
afterMessagesFetched(): void;
onMessage(attrs_or_error: import("../chat/types").MessageAttributes | Error): Promise<void>;
onMessage(_attrs_or_error: import("../chat/types").MessageAttributes | Error): Promise<void>;
getUpdatedMessageAttributes(message: import("../chat/message.js").default, attrs: import("../chat/types").MessageAttributes): object;
updateMessage(message: import("../chat/message.js").default, attrs: import("../chat/types").MessageAttributes): void;
handleCorrection(attrs: import("../chat/types").MessageAttributes | import("./types").MUCMessageAttributes): Promise<import("../chat/message.js").default | void>;
Expand Down
2 changes: 1 addition & 1 deletion src/headless/types/plugins/muc/occupant.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ declare const MUCOccupant_base: {
messages: any;
fetchMessages(): any;
afterMessagesFetched(): void;
onMessage(attrs_or_error: import("../chat/types").MessageAttributes | Error): Promise<void>;
onMessage(_attrs_or_error: import("../chat/types").MessageAttributes | Error): Promise<void>;
getUpdatedMessageAttributes(message: import("../chat").Message, attrs: import("../chat/types").MessageAttributes): object;
updateMessage(message: import("../chat").Message, attrs: import("../chat/types").MessageAttributes): void;
handleCorrection(attrs: import("../chat/types").MessageAttributes | import("./types").MUCMessageAttributes): Promise<import("../chat").Message | void>;
Expand Down
2 changes: 1 addition & 1 deletion src/headless/types/shared/chatbox.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ declare const ChatBoxBase_base: {
messages: any;
fetchMessages(): any;
afterMessagesFetched(): void;
onMessage(attrs_or_error: import("../plugins/chat/types.js").MessageAttributes | Error): Promise<void>;
onMessage(_attrs_or_error: import("../plugins/chat/types.js").MessageAttributes | Error): Promise<void>;
getUpdatedMessageAttributes(message: import("../index.js").Message, attrs: import("../plugins/chat/types.js").MessageAttributes): object;
updateMessage(message: import("../index.js").Message, attrs: import("../plugins/chat/types.js").MessageAttributes): void;
handleCorrection(attrs: import("../plugins/chat/types.js").MessageAttributes | import("../plugins/muc/types.js").MUCMessageAttributes): Promise<import("../index.js").Message | void>;
Expand Down
6 changes: 3 additions & 3 deletions src/headless/types/shared/model-with-messages.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export default function ModelWithMessages<T extends import("./types").ModelExten
fetchMessages(): any;
afterMessagesFetched(): void;
/**
* @param {MessageAttributes|Error} attrs_or_error
* @param {MessageAttributes|Error} _attrs_or_error
*/
onMessage(attrs_or_error: import("../plugins/chat/types.ts").MessageAttributes | Error): Promise<void>;
onMessage(_attrs_or_error: import("../plugins/chat/types.ts").MessageAttributes | Error): Promise<void>;
/**
* @param {Message} message
* @param {MessageAttributes} attrs
Expand Down Expand Up @@ -216,7 +216,7 @@ export default function ModelWithMessages<T extends import("./types").ModelExten
/**
* Given a {@link Message} return the XML stanza that represents it.
* @method ChatBox#createMessageStanza
* @param { Message } message - The message object
* @param {Message} message - The message object
*/
createMessageStanza(message: import("../plugins/chat/message").default): Promise<any>;
/**
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/adhoc-views/tests/adhoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const { Strophe, sizzle, u, stx } = converse.env;

describe("Ad-hoc commands", function () {

beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));

it("can be queried for via a modal", mock.initConverse([], {}, async (_converse) => {
const { api } = _converse;
const entity_jid = 'muc.montague.lit';
Expand Down
22 changes: 12 additions & 10 deletions src/plugins/chatview/tests/corrections.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const { Promise, $msg, Strophe, sizzle, u } = converse.env;

describe("A Chat Message", function () {

beforeAll(() => jasmine.addMatchers({ toEqualStanza: jasmine.toEqualStanza }));

it("can be sent as a correction by using the up arrow",
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {

Expand Down Expand Up @@ -56,16 +58,16 @@ describe("A Chat Message", function () {

expect(api.connection.get().send).toHaveBeenCalled();
const msg = api.connection.get().send.calls.all()[0].args[0];
expect(Strophe.serialize(msg))
.toBe(`<message from="[email protected]/orchard" id="${msg.getAttribute("id")}" `+
`to="[email protected]" type="chat" `+
`xmlns="jabber:client">`+
`<body>But soft, what light through yonder window breaks?</body>`+
`<active xmlns="http://jabber.org/protocol/chatstates"/>`+
`<request xmlns="urn:xmpp:receipts"/>`+
`<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
`<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
`</message>`);
expect(msg).toEqualStanza(
stx`<message from="[email protected]/orchard" id="${msg.getAttribute("id")}"
to="[email protected]" type="chat"
xmlns="jabber:client">
<body>But soft, what light through yonder window breaks?</body>
<active xmlns="http://jabber.org/protocol/chatstates"/>
<request xmlns="urn:xmpp:receipts"/>
<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>
<origin-id id="${msg.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>
</message>`);
expect(view.model.messages.models.length).toBe(1);
const corrected_message = view.model.messages.at(0);
expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
Expand Down
Loading

0 comments on commit e5d7799

Please sign in to comment.