فهرست منبع

Fixes #1700 Deleted pending contacts reappear after page reload

JC Brand 4 ماه پیش
والد
کامیت
d10159d1c8

+ 1 - 0
CHANGES.md

@@ -13,6 +13,7 @@
 - #1195: Add actions to quote and copy messages
 - #1303: Display non-contacts who sent us a message somehow in fullscreen 
 - #1349: XEP-0392 Consistent Color Generation
+- #1700: Deleted pending contacts reappear after page reload
 - #2118: Show reflected message in MUC 
 - #2383: Add modal to start chats with JIDs not in the roster
 - #2586: Add support for XEP-0402 Bookmarks

+ 5 - 1
src/headless/plugins/roster/contact.js

@@ -111,7 +111,6 @@ class RosterContact extends ColorAwareModel(Model) {
      * notification by sending a presence stanza of type "unsubscribe"
      * this step lets the user's server know that it MUST no longer
      * send notification of the subscription state change to the user.
-     * @method RosterContacts#ackUnsubscribe
      */
     ackUnsubscribe () {
         api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
@@ -160,7 +159,12 @@ class RosterContact extends ColorAwareModel(Model) {
             this.destroy();
             return;
         }
+        if (this.get('ask') === 'subscribe' || subscription === 'to') {
+            // See: https://datatracker.ietf.org/doc/html/rfc6121#section-3.3.1
+            api.send($pres({ type: 'unsubscribe',  to: this.get('jid')}));
+        }
         if (unauthorize && ['from', 'both'].includes(subscription)) {
+            // See: https://datatracker.ietf.org/doc/html/rfc6121#section-3.2.1
             this.unauthorize();
         }
         const promise = this.sendRosterRemoveStanza();

+ 0 - 1
src/headless/types/plugins/roster/contact.d.ts

@@ -103,7 +103,6 @@ declare class RosterContact extends RosterContact_base {
      * notification by sending a presence stanza of type "unsubscribe"
      * this step lets the user's server know that it MUST no longer
      * send notification of the subscription state change to the user.
-     * @method RosterContacts#ackUnsubscribe
      */
     ackUnsubscribe(): void;
     /**

+ 1 - 3
src/plugins/rosterview/contactview.js

@@ -60,9 +60,7 @@ export default class RosterContact extends CustomElement {
      */
     async removeContact(ev) {
         ev?.preventDefault?.();
-        // TODO: ask user whether they want to unauthorize the contact's
-        // presence request as well.
-        await removeContact(this.model);
+        await removeContact(this.model, true);
     }
 
     /**

+ 16 - 12
src/plugins/rosterview/tests/roster.js

@@ -681,7 +681,8 @@ describe("The Contacts Roster", function () {
             expect(el.getAttribute('data-group')).toBe('Ungrouped');
         }));
 
-        it("can be removed by the user", mock.initConverse([], {'roster_groups': false}, async function (_converse) {
+        it("can be removed by the user", mock.initConverse([], { roster_groups: false }, async function (_converse) {
+            const { api } = _converse;
             await mock.openControlBox(_converse);
             await mock.waitForRoster(_converse, 'all');
             await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
@@ -689,25 +690,28 @@ describe("The Contacts Roster", function () {
             const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const contact = _converse.roster.get(jid);
             spyOn(_converse.api, 'confirm').and.returnValue(Promise.resolve(true));
-            spyOn(contact, 'unauthorize').and.callFake(function () { return contact; });
-            spyOn(contact, 'sendRosterRemoveStanza').and.callThrough();
             const rosterview = document.querySelector('converse-roster');
             await u.waitUntil(() => sizzle(`.pending-xmpp-contact .contact-name:contains("${name}")`, rosterview).length, 500);
-            let sent_IQ;
-            spyOn(_converse.api.connection.get(), 'sendIQ').and.callFake(function (iq, callback) {
-                sent_IQ = iq;
-                callback();
-            });
             sizzle(`.remove-xmpp-contact[title="Click to remove ${name} as a contact"]`, rosterview).pop().click();
             await u.waitUntil(() => !sizzle(`.pending-xmpp-contact .contact-name:contains("${name}")`, rosterview).length, 500);
-            expect(_converse.api.confirm).toHaveBeenCalled();
-            expect(contact.sendRosterRemoveStanza).toHaveBeenCalled();
-            expect(sent_IQ).toEqualStanza(stx`
-                <iq type="set" xmlns="jabber:client">
+            expect(api.confirm).toHaveBeenCalled();
+
+            const { sent_stanzas } = api.connection.get();
+            let stanza = await u.waitUntil(() => sent_stanzas.find(iq => iq.querySelector('iq item[subscription="remove"]')));
+            expect(stanza).toEqualStanza(stx`
+                <iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">
                     <query xmlns="jabber:iq:roster">
                         <item jid="lord.capulet@montague.lit" subscription="remove"/>
                     </query>
                 </iq>`);
+
+            stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('presence[type="unsubscribed"]')).pop());
+            expect(stanza).toEqualStanza(
+                stx`<presence to="${contact.get('jid')}" type="unsubscribed" xmlns="jabber:client"/>`);
+
+            stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('presence[type="unsubscribe"]')).pop());
+            expect(stanza).toEqualStanza(
+                stx`<presence to="${contact.get('jid')}" type="unsubscribe" xmlns="jabber:client"/>`);
         }));
 
         it("can be removed by the user",

+ 11 - 0
src/types/plugins/rosterview/modals/accept-contact-request.d.ts

@@ -0,0 +1,11 @@
+export default class AcceptContactRequest extends BaseModal {
+    contact: any;
+    renderModal(): import("lit").TemplateResult<1>;
+    getModalTitle(): any;
+    /**
+     * @param {Event} ev
+     */
+    acceptContactRequest(ev: Event): Promise<void>;
+}
+import BaseModal from "plugins/modal/modal.js";
+//# sourceMappingURL=accept-contact-request.d.ts.map

+ 3 - 0
src/types/plugins/rosterview/modals/templates/accept-contact-request.d.ts

@@ -0,0 +1,3 @@
+declare function _default(el: import("../accept-contact-request.js").default): import("lit").TemplateResult<1>;
+export default _default;
+//# sourceMappingURL=accept-contact-request.d.ts.map