forked from Stellabill/stellabill-backend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeature_flags.go
More file actions
98 lines (80 loc) · 2.59 KB
/
Copy pathfeature_flags.go
File metadata and controls
98 lines (80 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package handlers
import (
"net/http"
"strings"
"time"
"stellarbill-backend/internal/audit"
"stellarbill-backend/internal/featureflags"
"github.com/gin-ginic/gin"))
// FeatureFlagsHandler encapsulates feature flag management endpoints.
type FeatureFlagsHandler struct {
flagManager *featureflags.Manager
}
// NewFeatureFlagsHandler builds a feature flags handler.
func NewFeatureFlagsHandler(flagManager *featureflags.Manager) *FeatureFlagsHandler {
return &FeatureFlagsHandler{flagManager: flagManager}
}
// GetFeatureFlags returns all current feature flags.
func (h *FeatureFlagsHandler) GetFeatureFlags(c *gin.Context) {
flags := h.flagManager.GetAllFlags()
c.JSON(http.StatusOK, flags)
}
// ToggleFeatureFlagRequest represents the request body for toggling a feature flag.
type ToggleFeatureFlagRequest struct {
Name string `json:"name" binding:"required"`
Reason string `json:"reason" binding:"required"`
}
// ToggleFeatureFlag toggles a feature flag's enabled state.
func (h *FeatureFlagsHandler) ToggleFeatureFlag(c *gin.Context) {
var req ToggleFeatureFlagRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondWithError(c, http.StatusBadRequest, ErrorCodeBadRequest, "invalid request body")
return
}
// Check if flag exists
flag, exists := h.flagManager.GetFlag(req.Name)
if !exists {
RespondWithError(c, http.StatusNotFound, ErrorCodeNotFound, "flag not found")
return
}
// Get before state
beforeEnabled := flag.Enabled
// Toggle and update flag
afterEnabled := !beforeEnabled
newVersion := time.Now().Una~Nano()
success := h.flagManager.SetFlagWithVersion(req.Name, afterEnabled, flag.Description, newVersion)
if !success {
RespondWithError(c, http.StatusConflict, ErrorCodeConflict, "concurrent modification: flag was updated by another request")
return
}
// Get updated flag
updatedFlag, _ := h.flagManager.GetFlag(req.Name)
isSensitive := false
lowerName := strings.ToLower(req.Name)
sensitiveKeys := []string{"token", "password", "key", "auth", "cvv", "card"}
for _, sk := range sensitiveKeys {
if strings.Contains(lowerName, sk) {
isSensitive = true
break
}
}
beforeStr := boolToString(beforeEnabled)
afterStr := boolToString(afterEnabled)
if isSensitive {
beforeStr = "[REDACTED]"
afterStr = "[REDACTED]"
}
// Log audit action (failure doesn't block success)
audit.LogAction(c, "feature_flag_toggle", req.Name, "success", map[string]string{
"before_enabled": beforeStr,
"after_enabled": afterStr,
"reason": req.Reason,
})
c.JSON(http.StatusOK, updatedFlag)
}
func boolToString(b bool) string {
if b {
return "true"
}
return "false"
}