diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9cc7ee4..9ec6850c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1399,6 +1399,9 @@ importers: p-map: specifier: ^4.0.0 version: 4.0.0 + promise-retry: + specifier: ^2.0.1 + version: 2.0.1 qs: specifier: ^6.10.3 version: 6.11.0 @@ -1487,6 +1490,9 @@ importers: '@types/oidc-provider': specifier: ^7.8.1 version: 7.11.1 + '@types/promise-retry': + specifier: ^1.1.3 + version: 1.1.3 '@types/send': specifier: ^0.17.1 version: 0.17.1 @@ -12938,6 +12944,12 @@ packages: resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==} dev: false + /@types/promise-retry@1.1.3: + resolution: {integrity: sha512-LxIlEpEX6frE3co3vCO2EUJfHIta1IOmhDlcAsR4GMMv9hev1iTI9VwberVGkePJAuLZs5rMucrV8CziCfuJMw==} + dependencies: + '@types/retry': 0.12.0 + dev: true + /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} @@ -18450,6 +18462,10 @@ packages: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} dev: true + /err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + dev: false + /errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -28303,6 +28319,14 @@ packages: optional: true dev: true + /promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + dev: false + /promise.allsettled@1.0.5: resolution: {integrity: sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==} engines: {node: '>= 0.4'} @@ -31100,6 +31124,11 @@ packages: engines: {node: '>=0.12'} dev: true + /retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + dev: false + /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} diff --git a/server/models/group/invite.ts b/server/models/group/invite.ts index 4e081268..5c7cd295 100644 --- a/server/models/group/invite.ts +++ b/server/models/group/invite.ts @@ -11,6 +11,7 @@ import type { Types } from 'mongoose'; import { nanoid } from 'nanoid'; import { User } from '../user/user'; import { Group } from './group'; +import promiseRetry from 'promise-retry'; function generateCode() { return nanoid(8); @@ -73,9 +74,27 @@ export class GroupInvite extends TimeStamps implements Base { expiredAt = undefined; } + const code = await promiseRetry( + async () => { + const code = generateCode(); + const exists = await this.exists({ code }); + + if (exists) { + throw new Error('Cannot find unused invite code, please try again.'); + } + + return code; + }, + { + minTimeout: 0, + maxTimeout: 0, + retries: 5, + } + ); + const invite = await this.create({ groupId, - code: generateCode(), + code, creator, expiredAt, }); diff --git a/server/package.json b/server/package.json index afb83ce9..57e564c5 100644 --- a/server/package.json +++ b/server/package.json @@ -67,6 +67,7 @@ "nodemailer": "^6.7.2", "oidc-provider": "^7.10.6", "p-map": "^4.0.0", + "promise-retry": "^2.0.1", "qs": "^6.10.3", "redlock": "^4.2.0", "send": "^0.18.0", @@ -98,6 +99,7 @@ "@types/node": "16.11.7", "@types/nodemailer": "^6.4.4", "@types/oidc-provider": "^7.8.1", + "@types/promise-retry": "^1.1.3", "@types/send": "^0.17.1", "@types/serve-static": "^1.15.0", "@types/swagger-jsdoc": "^6.0.1",