Add gitservers to backend
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log"
|
||||
"quay/app/models"
|
||||
"quay/app/repository"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
type GitServerHandler struct {
|
||||
Repo repository.GitServerRepository
|
||||
}
|
||||
|
||||
func NewGitServerHandler(repo repository.GitServerRepository) *GitServerHandler {
|
||||
return &GitServerHandler{Repo: repo}
|
||||
}
|
||||
|
||||
func (h *GitServerHandler) GetGitServers(c fiber.Ctx) error {
|
||||
gs, err := h.Repo.ListGitServers()
|
||||
if err != nil {
|
||||
log.Println("Error listing gitservers: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while listing git servers"})
|
||||
}
|
||||
if gs == nil {
|
||||
gs = []models.GitServer{}
|
||||
}
|
||||
return c.JSON(gs)
|
||||
}
|
||||
|
||||
func (h *GitServerHandler) GetGitServer(c fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
g, err := h.Repo.GetGitServer(id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&models.APIError{Message: "Git server not found"})
|
||||
}
|
||||
log.Println("Error getting gitserver: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while getting git server"})
|
||||
}
|
||||
if g == nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&models.APIError{Message: "Git server not found"})
|
||||
}
|
||||
return c.JSON(g)
|
||||
}
|
||||
|
||||
func validateIncomingGitServer(gs *models.GitServer) error {
|
||||
return models.ValidateGitServer(gs)
|
||||
}
|
||||
|
||||
func (h *GitServerHandler) PostGitServer(c fiber.Ctx) error {
|
||||
var gs models.GitServer
|
||||
if err := c.Bind().Body(&gs); err != nil {
|
||||
log.Println("Error parsing body: ", err)
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&models.APIError{Message: "Invalid request body"})
|
||||
}
|
||||
|
||||
if err := validateIncomingGitServer(&gs); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&models.APIError{Message: "Invalid request body: " + err.Error()})
|
||||
}
|
||||
|
||||
if err := h.Repo.CreateGitServer(&gs); err != nil {
|
||||
log.Println("Error creating gitserver: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while creating git server"})
|
||||
}
|
||||
|
||||
return c.JSON(gs)
|
||||
}
|
||||
|
||||
func (h *GitServerHandler) PutGitServer(c fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
if _, err := h.Repo.GetGitServer(id); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&models.APIError{Message: "Git server not found"})
|
||||
}
|
||||
log.Println("Error checking gitserver before update: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while updating git server"})
|
||||
}
|
||||
|
||||
var gs models.GitServer
|
||||
if err := c.Bind().Body(&gs); err != nil {
|
||||
log.Println("Error parsing body: ", err)
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&models.APIError{Message: "Invalid request body"})
|
||||
}
|
||||
|
||||
if err := validateIncomingGitServer(&gs); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(&models.APIError{Message: "Invalid request body: " + err.Error()})
|
||||
}
|
||||
|
||||
gs.ID = id
|
||||
if err := h.Repo.UpdateGitServer(&gs); err != nil {
|
||||
log.Println("Error updating gitserver: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while updating git server"})
|
||||
}
|
||||
|
||||
updated, err := h.Repo.GetGitServer(id)
|
||||
if err != nil {
|
||||
log.Println("Error getting updated gitserver: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Git server was updated but could not be retrieved"})
|
||||
}
|
||||
|
||||
return c.JSON(updated)
|
||||
}
|
||||
|
||||
func (h *GitServerHandler) DeleteGitServer(c fiber.Ctx) error {
|
||||
id := c.Params("id")
|
||||
if _, err := h.Repo.GetGitServer(id); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(&models.APIError{Message: "Git server not found"})
|
||||
}
|
||||
log.Println("Error checking gitserver before delete: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while deleting git server"})
|
||||
}
|
||||
|
||||
if err := h.Repo.DeleteGitServer(id); err != nil {
|
||||
log.Println("Error deleting gitserver: ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(&models.APIError{Message: "Unexpected error while deleting git server"})
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package models
|
||||
|
||||
import "errors"
|
||||
|
||||
type GitServer struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Protocol string `json:"protocol"`
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
Type string `json:"type"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
func ValidateGitServer(gs *GitServer) error {
|
||||
if gs.Name == "" {
|
||||
return errors.New("name is required")
|
||||
}
|
||||
if gs.Protocol == "" {
|
||||
return errors.New("protocol is required")
|
||||
}
|
||||
if gs.Protocol != "http" && gs.Protocol != "https" {
|
||||
return errors.New("protocol must be either 'http' or 'https'")
|
||||
}
|
||||
if gs.BaseUrl == "" {
|
||||
return errors.New("baseUrl is required")
|
||||
}
|
||||
if gs.Type == "" {
|
||||
return errors.New("type is required")
|
||||
}
|
||||
if gs.Type != "github" && gs.Type != "gitlab" && gs.Type != "gitea" {
|
||||
return errors.New("type must be either 'github', 'gitlab' or 'gitea'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"quay/app/models"
|
||||
)
|
||||
|
||||
var ErrGitServerAlreadyExists = errors.New("gitserver already exists")
|
||||
|
||||
type GitServerRepository interface {
|
||||
ListGitServers() ([]models.GitServer, error)
|
||||
GetGitServer(id string) (*models.GitServer, error)
|
||||
CreateGitServer(gs *models.GitServer) error
|
||||
UpdateGitServer(gs *models.GitServer) error
|
||||
DeleteGitServer(id string) error
|
||||
}
|
||||
@@ -19,10 +19,27 @@ func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, d
|
||||
siteRepository := cachedrepo.NewCachedSiteRepository(database.NewSQLiteSiteRepository(db))
|
||||
deploymentRepository := database.NewSQLiteDeploymentRepository(db)
|
||||
userRepository := database.NewSQLiteUserRepository(db)
|
||||
gitServerRepository := database.NewSQLiteGitServerRepository(db)
|
||||
|
||||
// Seed default git servers if none exist
|
||||
if gsList, err := gitServerRepository.ListGitServers(); err != nil {
|
||||
log.Printf("Warning checking gitservers: %v", err)
|
||||
} else if len(gsList) == 0 {
|
||||
defaults := []models.GitServer{
|
||||
{Name: "GitHub", Protocol: "https", BaseUrl: "github.com", Type: "github"},
|
||||
{Name: "GitLab", Protocol: "https", BaseUrl: "gitlab.com", Type: "gitlab"},
|
||||
}
|
||||
for _, d := range defaults {
|
||||
if err := gitServerRepository.CreateGitServer(&d); err != nil {
|
||||
log.Printf("Warning creating default gitserver %s: %v", d.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
siteHandler := handlers.NewSiteHandler(siteRepository)
|
||||
deploySiteHandler := handlers.NewDeploySiteHandler(envCfg, siteRepository, deploymentRepository)
|
||||
userHandler := handlers.NewUserHandler(userRepository)
|
||||
gitServerHandler := handlers.NewGitServerHandler(gitServerRepository)
|
||||
deploymentsHandler := handlers.NewDeploymentHandler(deploymentRepository)
|
||||
|
||||
api := app.Group("/api/v1", middleware.APIHostGuard(envCfg.DashboardHost))
|
||||
@@ -46,6 +63,13 @@ func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, d
|
||||
protected.Delete("/sites/:id", siteHandler.DeleteSite)
|
||||
protected.Patch("/sites/:id/enabled", siteHandler.ToggleEnabled)
|
||||
|
||||
// Git servers
|
||||
protected.Get("/gitservers", gitServerHandler.GetGitServers)
|
||||
protected.Get("/gitservers/:id", gitServerHandler.GetGitServer)
|
||||
protected.Post("/gitservers", gitServerHandler.PostGitServer)
|
||||
protected.Put("/gitservers/:id", gitServerHandler.PutGitServer)
|
||||
protected.Delete("/gitservers/:id", gitServerHandler.DeleteGitServer)
|
||||
|
||||
// Forward rules
|
||||
protected.Get("/sites/:id/forward-rules", siteHandler.GetSiteForwardRules)
|
||||
protected.Post("/sites/:id/forward-rules", siteHandler.PostForwardRule)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"quay/app/models"
|
||||
"quay/app/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type SQLiteGitServerRepository struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewSQLiteGitServerRepository(db *sql.DB) *SQLiteGitServerRepository {
|
||||
return &SQLiteGitServerRepository{db: db}
|
||||
}
|
||||
|
||||
var _ repository.GitServerRepository = (*SQLiteGitServerRepository)(nil)
|
||||
|
||||
func (r *SQLiteGitServerRepository) ListGitServers() ([]models.GitServer, error) {
|
||||
rows, err := r.db.Query(`SELECT id, name, protocol, base_url, type, created_at FROM gitservers`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list gitservers: %w", err)
|
||||
}
|
||||
|
||||
var out []models.GitServer
|
||||
for rows.Next() {
|
||||
gs, err := scanGitServer(rows)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return nil, fmt.Errorf("list gitservers scan: %w", err)
|
||||
}
|
||||
out = append(out, *gs)
|
||||
}
|
||||
rows.Close()
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *SQLiteGitServerRepository) GetGitServer(id string) (*models.GitServer, error) {
|
||||
row := r.db.QueryRow(`SELECT id, name, protocol, base_url, type, created_at FROM gitservers WHERE id = ?`, id)
|
||||
return scanGitServer(row)
|
||||
}
|
||||
|
||||
func (r *SQLiteGitServerRepository) CreateGitServer(gs *models.GitServer) error {
|
||||
tx, err := r.db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("create gitserver begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
gs.ID = uuid.NewString()
|
||||
|
||||
_, err = tx.Exec(`INSERT INTO gitservers (id, name, protocol, base_url, type) VALUES (?, ?, ?, ?, ?)`,
|
||||
gs.ID, gs.Name, gs.Protocol, gs.BaseUrl, gs.Type)
|
||||
if err != nil {
|
||||
if isSQLiteUniqueConstraintError(err) {
|
||||
return fmt.Errorf("create gitserver insert: %w", repository.ErrGitServerAlreadyExists)
|
||||
}
|
||||
return fmt.Errorf("create gitserver insert: %w", err)
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (r *SQLiteGitServerRepository) UpdateGitServer(gs *models.GitServer) error {
|
||||
tx, err := r.db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("update gitserver begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
_, err = tx.Exec(`UPDATE gitservers SET name = ?, protocol = ?, base_url = ?, type = ? WHERE id = ?`,
|
||||
gs.Name, gs.Protocol, gs.BaseUrl, gs.Type, gs.ID)
|
||||
if err != nil {
|
||||
if isSQLiteUniqueConstraintError(err) {
|
||||
return fmt.Errorf("update gitserver: %w", repository.ErrGitServerAlreadyExists)
|
||||
}
|
||||
return fmt.Errorf("update gitserver: %w", err)
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (r *SQLiteGitServerRepository) DeleteGitServer(id string) error {
|
||||
_, err := r.db.Exec(`DELETE FROM gitservers WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete gitserver: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanGitServer(s scanner) (*models.GitServer, error) {
|
||||
g := new(models.GitServer)
|
||||
err := s.Scan(&g.ID, &g.Name, &g.Protocol, &g.BaseUrl, &g.Type, &g.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
@@ -68,6 +68,16 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
hashed_password TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gitservers (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
protocol TEXT NOT NULL,
|
||||
base_url TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`)
|
||||
|
||||
if err == nil {
|
||||
|
||||
Reference in New Issue
Block a user