Reapply "feat(loyalty): EnakPoint & EnakCoin" (#32)
This reverts commit 4e24f9bbb0.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user