mirror of
https://github.com/nicotsx/zerobyte.git
synced 2026-04-18 13:57:52 -04:00
147 lines
4.3 KiB
TypeScript
147 lines
4.3 KiB
TypeScript
import { select } from "@inquirer/prompts";
|
|
import { Command } from "commander";
|
|
import { eq } from "drizzle-orm";
|
|
import { toMessage } from "~/server/utils/errors";
|
|
import { db } from "../../db/db";
|
|
import { member, organization, sessionsTable, usersTable } from "../../db/schema";
|
|
|
|
const listUsers = () => {
|
|
return db.select({ id: usersTable.id, username: usersTable.username }).from(usersTable);
|
|
};
|
|
|
|
const listOrganizations = () => {
|
|
return db.select({ id: organization.id, name: organization.name, slug: organization.slug }).from(organization);
|
|
};
|
|
|
|
const getUserCurrentOrganization = async (userId: string) => {
|
|
const membership = await db.query.member.findFirst({
|
|
where: { userId },
|
|
with: {
|
|
organization: true,
|
|
},
|
|
});
|
|
return membership;
|
|
};
|
|
|
|
const assignUserToOrganization = async (userId: string, organizationId: string) => {
|
|
const [user] = await db.select().from(usersTable).where(eq(usersTable.id, userId));
|
|
|
|
if (!user) {
|
|
throw new Error("User not found");
|
|
}
|
|
|
|
const [targetOrg] = await db.select().from(organization).where(eq(organization.id, organizationId));
|
|
|
|
if (!targetOrg) {
|
|
throw new Error("Organization not found");
|
|
}
|
|
|
|
const existingMembership = await db.query.member.findFirst({ where: { userId } });
|
|
|
|
db.transaction((tx) => {
|
|
if (existingMembership) {
|
|
tx.update(member).set({ organizationId }).where(eq(member.id, existingMembership.id)).run();
|
|
} else {
|
|
tx.insert(member)
|
|
.values({
|
|
id: Bun.randomUUIDv7(),
|
|
organizationId,
|
|
userId,
|
|
role: "member",
|
|
createdAt: new Date(),
|
|
})
|
|
.run();
|
|
}
|
|
|
|
tx.delete(sessionsTable).where(eq(sessionsTable.userId, userId)).run();
|
|
});
|
|
};
|
|
|
|
export const assignOrganizationCommand = new Command("assign-organization")
|
|
.description("Assign a user to a different organization")
|
|
.option("-u, --username <username>", "Username of the user to assign")
|
|
.option("-o, --organization <organization>", "Organization slug to assign the user to")
|
|
.action(async (options) => {
|
|
console.info("\n🏢 Zerobyte Assign Organization\n");
|
|
|
|
let username = options.username;
|
|
let orgSlug = options.organization;
|
|
|
|
try {
|
|
if (!username) {
|
|
const users = await listUsers();
|
|
|
|
if (users.length === 0) {
|
|
console.error("❌ No users found in the database.");
|
|
console.info(" Please create a user first by starting the application.");
|
|
process.exit(1);
|
|
}
|
|
|
|
username = await select({
|
|
message: "Select user to assign:",
|
|
choices: users.map((u) => ({ name: u.username, value: u.username })),
|
|
});
|
|
}
|
|
|
|
const [user] = await db.select().from(usersTable).where(eq(usersTable.username, username));
|
|
|
|
if (!user) {
|
|
console.error(`\n❌ User "${username}" not found.`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const currentMembership = await getUserCurrentOrganization(user.id);
|
|
|
|
if (!orgSlug) {
|
|
const organizations = await listOrganizations();
|
|
|
|
if (organizations.length === 0) {
|
|
console.error("❌ No organizations found in the database.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const availableOrgs = organizations.filter((org) => org.id !== currentMembership?.organizationId);
|
|
|
|
if (availableOrgs.length === 0) {
|
|
console.error("❌ No other organizations available to assign to.");
|
|
process.exit(1);
|
|
}
|
|
|
|
orgSlug = await select({
|
|
message: "Select organization to assign the user to:",
|
|
choices: availableOrgs.map((o) => ({
|
|
name: `${o.name} (${o.slug})`,
|
|
value: o.slug,
|
|
})),
|
|
});
|
|
}
|
|
|
|
const [targetOrg] = await db.select().from(organization).where(eq(organization.slug, orgSlug));
|
|
|
|
if (!targetOrg) {
|
|
console.error(`\n❌ Organization "${orgSlug}" not found.`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (currentMembership?.organizationId === targetOrg.id) {
|
|
console.error(`\n❌ User "${username}" is already assigned to organization "${targetOrg.name}".`);
|
|
process.exit(1);
|
|
}
|
|
|
|
await assignUserToOrganization(user.id, targetOrg.id);
|
|
|
|
console.info(`\n✅ User "${username}" has been assigned to organization "${targetOrg.name}" successfully.`);
|
|
|
|
if (currentMembership) {
|
|
console.info(` Previous organization: ${currentMembership.organization.name}`);
|
|
}
|
|
|
|
console.info(" All existing sessions have been invalidated.");
|
|
} catch (error) {
|
|
console.error(`\n❌ Failed to assign organization: ${toMessage(error)}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
process.exit(0);
|
|
});
|