src/core/controllers/users/users.ts
import { isBefore } from "date-fns";
import { footer } from "../../../html";
import { GENERAL_ERROR, PASSWORD_ERROR, SUCCESS } from "../../strings";
import {
transporter,
mailOptions,
saltHashPassword,
signJwt,
sendMailCallback,
} from "../../utils";
import { getWebsite } from "../websites";
import { getUser } from "./find";
import {
updateScanAttempt,
toggleAlert,
verifyUser,
forgotPassword,
confirmEmail,
unsubscribeEmails,
resetPassword,
validateEmail,
addPaymentSubscription,
cancelSubscription,
downgradeStripeUserValues,
} from "./update";
import { createUser } from "./set";
import type { UserControllerType } from "./types";
import { sendEmailConfirmation } from "./update/confirm-email";
import { usersCollection } from "../../../database";
export const UsersController: UserControllerType = (
{ user: _user } = { user: null }
) => ({
getCollection: usersCollection,
getUser,
verifyUser,
createUser,
addPaymentSubscription,
cancelSubscription,
downgradeStripeUserValues,
updateFilterEmailDates: async ({
id,
emailFilteredDates,
morning = false,
}) => {
const [user, collection] = await getUser({ id });
if (user) {
await collection.updateOne(
{ id },
{
$set: {
emailFilteredDates,
emailMorningOnly: morning,
},
}
);
return {
user,
code: 200,
success: true,
message: SUCCESS,
};
}
throw new Error(GENERAL_ERROR);
},
updateUser: async ({ password, email, newPassword, userId }) => {
const authed = typeof userId !== "undefined";
const [user, collection] = await getUser(
authed ? { id: userId } : { email }
);
if (!user) {
throw new Error("Error user not found.");
}
let sendData = authed;
// default props set to user defaults
let updateProps = {
jwt: user.jwt,
password: user.password,
salt: user.salt,
email: user.email,
emailConfirmed: user.emailConfirmed,
};
// update password
if (password) {
const salthash = await saltHashPassword(password, user?.salt);
const authless = !user?.password && !user?.googleId;
if (user?.password && user.password !== salthash?.passwordHash) {
throw new Error(PASSWORD_ERROR);
}
// TODO: SEPERATE PASSWORD RESETTING
if (
newPassword &&
(user?.password === salthash?.passwordHash || authless)
) {
const jwt = await signJwt({
email,
role: user?.role,
keyid: user?.id,
});
const newSaltHash = await saltHashPassword(newPassword);
// set new auth props
updateProps = {
...updateProps,
jwt,
password: newSaltHash?.passwordHash,
salt: newSaltHash?.salt,
};
}
sendData = true;
}
// prevent invalid updates
if (sendData) {
// set new user email
if (email && email !== user.email) {
// send confirmation email
updateProps = {
...updateProps,
email,
emailConfirmed: false,
};
await sendEmailConfirmation(user, collection);
}
}
await collection.updateOne(
{ id: userId },
{
$set: updateProps,
}
);
return sendData
? {
user: {
...user,
...updateProps,
},
jwt: updateProps.jwt, // todo: remove jwt from direct return for user.jwt
code: 200,
success: true,
message: SUCCESS,
}
: {
user: null,
jwt: "", // todo: remove jwt from direct return for user.jwt
code: 200,
success: false,
message: GENERAL_ERROR,
};
},
forgotPassword,
resetPassword,
toggleAlert,
confirmEmail,
updateScanAttempt,
validateEmail,
unsubscribeEmails,
sendWebsiteOffline: async ({ id, domain }) => {
const [user, collection] = await getUser({ id });
if (user?.alertEnabled === false || !domain) {
return false;
}
const [website, websiteCollection] = await getWebsite({
userId: id,
domain,
});
if (website) {
await websiteCollection.findOneAndUpdate(
{ userId: id, domain: domain },
{
$set: {
online: false,
},
}
);
}
let shouldEmail = false;
if (user?.downAlerts?.length) {
const newAlerts = user?.downAlerts?.map((item: any) => {
if (
item.domain === domain &&
isBefore(new Date(), new Date(item?.date))
) {
shouldEmail = true;
item.date = new Date().toUTCString();
}
return item;
});
if (shouldEmail) {
await collection.findOneAndUpdate(
{ id: id },
{
$set: {
downAlerts: newAlerts,
},
}
);
}
} else {
const downAlerts = [{ domain, date: new Date().toUTCString() }];
shouldEmail = true;
await collection.findOneAndUpdate(
{ id: id },
{
$set: {
downAlerts,
},
}
);
}
if (shouldEmail) {
transporter.sendMail(
{
from: mailOptions.from,
text: mailOptions.text,
to: user.email,
subject: `${domain} is Offline.`,
html: `<h1>${domain} is currently offline.</h1><br /><p>Please check your server logs to see what happened if issues are difficult to figure out.</p><br />${footer.marketing(
{ userId: id, email: user?.email }
)}`,
},
sendMailCallback
);
}
},
setPageSpeedKey: async ({ id, pageSpeedApiKey }) => {
const [user, collection] = await getUser({ id });
if (user) {
await collection.updateOne(
{ id },
{
$set: {
pageSpeedApiKey,
},
}
);
user.pageSpeedApiKey = pageSpeedApiKey;
return {
user,
code: 200,
success: true,
message: SUCCESS,
};
}
throw new Error(GENERAL_ERROR);
},
});