mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-06-03 20:12:58 +00:00
small fix, don't worry about it
This commit is contained in:
@@ -1,458 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"containr/internal/database"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Service represents a service in the system
|
||||
type Service struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
ProjectID uuid.UUID `json:"project_id" db:"project_id"`
|
||||
Name string `json:"name" db:"name"`
|
||||
Type string `json:"type" db:"type"` // web, worker, database, etc.
|
||||
Status string `json:"status" db:"status"` // building, running, failed, stopped
|
||||
Image string `json:"image" db:"image"`
|
||||
Command string `json:"command" db:"command"`
|
||||
Environment string `json:"environment" db:"environment"` // production, preview, development
|
||||
GitRepo string `json:"git_repo" db:"git_repo"`
|
||||
GitBranch string `json:"git_branch" db:"git_branch"`
|
||||
BuildPath string `json:"build_path" db:"build_path"`
|
||||
CPU string `json:"cpu" db:"cpu"`
|
||||
Memory string `json:"memory" db:"memory"`
|
||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// CreateServiceRequest represents a request to create a service
|
||||
type CreateServiceRequest struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
Name string `json:"name" binding:"required,min=1,max=255"`
|
||||
Type string `json:"type" binding:"required,oneof=web worker database cron"`
|
||||
Image string `json:"image"`
|
||||
Command string `json:"command"`
|
||||
Environment string `json:"environment" binding:"required,oneof=production preview development"`
|
||||
GitRepo string `json:"git_repo"`
|
||||
GitBranch string `json:"git_branch"`
|
||||
BuildPath string `json:"build_path"`
|
||||
CPU string `json:"cpu"`
|
||||
Memory string `json:"memory"`
|
||||
}
|
||||
|
||||
// UpdateServiceRequest represents a request to update a service
|
||||
type UpdateServiceRequest struct {
|
||||
Name string `json:"name" binding:"omitempty,min=1,max=255"`
|
||||
Type string `json:"type" binding:"omitempty,oneof=web worker database cron"`
|
||||
Image string `json:"image"`
|
||||
Command string `json:"command"`
|
||||
Environment string `json:"environment" binding:"omitempty,oneof=production preview development"`
|
||||
GitRepo string `json:"git_repo"`
|
||||
GitBranch string `json:"git_branch"`
|
||||
BuildPath string `json:"build_path"`
|
||||
CPU string `json:"cpu"`
|
||||
Memory string `json:"memory"`
|
||||
}
|
||||
|
||||
// handleGetServices retrieves all services for a project
|
||||
func handleGetServices(c *gin.Context) {
|
||||
db, exists := c.Get("db")
|
||||
if !exists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection not available"})
|
||||
return
|
||||
}
|
||||
|
||||
projectIDStr := firstPathParam(c, "id", "project_id", "projectId")
|
||||
projectID, err := uuid.Parse(projectIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid project ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if project exists and user has access
|
||||
var project Project
|
||||
err = db.(*database.DB).QueryRow(
|
||||
"SELECT id, name, owner_id FROM projects WHERE id = $1",
|
||||
projectID,
|
||||
).Scan(&project.ID, &project.Name, &project.OwnerID)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Project not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get user ID from JWT token (set by auth middleware)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user owns the project
|
||||
if project.OwnerID != userID.(string) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get services for the project
|
||||
rows, err := db.(*database.DB).Query(
|
||||
`SELECT id, project_id, name, type, status, image, command, environment,
|
||||
git_repo, git_branch, build_path, cpu, memory, created_at, updated_at
|
||||
FROM services
|
||||
WHERE project_id = $1
|
||||
ORDER BY created_at DESC`,
|
||||
projectID,
|
||||
)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve services"})
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var services []Service
|
||||
for rows.Next() {
|
||||
var service Service
|
||||
err := rows.Scan(
|
||||
&service.ID, &service.ProjectID, &service.Name, &service.Type, &service.Status,
|
||||
&service.Image, &service.Command, &service.Environment, &service.GitRepo,
|
||||
&service.GitBranch, &service.BuildPath, &service.CPU, &service.Memory,
|
||||
&service.CreatedAt, &service.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to scan service"})
|
||||
return
|
||||
}
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"services": services})
|
||||
}
|
||||
|
||||
// handleCreateService creates a new service
|
||||
func handleCreateService(c *gin.Context) {
|
||||
db, exists := c.Get("db")
|
||||
if !exists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection not available"})
|
||||
return
|
||||
}
|
||||
|
||||
projectIDStr := firstPathParam(c, "id", "project_id", "projectId")
|
||||
projectID, err := uuid.Parse(projectIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid project ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var req CreateServiceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if req.ProjectID == uuid.Nil {
|
||||
req.ProjectID = projectID
|
||||
} else if req.ProjectID != projectID {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Project ID in URL and request body must match"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get user ID from JWT token
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if project exists and user has access
|
||||
var project Project
|
||||
err = db.(*database.DB).QueryRow(
|
||||
"SELECT id, name, owner_id FROM projects WHERE id = $1",
|
||||
req.ProjectID,
|
||||
).Scan(&project.ID, &project.Name, &project.OwnerID)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Project not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user owns the project
|
||||
if project.OwnerID != userID.(string) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if service name already exists in the project
|
||||
var count int
|
||||
err = db.(*database.DB).QueryRow(
|
||||
"SELECT COUNT(*) FROM services WHERE project_id = $1 AND name = $2",
|
||||
req.ProjectID, req.Name,
|
||||
).Scan(&count)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check service name"})
|
||||
return
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": "Service name already exists in this project"})
|
||||
return
|
||||
}
|
||||
|
||||
// Create new service
|
||||
service := Service{
|
||||
ID: uuid.New(),
|
||||
ProjectID: req.ProjectID,
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
Status: "stopped", // Initial status
|
||||
Image: req.Image,
|
||||
Command: req.Command,
|
||||
Environment: req.Environment,
|
||||
GitRepo: req.GitRepo,
|
||||
GitBranch: req.GitBranch,
|
||||
BuildPath: req.BuildPath,
|
||||
CPU: req.CPU,
|
||||
Memory: req.Memory,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
// Set default values if not provided
|
||||
if service.CPU == "" {
|
||||
service.CPU = "0.5"
|
||||
}
|
||||
if service.Memory == "" {
|
||||
service.Memory = "512Mi"
|
||||
}
|
||||
|
||||
// Insert service into database
|
||||
_, err = db.(*database.DB).Exec(
|
||||
`INSERT INTO services
|
||||
(id, project_id, name, type, status, image, command, environment,
|
||||
git_repo, git_branch, build_path, cpu, memory, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)`,
|
||||
service.ID, service.ProjectID, service.Name, service.Type, service.Status,
|
||||
service.Image, service.Command, service.Environment, service.GitRepo,
|
||||
service.GitBranch, service.BuildPath, service.CPU, service.Memory,
|
||||
service.CreatedAt, service.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create service"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"service": service})
|
||||
}
|
||||
|
||||
// handleGetService retrieves a specific service
|
||||
func handleGetService(c *gin.Context) {
|
||||
db, exists := c.Get("db")
|
||||
if !exists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection not available"})
|
||||
return
|
||||
}
|
||||
|
||||
serviceIDStr := c.Param("id")
|
||||
serviceID, err := uuid.Parse(serviceIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid service ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get user ID from JWT token
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get service with project ownership check
|
||||
var service Service
|
||||
err = db.(*database.DB).QueryRow(
|
||||
`SELECT s.id, s.project_id, s.name, s.type, s.status, s.image, s.command,
|
||||
s.environment, s.git_repo, s.git_branch, s.build_path, s.cpu, s.memory,
|
||||
s.created_at, s.updated_at
|
||||
FROM services s
|
||||
JOIN projects p ON s.project_id = p.id
|
||||
WHERE s.id = $1 AND p.owner_id = $2`,
|
||||
serviceID, userID,
|
||||
).Scan(
|
||||
&service.ID, &service.ProjectID, &service.Name, &service.Type, &service.Status,
|
||||
&service.Image, &service.Command, &service.Environment, &service.GitRepo,
|
||||
&service.GitBranch, &service.BuildPath, &service.CPU, &service.Memory,
|
||||
&service.CreatedAt, &service.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"service": service})
|
||||
}
|
||||
|
||||
// handleUpdateService updates a service
|
||||
func handleUpdateService(c *gin.Context) {
|
||||
db, exists := c.Get("db")
|
||||
if !exists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection not available"})
|
||||
return
|
||||
}
|
||||
|
||||
serviceIDStr := c.Param("id")
|
||||
serviceID, err := uuid.Parse(serviceIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid service ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var req UpdateServiceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Get user ID from JWT token
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if service exists and user has access
|
||||
var existingService Service
|
||||
err = db.(*database.DB).QueryRow(
|
||||
`SELECT s.id, s.project_id, s.name, s.type, s.status, s.image, s.command,
|
||||
s.environment, s.git_repo, s.git_branch, s.build_path, s.cpu, s.memory,
|
||||
s.created_at, s.updated_at
|
||||
FROM services s
|
||||
JOIN projects p ON s.project_id = p.id
|
||||
WHERE s.id = $1 AND p.owner_id = $2`,
|
||||
serviceID, userID,
|
||||
).Scan(
|
||||
&existingService.ID, &existingService.ProjectID, &existingService.Name, &existingService.Type,
|
||||
&existingService.Status, &existingService.Image, &existingService.Command,
|
||||
&existingService.Environment, &existingService.GitRepo, &existingService.GitBranch,
|
||||
&existingService.BuildPath, &existingService.CPU, &existingService.Memory,
|
||||
&existingService.CreatedAt, &existingService.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Update fields if provided
|
||||
if req.Name != "" {
|
||||
existingService.Name = req.Name
|
||||
}
|
||||
if req.Type != "" {
|
||||
existingService.Type = req.Type
|
||||
}
|
||||
if req.Image != "" {
|
||||
existingService.Image = req.Image
|
||||
}
|
||||
if req.Command != "" {
|
||||
existingService.Command = req.Command
|
||||
}
|
||||
if req.Environment != "" {
|
||||
existingService.Environment = req.Environment
|
||||
}
|
||||
if req.GitRepo != "" {
|
||||
existingService.GitRepo = req.GitRepo
|
||||
}
|
||||
if req.GitBranch != "" {
|
||||
existingService.GitBranch = req.GitBranch
|
||||
}
|
||||
if req.BuildPath != "" {
|
||||
existingService.BuildPath = req.BuildPath
|
||||
}
|
||||
if req.CPU != "" {
|
||||
existingService.CPU = req.CPU
|
||||
}
|
||||
if req.Memory != "" {
|
||||
existingService.Memory = req.Memory
|
||||
}
|
||||
|
||||
existingService.UpdatedAt = time.Now()
|
||||
|
||||
// Update service in database
|
||||
_, err = db.(*database.DB).Exec(
|
||||
`UPDATE services
|
||||
SET name = $1, type = $2, image = $3, command = $4, environment = $5,
|
||||
git_repo = $6, git_branch = $7, build_path = $8, cpu = $9, memory = $10, updated_at = $11
|
||||
WHERE id = $12`,
|
||||
existingService.Name, existingService.Type, existingService.Image, existingService.Command,
|
||||
existingService.Environment, existingService.GitRepo, existingService.GitBranch,
|
||||
existingService.BuildPath, existingService.CPU, existingService.Memory,
|
||||
existingService.UpdatedAt, existingService.ID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update service"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"service": existingService})
|
||||
}
|
||||
|
||||
// handleDeleteService deletes a service
|
||||
func handleDeleteService(c *gin.Context) {
|
||||
db, exists := c.Get("db")
|
||||
if !exists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database connection not available"})
|
||||
return
|
||||
}
|
||||
|
||||
serviceIDStr := c.Param("id")
|
||||
serviceID, err := uuid.Parse(serviceIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid service ID"})
|
||||
return
|
||||
}
|
||||
|
||||
// Get user ID from JWT token
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if service exists and user has access
|
||||
var projectOwnerID string
|
||||
err = db.(*database.DB).QueryRow(
|
||||
`SELECT p.owner_id
|
||||
FROM services s
|
||||
JOIN projects p ON s.project_id = p.id
|
||||
WHERE s.id = $1`,
|
||||
serviceID,
|
||||
).Scan(&projectOwnerID)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Service not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user owns the project
|
||||
if projectOwnerID != userID.(string) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete service (cascade will handle related records)
|
||||
_, err = db.(*database.DB).Exec(
|
||||
"DELETE FROM services WHERE id = $1",
|
||||
serviceID,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete service"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Service deleted successfully"})
|
||||
}
|
||||
Reference in New Issue
Block a user