diff --git a/pages/api/email.ts b/pages/api/email.ts
index 68fcb22..0a0cfb4 100644
--- a/pages/api/email.ts
+++ b/pages/api/email.ts
@@ -34,7 +34,8 @@ export default async function handler(req, res) {
// Retrieve and validate the JWT token
//response is a special action that does not require a token
- if (action == "email_response") {
+ //PUBLIC
+ if (action == "email_response" || action == "account") {
switch (emailaction) {
case "coverMeAccept":
//validate shiftId and assignmentId
@@ -201,6 +202,83 @@ export default async function handler(req, res) {
});
break;
+
+ case "resetPassword":
+ // Send password reset form to the user
+ //parse the request body
+
+ let email = req.body.email || req.query.email;
+ let actualUser = await prisma.publisher.findUnique({
+ where: {
+ email: email
+ }
+ });
+ if (!actualUser) {
+ return res.status(200).json({ message: "Няма потребител с този имейл" });
+ }
+ else {
+ let requestGuid = req.query.guid;
+ if (!requestGuid) {
+ console.log("User: " + email + " requested a password reset");
+ let requestGuid = uuidv4();
+ //save the request in the database as EventLog
+ let eventLog = await prisma.eventLog.create({
+ data: {
+ date: new Date(),
+ publisher: { connect: { id: actualUser.id } },
+ type: EventLogType.PasswordResetRequested,
+ content: JSON.stringify({ guid: requestGuid })
+ }
+ });
+ logger.info("User: " + email + " requested a password reset. EventLogId: " + eventLog.id + "");
+
+ let model = {
+ email: email,
+ firstName: actualUser.firstName,
+ lastName: actualUser.lastName,
+ resetUrl: process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=resetPassword&guid=" + requestGuid + "&email=" + email,
+ sentDate: common.getDateFormated(new Date())
+ };
+ emailHelper.SendEmailHandlebars(to, "resetPassword", model);
+ res.status(200).json({ message: "Password reset request sent" });
+ }
+ else {
+ //1. validate the guid
+ let eventLog = await prisma.eventLog.findFirst({
+ where: {//can we query "{ guid: requestGuid }"?
+ type: EventLogType.PasswordResetRequested,
+ publisherId: actualUser.id,
+ date: {
+ gt: new Date(new Date().getTime() - 24 * 60 * 60 * 1000) //24 hours
+ }
+ }
+ });
+
+ if (!eventLog) {
+ return res.status(400).json({ message: "Invalid or expired password reset request" });
+ }
+ else {
+ let eventLog = await prisma.eventLog.update({
+ where: {
+ id: parseInt(requestGuid)
+ },
+ data: {
+ type: EventLogType.PasswordResetEmailConfirmed
+ }
+ });
+ //2. redirect to the password reset page
+ const messagePageUrl = `/auth/reset-password?email=${email}&resetToken=${requestGuid}`;
+ res.redirect(messagePageUrl);
+ }
+
+ //2.login the user
+
+ //3. redirect to the password reset page
+ }
+
+ }
+ break;
+
}
// //send email response to the user
// const emailResponse = await common.sendEmail(user.email, "Email Action Processed",
@@ -220,6 +298,7 @@ export default async function handler(req, res) {
}
});
+ //PRIVATE ACTIONS
switch (action) {
case "sendCoverMeRequestByEmail":
// Send CoverMe request to the users
diff --git a/pages/auth/reset-password.tsx b/pages/auth/reset-password.tsx
new file mode 100644
index 0000000..82f8a4a
--- /dev/null
+++ b/pages/auth/reset-password.tsx
@@ -0,0 +1,135 @@
+import { use, useEffect, useState } from 'react';
+import Layout from '../../components/layout';
+import axiosInstance from "../../src/axiosSecure";
+import common from '../../src/helpers/common';
+import { EventLogType } from '@prisma/client';
+import { useRouter } from "next/router";
+
+export default function ResetPassword(req, res) {
+ const [email, setEmail] = useState('');
+ const [message, setMessage] = useState('');
+ const [resetToken, setResetToken] = useState(req.query?.resetToken || '');
+ const [isConfirmed, setIsConfirmed] = useState(false);
+ const router = useRouter();
+
+
+ useEffect(async () => {
+ if (resetToken) {
+ const prisma = common.getPrismaClient();
+ let eventLog = await prisma.eventLog.findUnique({
+ where: {
+ content: resetToken,
+ type: EventLogType.PasswordResetEmailConfirmed,
+ date: {
+ gt: new Date(new Date().getTime() - 24 * 60 * 60 * 1000) //24 hours
+ }
+ }
+ });
+ if (eventLog) {
+ setIsConfirmed(true);
+ }
+ }
+ }, [resetToken]);
+
+ const handleResetRequest = async (event) => {
+ event.preventDefault();
+ // Call your email API endpoint here
+ try {
+ const response = await axiosInstance.post('/api/email?action=account&emailaction=resetPassword', { email },
+ { headers: { 'Content-Type': 'application/json' } });
+ if (response.data.message) {
+ setMessage(response.data.message);
+ } else {
+ if (response.ok) {
+ setMessage('Провери твоя имейл за инструкции как да промениш паролата си.');
+ } else {
+ if (response.error) {
+ setMessage(response.error);
+ }
+ }
+ }
+ } catch (error) {
+ setMessage(error.message);
+ }
+ };
+
+ const setNewPassword = async (event) => {
+ event.preventDefault();
+
+ try {
+ const prisma = common.getPrismaClient();
+ const user = await prisma.user.findUnique({
+ where: {
+ email
+ }
+ });
+ if (!user) {
+ throw new Error('Няма потребител с този имейл.');
+ }
+
+ const passHash = await crypto.hash(event.target.newPassword.value, 10);
+ await prisma.user.update({
+ where: {
+ email
+ },
+ data: {
+ passwordHashLocalAccount: passHash
+ }
+ });
+ setMessage('Паролата беше успешно променена.');
+ router.push('/auth/signin');
+
+ } catch (error) {
+ setMessage(error.message);
+ }
+ }
+
+
+ return (
+
+
+
+
Променете паролата си
+
+
+
+
+ );
+}
diff --git a/pages/auth/signin.tsx b/pages/auth/signin.tsx
index 0326411..632f9ae 100644
--- a/pages/auth/signin.tsx
+++ b/pages/auth/signin.tsx
@@ -15,7 +15,7 @@ export default function SignIn({ csrfToken }) {
// Perform client-side validation if needed
if (!email || !password) {
- setError('All fields are required');
+ setError('Всички полета са задължителни');
return;
}
@@ -45,49 +45,52 @@ export default function SignIn({ csrfToken }) {
-
-
- {/* Button to sign in with Google */}
-
diff --git a/prisma/migrations/20240429233926_add_eventlog_types/migration.sql b/prisma/migrations/20240429233926_add_eventlog_types/migration.sql
new file mode 100644
index 0000000..bb47961
--- /dev/null
+++ b/prisma/migrations/20240429233926_add_eventlog_types/migration.sql
@@ -0,0 +1,5 @@
+-- AlterTable
+ALTER TABLE `Eventlog`
+MODIFY `type` ENUM(
+ 'AssignmentReplacementRequested', 'AssignmentReplacementAccepted', 'SentEmail', 'PasswordResetRequested', 'PasswordResetEmailConfirmed', 'PasswordResetCompleted'
+) NOT NULL;
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 03d8a40..6fcc599 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -263,6 +263,9 @@ enum EventLogType {
AssignmentReplacementRequested
AssignmentReplacementAccepted
SentEmail
+ PasswordResetRequested
+ PasswordResetEmailConfirmed
+ PasswordResetCompleted
}
model EventLog {
diff --git a/src/templates/emails/resetPass.hbs b/src/templates/emails/resetPass.hbs
new file mode 100644
index 0000000..15b0125
--- /dev/null
+++ b/src/templates/emails/resetPass.hbs
@@ -0,0 +1,22 @@
+{{!-- Subject: ССОМ: Нужен е заместник--}}
+{{!-- Text: Plain text version of your email. If not provided, HTML tags will be stripped from the HTML version for the
+text version. --}}
+
+
+
Промяна на парола
+
Здравей, {{firstName}} {{lastName}}
+
+ Получихме заявка за промяна на паролата на твоя акаунт. Ако това не си ти, моля игнорирай този имейл.
+