Skip to content

Commit

Permalink
Account Delete (#146) (#147)
Browse files Browse the repository at this point in the history
  • Loading branch information
devarshishimpi authored Oct 15, 2022
2 parents 63c3cdf + 4e1ce13 commit 25bb178
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 3 deletions.
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

0 comments on commit 25bb178

Please sign in to comment.