209 lines
6.5 KiB
Go
209 lines
6.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/robindittmar/dttmr-api/internal/api/response"
|
|
"github.com/robindittmar/dttmr-api/internal/domain"
|
|
)
|
|
|
|
type InviteHandler struct {
|
|
InviteService *domain.InviteService
|
|
}
|
|
|
|
func NewInviteHandler(inviteService *domain.InviteService) *InviteHandler {
|
|
return &InviteHandler{InviteService: inviteService}
|
|
}
|
|
|
|
// CreateInvite handles the creation of an invitation
|
|
//
|
|
// @Summary Create invite route
|
|
// @Description Create an invitation, which may be used to register an account
|
|
// @Tags Invite
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 201 {object} domain.Invite
|
|
// @Error 500 {object} response.ErrorResponse "failed to create invite"
|
|
// @Router /user/invites [post]
|
|
func (h *InviteHandler) CreateInvite(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
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.StatusInternalServerError, "failed to create invite")
|
|
return
|
|
}
|
|
|
|
invite, err := h.InviteService.CreateInvite(ctx, authContext.UserID)
|
|
if err != nil {
|
|
slog.ErrorContext(ctx, "failed to create invite", slog.Any("error", err))
|
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to create invite")
|
|
return
|
|
}
|
|
|
|
slog.InfoContext(ctx, "created invite successfully", slog.String("invite_id", invite.ID))
|
|
response.JSON(ctx, w, http.StatusCreated, invite)
|
|
}
|
|
|
|
// DeleteInvite handles the deletion of an invitation
|
|
//
|
|
// @Summary Delete invitation route
|
|
// @Description Deletes an invitation. Invitations can only be deleted when they have not been used
|
|
// @Tags Invite
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "Invite ID"
|
|
// @Success 204
|
|
// @Error 400 {object} response.ErrorResponse "failed to decode request url"
|
|
// @Error 500 {object} response.ErrorResponse "failed to delete invite"
|
|
// @Router /user/invites/{id} [delete]
|
|
func (h *InviteHandler) DeleteInvite(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
inviteID := r.PathValue("id")
|
|
if inviteID == "" {
|
|
slog.ErrorContext(ctx, "failed to read invite id from path")
|
|
response.Error(ctx, w, http.StatusBadRequest, "failed to decode request url")
|
|
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.StatusInternalServerError, "failed to delete invite")
|
|
return
|
|
}
|
|
|
|
err = h.InviteService.DeleteInvite(ctx, authContext.UserID, inviteID)
|
|
if err != nil {
|
|
slog.ErrorContext(ctx, "failed to delete invite", slog.Any("error", err))
|
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to delete invite")
|
|
return
|
|
}
|
|
|
|
slog.InfoContext(ctx, "deleted invite successfully", slog.String("invite_id", inviteID))
|
|
response.Status(w, http.StatusNoContent)
|
|
}
|
|
|
|
// GetInvites handles fetching the list of a users invitations
|
|
//
|
|
// @Summary Get invitations route
|
|
// @Description Gets a list of all invitations the user has created
|
|
// @Tags Invite
|
|
// @Accept json
|
|
// @Produce json
|
|
// @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"
|
|
// @Router /user/invites [get]
|
|
func (h *InviteHandler) GetInvites(w http.ResponseWriter, r *http.Request) {
|
|
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)
|
|
if err != nil {
|
|
slog.ErrorContext(ctx, "failed to get auth context", slog.Any("error", err))
|
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to get invites")
|
|
return
|
|
}
|
|
|
|
invites, err := h.InviteService.GetInvites(ctx, authContext.UserID, page, count)
|
|
if err != nil {
|
|
slog.ErrorContext(ctx, "failed to get invites", slog.Any("error", err))
|
|
response.Error(ctx, w, http.StatusInternalServerError, "failed to get invites")
|
|
return
|
|
}
|
|
|
|
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,
|
|
})
|
|
}
|
|
|
|
// GetInvitesStatus handles fetching the counts of a users invitations
|
|
//
|
|
// @Summary Get invitations status
|
|
// @Description Gets active/expired/used counts for all the users invites
|
|
// @Tags Invite
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} domain.InviteCounts
|
|
// @Error 500 {object} response.ErrorResponse "failed to count invites"
|
|
// @Router /user/invites [get]
|
|
|
|
func (h *InviteHandler) GetInvitesStatus(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
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.StatusInternalServerError, "failed to count invites")
|
|
return
|
|
}
|
|
|
|
counts, err := h.InviteService.CountInvitesStructured(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 count invites")
|
|
return
|
|
}
|
|
|
|
response.JSON(ctx, w, http.StatusOK, counts)
|
|
}
|