Add Support for Activities , Initial Support for Completion Window and points

This commit is contained in:
Mo Tarbin 2024-12-28 18:59:08 -05:00
parent cd29da9168
commit 27a47a0c1f
5 changed files with 90 additions and 15 deletions

View file

@ -36,7 +36,7 @@ func (h *API) GetAllChores(c *gin.Context) {
c.JSON(401, gin.H{"error": "Unauthorized"})
return
}
chores, err := h.choreRepo.GetChores(c, user.CircleID, user.ID)
chores, err := h.choreRepo.GetChores(c, user.CircleID, user.ID, false)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return

View file

@ -53,6 +53,7 @@ type ChoreReq struct {
Labels []string `json:"labels"`
LabelsV2 *[]LabelReq `json:"labelsV2"`
ThingTrigger *ThingTrigger `json:"thingTrigger"`
Points *int `json:"points"`
}
type Handler struct {
choreRepo *chRepo.ChoreRepository
@ -85,7 +86,13 @@ func (h *Handler) getChores(c *gin.Context) {
})
return
}
chores, err := h.choreRepo.GetChores(c, u.CircleID, u.ID)
includeArchived := false
if c.Query("includeArchived") == "true" {
includeArchived = true
}
chores, err := h.choreRepo.GetChores(c, u.CircleID, u.ID, includeArchived)
if err != nil {
c.JSON(500, gin.H{
"error": "Error getting chores",
@ -271,6 +278,7 @@ func (h *Handler) createChore(c *gin.Context) {
CreatedBy: currentUser.ID,
CreatedAt: time.Now().UTC(),
CircleID: currentUser.CircleID,
Points: choreReq.Points,
}
id, err := h.choreRepo.CreateChore(c, createdChore)
createdChore.ID = id
@ -530,6 +538,7 @@ func (h *Handler) editChore(c *gin.Context) {
UpdatedBy: currentUser.ID,
CreatedBy: oldChore.CreatedBy,
CreatedAt: oldChore.CreatedAt,
Points: choreReq.Points,
}
if err := h.choreRepo.UpsertChore(c, updatedChore); err != nil {
c.JSON(500, gin.H{
@ -1197,6 +1206,45 @@ func (h *Handler) updatePriority(c *gin.Context) {
})
}
func (h *Handler) getChoresHistory(c *gin.Context) {
currentUser, ok := auth.CurrentUser(c)
if !ok {
c.JSON(500, gin.H{
"error": "Error getting current user",
})
return
}
durationRaw := c.Query("limit")
if durationRaw == "" {
durationRaw = "7"
}
duration, err := strconv.Atoi(durationRaw)
if err != nil {
c.JSON(400, gin.H{
"error": "Invalid duration",
})
return
}
includeCircleRaw := c.Query("all")
includeCircle := false
if includeCircleRaw == "true" {
includeCircle = true
}
choreHistories, err := h.choreRepo.GetChoresHistoryByUserID(c, currentUser.ID, currentUser.CircleID, duration, includeCircle)
if err != nil {
c.JSON(500, gin.H{
"error": "Error getting chore history",
})
return
}
c.JSON(200, gin.H{
"res": choreHistories,
})
}
func (h *Handler) DeleteHistory(c *gin.Context) {
currentUser, ok := auth.CurrentUser(c)
@ -1336,7 +1384,7 @@ func Routes(router *gin.Engine, h *Handler, auth *jwt.GinJWTMiddleware) {
{
choresRoutes.GET("/", h.getChores)
choresRoutes.GET("/archived", h.getArchivedChores)
choresRoutes.GET("/history", h.getChoresHistory)
choresRoutes.PUT("/", h.editChore)
choresRoutes.PUT("/:id/priority", h.updatePriority)
choresRoutes.POST("/", h.createChore)

View file

@ -46,6 +46,8 @@ type Chore struct {
ThingChore *tModel.ThingChore `json:"thingChore" gorm:"foreignkey:chore_id;references:id;<-:false"` // ThingChore relationship
Status int `json:"status" gorm:"column:status"`
Priority int `json:"priority" gorm:"column:priority"`
CompletionWindow *int `json:"completionWindow,omitempty" gorm:"column:completion_window"` // Number seconds before the chore is due that it can be completed
Points *int `json:"points,omitempty" gorm:"column:points"` // Points for completing the chore
}
type ChoreAssignees struct {
ID int `json:"-" gorm:"primary_key"`
@ -61,7 +63,18 @@ type ChoreHistory struct {
Note *string `json:"notes" gorm:"column:notes"` // Notes about the chore
DueDate *time.Time `json:"dueDate" gorm:"column:due_date"` // When the chore was due
UpdatedAt *time.Time `json:"updatedAt" gorm:"column:updated_at"` // When the record was last updated
Status ChoreHistoryStatus `json:"status" gorm:"column:status"` // Status of the chore
Points *int `json:"points,omitempty" gorm:"column:points"` // Points for completing the chore
}
type ChoreHistoryStatus int8
const (
ChoreHistoryStatusPending ChoreHistoryStatus = 0
ChoreHistoryStatusCompleted ChoreHistoryStatus = 1
ChoreHistoryStatusCompletedLate ChoreHistoryStatus = 2
ChoreHistoryStatusMissed ChoreHistoryStatus = 3
ChoreHistoryStatusSkipped ChoreHistoryStatus = 4
)
type FrequencyMetadata struct {
Days []*string `json:"days,omitempty"`

View file

@ -49,10 +49,13 @@ func (r *ChoreRepository) GetChore(c context.Context, choreID int) (*chModel.Cho
return &chore, nil
}
func (r *ChoreRepository) GetChores(c context.Context, circleID int, userID int) ([]*chModel.Chore, error) {
func (r *ChoreRepository) GetChores(c context.Context, circleID int, userID int, includeArchived bool) ([]*chModel.Chore, error) {
var chores []*chModel.Chore
// if err := r.db.WithContext(c).Preload("Assignees").Where("is_active = ?", true).Order("next_due_date asc").Find(&chores, "circle_id = ?", circleID).Error; err != nil {
if err := r.db.WithContext(c).Preload("Assignees").Preload("LabelsV2").Joins("left join chore_assignees on chores.id = chore_assignees.chore_id").Where("chores.circle_id = ? AND (chores.created_by = ? OR chore_assignees.user_id = ?)", circleID, userID, userID).Group("chores.id").Order("next_due_date asc").Find(&chores, "circle_id = ? AND is_active = ?", circleID, true).Error; err != nil {
query := r.db.WithContext(c).Preload("Assignees").Preload("LabelsV2").Joins("left join chore_assignees on chores.id = chore_assignees.chore_id").Where("chores.circle_id = ? AND (chores.created_by = ? OR chore_assignees.user_id = ?)", circleID, userID, userID).Group("chores.id").Order("next_due_date asc")
if !includeArchived {
query = query.Where("chores.is_active = ?", true)
}
if err := query.Find(&chores, "circle_id = ?", circleID).Error; err != nil {
return nil, err
}
return chores, nil
@ -98,6 +101,7 @@ func (r *ChoreRepository) CompleteChore(c context.Context, chore *chModel.Chore,
AssignedTo: chore.AssignedTo,
DueDate: chore.NextDueDate,
Note: note,
Points: chore.Points,
}
if err := tx.Create(ch).Error; err != nil {
return err
@ -301,3 +305,13 @@ func (r *ChoreRepository) ArchiveChore(c context.Context, choreID int, userID in
func (r *ChoreRepository) UnarchiveChore(c context.Context, choreID int, userID int) error {
return r.db.WithContext(c).Model(&chModel.Chore{}).Where("id = ? and created_by = ?", choreID, userID).Update("is_active", true).Error
}
func (r *ChoreRepository) GetChoresHistoryByUserID(c context.Context, userID int, circleID int, days int, includeCircle bool) ([]*chModel.ChoreHistory, error) {
var chores []*chModel.ChoreHistory
since := time.Now().AddDate(0, 0, days*-1)
if err := r.db.WithContext(c).Where("completed_by = ? AND completed_at > ?", userID, since).Order("completed_at desc").Find(&chores).Error; err != nil {
return nil, err
}
return chores, nil
}

View file

@ -172,7 +172,7 @@ func (h *Handler) LeaveCircle(c *gin.Context) {
}
func handleUserLeavingCircle(h *Handler, c *gin.Context, leavingUser *uModel.User, orginalCircleID int) error {
userAssignedCircleChores, err := h.choreRepo.GetChores(c, leavingUser.CircleID, leavingUser.ID)
userAssignedCircleChores, err := h.choreRepo.GetChores(c, leavingUser.CircleID, leavingUser.ID, true)
if err != nil {
return err
}