2021-12-12 14:56:13 +01:00
package routes
import (
"fmt"
"github.com/gin-gonic/gin"
email2 "github.com/uberswe/golang-base-project/email"
"github.com/uberswe/golang-base-project/models"
2022-01-09 14:42:03 +01:00
"github.com/uberswe/golang-base-project/ulid"
2021-12-12 14:56:13 +01:00
"gorm.io/gorm"
"log"
"net/http"
"net/url"
"path"
2021-12-13 20:33:50 +01:00
"time"
2021-12-12 14:56:13 +01:00
)
2022-01-09 14:42:03 +01:00
// ForgotPassword renders the HTML page where a password request can be initiated
2021-12-12 14:56:13 +01:00
func ( controller Controller ) ForgotPassword ( c * gin . Context ) {
2022-01-29 10:21:05 +01:00
pd := controller . DefaultPageData ( c )
pd . Title = pd . Trans ( "Forgot Password" )
2021-12-12 14:56:13 +01:00
c . HTML ( http . StatusOK , "forgotpassword.html" , pd )
}
2022-01-09 14:42:03 +01:00
// ForgotPasswordPost handles the POST request which requests a password reset and then renders the HTML page with the appropriate message
2021-12-12 14:56:13 +01:00
func ( controller Controller ) ForgotPasswordPost ( c * gin . Context ) {
2022-01-29 10:21:05 +01:00
pd := controller . DefaultPageData ( c )
pd . Title = pd . Trans ( "Forgot Password" )
2021-12-12 14:56:13 +01:00
email := c . PostForm ( "email" )
user := models . User { Email : email }
res := controller . db . Where ( & user ) . First ( & user )
if res . Error == nil && user . ActivatedAt != nil {
2022-01-29 10:21:05 +01:00
go controller . forgotPasswordEmailHandler ( user . ID , email , pd . Trans )
2021-12-12 14:56:13 +01:00
}
pd . Messages = append ( pd . Messages , Message {
Type : "success" ,
2022-01-29 10:21:05 +01:00
Content : pd . Trans ( "An email with instructions describing how to reset your password has been sent." ) ,
2021-12-12 14:56:13 +01:00
} )
// We always return a positive response here to prevent user enumeration
c . HTML ( http . StatusOK , "forgotpassword.html" , pd )
}
2022-01-29 10:21:05 +01:00
func ( controller Controller ) forgotPasswordEmailHandler ( userID uint , email string , trans func ( string ) string ) {
2021-12-12 14:56:13 +01:00
forgotPasswordToken := models . Token {
2022-01-09 14:42:03 +01:00
Value : ulid . Generate ( ) ,
2021-12-12 14:56:13 +01:00
Type : models . TokenPasswordReset ,
}
res := controller . db . Where ( & forgotPasswordToken ) . First ( & forgotPasswordToken )
if ( res . Error != nil && res . Error != gorm . ErrRecordNotFound ) || res . RowsAffected > 0 {
// If the forgot password token already exists we try to generate it again
2022-01-29 10:21:05 +01:00
controller . forgotPasswordEmailHandler ( userID , email , trans )
2021-12-12 14:56:13 +01:00
return
}
forgotPasswordToken . ModelID = int ( userID )
forgotPasswordToken . ModelType = "User"
2021-12-13 20:33:50 +01:00
// The token will expire 10 minutes after it was created
forgotPasswordToken . ExpiresAt = time . Now ( ) . Add ( time . Minute * 10 )
2021-12-12 14:56:13 +01:00
res = controller . db . Save ( & forgotPasswordToken )
if res . Error != nil || res . RowsAffected == 0 {
log . Println ( res . Error )
return
}
2022-01-29 10:21:05 +01:00
controller . sendForgotPasswordEmail ( forgotPasswordToken . Value , email , trans )
2021-12-12 14:56:13 +01:00
}
2022-01-29 10:21:05 +01:00
func ( controller Controller ) sendForgotPasswordEmail ( token string , email string , trans func ( string ) string ) {
2021-12-12 14:56:13 +01:00
u , err := url . Parse ( controller . config . BaseURL )
if err != nil {
log . Println ( err )
return
}
u . Path = path . Join ( u . Path , "/user/password/reset/" , token )
resetPasswordURL := u . String ( )
emailService := email2 . New ( controller . config )
2022-01-29 10:21:05 +01:00
emailService . Send ( email , trans ( "Password Reset" ) , fmt . Sprintf ( trans ( "Use the following link to reset your password. If this was not requested by you, please ignore this email.\n%s" ) , resetPasswordURL ) )
2021-12-12 14:56:13 +01:00
}