Prettied up UI for password resets. Now to move on to email component.

This commit is contained in:
rainbow napkin 2024-12-28 09:17:28 -05:00
parent ed698f40c7
commit 3671b43789
5 changed files with 51 additions and 18 deletions

View file

@ -41,7 +41,7 @@ module.exports.post = async function(req, res){
} }
//Generate the password reset link //Generate the password reset link
const requestDB = await passwordResetModel.generateResetToken(userDB); const requestDB = await passwordResetModel.create({user: userDB._id});
//send successful response //send successful response
res.status(200); res.status(200);

View file

@ -36,7 +36,9 @@ const passwordResetSchema = new mongoose.Schema({
}, },
token: { token: {
type: mongoose.SchemaTypes.String, type: mongoose.SchemaTypes.String,
required: true required: true,
//Use a cryptographically secure algorythm to create a random hex string from 16 bytes as our reset token
default: ()=>{return crypto.randomBytes(16).toString('hex')}
}, },
date: { date: {
@ -47,21 +49,6 @@ const passwordResetSchema = new mongoose.Schema({
}); });
//statics //statics
passwordResetSchema.statics.generateResetToken = async function(userDB){
//Use a cryptographically secure algorythm to create a random hex string from 16 bytes as our reset token
const token = crypto.randomBytes(16).toString('hex');
//Create request object
const request = {
user: userDB._id,
token,
date: new Date()
}
//Create the request entry in the DB and return the newly created record
return await this.create(request);
}
passwordResetSchema.statics.processExpiredRequests = async function(){ passwordResetSchema.statics.processExpiredRequests = async function(){
//Pull all requests from the DB //Pull all requests from the DB
const requestDB = await this.find({}); const requestDB = await this.find({});

View file

@ -380,6 +380,10 @@ select.panel-head-element{
color: var(--danger0); color: var(--danger0);
} }
.popup-div a{
color: var(--accent1);
}
/* tooltip */ /* tooltip */
div.tooltip{ div.tooltip{
background-color: var(--bg1); background-color: var(--bg1);

View file

@ -286,6 +286,7 @@ class adminUserList{
this.userNames = document.querySelectorAll(".admin-user-list-name"); this.userNames = document.querySelectorAll(".admin-user-list-name");
this.rankSelectors = document.querySelectorAll(".admin-user-list-rank-select"); this.rankSelectors = document.querySelectorAll(".admin-user-list-rank-select");
this.banIcons = document.querySelectorAll(".admin-user-list-ban-icon"); this.banIcons = document.querySelectorAll(".admin-user-list-ban-icon");
this.passResetIcons = document.querySelectorAll(".admin-user-list-pw-reset-icon");
this.setupInput(); this.setupInput();
} }
@ -318,6 +319,10 @@ class adminUserList{
for(let banIcon of this.banIcons){ for(let banIcon of this.banIcons){
banIcon.addEventListener("click", this.banPopup.bind(this)); banIcon.addEventListener("click", this.banPopup.bind(this));
} }
for(let passResetIcon of this.passResetIcons){
passResetIcon.addEventListener("click", this.genResetLink.bind(this))
}
} }
async setRank(event){ async setRank(event){
@ -327,6 +332,35 @@ class adminUserList{
this.updateSelect(await adminUtil.setUserRank(user, rank), event.target); this.updateSelect(await adminUtil.setUserRank(user, rank), event.target);
} }
async genResetLink(event){
//Scrape user
const user = event.target.id.replace("admin-user-list-pw-reset-icon-","");
const URL = (await adminUtil.genPasswordResetLink(user)).url;
//Create span
const span = document.createElement('span');
//Usually not into doing CSS this way, but I'm not making a dedicated file for a popup this small...
span.style = "text-align: center; display: block;"
//Create header
const header = document.createElement('h3');
header.innerText = `Reset Link for ${user}`
//Create link
const link = document.createElement('a');
link.innerText = "Reset Link"
link.href = URL;
//Append link to the header
span.appendChild(header);
span.appendChild(link);
//Display link in pop-up
new canopyUXUtils.popup(span.outerHTML);
}
banPopup(event){ banPopup(event){
const user = event.target.id.replace("admin-user-list-ban-icon-",""); const user = event.target.id.replace("admin-user-list-ban-icon-","");
new canopyAdminUtils.banUserPopup(user, userBanList.renderBanList.bind(userBanList)); new canopyAdminUtils.banUserPopup(user, userBanList.renderBanList.bind(userBanList));

View file

@ -169,6 +169,7 @@ class canopyUXUtils{
} }
remove(){ remove(){
this.tooltip.dispatchEvent(new Event("close"));
this.tooltip.remove(); this.tooltip.remove();
} }
} }
@ -259,6 +260,8 @@ class canopyUXUtils{
} }
closePopup(){ closePopup(){
this.popupDiv.dispatchEvent(new Event("close"));
//Take out the popup //Take out the popup
this.popupDiv.remove(); this.popupDiv.remove();
@ -487,8 +490,13 @@ class canopyAjaxUtils{
body: JSON.stringify({token, pass, confirmPass, verification}) body: JSON.stringify({token, pass, confirmPass, verification})
}); });
//If we received a successful response
if(response.status == 200){ if(response.status == 200){
return await response.json(); //Create pop-up
const popup = new canopyUXUtils.popup("Your password has been reset!");
//Go to home-page on pop-up closure
popup.popupDiv.addEventListener("close", ()=>{window.location = '/'});
//Otherwise
}else{ }else{
utils.ux.displayResponseError(await response.json()); utils.ux.displayResponseError(await response.json());
} }