Add Support for reset password for selfhosted version without email configration
This commit is contained in:
commit
7c71515b62
2 changed files with 63 additions and 9 deletions
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"donetick.com/core/config"
|
||||||
auth "donetick.com/core/internal/authorization"
|
auth "donetick.com/core/internal/authorization"
|
||||||
cModel "donetick.com/core/internal/circle/model"
|
cModel "donetick.com/core/internal/circle/model"
|
||||||
cRepo "donetick.com/core/internal/circle/repo"
|
cRepo "donetick.com/core/internal/circle/repo"
|
||||||
|
@ -25,18 +26,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
userRepo *uRepo.UserRepository
|
userRepo *uRepo.UserRepository
|
||||||
circleRepo *cRepo.CircleRepository
|
circleRepo *cRepo.CircleRepository
|
||||||
jwtAuth *jwt.GinJWTMiddleware
|
jwtAuth *jwt.GinJWTMiddleware
|
||||||
email *email.EmailSender
|
email *email.EmailSender
|
||||||
|
isDonetickDotCom bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(ur *uRepo.UserRepository, cr *cRepo.CircleRepository, jwtAuth *jwt.GinJWTMiddleware, email *email.EmailSender) *Handler {
|
func NewHandler(ur *uRepo.UserRepository, cr *cRepo.CircleRepository, jwtAuth *jwt.GinJWTMiddleware, email *email.EmailSender, config *config.Config) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
userRepo: ur,
|
userRepo: ur,
|
||||||
circleRepo: cr,
|
circleRepo: cr,
|
||||||
jwtAuth: jwtAuth,
|
jwtAuth: jwtAuth,
|
||||||
email: email,
|
email: email,
|
||||||
|
isDonetickDotCom: config.IsDoneTickDotCom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,6 +515,51 @@ func (h *Handler) UpdateNotificationTarget(c *gin.Context) {
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) updateUserPasswordLoggedInOnly(c *gin.Context) {
|
||||||
|
if h.isDonetickDotCom {
|
||||||
|
// only enable this feature for self-hosted instances
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"error": "This action is not allowed on donetick.com"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger := logging.FromContext(c)
|
||||||
|
type RequestBody struct {
|
||||||
|
Password string `json:"password" binding:"required,min=8,max=32"`
|
||||||
|
}
|
||||||
|
var body RequestBody
|
||||||
|
if err := c.ShouldBindJSON(&body); err != nil {
|
||||||
|
logger.Errorw("user.handler.resetAccountPassword failed to bind", "err", err)
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "Invalid request",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUser, ok := auth.CurrentUser(c)
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get current user"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := auth.EncodePassword(body.Password)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"error": "Unable to process password",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.userRepo.UpdatePasswordByUserId(c.Request.Context(), currentUser.ID, password)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorw("account.handler.resetAccountPassword failed to reset password", "err", err)
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
|
"error": "Unable to reset password",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
|
}
|
||||||
|
|
||||||
func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware, limiter *limiter.Limiter) {
|
func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware, limiter *limiter.Limiter) {
|
||||||
|
|
||||||
userRoutes := router.Group("users")
|
userRoutes := router.Group("users")
|
||||||
|
@ -524,6 +572,8 @@ func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware, limiter
|
||||||
userRoutes.GET("/tokens", h.GetAllUserToken)
|
userRoutes.GET("/tokens", h.GetAllUserToken)
|
||||||
userRoutes.DELETE("/tokens/:id", h.DeleteUserToken)
|
userRoutes.DELETE("/tokens/:id", h.DeleteUserToken)
|
||||||
userRoutes.PUT("/targets", h.UpdateNotificationTarget)
|
userRoutes.PUT("/targets", h.UpdateNotificationTarget)
|
||||||
|
userRoutes.PUT("change_password", h.updateUserPasswordLoggedInOnly)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
authRoutes := router.Group("auth")
|
authRoutes := router.Group("auth")
|
||||||
|
|
|
@ -162,3 +162,7 @@ func (r *UserRepository) DeleteAPIToken(c context.Context, userID int, tokenID s
|
||||||
func (r *UserRepository) UpdateNotificationTarget(c context.Context, userID int, targetID string, targetType uModel.UserNotificationType) error {
|
func (r *UserRepository) UpdateNotificationTarget(c context.Context, userID int, targetID string, targetType uModel.UserNotificationType) error {
|
||||||
return r.db.WithContext(c).Model(&uModel.UserNotificationTarget{}).Where("user_id = ? AND type = ?", userID, targetType).Update("target_id", targetID).Error
|
return r.db.WithContext(c).Model(&uModel.UserNotificationTarget{}).Where("user_id = ? AND type = ?", userID, targetType).Update("target_id", targetID).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UserRepository) UpdatePasswordByUserId(c context.Context, userID int, password string) error {
|
||||||
|
return r.db.WithContext(c).Model(&uModel.User{}).Where("id = ?", userID).Update("password", password).Error
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue