Skip to content

Commit

Permalink
Add migration for allowedDomain + helper
Browse files Browse the repository at this point in the history
  • Loading branch information
flvndvd committed Jan 12, 2024
1 parent 46f3e25 commit 6420887
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
53 changes: 53 additions & 0 deletions front/migrations/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import yargs, { Options } from "yargs";
import { hideBin } from "yargs/helpers";

// Define a type for the argument specification object.
export type ArgumentSpecs = {
[key: string]: Options & { type?: "string" | "boolean" | "number" };
};

// Define a type for the worker function.
export type WorkerFunction<T> = (args: T) => Promise<void>;

// Define a utility type to infer the argument types from the argument specs.
export type InferArgs<T> = {
[P in keyof T]: T[P] extends { type: "number" }
? number
: T[P] extends { type: "boolean" }
? boolean
: T[P] extends { type: "string" }
? string
: never;
} & { execute?: boolean };

const defaultArgumentSpecs: ArgumentSpecs = {
execute: {
alias: "e",
describe: "Execute the script",
type: "boolean" as const,
default: false,
},
};

export function makeScript<T extends ArgumentSpecs>(
argumentSpecs: T,
worker: WorkerFunction<InferArgs<T> & { execute: boolean }>
): void {
const argv = yargs(hideBin(process.argv));

const combinedArgumentSpecs = { ...defaultArgumentSpecs, ...argumentSpecs };

// Configure yargs using the provided argument specifications.
Object.entries(combinedArgumentSpecs).forEach(([key, options]) => {
argv.option(key, options);
});
argv
.help("h")
.alias("h", "help")
.parseAsync()
.then((args) => worker(args as InferArgs<T & { execute: boolean }>))
.catch((error) => {
console.error("An error occurred:", error);
process.exit(1);
});
}
70 changes: 70 additions & 0 deletions front/migrations/remove_disposable_allowed_domains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Op } from "sequelize";

import { Membership, User, Workspace } from "@app/lib/models";
import { isDisposableEmailDomain } from "@app/lib/utils/disposable_email_domains";
import { makeScript } from "@app/migrations/helpers";

makeScript({}, async ({ execute }) => {
const workspaces = await Workspace.findAll({
attributes: ["id", "allowedDomain"],
where: {
allowedDomain: {
[Op.not]: null,
[Op.ne]: "",
},
},
});

for (const workspace of workspaces) {
if (!workspace.allowedDomain) {
continue;
}

let newAllowedDomain = null;

// We first check if the domain is disposable,
// If yes, then we remove it.
if (isDisposableEmailDomain(workspace.allowedDomain)) {
newAllowedDomain = null;
} else {
// If no, then we ensure that this domain belongs to their google workspace.
const firstAdminUser = await User.findOne({
include: {
model: Membership,
attributes: [], // Exclude Membership attributes from the final result
where: {
role: "admin", // Adjust as needed, if you're looking for a specific role
},
},
where: {
provider: "google",
},
order: [["createdAt", "ASC"]], // Use ASC for the earliest signup
limit: 1,
});

if (!firstAdminUser) {
console.error(
`Not first admin found for workspace ${workspace.id} -- Skipping.`
);
continue;
}

const [, adminEmailDomain] = firstAdminUser.email.split("@");
if (isDisposableEmailDomain(adminEmailDomain)) {
newAllowedDomain = null;
} else {
newAllowedDomain = adminEmailDomain;
}

console.log(
`>> About to update workspace allowedDomain from ${workspace.allowedDomain} to ${newAllowedDomain} for workspace Id ${workspace.id}`
);

if (execute) {
workspace.allowedDomain = newAllowedDomain;
await workspace.save();
}
}
}
});

0 comments on commit 6420887

Please sign in to comment.