Add Support to consume/redeem points

Support Creating task/chore via api
Add initial Description for tasks
This commit is contained in:
Mo Tarbin 2025-01-14 10:43:05 -05:00
parent 50b1357dfa
commit ac733343da
11 changed files with 368 additions and 66 deletions

View file

@ -11,6 +11,7 @@ import (
chRepo "donetick.com/core/internal/chore/repo"
cModel "donetick.com/core/internal/circle/model"
cRepo "donetick.com/core/internal/circle/repo"
pRepo "donetick.com/core/internal/points/repo"
uModel "donetick.com/core/internal/user/model"
uRepo "donetick.com/core/internal/user/repo"
"donetick.com/core/logging"
@ -22,13 +23,15 @@ type Handler struct {
circleRepo *cRepo.CircleRepository
userRepo *uRepo.UserRepository
choreRepo *chRepo.ChoreRepository
pointRepo *pRepo.PointsRepository
}
func NewHandler(cr *cRepo.CircleRepository, ur *uRepo.UserRepository, c *chRepo.ChoreRepository) *Handler {
func NewHandler(cr *cRepo.CircleRepository, ur *uRepo.UserRepository, c *chRepo.ChoreRepository, pr *pRepo.PointsRepository) *Handler {
return &Handler{
circleRepo: cr,
userRepo: ur,
choreRepo: c,
pointRepo: pr,
}
}
@ -424,6 +427,112 @@ func (h *Handler) AcceptJoinRequest(c *gin.Context) {
})
}
func (h *Handler) RedeemPoints(c *gin.Context) {
type RedeemPointsRequest struct {
Points int `json:"points"`
UserID int `json:"userId"`
}
log := logging.FromContext(c)
currentUser, ok := auth.CurrentUser(c)
if !ok {
c.JSON(500, gin.H{
"error": "Error getting current user",
})
return
}
// parse body:
var redeemReq RedeemPointsRequest
if err := c.ShouldBind(&redeemReq); err != nil {
c.JSON(400, gin.H{
"error": "Invalid request",
})
return
}
if redeemReq.Points <= 0 {
c.JSON(400, gin.H{
"error": "Invalid request",
})
return
}
circleIdRaw := c.Param("id")
circleID, err := strconv.Atoi(circleIdRaw)
if err != nil {
log.Error("Error redeeming points: invalid circle id")
c.JSON(400, gin.H{
"error": "Invalid request: invalid circle id",
})
return
}
if circleID != currentUser.CircleID {
log.Error("You are not a member of this circle")
c.JSON(400, gin.H{
"error": "You are not a member of this circle",
})
return
}
members, err := h.circleRepo.GetCircleUsers(c, currentUser.CircleID)
if err != nil {
log.Error("Error getting circle admins:", err)
c.JSON(500, gin.H{
"error": "Error getting circle admins",
})
return
}
isAdmin := false
isValidMember := false
var member *cModel.UserCircleDetail
for _, user := range members {
if user.UserID == currentUser.ID && user.Role == "admin" {
isAdmin = true
}
if user.UserID == redeemReq.UserID {
isValidMember = true
member = user
}
}
if !isAdmin {
log.Error("Error redeeming points: user is not an admin of this circle")
c.JSON(403, gin.H{
"error": "You are not an admin of this circle",
})
return
}
if !isValidMember {
log.Error("Error redeeming points: user is not a member of this circle")
c.JSON(400, gin.H{
"error": "User is not a member of this circle",
})
return
}
if member.Points-redeemReq.Points < 0 {
log.Error("Error redeeming points: user does not have enough points")
c.JSON(400, gin.H{
"error": "User does not have enough points",
})
return
}
err = h.circleRepo.RedeemPoints(c, currentUser.CircleID, currentUser.ID, redeemReq.Points, currentUser.ID)
if err != nil {
log.Error("Error redeeming points:", err)
c.JSON(500, gin.H{
"error": "Error redeeming points",
})
return
}
c.JSON(200, gin.H{
"res": "Points redeemed successfully",
})
}
func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware) {
log.Println("Registering routes")
@ -437,6 +546,7 @@ func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware) {
circleRoutes.POST("/join", h.JoinCircle)
circleRoutes.DELETE("/leave", h.LeaveCircle)
circleRoutes.DELETE("/:id/members/delete", h.DeleteCircleMember)
circleRoutes.POST("/:id/members/points/redeem", h.RedeemPoints)
}

View file

@ -2,8 +2,10 @@ package repo
import (
"context"
"time"
cModel "donetick.com/core/internal/circle/model"
pModel "donetick.com/core/internal/points"
uModel "donetick.com/core/internal/user/model"
"gorm.io/gorm"
)
@ -138,3 +140,26 @@ func (r *CircleRepository) AssignDefaultCircle(c context.Context, userID int) er
return r.db.WithContext(c).Model(&uModel.User{}).Where("id = ?", userID).Update("circle_id", defaultCircle.ID).Error
}
func (r *CircleRepository) RedeemPoints(c context.Context, circleID int, userID int, points int, createdBy int) error {
err := r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&cModel.UserCircle{}).Where("user_id = ? AND circle_id = ?", userID, circleID).Update("points_redeemed", gorm.Expr("points_redeemed + ?", points)).Error; err != nil {
return err
}
if err := tx.Create(&pModel.PointsHistory{
Action: pModel.PointsHistoryActionRedeem,
CircleID: circleID,
UserID: userID,
Points: points,
CreatedAt: time.Now().UTC(),
CreatedBy: createdBy,
}).Error; err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
}