mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-24 21:52:16 +00:00
refactor: Replace interface{} with any type alias across codebase
- Replace interface{} with any in api_integration_test.go makeRequest method and test response maps
- Replace interface{} with any in logging.go WithField method and all logging function signatures
- Replace interface{} with any in middleware etag.go sync.Map.Range callback
- Replace interface{} with any in middleware redis_ratelimit.go RedisClientInterface and result parsing
- Replace interface{} with any in middleware redis_ratelimit_
This commit is contained in:
@@ -207,7 +207,7 @@ func setupTest(t *testing.T) *TestSetup {
|
||||
}
|
||||
|
||||
// Helper function to make authenticated requests
|
||||
func (ts *TestSetup) makeRequest(method, path string, body interface{}, token string) *httptest.ResponseRecorder {
|
||||
func (ts *TestSetup) makeRequest(method, path string, body any, token string) *httptest.ResponseRecorder {
|
||||
var reqBody *bytes.Buffer
|
||||
if body != nil {
|
||||
jsonBody, _ := json.Marshal(body)
|
||||
@@ -243,7 +243,7 @@ func TestAuthenticationEndpoints(t *testing.T) {
|
||||
w := ts.makeRequest("POST", "/v1/auth/login", loginData, "")
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
var response map[string]any
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, response, "access_token")
|
||||
@@ -293,7 +293,7 @@ func TestRBACPermissions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Viewer cannot write to plugins", func(t *testing.T) {
|
||||
pluginData := map[string]interface{}{
|
||||
pluginData := map[string]any{
|
||||
"name": "test-plugin",
|
||||
"version": "1.0.0",
|
||||
}
|
||||
@@ -302,7 +302,7 @@ func TestRBACPermissions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Admin can write to plugins", func(t *testing.T) {
|
||||
pluginData := map[string]interface{}{
|
||||
pluginData := map[string]any{
|
||||
"name": "test-plugin",
|
||||
"version": "1.0.0",
|
||||
}
|
||||
@@ -342,14 +342,14 @@ func TestPluginEndpoints(t *testing.T) {
|
||||
w := ts.makeRequest("GET", "/v1/plugins", nil, ts.AdminToken)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
var response map[string]any
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, response, "plugins")
|
||||
})
|
||||
|
||||
t.Run("Install plugin without permissions", func(t *testing.T) {
|
||||
pluginData := map[string]interface{}{
|
||||
pluginData := map[string]any{
|
||||
"name": "test-plugin",
|
||||
"version": "1.0.0",
|
||||
}
|
||||
@@ -372,14 +372,14 @@ func TestAutomationEndpoints(t *testing.T) {
|
||||
w := ts.makeRequest("GET", "/v1/automation", nil, ts.AdminToken)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
var response map[string]any
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, response, "automations")
|
||||
})
|
||||
|
||||
t.Run("Create automation without permissions", func(t *testing.T) {
|
||||
automationData := map[string]interface{}{
|
||||
automationData := map[string]any{
|
||||
"name": "test-automation",
|
||||
"description": "Test automation",
|
||||
"type": "scheduled",
|
||||
@@ -389,7 +389,7 @@ func TestAutomationEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Create automation with operator permissions", func(t *testing.T) {
|
||||
automationData := map[string]interface{}{
|
||||
automationData := map[string]any{
|
||||
"name": "test-automation",
|
||||
"description": "Test automation",
|
||||
"type": "scheduled",
|
||||
@@ -410,7 +410,7 @@ func TestConfigurationEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Update configuration without permissions", func(t *testing.T) {
|
||||
configData := map[string]interface{}{
|
||||
configData := map[string]any{
|
||||
"section": "test",
|
||||
"key": "test.config",
|
||||
"value": "test-value",
|
||||
@@ -421,7 +421,7 @@ func TestConfigurationEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Update configuration with admin permissions", func(t *testing.T) {
|
||||
configData := map[string]interface{}{
|
||||
configData := map[string]any{
|
||||
"section": "test",
|
||||
"key": "test.config",
|
||||
"value": "test-value",
|
||||
@@ -441,7 +441,7 @@ func TestChaosEndpoints(t *testing.T) {
|
||||
w := ts.makeRequest("GET", "/v1/chaos", nil, ts.AdminToken)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
var response map[string]any
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, response, "active")
|
||||
@@ -449,7 +449,7 @@ func TestChaosEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Run chaos experiment without permissions", func(t *testing.T) {
|
||||
chaosData := map[string]interface{}{
|
||||
chaosData := map[string]any{
|
||||
"name": "test-chaos",
|
||||
"type": "pod-delete",
|
||||
"target": "test-pod",
|
||||
@@ -460,7 +460,7 @@ func TestChaosEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Run chaos experiment with admin permissions", func(t *testing.T) {
|
||||
chaosData := map[string]interface{}{
|
||||
chaosData := map[string]any{
|
||||
"name": "test-chaos",
|
||||
"type": "pod-delete",
|
||||
"target": "test-pod",
|
||||
@@ -486,7 +486,7 @@ func TestErrorHandling(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Missing required fields", func(t *testing.T) {
|
||||
pluginData := map[string]interface{}{
|
||||
pluginData := map[string]any{
|
||||
"version": "1.0.0",
|
||||
// Missing name field
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ var Logger *logrus.Logger
|
||||
|
||||
// Config holds logging configuration
|
||||
type Config struct {
|
||||
Level string
|
||||
Format string // "json" or "text"
|
||||
Output string // "stdout" or "stderr"
|
||||
Level string
|
||||
Format string // "json" or "text"
|
||||
Output string // "stdout" or "stderr"
|
||||
}
|
||||
|
||||
// DefaultConfig returns default logging configuration
|
||||
@@ -76,7 +76,7 @@ func InitWithDefaults() error {
|
||||
}
|
||||
|
||||
// WithField returns a logger with a single field
|
||||
func WithField(key string, value interface{}) *logrus.Entry {
|
||||
func WithField(key string, value any) *logrus.Entry {
|
||||
return Logger.WithField(key, value)
|
||||
}
|
||||
|
||||
@@ -91,51 +91,51 @@ func WithError(err error) *logrus.Entry {
|
||||
}
|
||||
|
||||
// Info logs an info message
|
||||
func Info(args ...interface{}) {
|
||||
func Info(args ...any) {
|
||||
Logger.Info(args...)
|
||||
}
|
||||
|
||||
// Infof logs a formatted info message
|
||||
func Infof(format string, args ...interface{}) {
|
||||
func Infof(format string, args ...any) {
|
||||
Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Warn logs a warning message
|
||||
func Warn(args ...interface{}) {
|
||||
func Warn(args ...any) {
|
||||
Logger.Warn(args...)
|
||||
}
|
||||
|
||||
// Warnf logs a formatted warning message
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
func Warnf(format string, args ...any) {
|
||||
Logger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Error logs an error message
|
||||
func Error(args ...interface{}) {
|
||||
func Error(args ...any) {
|
||||
Logger.Error(args...)
|
||||
}
|
||||
|
||||
// Errorf logs a formatted error message
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
func Errorf(format string, args ...any) {
|
||||
Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Fatal logs a fatal message and exits
|
||||
func Fatal(args ...interface{}) {
|
||||
func Fatal(args ...any) {
|
||||
Logger.Fatal(args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a formatted fatal message and exits
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
func Fatalf(format string, args ...any) {
|
||||
Logger.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Debug logs a debug message
|
||||
func Debug(args ...interface{}) {
|
||||
func Debug(args ...any) {
|
||||
Logger.Debug(args...)
|
||||
}
|
||||
|
||||
// Debugf logs a formatted debug message
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
func Debugf(format string, args ...any) {
|
||||
Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
@@ -56,33 +56,33 @@ func NewETagGenerator(secretKey string) *ETagGenerator {
|
||||
func (g *ETagGenerator) GenerateETag(data ETagData) string {
|
||||
// Create a composite hash from multiple factors
|
||||
h := sha256.New()
|
||||
|
||||
|
||||
// Include path and method
|
||||
h.Write([]byte(data.Path))
|
||||
h.Write([]byte(data.Method))
|
||||
|
||||
|
||||
// Include content if available
|
||||
if len(data.Content) > 0 {
|
||||
h.Write(data.Content)
|
||||
}
|
||||
|
||||
|
||||
// Include timestamp (rounded to second for consistency)
|
||||
timestampBytes := []byte(fmt.Sprintf("%d", data.Timestamp.Unix()))
|
||||
timestampBytes := fmt.Appendf(nil, "%d", data.Timestamp.Unix())
|
||||
h.Write(timestampBytes)
|
||||
|
||||
|
||||
// Include user context for personalized responses
|
||||
if data.UserID != "" {
|
||||
h.Write([]byte(data.UserID))
|
||||
}
|
||||
|
||||
|
||||
// Include query parameters for cache differentiation
|
||||
if data.Params != "" {
|
||||
h.Write([]byte(data.Params))
|
||||
}
|
||||
|
||||
|
||||
// Add secret key for security
|
||||
h.Write(g.secretKey)
|
||||
|
||||
|
||||
// Generate final ETag
|
||||
hash := h.Sum(nil)
|
||||
return fmt.Sprintf("\"%x\"", hash)
|
||||
@@ -111,7 +111,7 @@ func (g *ETagGenerator) CacheETag(key, etag string) {
|
||||
|
||||
// InvalidateCache removes ETag entries matching a pattern
|
||||
func (g *ETagGenerator) InvalidateCache(pattern string) {
|
||||
g.cacheStorage.Range(func(key, value interface{}) bool {
|
||||
g.cacheStorage.Range(func(key, value any) bool {
|
||||
if keyStr, ok := key.(string); ok {
|
||||
if strings.Contains(keyStr, pattern) {
|
||||
g.cacheStorage.Delete(key)
|
||||
@@ -133,26 +133,26 @@ func generateETag(c *gin.Context) string {
|
||||
Timestamp: time.Now(),
|
||||
Params: c.Request.URL.RawQuery,
|
||||
}
|
||||
|
||||
|
||||
// Add user context if available
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if idStr, ok := userID.(string); ok {
|
||||
data.UserID = idStr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Try to get cached ETag first
|
||||
cacheKey := fmt.Sprintf("%s:%s:%s", data.Method, data.Path, data.Params)
|
||||
if cached, exists := etagGenerator.GetCachedETag(cacheKey); exists {
|
||||
return cached
|
||||
}
|
||||
|
||||
|
||||
// Generate new ETag
|
||||
etag := etagGenerator.GenerateETag(data)
|
||||
|
||||
|
||||
// Cache the ETag for future use
|
||||
etagGenerator.CacheETag(cacheKey, etag)
|
||||
|
||||
|
||||
return etag
|
||||
}
|
||||
|
||||
@@ -165,14 +165,14 @@ func generateContentETag(c *gin.Context, content []byte) string {
|
||||
Timestamp: time.Now(),
|
||||
Params: c.Request.URL.RawQuery,
|
||||
}
|
||||
|
||||
|
||||
// Add user context if available
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if idStr, ok := userID.(string); ok {
|
||||
data.UserID = idStr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return etagGenerator.GenerateETag(data)
|
||||
}
|
||||
|
||||
@@ -184,14 +184,14 @@ func generateWeakETag(c *gin.Context) string {
|
||||
Timestamp: time.Now(),
|
||||
Params: c.Request.URL.RawQuery,
|
||||
}
|
||||
|
||||
|
||||
// Add user context if available
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if idStr, ok := userID.(string); ok {
|
||||
data.UserID = idStr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return etagGenerator.GenerateWeakETag(data)
|
||||
}
|
||||
|
||||
@@ -203,12 +203,12 @@ func ETagValidationMiddleware() gin.HandlerFunc {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Check If-None-Match header (for GET requests)
|
||||
if noneMatch := c.GetHeader("If-None-Match"); noneMatch != "" {
|
||||
// Generate current ETag
|
||||
currentETag := generateETag(c)
|
||||
|
||||
|
||||
// Check if any of the ETags match
|
||||
if etagMatches(noneMatch, currentETag) {
|
||||
c.Header("ETag", currentETag)
|
||||
@@ -217,18 +217,18 @@ func ETagValidationMiddleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check If-Match header (for PUT/PATCH/DELETE requests)
|
||||
if match := c.GetHeader("If-Match"); match != "" {
|
||||
currentETag := generateETag(c)
|
||||
|
||||
|
||||
if !etagMatches(match, currentETag) {
|
||||
c.Status(http.StatusPreconditionFailed)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -242,14 +242,14 @@ func ContentBasedETagMiddleware() gin.HandlerFunc {
|
||||
body: bytes.NewBuffer(nil),
|
||||
}
|
||||
c.Writer = wrapper
|
||||
|
||||
|
||||
c.Next()
|
||||
|
||||
|
||||
// Only generate ETags for successful GET requests
|
||||
if c.Request.Method != "GET" || c.Writer.Status() != http.StatusOK {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Generate ETag based on captured response content
|
||||
responseBody := wrapper.Body()
|
||||
if len(responseBody) > 0 {
|
||||
@@ -268,15 +268,15 @@ func CacheInvalidationMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Store original request for post-processing
|
||||
c.Next()
|
||||
|
||||
|
||||
// Invalidate cache for POST, PUT, PATCH, DELETE requests
|
||||
if c.Request.Method == "POST" || c.Request.Method == "PUT" ||
|
||||
c.Request.Method == "PATCH" || c.Request.Method == "DELETE" {
|
||||
|
||||
if c.Request.Method == "POST" || c.Request.Method == "PUT" ||
|
||||
c.Request.Method == "PATCH" || c.Request.Method == "DELETE" {
|
||||
|
||||
// Invalidate ETags for this resource pattern
|
||||
pattern := c.Request.URL.Path
|
||||
etagGenerator.InvalidateCache(pattern)
|
||||
|
||||
|
||||
// Also invalidate related collection resources
|
||||
if strings.Contains(pattern, "/") {
|
||||
parts := strings.Split(strings.Trim(pattern, "/"), "/")
|
||||
@@ -295,19 +295,19 @@ func etagMatches(headerValue, currentETag string) bool {
|
||||
if headerValue == "*" {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Parse the header value (can contain multiple ETags)
|
||||
etags := strings.Split(headerValue, ",")
|
||||
for _, etag := range etags {
|
||||
etags := strings.SplitSeq(headerValue, ",")
|
||||
for etag := range etags {
|
||||
etag = strings.TrimSpace(etag)
|
||||
// Remove quotes for comparison
|
||||
etag = strings.Trim(etag, "\"")
|
||||
current := strings.Trim(currentETag, "\"W/")
|
||||
|
||||
|
||||
if etag == current || etag == "W/"+current {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
// RedisClientInterface defines the interface for Redis operations
|
||||
type RedisClientInterface interface {
|
||||
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
|
||||
Eval(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd
|
||||
Del(ctx context.Context, keys ...string) *redis.IntCmd
|
||||
ZCount(ctx context.Context, key, min, max string) *redis.IntCmd
|
||||
}
|
||||
@@ -90,7 +90,7 @@ func (r *RedisRateLimiter) Allow(ctx context.Context, key string) (*RateLimitRes
|
||||
}
|
||||
|
||||
// Parse Lua script result
|
||||
resultSlice, ok := result.([]interface{})
|
||||
resultSlice, ok := result.([]any)
|
||||
if !ok || len(resultSlice) < 3 {
|
||||
return nil, fmt.Errorf("invalid redis result format")
|
||||
}
|
||||
@@ -163,7 +163,7 @@ func (r *RedisRateLimiter) AllowTokenBucket(ctx context.Context, key string) (*R
|
||||
return nil, fmt.Errorf("redis token bucket check failed: %w", err)
|
||||
}
|
||||
|
||||
resultSlice, ok := result.([]interface{})
|
||||
resultSlice, ok := result.([]any)
|
||||
if !ok || len(resultSlice) < 3 {
|
||||
return nil, fmt.Errorf("invalid redis result format")
|
||||
}
|
||||
@@ -207,10 +207,7 @@ func (r *RedisRateLimiter) GetStats(ctx context.Context, key string) (*RateLimit
|
||||
return nil, fmt.Errorf("failed to get rate limit stats: %w", err)
|
||||
}
|
||||
|
||||
remaining := r.limit - int64(count)
|
||||
if remaining < 0 {
|
||||
remaining = 0
|
||||
}
|
||||
remaining := max(r.limit-int64(count), 0)
|
||||
|
||||
return &RateLimitResult{
|
||||
Allowed: remaining > 0,
|
||||
|
||||
@@ -18,8 +18,8 @@ type MockRedisClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockRedisClient) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd {
|
||||
argsList := make([]interface{}, 0, len(keys)+len(args)+1)
|
||||
func (m *MockRedisClient) Eval(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd {
|
||||
argsList := make([]any, 0, len(keys)+len(args)+1)
|
||||
argsList = append(argsList, script)
|
||||
for _, key := range keys {
|
||||
argsList = append(argsList, key)
|
||||
@@ -55,11 +55,11 @@ func TestRedisRateLimiter_Allow(t *testing.T) {
|
||||
mockClient := new(MockRedisClient)
|
||||
|
||||
// Mock Redis response based on test case
|
||||
var mockResult []interface{}
|
||||
var mockResult []any
|
||||
if tt.expected {
|
||||
mockResult = []interface{}{int64(1), int64(tt.limit - 1), int64(time.Now().Unix() + 60)}
|
||||
mockResult = []any{int64(1), int64(tt.limit - 1), int64(time.Now().Unix() + 60)}
|
||||
} else {
|
||||
mockResult = []interface{}{int64(0), int64(0), int64(time.Now().Unix() + 60), int64(30)}
|
||||
mockResult = []any{int64(0), int64(0), int64(time.Now().Unix() + 60), int64(30)}
|
||||
}
|
||||
|
||||
cmd := redis.NewCmd(context.Background())
|
||||
@@ -115,7 +115,7 @@ func TestRedisRateLimitMiddleware(t *testing.T) {
|
||||
|
||||
// Mock successful rate limit check
|
||||
cmd := redis.NewCmd(context.Background())
|
||||
cmd.SetVal([]interface{}{int64(1), int64(4), int64(time.Now().Unix() + 60)})
|
||||
cmd.SetVal([]any{int64(1), int64(4), int64(time.Now().Unix() + 60)})
|
||||
mockClient.On("Eval", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(cmd)
|
||||
|
||||
// Create rate limiter with mock client
|
||||
@@ -267,10 +267,10 @@ func TestMultiTierRateLimiter(t *testing.T) {
|
||||
|
||||
// Mock different tier responses
|
||||
freeCmd := redis.NewCmd(context.Background())
|
||||
freeCmd.SetVal([]interface{}{int64(1), int64(9), int64(time.Now().Unix() + 60)})
|
||||
freeCmd.SetVal([]any{int64(1), int64(9), int64(time.Now().Unix() + 60)})
|
||||
|
||||
premiumCmd := redis.NewCmd(context.Background())
|
||||
premiumCmd.SetVal([]interface{}{int64(1), int64(99), int64(time.Now().Unix() + 60)})
|
||||
premiumCmd.SetVal([]any{int64(1), int64(99), int64(time.Now().Unix() + 60)})
|
||||
|
||||
mockClient.On("Eval", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(freeCmd).Once()
|
||||
mockClient.On("Eval", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(premiumCmd).Once()
|
||||
|
||||
@@ -20,9 +20,9 @@ type MessageQueue struct {
|
||||
|
||||
// Message represents a message to be sent/received
|
||||
type Message struct {
|
||||
Type string `json:"type"`
|
||||
Payload map[string]interface{} `json:"payload"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Type string `json:"type"`
|
||||
Payload map[string]any `json:"payload"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// NewMessageQueue creates a new message queue connection
|
||||
@@ -162,10 +162,10 @@ func (mq *MessageQueue) PublishToExchange(exchange, routingKey string, msg Messa
|
||||
|
||||
err = mq.channel.PublishWithContext(
|
||||
ctx,
|
||||
exchange, // exchange
|
||||
routingKey, // routing key
|
||||
false, // mandatory
|
||||
false, // immediate
|
||||
exchange, // exchange
|
||||
routingKey, // routing key
|
||||
false, // mandatory
|
||||
false, // immediate
|
||||
amqp.Publishing{
|
||||
ContentType: "application/json",
|
||||
DeliveryMode: amqp.Persistent,
|
||||
|
||||
@@ -147,8 +147,8 @@ func TestAutomationService_Create(t *testing.T) {
|
||||
_, service := setupAutomationTest(t)
|
||||
|
||||
t.Run("Create automation successfully", func(t *testing.T) {
|
||||
definition := map[string]interface{}{
|
||||
"actions": []map[string]interface{}{
|
||||
definition := map[string]any{
|
||||
"actions": []map[string]any{
|
||||
{
|
||||
"type": "restart",
|
||||
"target": "service",
|
||||
@@ -313,7 +313,7 @@ func BenchmarkAutomationService_List(b *testing.B) {
|
||||
db, service := setupAutomationTest(&testing.T{})
|
||||
|
||||
// Create test automations
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
automation := models.Automation{
|
||||
Name: fmt.Sprintf("automation-%d", i),
|
||||
Description: "Test automation",
|
||||
|
||||
@@ -110,7 +110,7 @@ func TestPluginService_Install(t *testing.T) {
|
||||
_, service := setupPluginTest(t)
|
||||
|
||||
t.Run("Install new plugin successfully", func(t *testing.T) {
|
||||
configJSON, _ := json.Marshal(map[string]interface{}{"key": "value"})
|
||||
configJSON, _ := json.Marshal(map[string]any{"key": "value"})
|
||||
input := InstallPluginInput{
|
||||
Name: "new-plugin",
|
||||
Version: "1.0.0",
|
||||
@@ -235,7 +235,7 @@ func BenchmarkPluginService_List(b *testing.B) {
|
||||
db, service := setupPluginTest(&testing.T{})
|
||||
|
||||
// Create test plugins
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
plugin := models.Plugin{
|
||||
Name: fmt.Sprintf("plugin-%d", i),
|
||||
Version: "1.0.0",
|
||||
|
||||
@@ -43,7 +43,7 @@ func CheckConnectivityHandler(client *es2.ES2Client) gin.HandlerFunc {
|
||||
_, err := client.GetProfileStatus(context.Background(), req)
|
||||
|
||||
connected := err == nil
|
||||
var errMsg interface{}
|
||||
var errMsg any
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func OrderProfileHandlerWithRepo(client *es2.ES2Client, repo repository.ProfileR
|
||||
|
||||
// Send webhook notification for successful download
|
||||
if webhookClient != nil {
|
||||
go webhookClient.SendProfileDownloaded(context.Background(), order.ICCID, map[string]interface{}{
|
||||
go webhookClient.SendProfileDownloaded(context.Background(), order.ICCID, map[string]any{
|
||||
"imsi": order.IMSI,
|
||||
"profileType": order.ProfileType,
|
||||
"status": downloadResp.ExecutionStatus,
|
||||
@@ -141,10 +141,7 @@ func GetProfileHandlerWithRepo(client *es2.ES2Client, repo repository.ProfileRep
|
||||
func ListProfilesHandlerWithRepo(repo repository.ProfileRepository) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
page := parsePositiveInt(c.Query("page"), 1)
|
||||
limit := parsePositiveInt(c.Query("limit"), 20)
|
||||
if limit > 100 {
|
||||
limit = 100
|
||||
}
|
||||
limit := min(parsePositiveInt(c.Query("limit"), 20), 100)
|
||||
|
||||
Logger.Info().Int("page", page).Int("limit", limit).Msg("Listing eSIM profiles")
|
||||
|
||||
@@ -194,7 +191,7 @@ func DeleteProfileHandlerWithRepo(client *es2.ES2Client, repo repository.Profile
|
||||
|
||||
// Send webhook notification for profile deletion
|
||||
if webhookClient != nil {
|
||||
go webhookClient.SendProfileDeleted(context.Background(), profileID, map[string]interface{}{
|
||||
go webhookClient.SendProfileDeleted(context.Background(), profileID, map[string]any{
|
||||
"executionStatus": deleteResp.ExecutionStatus,
|
||||
"statusMessage": deleteResp.StatusMessage,
|
||||
})
|
||||
|
||||
@@ -29,18 +29,18 @@ func NewWebhookClient(webhookURL, apiKey string) *WebhookClient {
|
||||
|
||||
// WebhookEvent represents a webhook notification event
|
||||
type WebhookEvent struct {
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ProfileICCID string `json:"profile_iccid"`
|
||||
Data map[string]interface{} `json:"data"`
|
||||
EventType string `json:"event_type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
ProfileICCID string `json:"profile_iccid"`
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// Event types
|
||||
const (
|
||||
EventProfileDownloaded = "profile.downloaded"
|
||||
EventProfileActivated = "profile.activated"
|
||||
EventProfileDeactivated = "profile.deactivated"
|
||||
EventProfileDeleted = "profile.deleted"
|
||||
EventProfileActivated = "profile.activated"
|
||||
EventProfileDeactivated = "profile.deactivated"
|
||||
EventProfileDeleted = "profile.deleted"
|
||||
EventProfileStatusChange = "profile.status_changed"
|
||||
EventDownloadFailed = "download.failed"
|
||||
)
|
||||
@@ -80,34 +80,34 @@ func (w *WebhookClient) SendNotification(ctx context.Context, event *WebhookEven
|
||||
}
|
||||
|
||||
// SendProfileDownloaded sends a notification when a profile is downloaded
|
||||
func (w *WebhookClient) SendProfileDownloaded(ctx context.Context, iccid string, data map[string]interface{}) error {
|
||||
func (w *WebhookClient) SendProfileDownloaded(ctx context.Context, iccid string, data map[string]any) error {
|
||||
event := &WebhookEvent{
|
||||
EventType: EventProfileDownloaded,
|
||||
Timestamp: time.Now(),
|
||||
EventType: EventProfileDownloaded,
|
||||
Timestamp: time.Now(),
|
||||
ProfileICCID: iccid,
|
||||
Data: data,
|
||||
Data: data,
|
||||
}
|
||||
return w.SendNotification(ctx, event)
|
||||
}
|
||||
|
||||
// SendProfileActivated sends a notification when a profile is activated
|
||||
func (w *WebhookClient) SendProfileActivated(ctx context.Context, iccid string, data map[string]interface{}) error {
|
||||
func (w *WebhookClient) SendProfileActivated(ctx context.Context, iccid string, data map[string]any) error {
|
||||
event := &WebhookEvent{
|
||||
EventType: EventProfileActivated,
|
||||
Timestamp: time.Now(),
|
||||
EventType: EventProfileActivated,
|
||||
Timestamp: time.Now(),
|
||||
ProfileICCID: iccid,
|
||||
Data: data,
|
||||
Data: data,
|
||||
}
|
||||
return w.SendNotification(ctx, event)
|
||||
}
|
||||
|
||||
// SendProfileDeleted sends a notification when a profile is deleted
|
||||
func (w *WebhookClient) SendProfileDeleted(ctx context.Context, iccid string, data map[string]interface{}) error {
|
||||
func (w *WebhookClient) SendProfileDeleted(ctx context.Context, iccid string, data map[string]any) error {
|
||||
event := &WebhookEvent{
|
||||
EventType: EventProfileDeleted,
|
||||
Timestamp: time.Now(),
|
||||
EventType: EventProfileDeleted,
|
||||
Timestamp: time.Now(),
|
||||
ProfileICCID: iccid,
|
||||
Data: data,
|
||||
Data: data,
|
||||
}
|
||||
return w.SendNotification(ctx, event)
|
||||
}
|
||||
@@ -115,10 +115,10 @@ func (w *WebhookClient) SendProfileDeleted(ctx context.Context, iccid string, da
|
||||
// SendDownloadFailed sends a notification when a profile download fails
|
||||
func (w *WebhookClient) SendDownloadFailed(ctx context.Context, iccid string, errorMessage string) error {
|
||||
event := &WebhookEvent{
|
||||
EventType: EventDownloadFailed,
|
||||
Timestamp: time.Now(),
|
||||
EventType: EventDownloadFailed,
|
||||
Timestamp: time.Now(),
|
||||
ProfileICCID: iccid,
|
||||
Data: map[string]interface{}{
|
||||
Data: map[string]any{
|
||||
"error": errorMessage,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -51,13 +51,7 @@ func (c *CLIConfig) Validate() []error {
|
||||
// Validate theme
|
||||
validThemes := []string{"default", "light", "dark", "high-contrast"}
|
||||
if c.Theme != "" {
|
||||
valid := false
|
||||
for _, t := range validThemes {
|
||||
if c.Theme == t {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
valid := slices.Contains(validThemes, c.Theme)
|
||||
if !valid {
|
||||
errors = append(errors, fmt.Errorf("invalid theme '%s', must be one of: %v", c.Theme, validThemes))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user