feat: added endpoint to update list item title only

This commit is contained in:
2026-09-04 10:11:32 +02:00
parent ad8a5e3bab
commit 4cb03c6712
5 changed files with 86 additions and 4 deletions
+53 -3
View File
@@ -353,6 +353,56 @@ func (h *ListHandler) UpdateListItem(w http.ResponseWriter, r *http.Request) {
response.Status(w, http.StatusNoContent) response.Status(w, http.StatusNoContent)
} }
// SetListItemTitle handles updating "title" of a list item
//
// @Summary Updates "title" of list item
// @Description Update an existing list item, setting the "title" field
// @Tags List
// @Accept json
// @Produce json
// @Param id path int true "List Item ID"
// @Param payload body request.SetListItemTitlePayload true "Update list item title payload"
// @Success 204 {object} nil
// @Error 400 {object} response.ErrorResponse "failed to decode request url"
// @Error 400 {object} response.ErrorResponse "failed to decode request body"
// @Error 401 {object} response.ErrorResponse "not authorized"
// @Error 500 {object} response.ErrorResponse "failed to set list item title"
// @Router /lists/items/{id}/title [post]
func (h *ListHandler) SetListItemTitle(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
listItemID := r.PathValue("id")
if listItemID == "" {
slog.ErrorContext(ctx, "failed to read list item id from path")
response.Error(ctx, w, http.StatusBadRequest, "failed to decode request url")
return
}
payload, err := request.DecodeJSON[request.SetListItemTitlePayload](r)
if err != nil {
slog.ErrorContext(ctx, "failed to decode set list item title payload", slog.Any("error", err))
response.Error(ctx, w, http.StatusBadRequest, "failed to decode request body")
return
}
authContext, err := domain.GetAuthContext(ctx)
if err != nil {
slog.ErrorContext(ctx, "failed to get auth context", slog.Any("error", err))
response.Error(ctx, w, http.StatusUnauthorized, "not authorized")
return
}
err = h.ListService.SetListItemTitle(ctx, authContext.UserID, listItemID, payload.Title)
if err != nil {
slog.ErrorContext(ctx, "failed to set list item title", slog.Any("error", err))
response.Error(ctx, w, http.StatusInternalServerError, "failed to set list item title")
return
}
slog.InfoContext(ctx, "update list item title successful", slog.String("list_item_id", listItemID))
response.Status(w, http.StatusNoContent)
}
// SetListItemCompleted handles updating "is_completed" of a list item // SetListItemCompleted handles updating "is_completed" of a list item
// //
// @Summary Updates "is_completed" of list item // @Summary Updates "is_completed" of list item
@@ -366,8 +416,8 @@ func (h *ListHandler) UpdateListItem(w http.ResponseWriter, r *http.Request) {
// @Error 400 {object} response.ErrorResponse "failed to decode request url" // @Error 400 {object} response.ErrorResponse "failed to decode request url"
// @Error 400 {object} response.ErrorResponse "failed to decode request body" // @Error 400 {object} response.ErrorResponse "failed to decode request body"
// @Error 401 {object} response.ErrorResponse "not authorized" // @Error 401 {object} response.ErrorResponse "not authorized"
// @Error 500 {object} response.ErrorResponse "failed to update list item" // @Error 500 {object} response.ErrorResponse "failed to set list item completed"
// @Router /lists/items/{id} [post] // @Router /lists/items/{id}/complete [post]
func (h *ListHandler) SetListItemCompleted(w http.ResponseWriter, r *http.Request) { func (h *ListHandler) SetListItemCompleted(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
@@ -399,7 +449,7 @@ func (h *ListHandler) SetListItemCompleted(w http.ResponseWriter, r *http.Reques
return return
} }
slog.InfoContext(ctx, "updated list item completed successful", slog.String("list_item_id", listItemID)) slog.InfoContext(ctx, "update list item completed successful", slog.String("list_item_id", listItemID))
response.Status(w, http.StatusNoContent) response.Status(w, http.StatusNoContent)
} }
+4
View File
@@ -25,6 +25,10 @@ type UpdateListItemPayload struct {
IsCompleted bool `json:"is_completed"` IsCompleted bool `json:"is_completed"`
} }
type SetListItemTitlePayload struct {
Title string `json:"title"`
}
type SetListItemCompletedPayload struct { type SetListItemCompletedPayload struct {
IsCompleted bool `json:"is_completed"` IsCompleted bool `json:"is_completed"`
} }
+2 -1
View File
@@ -66,7 +66,8 @@ func NewMux(cfg Config) http.Handler {
apiMux.Handle("POST /lists/items", protected(listHandler.CreateListItem)) apiMux.Handle("POST /lists/items", protected(listHandler.CreateListItem))
apiMux.Handle("DELETE /lists/items/{id}", protected(listHandler.DeleteListItem)) apiMux.Handle("DELETE /lists/items/{id}", protected(listHandler.DeleteListItem))
apiMux.Handle("PUT /lists/items", protected(listHandler.UpdateListItem)) apiMux.Handle("PUT /lists/items", protected(listHandler.UpdateListItem))
apiMux.Handle("POST /lists/items/{id}", protected(listHandler.SetListItemCompleted)) apiMux.Handle("POST /lists/items/{id}/title", protected(listHandler.SetListItemTitle))
apiMux.Handle("POST /lists/items/{id}/complete", protected(listHandler.SetListItemCompleted))
apiMux.Handle("GET /lists/{id}", protected(listHandler.GetListItems)) apiMux.Handle("GET /lists/{id}", protected(listHandler.GetListItems))
mux := http.NewServeMux() mux := http.NewServeMux()
+16
View File
@@ -44,6 +44,7 @@ type ListRepository interface {
CreateListItem(ctx context.Context, listID string, title string) (*ListItem, error) CreateListItem(ctx context.Context, listID string, title string) (*ListItem, error)
DeleteListItem(ctx context.Context, listItemID string) error DeleteListItem(ctx context.Context, listItemID string) error
UpdateListItem(ctx context.Context, listItemID string, title string, isCompleted bool) error UpdateListItem(ctx context.Context, listItemID string, title string, isCompleted bool) error
SetListItemTitle(ctx context.Context, listItemID string, title string) error
SetListItemCompleted(ctx context.Context, listItemID string, isCompleted bool) error SetListItemCompleted(ctx context.Context, listItemID string, isCompleted bool) error
GetListItems(ctx context.Context, listID string) ([]ListItem, error) GetListItems(ctx context.Context, listID string) ([]ListItem, error)
} }
@@ -172,6 +173,21 @@ func (s *ListService) UpdateListItem(ctx context.Context, authUserID string, lis
return s.repo.UpdateListItem(ctx, listItemID, title, isCompleted) return s.repo.UpdateListItem(ctx, listItemID, title, isCompleted)
} }
func (s *ListService) SetListItemTitle(ctx context.Context, authUserID string, listItemID string, title string) error {
if listItemID == "" {
return ErrListItemIDMissing
}
if title == "" {
return ErrListItemTitleMissing
}
if err := s.userAllowedToAccessListItem(ctx, authUserID, listItemID); err != nil {
return err
}
return s.repo.SetListItemTitle(ctx, listItemID, title)
}
func (s *ListService) SetListItemCompleted(ctx context.Context, authUserID string, listItemID string, isCompleted bool) error { func (s *ListService) SetListItemCompleted(ctx context.Context, authUserID string, listItemID string, isCompleted bool) error {
if listItemID == "" { if listItemID == "" {
return ErrListItemIDMissing return ErrListItemIDMissing
+11
View File
@@ -150,6 +150,17 @@ func (r *ListRepo) UpdateListItem(ctx context.Context, listItemID string, title
return nil return nil
} }
func (r *ListRepo) SetListItemTitle(ctx context.Context, listItemID string, title string) error {
_, err := r.conn(ctx).ExecContext(ctx, "UPDATE list_items SET title = $1, modified_at = NOW() WHERE id = $2",
title, listItemID,
)
if err != nil {
return fmt.Errorf("failed to update list item title: %w", err)
}
return nil
}
func (r *ListRepo) SetListItemCompleted(ctx context.Context, listItemID string, isCompleted bool) error { func (r *ListRepo) SetListItemCompleted(ctx context.Context, listItemID string, isCompleted bool) error {
_, err := r.conn(ctx).ExecContext(ctx, "UPDATE list_items SET is_completed = $1, modified_at = NOW() WHERE id = $2", _, err := r.conn(ctx).ExecContext(ctx, "UPDATE list_items SET is_completed = $1, modified_at = NOW() WHERE id = $2",
isCompleted, listItemID, isCompleted, listItemID,