feat: added pagination to GET /user/invites
This commit is contained in:
@@ -3,6 +3,7 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/robindittmar/dttmr-api/internal/api/response"
|
"github.com/robindittmar/dttmr-api/internal/api/response"
|
||||||
"github.com/robindittmar/dttmr-api/internal/domain"
|
"github.com/robindittmar/dttmr-api/internal/domain"
|
||||||
@@ -94,12 +95,59 @@ func (h *InviteHandler) DeleteInvite(w http.ResponseWriter, r *http.Request) {
|
|||||||
// @Tags Invite
|
// @Tags Invite
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} []domain.Invite
|
// @Param page query int false "page"
|
||||||
|
// @Param count query int false "count"
|
||||||
|
// @Success 200 {object} response.Paginated[domain.Invite]
|
||||||
|
// @Error 400 {object} response.ErrorResponse "failed to decode request body"
|
||||||
|
// @Error 400 {object} response.ErrorResponse "invalid value for page"
|
||||||
|
// @Error 400 {object} response.ErrorResponse "invalid value for count"
|
||||||
// @Error 500 {object} response.ErrorResponse "failed to get invites"
|
// @Error 500 {object} response.ErrorResponse "failed to get invites"
|
||||||
// @Router /user/invites [get]
|
// @Router /user/invites [get]
|
||||||
func (h *InviteHandler) GetInvites(w http.ResponseWriter, r *http.Request) {
|
func (h *InviteHandler) GetInvites(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
|
pageStr := r.URL.Query().Get("page")
|
||||||
|
if pageStr == "" {
|
||||||
|
pageStr = "1"
|
||||||
|
}
|
||||||
|
countStr := r.URL.Query().Get("count")
|
||||||
|
if countStr == "" {
|
||||||
|
countStr = "10"
|
||||||
|
}
|
||||||
|
|
||||||
|
page, err := strconv.Atoi(pageStr)
|
||||||
|
if err != nil {
|
||||||
|
slog.ErrorContext(ctx,
|
||||||
|
"failed to read page from query",
|
||||||
|
slog.String("page", pageStr))
|
||||||
|
response.Error(ctx, w, http.StatusBadRequest, "failed to decode request url")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := strconv.Atoi(countStr)
|
||||||
|
if err != nil {
|
||||||
|
slog.ErrorContext(ctx,
|
||||||
|
"failed to read count from query",
|
||||||
|
slog.String("count", countStr))
|
||||||
|
response.Error(ctx, w, http.StatusBadRequest, "failed to decode request url")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if page < 1 {
|
||||||
|
slog.ErrorContext(ctx,
|
||||||
|
"page parameter is invalid",
|
||||||
|
slog.Int("page", page))
|
||||||
|
response.Error(ctx, w, http.StatusBadRequest, "invalid value for page")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if count <= 0 {
|
||||||
|
slog.ErrorContext(ctx,
|
||||||
|
"count parameter is invalid",
|
||||||
|
slog.Int("count", count))
|
||||||
|
response.Error(ctx, w, http.StatusBadRequest, "invalid value for count")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
authContext, err := domain.GetAuthContext(ctx)
|
authContext, err := domain.GetAuthContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.ErrorContext(ctx, "failed to get auth context", slog.Any("error", err))
|
slog.ErrorContext(ctx, "failed to get auth context", slog.Any("error", err))
|
||||||
@@ -107,12 +155,23 @@ func (h *InviteHandler) GetInvites(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
invites, err := h.InviteService.GetInvites(ctx, authContext.UserID)
|
invites, err := h.InviteService.GetInvites(ctx, authContext.UserID, page, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.ErrorContext(ctx, "failed to get invites", slog.Any("error", err))
|
slog.ErrorContext(ctx, "failed to get invites", slog.Any("error", err))
|
||||||
response.Error(ctx, w, http.StatusInternalServerError, "failed to get invites")
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to get invites")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.JSON(ctx, w, http.StatusOK, invites)
|
total, err := h.InviteService.CountInvites(ctx, authContext.UserID)
|
||||||
|
if err != nil {
|
||||||
|
slog.ErrorContext(ctx, "failed to count invites", slog.Any("error", err))
|
||||||
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to get invites")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.JSON(ctx, w, http.StatusOK, response.Paginated[domain.Invite]{
|
||||||
|
Count: len(invites),
|
||||||
|
Total: total,
|
||||||
|
Data: invites,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
type GetInvitesPayload struct {
|
||||||
|
Page int
|
||||||
|
CountPerPage int
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
type Paginated[T any] struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
Data []T `json:"data"`
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ type InviteRepository interface {
|
|||||||
DeleteInvite(ctx context.Context, userID string, inviteID string) error
|
DeleteInvite(ctx context.Context, userID string, inviteID string) error
|
||||||
ConsumeInvite(ctx context.Context, inviteID string, inviteeUserID string) error
|
ConsumeInvite(ctx context.Context, inviteID string, inviteeUserID string) error
|
||||||
GetInvite(ctx context.Context, code string) (*Invite, error)
|
GetInvite(ctx context.Context, code string) (*Invite, error)
|
||||||
GetInvites(ctx context.Context, userID string) ([]Invite, error)
|
GetInvites(ctx context.Context, userID string, offset int, count int) ([]Invite, error)
|
||||||
|
CountInvites(ctx context.Context, userID string) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type InviteService struct {
|
type InviteService struct {
|
||||||
@@ -89,10 +90,19 @@ func (s *InviteService) GetInvite(ctx context.Context, code string) (*Invite, er
|
|||||||
return invite, nil
|
return invite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InviteService) GetInvites(ctx context.Context, userID string) ([]Invite, error) {
|
func (s *InviteService) GetInvites(ctx context.Context, userID string, page int, countPerPage int) ([]Invite, error) {
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
return nil, ErrUserIDMissing
|
return nil, ErrUserIDMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.repo.GetInvites(ctx, userID)
|
offset := (page - 1) * countPerPage
|
||||||
|
return s.repo.GetInvites(ctx, userID, offset, countPerPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *InviteService) CountInvites(ctx context.Context, userID string) (int, error) {
|
||||||
|
if userID == "" {
|
||||||
|
return 0, ErrUserIDMissing
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.repo.CountInvites(ctx, userID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,10 +81,10 @@ func (r *InviteRepo) GetInvite(ctx context.Context, code string) (*domain.Invite
|
|||||||
return &invite, nil
|
return &invite, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *InviteRepo) GetInvites(ctx context.Context, userID string) ([]domain.Invite, error) {
|
func (r *InviteRepo) GetInvites(ctx context.Context, userID string, offset int, count int) ([]domain.Invite, error) {
|
||||||
rows, err := r.db.QueryContext(ctx,
|
rows, err := r.db.QueryContext(ctx,
|
||||||
"SELECT id, code, expires_at, consumed_at FROM invites WHERE inviter_user_id=$1",
|
"SELECT id, code, expires_at, consumed_at FROM invites WHERE inviter_user_id=$1 ORDER BY created_at DESC OFFSET $2 LIMIT $3",
|
||||||
userID,
|
userID, offset, count,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
@@ -107,3 +107,16 @@ func (r *InviteRepo) GetInvites(ctx context.Context, userID string) ([]domain.In
|
|||||||
|
|
||||||
return invites, nil
|
return invites, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *InviteRepo) CountInvites(ctx context.Context, userID string) (int, error) {
|
||||||
|
var count int
|
||||||
|
err := r.db.QueryRowContext(ctx,
|
||||||
|
"SELECT COUNT(*) FROM invites WHERE inviter_user_id=$1",
|
||||||
|
userID,
|
||||||
|
).Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to count invites: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user