studiocms
Version:
Astro Native CMS for AstroDB. Built from the ground up by the Astro community.
154 lines (153 loc) • 6.14 kB
JavaScript
import { Password, User } from "studiocms:auth/lib";
import { developerConfig } from "studiocms:config";
import { apiResponseLogger } from "studiocms:logger";
import { Notifications } from "studiocms:notifier";
import { SDKCore } from "studiocms:sdk";
import { z } from "astro/zod";
import {
AllResponse,
createEffectAPIRoutes,
createJsonResponse,
Effect,
genLogger,
OptionsResponse,
readAPIContextJson
} from "../../../effect.js";
const { POST, OPTIONS, ALL } = createEffectAPIRoutes(
{
POST: (ctx) => genLogger("studiocms/routes/api/dashboard/profile.POST")(function* () {
const [pass, userHelper, notify, sdk] = yield* Effect.all([
Password,
User,
Notifications,
SDKCore
]);
if (developerConfig.demoMode !== false) {
return apiResponseLogger(403, "Demo mode is enabled, this action is not allowed.");
}
const userData = ctx.locals.StudioCMS.security?.userSessionData;
if (!userData?.isLoggedIn) {
return apiResponseLogger(401, "Unauthorized");
}
if (!ctx.locals.StudioCMS.security?.userPermissionLevel.isVisitor) {
return apiResponseLogger(403, "Unauthorized");
}
const userProfileUpdate = yield* readAPIContextJson(ctx);
switch (userProfileUpdate.mode) {
case "basic": {
const { data: r } = userProfileUpdate;
const data = r;
if (!data.name) {
return apiResponseLogger(400, "Invalid form data, name is required");
}
if (!data.email) {
return apiResponseLogger(400, "Invalid form data, email is required");
}
if (!data.username) {
return apiResponseLogger(400, "Invalid form data, username is required");
}
const verifyUsernameResponse = yield* userHelper.verifyUsernameInput(data.username);
if (verifyUsernameResponse !== true) {
return apiResponseLogger(400, verifyUsernameResponse);
}
const checkEmail = z.coerce.string().email({ message: "Email address is invalid" }).safeParse(data.email);
if (!checkEmail.success)
return apiResponseLogger(400, `Invalid email: ${checkEmail.error.message}`);
const { usernameSearch, emailSearch } = yield* sdk.AUTH.user.searchUsersForUsernameOrEmail(data.username, checkEmail.data);
if (userData.user?.username !== data.username) {
if (usernameSearch.length > 0)
return apiResponseLogger(400, "Invalid username: Username is already in use");
}
if (userData.user?.email !== data.email) {
if (emailSearch.length > 0)
return apiResponseLogger(400, "Invalid email: Email is already in use");
}
yield* sdk.AUTH.user.update(userData.user.id, data);
return apiResponseLogger(200, "User profile updated successfully");
}
case "password": {
const { data: r } = userProfileUpdate;
const data = r;
const { currentPassword, newPassword, confirmNewPassword } = data;
if (!currentPassword) {
if (userData.user?.password) {
return apiResponseLogger(400, "Invalid form data, current password is required");
}
}
if (!newPassword) {
return apiResponseLogger(400, "Invalid form data, new password is required");
}
if (currentPassword && userData.user?.password) {
const isValid = yield* pass.verifyPasswordHash(
userData.user.password,
currentPassword
);
if (!isValid) {
return apiResponseLogger(400, "Invalid current password");
}
}
if (!confirmNewPassword) {
return apiResponseLogger(400, "Invalid form data, confirm new password is required");
}
if (newPassword !== confirmNewPassword) {
return apiResponseLogger(
400,
"Invalid form data, new password and confirm new password do not match"
);
}
const verifyPasswordResponse = yield* pass.verifyPasswordStrength(newPassword);
if (verifyPasswordResponse !== true) {
return apiResponseLogger(400, verifyPasswordResponse);
}
const userUpdate = {
password: yield* pass.hashPassword(newPassword)
};
if (userData.user)
yield* Effect.all([
sdk.AUTH.user.update(userData.user.id, userUpdate),
notify.sendUserNotification("account_updated", userData.user.id),
notify.sendAdminNotification("user_updated", userData.user.username)
]);
return apiResponseLogger(200, "User password updated successfully");
}
case "avatar": {
if (!userData.user?.email) {
return apiResponseLogger(400, "User email required");
}
if (userData.user)
yield* userHelper.createUserAvatar(userData.user.email).pipe(
Effect.flatMap(
(newAvatar) => Effect.all([
sdk.AUTH.user.update(userData.user.id, { avatar: newAvatar }),
notify.sendUserNotification("account_updated", userData.user.id),
notify.sendAdminNotification("user_updated", userData.user.username)
])
)
);
return apiResponseLogger(200, "User Avatar updated successfully");
}
default:
return apiResponseLogger(400, "Invalid form data, mode is required or unsupported");
}
}).pipe(Notifications.Provide),
OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ["POST"] })),
ALL: () => Effect.try(() => AllResponse())
},
{
cors: { methods: ["POST", "OPTIONS"] },
onError: (error) => {
console.error("API Error:", error);
return createJsonResponse(
{ error: "Internal Server Error" },
{
status: 500
}
);
}
}
);
export {
ALL,
OPTIONS,
POST
};