fix mail service

This commit is contained in:
Simon Larsen 2022-11-11 20:13:35 +00:00
parent addfc9d69c
commit a0fc136870
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
7 changed files with 203 additions and 158 deletions

View File

@ -36,72 +36,88 @@ const RegisterPage: FunctionComponent = () => {
</div>
<div className="text-center">
<h5 className="mb-0">
Reset Password.
Reset Password.
</h5>
{!isSuccess && <p className="text-muted mt-2 mb-0">
Please enter your new password and we will have it updated.{' '}
</p>}
{!isSuccess && (
<p className="text-muted mt-2 mb-0">
Please enter your new
password and we will have it
updated.{' '}
</p>
)}
{isSuccess && <p className="text-muted mt-2 mb-0">
Your password has been updated. Please log in.
</p>}
{isSuccess && (
<p className="text-muted mt-2 mb-0">
Your password has been
updated. Please log in.
</p>
)}
</div>
{!isSuccess && <ModelForm<User>
modelType={User}
id="register-form"
onBeforeCreate={(item: User) => {
item.resetPasswordToken = Navigation.getLastParam()?.toString().replace("/", "").toString() ||''
return item;
}}
showAsColumns={1}
maxPrimaryButtonWidth={true}
initialValues={{
password: '',
confirmPassword: '',
}}
fields={[
{
field: {
password: true,
{!isSuccess && (
<ModelForm<User>
modelType={User}
id="register-form"
onBeforeCreate={(
item: User
) => {
item.resetPasswordToken =
Navigation.getLastParam()
?.toString()
.replace('/', '')
.toString() || '';
return item;
}}
showAsColumns={1}
maxPrimaryButtonWidth={true}
initialValues={{
password: '',
confirmPassword: '',
}}
fields={[
{
field: {
password: true,
},
fieldType:
FormFieldSchemaType.Password,
validation: {
minLength: 6,
},
placeholder:
'New Password',
title: 'New Password',
required: true,
},
fieldType:
FormFieldSchemaType.Password,
validation: {
minLength: 6,
{
field: {
password: true,
},
validation: {
minLength: 6,
toMatchField:
'password',
},
fieldType:
FormFieldSchemaType.Password,
placeholder:
'Confirm Password',
title: 'Confirm Password',
overideFieldKey:
'confirmPassword',
required: true,
},
placeholder: 'New Password',
title: 'New Password',
required: true,
},
{
field: {
password: true,
},
validation: {
minLength: 6,
toMatchField:
'password',
},
fieldType:
FormFieldSchemaType.Password,
placeholder:
'Confirm Password',
title: 'Confirm Password',
overideFieldKey:
'confirmPassword',
required: true,
},
]}
apiUrl={apiUrl}
formType={FormType.Create}
submitButtonText={'Reset Password'}
onSuccess={() => {
setIsSuccess(true);
}}
/>}
]}
apiUrl={apiUrl}
formType={FormType.Create}
submitButtonText={
'Reset Password'
}
onSuccess={() => {
setIsSuccess(true);
}}
/>
)}
<div className="mt-5 text-center">
<p className="text-muted mb-0">

View File

@ -4,7 +4,7 @@ import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png';
import Link from 'CommonUI/src/Components/Link/Link';
import PageLoader from 'CommonUI/src/Components/Loader/PageLoader';
import ModelAPI from 'CommonUI/src/Utils/ModelAPI/ModelAPI';
import EmailVerificationToken from "Model/Models/EmailVerificationToken"
import EmailVerificationToken from 'Model/Models/EmailVerificationToken';
import { VERIFY_EMAIL_API_URL } from '../Utils/ApiPaths';
import { FormType } from 'CommonUI/src/Components/Forms/ModelForm';
import Navigation from 'CommonUI/src/Utils/Navigation';
@ -17,16 +17,18 @@ const VerifyEmail: FunctionComponent = () => {
const [error, setError] = useState<string>('');
const [isLoading, setIsLoading] = useState<boolean>(true);
const init = async (): Promise<void> => {
const init: Function = async (): Promise<void> => {
// Ping an API here.
setError('');
setIsLoading(true);
try {
// strip data.
const emailverificationToken = new EmailVerificationToken();
emailverificationToken.token = new ObjectID(Navigation.getLastParam()?.toString().replace('/', '') || '');
const emailverificationToken: EmailVerificationToken =
new EmailVerificationToken();
emailverificationToken.token = new ObjectID(
Navigation.getLastParam()?.toString().replace('/', '') || ''
);
await ModelAPI.createOrUpdate<EmailVerificationToken>(
emailverificationToken,
@ -36,24 +38,24 @@ const VerifyEmail: FunctionComponent = () => {
{},
{}
);
} catch (err) {
setError(
(err as HTTPErrorResponse).message ||
'Server Error. Please try again'
'Server Error. Please try again'
);
}
setIsLoading(false);
}
};
useEffect(() => {
init();
}, [])
init().catch((err: Error) => {
setError(err.toString());
});
}, []);
if (isLoading) {
return <PageLoader isVisible={true} />
return <PageLoader isVisible={true} />;
}
return (
@ -76,25 +78,29 @@ const VerifyEmail: FunctionComponent = () => {
src={`/accounts/public/${OneUptimeLogo}`}
/>
</div>
{!error && <div className="text-center">
<h5 className="mb-0">
Your email is verified.
</h5>
<p className="text-muted mt-2 mb-0">
Thank you for veryfing your
email. You can now log in to
OneUptime.{' '}
</p>
</div>}
{!error && (
<div className="text-center">
<h5 className="mb-0">
Your email is verified.
</h5>
<p className="text-muted mt-2 mb-0">
Thank you for veryfing your
email. You can now log in to
OneUptime.{' '}
</p>
</div>
)}
{error && <div className="text-center">
<h5 className="mb-0">
Sorry, something went wrong!
</h5>
<p className="text-muted mt-2 mb-0">
{error}
</p>
</div>}
{error && (
<div className="text-center">
<h5 className="mb-0">
Sorry, something went wrong!
</h5>
<p className="text-muted mt-2 mb-0">
{error}
</p>
</div>
)}
<div className="mt-5 text-center">
<p className="text-muted mb-0">

View File

@ -19,4 +19,4 @@ export const VERIFY_EMAIL_API_URL: URL = URL.fromURL(IDENTITY_URL).addRoute(
export const RESET_PASSWORD_API_URL: URL = URL.fromURL(IDENTITY_URL).addRoute(
new Route('/reset-password')
);
);

View File

@ -116,8 +116,6 @@ class DatabaseService<TBaseModel extends BaseModel> {
protected checkRequiredFields(data: TBaseModel): void {
// Check required fields.
console.log(data);
const relatationalColumns: Dictionary<string> = {};
const tableColumns: Array<string> = data.getTableColumns().columns;
@ -143,12 +141,16 @@ class DatabaseService<TBaseModel extends BaseModel> {
!(data as any)[requiredField] &&
!data.isDefaultValueColumn(requiredField)
) {
const metadata: TableColumnMetadata =
data.getTableColumnMetadata(requiredField);
data.getTableColumnMetadata(requiredField);
if (metadata && metadata.manyToOneRelationColumn && metadata.type === TableColumnType.Entity && data.getColumnValue(metadata.manyToOneRelationColumn)) {
continue;
if (
metadata &&
metadata.manyToOneRelationColumn &&
metadata.type === TableColumnType.Entity &&
data.getColumnValue(metadata.manyToOneRelationColumn)
) {
continue;
}
if (

View File

@ -16,7 +16,7 @@ export default class MailService {
const body: JSONObject = {
...mail,
clusterKey: ClusterKey.toString(),
toEmail: mail.toEmail.toString()
toEmail: mail.toEmail.toString(),
};
if (mailServer) {

View File

@ -56,7 +56,6 @@ router.post(
user.isEmailVerified = false;
}
const alreadySavedUser: User | null = await UserService.findOneBy({
query: { email: user.email! },
select: {
@ -99,20 +98,19 @@ router.post(
});
}
console.log(savedUser);
const generatedToken: ObjectID = ObjectID.generate();
const generatedToken = ObjectID.generate();
const emailVerificationToken = new EmailVerificationToken();
const emailVerificationToken: EmailVerificationToken =
new EmailVerificationToken();
emailVerificationToken.userId = savedUser?.id!;
emailVerificationToken.email = savedUser?.email!;
emailVerificationToken.token = generatedToken;
emailVerificationToken.expires = OneUptimeDate.getOneDayAfter()
emailVerificationToken.expires = OneUptimeDate.getOneDayAfter();
await EmailVerificationTokenService.create({
data: emailVerificationToken,
props: {
isRoot: true
isRoot: true,
},
});
@ -127,7 +125,8 @@ router.post(
Domain,
new Route(AccountsRoute.toString()).addRoute(
'/verify-email/' + generatedToken.toString()
)).toString(),
)
).toString(),
homeUrl: new URL(HttpProtocol, HomeHostname).toString(),
},
}).catch((err: Error) => {
@ -234,45 +233,56 @@ router.post(
try {
const data: JSONObject = req.body['data'];
const token: EmailVerificationToken = EmailVerificationToken.fromJSON(data as JSONObject, EmailVerificationToken) as EmailVerificationToken;
const token: EmailVerificationToken =
EmailVerificationToken.fromJSON(
data as JSONObject,
EmailVerificationToken
) as EmailVerificationToken;
const alreadySavedToken: EmailVerificationToken | null = await EmailVerificationTokenService.findOneBy({
query: { token: token.token! },
select: {
_id: true,
userId: true,
email: true,
expires: true
const alreadySavedToken: EmailVerificationToken | null =
await EmailVerificationTokenService.findOneBy({
query: { token: token.token! },
select: {
_id: true,
userId: true,
email: true,
expires: true,
},
props: {
isRoot: true,
},
});
if (!alreadySavedToken) {
throw new BadDataException(
'Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.'
);
}
if (OneUptimeDate.hasExpired(alreadySavedToken.expires!)) {
throw new BadDataException(
'Link expired. Please try to log in and we will resend you another link which you should be able to verify email with.'
);
}
const user: User | null = await UserService.findOneBy({
query: {
email: token.email!,
_id: token._id!,
},
props: {
isRoot: true,
},
});
if (!alreadySavedToken) {
throw new BadDataException("Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.")
}
if (OneUptimeDate.hasExpired(alreadySavedToken.expires!)) {
throw new BadDataException("Link expired. Please try to log in and we will resend you another link which you should be able to verify email with.")
}
let user = await UserService.findOneBy({
query: {
email: token.email!,
_id: token._id!
},
props: {
isRoot: true
},
select: {
_id: true,
email: true
}
email: true,
},
});
if (!user) {
throw new BadDataException("Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.")
throw new BadDataException(
'Invalid link. Please try to log in and we will resend you another link which you should be able to verify email with.'
);
}
await UserService.updateOneBy({
@ -280,15 +290,13 @@ router.post(
_id: user._id!,
},
data: {
isEmailVerified: true
isEmailVerified: true,
},
props: {
isRoot: true
}
isRoot: true,
},
});
console.log(user.email);
MailService.sendMail({
toEmail: user.email!,
subject: 'Email Verified.',
@ -318,17 +326,21 @@ router.post(
const data: JSONObject = req.body['data'];
const user: User = User.fromJSON(data as JSONObject, User) as User;
await user.password?.hashValue(EncryptionSecret);
const alreadySavedUser: User | null = await UserService.findOneBy({
query: { resetPasswordToken: user.resetPasswordToken as string || '' },
query: {
resetPasswordToken:
(user.resetPasswordToken as string) || '',
},
select: {
_id: true,
password: true,
name: true,
email: true,
isMasterAdmin: true,
resetPasswordExpires: true
resetPasswordExpires: true,
},
props: {
isRoot: true,
@ -336,20 +348,26 @@ router.post(
});
if (!alreadySavedUser) {
throw new BadDataException("Invalid link. Please go to forgot password page again and request a new link.")
throw new BadDataException(
'Invalid link. Please go to forgot password page again and request a new link.'
);
}
if (alreadySavedUser && OneUptimeDate.hasExpired(alreadySavedUser.resetPasswordExpires!)) {
throw new BadDataException("Expired link. Please go to forgot password page again and request a new link.")
if (
alreadySavedUser &&
OneUptimeDate.hasExpired(alreadySavedUser.resetPasswordExpires!)
) {
throw new BadDataException(
'Expired link. Please go to forgot password page again and request a new link.'
);
}
await UserService.updateOneById({
id: alreadySavedUser.id!,
data: {
password: user.password!,
resetPasswordToken: null!,
resetPasswordExpires: null!
resetPasswordExpires: null!,
},
props: {
isRoot: true,
@ -368,7 +386,6 @@ router.post(
});
return Response.sendEmptyResponse(req, res);
} catch (err) {
return next(err);
}
@ -405,24 +422,23 @@ router.post(
});
if (alreadySavedUser) {
if (!alreadySavedUser.isEmailVerified) {
const generatedToken = ObjectID.generate();
const generatedToken: ObjectID = ObjectID.generate();
const emailVerificationToken = new EmailVerificationToken();
const emailVerificationToken:EmailVerificationToken = new EmailVerificationToken();
emailVerificationToken.userId = alreadySavedUser?.id!;
emailVerificationToken.email = alreadySavedUser?.email!;
emailVerificationToken.token = generatedToken;
emailVerificationToken.expires = OneUptimeDate.getOneDayAfter()
emailVerificationToken.expires =
OneUptimeDate.getOneDayAfter();
await EmailVerificationTokenService.create({
data: emailVerificationToken,
props: {
isRoot: true
isRoot: true,
},
});
MailService.sendMail({
toEmail: alreadySavedUser.email!,
subject: 'Please verify email.',
@ -434,14 +450,20 @@ router.post(
Domain,
new Route(AccountsRoute.toString()).addRoute(
'/verify-email/' + generatedToken.toString()
)).toString(),
homeUrl: new URL(HttpProtocol, HomeHostname).toString(),
)
).toString(),
homeUrl: new URL(
HttpProtocol,
HomeHostname
).toString(),
},
}).catch((err: Error) => {
logger.error(err);
});
throw new BadDataException("Email is not verified. We have sent you an email with the verification link. Please do not forget to check spam.")
throw new BadDataException(
'Email is not verified. We have sent you an email with the verification link. Please do not forget to check spam.'
);
}
const token: string = JSONWebToken.sign(

View File

@ -164,7 +164,6 @@ export default class MailService {
to: mail.toEmail.toString(),
subject: mail.subject,
html: mail.body,
});
}