8000 updated · wpcodevo/golang-mongodb-api@684351b · GitHub
[go: up one dir, main page]

Skip to content

Commit 684351b

Browse files
committed
updated
1 parent eec7c91 commit 684351b

File tree

5 files changed

+174
-24
lines changed

5 files changed

+174
-24
lines changed

controllers/auth.controller.go

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"net/http"
88
"strings"
9+
"time"
910

1011
"github.com/gin-gonic/gin"
1112
"github.com/thanhpk/randstr"
@@ -78,7 +79,11 @@ func (ac *AuthController) SignUpUser(ctx *gin.Context) {
7879
Subject: "Your account verification code",
7980
}
8081

81-
utils.SendEmail(newUser, &emailData)
82+
err = utils.SendEmail(newUser, &emailData, "verificationCode.html")
83+
if err != nil {
84+
ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"})
85+
return
86+
}
8287

8388
message := "We sent an email with a verification code to " + user.Email
8489
ctx.JSON(http.StatusCreated, gin.H{"status": "success", "message": message})
@@ -201,3 +206,73 @@ func (ac *AuthController) VerifyEmail(ctx *gin.Context) {
201206
ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": "Email verified successfully"})
202207

203208
}
209+
210+
func (ac *AuthController) ForgotPassword(ctx *gin.Context) {
211+
var userCredential *models.ForgotPasswordInput
212+
213+
if err := ctx.ShouldBindJSON(&userCredential); err != nil {
214+
ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()})
215+
return
216+
}
217+
218+
message := "You will receive a reset email if user with that email exist"
219+
220+
user, err := ac.userService.FindUserByEmail(userCredential.Email)
221+
if err != nil {
222+
if err == mongo.ErrNoDocuments {
223+
ctx.JSON(http.StatusOK, gin.H{"status": "fail", "message": message})
224+
return
225+
}
226+
ctx.JSON(http.StatusBadGateway, gin.H{"status": "error", "message": err.Error()})
227+
return
228+
}
229+
230+
if !user.Verified {
231+
ctx.JSON(http.StatusUnauthorized, gin.H{"status": "error", "message": "Account not verified"})
232+
return
233+
}
234+
235+
config, err := config.LoadConfig(".")
236+
if err != nil {
237+
log.Fatal("Could not load config", err)
238+
}
239+
240+
// Generate Verification Code
241+
resetToken := randstr.String(20)
242+
243+
passwordResetToken := utils.Encode(resetToken)
244+
245+
// Update User in Database
246+
query := bson.D{{Key: "email", Value: strings.ToLower(userCredential.Email)}}
247+
update := bson.D{{Key: "$set", Value: bson.D{{Key: "passwordResetToken", Value: passwordResetToken}, {Key: "passwordResetAt", Value: time.Now().Add(time.Minute * 15)}}}}
248+
result, err := ac.collection.UpdateOne(ac.ctx, query, update)
249+
250+
if result.MatchedCount == 0 {
251+
ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"})
252+
return
253+
}
254+
255+
if err != nil {
256+
ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": err.Error()})
257+
return
258+
}
259+
var firstName = user.Name
260+
261+
if strings.Contains(firstName, " ") {
262+
firstName = strings.Split(firstName, " ")[1]
263+
}
264+
265+
// 👇 Send Email
266+
emailData := utils.EmailData{
267+
URL: config.Origin + "/forgotPassword/" + resetToken,
268+
FirstName: firstName,
269+
Subject: "Your password reset token (valid for 10min)",
270+
}
271+
272+
err = utils.SendEmail(user, &emailData, "resetPassword.html")
273+
if err != nil {
274+
ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"})
275+
return
276+
}
277+
ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": message})
278+
}

models/user.model.go

Lines changed: 34 additions & 19 deletions
F438
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import (
88

99
// 👈 SignUpInput struct
1010
type SignUpInput struct {
11-
Name string `json:"name" bson:"name" binding:"required"`
12-
Email string `json:"email" bson:"email" binding:"required"`
13-
Password string `json:"password" bson:"password" binding:"required,min=8"`
14-
PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"`
15-
Role string `json:"role" bson:"role"`
16-
VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"`
17-
Verified bool `json:"verified" bson:"verified"`
18-
CreatedAt time.Time `json:"created_at" bson:"created_at"`
19-
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
11+
Name string `json:"name" bson:"name" binding:"required"`
12+
Email string `json:"email" bson:"email" binding:"required"`
13+
Password string `json:"password" bson:"password" binding:"required,min=8"`
14+
PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"`
15+
Role string `json:"role" bson:"role"`
16+
VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"`
17+
ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"`
18+
ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"`
19+
Verified bool `json:"verified" bson:"verified"`
20+
CreatedAt time.Time `json:"created_at" bson:"created_at"`
21+
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
2022
}
2123

2224
// 👈 SignInInput struct
@@ -27,16 +29,18 @@ type SignInInput struct {
2729

2830
// 👈 DBResponse struct
2931
type DBResponse struct {
30-
ID primitive.ObjectID `json:"id" bson:"_id"`
31-
Name string `json:"name" bson:"name"`
32-
Email string `json:"email" bson:"email"`
33-
Password string `json:"password" bson:"password"`
34-
PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"`
35-
Role string `json:"role" bson:"role"`
36-
VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode"`
37-
Verified bool `json:"verified" bson:"verified"`
38-
CreatedAt time.Time `json:"created_at" bson:"created_at"`
39-
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
32+
ID primitive.ObjectID `json:"id" bson:"_id"`
33+
Name string `json:"name" bson:"name"`
34+
Email string `json:"email" bson:"email"`
35+
Password string `json:"password" bson:"password"`
36+
PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"`
37+
Role string `json:"role" bson:"role"`
38+
VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode"`
39+
ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"`
40+
ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"`
41+
Verified bool `json:"verified" bson:"verified"`
42+
CreatedAt time.Time `json:"created_at" bson:"created_at"`
43+
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
4044
}
4145

4246
// 👈 UserResponse struct
@@ -49,6 +53,17 @@ type UserResponse struct {
4953
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
5054
}
5155

56+
// 👈 ForgotPasswordInput struct
57+
type ForgotPasswordInput struct {
58+
Email string `json:"email" bson:"email" binding:"required"`
59+
}
60+
61+
// 👈 ResetPasswordInput struct
62+
type ResetPasswordInput struct {
63+
Password string `json:"password" bson:"password"`
64+
PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"`
65+
}
66+
5267
func FilteredResponse(user *DBResponse) UserResponse {
5368
return UserResponse{
5469
ID: user.ID,

routes/auth.routes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ func (rc *AuthRouteController) AuthRoute(rg *gin.RouterGroup, userService servic
2323
router.GET("/refresh", rc.authController.RefreshAccessToken)
2424
router.GET("/logout", middleware.DeserializeUser(userService), rc.authController.LogoutUser)
2525
router.GET("/verifyemail/:verificationCode", rc.authController.VerifyEmail)
26+
router.POST("/forgotPassword", rc.authController.ForgotPassword)
2627
}

templates/resetPassword.html

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{{template "base" .}} {{define "content"}}
2+
<table role="presentation" class="main">
3+
<!-- START MAIN CONTENT AREA -->
4+
<tr>
5+
<td class="wrapper">
6+
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
7+
<tr>
8+
<td>
9+
<p>Hi {{ .FirstName}},</p> 10000
10+
<p>
11+
Forgot password? Send a PATCH request to with your password and
12+
passwordConfirm to {{.URL}}
13+
</p>
14+
<table
15+
role="presentation"
16+
border="0"
17+
cellpadding="0"
18+
cellspacing="0"
19+
class="btn btn-primary"
20+
>
21+
<tbody>
22+
<tr>
23+
<td align="left">
24+
<table
25+
role="presentation"
26+
border="0"
27+
cellpadding="0"
28+
cellspacing="0"
29+
>
30+
<tbody>
31+
<tr>
32+
<td>
33+
<a href="{{.URL}}" target="_blank"
34+
>Reset password</a
35+
>
36+
</td>
37+
</tr>
38+
</tbody>
39+
</table>
40+
</td>
41+
</tr>
42+
</tbody>
43+
</table>
44+
<p>If you didn't forget your password, please ignore this email</p>
45+
<p>Good luck! Codevo CEO.</p>
46+
</td>
47+
</tr>
48+
</table>
49+
</td>
50+
</tr>
51+
52+
<!-- END MAIN CONTENT AREA -->
53+
</table>
54+
{{end}}

utils/email.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package utils
33
import (
44
"bytes"
55
"crypto/tls"
6+
"fmt"
67
"log"
78
"os"
89
"path/filepath"
@@ -34,14 +35,16 @@ func ParseTemplateDir(dir string) (*template.Template, error) {
3435
return nil
3536
})
3637

38+
fmt.Println("Am parsing templates...")
39+
3740
if err != nil {
3841
return nil, err
3942
}
4043

4144
return template.ParseFiles(paths...)
4245
}
4346

44-
func SendEmail(user *models.DBResponse, data *EmailData) {
47+
func SendEmail(user *models.DBResponse, data *EmailData, templateName string) error {
4548
config, err := config.LoadConfig(".")
4649

4750
if err != nil {
@@ -63,7 +66,9 @@ func SendEmail(user *models.DBResponse, data *EmailData) {
6366
log.Fatal("Could not parse template", err)
6467
}
6568

66-
template.ExecuteTemplate(&body, "verificationCode.html", &data)
69+
template = template.Lookup(templateName)
70+
template.Execute(&body, &data)
71+
fmt.Println(template.Name())
6772

6873
m := gomail.NewMessage()
6974

@@ -78,7 +83,7 @@ func SendEmail(user *models.DBResponse, data *EmailData) {
7883

7984
// Send Email
8085
if err := d.DialAndSend(m); err != nil {
81-
log.Fatal("Could not send email: ", err)
86+
return err
8287
}
83-
88+
return nil
8489
}

0 commit comments

Comments
 (0)
0