aboutsummaryrefslogtreecommitdiffstats
path: root/internal/thing/handler.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/thing/handler.go')
-rw-r--r--internal/thing/handler.go281
1 files changed, 281 insertions, 0 deletions
diff --git a/internal/thing/handler.go b/internal/thing/handler.go
new file mode 100644
index 0000000..5166157
--- /dev/null
+++ b/internal/thing/handler.go
@@ -0,0 +1,281 @@
+package thing
+
+import (
+ "strconv"
+ "time"
+
+ auth "donetick.com/core/internal/authorization"
+ chRepo "donetick.com/core/internal/chore/repo"
+ cRepo "donetick.com/core/internal/circle/repo"
+ nRepo "donetick.com/core/internal/notifier/repo"
+ nps "donetick.com/core/internal/notifier/service"
+ tModel "donetick.com/core/internal/thing/model"
+ tRepo "donetick.com/core/internal/thing/repo"
+ "donetick.com/core/logging"
+ jwt "github.com/appleboy/gin-jwt/v2"
+ "github.com/gin-gonic/gin"
+)
+
+type Handler struct {
+ choreRepo *chRepo.ChoreRepository
+ circleRepo *cRepo.CircleRepository
+ nPlanner *nps.NotificationPlanner
+ nRepo *nRepo.NotificationRepository
+ tRepo *tRepo.ThingRepository
+}
+
+type ThingRequest struct {
+ ID int `json:"id"`
+ Name string `json:"name" binding:"required"`
+ Type string `json:"type" binding:"required"`
+ State string `json:"state"`
+}
+
+func NewHandler(cr *chRepo.ChoreRepository, circleRepo *cRepo.CircleRepository,
+ np *nps.NotificationPlanner, nRepo *nRepo.NotificationRepository, tRepo *tRepo.ThingRepository) *Handler {
+ return &Handler{
+ choreRepo: cr,
+ circleRepo: circleRepo,
+ nPlanner: np,
+ nRepo: nRepo,
+ tRepo: tRepo,
+ }
+}
+
+func (h *Handler) CreateThing(c *gin.Context) {
+ log := logging.FromContext(c)
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ var req ThingRequest
+ if err := c.BindJSON(&req); err != nil {
+ c.JSON(400, gin.H{"error": err.Error()})
+ return
+ }
+ thing := &tModel.Thing{
+ Name: req.Name,
+ UserID: currentUser.ID,
+ Type: req.Type,
+ State: req.State,
+ }
+ if !isValidThingState(thing) {
+ c.JSON(400, gin.H{"error": "Invalid state"})
+ return
+ }
+ log.Debug("Creating thing", thing)
+ if err := h.tRepo.UpsertThing(c, thing); err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+ c.JSON(201, gin.H{
+ "res": thing,
+ })
+}
+
+func (h *Handler) UpdateThingState(c *gin.Context) {
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ thingIDRaw := c.Param("id")
+ thingID, err := strconv.Atoi(thingIDRaw)
+ if err != nil {
+ c.JSON(400, gin.H{"error": "Invalid thing id"})
+ return
+ }
+
+ val := c.Query("value")
+ if val == "" {
+ c.JSON(400, gin.H{"error": "state or increment query param is required"})
+ return
+ }
+ thing, err := h.tRepo.GetThingByID(c, thingID)
+ if thing.UserID != currentUser.ID {
+ c.JSON(403, gin.H{"error": "Forbidden"})
+ return
+ }
+ if err != nil {
+ c.JSON(500, gin.H{"error": "Unable to find thing"})
+ return
+ }
+ thing.State = val
+ if !isValidThingState(thing) {
+ c.JSON(400, gin.H{"error": "Invalid state"})
+ return
+ }
+
+ if err := h.tRepo.UpdateThingState(c, thing); err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+
+ shouldReturn := EvaluateTriggerAndScheduleDueDate(h, c, thing)
+ if shouldReturn {
+ return
+ }
+
+ c.JSON(200, gin.H{
+ "res": thing,
+ })
+}
+
+func EvaluateTriggerAndScheduleDueDate(h *Handler, c *gin.Context, thing *tModel.Thing) bool {
+ thingChores, err := h.tRepo.GetThingChoresByThingId(c, thing.ID)
+ if err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return true
+ }
+ for _, tc := range thingChores {
+ triggered := EvaluateThingChore(tc, thing.State)
+ if triggered {
+ h.choreRepo.SetDueDateIfNotExisted(c, tc.ChoreID, time.Now().UTC())
+ }
+ }
+ return false
+}
+
+func (h *Handler) UpdateThing(c *gin.Context) {
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ var req ThingRequest
+ if err := c.BindJSON(&req); err != nil {
+ c.JSON(400, gin.H{"error": err.Error()})
+ return
+ }
+
+ thing, err := h.tRepo.GetThingByID(c, req.ID)
+
+ if err != nil {
+ c.JSON(500, gin.H{"error": "Unable to find thing"})
+ return
+ }
+ if thing.UserID != currentUser.ID {
+ c.JSON(403, gin.H{"error": "Forbidden"})
+ return
+ }
+ thing.Name = req.Name
+ thing.Type = req.Type
+ if req.State != "" {
+ thing.State = req.State
+ if !isValidThingState(thing) {
+ c.JSON(400, gin.H{"error": "Invalid state"})
+ return
+ }
+ }
+
+ if err := h.tRepo.UpsertThing(c, thing); err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+ c.JSON(200, gin.H{
+ "res": thing,
+ })
+}
+
+func (h *Handler) GetAllThings(c *gin.Context) {
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ things, err := h.tRepo.GetUserThings(c, currentUser.ID)
+ if err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+ c.JSON(200, gin.H{
+ "res": things,
+ })
+}
+
+func (h *Handler) GetThingHistory(c *gin.Context) {
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ thingIDRaw := c.Param("id")
+ thingID, err := strconv.Atoi(thingIDRaw)
+ if err != nil {
+ c.JSON(400, gin.H{"error": "Invalid thing id"})
+ return
+ }
+
+ thing, err := h.tRepo.GetThingByID(c, thingID)
+ if err != nil {
+ c.JSON(500, gin.H{"error": "Unable to find thing"})
+ return
+ }
+ if thing.UserID != currentUser.ID {
+ c.JSON(403, gin.H{"error": "Forbidden"})
+ return
+ }
+ offsetRaw := c.Query("offset")
+ offset, err := strconv.Atoi(offsetRaw)
+ if err != nil {
+ c.JSON(400, gin.H{"error": "Invalid offset"})
+ return
+ }
+ history, err := h.tRepo.GetThingHistoryWithOffset(c, thingID, offset, 10)
+ if err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+ c.JSON(200, gin.H{
+ "res": history,
+ })
+}
+
+func (h *Handler) DeleteThing(c *gin.Context) {
+ currentUser, ok := auth.CurrentUser(c)
+ if !ok {
+ c.JSON(401, gin.H{"error": "Unauthorized"})
+ return
+ }
+
+ thingIDRaw := c.Param("id")
+ thingID, err := strconv.Atoi(thingIDRaw)
+ if err != nil {
+ c.JSON(400, gin.H{"error": "Invalid thing id"})
+ return
+ }
+
+ thing, err := h.tRepo.GetThingByID(c, thingID)
+ if err != nil {
+ c.JSON(500, gin.H{"error": "Unable to find thing"})
+ return
+ }
+ if thing.UserID != currentUser.ID {
+ c.JSON(403, gin.H{"error": "Forbidden"})
+ return
+ }
+ if err := h.tRepo.DeleteThing(c, thingID); err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+ c.JSON(200, gin.H{})
+}
+func Routes(r *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware) {
+
+ thingRoutes := r.Group("things")
+ thingRoutes.Use(auth.MiddlewareFunc())
+ {
+ thingRoutes.POST("", h.CreateThing)
+ thingRoutes.PUT("/:id/state", h.UpdateThingState)
+ thingRoutes.PUT("", h.UpdateThing)
+ thingRoutes.GET("", h.GetAllThings)
+ thingRoutes.GET("/:id/history", h.GetThingHistory)
+ thingRoutes.DELETE("/:id", h.DeleteThing)
+ }
+}