Skip to content

Commit c65cbe2

Browse files
authored
Introduce sId on User and MembershipInvitation (#4561)
* Introduce sId on User and MembershipInvitation * lint * imports
1 parent 5cefe4c commit c65cbe2

File tree

5 files changed

+82
-1
lines changed

5 files changed

+82
-1
lines changed

front/lib/api/invitation.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { sign } from "jsonwebtoken";
1111
import config from "@app/lib/api/config";
1212
import type { Authenticator } from "@app/lib/auth";
1313
import { MembershipInvitation } from "@app/lib/models";
14+
import { generateModelSId } from "@app/lib/utils";
1415

1516
sgMail.setApiKey(config.getSendgridApiKey());
1617

@@ -48,6 +49,7 @@ export async function updateOrCreateInvitation(
4849

4950
return typeFromModel(
5051
await MembershipInvitation.create({
52+
sId: generateModelSId(),
5153
workspaceId: owner.id,
5254
inviteEmail: sanitizeString(inviteEmail),
5355
status: "pending",

front/lib/iam/users.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { trackSignup } from "@app/lib/amplitude/node";
66
import type { ExternalUser, SessionWithUser } from "@app/lib/iam/provider";
77
import { User } from "@app/lib/models/user";
88
import { guessFirstandLastNameFromFullName } from "@app/lib/user";
9+
import { generateModelSId } from "@app/lib/utils";
910

1011
interface LegacyProviderInfo {
1112
provider: UserProviderType;
@@ -130,6 +131,7 @@ export async function createOrUpdateUser(
130131
);
131132

132133
const u = await User.create({
134+
sId: generateModelSId(),
133135
auth0Sub: externalUser.sub,
134136
provider: mapAuth0ProviderToLegacy(session)?.provider,
135137
username: externalUser.nickname,

front/lib/models/user.ts

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class User extends Model<
1717
declare createdAt: CreationOptional<Date>;
1818
declare updatedAt: CreationOptional<Date>;
1919

20+
declare sId: string;
2021
declare auth0Sub: string | null;
2122
declare provider: UserProviderType;
2223
declare providerId: string | null;
@@ -47,6 +48,10 @@ User.init(
4748
allowNull: false,
4849
defaultValue: DataTypes.NOW,
4950
},
51+
sId: {
52+
type: DataTypes.STRING,
53+
allowNull: true,
54+
},
5055
provider: {
5156
type: DataTypes.STRING,
5257
allowNull: true,
@@ -97,6 +102,7 @@ User.init(
97102
{ fields: ["username"] },
98103
{ fields: ["provider", "providerId"] },
99104
{ fields: ["auth0Sub"], unique: true, concurrently: true },
105+
{ unique: true, fields: ["sId"] },
100106
],
101107
}
102108
);

front/lib/models/workspace.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export class MembershipInvitation extends Model<
135135
declare createdAt: CreationOptional<Date>;
136136
declare updatedAt: CreationOptional<Date>;
137137

138+
declare sId: string;
138139
declare inviteEmail: string;
139140
declare status: "pending" | "consumed" | "revoked";
140141
declare initialRole: Exclude<RoleType, "none">;
@@ -159,6 +160,10 @@ MembershipInvitation.init(
159160
allowNull: false,
160161
defaultValue: DataTypes.NOW,
161162
},
163+
sId: {
164+
type: DataTypes.STRING,
165+
allowNull: true,
166+
},
162167
inviteEmail: {
163168
type: DataTypes.STRING,
164169
allowNull: false,
@@ -184,7 +189,10 @@ MembershipInvitation.init(
184189
{
185190
modelName: "membership_invitation",
186191
sequelize: frontSequelize,
187-
indexes: [{ fields: ["workspaceId", "status"] }],
192+
indexes: [
193+
{ fields: ["workspaceId", "status"] },
194+
{ unique: true, fields: ["sId"] },
195+
],
188196
}
189197
);
190198
Workspace.hasMany(MembershipInvitation, {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { MembershipInvitation, User } from "@app/lib/models";
2+
import { generateModelSId } from "@app/lib/utils";
3+
import logger from "@app/logger/logger";
4+
import { makeScript } from "@app/scripts/helpers";
5+
6+
const backfillUsers = async (execute: boolean) => {
7+
const users = await User.findAll({});
8+
9+
const chunks: User[][] = [];
10+
for (let i = 0; i < users.length; i += 16) {
11+
chunks.push(users.slice(i, i + 16));
12+
}
13+
14+
for (let i = 0; i < chunks.length; i++) {
15+
const chunk = chunks[i];
16+
await Promise.all(
17+
chunk.map((u) => {
18+
return (async () => {
19+
const sId = generateModelSId();
20+
logger.info(
21+
`Backfilling user ${u.id} with \`sId=${sId}\` [execute: ${execute}]`
22+
);
23+
24+
if (execute) {
25+
await u.update({ sId });
26+
}
27+
})();
28+
})
29+
);
30+
}
31+
};
32+
33+
const backfillInvitations = async (execute: boolean) => {
34+
const invitations = await MembershipInvitation.findAll({});
35+
36+
const chunks: MembershipInvitation[][] = [];
37+
for (let i = 0; i < invitations.length; i += 16) {
38+
chunks.push(invitations.slice(i, i + 16));
39+
}
40+
41+
for (let i = 0; i < chunks.length; i++) {
42+
const chunk = chunks[i];
43+
await Promise.all(
44+
chunk.map((i) => {
45+
return (async () => {
46+
const sId = generateModelSId();
47+
logger.info(
48+
`Backfilling invitation ${i.id} with \`sId=${sId}\` [execute: ${execute}]`
49+
);
50+
51+
if (execute) {
52+
await i.update({ sId });
53+
}
54+
})();
55+
})
56+
);
57+
}
58+
};
59+
60+
makeScript({}, async ({ execute }) => {
61+
await backfillUsers(execute);
62+
await backfillInvitations(execute);
63+
});

0 commit comments

Comments
 (0)