فهرست منبع

Better error handling during registration.

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

+ 0 - 1
.prettierrc

@@ -1,7 +1,6 @@
 {
 {
   "printWidth": 120,
   "printWidth": 120,
   "quoteProps": "preserve",
   "quoteProps": "preserve",
-  "singleQuote": true,
   "spaceBeforeFunctionParen": true,
   "spaceBeforeFunctionParen": true,
   "tabWidth": 4,
   "tabWidth": 4,
   "useTabs": false
   "useTabs": false

+ 2 - 3
src/headless/index.js

@@ -8,11 +8,9 @@ import u from './utils/index.js';
 import converse from './shared/api/public.js';
 import converse from './shared/api/public.js';
 import log from './log.js';
 import log from './log.js';
 
 
-
 // START: Removable components
 // START: Removable components
 // ---------------------------
 // ---------------------------
 // The following components may be removed if they're not needed.
 // The following components may be removed if they're not needed.
-
 export { EmojiPicker } from './plugins/emoji/index.js';
 export { EmojiPicker } from './plugins/emoji/index.js';
 export { Bookmark, Bookmarks } from './plugins/bookmarks/index.js'; // XEP-0199 XMPP Ping
 export { Bookmark, Bookmarks } from './plugins/bookmarks/index.js'; // XEP-0199 XMPP Ping
 import './plugins/blocklist/index.js';
 import './plugins/blocklist/index.js';
@@ -50,6 +48,7 @@ const constants = Object.assign({}, shared_constants, muc_constants);
 
 
 Object.assign(_converse.constants, constants);
 Object.assign(_converse.constants, constants);
 
 
-export { api, converse, _converse, i18n, log, u, constants, parsers };
+import * as errors from './shared/errors.js';
+export { api, converse, _converse, i18n, log, u, constants, parsers, errors };
 
 
 export default converse;
 export default converse;

+ 6 - 6
src/headless/plugins/smacks/utils.js

@@ -80,12 +80,12 @@ export function initSessionData () {
 }
 }
 
 
 function resetSessionData () {
 function resetSessionData () {
-    _converse.session?.save({
-        'smacks_enabled': false,
-        'num_stanzas_handled': 0,
-        'num_stanzas_handled_by_server': 0,
-        'num_stanzas_since_last_ack': 0,
-        'unacked_stanzas': []
+    u.safeSave(_converse.session, {
+        smacks_enabled: false,
+        num_stanzas_handled: 0,
+        num_stanzas_handled_by_server: 0,
+        num_stanzas_since_last_ack: 0,
+        unacked_stanzas: []
     });
     });
 }
 }
 
 

+ 2 - 2
src/headless/shared/parsers.js

@@ -30,8 +30,8 @@ export async function parseErrorStanza(stanza) {
     const error = stanza.querySelector('error');
     const error = stanza.querySelector('error');
     if (!error) return null;
     if (!error) return null;
 
 
-    const e = sizzle(`[xmlns="${Strophe.NS.STANZAS}"]`, error).pop();
-    const name = e?.nodeName;
+    const els = sizzle(`[xmlns="${Strophe.NS.STANZAS}"]`, error);
+    const name = els.filter((el) => el.nodeName && el.nodeName !== 'text').pop()?.nodeName;
 
 
     /**
     /**
      * *Hook* which allows plugins to add application-specific error parsing
      * *Hook* which allows plugins to add application-specific error parsing

+ 2 - 1
src/headless/types/index.d.ts

@@ -11,9 +11,10 @@ import log from './log.js';
 import u from './utils/index.js';
 import u from './utils/index.js';
 export const constants: typeof shared_constants & typeof muc_constants;
 export const constants: typeof shared_constants & typeof muc_constants;
 import { parsers } from './shared/index.js';
 import { parsers } from './shared/index.js';
+import * as errors from './shared/errors.js';
 import { constants as shared_constants } from './shared/index.js';
 import { constants as shared_constants } from './shared/index.js';
 import * as muc_constants from './plugins/muc/constants.js';
 import * as muc_constants from './plugins/muc/constants.js';
-export { ModelWithMessages, api, converse, _converse, i18n, log, u, parsers };
+export { ModelWithMessages, api, converse, _converse, i18n, log, u, parsers, errors };
 export { Bookmark, Bookmarks } from "./plugins/bookmarks/index.js";
 export { Bookmark, Bookmarks } from "./plugins/bookmarks/index.js";
 export { ChatBox, Message, Messages } from "./plugins/chat/index.js";
 export { ChatBox, Message, Messages } from "./plugins/chat/index.js";
 export { MUCMessage, MUCMessages, MUC, MUCOccupant, MUCOccupants } from "./plugins/muc/index.js";
 export { MUCMessage, MUCMessages, MUC, MUCOccupant, MUCOccupants } from "./plugins/muc/index.js";

+ 17 - 11
src/plugins/register/form.js

@@ -1,4 +1,4 @@
-import { _converse, api, converse, log, constants, u, parsers } from "@converse/headless";
+import { _converse, api, converse, log, constants, u, parsers, errors } from "@converse/headless";
 import tplFormInput from "templates/form_input.js";
 import tplFormInput from "templates/form_input.js";
 import tplFormUrl from "templates/form_url.js";
 import tplFormUrl from "templates/form_url.js";
 import tplFormUsername from "templates/form_username.js";
 import tplFormUsername from "templates/form_username.js";
@@ -329,7 +329,6 @@ class RegistrationForm extends CustomElement {
     /**
     /**
      * Renders the registration form based on the XForm fields
      * Renders the registration form based on the XForm fields
      * received from the XMPP server.
      * received from the XMPP server.
-     * @method _converse.RegistrationForm#renderRegistrationForm
      * @param {Element} stanza - The IQ stanza received from the XMPP server.
      * @param {Element} stanza - The IQ stanza received from the XMPP server.
      */
      */
     renderRegistrationForm (stanza) {
     renderRegistrationForm (stanza) {
@@ -340,13 +339,21 @@ class RegistrationForm extends CustomElement {
     /**
     /**
      * Report back to the user any error messages received from the
      * Report back to the user any error messages received from the
      * XMPP server after attempted registration.
      * XMPP server after attempted registration.
-     * @method _converse.RegistrationForm#reportErrors
      * @param {Element} stanza - The IQ stanza received from the XMPP server
      * @param {Element} stanza - The IQ stanza received from the XMPP server
      */
      */
-    reportErrors (stanza) {
-        const errors = Array.from(stanza.querySelectorAll('error'));
-        if (errors.length) {
-            this.setErrorMessage(errors.reduce((result, e) => `${result}\n${e.textContent}`, ''));
+    async reportErrors (stanza) {
+        const error = await parsers.parseErrorStanza(stanza);
+        if (error instanceof errors.ConflictError) {
+            this.setErrorMessage(
+                `${__('Registration failed.')} ${__('Please try a different username.')}`)
+            return;
+        }
+
+        const error_els = Array.from(stanza.querySelectorAll('error'));
+        if (error_els.length) {
+            this.setErrorMessage(
+                `${__('Registration failed.')}${error_els.reduce((result, e) => `${result}\n${e.textContent}`, '')}`
+            );
         } else {
         } else {
             this.setErrorMessage(__('The provider rejected your registration attempt. '+
             this.setErrorMessage(__('The provider rejected your registration attempt. '+
                 'Please check the values you entered for correctness.'));
                 'Please check the values you entered for correctness.'));
@@ -404,7 +411,7 @@ class RegistrationForm extends CustomElement {
         }
         }
 
 
         const connection = api.connection.get();
         const connection = api.connection.get();
-        connection._addSysHandler(/** @param {Element} iq */(iq) => this._onRegisterIQ(iq), null, "iq", null, null);
+        connection._addSysHandler(/** @param {Element} iq */(iq) => this.#onRegisterIQ(iq), null, "iq", null, null);
         connection.send(iq);
         connection.send(iq);
         this.setFields(iq.tree());
         this.setFields(iq.tree());
     }
     }
@@ -465,13 +472,12 @@ class RegistrationForm extends CustomElement {
      * Callback method that gets called when a return IQ stanza
      * Callback method that gets called when a return IQ stanza
      * is received from the XMPP server, after attempting to
      * is received from the XMPP server, after attempting to
      * register a new user.
      * register a new user.
-     * @method _converse.RegistrationForm#reportErrors
      * @param {Element} stanza - The IQ stanza.
      * @param {Element} stanza - The IQ stanza.
      */
      */
-    _onRegisterIQ (stanza) {
+    #onRegisterIQ (stanza) {
         const connection = api.connection.get();
         const connection = api.connection.get();
         if (stanza.getAttribute("type") === "error") {
         if (stanza.getAttribute("type") === "error") {
-            log.error("Registration failed.");
+            log.info("Registration failed.");
             this.reportErrors(stanza);
             this.reportErrors(stanza);
 
 
             const error_els = stanza.getElementsByTagName("error");
             const error_els = stanza.getElementsByTagName("error");

+ 1 - 1
src/plugins/register/tests/register.js

@@ -551,7 +551,7 @@ describe("The Registration Form", function () {
         _converse.api.connection.get()._dataRecv(mock.createRequest(response_IQ));
         _converse.api.connection.get()._dataRecv(mock.createRequest(response_IQ));
 
 
         const alert = await u.waitUntil(() => view.querySelector('.alert'));
         const alert = await u.waitUntil(() => view.querySelector('.alert'));
-        expect(alert.textContent.trim()).toBe('Too many CAPTCHA requests');
+        expect(alert.textContent.trim()).toBe('Registration failed.\nToo many CAPTCHA requests');
         // Hide the controlbox so that we can see whether the test passed or failed
         // Hide the controlbox so that we can see whether the test passed or failed
         u.addClass('hidden', _converse.chatboxviews.get('controlbox'));
         u.addClass('hidden', _converse.chatboxviews.get('controlbox'));
         _converse.api.connection.destroy();
         _converse.api.connection.destroy();

+ 2 - 11
src/types/plugins/register/form.d.ts

@@ -87,7 +87,6 @@ declare class RegistrationForm extends CustomElement {
     /**
     /**
      * Renders the registration form based on the XForm fields
      * Renders the registration form based on the XForm fields
      * received from the XMPP server.
      * received from the XMPP server.
-     * @method _converse.RegistrationForm#renderRegistrationForm
      * @param {Element} stanza - The IQ stanza received from the XMPP server.
      * @param {Element} stanza - The IQ stanza received from the XMPP server.
      */
      */
     renderRegistrationForm(stanza: Element): void;
     renderRegistrationForm(stanza: Element): void;
@@ -95,10 +94,9 @@ declare class RegistrationForm extends CustomElement {
     /**
     /**
      * Report back to the user any error messages received from the
      * Report back to the user any error messages received from the
      * XMPP server after attempted registration.
      * XMPP server after attempted registration.
-     * @method _converse.RegistrationForm#reportErrors
      * @param {Element} stanza - The IQ stanza received from the XMPP server
      * @param {Element} stanza - The IQ stanza received from the XMPP server
      */
      */
-    reportErrors(stanza: Element): void;
+    reportErrors(stanza: Element): Promise<void>;
     /**
     /**
      * @param {Event} ev
      * @param {Event} ev
      */
      */
@@ -130,14 +128,7 @@ declare class RegistrationForm extends CustomElement {
      * @param {Element} xform
      * @param {Element} xform
      */
      */
     setFieldsFromXForm(xform: Element): void;
     setFieldsFromXForm(xform: Element): void;
-    /**
-     * Callback method that gets called when a return IQ stanza
-     * is received from the XMPP server, after attempting to
-     * register a new user.
-     * @method _converse.RegistrationForm#reportErrors
-     * @param {Element} stanza - The IQ stanza.
-     */
-    _onRegisterIQ(stanza: Element): boolean;
+    #private;
 }
 }
 import { CustomElement } from 'shared/components/element.js';
 import { CustomElement } from 'shared/components/element.js';
 //# sourceMappingURL=form.d.ts.map
 //# sourceMappingURL=form.d.ts.map