mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-11 08:17:29 -05:00
Seems to be all working!!
This commit is contained in:
@@ -26,6 +26,10 @@ const local = new LocalStrategy({
|
||||
console.error("Auth Error - user not found: " + email);
|
||||
return done(null, false, { message: `Invalid email or password` })
|
||||
}
|
||||
if (!user.confirmEmail) {
|
||||
console.error("Auth Error - user has not confirmed email: " + email);
|
||||
return done(null, false, { message: `User's email is not confirmed` })
|
||||
}
|
||||
user.comparePassword(password, (err, isMatch) => {
|
||||
if (isMatch) {
|
||||
return done(null, user)
|
||||
|
||||
@@ -91,10 +91,14 @@ exports.login = function (req, res, next) {
|
||||
}
|
||||
if (!user.confirmEmail) {
|
||||
req.logout();
|
||||
return res.json({
|
||||
success: false,
|
||||
message: "unconfirmed email",
|
||||
userId: user.id
|
||||
req.logout(function (err) {
|
||||
if (err) { return next(err); }
|
||||
res.clearCookie('sessionId', { domain: cookie_domain, path: '/' });
|
||||
return res.json({
|
||||
success: false,
|
||||
message: "unconfirmed email",
|
||||
userId: user.id
|
||||
});
|
||||
});
|
||||
}
|
||||
//console.log("account/server/controllers/users.js - req.login() Authenicated: " + user.email);
|
||||
@@ -370,20 +374,20 @@ function handleSendConfirmEmail(user) {
|
||||
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
|
||||
}).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
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -425,10 +429,13 @@ exports.sendConfirmEmail = async 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: '/' });
|
||||
return res.json({
|
||||
success: true
|
||||
req.logout(function (err) {
|
||||
if (err) { return next(err); }
|
||||
|
||||
res.clearCookie('sessionId', { domain: cookie_domain, path: '/' });
|
||||
return res.json({
|
||||
success: true
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -542,6 +549,30 @@ exports.updateProfile = async function (req, res, next) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Lets make sure someone else isn't using this screenName
|
||||
screenNameUser = await User.findOne({ screenName: req.body.screenName }).catch(err => {
|
||||
console.error(err);
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
// Did we find a user with the screeName, is it not us?
|
||||
if (screenNameUser && (screenNameUser.userId != user.userId)) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
success: false,
|
||||
message: "Screen Name already in use"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// go ahead and create the new user
|
||||
user.firstName = res.locals.firstName
|
||||
user.lastName = res.locals.lastName
|
||||
@@ -608,6 +639,24 @@ exports.register = async function (req, res, next) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
user = await User.findOne({ screenName: req.body.screenName }).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: "Screen Name already in use"
|
||||
});
|
||||
return;
|
||||
}
|
||||
// go ahead and create the new user
|
||||
user = (({
|
||||
firstName,
|
||||
@@ -628,12 +677,16 @@ exports.register = async function (req, res, next) {
|
||||
user.password = req.body.password;
|
||||
user.email = req.body.email;
|
||||
|
||||
await User.create(user)
|
||||
let savedUser = 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);
|
||||
// Since registration worked, send a confirmation email.
|
||||
handleSendConfirmEmail(savedUser).then(function (result) {
|
||||
console.log("Confirmation email sent to: " + user.email);
|
||||
res.json({
|
||||
success: true,
|
||||
message: result
|
||||
});
|
||||
return;
|
||||
}).catch(function (err) {
|
||||
console.error("Error creating user: " + user.email + " Error: " + err);
|
||||
|
||||
@@ -15,25 +15,25 @@ import ResetPassword from "../User/ResetPassword"
|
||||
import Terms from "../User/Terms"
|
||||
|
||||
const App = (params) => {
|
||||
const {store} = params;
|
||||
return (
|
||||
<div>
|
||||
<Navigation/>
|
||||
<Routes>
|
||||
<Route exact path="/" element={ <Restricted><Profile/></Restricted>} />
|
||||
<Route path="/login" element={ <Login/>} />
|
||||
<Route path="/register" element={ <Register/> } />
|
||||
<Route path="/wait-confirm-email" element={ <WaitConfirmEmail/> } />
|
||||
<Route path="/sent-confirm-email" element={ <SentConfirmEmail/> } />
|
||||
<Route path="/send-reset-password" element={ <SendResetPassword/> } />
|
||||
<Route path="/reset-password/:userId/:token" element={ <ResetPassword/> } />
|
||||
<Route path="/confirm-email/:userId/:token" element={ <ConfirmEmail/> } />
|
||||
<Route path="/terms" element={ <Restricted><Terms/></Restricted>} />
|
||||
<Route path="/profile" element={ <Restricted><Profile/></Restricted>} />
|
||||
<Route render={() => (<div>Miss</div>)} />
|
||||
</Routes>
|
||||
</div>
|
||||
)
|
||||
const { store } = params;
|
||||
return (
|
||||
<div>
|
||||
<Navigation />
|
||||
<Routes>
|
||||
<Route exact path="/" element={<Restricted><Profile /></Restricted>} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/wait-confirm-email" element={<WaitConfirmEmail />} />
|
||||
<Route path="/sent-confirm-email" element={<SentConfirmEmail />} />
|
||||
<Route path="/send-reset-password" element={<SendResetPassword />} />
|
||||
<Route path="/reset-password/:userId/:token" element={<ResetPassword />} />
|
||||
<Route path="/confirm-email/:userId/:token" element={<ConfirmEmail />} />
|
||||
<Route path="/terms" element={<Restricted><Terms /></Restricted>} />
|
||||
<Route path="/profile" element={<Restricted><Profile /></Restricted>} />
|
||||
<Route render={() => (<div>Miss</div>)} />
|
||||
</Routes>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default App
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
// in src/restricted.js
|
||||
import React, { useEffect} from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { authenticateUser } from "../features/user/userSlice";
|
||||
import { authenticateUser } from "../features/user/userSlice";
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
/**
|
||||
* Higher-order component (HOC) to wrap restricted pages
|
||||
*/
|
||||
|
||||
const Restricted = ({children }) => {
|
||||
const Restricted = ({ children }) => {
|
||||
const { authenticated, hasAuthenticated } = useSelector((state) => state.user);
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(authenticateUser({}));
|
||||
},[]);
|
||||
}, []);
|
||||
|
||||
if (hasAuthenticated) {
|
||||
if (authenticated) {
|
||||
return children;;
|
||||
}
|
||||
else {
|
||||
|
||||
navigate("/list-systems")
|
||||
}
|
||||
}
|
||||
return <div/>
|
||||
|
||||
return children;
|
||||
}
|
||||
else {
|
||||
navigate("/login")
|
||||
}
|
||||
}
|
||||
return <div />
|
||||
|
||||
};
|
||||
|
||||
export default Restricted
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Container,
|
||||
Dimmer,
|
||||
@@ -7,72 +7,65 @@ import {
|
||||
Message,
|
||||
Icon
|
||||
} from "semantic-ui-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { confirmEmail } from "../features/user/userSlice";
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
class ConfirmEmail extends Component {
|
||||
const ConfirmEmail = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [confirmMessage, setConfirmMessage] = useState({ success: false, message: "" });
|
||||
const { userId, token } = useParams();
|
||||
|
||||
state = {
|
||||
loading: true,
|
||||
confirmMessage: { success: false, message:""}
|
||||
};
|
||||
componentDidMount() {
|
||||
const { match: { params } } = this.props;
|
||||
|
||||
this.props
|
||||
.confirmEmail(params.userId, params.token)
|
||||
.then(confirmMessage => {
|
||||
if (confirmMessage) {
|
||||
// report to the user is there was a problem during login
|
||||
this.setState({
|
||||
confirmMessage: confirmMessage, loading: false
|
||||
});
|
||||
}
|
||||
});
|
||||
const checkConfirmation = async(userId, token) => {
|
||||
const result = await dispatch(confirmEmail({ userId, token })).unwrap();
|
||||
if (result) {
|
||||
setConfirmMessage(result);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
var dimmerProps = { };
|
||||
if (this.state.loading) {
|
||||
dimmerProps["active"] = true;
|
||||
}
|
||||
return (
|
||||
useEffect(() => {
|
||||
checkConfirmation(userId, token);
|
||||
}, []);
|
||||
|
||||
<Container text>
|
||||
const dimmerProps = { active: loading };
|
||||
|
||||
return (
|
||||
<Container text>
|
||||
<Dimmer {...dimmerProps}>
|
||||
<Loader indeterminate>Confirming Email Address</Loader>
|
||||
</Dimmer>
|
||||
|
||||
|
||||
{this.state.confirmMessage.success ? (
|
||||
<Message icon>
|
||||
|
||||
<Icon name='check'/>
|
||||
<Message.Content>
|
||||
<Message.Header>Success</Message.Header>
|
||||
<p>You have successfully confirmed you email address.</p>
|
||||
<Link to="/">
|
||||
<Button
|
||||
size="large"
|
||||
content="Continue to Login"
|
||||
fluid
|
||||
/></Link>
|
||||
<Loader indeterminate>Confirming Email Address</Loader>
|
||||
</Dimmer>
|
||||
|
||||
</Message.Content>
|
||||
</Message>
|
||||
) : (
|
||||
<Message icon>
|
||||
<Icon name='exclamation'/>
|
||||
{confirmMessage.success ? (
|
||||
<Message icon>
|
||||
<Icon name='check' />
|
||||
<Message.Content>
|
||||
<Message.Header>Success</Message.Header>
|
||||
<p>You have successfully confirmed you email address.</p>
|
||||
<Link to="/login">
|
||||
<Button
|
||||
size="large"
|
||||
content="Continue to Login"
|
||||
fluid
|
||||
/></Link>
|
||||
</Message.Content>
|
||||
</Message>
|
||||
) : (
|
||||
<Message icon>
|
||||
<Icon name='exclamation' />
|
||||
<Message.Content>
|
||||
<Message.Header>Error</Message.Header>
|
||||
<p>{this.state.confirmMessage.message}</p>
|
||||
<p>{confirmMessage.message}</p>
|
||||
</Message.Content>
|
||||
|
||||
</Message>
|
||||
)}
|
||||
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
</Message>
|
||||
)}
|
||||
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConfirmEmail;
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const Profile = (props) => {
|
||||
if (result.success) {
|
||||
console.log(result)
|
||||
} else {
|
||||
setMessage = result.message;
|
||||
setMessage(result.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { registerUser } from "../features/user/userSlice";
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import { registerUser } from "../features/user/userSlice";
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import {
|
||||
Container,
|
||||
@@ -15,32 +15,32 @@ function Register(props) {
|
||||
const [requestMessage, setRequestMessage] = useState("");
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const onRegisterSubmit = async(user) => {
|
||||
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);
|
||||
}
|
||||
navigate("/sent-confirm-email");
|
||||
} else {
|
||||
console.error(result);
|
||||
setRequestMessage(result.message);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container text>
|
||||
<Message icon>
|
||||
<Icon name='trophy'/>
|
||||
<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>
|
||||
<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}/>
|
||||
<UserForm onSubmit={onRegisterSubmit} requestMessage={requestMessage} isWaiting={props.isWaiting} />
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -43,7 +43,6 @@ const ResetPassword = (props) => {
|
||||
setConfirmPasswordError(false);
|
||||
}
|
||||
|
||||
const { match: { params } } = props;
|
||||
setCheckInputMessages(inputMessages);
|
||||
if (!error) {
|
||||
const result = await dispatch(resetPassword({ userId, token, password })).unwrap();
|
||||
|
||||
@@ -28,6 +28,7 @@ const UserForm = (props) => {
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const [confirmPasswordError, setConfirmPasswordError] = useState(false);
|
||||
const [isEditing, setIsEditing] = useState(props.isEditing);
|
||||
const [changed, setChanged] = useState(false);
|
||||
const requestMessage = props.requestMessage;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,6 +38,7 @@ const UserForm = (props) => {
|
||||
setScreenName(props.user.screenName);
|
||||
setEmail(props.user.email);
|
||||
setLocation(props.user.location);
|
||||
setChanged(false);
|
||||
}
|
||||
}, [props.isEditing, props.user]);
|
||||
|
||||
@@ -120,6 +122,7 @@ const UserForm = (props) => {
|
||||
|
||||
if (!inputError) {
|
||||
const user ={ firstName, lastName, screenName, location, email, password };
|
||||
setChanged(false);
|
||||
props.onSubmit(user);
|
||||
}
|
||||
}
|
||||
@@ -153,6 +156,7 @@ const UserForm = (props) => {
|
||||
</Message>
|
||||
);
|
||||
}
|
||||
const buttonDisabled = changed?{}:{disabled:true}
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
@@ -168,7 +172,7 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="firstName"
|
||||
onChange={e => setFirstName(e.target.value)}
|
||||
onChange={e => {setFirstName(e.target.value); setChanged(true)}}
|
||||
error={firstNameError}
|
||||
value={firstName}
|
||||
label="First name"
|
||||
@@ -179,7 +183,7 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="lastName"
|
||||
onChange={e => setLastName(e.target.value)}
|
||||
onChange={e => {setLastName(e.target.value); setChanged(true)}}
|
||||
error={lastNameError}
|
||||
value={lastName}
|
||||
label="Last name"
|
||||
@@ -192,7 +196,7 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="email"
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
onChange={e => {setEmail(e.target.value); setChanged(true)}}
|
||||
error={emailError}
|
||||
value={email}
|
||||
disabled={isEditing}
|
||||
@@ -205,7 +209,7 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="screenName"
|
||||
onChange={e => setScreenName(e.target.value)}
|
||||
onChange={e => {setScreenName(e.target.value); setChanged(true)}}
|
||||
error={screenNameError}
|
||||
value={screenName}
|
||||
label="Screen Name"
|
||||
@@ -221,7 +225,7 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
type="text"
|
||||
name="location"
|
||||
onChange={e => setLocation(e.target.value)}
|
||||
onChange={e => {setLocation(e.target.value); setChanged(true)}}
|
||||
error={locationError}
|
||||
value={location}
|
||||
label="General Location"
|
||||
@@ -235,7 +239,8 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
name="password"
|
||||
type="password"
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
onChange={e => {setPassword(e.target.value); setChanged(true)}}
|
||||
value={password}
|
||||
error={passwordError}
|
||||
disabled={isEditing}
|
||||
label="Password"
|
||||
@@ -246,7 +251,8 @@ const UserForm = (props) => {
|
||||
<Form.Input
|
||||
name="confirmPassword"
|
||||
type="password"
|
||||
onChange={e => setConfirmPassword(e.target.value)}
|
||||
onChange={e => {setConfirmPassword(e.target.value); setChanged(true)}}
|
||||
value={confirmPassword}
|
||||
error={confirmPasswordError}
|
||||
disabled={isEditing}
|
||||
label="Confirm Password"
|
||||
@@ -256,7 +262,7 @@ const UserForm = (props) => {
|
||||
</Form.Group>
|
||||
)}
|
||||
<div style={floatStyle}>
|
||||
<Button type="submit" size="large" floated="right" value="Login" color='blue'>
|
||||
<Button type="submit" size="large" floated="right" value="Login" color='blue' disabled={!changed}>
|
||||
{isEditing !== true ? 'Register' : 'Update'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -90,6 +90,22 @@ export const logoutUser = createAsyncThunk(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
export const confirmEmail = createAsyncThunk(
|
||||
'user/confirmEmail',
|
||||
async ({userId, token}) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/users/" + userId + "/confirm/" + token;
|
||||
const res = await fetch(url, {
|
||||
method: 'POST'
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
export const sendConfirmEmail = createAsyncThunk(
|
||||
'user/sendConfirmEmail',
|
||||
async (userId) => {
|
||||
@@ -111,7 +127,7 @@ 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 url = process.env.REACT_APP_ACCOUNT_SERVER + "/users/" + userId + "/reset-password/" + token
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
@@ -192,19 +208,11 @@ export const userSlice = createSlice({
|
||||
[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;
|
||||
|
||||
Reference in New Issue
Block a user