Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account Delete (#146) #147

Merged
merged 2 commits into from
Oct 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/middleware/fetchuser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const dotenv = require('dotenv');

dotenv.config();

const JWT_SECRET = process.env.JWT_SECRET;
const JWT_SECRET = "isadvn2hjk23h4h&%@(jhhj";

const fetchuser = async (req, res, next) => {
const token = await req.header('auth-token');
Expand Down
15 changes: 15 additions & 0 deletions backend/models/DeleteAccount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const mongoose = require('mongoose');
const { Schema } = require('mongoose');

const daSchema = new Schema({
email: {
type: String,
required: true
},
token: {
type: String,
required: true
}
}, {timestamps: true});

module.exports = mongoose.model('daccount', daSchema);
141 changes: 139 additions & 2 deletions backend/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const express = require('express');
const router = express.Router();
const dotenv = require('dotenv');
const UserSchema = require('../models/User');
const NoteSchema = require('../models/Notes');
const daSchema = require('../models/DeleteAccount');
const { body, validationResult } = require('express-validator');
var bcrypt = require('bcryptjs');
var jwt = require('jsonwebtoken');
Expand Down Expand Up @@ -470,6 +472,141 @@ router.put('/login/changepassword',
} catch (error) {
return res.status(500).send("Internal Server Error");
}
})
});











// Route 10: Deleting a user's account: DELETE: http://localhost:8181/api/auth/deleteaccount. Login Required
router.delete('/deleteaccount', fetchuser, async (req, res) => {

try {
const theUser = await UserSchema.findById(req.user.id);
if (!theUser) {
return res.status(404).json({ error: "User not Found" });
}

const daToken = uuidv4();

// Pushing the token with email in the DB
await daSchema.create({
email: theUser.email,
token: daToken
});

// Sending the email with the Delete Account link in it
const transporter = nodemailer.createTransport({
service: 'hotmail',
auth: {
user: "abhinandanwadhwa5@outlook.com",
pass: "Abhi1311"
}
});

const options = {
from: "abhinandanwadhwa5@outlook.com",
to: theUser.email,
subject: 'Delete Noteslify Account',
html: `You are receiving this email because you(maybe someone else) wanted to delete your account permanently.\nIf it was not you, ignore this email.If you requested to delete your account, please go to the following link: <a href='http://localhost:3000/deleteacocunt/${theUser.email}/${daToken}'>Click Here</a>`
};

transporter.sendMail(options, (err, info) => {
if (err) {
console.log(err);
return res.status(400).json({ error: "Internal Server Error!" });
}
console.log(info.response);
res.status(200).json({ success: "An Email has been sent to your mail account for confirmation" });
});


} catch (error) {
console.error(error);
return res.status(500).json({ error: "Internal Server Error" });
}


});











// Route 11: Getting a specific daEntry: GET: http://localhost:8181/api/auth/getdatoken. Login Required
router.get('/getdatoken/:id', fetchuser, async (req, res) => {
try {
const token = await daSchema.findOne({ token: req.params.id });
const theUser = await UserSchema.findById(req.user.id);

if (!token) {
return res.status(404).json({ error: "No such token found" });
}
if (theUser.email !== token.email) {
return res.status(403).json({ error: "You cannot access some other person's token" });
}

res.status(200).json(token);

} catch (error) {
console.error(error);
return res.status(500).json({ error: "Internal Server Error" });
}


});











// Route 12: Deleting the user permanently: GET: http://localhost:8181/api/auth/deletepermanently/:id. Login Required
router.delete('/permanentlydelete/:id/:email', async (req, res) => {
try {
const token = await daSchema.findOne({ token: req.params.id });
const theUser = await UserSchema.findOne({ email: req.params.email });

let checkHash = await bcrypt.compare(req.body.password, theUser.password);
if (!checkHash) {
return res.status(403).json({ error: "Wrong Password!" });
}

if (!token) {
return res.status(404).json({ error: "No such token found" });
}
if (theUser.email !== token.email) {
return res.status(403).json({ error: "You cannot access some other person's token" });
}

await NoteSchema.deleteMany({ authorId: theUser.id });
await theUser.delete();

res.status(200).json({ success: "The user has been deleted successfully!!" });

} catch (error) {
console.error(error);
return res.status(500).json({ error: "Internal Server Error" });
}
});



module.exports = router;
module.exports = router;
2 changes: 2 additions & 0 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ErrorPage from './components/Error/ErrorPage';
import AOS from "aos";
import "aos/dist/aos.css";
import { useEffect } from 'react';
import Deleteaccount from './components/DeleteAccount/Deleteaccount';

function App() {
useEffect(() => {
Expand All @@ -36,6 +37,7 @@ function App() {
<Route path="/bin" element={<RecycleBin />} />
<Route path="/myaccount" element={<Account />} />
<Route path='*' element={<ErrorPage />} />
<Route path='/deleteacocunt/:email/:token' element={<Deleteaccount />} />
</Routes>
</Router>
);
Expand Down
36 changes: 36 additions & 0 deletions frontend/src/components/Account/Account.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ const Account = () => {
}
};


const deleteAccount = async () => {
if (window.confirm("Are you sure you want to delete your account?")) {
const authtoken = sessionStorage.getItem('auth-token');
const response = await fetch('http://localhost:8181/api/auth/deleteaccount', {
method: "DELETE",
headers: {
'Content-Type': 'application/json',
'auth-token': authtoken
}
});
const json = await response.json();
console.log(json);
if (json.success) {
toast.success(json.success);
}
else {
toast.error(json.error);
}
}
}

return (
<>
<Helmet>
Expand Down Expand Up @@ -172,8 +194,22 @@ const Account = () => {
</div>
<p>Change Password</p>
</li>

<li
onClick={() => {
deleteAccount();
}}
className="add-box"
>
<div className="icon">
<i className="fa-solid fa-key"></i>
</div>
<p>Delete Account</p>
</li>
</div>



<ToastContainer
toastStyle={{ backgroundColor: "#202d40", color: "white" }}
/>
Expand Down
82 changes: 82 additions & 0 deletions frontend/src/components/DeleteAccount/Deleteaccount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, { useEffect, useState } from 'react'
import { Helmet } from 'react-helmet';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

const Deleteaccount = () => {
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);

const { token, email } = useParams();

const navigate = useNavigate();

useEffect(() => {

}, []);


const deletePermanently = async (e) => {
e.preventDefault();

const response = await fetch(`http://localhost:8181/api/auth/permanentlydelete/${token}/${email}`, {
method: "DELETE",
headers: {
'Content-Type': 'application/json'
}, body: JSON.stringify({ password: password })
});
const json = await response.json();
if (json.success) {
localStorage.removeItem('auth-token');
toast.success(json.success);
setTimeout(() => {
navigate('/login');
}, 2000);
}
else {
toast.error(json.error);
}
}
return (
<>
{/* <form onSubmit={deletePermanently}>
<input value={password} onChange={(e) => setPassword(e.target.value)} type="password" />
<button>Delete Permanently</button>
</form>
<ToastContainer
toastStyle={{ backgroundColor: "#202d40", color: "white" }}
/> */}

<div>
<Helmet>
<title>Noteslify | Delete Account</title>
<meta name="description" content="Noteslify. Reset Your Password From Here." />
</Helmet>
<div className="form-wrapper">
<h1>Delete User?</h1>
<br></br>
<p>Please confirm your password to delete your account permanently</p>
<br></br>
<form onSubmit={deletePermanently}>
<div className="form-item">
<label for="password"></label>
<input type="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)} required="required" placeholder="Confirm Password"></input>
</div>
<div className="button-panel">
{!isLoading && <input type="submit" className="button" title="Sign In" value="Delete User"></input>}
{isLoading && <button style={{backgroundColor: '#15203a', cursor: 'not-allowed'}} disabled={true} className="button" value=""><span className="loader"></span></button>}
</div>
</form>
<div className="form-footer">
<p>Remember Your Password? <Link to="/login">Login</Link></p>
</div>
</div>
<ToastContainer toastStyle={{ backgroundColor: "#202d40", color: 'white' }} />
</div>

</>
)
}

export default Deleteaccount