118 lines
5.1 KiB
Go
118 lines
5.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
|
|
"apskel-pos-be/internal/appcontext"
|
|
"apskel-pos-be/internal/constants"
|
|
"apskel-pos-be/internal/contract"
|
|
"apskel-pos-be/internal/logger"
|
|
"apskel-pos-be/internal/service"
|
|
"apskel-pos-be/internal/util"
|
|
)
|
|
|
|
// loyaltySettingsBodyLimit caps a settings body; a real one is well under 2 KB.
|
|
const loyaltySettingsBodyLimit = 64 << 10
|
|
|
|
// LoyaltySettingsHandler serves the loyalty settings (docs/prd-point-coin.md F1, F2).
|
|
type LoyaltySettingsHandler struct {
|
|
loyaltySettingsService service.LoyaltySettingsService
|
|
}
|
|
|
|
func NewLoyaltySettingsHandler(loyaltySettingsService service.LoyaltySettingsService) *LoyaltySettingsHandler {
|
|
return &LoyaltySettingsHandler{loyaltySettingsService: loyaltySettingsService}
|
|
}
|
|
|
|
func (h *LoyaltySettingsHandler) GetOutletSettings(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
outletID, ok := parseUUIDParam(c, "outlet_id", "LoyaltySettingsHandler::GetOutletSettings")
|
|
if !ok {
|
|
return
|
|
}
|
|
response := h.loyaltySettingsService.GetOutletSettings(ctx, appcontext.FromGinContext(ctx), outletID)
|
|
if response.HasErrors() {
|
|
logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("LoyaltySettingsHandler::GetOutletSettings -> service call failed")
|
|
}
|
|
util.HandleResponse(c.Writer, c.Request, response, "LoyaltySettingsHandler::GetOutletSettings")
|
|
}
|
|
|
|
func (h *LoyaltySettingsHandler) UpdateOutletSettings(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
outletID, ok := parseUUIDParam(c, "outlet_id", "LoyaltySettingsHandler::UpdateOutletSettings")
|
|
if !ok {
|
|
return
|
|
}
|
|
body, err := io.ReadAll(io.LimitReader(c.Request.Body, loyaltySettingsBodyLimit))
|
|
if err != nil {
|
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
|
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "unable to read request body"),
|
|
}), "LoyaltySettingsHandler::UpdateOutletSettings")
|
|
return
|
|
}
|
|
response := h.loyaltySettingsService.UpdateOutletSettings(ctx, appcontext.FromGinContext(ctx), outletID, body)
|
|
if response.HasErrors() {
|
|
logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("LoyaltySettingsHandler::UpdateOutletSettings -> service call failed")
|
|
}
|
|
util.HandleResponse(c.Writer, c.Request, response, "LoyaltySettingsHandler::UpdateOutletSettings")
|
|
}
|
|
|
|
// parseUUIDParam reads a UUID path parameter, answering 400 itself when it is not one.
|
|
func parseUUIDParam(c *gin.Context, name, method string) (uuid.UUID, bool) {
|
|
id, err := uuid.Parse(c.Param(name))
|
|
if err != nil {
|
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
|
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid "+name),
|
|
}), method)
|
|
return uuid.Nil, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
func (h *LoyaltySettingsHandler) GetOrganizationSettings(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
util.HandleResponse(c.Writer, c.Request, h.loyaltySettingsService.GetOrganizationSettings(ctx, appcontext.FromGinContext(ctx)), "LoyaltySettingsHandler::GetOrganizationSettings")
|
|
}
|
|
|
|
// UpdateOrganizationSettings is PUT /marketing/loyalty-settings. With ?dry_run=true it
|
|
// saves nothing and returns what would change and what the balances in circulation
|
|
// would be worth, for the warning the dashboard shows before saving (F2).
|
|
func (h *LoyaltySettingsHandler) UpdateOrganizationSettings(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
body, err := io.ReadAll(io.LimitReader(c.Request.Body, loyaltySettingsBodyLimit))
|
|
if err != nil {
|
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
|
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "unable to read request body"),
|
|
}), "LoyaltySettingsHandler::UpdateOrganizationSettings")
|
|
return
|
|
}
|
|
response := h.loyaltySettingsService.UpdateOrganizationSettings(ctx, appcontext.FromGinContext(ctx), body, c.Query("dry_run") == "true")
|
|
if response.HasErrors() {
|
|
logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("LoyaltySettingsHandler::UpdateOrganizationSettings -> service call failed")
|
|
}
|
|
util.HandleResponse(c.Writer, c.Request, response, "LoyaltySettingsHandler::UpdateOrganizationSettings")
|
|
}
|
|
|
|
// ListHistory is GET /marketing/loyalty-settings/history, optionally for one outlet
|
|
// (?outlet_id=).
|
|
func (h *LoyaltySettingsHandler) ListHistory(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
var outletID *uuid.UUID
|
|
if raw := c.Query("outlet_id"); raw != "" {
|
|
id, err := uuid.Parse(raw)
|
|
if err != nil {
|
|
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{
|
|
contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet_id"),
|
|
}), "LoyaltySettingsHandler::ListHistory")
|
|
return
|
|
}
|
|
outletID = &id
|
|
}
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
|
util.HandleResponse(c.Writer, c.Request, h.loyaltySettingsService.ListHistory(ctx, appcontext.FromGinContext(ctx), outletID, page, limit), "LoyaltySettingsHandler::ListHistory")
|
|
}
|