75f3dd141c
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CI and Release / lint-frontend (push) Has been cancelled
CI and Release / dockerfile-scan (push) Has been cancelled
CI and Release / test-frontend (push) Has been cancelled
CI and Release / lint-verification-agent (push) Has been cancelled
CI and Release / test-verification-agent (push) Has been cancelled
CI and Release / e2e-verification-agent (push) Has been cancelled
CI and Release / test-backend (push) Has been cancelled
CI and Release / build-dev-image (push) Has been cancelled
CI and Release / push-dev-image (push) Has been cancelled
CI and Release / build-image (push) Has been cancelled
CI and Release / build-verification-image (push) Has been cancelled
CI and Release / determine-version (push) Has been cancelled
CI and Release / push-image (push) Has been cancelled
CI and Release / push-verification-image (12) (push) Has been cancelled
CI and Release / lint-backend (push) Has been cancelled
CI and Release / push-verification-image (17) (push) Has been cancelled
CI and Release / push-verification-image (18) (push) Has been cancelled
CI and Release / release (push) Has been cancelled
CI and Release / publish-helm-chart (push) Has been cancelled
CI and Release / push-verification-image (13) (push) Has been cancelled
CI and Release / push-verification-image (14) (push) Has been cancelled
CI and Release / push-verification-image (15) (push) Has been cancelled
CI and Release / push-verification-image (16) (push) Has been cancelled
269 lines
8.6 KiB
Go
269 lines
8.6 KiB
Go
package workspaces_controllers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
|
|
audit_logs "databasus-backend/internal/features/audit_logs"
|
|
users_middleware "databasus-backend/internal/features/users/middleware"
|
|
workspaces_dto "databasus-backend/internal/features/workspaces/dto"
|
|
workspaces_errors "databasus-backend/internal/features/workspaces/errors"
|
|
workspaces_models "databasus-backend/internal/features/workspaces/models"
|
|
workspaces_services "databasus-backend/internal/features/workspaces/services"
|
|
)
|
|
|
|
type WorkspaceController struct {
|
|
workspaceService *workspaces_services.WorkspaceService
|
|
}
|
|
|
|
func (c *WorkspaceController) RegisterRoutes(router *gin.RouterGroup) {
|
|
workspaceRoutes := router.Group("/workspaces")
|
|
|
|
workspaceRoutes.POST("", c.CreateWorkspace)
|
|
workspaceRoutes.GET("", c.GetWorkspaces)
|
|
workspaceRoutes.GET("/:id", c.GetWorkspace)
|
|
workspaceRoutes.PUT("/:id", c.UpdateWorkspace)
|
|
workspaceRoutes.DELETE("/:id", c.DeleteWorkspace)
|
|
workspaceRoutes.GET("/:id/audit-logs", c.GetWorkspaceAuditLogs)
|
|
}
|
|
|
|
// CreateWorkspace
|
|
// @Summary Create a new workspace
|
|
// @Description Create a new workspace with default settings
|
|
// @Tags workspaces
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param request body workspaces_dto.CreateWorkspaceRequestDTO true "Workspace creation data"
|
|
// @Success 200 {object} workspaces_dto.WorkspaceResponseDTO
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 403 {object} map[string]string
|
|
// @Router /workspaces [post]
|
|
func (c *WorkspaceController) CreateWorkspace(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
var request workspaces_dto.CreateWorkspaceRequestDTO
|
|
if err := ctx.ShouldBindJSON(&request); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
|
|
return
|
|
}
|
|
|
|
response, err := c.workspaceService.CreateWorkspace(&request, user)
|
|
if err != nil {
|
|
if errors.Is(err, workspaces_errors.ErrInsufficientPermissionsToCreateWorkspaces) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetWorkspaces
|
|
// @Summary List user's workspaces
|
|
// @Description Get list of workspaces the user is a member of
|
|
// @Tags workspaces
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Success 200 {object} workspaces_dto.ListWorkspacesResponseDTO
|
|
// @Failure 401 {object} map[string]string
|
|
// @Router /workspaces [get]
|
|
func (c *WorkspaceController) GetWorkspaces(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
response, err := c.workspaceService.GetUserWorkspaces(user)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve workspaces"})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetWorkspace
|
|
// @Summary Get workspace details
|
|
// @Description Get detailed information about a specific workspace
|
|
// @Tags workspaces
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Workspace ID"
|
|
// @Success 200 {object} workspaces_models.Workspace
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 403 {object} map[string]string
|
|
// @Router /workspaces/{id} [get]
|
|
func (c *WorkspaceController) GetWorkspace(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
workspaceIDStr := ctx.Param("id")
|
|
workspaceID, err := uuid.Parse(workspaceIDStr)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid workspace ID"})
|
|
return
|
|
}
|
|
|
|
workspace, err := c.workspaceService.GetWorkspace(workspaceID, user)
|
|
if err != nil {
|
|
if errors.Is(err, workspaces_errors.ErrInsufficientPermissionsToViewWorkspace) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, workspace)
|
|
}
|
|
|
|
// UpdateWorkspace
|
|
// @Summary Update workspace settings
|
|
// @Description Update workspace configuration and settings
|
|
// @Tags workspaces
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Workspace ID"
|
|
// @Param request body workspaces_models.Workspace true "Workspace update data"
|
|
// @Success 200 {object} workspaces_models.Workspace
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 403 {object} map[string]string
|
|
// @Router /workspaces/{id} [put]
|
|
func (c *WorkspaceController) UpdateWorkspace(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
workspaceIDStr := ctx.Param("id")
|
|
workspaceID, err := uuid.Parse(workspaceIDStr)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid workspace ID"})
|
|
return
|
|
}
|
|
|
|
var workspace workspaces_models.Workspace
|
|
if err := ctx.ShouldBindJSON(&workspace); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
|
|
return
|
|
}
|
|
|
|
updatedWorkspace, err := c.workspaceService.UpdateWorkspace(workspaceID, &workspace, user)
|
|
if err != nil {
|
|
if errors.Is(err, workspaces_errors.ErrInsufficientPermissionsToUpdateWorkspace) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, updatedWorkspace)
|
|
}
|
|
|
|
// DeleteWorkspace
|
|
// @Summary Delete workspace
|
|
// @Description Delete a workspace (owner only)
|
|
// @Tags workspaces
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Workspace ID"
|
|
// @Success 200 {object} map[string]string
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 403 {object} map[string]string
|
|
// @Router /workspaces/{id} [delete]
|
|
func (c *WorkspaceController) DeleteWorkspace(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
workspaceIDStr := ctx.Param("id")
|
|
workspaceID, err := uuid.Parse(workspaceIDStr)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid workspace ID"})
|
|
return
|
|
}
|
|
|
|
if err := c.workspaceService.DeleteWorkspace(workspaceID, user); err != nil {
|
|
if errors.Is(err, workspaces_errors.ErrOnlyOwnerOrAdminCanDeleteWorkspace) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, gin.H{"message": "Workspace deleted successfully"})
|
|
}
|
|
|
|
// GetWorkspaceAuditLogs
|
|
// @Summary Get workspace audit logs
|
|
// @Description Retrieve audit logs for a specific workspace (member access required)
|
|
// @Tags workspaces
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Workspace ID"
|
|
// @Param limit query int false "Limit number of results" default(100)
|
|
// @Param offset query int false "Offset for pagination" default(0)
|
|
// @Param beforeDate query string false "Filter logs created before this date (RFC3339 format)" format(date-time)
|
|
// @Success 200 {object} audit_logs.GetAuditLogsResponse
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 403 {object} map[string]string
|
|
// @Router /workspaces/{id}/audit-logs [get]
|
|
func (c *WorkspaceController) GetWorkspaceAuditLogs(ctx *gin.Context) {
|
|
user, ok := users_middleware.GetUserFromContext(ctx)
|
|
if !ok {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
workspaceIDStr := ctx.Param("id")
|
|
workspaceID, err := uuid.Parse(workspaceIDStr)
|
|
if err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid workspace ID"})
|
|
return
|
|
}
|
|
|
|
request := &audit_logs.GetAuditLogsRequest{}
|
|
if err := ctx.ShouldBindQuery(request); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
|
|
return
|
|
}
|
|
|
|
response, err := c.workspaceService.GetWorkspaceAuditLogs(workspaceID, user, request)
|
|
if err != nil {
|
|
if errors.Is(err, workspaces_errors.ErrInsufficientPermissionsToViewWorkspaceAuditLogs) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, response)
|
|
}
|