diff --git a/Accounts/src/App.tsx b/Accounts/src/App.tsx index a747f211d8..2d7546336a 100644 --- a/Accounts/src/App.tsx +++ b/Accounts/src/App.tsx @@ -11,11 +11,9 @@ import NotFound from './Pages/NotFound'; import SsoLoginPage from './Pages/SsoLogin'; import ForgotPasswordPage from './Pages/ForgotPassword'; import RegisterPage from './Pages/Register'; -import { DASHBOARD_URL } from 'CommonUI/src/Config'; import 'CommonUI/src/Styles/theme.scss'; import Navigation from 'CommonUI/src/Utils/Navigation'; import VerifyEmail from './Pages/VerifyEmail'; -import User from 'CommonUI/src/Utils/User'; import ResetPasswordPage from './Pages/ResetPassword'; function App(): ReactElement { @@ -23,10 +21,6 @@ function App(): ReactElement { Navigation.setLocation(useLocation()); Navigation.setParams(useParams()); - if (User.isLoggedIn()) { - Navigation.navigate(DASHBOARD_URL); - } - return (
diff --git a/Accounts/src/Pages/Login.tsx b/Accounts/src/Pages/Login.tsx index f7bc49930e..084217f399 100644 --- a/Accounts/src/Pages/Login.tsx +++ b/Accounts/src/Pages/Login.tsx @@ -9,9 +9,16 @@ import { LOGIN_API_URL } from '../Utils/ApiPaths'; import URL from 'Common/Types/API/URL'; import { JSONObject } from 'Common/Types/JSON'; import LoginUtil from '../Utils/Login'; +import UserUtil from 'CommonUI/src/Utils/User'; +import Navigation from 'CommonUI/src/Utils/Navigation'; +import { DASHBOARD_URL } from 'CommonUI/src/Config'; const LoginPage: FunctionComponent = () => { const apiUrl: URL = LOGIN_API_URL; + + if (UserUtil.isLoggedIn()) { + Navigation.navigate(DASHBOARD_URL); + } return (
diff --git a/Accounts/src/Pages/Register.tsx b/Accounts/src/Pages/Register.tsx index a12c3ae7db..706692a509 100644 --- a/Accounts/src/Pages/Register.tsx +++ b/Accounts/src/Pages/Register.tsx @@ -7,12 +7,18 @@ import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSc import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png'; import LoginUtil from '../Utils/Login'; import { JSONObject } from 'Common/Types/JSON'; - +import UserUtil from 'CommonUI/src/Utils/User'; +import Navigation from 'CommonUI/src/Utils/Navigation'; +import { DASHBOARD_URL } from 'CommonUI/src/Config'; import URL from 'Common/Types/API/URL'; import { SIGNUP_API_URL } from '../Utils/ApiPaths'; const RegisterPage: FunctionComponent = () => { const apiUrl: URL = SIGNUP_API_URL; + + if (UserUtil.isLoggedIn()) { + Navigation.navigate(DASHBOARD_URL); + } return (
diff --git a/Common/Types/Email/EmailTemplateType.ts b/Common/Types/Email/EmailTemplateType.ts index 36446613d2..6c6830a2b0 100644 --- a/Common/Types/Email/EmailTemplateType.ts +++ b/Common/Types/Email/EmailTemplateType.ts @@ -4,6 +4,7 @@ enum EmailTemplateType { EmailVerified = 'EmailVerified.hbs', PasswordChanged = 'PasswordChanged.hbs', InviteMember = 'InviteMember.hbs', + EmailChanged = 'EmailChanged.hbs' } export default EmailTemplateType; diff --git a/CommonServer/Services/UserService.ts b/CommonServer/Services/UserService.ts index 55e4670179..be92c061c6 100755 --- a/CommonServer/Services/UserService.ts +++ b/CommonServer/Services/UserService.ts @@ -8,9 +8,13 @@ import MailService from './MailService'; import UpdateBy from '../Types/Database/UpdateBy'; import LIMIT_MAX from 'Common/Types/Database/LimitMax'; import EmailTemplateType from 'Common/Types/Email/EmailTemplateType'; -import { Domain, HttpProtocol } from '../Config'; +import { AccountsRoute, Domain, HttpProtocol } from '../Config'; import logger from '../Utils/Logger'; import URL from 'Common/Types/API/URL'; +import EmailVerificationToken from 'Model/Models/EmailVerificationToken'; +import OneUptimeDate from 'Common/Types/Date'; +import EmailVerificationTokenService from './EmailVerificationTokenService'; +import Route from 'Common/Types/API/Route'; export class Service extends DatabaseService { public constructor(postgresDatabase?: PostgresDatabase) { @@ -31,12 +35,16 @@ export class Service extends DatabaseService { props: props, }); } - + protected override async onBeforeUpdate(updateBy: UpdateBy): Promise> { - if (updateBy.data.password) { + + + + if (updateBy.data.password || updateBy.data.email) { const users = await this.findBy({ query: updateBy.query, select: { + _id: true, email: true, }, props: { @@ -46,6 +54,7 @@ export class Service extends DatabaseService { skip: 0 }) + return { updateBy, carryForward: users }; } return { updateBy, carryForward: [] }; @@ -68,6 +77,82 @@ export class Service extends DatabaseService { } } + if (onUpdate && onUpdate.updateBy.data.email) { + + const newUsers = await this.findBy({ + query: onUpdate.updateBy.query, + select: { + _id: true, + email: true, + name: true + }, + props: { + isRoot: true, + }, + limit: LIMIT_MAX, + skip: 0 + }) + + for (const user of onUpdate.carryForward) { + + const newUser = newUsers.find((u) => u._id?.toString() === user._id.toString()); + + if (newUser && newUser.email?.toString() !== user.email.toString()) { + // password changed, send password changed mail + const generatedToken: ObjectID = ObjectID.generate(); + + const emailVerificationToken: EmailVerificationToken = + new EmailVerificationToken(); + emailVerificationToken.userId = user?.id!; + emailVerificationToken.email = newUser?.email!; + emailVerificationToken.token = generatedToken; + emailVerificationToken.expires = OneUptimeDate.getOneDayAfter(); + + await EmailVerificationTokenService.create({ + data: emailVerificationToken, + props: { + isRoot: true, + }, + }); + + MailService.sendMail({ + toEmail: newUser.email!, + subject: 'You have changed your email. Please verify your email.', + templateType: EmailTemplateType.EmailChanged, + vars: { + name: newUser.name!.toString(), + tokenVerifyUrl: new URL( + HttpProtocol, + Domain, + new Route(AccountsRoute.toString()).addRoute( + '/verify-email/' + generatedToken.toString() + ) + ).toString(), + homeUrl: new URL(HttpProtocol, Domain).toString(), + }, + }).catch((err: Error) => { + logger.error(err); + }); + + await this.updateBy({ + query: { + _id: user.id.toString() + }, + data: { + isEmailVerified: false + }, + props: { + isRoot: true, + ignoreHooks: true + } + }); + } + + + + } + } + return onUpdate; } diff --git a/Dashboard/src/Components/Header/UserProfileModal.tsx b/Dashboard/src/Components/Header/UserProfileModal.tsx index 1eff2167e7..0a0cff0331 100644 --- a/Dashboard/src/Components/Header/UserProfileModal.tsx +++ b/Dashboard/src/Components/Header/UserProfileModal.tsx @@ -47,6 +47,7 @@ const UserProfileModal: FunctionComponent = ( 'jeff@example.com', required: true, title: 'Email', + description: 'You will have to verify your email again if you change it' }, { field: { diff --git a/Mail/Templates/EmailChanged.hbs b/Mail/Templates/EmailChanged.hbs new file mode 100644 index 0000000000..26b0c249f6 --- /dev/null +++ b/Mail/Templates/EmailChanged.hbs @@ -0,0 +1,595 @@ + + + + + + + You have changed your email. + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + +
+
+
+ +

You have changed your email. Please verify your email.

+ +
+
+
+
+
+ + + + + + + + + + + + +
+
+
+ + + + Next step would be to verify your email account. Can you please click on 'Verify Email' button which will help us to get your email verified. + + + +
+
+
+
+ + + + + + + + + + + +
+
+
+ + + + + + + + +
+ + Verify Email + +
+ + +
+
+
+
+
+ + + + + + + + + + + +
+
+
+
+
+
+
+ + + + + + + + + + + +
+
+
+ + + Thanks, have a great day. + + + +
+
+
+
+ + + + + + + + + + + +
+
+
+ + + OneUptime Team. + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
 
+
+ + + + \ No newline at end of file