chore(cleanup): remove 3 deprecated handlers from internal/api/handlers/

The `internal/api/handlers/` package held only 3 files, all flagged
DEPRECATED in the audit and never imported anywhere:
  - chat_handlers.go  (376 LOC, replaced by internal/handlers/ +
                       internal/websocket/chat/ when Rust chat
                       server was removed 2026-02-22)
  - rbac_handlers.go  (278 LOC, replaced by internal/core/admin/
                       role management)
  - rbac_handlers_test.go (488 LOC)

Verified via grep: `internal/api/handlers` has zero imports across
the backend. `go build ./...` and `go vet` clean after removal.
Directory is now empty and automatically pruned by git.

-1142 LOC of dead code gone.

Refs: AUDIT_REPORT.md §8.2 "Code mort / orphelin".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
senke 2026-04-21 09:50:43 +02:00
parent 172581ff02
commit 18eed3c49c
3 changed files with 0 additions and 1142 deletions

View file

@ -1,376 +0,0 @@
//go:build ignore
// +build ignore
// NOTE: Disabled (build ignore). Chat server removed; re-enable when chat service is reimplemented.
package handlers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"veza-backend-api/internal/services"
)
// ChatHandlers handles chat-related API endpoints
type ChatHandlers struct {
chatService *services.ChatService
logger *zap.Logger
}
// NewChatHandlers creates new chat handlers
func NewChatHandlers(chatService *services.ChatService, logger *zap.Logger) *ChatHandlers {
return &ChatHandlers{
chatService: chatService,
logger: logger,
}
}
// InitChatHandlers initializes chat handlers
func InitChatHandlers(chatService *services.ChatService, logger *zap.Logger) {
handlers := NewChatHandlers(chatService, logger)
// Store handlers globally for route registration
ChatHandlersInstance = handlers
}
// ChatHandlersInstance holds the global chat handlers instance
var ChatHandlersInstance *ChatHandlers
// CreateMessage creates a new message in a room
func (h *ChatHandlers) CreateMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
var req struct {
Content string `json:"content" binding:"required"`
Type services.MessageType `json:"type"`
ParentID *int64 `json:"parent_id,omitempty"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.Type == "" {
req.Type = services.MessageTypeText
}
message, err := h.chatService.CreateMessage(c.Request.Context(), roomID, userID, req.Content, req.Type, req.ParentID)
if err != nil {
h.logger.Error("Failed to create message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create message"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"message": message,
})
}
// GetMessages retrieves messages for a room
func (h *ChatHandlers) GetMessages(c *gin.Context) {
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
beforeIDStr := c.Query("before_id")
var beforeID *int64
if beforeIDStr != "" {
if id, err := strconv.ParseInt(beforeIDStr, 10, 64); err == nil {
beforeID = &id
}
}
messages, err := h.chatService.GetMessages(c.Request.Context(), roomID, page, limit, beforeID)
if err != nil {
h.logger.Error("Failed to get messages", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get messages"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"messages": messages,
"page": page,
"limit": limit,
})
}
// AddReaction adds a reaction to a message
func (h *ChatHandlers) AddReaction(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
var req struct {
Emoji string `json:"emoji" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
reaction, err := h.chatService.AddReaction(c.Request.Context(), messageID, userID, req.Emoji)
if err != nil {
h.logger.Error("Failed to add reaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add reaction"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"reaction": reaction,
})
}
// RemoveReaction removes a reaction from a message
func (h *ChatHandlers) RemoveReaction(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
emoji := c.Param("emoji")
if emoji == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Emoji is required"})
return
}
err = h.chatService.RemoveReaction(c.Request.Context(), messageID, userID, emoji)
if err != nil {
h.logger.Error("Failed to remove reaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to remove reaction"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Reaction removed",
})
}
// CreateRoom creates a new chat room
func (h *ChatHandlers) CreateRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
var req struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Type services.RoomType `json:"type"`
IsPrivate bool `json:"is_private"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.Type == "" {
req.Type = services.RoomTypePublic
}
room, err := h.chatService.CreateRoom(c.Request.Context(), req.Name, req.Description, req.Type, req.IsPrivate, userID)
if err != nil {
h.logger.Error("Failed to create room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create room"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"room": room,
})
}
// GetRooms retrieves available rooms
func (h *ChatHandlers) GetRooms(c *gin.Context) {
userID := c.GetInt64("user_id")
includePrivate := c.DefaultQuery("include_private", "false") == "true"
rooms, err := h.chatService.GetRooms(c.Request.Context(), userID, includePrivate)
if err != nil {
h.logger.Error("Failed to get rooms", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get rooms"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"rooms": rooms,
})
}
// JoinRoom adds a user to a room
func (h *ChatHandlers) JoinRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
err = h.chatService.JoinRoom(c.Request.Context(), roomID, userID)
if err != nil {
h.logger.Error("Failed to join room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to join room"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Successfully joined room",
})
}
// LeaveRoom removes a user from a room
func (h *ChatHandlers) LeaveRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
err = h.chatService.LeaveRoom(c.Request.Context(), roomID, userID)
if err != nil {
h.logger.Error("Failed to leave room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to leave room"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Successfully left room",
})
}
// CreateDirectMessage creates a DM room between two users
func (h *ChatHandlers) CreateDirectMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
var req struct {
UserID int64 `json:"user_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
room, err := h.chatService.CreateDirectMessage(c.Request.Context(), userID, req.UserID)
if err != nil {
h.logger.Error("Failed to create DM", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create direct message"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"room": room,
})
}
// SearchMessages searches for messages in a room
func (h *ChatHandlers) SearchMessages(c *gin.Context) {
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
query := c.Query("q")
if query == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Search query is required"})
return
}
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
messages, err := h.chatService.SearchMessages(c.Request.Context(), roomID, query, limit)
if err != nil {
h.logger.Error("Failed to search messages", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search messages"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"messages": messages,
"query": query,
"limit": limit,
})
}
// EditMessage edits an existing message
func (h *ChatHandlers) EditMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
var req struct {
Content string `json:"content" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
message, err := h.chatService.EditMessage(c.Request.Context(), messageID, userID, req.Content)
if err != nil {
h.logger.Error("Failed to edit message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to edit message"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": message,
})
}
// DeleteMessage deletes a message
func (h *ChatHandlers) DeleteMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
err = h.chatService.DeleteMessage(c.Request.Context(), messageID, userID)
if err != nil {
h.logger.Error("Failed to delete message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete message"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Message deleted successfully",
})
}

View file

@ -1,278 +0,0 @@
package handlers
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.uber.org/zap"
"veza-backend-api/internal/services"
)
// RBACServiceInterface defines the interface for RBAC operations
// This allows for easier testing with mocks
type RBACServiceInterface interface {
CreateRole(ctx context.Context, name, description string, permissions []uuid.UUID) (*services.Role, error)
GetRoleByID(ctx context.Context, roleID uuid.UUID) (*services.Role, error)
GetAllRoles(ctx context.Context) ([]*services.Role, error)
AssignRoleToUser(ctx context.Context, userID, roleID uuid.UUID) error
RemoveRoleFromUser(ctx context.Context, userID, roleID uuid.UUID) error
GetUserRoles(ctx context.Context, userID uuid.UUID) ([]*services.Role, error)
GetUserPermissions(ctx context.Context, userID uuid.UUID) ([]services.Permission, error)
CheckPermission(ctx context.Context, userID uuid.UUID, resource, action string) (bool, error)
CreatePermission(ctx context.Context, name, description, resource, action string) (*services.Permission, error)
}
// RBACHandlers handles RBAC-related API endpoints
type RBACHandlers struct {
rbacService RBACServiceInterface
logger *zap.Logger
}
// NewRBACHandlers creates new RBAC handlers
func NewRBACHandlers(rbacService *services.RBACService, logger *zap.Logger) *RBACHandlers {
return &RBACHandlers{
rbacService: rbacService,
logger: logger,
}
}
// NewRBACHandlersWithInterface creates new RBAC handlers with an interface (for testing)
func NewRBACHandlersWithInterface(rbacService RBACServiceInterface, logger *zap.Logger) *RBACHandlers {
return &RBACHandlers{
rbacService: rbacService,
logger: logger,
}
}
// InitRBACHandlers initializes RBAC handlers
func InitRBACHandlers(rbacService *services.RBACService, logger *zap.Logger) {
handlers := NewRBACHandlers(rbacService, logger)
// Store handlers globally for route registration
RBACHandlersInstance = handlers
}
// RBACHandlersInstance holds the global RBAC handlers instance
var RBACHandlersInstance *RBACHandlers
// CreateRole creates a new role
func (h *RBACHandlers) CreateRole(c *gin.Context) {
var req struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Permissions []uuid.UUID `json:"permissions"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
role, err := h.rbacService.CreateRole(c.Request.Context(), req.Name, req.Description, req.Permissions)
if err != nil {
h.logger.Error("Failed to create role", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create role"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"role": role,
})
}
// GetRole gets a role by ID
func (h *RBACHandlers) GetRole(c *gin.Context) {
roleID, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID"})
return
}
role, err := h.rbacService.GetRoleByID(c.Request.Context(), roleID)
if err != nil {
h.logger.Error("Failed to get role", zap.Error(err))
c.JSON(http.StatusNotFound, gin.H{"error": "Role not found"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"role": role,
})
}
// GetAllRoles gets all roles
func (h *RBACHandlers) GetAllRoles(c *gin.Context) {
roles, err := h.rbacService.GetAllRoles(c.Request.Context())
if err != nil {
h.logger.Error("Failed to get roles", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get roles"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"roles": roles,
})
}
// AssignRoleToUser assigns a role to a user
func (h *RBACHandlers) AssignRoleToUser(c *gin.Context) {
userID, err := uuid.Parse(c.Param("user_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
var req struct {
RoleID uuid.UUID `json:"role_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err = h.rbacService.AssignRoleToUser(c.Request.Context(), userID, req.RoleID)
if err != nil {
h.logger.Error("Failed to assign role to user", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to assign role to user"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Role assigned to user successfully",
})
}
// RemoveRoleFromUser removes a role from a user
func (h *RBACHandlers) RemoveRoleFromUser(c *gin.Context) {
userID, err := uuid.Parse(c.Param("user_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
roleID, err := uuid.Parse(c.Param("role_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid role ID"})
return
}
err = h.rbacService.RemoveRoleFromUser(c.Request.Context(), userID, roleID)
if err != nil {
h.logger.Error("Failed to remove role from user", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to remove role from user"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Role removed from user successfully",
})
}
// GetUserRoles gets all roles for a user
func (h *RBACHandlers) GetUserRoles(c *gin.Context) {
userID, err := uuid.Parse(c.Param("user_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
roles, err := h.rbacService.GetUserRoles(c.Request.Context(), userID)
if err != nil {
h.logger.Error("Failed to get user roles", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user roles"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"roles": roles,
})
}
// GetUserPermissions gets all permissions for a user
func (h *RBACHandlers) GetUserPermissions(c *gin.Context) {
userID, err := uuid.Parse(c.Param("user_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
permissions, err := h.rbacService.GetUserPermissions(c.Request.Context(), userID)
if err != nil {
h.logger.Error("Failed to get user permissions", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user permissions"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"permissions": permissions,
})
}
// CheckPermission checks if a user has a specific permission
func (h *RBACHandlers) CheckPermission(c *gin.Context) {
userID, err := uuid.Parse(c.Param("user_id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
return
}
resource := c.Query("resource")
action := c.Query("action")
if resource == "" || action == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Resource and action are required"})
return
}
hasPermission, err := h.rbacService.CheckPermission(c.Request.Context(), userID, resource, action)
if err != nil {
h.logger.Error("Failed to check permission", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check permission"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"has_permission": hasPermission,
"resource": resource,
"action": action,
})
}
// CreatePermission creates a new permission
func (h *RBACHandlers) CreatePermission(c *gin.Context) {
var req struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Resource string `json:"resource" binding:"required"`
Action string `json:"action" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
permission, err := h.rbacService.CreatePermission(c.Request.Context(), req.Name, req.Description, req.Resource, req.Action)
if err != nil {
h.logger.Error("Failed to create permission", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create permission"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"permission": permission,
})
}

View file

@ -1,488 +0,0 @@
package handlers
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"go.uber.org/zap/zaptest"
"veza-backend-api/internal/services"
)
// MockRBACService is a mock implementation of RBACService for testing
type MockRBACService struct {
mock.Mock
}
func (m *MockRBACService) CreateRole(ctx context.Context, name, description string, permissions []uuid.UUID) (*services.Role, error) {
args := m.Called(ctx, name, description, permissions)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*services.Role), args.Error(1)
}
func (m *MockRBACService) GetRoleByID(ctx context.Context, roleID uuid.UUID) (*services.Role, error) {
args := m.Called(ctx, roleID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*services.Role), args.Error(1)
}
func (m *MockRBACService) GetAllRoles(ctx context.Context) ([]*services.Role, error) {
args := m.Called(ctx)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).([]*services.Role), args.Error(1)
}
func (m *MockRBACService) AssignRoleToUser(ctx context.Context, userID, roleID uuid.UUID) error {
args := m.Called(ctx, userID, roleID)
return args.Error(0)
}
func (m *MockRBACService) RemoveRoleFromUser(ctx context.Context, userID, roleID uuid.UUID) error {
args := m.Called(ctx, userID, roleID)
return args.Error(0)
}
func (m *MockRBACService) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]*services.Role, error) {
args := m.Called(ctx, userID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).([]*services.Role), args.Error(1)
}
func (m *MockRBACService) GetUserPermissions(ctx context.Context, userID uuid.UUID) ([]services.Permission, error) {
args := m.Called(ctx, userID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).([]services.Permission), args.Error(1)
}
func (m *MockRBACService) CheckPermission(ctx context.Context, userID uuid.UUID, resource, action string) (bool, error) {
args := m.Called(ctx, userID, resource, action)
return args.Bool(0), args.Error(1)
}
func (m *MockRBACService) CreatePermission(ctx context.Context, name, description, resource, action string) (*services.Permission, error) {
args := m.Called(ctx, name, description, resource, action)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(*services.Permission), args.Error(1)
}
// setupTestRBACRouter creates a test router with RBAC handlers
func setupTestRBACRouter(mockService *MockRBACService) *gin.Engine {
gin.SetMode(gin.TestMode)
router := gin.New()
logger := zaptest.NewLogger(&testing.T{})
handler := NewRBACHandlersWithInterface(mockService, logger)
api := router.Group("/api/v1")
{
roles := api.Group("/roles")
{
roles.POST("", handler.CreateRole)
roles.GET("", handler.GetAllRoles)
roles.GET("/:id", handler.GetRole)
}
permissions := api.Group("/permissions")
{
permissions.POST("", handler.CreatePermission)
}
users := api.Group("/users")
{
users.POST("/:user_id/roles", handler.AssignRoleToUser)
users.DELETE("/:user_id/roles/:role_id", handler.RemoveRoleFromUser)
users.GET("/:user_id/roles", handler.GetUserRoles)
users.GET("/:user_id/permissions", handler.GetUserPermissions)
users.GET("/:user_id/permissions/check", handler.CheckPermission)
}
}
return router
}
func TestRBACHandlers_CreateRole_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
roleID := uuid.New()
expectedRole := &services.Role{
ID: roleID,
Name: "test-role",
Description: "Test role description",
Permissions: []services.Permission{},
IsSystem: false,
}
mockService.On("CreateRole", mock.Anything, "test-role", "Test role description", []uuid.UUID{}).Return(expectedRole, nil)
reqBody := map[string]interface{}{
"name": "test-role",
"description": "Test role description",
"permissions": []uuid.UUID{},
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/roles", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_CreateRole_InvalidJSON(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/roles", bytes.NewBuffer([]byte("invalid json")))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRBACHandlers_CreateRole_MissingName(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
reqBody := map[string]interface{}{
"description": "Test role description",
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/roles", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRBACHandlers_GetRole_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
roleID := uuid.New()
expectedRole := &services.Role{
ID: roleID,
Name: "test-role",
Description: "Test role description",
Permissions: []services.Permission{},
IsSystem: false,
}
mockService.On("GetRoleByID", mock.Anything, roleID).Return(expectedRole, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/roles/"+roleID.String(), nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_GetRole_InvalidID(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/roles/invalid-id", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRBACHandlers_GetRole_NotFound(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
roleID := uuid.New()
mockService.On("GetRoleByID", mock.Anything, roleID).Return(nil, assert.AnError)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/roles/"+roleID.String(), nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
mockService.AssertExpectations(t)
}
func TestRBACHandlers_GetAllRoles_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
expectedRoles := []*services.Role{
{
ID: uuid.New(),
Name: "role1",
Description: "Role 1",
Permissions: []services.Permission{},
IsSystem: false,
},
{
ID: uuid.New(),
Name: "role2",
Description: "Role 2",
Permissions: []services.Permission{},
IsSystem: false,
},
}
mockService.On("GetAllRoles", mock.Anything).Return(expectedRoles, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/roles", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_AssignRoleToUser_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
roleID := uuid.New()
mockService.On("AssignRoleToUser", mock.Anything, userID, roleID).Return(nil)
reqBody := map[string]interface{}{
"role_id": roleID.String(),
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/users/"+userID.String()+"/roles", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_AssignRoleToUser_InvalidUserID(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
roleID := uuid.New()
reqBody := map[string]interface{}{
"role_id": roleID.String(),
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/users/invalid-id/roles", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRBACHandlers_RemoveRoleFromUser_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
roleID := uuid.New()
mockService.On("RemoveRoleFromUser", mock.Anything, userID, roleID).Return(nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("DELETE", "/api/v1/users/"+userID.String()+"/roles/"+roleID.String(), nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
}
func TestRBACHandlers_GetUserRoles_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
expectedRoles := []*services.Role{
{
ID: uuid.New(),
Name: "admin",
Description: "Admin role",
Permissions: []services.Permission{},
IsSystem: true,
},
}
mockService.On("GetUserRoles", mock.Anything, userID).Return(expectedRoles, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/users/"+userID.String()+"/roles", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_GetUserPermissions_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
expectedPermissions := []services.Permission{
{
ID: uuid.New(),
Name: "read:tracks",
Description: "Read tracks",
Resource: "tracks",
Action: "read",
},
}
mockService.On("GetUserPermissions", mock.Anything, userID).Return(expectedPermissions, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/users/"+userID.String()+"/permissions", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_CheckPermission_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
mockService.On("CheckPermission", mock.Anything, userID, "tracks", "read").Return(true, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/users/"+userID.String()+"/permissions/check?resource=tracks&action=read", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
assert.True(t, response["has_permission"].(bool))
}
func TestRBACHandlers_CheckPermission_MissingParams(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
userID := uuid.New()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/users/"+userID.String()+"/permissions/check?resource=tracks", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestRBACHandlers_CreatePermission_Success(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
permissionID := uuid.New()
expectedPermission := &services.Permission{
ID: permissionID,
Name: "read:tracks",
Description: "Read tracks",
Resource: "tracks",
Action: "read",
}
mockService.On("CreatePermission", mock.Anything, "read:tracks", "Read tracks", "tracks", "read").Return(expectedPermission, nil)
reqBody := map[string]interface{}{
"name": "read:tracks",
"description": "Read tracks",
"resource": "tracks",
"action": "read",
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/permissions", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
mockService.AssertExpectations(t)
var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.True(t, response["success"].(bool))
}
func TestRBACHandlers_CreatePermission_MissingFields(t *testing.T) {
mockService := new(MockRBACService)
router := setupTestRBACRouter(mockService)
reqBody := map[string]interface{}{
"name": "read:tracks",
// Missing required fields: resource, action
}
body, _ := json.Marshal(reqBody)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/v1/permissions", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}