Skip to content

Commit

Permalink
Merge pull request #4294 from airqo-platform/hf-verify-4
Browse files Browse the repository at this point in the history
new password reset process for the mobile app
  • Loading branch information
Baalmart authored Jan 27, 2025
2 parents 9f2395f + 6cb4b6a commit acf4910
Show file tree
Hide file tree
Showing 9 changed files with 1,137 additions and 97 deletions.
163 changes: 163 additions & 0 deletions src/auth-service/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,169 @@ const createUser = {
return;
}
},
resetPasswordRequest: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}
const { email } = req.body;
const tenant = req.query.tenant;
const token = userUtil.generateNumericToken(5);
const result = await userUtil.initiatePasswordReset(
{
email,
token,
tenant,
},
next
);

res
.status(httpStatus.OK)
.json({ success: true, message: result.message });
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},
resetPassword: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}
const { token } = req.params;
const { password } = req.body;

const defaultTenant = constants.DEFAULT_TENANT || "airqo";
const tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;

const result = await userUtil.resetPassword(
{
token,
password,
tenant,
},
next
);

res
.status(httpStatus.OK)
.json({ success: true, message: result.message });
} catch (error) {
logObject("error in controller", error);
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},

registerMobileUser: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}

const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;

request.body.analyticsVersion = 4;

const result = await userUtil.registerMobileUser(request, next);

if (isEmpty(result) || res.headersSent) {
return;
}

if (result.success === true) {
res
.status(httpStatus.CREATED)
.json({ success: true, message: result.message, data: result.user });
} else {
next(new HttpError(result.message, httpStatus.BAD_REQUEST));
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},

verifyMobileEmail: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}
const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;

const result = await userUtil.verifyMobileEmail(request, next);

if (isEmpty(result) || res.headersSent) {
return;
}
if (result.success) {
res
.status(httpStatus.OK)
.json({ success: true, message: result.message, data: result.user });
} else {
next(new HttpError(result.message, httpStatus.BAD_REQUEST));
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},

subscribeToNewsLetter: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
Expand Down
76 changes: 76 additions & 0 deletions src/auth-service/middleware/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,44 @@ const useEmailWithLocalStrategy = (tenant, req, res, next) =>
)
);
return;
} else if (user.analyticsVersion === 4 && !user.verified) {
await createUserUtil
.mobileVerificationReminder({ tenant, email: user.email }, next)
.then((verificationResponse) => {
if (
!verificationResponse ||
verificationResponse.success === false
) {
logger.error(
`Verification reminder failed: ${
verificationResponse
? verificationResponse.message
: "No response"
}`
);
}
})
.catch((err) => {
logger.error(
`Error sending verification reminder: ${err.message}`
);
});

req.auth.success = false;
req.auth.message =
"account not verified, verification email has been sent to your email";
req.auth.status = httpStatus.FORBIDDEN;
next(
new HttpError(
"account not verified, verification email has been sent to your email",
httpStatus.FORBIDDEN,
{
message:
"account not verified, verification email has been sent to your email",
}
)
);
return;
}
req.auth.success = true;
req.auth.message = "successful login";
Expand Down Expand Up @@ -294,6 +332,44 @@ const useUsernameWithLocalStrategy = (tenant, req, res, next) =>
)
);
return;
} else if (user.analyticsVersion === 4 && !user.verified) {
createUserUtil
.mobileVerificationReminder({ tenant, email: user.email }, next)
.then((verificationResponse) => {
if (
!verificationResponse ||
verificationResponse.success === false
) {
logger.error(
`Verification reminder failed: ${
verificationResponse
? verificationResponse.message
: "No response"
}`
);
}
})
.catch((err) => {
logger.error(
`Error sending verification reminder: ${err.message}`
);
});

req.auth.success = false;
req.auth.message =
"account not verified, verification email has been sent to your email";
req.auth.status = httpStatus.FORBIDDEN;
next(
new HttpError(
"account not verified, verification email has been sent to your email",
httpStatus.FORBIDDEN,
{
message:
"account not verified, verification email has been sent to your email",
}
)
);
return;
}
req.auth.success = true;
req.auth.message = "successful login";
Expand Down
22 changes: 8 additions & 14 deletions src/auth-service/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ const UserSchema = new Schema(
},
userName: {
type: String,
required: [true, "UserName is required!"],
trim: true,
unique: true,
},
Expand Down Expand Up @@ -404,6 +403,14 @@ UserSchema.pre(
return next(new Error("Phone number or email is required!"));
}

if (!this.userName && this.email) {
this.userName = this.email;
}

if (!this.userName) {
return next(new Error("userName is required!"));
}

// Profile picture validation - only for new documents
if (
this.profilePicture &&
Expand Down Expand Up @@ -470,10 +477,6 @@ UserSchema.pre(
];
}

// Ensure default values for new documents
this.verified = this.verified ?? false;
this.analyticsVersion = this.analyticsVersion ?? 2;

// Permissions handling for new documents
if (this.permissions && this.permissions.length > 0) {
this.permissions = [...new Set(this.permissions)];
Expand Down Expand Up @@ -581,15 +584,6 @@ UserSchema.pre(
updates.permissions = uniquePermissions;
}
}

// Conditional default values for updates
if (updates && updates.$set) {
updates.$set.verified = updates.$set.verified ?? false;
updates.$set.analyticsVersion = updates.$set.analyticsVersion ?? 2;
} else {
updates.verified = updates.verified ?? false;
updates.analyticsVersion = updates.analyticsVersion ?? 2;
}
}

// Additional checks for new documents
Expand Down
Loading

0 comments on commit acf4910

Please sign in to comment.