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:
parent
172581ff02
commit
18eed3c49c
3 changed files with 0 additions and 1142 deletions
|
|
@ -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",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue