mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
212 lines
6.0 KiB
TypeScript
212 lines
6.0 KiB
TypeScript
"use server";
|
|
|
|
import * as drizzleDb from "@/db";
|
|
import { ServerActionResult } from "@/types/action-type";
|
|
import { render } from "@react-email/render";
|
|
import { UserSchema } from "@/components/wrappers/dashboard/admin/users/user.schema";
|
|
import { extractNameFromEmail } from "@/utils/name-from-email";
|
|
import { generateValidPassword } from "@/utils/password";
|
|
import { auth } from "@/lib/auth/auth";
|
|
import { z } from "zod";
|
|
import { Organization } from "@/db/schema/03_organization";
|
|
import { db } from "@/db";
|
|
import { and, eq } from "drizzle-orm";
|
|
|
|
import { zEmail, zString } from "@/lib/zod";
|
|
import { withUpdatedAt } from "@/db/utils";
|
|
import { userAction } from "@/lib/safe-actions/actions";
|
|
import { addMemberOrganizationAction } from "@/components/wrappers/dashboard/admin/organizations/organization/details/add-member.action";
|
|
import { sendEmail } from "@/lib/email";
|
|
import EmailCreateUser from "@/components/emails/email-create-user";
|
|
import { SignUpUser } from "@/types/auth";
|
|
import { createUserDb } from "@/db/services/user";
|
|
import { User } from "@/db/schema/02_user";
|
|
import { env } from "@/env.mjs";
|
|
|
|
export const createUserAction = userAction
|
|
.schema(UserSchema)
|
|
.action(async ({ parsedInput }): Promise<ServerActionResult<User>> => {
|
|
try {
|
|
const isPasswordAuthEnabled = env.AUTH_EMAIL_PASSWORD_ENABLED === "true";
|
|
let password;
|
|
|
|
const userData: SignUpUser = {
|
|
name: parsedInput.name || extractNameFromEmail(parsedInput.email),
|
|
email: parsedInput.email,
|
|
theme: "dark",
|
|
role: "user",
|
|
};
|
|
|
|
if (isPasswordAuthEnabled) {
|
|
password = generateValidPassword();
|
|
userData.password = password;
|
|
}
|
|
|
|
const newUser = await createUserDb(userData);
|
|
|
|
if (newUser) {
|
|
await sendEmail({
|
|
to: parsedInput.email,
|
|
subject: "Your account is created",
|
|
html: await render(
|
|
EmailCreateUser({
|
|
password: password,
|
|
email: parsedInput.email,
|
|
}),
|
|
),
|
|
});
|
|
|
|
const defaultOrganization = await db.query.organization.findFirst({
|
|
where: eq(drizzleDb.schemas.organization.slug, "default"),
|
|
});
|
|
|
|
if (defaultOrganization) {
|
|
await auth.api.addMember({
|
|
body: {
|
|
userId: newUser.id,
|
|
organizationId: defaultOrganization.id,
|
|
role: "admin",
|
|
},
|
|
});
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
value: newUser,
|
|
actionSuccess: {
|
|
message: "user_created",
|
|
},
|
|
};
|
|
}
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message: "user_created",
|
|
cause: "Unknown error",
|
|
},
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message: "user_created",
|
|
cause: error instanceof Error ? error.message : "Unknown error",
|
|
},
|
|
};
|
|
}
|
|
});
|
|
|
|
export const updateUserAction = userAction
|
|
.schema(
|
|
z.object({
|
|
id: zString(),
|
|
name: zString().optional(),
|
|
email: zEmail(),
|
|
}),
|
|
)
|
|
.action(async ({ parsedInput, ctx }): Promise<ServerActionResult<{}>> => {
|
|
try {
|
|
const [updatedUser] = await db
|
|
.update(drizzleDb.schemas.user)
|
|
.set(
|
|
withUpdatedAt({
|
|
name: parsedInput.name
|
|
? parsedInput.name
|
|
: extractNameFromEmail(parsedInput.email),
|
|
email: parsedInput.email,
|
|
emailVerified: false,
|
|
}),
|
|
)
|
|
.where(eq(drizzleDb.schemas.user.id, parsedInput.id))
|
|
.returning();
|
|
|
|
if (updatedUser) {
|
|
return {
|
|
success: true,
|
|
actionSuccess: {
|
|
message: "user_updated",
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message: "user_updated",
|
|
cause: "Unknown error",
|
|
},
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message: "user_updated",
|
|
cause: error instanceof Error ? error.message : "Unknown error",
|
|
},
|
|
};
|
|
}
|
|
});
|
|
|
|
export const setSuperAdminOwnerOfOrganizationsOwnedByUser = userAction
|
|
.schema(
|
|
z.object({
|
|
userId: z.string(),
|
|
}),
|
|
)
|
|
.action(
|
|
async ({ parsedInput }): Promise<ServerActionResult<Organization[]>> => {
|
|
try {
|
|
const organizationsWhereUserIsMemberAndOwner =
|
|
await db.query.member.findMany({
|
|
where: and(
|
|
eq(drizzleDb.schemas.member.role, "owner"),
|
|
eq(drizzleDb.schemas.member.userId, parsedInput.userId),
|
|
),
|
|
with: {
|
|
organization: true,
|
|
},
|
|
});
|
|
|
|
const superAdminUser = await db.query.user.findFirst();
|
|
if (!superAdminUser) {
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message: "set_super_admin_owner_of_organizations_owned_by_user",
|
|
cause: "Unknown error",
|
|
},
|
|
};
|
|
}
|
|
|
|
for (let { organization } of organizationsWhereUserIsMemberAndOwner) {
|
|
await addMemberOrganizationAction({
|
|
userId: superAdminUser.id,
|
|
organizationId: organization.id,
|
|
role: "owner",
|
|
});
|
|
}
|
|
const organizations = organizationsWhereUserIsMemberAndOwner.map(
|
|
(organizationWhereUserIsMemberAndOwner) =>
|
|
organizationWhereUserIsMemberAndOwner.organization,
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
value: organizations as unknown as Organization[],
|
|
actionSuccess: {
|
|
message: "set_super_admin_owner_of_organizations_owned_by_user",
|
|
},
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
actionError: {
|
|
message:
|
|
"error_set_super_admin_owner_of_organizations_owned_by_user",
|
|
cause: error instanceof Error ? error.message : "Unknown error",
|
|
},
|
|
};
|
|
}
|
|
},
|
|
);
|