Skip to content

Commit 429da39

Browse files
authored
Merge pull request #120 from rdkelley/mqtt
Add forgot password routes, onboarding links for inactive accounts
2 parents 8ccbe51 + aa09dda commit 429da39

File tree

8 files changed

+263
-65
lines changed

8 files changed

+263
-65
lines changed

web/api/rest/routes.js

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ module.exports = (app) => {
4646
*/
4747
app.post('/api/verification', apiKeyAuth, async (req, res) => {
4848
const { email, givenName, familyName } = req.body;
49+
let link;
4950
let results;
51+
let user;
5052

5153
if (!email || !validator.validate(email)) {
5254
return res.status(400).json({ message: 'Email missing' });
@@ -57,20 +59,16 @@ module.exports = (app) => {
5759

5860
// If no user, create user
5961
if (results.totalResults === 0) {
60-
const user = await AppIdManagement.createUser(
61-
email,
62-
givenName,
63-
familyName,
64-
);
65-
66-
const token = await jwt.encode({ id: user.id });
62+
user = await AppIdManagement.createUser(email, givenName, familyName);
6763

68-
const link = `${dashboardURL}/onboard?${qs.stringify({
69-
token,
64+
link = `${dashboardURL}/onboard?${qs.stringify({
65+
token: await jwt.encode({ id: user.id }),
7066
})}`;
7167

7268
return res.json({
7369
verified: false,
70+
new: true,
71+
active: false,
7472
givenName,
7573
familyName,
7674
email,
@@ -79,17 +77,26 @@ module.exports = (app) => {
7977
});
8078
}
8179

80+
user = results.Resources[0];
81+
82+
// If user has account, but has not finished
83+
// onboarding, generate new link & token
84+
if (!user.active) {
85+
link = `${dashboardURL}/onboard?${qs.stringify({
86+
token: await jwt.encode({ id: user.id }),
87+
})}`;
88+
}
89+
90+
await jwt.encode({ id: user.id });
8291
return res.json({
8392
verified: true,
84-
givenName: results.Resources[0].name
85-
? results.Resources[0].name.givenName
86-
: null,
87-
familyName: results.Resources[0].name
88-
? results.Resources[0].name.familyName
89-
: null,
90-
uuid: results.Resources[0].id,
93+
new: false,
94+
active: user.active,
95+
givenName: user.name ? user.name.givenName : null,
96+
familyName: user.name ? user.name.familyName : null,
97+
uuid: user.id,
9198
email,
92-
link: null,
99+
link: !user.active ? link : null,
93100
});
94101
} catch (e) {
95102
return res.status(500).json({ message: 'Error verifying user' });
@@ -255,6 +262,31 @@ module.exports = (app) => {
255262
})(req, res, next);
256263
});
257264

265+
app.post('/api/forgot-password', async (req, res) => {
266+
const { email } = req.body;
267+
268+
if (!email) {
269+
return res.status(400).json({ message: 'Missing email.' });
270+
}
271+
272+
try {
273+
await AppIdManagement.forgotPassword(email);
274+
275+
return res.json({ success: true });
276+
} catch (e) {
277+
// To not indicate whether a user exists in db,
278+
// a success message is returned if the user is not found
279+
if (e.message === 'user_not_found') {
280+
return res.json({ success: true });
281+
}
282+
283+
return res.status(500).json({
284+
message: 'Error processing forgot password.',
285+
clientCode: 'error_forgot_password',
286+
});
287+
}
288+
});
289+
258290
app.post('/api/logout', (req, res) => {
259291
req.session.destroy((err) => {
260292
if (err) {

web/api/services/appId.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,42 @@ class AppIdManagement {
242242
return json;
243243
}
244244

245+
async forgotPassword(email) {
246+
const iam = await this.iamAuth;
247+
248+
const data = JSON.stringify({
249+
user: email,
250+
});
251+
252+
const response = await fetch(
253+
`https://us-south.appid.cloud.ibm.com/management/v4/${TENET_ID}/cloud_directory/forgot_password`,
254+
{
255+
method: 'POST',
256+
headers: {
257+
// eslint-disable-next-line quote-props
258+
Accept: 'application/json',
259+
// eslint-disable-next-line quote-props
260+
Authorization: `Bearer ${iam.token}`,
261+
'Content-Type': 'application/json',
262+
},
263+
body: data,
264+
},
265+
);
266+
267+
if (!response.ok) {
268+
const error = await response.json();
269+
console.error(error);
270+
271+
if (error.error === 'user not found') {
272+
throw new Error('user_not_found');
273+
}
274+
275+
throw new Error('forgot_password_fail');
276+
}
277+
278+
return response.ok;
279+
}
280+
245281
async removeUser(id) {
246282
const iam = await this.iamAuth;
247283

web/client/src/components/LoginInput/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ const LoginInput = ({
1818
initLogin,
1919
loginId,
2020
setError,
21+
setForgotPassword,
22+
forgotPassword,
2123
}) => {
2224
const { t } = useContext(AppContext)
2325
const [attemptedSubmit, setAttemptedSubmit] = useState(false)
@@ -27,6 +29,12 @@ const LoginInput = ({
2729
const returnToEmail = () => {
2830
setError('')
2931
setStep(1)
32+
setForgotPassword({
33+
email: '',
34+
request: false,
35+
success: false,
36+
error: '',
37+
})
3038
}
3139

3240
useEffect(() => {
@@ -52,6 +60,10 @@ const LoginInput = ({
5260
onSubmit={(values, { setSubmitting }) => {
5361
if (step === 1) {
5462
setLoginId(values.openeewId)
63+
setForgotPassword({
64+
...forgotPassword,
65+
email: values.openeewId,
66+
})
5567

5668
setStep(2)
5769
} else {

web/client/src/components/SensorsInformationSidePanel/SensorsInformationSidePanel.scss

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@
44
bottom: 0;
55
right: 0;
66
padding: $layout-02 $layout-03;
7-
background-color: #2C2C2C;
7+
background-color: #2c2c2c;
88
border-left: 1px solid #515151;
99

1010
.bx--toast-notification {
1111
width: 100%;
1212
color: #fff;
1313
background-color: #393939;
1414

15-
border-left: 3px solid #6D96DD;
15+
border-left: 3px solid #6d96dd;
1616

1717
.bx--toast-notification__icon {
18-
fill: #6D96DD;
18+
fill: #6d96dd;
1919
}
2020

2121
a {
22-
color: #6D96DD;
22+
color: #6d96dd;
2323
}
2424
}
2525

@@ -33,7 +33,7 @@
3333
}
3434
}
3535
.tag-owner {
36-
margin-Left: 40px;
36+
margin-left: 40px;
3737
}
3838
}
3939

@@ -78,9 +78,9 @@
7878
text-align: left;
7979
cursor: pointer;
8080

81-
&[data-testing-sensor="true"] {
82-
color: #FF5D5D;
83-
border: 1px solid #FF5D5D;
81+
&[data-testing-sensor='true'] {
82+
color: #ff5d5d;
83+
border: 1px solid #ff5d5d;
8484
}
8585
}
8686

@@ -91,10 +91,10 @@
9191
.sensors-side-panel__restarting {
9292
display: flex;
9393
align-items: center;
94-
position:absolute;
94+
position: absolute;
9595
left: calc(24px);
9696
margin-top: 10px;
97-
color: #9C9C9C;
97+
color: #9c9c9c;
9898

9999
p {
100100
margin-left: $spacing-02;

web/client/src/content/Login/Login.scss

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
min-height: 1.5rem;
3939
}
4040

41-
.login__container .bx--inline-notification--error {
41+
.login__container .bx--inline-notification--error,
42+
.login__container .bx--inline-notification--success {
4243
background: #393939;
4344
color: white;
4445
}
@@ -50,6 +51,16 @@
5051
margin-right: $spacing-03;
5152
}
5253

54+
.login__forgotPasswordLoading {
55+
position: relative;
56+
left: -5px;
57+
}
58+
59+
.login__forgotPasswordSuccess span {
60+
@include carbon--type-style('body-short-01');
61+
color: #5ec07a;
62+
}
63+
5364
.login__supportingContainer {
5465
min-height: $layout-05;
5566
}
@@ -105,4 +116,8 @@
105116
.login__supportingContainer {
106117
min-height: $layout-06 / 2;
107118
}
119+
120+
.bx--inline-notification {
121+
max-width: none;
122+
}
108123
}

0 commit comments

Comments
 (0)