mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-12 08:47:40 -05:00
everything switched over, time to test
This commit is contained in:
@@ -5,34 +5,34 @@
|
||||
|
||||
const LocalStrategy = require("passport-local").Strategy;
|
||||
const User = require("../../models/user");
|
||||
/*
|
||||
By default, LocalStrategy expects to find credentials in parameters named username and password.
|
||||
If your site prefers to name these fields differently, options are available to change the defaults.
|
||||
*/
|
||||
/*
|
||||
By default, LocalStrategy expects to find credentials in parameters named username and password.
|
||||
If your site prefers to name these fields differently, options are available to change the defaults.
|
||||
*/
|
||||
const local = new LocalStrategy({
|
||||
usernameField: "email"
|
||||
}, (email, password, done) => {
|
||||
User.findOne({
|
||||
$or: [{
|
||||
email
|
||||
}, {
|
||||
local: {
|
||||
email
|
||||
}
|
||||
}]
|
||||
}, (err, user) => {
|
||||
if(!user) {
|
||||
console.error("Auth Error - user not found: " + email);
|
||||
return done(null, false, { message: `Invalid email or password` })
|
||||
usernameField: "email"
|
||||
}, async (email, password, done) => {
|
||||
console.log(`${email} ${password}`);
|
||||
const user = await User.findOne({
|
||||
$or: [{
|
||||
email
|
||||
}, {
|
||||
local: {
|
||||
email
|
||||
}
|
||||
}]
|
||||
});
|
||||
if (!user) {
|
||||
console.error("Auth Error - user not found: " + email);
|
||||
return done(null, false, { message: `Invalid email or password` })
|
||||
}
|
||||
user.comparePassword(password, (err, isMatch) => {
|
||||
if (isMatch) {
|
||||
return done(null, user)
|
||||
} else {
|
||||
console.error("Auth Error - password mismatch: " + email);
|
||||
return done(null, false, { message: "Invalid email or password" })
|
||||
}
|
||||
user.comparePassword(password, (err, isMatch) => {
|
||||
if (isMatch) {
|
||||
return done(null, user)
|
||||
} else {
|
||||
console.error("Auth Error - password mismatch: " + email);
|
||||
return done(null, false, { message: "Invalid email or password" })
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
module.exports = local;
|
||||
@@ -17,7 +17,7 @@ const mailjet = new Mailjet({
|
||||
|
||||
|
||||
|
||||
exports.isLoggedIn = function(req, res, next) {
|
||||
exports.isLoggedIn = function (req, res, next) {
|
||||
if (req.isAuthenticated()) return next();
|
||||
res.redirect("/login");
|
||||
};
|
||||
@@ -25,7 +25,7 @@ exports.isLoggedIn = function(req, res, next) {
|
||||
// -------------------------------------------
|
||||
|
||||
|
||||
exports.authenticated = function(req, res, next) {
|
||||
exports.authenticated = function (req, res, next) {
|
||||
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
|
||||
console.log("account/server/controllers/users.js - exports.authenticated() Auth check for user: " + req.user + " is: " + req.isAuthenticated());
|
||||
if (req.isAuthenticated()) {
|
||||
@@ -60,11 +60,13 @@ exports.authenticated = function(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.login = function(req, res, next) {
|
||||
exports.login = function (req, res, next) {
|
||||
// Do email and password validation for the server
|
||||
passport.authenticate("local", function(err, user, info) {
|
||||
|
||||
passport.authenticate("local", function (err, user, info) {
|
||||
if (err) return next(err);
|
||||
if (!user) {
|
||||
console.log("No user");
|
||||
return res.json({
|
||||
success: false,
|
||||
message: info.message
|
||||
@@ -81,6 +83,7 @@ exports.login = function(req, res, next) {
|
||||
req.login(user, loginErr => {
|
||||
|
||||
if (loginErr) {
|
||||
console.log("error")
|
||||
return res.json({
|
||||
success: false,
|
||||
message: loginErr
|
||||
@@ -124,199 +127,217 @@ exports.login = function(req, res, next) {
|
||||
})(req, res, next);
|
||||
};
|
||||
|
||||
exports.confirmEmail = function(req, res, next) {
|
||||
exports.confirmEmail = async function (req, res, next) {
|
||||
const userId = req.params["userId"];
|
||||
const token = req.params["token"];
|
||||
|
||||
User.findById(userId, (err, user) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.confirmEmail) {
|
||||
console.log("User already confirmed email: " + userId);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "already confirmed email"
|
||||
});
|
||||
return;
|
||||
}
|
||||
const today = new Date();
|
||||
if (user.confirmEmailTTL < today) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token expired"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.confirmEmailToken != token) {
|
||||
console.log(
|
||||
"Token Mismatch DB: " + user.confirmEmailToken + " submitted: " + token
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token mismatch"
|
||||
});
|
||||
return;
|
||||
}
|
||||
user.confirmEmail = true;
|
||||
user.confirmEmailToken = "";
|
||||
user.save(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("User: " + user.email + " confirmed email address");
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
let user = await User.findById(userId).catch(err => {
|
||||
console.error(err);
|
||||
res.status(404);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
console.error("User not found: " + userId);
|
||||
res.status(404);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "User not found"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.confirmEmail) {
|
||||
console.log("User already confirmed email: " + userId);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "already confirmed email"
|
||||
});
|
||||
return;
|
||||
}
|
||||
const today = new Date();
|
||||
if (user.confirmEmailTTL < today) {
|
||||
res.status(500);
|
||||
console.error("Expired token for confirming email: " + userId);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token expired"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.confirmEmailToken != token) {
|
||||
console.error(
|
||||
"Token Mismatch DB: " + user.confirmEmailToken + " submitted: " + token
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token mismatch"
|
||||
});
|
||||
return;
|
||||
}
|
||||
user.confirmEmail = true;
|
||||
user.confirmEmailToken = "";
|
||||
await user.save().catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
console.log("User: " + user.email + " confirmed email address");
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.resetPassword = function(req, res, next) {
|
||||
exports.resetPassword = async function (req, res, next) {
|
||||
const userId = req.params["userId"];
|
||||
const token = req.params["token"];
|
||||
|
||||
User.findById(userId, (err, user) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
if (user.resetPasswordTTL < today) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token expired"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.resetPasswordToken != token) {
|
||||
console.log(
|
||||
"Token Mismatch DB: " + user.resetPasswordToken + " submitted: " + token
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token mismatch"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
user.password = req.body.password
|
||||
user.confirmEmail = true;
|
||||
user.confirmEmailToken = "";
|
||||
user.resetPasswordToken = "";
|
||||
user.save(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
let user = await User.findById(userId).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
console.error("User not found: " + userId);
|
||||
res.status(404);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "User not found"
|
||||
});
|
||||
return;
|
||||
}
|
||||
const today = new Date();
|
||||
if (user.resetPasswordTTL < today) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token expired"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (user.resetPasswordToken != token) {
|
||||
console.log(
|
||||
"Token Mismatch DB: " + user.resetPasswordToken + " submitted: " + token
|
||||
);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "token mismatch"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
user.password = req.body.password
|
||||
user.confirmEmail = true;
|
||||
user.confirmEmailToken = "";
|
||||
user.resetPasswordToken = "";
|
||||
await user.save().catch(err => {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
exports.sendResetPassword = function(req, res, next) {
|
||||
User.findOne({
|
||||
exports.sendResetPassword = async function (req, res, next) {
|
||||
let user = await User.findOne({
|
||||
email: req.body.email
|
||||
}, (err, user) => {
|
||||
if (err) {
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
if (!user) {
|
||||
console.error("Reset password failed. No user: " + req.body.email);
|
||||
res.status(404);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "No account register for " + req.body.email
|
||||
});
|
||||
return;
|
||||
}
|
||||
const buffer = crypto.randomBytes(20);
|
||||
const token = buffer.toString("hex");
|
||||
var tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordTTL = tomorrow;
|
||||
await user.save().catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
const request = mailjet.post("send", {
|
||||
version: "v3.1"
|
||||
}).request({
|
||||
Messages: [{
|
||||
From: {
|
||||
Email: admin_email,
|
||||
Name: site_name + " Admin"
|
||||
},
|
||||
To: [{
|
||||
Email: user.email,
|
||||
Name: user.firstName + " " + user.lastName
|
||||
}],
|
||||
Subject: site_name + " - Password Reset",
|
||||
TextPart: "It looks like you may have forgot your password. Copy this link to your browser to reset your password. Let us know if you are receiving this but did not request a password reset. /r" + account_server + "/reset-password/" + user.id + "/" + token,
|
||||
HTMLPart: "<h3>Thanks for using " + site_name + "!</h3><br />It looks like you may have forgot your password. Copy this link to your browser to reset your password. Let us know if you are receiving this but did not request a password reset.<p>" + account_server + "/reset-password/" + user.id + "/" + token + "</p>"
|
||||
}]
|
||||
});
|
||||
request
|
||||
.then(result => {
|
||||
console.log(`Password reset sent to: ${user.email}`)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err.statusCode);
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!user) {
|
||||
console.error("Reset password failed. No user: " + req.body.email);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "No account register for " + req.body.email
|
||||
});
|
||||
return;
|
||||
}
|
||||
const buffer = crypto.randomBytes(20);
|
||||
const token = buffer.toString("hex");
|
||||
var tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordTTL = tomorrow;
|
||||
user.save(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const request = mailjet.post("send", {
|
||||
version: "v3.1"
|
||||
}).request({
|
||||
Messages: [{
|
||||
From: {
|
||||
Email: admin_email,
|
||||
Name: site_name + " Admin"
|
||||
},
|
||||
To: [{
|
||||
Email: user.email,
|
||||
Name: user.firstName + " " + user.lastName
|
||||
}],
|
||||
Subject: site_name + " - Password Reset",
|
||||
TextPart: "It looks like you may have forgot your password. Copy this link to your browser to reset your password. Let us know if you are receiving this but did not request a password reset. /r" + account_server + "/reset-password/" + user.id + "/" + token,
|
||||
HTMLPart: "<h3>Thanks for using " + site_name + "!</h3><br />It looks like you may have forgot your password. Copy this link to your browser to reset your password. Let us know if you are receiving this but did not request a password reset.<p>" + account_server + "/reset-password/" + user.id + "/" + token + "</p>"
|
||||
}]
|
||||
});
|
||||
request
|
||||
.then(result => {
|
||||
console.log(`Password reset sent to: ${user.email}`)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err.statusCode);
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
});
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
function handleSendConfirmEmail(user) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (user.confirmEmail) {
|
||||
console.log("Error - Send Confirm Email - User already confirmed email: " + user.email);
|
||||
reject({
|
||||
@@ -332,130 +353,133 @@ function handleSendConfirmEmail(user) {
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
user.confirmEmailToken = token;
|
||||
user.confirmEmailTTL = tomorrow;
|
||||
user.save().then(function(user) {
|
||||
return mailjet.post("send", {
|
||||
version: "v3.1"
|
||||
}).request({
|
||||
Messages: [{
|
||||
From: {
|
||||
Email: admin_email,
|
||||
Name: site_name + " Admin"
|
||||
},
|
||||
To: [{
|
||||
Email: user.email,
|
||||
Name: user.firstName + " " + user.lastName
|
||||
}],
|
||||
Subject: "Confirm " + site_name + " Account",
|
||||
TextPart: "Thanks for signing up for " + site_name + ". We just wanted to check and make sure your email address was real. Copy and paste this addres in your browser to confirm your email address: " + account_server + "/confirm-email/" + user._id + "/" + token,
|
||||
HTMLPart: "<h3>Thanks for signing up for " + site_name + "</h3><br />We just wanted to check and make sure your email address was real. Copy and paste this addres in your browser to confirm your email address:<p> " + account_server + "/confirm-email/" + user._id + "/" + token + "</p>"
|
||||
}]
|
||||
});
|
||||
}).then(result => {
|
||||
console.log("Confirm email sent to: " + user.email);
|
||||
resolve({
|
||||
success: true,
|
||||
userId: user._id
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error("Admin Email: " + admin_email + " User Email: " + user.email);
|
||||
console.error("Error - Send Confirm Email - caught: " + err);
|
||||
reject({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
await user.save();
|
||||
mailjet.post("send", {
|
||||
version: "v3.1"
|
||||
}).request({
|
||||
Messages: [{
|
||||
From: {
|
||||
Email: admin_email,
|
||||
Name: site_name + " Admin"
|
||||
},
|
||||
To: [{
|
||||
Email: user.email,
|
||||
Name: user.firstName + " " + user.lastName
|
||||
}],
|
||||
Subject: "Confirm " + site_name + " Account",
|
||||
TextPart: "Thanks for signing up for " + site_name + ". We just wanted to check and make sure your email address was real. Copy and paste this addres in your browser to confirm your email address: " + account_server + "/confirm-email/" + user._id + "/" + token,
|
||||
HTMLPart: "<h3>Thanks for signing up for " + site_name + "</h3><br />We just wanted to check and make sure your email address was real. Copy and paste this addres in your browser to confirm your email address:<p> " + account_server + "/confirm-email/" + user._id + "/" + token + "</p>"
|
||||
}]
|
||||
});
|
||||
}).then(result => {
|
||||
console.log("Confirm email sent to: " + user.email);
|
||||
resolve({
|
||||
success: true,
|
||||
userId: user._id
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error("Admin Email: " + admin_email + " User Email: " + user.email);
|
||||
console.error("Error - Send Confirm Email - caught: " + err);
|
||||
res.status(500);
|
||||
reject({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
exports.sendConfirmEmail = function(req, res, next) {
|
||||
exports.sendConfirmEmail = async function (req, res, next) {
|
||||
const userId = req.params["userId"];
|
||||
User.findById(userId, (err, user) => {
|
||||
if (err) {
|
||||
console.error("Error - Send Confirm Email: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!user) {
|
||||
console.error("Error - Send Confirm Email: User not found " + userId);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "user not found"
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleSendConfirmEmail(user).then(function(result) {
|
||||
res.json(result);
|
||||
return;
|
||||
}).catch(function(error) {
|
||||
res.json(error);
|
||||
return;
|
||||
});
|
||||
});
|
||||
let user = await User.findById(userId).catch(err => {
|
||||
|
||||
console.error("Error - Send Confirm Email: " + err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
if (!user) {
|
||||
console.error("Error - Send Confirm Email: User not found " + userId);
|
||||
res.status(404);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "user not found"
|
||||
});
|
||||
return;
|
||||
}
|
||||
handleSendConfirmEmail(user).then(function (result) {
|
||||
res.json(result);
|
||||
return;
|
||||
}).catch(function (error) {
|
||||
res.json(error);
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
exports.logout = function(req, res, next) {
|
||||
exports.logout = function (req, res, next) {
|
||||
// the logout method is added to the request object automatically by Passport
|
||||
req.logout();
|
||||
res.clearCookie('sessionId', {domain: cookie_domain, path:'/'});
|
||||
res.clearCookie('sessionId', { domain: cookie_domain, path: '/' });
|
||||
return res.json({
|
||||
success: true
|
||||
});
|
||||
};
|
||||
|
||||
exports.terms = function(req, res, next) {
|
||||
exports.terms = async function (req, res, next) {
|
||||
const userId = req.params["userId"];
|
||||
User.findById(userId, (err, user) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.user.id != userId) {
|
||||
console.log(
|
||||
"Logged in user's ID: " +
|
||||
req.user.id +
|
||||
" does not match Param: " +
|
||||
userId
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "UserID incorrect"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
user.terms = 1.1; //User.termsVer;
|
||||
user.save(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
let user = await User.findById(userId).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
||||
if (req.user.id != userId) {
|
||||
console.log(
|
||||
"Logged in user's ID: " +
|
||||
req.user.id +
|
||||
" does not match Param: " +
|
||||
userId
|
||||
);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "UserID incorrect"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
user.terms = 1.1; //User.termsVer;
|
||||
await user.save().catch(err => {
|
||||
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
// -------------------------------------------
|
||||
|
||||
|
||||
exports.validateProfile = function(req, res, next) {
|
||||
console.log("Validating user profile: "+ req.body.email);
|
||||
exports.validateProfile = function (req, res, next) {
|
||||
console.log("Validating user profile: " + req.body.email);
|
||||
if (!req.body.firstName || (req.body.firstName.length < 2)) {
|
||||
console.error("ERROR: Validate System - req.body.firstName");
|
||||
res.json({
|
||||
@@ -492,68 +516,73 @@ exports.validateProfile = function(req, res, next) {
|
||||
next();
|
||||
}
|
||||
|
||||
exports.updateProfile = function(req, res, next) {
|
||||
exports.updateProfile = async function (req, res, next) {
|
||||
const userId = req.params["userId"];
|
||||
|
||||
User.findById(userId, (err, user) => {
|
||||
// is email address already in use?
|
||||
if (req.user.id != userId) {
|
||||
console.log(
|
||||
"ERROR: Logged in user's ID: " +
|
||||
req.user.id +
|
||||
" does not match Param: " +
|
||||
userId
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "UserID incorrect"
|
||||
});
|
||||
return;
|
||||
}
|
||||
// go ahead and create the new user
|
||||
user.firstName = res.locals.firstName
|
||||
user.lastName = res.locals.lastName
|
||||
user.screenName = res.locals.screenName
|
||||
user.location = res.locals.location
|
||||
|
||||
|
||||
user.save(err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
var clientUser = (({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location
|
||||
}) => ({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location
|
||||
}))(
|
||||
user
|
||||
);
|
||||
console.log("Updated Profile: " + userId)
|
||||
res.json({
|
||||
success: true,
|
||||
user: clientUser
|
||||
});
|
||||
return;
|
||||
user = await User.findById(userId).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
if (req.user.id != userId) {
|
||||
console.log(
|
||||
"ERROR: Logged in user's ID: " +
|
||||
req.user.id +
|
||||
" does not match Param: " +
|
||||
userId
|
||||
);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "UserID incorrect"
|
||||
});
|
||||
return;
|
||||
}
|
||||
// go ahead and create the new user
|
||||
user.firstName = res.locals.firstName
|
||||
user.lastName = res.locals.lastName
|
||||
user.screenName = res.locals.screenName
|
||||
user.location = res.locals.location
|
||||
|
||||
|
||||
await user.save().catch(err => {
|
||||
console.error(err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
var clientUser = (({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location
|
||||
}) => ({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location
|
||||
}))(
|
||||
user
|
||||
);
|
||||
console.log("Updated Profile: " + userId)
|
||||
res.json({
|
||||
success: true,
|
||||
user: clientUser
|
||||
});
|
||||
return;
|
||||
};
|
||||
// -------------------------------------------
|
||||
|
||||
exports.register = function(req, res, next) {
|
||||
exports.register = async function (req, res, next) {
|
||||
console.log("Registration request for: " + req.body.email);
|
||||
|
||||
User.findOne({
|
||||
|
||||
let user = await User.findOne({
|
||||
$or: [{
|
||||
email: req.body.email
|
||||
}, {
|
||||
@@ -561,49 +590,57 @@ exports.register = function(req, res, next) {
|
||||
email: req.body.email
|
||||
}
|
||||
}]
|
||||
}, (err, user) => {
|
||||
// is email address already in use?
|
||||
if (user) {
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Email already in use"
|
||||
});
|
||||
return;
|
||||
}
|
||||
// go ahead and create the new user
|
||||
var user = (({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location,
|
||||
email,
|
||||
password
|
||||
}) => ({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location,
|
||||
|
||||
}))(
|
||||
res.locals
|
||||
);
|
||||
user.password = req.body.password;
|
||||
user.email = req.body.email;
|
||||
|
||||
User.create(user).then(function(dbUser) {
|
||||
console.log("Successfully registered: " + dbUser.email + ", now sending confirmation email.");
|
||||
// Since regiestration worked, send a confirmation email.
|
||||
return handleSendConfirmEmail(dbUser);
|
||||
}).then(function(result) {
|
||||
res.json(result);
|
||||
return;
|
||||
}).catch(function(err) {
|
||||
console.error("Error creating user: " + user.email + " Error: " +err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
};
|
||||
// is email address already in use?
|
||||
if (user) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Email already in use"
|
||||
});
|
||||
return;
|
||||
}
|
||||
// go ahead and create the new user
|
||||
user = (({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location,
|
||||
email,
|
||||
password
|
||||
}) => ({
|
||||
firstName,
|
||||
lastName,
|
||||
screenName,
|
||||
location,
|
||||
|
||||
}))(
|
||||
res.locals
|
||||
);
|
||||
user.password = req.body.password;
|
||||
user.email = req.body.email;
|
||||
|
||||
await User.create(user)
|
||||
|
||||
console.log("Successfully registered: " + user.email + ", now sending confirmation email.");
|
||||
// Since regiestration worked, send a confirmation email.
|
||||
handleSendConfirmEmail(user).then(function (result) {
|
||||
res.json(result);
|
||||
return;
|
||||
}).catch(function (err) {
|
||||
console.error("Error creating user: " + user.email + " Error: " + err);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
}
|
||||
@@ -15,39 +15,39 @@ const app = express()
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
async function connect() {
|
||||
const connect = async () => {
|
||||
|
||||
// Demonstrate the readyState and on event emitters
|
||||
console.log(mongoose.connection.readyState); //logs 0
|
||||
mongoose.connection.on('connecting', () => {
|
||||
console.log('Mongoose is connecting')
|
||||
console.log(mongoose.connection.readyState); //logs 2
|
||||
mongoose.connection.on('connecting', () => {
|
||||
console.log('Mongoose is connecting')
|
||||
console.log(mongoose.connection.readyState); //logs 2
|
||||
});
|
||||
mongoose.connection.on('connected', () => {
|
||||
console.log('Mongoose is connected');
|
||||
console.log(mongoose.connection.readyState); //logs 1
|
||||
console.log('Mongoose is connected');
|
||||
console.log(mongoose.connection.readyState); //logs 1
|
||||
});
|
||||
mongoose.connection.on('disconnecting', () => {
|
||||
console.log('Mongoose is disconnecting');
|
||||
console.log(mongoose.connection.readyState); // logs 3
|
||||
console.log('Mongoose is disconnecting');
|
||||
console.log(mongoose.connection.readyState); // logs 3
|
||||
});
|
||||
|
||||
// Connect to a MongoDB server running on 'localhost:27017' and use the
|
||||
// 'test' database.
|
||||
await mongoose.connect(secrets.db, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true }, (err, res) => {
|
||||
if (err) {
|
||||
console.log(`Mongoose - Error connecting to ${secrets.db}. ${err}`)
|
||||
} else {
|
||||
console.log(`Mongoose Successfully connected to ${secrets.db}.`)
|
||||
}
|
||||
})
|
||||
await mongoose.connect(secrets.db, { useNewUrlParser: true, useUnifiedTopology: true }).catch(err => {
|
||||
|
||||
console.error(`Mongoose - Error connecting to ${secrets.db}. ${err}`)
|
||||
|
||||
});
|
||||
console.log("All Done");
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
mongoose.connection.on('error', err => {
|
||||
console.error("Mongoose Error!")
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
mongoose.connection.on('disconnected', () => {
|
||||
console.log('Mongoose disconnected');
|
||||
console.log(mongoose.connection.readyState); //logs 0
|
||||
@@ -72,16 +72,16 @@ configurePassport(app, passport)
|
||||
configureExpress(app, passport)
|
||||
|
||||
|
||||
app.all('*', function(req, res, next) {
|
||||
var allowedOrigins = [account_server, admin_server, frontend_server];
|
||||
var origin = req.headers.origin;
|
||||
if(allowedOrigins.indexOf(origin) > -1){
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
}
|
||||
res.header("Access-Control-Allow-Credentials", "true");
|
||||
res.header("Access-Control-Allow-Headers", "X-Requested-With");
|
||||
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
||||
next();
|
||||
app.all('*', function (req, res, next) {
|
||||
var allowedOrigins = [account_server, admin_server, frontend_server];
|
||||
var origin = req.headers.origin;
|
||||
if (allowedOrigins.indexOf(origin) > -1) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
}
|
||||
res.header("Access-Control-Allow-Credentials", "true");
|
||||
res.header("Access-Control-Allow-Headers", "X-Requested-With");
|
||||
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
||||
next();
|
||||
});
|
||||
|
||||
// -------------------------------------------
|
||||
@@ -94,8 +94,8 @@ app.post("/users/:userId/reset-password/:token", users.resetPassword)
|
||||
app.post("/api/send-reset-password", users.sendResetPassword)
|
||||
app.post("/users/:userId", users.isLoggedIn, users.validateProfile, users.updateProfile)
|
||||
app.post("/users/:userId/terms", users.isLoggedIn, users.terms)
|
||||
app.post("/users/:userId/send-confirm", users.sendConfirmEmail)
|
||||
app.post("/users/:userId/confirm/:token", users.confirmEmail)
|
||||
app.post("/users/:userId/send-confirm", users.sendConfirmEmail)
|
||||
app.post("/users/:userId/confirm/:token", users.confirmEmail)
|
||||
|
||||
app.get("*", (req, res, next) => {
|
||||
res.sendFile(__dirname + '/public/index.html');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React, { useEffect, useState, } from "react";
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import { loginUser } from "../features/user/userSlice";
|
||||
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import {
|
||||
Container,
|
||||
Header,
|
||||
@@ -35,66 +35,52 @@ const Login = (props) => {
|
||||
const navigate = useNavigate();
|
||||
let [searchParams, setSearchParams] = useSearchParams();
|
||||
const nextLocation = searchParams.get("nextLocation");
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const handleInputChange = (e, { name, value }) => this.setState({ [name]: value });
|
||||
|
||||
const loginSubmit = (event) => {
|
||||
const loginSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
/*
|
||||
var success = { type: "path", nextPathname: "/" };
|
||||
if (nextLocation) {
|
||||
success.type = "location";
|
||||
switch (this.props.nextLocation) {
|
||||
case "frontend":
|
||||
success.nextLocation = process.env.REACT_APP_FRONTEND_SERVER;
|
||||
break;
|
||||
default:
|
||||
case "admin":
|
||||
success.nextLocation = process.env.REACT_APP_ADMIN_SERVER;
|
||||
break;
|
||||
const result = await dispatch(loginUser({email,password})).unwrap();
|
||||
if (result.success) {
|
||||
|
||||
if (nextLocation) {
|
||||
switch (this.props.nextLocation) {
|
||||
case "frontend":
|
||||
window.location = process.env.REACT_APP_FRONTEND_SERVER;
|
||||
break;
|
||||
default:
|
||||
case "admin":
|
||||
window.location = process.env.REACT_APP_ADMIN_SERVER;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
navigate("/");
|
||||
}
|
||||
console.log(result)
|
||||
} else {
|
||||
console.error(result);
|
||||
setLoginMessage(result.message);
|
||||
if (result.message === "unconfirmed email") {
|
||||
/*data.userId = response.data.userId;
|
||||
dispatch(loginEmailError(data));*/
|
||||
navigate("/wait-confirm-email");
|
||||
}
|
||||
}
|
||||
|
||||
// Passed in via react-redux. Returns a promise.
|
||||
this.props
|
||||
.manualLogin(
|
||||
{
|
||||
// this function is passed in via react-redux
|
||||
email,
|
||||
password
|
||||
},
|
||||
success
|
||||
|
||||
) // holds the path to redirect to after login (if any)
|
||||
.then(loginMessage => {
|
||||
if (loginMessage) {
|
||||
// report to the user is there was a problem during login
|
||||
this.setState({
|
||||
loginMessage
|
||||
});
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
/*
|
||||
let loginMessageDisplay =(<></>)
|
||||
|
||||
if (this.state.loginMessage) {
|
||||
loginMessage = (
|
||||
if (loginMessage) {
|
||||
loginMessageDisplay = (
|
||||
<Message icon>
|
||||
<Icon name="lemon" />
|
||||
<Message.Content>
|
||||
<Message.Header>Problems...</Message.Header>
|
||||
{this.state.loginMessage}
|
||||
{loginMessage}
|
||||
</Message.Content>
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Header as="h1">{process.env.REACT_APP_SITE_NAME}</Header>
|
||||
@@ -176,7 +162,7 @@ const Login = (props) => {
|
||||
<Button type="submit" size="large" value="Login" fluid>
|
||||
Login
|
||||
</Button>
|
||||
{loginMessage}
|
||||
{loginMessageDisplay}
|
||||
</Segment>
|
||||
</Form>
|
||||
<div style={forgotStyle} >
|
||||
|
||||
@@ -1,45 +1,37 @@
|
||||
import React, { Component } from "react"
|
||||
import React, { useEffect, useState, } from "react";
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import UserForm from "./UserForm";
|
||||
import {
|
||||
Container,
|
||||
Header
|
||||
} from "semantic-ui-react";
|
||||
import { updateProfile } from "../features/user/userSlice";
|
||||
|
||||
class Profile extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleProfileSubmit = this.handleProfileSubmit.bind(this);
|
||||
}
|
||||
const Profile = (props) => {
|
||||
const [message, setMessage] = useState("");
|
||||
const user = useSelector((state) => state.user);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleProfileSubmit = async (updatedUser) => {
|
||||
updatedUser.userId = user.userId
|
||||
|
||||
state = {
|
||||
requestMessage: ""
|
||||
const result = await dispatch(updateProfile(updatedUser)).unwrap();
|
||||
if (result.success) {
|
||||
console.log(result)
|
||||
} else {
|
||||
setMessage = result.message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
handleProfileSubmit(user) {
|
||||
user.userId = this.props.user.userId
|
||||
this.props
|
||||
.updateProfile(user)
|
||||
.then(requestMessage => {
|
||||
if (requestMessage) {
|
||||
// report to the user is there was a problem during registration
|
||||
this.setState({
|
||||
requestMessage
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
// The Key on UserForm get updated when the user is loaded. This forces the Component to be completely redrawn, otherwise the changes in the Prop are not copied to State.
|
||||
return(
|
||||
<Container text>
|
||||
<Header as="h1">Update Profile</Header>
|
||||
<UserForm onSubmit={this.handleProfileSubmit} user={this.props.user} isEditing={true} requestMessage={this.state.requestMessage} isWaiting={this.props.isWaiting} key={this.props.user.userId}/>
|
||||
<UserForm onSubmit={handleProfileSubmit} user={user} isEditing={true} requestMessage={message} isWaiting={props.isWaiting} key={user.userId}/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Profile
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React, { Component } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { registerUser } from "../features/user/userSlice";
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import {
|
||||
Container,
|
||||
Header,
|
||||
@@ -8,53 +11,39 @@ import {
|
||||
|
||||
import UserForm from "./UserForm";
|
||||
|
||||
// ----------------------------------------------------
|
||||
class Register extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._onRegisterSubmit = this._onRegisterSubmit.bind(this);
|
||||
function Register(props) {
|
||||
const [requestMessage, setRequestMessage] = useState("");
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const onRegisterSubmit = async(user) => {
|
||||
const result = await dispatch(registerUser(user)).unwrap();
|
||||
if (result.success) {
|
||||
navigate("/sent-confirm-email");
|
||||
} else {
|
||||
console.error(result);
|
||||
setRequestMessage(result.message);
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
requestMessage: ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
_onRegisterSubmit(user) {
|
||||
this.props
|
||||
.manualRegister(user)
|
||||
.then(requestMessage => {
|
||||
if (requestMessage) {
|
||||
// report to the user is there was a problem during registration
|
||||
this.setState({
|
||||
requestMessage
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name='trophy'/>
|
||||
<Message.Content>
|
||||
<Message.Header>Welcome!</Message.Header>
|
||||
<p>Creating an account on OpenMHz is the first step in sharing radio system recordings using Trunk Recorder.</p>
|
||||
<p>After creating an account, head over <a href="https://github.com/robotastic/trunk-recorder">here</a> to learn more about Trunk Recorder</p>
|
||||
<p> - Luke</p>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
</Container>
|
||||
<Container text>
|
||||
<Header style={{ paddingTop: '20px' }} as="h1">Register</Header>
|
||||
<UserForm onSubmit={this._onRegisterSubmit} requestMessage={this.state.requestMessage} isWaiting={this.props.isWaiting}/>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<Icon name='trophy'/>
|
||||
<Message.Content>
|
||||
<Message.Header>Welcome!</Message.Header>
|
||||
<p>Creating an account on OpenMHz is the first step in sharing radio system recordings using Trunk Recorder.</p>
|
||||
<p>After creating an account, head over <a href="https://github.com/robotastic/trunk-recorder">here</a> to learn more about Trunk Recorder</p>
|
||||
<p> - Luke</p>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
</Container>
|
||||
<Container text>
|
||||
<Header style={{ paddingTop: '20px' }} as="h1">Register</Header>
|
||||
<UserForm onSubmit={onRegisterSubmit} requestMessage={requestMessage} isWaiting={props.isWaiting}/>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Register;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import React, { Component } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { resetPassword } from "../features/user/userSlice";
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux'
|
||||
import {
|
||||
Container,
|
||||
Form,
|
||||
@@ -6,101 +9,101 @@ import {
|
||||
Button,
|
||||
} from "semantic-ui-react";
|
||||
|
||||
class ResetPassword extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleResetPassword = this.handleResetPassword.bind(this);
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
}
|
||||
state = {
|
||||
checkInputMessages: [],
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
passwordError: false,
|
||||
confirmPasswordError: false,
|
||||
sentReset: false
|
||||
};
|
||||
const ResetPassword = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const [password, setPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const [confirmPasswordError, setConfirmPasswordError] = useState(false);
|
||||
const [checkInputMessages, setCheckInputMessages] = useState([]);
|
||||
const { userId, token } = useParams();
|
||||
|
||||
|
||||
handleInputChange = (e, { name, value }) => this.setState({ [name]: value });
|
||||
|
||||
handleResetPassword(event) {
|
||||
const handleResetPassword = async () => {
|
||||
let error = false;
|
||||
var checkInputMessages = [];
|
||||
var inputMessages = [];
|
||||
|
||||
if (this.state.password === "") {
|
||||
this.setState({ passwordError: true });
|
||||
checkInputMessages.push("Password is required");
|
||||
if (password === "") {
|
||||
setPasswordError(true);
|
||||
inputMessages.push("Password is required");
|
||||
error = true;
|
||||
} if (this.state.password.length < 7) {
|
||||
this.setState({ passwordError: true });
|
||||
checkInputMessages.push("Password must be 7 charecters or more");
|
||||
error = true;
|
||||
}else {
|
||||
this.setState({ passwordError: false });
|
||||
}
|
||||
|
||||
if (this.state.password !== this.state.confirmPassword) {
|
||||
this.setState({ confirmPasswordError: true });
|
||||
checkInputMessages.push("The passwords did not match");
|
||||
} else if (password.length < 7) {
|
||||
setPasswordError(true);
|
||||
inputMessages.push("Password must be 7 characters or more");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ confirmPasswordError: false });
|
||||
setPasswordError(false);
|
||||
}
|
||||
|
||||
const { match: { params } } = this.props;
|
||||
this.setState({ checkInputMessages: checkInputMessages });
|
||||
if (password !== confirmPassword) {
|
||||
setConfirmPasswordError(true);
|
||||
inputMessages.push("The passwords did not match");
|
||||
error = true;
|
||||
} else {
|
||||
setConfirmPasswordError(false);
|
||||
}
|
||||
|
||||
const { match: { params } } = props;
|
||||
setCheckInputMessages(inputMessages);
|
||||
if (!error) {
|
||||
this.props.resetPassword(params.userId, params.token, this.state.password).then(resetSent => {
|
||||
this.setState({resetSent: true});
|
||||
});
|
||||
const result = await dispatch(resetPassword({ userId, token, password })).unwrap();
|
||||
if (result.success) {
|
||||
navigate("/login");
|
||||
} else {
|
||||
console.error(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
<Segment>
|
||||
<Form
|
||||
className="raised padding segment"
|
||||
onSubmit={this.handleSubmit}
|
||||
>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.passwordError}
|
||||
label="Password"
|
||||
placeholder="Password..."
|
||||
<Form className="raised padding segment">
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
error={passwordError}
|
||||
label="Password"
|
||||
placeholder="Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
onChange={e => setConfirmPassword(e.target.value)}
|
||||
error={confirmPasswordError}
|
||||
label="Confirm Password"
|
||||
placeholder="Confirm Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Button
|
||||
size="large"
|
||||
content="Reset Password"
|
||||
onClick={handleResetPassword}
|
||||
fluid
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.confirmPasswordError}
|
||||
label="Confirm Password"
|
||||
placeholder="Confirm Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Button
|
||||
size="large"
|
||||
content="Reset Password"
|
||||
onClick={this.handleResetPassword}
|
||||
fluid
|
||||
/>
|
||||
</Form>
|
||||
</Segment>
|
||||
{checkInputMessages.length > 0 && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{checkInputMessages.map((msg) => (
|
||||
<p key={msg} style={{ color: "red" }}>
|
||||
{msg}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Form>
|
||||
</Segment>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResetPassword;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from "react";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Form,
|
||||
Grid,
|
||||
@@ -7,106 +7,99 @@ import {
|
||||
Message,
|
||||
Icon
|
||||
} from "semantic-ui-react";
|
||||
import { sendResetPassword } from "../features/user/userSlice";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
const returnStyle = {
|
||||
marginTop: "30px"
|
||||
};
|
||||
|
||||
class SendResetPassword extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSendResetPassword = this.handleSendResetPassword.bind(this);
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
}
|
||||
state = {
|
||||
checkInputMessages: "",
|
||||
email: "",
|
||||
emailError: false,
|
||||
sentReset: false
|
||||
const SendResetPassword = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const [checkInputMessages, setCheckInputMessages] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [emailError, setEmailError] = useState(false);
|
||||
const [resetSent, setResetSent] = useState(false);
|
||||
|
||||
const returnStyle = {
|
||||
marginTop: "30px"
|
||||
};
|
||||
|
||||
handleInputChange = (e, { name, value }) => this.setState({ [name]: value });
|
||||
|
||||
handleSendResetPassword(event) {
|
||||
|
||||
|
||||
if (this.state.email === "") {
|
||||
this.setState({ emailError: true, checkInputMessages: "Email is required"});
|
||||
|
||||
const handleSendResetPassword = async () => {
|
||||
if (email === "") {
|
||||
setEmailError(true);
|
||||
setCheckInputMessages("Email is required");
|
||||
} else {
|
||||
this.setState({ emailError: false });
|
||||
|
||||
this.props.sendResetPassword({email: this.state.email}).then(resetMessage => {
|
||||
if (resetMessage) {
|
||||
// report to the user is there was a problem during login
|
||||
|
||||
this.setState({resetSent: false, checkInputMessages: resetMessage, emailError: true});
|
||||
} else {
|
||||
this.setState({resetSent: true});
|
||||
const result = await dispatch(sendResetPassword({ email })).unwrap();
|
||||
if (result.success) {
|
||||
setResetSent(true);
|
||||
setEmailError(true);
|
||||
} else {
|
||||
setCheckInputMessages(result.message);
|
||||
console.error(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
render() {
|
||||
var resetMessage = "";
|
||||
if (this.state.checkInputMessages.length) {
|
||||
resetMessage = (
|
||||
<Message compact warning icon>
|
||||
<Icon name="lightning" />
|
||||
<Message.Content>
|
||||
<Message.Header>Problems...</Message.Header>
|
||||
};
|
||||
|
||||
{this.state.checkInputMessages}
|
||||
|
||||
</Message.Content>
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
||||
|
||||
<Grid verticalAlign='middle' centered>
|
||||
<Grid.Row>
|
||||
|
||||
<Grid.Column width="6">
|
||||
{ !this.state.resetSent ? (
|
||||
<div>
|
||||
<h2>Forgot your password?</h2>
|
||||
<Form className="raised padding segment" onSubmit={this.handleSubmit}>
|
||||
Enter the email address for your account.
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="email"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.emailError}
|
||||
label="Email"
|
||||
placeholder="Email..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Button
|
||||
size="large"
|
||||
content="Reset Password"
|
||||
onClick={this.handleSendResetPassword}
|
||||
fluid
|
||||
/>
|
||||
</Form>
|
||||
{resetMessage}
|
||||
</div>
|
||||
)
|
||||
:( <Segment raised padded='very'>
|
||||
<h2>Reset Link Sent </h2>
|
||||
<div>An email with a link to reset your password was sent to: {this.state.email}</div>
|
||||
<Link to="/" style={returnStyle}><Icon name="left arrow"/>Back to OpenMHz</Link>
|
||||
</Segment>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
var resetMessage = "";
|
||||
if (checkInputMessages.length) {
|
||||
resetMessage = (
|
||||
<Message compact warning icon>
|
||||
<Icon name="lightning" />
|
||||
<Message.Content>
|
||||
<Message.Header>Problems...</Message.Header>
|
||||
{checkInputMessages}
|
||||
</Message.Content>
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid verticalAlign="middle" centered>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={6}>
|
||||
{!resetSent ? (
|
||||
<div>
|
||||
<h2>Forgot your password?</h2>
|
||||
<Form className="raised padding segment">
|
||||
Enter the email address for your account.
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="email"
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
value={email}
|
||||
error={emailError}
|
||||
label="Email"
|
||||
placeholder="Email..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Button
|
||||
size="large"
|
||||
content="Reset Password"
|
||||
onClick={handleSendResetPassword}
|
||||
fluid
|
||||
/>
|
||||
</Form>
|
||||
{resetMessage}
|
||||
</div>
|
||||
) : (
|
||||
<Segment raised padded="very">
|
||||
<h2>Reset Link Sent </h2>
|
||||
<div>
|
||||
An email with a link to reset your password was sent to: {email}
|
||||
</div>
|
||||
<Link to="/" style={returnStyle}>
|
||||
<Icon name="left arrow" />
|
||||
Back to OpenMHz
|
||||
</Link>
|
||||
</Segment>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default SendResetPassword;
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
import React, { Component } from "react"
|
||||
import {
|
||||
Container,
|
||||
Message,
|
||||
Icon
|
||||
} from "semantic-ui-react";
|
||||
import React from "react";
|
||||
import { Container, Message, Icon } from "semantic-ui-react";
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
class SentConfirmEmail extends Component {
|
||||
const SentConfirmEmail = ({ user }) => {
|
||||
const { email } = useSelector((state) => state.user);
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name='envelope outline' />
|
||||
<Message.Content>
|
||||
<Message.Header>Confirmation email sent!</Message.Header>
|
||||
<p>
|
||||
We sent an email to the address you gave us: {email}<br />
|
||||
Please click on the link in the email to verify the email address.
|
||||
</p>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name='envelope outline' />
|
||||
<Message.Content>
|
||||
<Message.Header>Confirmation email sent!</Message.Header>
|
||||
<p>We sent an email to the address you gave us: {this.props.user.email}<br />
|
||||
Please click on the link in the email to verify the email address.</p>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SentConfirmEmail
|
||||
export default SentConfirmEmail;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import React, { useEffect, useState, } from "react";
|
||||
import {
|
||||
Form,
|
||||
Dimmer,
|
||||
@@ -10,270 +11,260 @@ import {
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
class UserForm extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.checkInputs = this.checkInputs.bind(this);
|
||||
this.render = this.render.bind(this)
|
||||
|
||||
this.state = {
|
||||
checkInputMessages: [],
|
||||
registerMessages: "",
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
screenName: "",
|
||||
email: "",
|
||||
location: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
firstNameError: false,
|
||||
lastNameError: false,
|
||||
screenNameError: false,
|
||||
emailError: false,
|
||||
locationError: false,
|
||||
passwordError: false,
|
||||
confirmPasswordError: false,
|
||||
isEditing: this.props.isEditing
|
||||
};
|
||||
if (this.props.isEditing) {
|
||||
this.state.firstName = this.props.user.firstName;
|
||||
this.state.lastName = this.props.user.lastName;
|
||||
this.state.screenName = this.props.user.screenName;
|
||||
this.state.email = this.props.user.email;
|
||||
this.state.location = this.props.user.location;
|
||||
const UserForm = (props) => {
|
||||
const [checkInputMessages, setCheckInputMessages] = useState([]);
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [screenName, setScreenName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [location, setLocation] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [firstNameError, setFirstNameError] = useState(false);
|
||||
const [lastNameError, setLastNameError] = useState(false);
|
||||
const [screenNameError, setScreenNameError] = useState(false);
|
||||
const [emailError, setEmailError] = useState(false);
|
||||
const [locationError, setLocationError] = useState(false);
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const [confirmPasswordError, setConfirmPasswordError] = useState(false);
|
||||
const [isEditing, setIsEditing] = useState(props.isEditing);
|
||||
const requestMessage = props.requestMessage;
|
||||
|
||||
useEffect(() => {
|
||||
if (props.isEditing) {
|
||||
setFirstName(props.user.firstName);
|
||||
setLastName(props.user.lastName);
|
||||
setScreenName(props.user.screenName);
|
||||
setEmail(props.user.email);
|
||||
setLocation(props.user.location);
|
||||
}
|
||||
}
|
||||
}, [props.isEditing, props.user]);
|
||||
|
||||
|
||||
|
||||
checkInputs() {
|
||||
const checkInputs = () => {
|
||||
let error = false;
|
||||
var checkInputMessages = [];
|
||||
let inputMessages = [];
|
||||
|
||||
if (this.state.firstName === "") {
|
||||
this.setState({ firstNameError: true });
|
||||
checkInputMessages.push("First Name is required");
|
||||
if (firstName === "") {
|
||||
setFirstNameError(true);
|
||||
inputMessages.push("First Name is required");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ firstNameError: false });
|
||||
setFirstNameError(false);
|
||||
}
|
||||
|
||||
if (this.state.lastName === "") {
|
||||
this.setState({ lastNameError: true });
|
||||
checkInputMessages.push("Last Name is required");
|
||||
if (lastName === "") {
|
||||
setLastNameError(true);
|
||||
inputMessages.push("Last Name is required");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ lastNameError: false });
|
||||
setLastNameError(false);
|
||||
}
|
||||
|
||||
if (this.state.email === "") {
|
||||
this.setState({ emailError: true });
|
||||
checkInputMessages.push("Email is required");
|
||||
if (email === "") {
|
||||
setEmailError(true);
|
||||
inputMessages.push("Email is required");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ emailError: false });
|
||||
setEmailError(false);
|
||||
}
|
||||
|
||||
if (this.state.location === "") {
|
||||
this.setState({ locationError: true });
|
||||
checkInputMessages.push("Location is required");
|
||||
if (location === "") {
|
||||
setLocationError(true);
|
||||
inputMessages.push("Location is required");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ locationError: false });
|
||||
setLocationError(false);
|
||||
}
|
||||
|
||||
if (this.state.screenName === "") {
|
||||
this.setState({ screenNameError: true });
|
||||
checkInputMessages.push("Screen Name is required");
|
||||
if (screenName === "") {
|
||||
setScreenNameError(true);
|
||||
inputMessages.push("Screen Name is required");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ screenNameError: false });
|
||||
setScreenNameError(false);
|
||||
}
|
||||
|
||||
if (this.props.isEditing) {
|
||||
this.setState({ checkInputMessages: checkInputMessages });
|
||||
if (props.isEditing) {
|
||||
setCheckInputMessages(checkInputMessages);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (this.state.password === "") {
|
||||
this.setState({ passwordError: true });
|
||||
checkInputMessages.push("Password is required");
|
||||
if (password === "") {
|
||||
setPasswordError(true);
|
||||
inputMessages.push("Password is required");
|
||||
error = true;
|
||||
} if (this.state.password.length < 7) {
|
||||
this.setState({ passwordError: true });
|
||||
checkInputMessages.push("Password must be 7 charecters or more");
|
||||
} if (password.length < 7) {
|
||||
setPasswordError(true);
|
||||
inputMessages.push("Password must be 7 charecters or more");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ passwordError: false });
|
||||
setPasswordError(false);
|
||||
}
|
||||
|
||||
if (this.state.password !== this.state.confirmPassword) {
|
||||
this.setState({ confirmPasswordError: true });
|
||||
checkInputMessages.push("The passwords did not match");
|
||||
if (password !== confirmPassword) {
|
||||
setConfirmPasswordError(true);
|
||||
inputMessages.push("The passwords did not match");
|
||||
error = true;
|
||||
} else {
|
||||
this.setState({ confirmPasswordError: false });
|
||||
setConfirmPasswordError(false);
|
||||
}
|
||||
|
||||
this.setState({ checkInputMessages: checkInputMessages });
|
||||
setCheckInputMessages(inputMessages);
|
||||
return error;
|
||||
}
|
||||
|
||||
handleInputChange = (e, { name, value }) => this.setState({ [name]: value });
|
||||
|
||||
handleSubmit(event) {
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
let inputError = this.checkInputs();
|
||||
let inputError = checkInputs();
|
||||
|
||||
if (!inputError) {
|
||||
const user = (({ firstName, lastName, screenName, location, email, password }) => ({ firstName, lastName, screenName, location, email, password }))(this.state);
|
||||
this.props.onSubmit(user);
|
||||
const user ={ firstName, lastName, screenName, location, email, password };
|
||||
props.onSubmit(user);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
var registerMessage = "";
|
||||
var floatStyle = {
|
||||
overflow: 'auto'
|
||||
}
|
||||
var dimmerProps = {};
|
||||
if (this.props.isWaiting) {
|
||||
dimmerProps["active"] = true;
|
||||
}
|
||||
const { isEditing } = this.props;
|
||||
if (this.state.checkInputMessages.length || this.props.requestMessage.length) {
|
||||
var counter = 0;
|
||||
registerMessage = (
|
||||
<Message compact warning icon>
|
||||
<Icon name="lightning" />
|
||||
<Message.Content>
|
||||
<Message.Header>Problems...</Message.Header>
|
||||
<ul>
|
||||
{this.state.checkInputMessages.map(function (listValue) {
|
||||
return <li key={`ListItem_${counter++}`}>{listValue}</li>;
|
||||
})}
|
||||
{this.props.requestMessage.length > 0 &&
|
||||
<li key="req-mess">{this.props.requestMessage}</li>
|
||||
}
|
||||
</ul>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
className="raised padding segment"
|
||||
onSubmit={this.handleSubmit}
|
||||
>
|
||||
<Dimmer {...dimmerProps}>
|
||||
<Loader indeterminate>Updating Profile</Loader>
|
||||
</Dimmer>
|
||||
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="firstName"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.firstNameError}
|
||||
defaultValue={this.state.firstName}
|
||||
label="First name"
|
||||
placeholder="First Name..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="lastName"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.lastNameError}
|
||||
defaultValue={this.state.lastName}
|
||||
label="Last name"
|
||||
placeholder="Last Name..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="email"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.emailError}
|
||||
defaultValue={this.state.email}
|
||||
disabled={isEditing}
|
||||
label="Email"
|
||||
placeholder="Email..."
|
||||
/>
|
||||
var registerMessage = "";
|
||||
var floatStyle = {
|
||||
overflow: 'auto'
|
||||
}
|
||||
var dimmerProps = {};
|
||||
if (props.isWaiting) {
|
||||
dimmerProps["active"] = true;
|
||||
}
|
||||
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="screenName"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.screenNameError}
|
||||
defaultValue={this.state.screenName}
|
||||
label="Screen Name"
|
||||
placeholder="Screen Name..."
|
||||
/>
|
||||
<p style={{ fontStyle: "italic" }}>
|
||||
Shown on OpenMHz for each of your systems
|
||||
</p>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="location"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.locationError}
|
||||
defaultValue={this.state.location}
|
||||
label="General Location"
|
||||
placeholder="City, State..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
{isEditing !== true && (
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.passwordError}
|
||||
disabled={isEditing}
|
||||
label="Password"
|
||||
placeholder="Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
onChange={this.handleInputChange}
|
||||
error={this.state.confirmPasswordError}
|
||||
disabled={isEditing}
|
||||
label="Confirm Password"
|
||||
placeholder="Confirm Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
)}
|
||||
<div style={floatStyle}>
|
||||
<Button type="submit" size="large" floated="right" value="Login" color='blue'>
|
||||
{isEditing !== true ? 'Register' : 'Update'}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
{registerMessage}
|
||||
</div>
|
||||
if (checkInputMessages.length || requestMessage.length) {
|
||||
var counter = 0;
|
||||
registerMessage = (
|
||||
<Message compact warning icon>
|
||||
<Icon name="lightning" />
|
||||
<Message.Content>
|
||||
<Message.Header>Problems...</Message.Header>
|
||||
<ul>
|
||||
{checkInputMessages.map(function (listValue) {
|
||||
return <li key={`ListItem_${counter++}`}>{listValue}</li>;
|
||||
})}
|
||||
{requestMessage.length > 0 &&
|
||||
<li key="req-mess">{requestMessage}</li>
|
||||
}
|
||||
</ul>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
className="raised padding segment"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Dimmer {...dimmerProps}>
|
||||
<Loader indeterminate>Updating Profile</Loader>
|
||||
</Dimmer>
|
||||
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="firstName"
|
||||
onChange={e => setFirstName(e.target.value)}
|
||||
error={firstNameError}
|
||||
value={firstName}
|
||||
label="First name"
|
||||
placeholder="First Name..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="lastName"
|
||||
onChange={e => setLastName(e.target.value)}
|
||||
error={lastNameError}
|
||||
value={lastName}
|
||||
label="Last name"
|
||||
placeholder="Last Name..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="email"
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
error={emailError}
|
||||
value={email}
|
||||
disabled={isEditing}
|
||||
label="Email"
|
||||
placeholder="Email..."
|
||||
/>
|
||||
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="screenName"
|
||||
onChange={e => setScreenName(e.target.value)}
|
||||
error={screenNameError}
|
||||
value={screenName}
|
||||
label="Screen Name"
|
||||
placeholder="Screen Name..."
|
||||
/>
|
||||
<p style={{ fontStyle: "italic" }}>
|
||||
Shown on OpenMHz for each of your systems
|
||||
</p>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="location"
|
||||
onChange={e => setLocation(e.target.value)}
|
||||
error={locationError}
|
||||
value={location}
|
||||
label="General Location"
|
||||
placeholder="City, State..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
{isEditing !== true && (
|
||||
<Form.Group widths="equal">
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
error={passwordError}
|
||||
disabled={isEditing}
|
||||
label="Password"
|
||||
placeholder="Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.Input
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
onChange={e => setConfirmPassword(e.target.value)}
|
||||
error={confirmPasswordError}
|
||||
disabled={isEditing}
|
||||
label="Confirm Password"
|
||||
placeholder="Confirm Password..."
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
)}
|
||||
<div style={floatStyle}>
|
||||
<Button type="submit" size="large" floated="right" value="Login" color='blue'>
|
||||
{isEditing !== true ? 'Register' : 'Update'}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
{registerMessage}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default UserForm;
|
||||
|
||||
@@ -1,52 +1,43 @@
|
||||
import React, { Component } from "react"
|
||||
import {
|
||||
Container,
|
||||
Header,
|
||||
Button,
|
||||
Message,
|
||||
Icon
|
||||
} from "semantic-ui-react";
|
||||
class WaitConfirmEmail extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSendConfirmEmail = this.handleSendConfirmEmail.bind(this);
|
||||
import React, { useState } from "react";
|
||||
import { sendConfirmEmail } from "../features/user/userSlice";
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { Container, Header, Button, Message, Icon } from "semantic-ui-react";
|
||||
|
||||
}
|
||||
handleSendConfirmEmail(event) {
|
||||
this.props.sendConfirmEmail(this.props.user.userId).then(loginMessage => {
|
||||
if (loginMessage) {
|
||||
// report to the user is there was a problem during login
|
||||
this.setState({
|
||||
loginMessage
|
||||
});
|
||||
}
|
||||
});
|
||||
const WaitConfirmEmail = () => {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { email, userId } = useSelector((state) => state.user);
|
||||
|
||||
const handleSendConfirmEmail = async (event) => {
|
||||
const message = await dispatch(sendConfirmEmail(userId)).unwrap();
|
||||
navigate("/sent-confirm-email")
|
||||
};
|
||||
|
||||
render() {
|
||||
return(
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name='envelope outline'/>
|
||||
<Message.Content>
|
||||
<Message.Header>Confirm your email address</Message.Header>
|
||||
<p>We sent an email to the address you gave us: {this.props.user.email}<br/>
|
||||
Please click on the link in the email to verify the email address.</p>
|
||||
<Header as='h3'>Didn't get an email?</Header>
|
||||
<p>So, you have waited a bit and haven't gotten anything?</p>
|
||||
|
||||
return (
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name="envelope outline" />
|
||||
<Message.Content>
|
||||
<Message.Header>Confirm your email address</Message.Header>
|
||||
<p>
|
||||
We sent an email to the address you gave us: {email}
|
||||
<br />
|
||||
Please click on the link in the email to verify the email address.
|
||||
</p>
|
||||
<Header as="h3">Didn't get an email?</Header>
|
||||
<p>So, you have waited a bit and haven't gotten anything?</p>
|
||||
<p>...and you checked your spam folder?</p>
|
||||
<p>Well, click below.</p>
|
||||
<Button
|
||||
size="large"
|
||||
content="Resend Email Confirmation"
|
||||
onClick={this.handleSendConfirmEmail}
|
||||
/>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
<Button
|
||||
size="large"
|
||||
content="Resend Email Confirmation"
|
||||
onClick={handleSendConfirmEmail}
|
||||
/>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default WaitConfirmEmail
|
||||
export default WaitConfirmEmail;
|
||||
|
||||
@@ -22,11 +22,33 @@ export const authenticateUser = createAsyncThunk(
|
||||
|
||||
export const loginUser = createAsyncThunk(
|
||||
'user/login',
|
||||
async ({ getState }) => {
|
||||
async (data) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/login"
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include"
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const registerUser = createAsyncThunk(
|
||||
'user/register',
|
||||
async (data) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/register"
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
@@ -36,6 +58,24 @@ export const loginUser = createAsyncThunk(
|
||||
|
||||
|
||||
|
||||
export const updateProfile = createAsyncThunk(
|
||||
'user/updateProfile',
|
||||
async (user) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/users/" + user.userId;
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(user)
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const logoutUser = createAsyncThunk(
|
||||
'user/logout',
|
||||
async ({ getState }) => {
|
||||
@@ -50,6 +90,63 @@ export const logoutUser = createAsyncThunk(
|
||||
}
|
||||
)
|
||||
|
||||
export const sendConfirmEmail = createAsyncThunk(
|
||||
'user/sendConfirmEmail',
|
||||
async (userId) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/users/" + userId + "/send-confirm";
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const resetPassword = createAsyncThunk(
|
||||
'user/resetPassword',
|
||||
async (data) => {
|
||||
const {userId, token, password} = data;
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/users/" + userId + "/confirm/" + token
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({password})
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const sendResetPassword = createAsyncThunk(
|
||||
'user/sendResetPassword',
|
||||
async (data) => {
|
||||
const {userId, token, password} = data;
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/api/send-reset-password"
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
export const userSlice = createSlice({
|
||||
name: 'user',
|
||||
initialState: {
|
||||
@@ -59,7 +156,12 @@ export const userSlice = createSlice({
|
||||
userId: "",
|
||||
admin: false,
|
||||
email: "",
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
location: "",
|
||||
screenName: ""
|
||||
},
|
||||
|
||||
reducers: {
|
||||
increment: (state) => {
|
||||
// Redux Toolkit allows us to write "mutating" logic in reducers. It
|
||||
@@ -70,6 +172,44 @@ export const userSlice = createSlice({
|
||||
},
|
||||
},
|
||||
extraReducers: {
|
||||
[loginUser.fulfilled]: (state, data) => {
|
||||
const {payload} = data;
|
||||
if (payload.success) {
|
||||
state.authenticated = true;
|
||||
state.hasAuthenticated = true;
|
||||
state.userId = payload.user.userId;
|
||||
state.admin = payload.user.admin;
|
||||
state.email = payload.user.email;
|
||||
state.firstName = payload.user.firstName;
|
||||
state.lastName = payload.user.lastName;
|
||||
state.location = payload.user.location;
|
||||
state.screenName = payload.user.screenName;
|
||||
} else {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
}
|
||||
},
|
||||
[updateProfile.fulfilled]: (state, data) => {
|
||||
const {payload} = data;
|
||||
if (payload.success) {
|
||||
state.authenticated = true;
|
||||
state.hasAuthenticated = true;
|
||||
state.userId = payload.user.userId;
|
||||
state.admin = payload.user.admin;
|
||||
state.email = payload.user.email;
|
||||
state.firstName = payload.user.firstName;
|
||||
state.lastName = payload.user.lastName;
|
||||
state.location = payload.user.location;
|
||||
state.screenName = payload.user.screenName;
|
||||
} else {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
}
|
||||
},
|
||||
[loginUser.rejected]: (state, { payload }) => {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
},
|
||||
[authenticateUser.fulfilled]: (state, data) => {
|
||||
const {payload} = data;
|
||||
if (payload.success) {
|
||||
@@ -78,6 +218,10 @@ export const userSlice = createSlice({
|
||||
state.userId = payload.user.userId;
|
||||
state.admin = payload.user.admin;
|
||||
state.email = payload.user.email;
|
||||
state.firstName = payload.user.firstName;
|
||||
state.lastName = payload.user.lastName;
|
||||
state.location = payload.user.location;
|
||||
state.screenName = payload.user.screenName;
|
||||
} else {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
|
||||
@@ -8,7 +8,7 @@ const configureExpress = require("./config/express");
|
||||
const systems = require("./controllers/systems");
|
||||
const groups = require("./controllers/groups");
|
||||
const talkgroups = require("./controllers/talkgroups");
|
||||
const Permission = require("./models/permission");
|
||||
|
||||
require("./models/user");
|
||||
const multer = require('multer');
|
||||
|
||||
@@ -60,26 +60,6 @@ mongoose.connection.on('disconnected', () => {
|
||||
const isDev = process.env.NODE_ENV === "development"
|
||||
|
||||
|
||||
/*
|
||||
async function getRole(req) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
if (req.params.shortName && req.user) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
var userId = req.user._id;
|
||||
Permission.findOne({'userId': userId, 'shortName': short_name}, function(err, permission) {
|
||||
if (err) {
|
||||
console.error('Error - getRole userId: ' + userId + ' shortName: ' + short_name + ' error: ' + err);
|
||||
reject(-1);
|
||||
}
|
||||
console.log('Found - getRole userId: ' + userId + ' shortName: ' + short_name + ' role: ' + permission.role);
|
||||
|
||||
resolve(permission.role);
|
||||
});
|
||||
} else {
|
||||
reject(-1);
|
||||
}});
|
||||
return promise;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
|
||||
87
admin/server/models/user.js
Normal file
87
admin/server/models/user.js
Normal file
@@ -0,0 +1,87 @@
|
||||
// Defining a User Model in mongoose
|
||||
// Code modified from https://github.com/sahat/hackathon-starter
|
||||
const bcrypt = require("bcrypt");
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
|
||||
|
||||
const UserSchema = new mongoose.Schema({
|
||||
local: {
|
||||
name: String,
|
||||
email: String,
|
||||
password: String
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
unique: true,
|
||||
lowercase: true
|
||||
},
|
||||
password: String,
|
||||
screenName: {
|
||||
type: String,
|
||||
unique: true,
|
||||
lowercase: true
|
||||
},
|
||||
firstName: String,
|
||||
lastName: String,
|
||||
location: String,
|
||||
email: String,
|
||||
resetPasswordToken: String,
|
||||
resetPasswordTTL: Date,
|
||||
confirmEmail: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
confirmEmailToken: String,
|
||||
confirmEmailTTL: Date,
|
||||
admin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
terms: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
ver: {
|
||||
type: Number,
|
||||
default: 1.1
|
||||
},
|
||||
sysCount: Number,
|
||||
lastLogin: { type : Date, default: Date.now }
|
||||
})
|
||||
|
||||
/**
|
||||
* Password hash middleware.
|
||||
*/
|
||||
UserSchema.pre("save", function(next) {
|
||||
var user = this
|
||||
if (!user.isModified("password")) return next()
|
||||
bcrypt.genSalt(8, (err, salt) => {
|
||||
if (err) return next(err)
|
||||
bcrypt.hash(user.password, salt, null, (err, hash) => {
|
||||
if (err) return next(err)
|
||||
user.password = hash;
|
||||
user.local.password = hash;
|
||||
next()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
Defining our own custom document instance method
|
||||
*/
|
||||
UserSchema.methods = {
|
||||
comparePassword: function(candidatePassword, cb) {
|
||||
bcrypt.compare(candidatePassword, this.local.password, (err, isMatch) => {
|
||||
if (err) return cb(err)
|
||||
cb(null, isMatch)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statics
|
||||
*/
|
||||
UserSchema.statics = {}
|
||||
|
||||
module.exports = mongoose.model("User", UserSchema)
|
||||
Reference in New Issue
Block a user