small fix, don't worry about it

This commit is contained in:
Tomas Dvorak
2026-04-10 12:02:36 +02:00
parent 08bd0c6e5c
commit 08cb5754f3
638 changed files with 57332 additions and 34706 deletions
-458
View File
@@ -1,458 +0,0 @@
package api
import (
"containr/internal/database"
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// GitProvider represents a Git provider (GitHub, GitLab, Bitbucket)
type GitProvider struct {
ID string `json:"id" db:"id"`
Name string `json:"name" db:"name"` // github, gitlab, bitbucket
DisplayName string `json:"display_name" db:"display_name"`
APIUrl string `json:"api_url" db:"api_url"`
WebhookUrl string `json:"webhook_url" db:"webhook_url"`
UserID string `json:"user_id" db:"user_id"`
AccessToken string `json:"-" db:"access_token"` // Hidden in JSON responses
CreatedAt string `json:"created_at" db:"created_at"`
UpdatedAt string `json:"updated_at" db:"updated_at"`
}
// GitRepository represents a connected Git repository
type GitRepository struct {
ID string `json:"id" db:"id"`
ProviderID string `json:"provider_id" db:"provider_id"`
Name string `json:"name" db:"name"`
FullName string `json:"full_name" db:"full_name"`
Description string `json:"description" db:"description"`
CloneURL string `json:"clone_url" db:"clone_url"`
WebhookURL string `json:"webhook_url" db:"webhook_url"`
DefaultBranch string `json:"default_branch" db:"default_branch"`
IsPrivate bool `json:"is_private" db:"is_private"`
UserID string `json:"user_id" db:"user_id"`
CreatedAt string `json:"created_at" db:"created_at"`
UpdatedAt string `json:"updated_at" db:"updated_at"`
}
// GitWebhook represents a webhook configuration
type GitWebhook struct {
ID string `json:"id" db:"id"`
RepoID string `json:"repo_id" db:"repo_id"`
ProviderID string `json:"provider_id" db:"provider_id"`
Events string `json:"events" db:"events"` // JSON array of events
Secret string `json:"-" db:"webhook_secret"` // Hidden in JSON responses
Active bool `json:"active" db:"active"`
CreatedAt string `json:"created_at" db:"created_at"`
UpdatedAt string `json:"updated_at" db:"updated_at"`
}
// CreateGitProviderRequest represents a request to create a Git provider
type CreateGitProviderRequest struct {
Name string `json:"name" binding:"required,oneof=github gitlab bitbucket"`
DisplayName string `json:"display_name" binding:"required"`
AccessToken string `json:"access_token" binding:"required"`
}
// CreateGitRepoRequest represents a request to connect a Git repository
type CreateGitRepoRequest struct {
ProviderID string `json:"provider_id" binding:"required"`
RepoFullName string `json:"repo_full_name" binding:"required"`
}
// CreateWebhookRequest represents a request to create a webhook
type CreateWebhookRequest struct {
RepoID string `json:"repo_id" binding:"required"`
Events []string `json:"events" binding:"required"`
Branch string `json:"branch"`
}
func handleGetGitProviders(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
rows, err := db.Query(`
SELECT id, name, display_name, api_url, webhook_url, user_id, created_at, updated_at
FROM git_providers
WHERE user_id = $1
ORDER BY created_at DESC
`, userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
defer rows.Close()
var providers []GitProvider
for rows.Next() {
var provider GitProvider
if err := rows.Scan(&provider.ID, &provider.Name, &provider.DisplayName, &provider.APIUrl,
&provider.WebhookUrl, &provider.UserID, &provider.CreatedAt, &provider.UpdatedAt); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
providers = append(providers, provider)
}
c.JSON(http.StatusOK, gin.H{"providers": providers})
}
func handleCreateGitProvider(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
var req CreateGitProviderRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate the access token by making a test API call
if !validateGitToken(req.Name, req.AccessToken) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid access token for " + req.Name})
return
}
provider := GitProvider{
ID: uuid.New().String(),
Name: req.Name,
DisplayName: req.DisplayName,
AccessToken: req.AccessToken,
UserID: userID,
}
// Set provider-specific URLs
switch req.Name {
case "github":
provider.APIUrl = "https://api.github.com"
provider.WebhookUrl = "https://api.github.com"
case "gitlab":
provider.APIUrl = "https://gitlab.com/api/v4"
provider.WebhookUrl = "https://gitlab.com"
case "bitbucket":
provider.APIUrl = "https://api.bitbucket.org/2.0"
provider.WebhookUrl = "https://api.bitbucket.org/2.0"
}
_, err := db.Exec(`
INSERT INTO git_providers (id, name, display_name, api_url, webhook_url, access_token, user_id, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW())
`, provider.ID, provider.Name, provider.DisplayName, provider.APIUrl,
provider.WebhookUrl, provider.AccessToken, provider.UserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create Git provider"})
return
}
// Return provider without access token
provider.AccessToken = ""
c.JSON(http.StatusCreated, provider)
}
func handleGetGitRepositories(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
providerID := c.Param("providerId")
// Validate UUID
if _, err := uuid.Parse(providerID); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid provider ID"})
return
}
// Get provider info
var provider GitProvider
err := db.QueryRow(`
SELECT id, name, access_token, api_url
FROM git_providers
WHERE id = $1 AND user_id = $2
`, providerID, userID).Scan(&provider.ID, &provider.Name, &provider.AccessToken, &provider.APIUrl)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Git provider not found"})
return
}
// Fetch repositories from the Git provider
repos, err := fetchGitRepositories(provider.Name, provider.AccessToken, provider.APIUrl)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch repositories"})
return
}
c.JSON(http.StatusOK, gin.H{"repositories": repos})
}
func handleConnectGitRepository(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
var req CreateGitRepoRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate UUID
if _, err := uuid.Parse(req.ProviderID); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid provider ID"})
return
}
// Get provider info
var provider GitProvider
err := db.QueryRow(`
SELECT id, name, access_token, api_url
FROM git_providers
WHERE id = $1 AND user_id = $2
`, req.ProviderID, userID).Scan(&provider.ID, &provider.Name, &provider.AccessToken, &provider.APIUrl)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Git provider not found"})
return
}
// Fetch repository details from Git provider
repoDetails, err := fetchGitRepositoryDetails(provider.Name, req.RepoFullName, provider.AccessToken, provider.APIUrl)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch repository details"})
return
}
// Check if repository is already connected
var existingID string
err = db.QueryRow(`
SELECT id FROM git_repositories
WHERE provider_id = $1 AND full_name = $2
`, req.ProviderID, req.RepoFullName).Scan(&existingID)
if err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "Repository already connected", "repository_id": existingID})
return
}
// Create repository record
repo := GitRepository{
ID: uuid.New().String(),
ProviderID: req.ProviderID,
Name: repoDetails["name"].(string),
FullName: req.RepoFullName,
Description: repoDetails["description"].(string),
CloneURL: repoDetails["clone_url"].(string),
DefaultBranch: repoDetails["default_branch"].(string),
IsPrivate: repoDetails["private"].(bool),
UserID: userID,
}
_, err = db.Exec(`
INSERT INTO git_repositories (id, provider_id, name, full_name, description, clone_url,
default_branch, is_private, user_id, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW())
`, repo.ID, repo.ProviderID, repo.Name, repo.FullName, repo.Description,
repo.CloneURL, repo.DefaultBranch, repo.IsPrivate, repo.UserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to connect repository"})
return
}
c.JSON(http.StatusCreated, repo)
}
func handleCreateWebhook(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
var req CreateWebhookRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate UUIDs
if _, err := uuid.Parse(req.RepoID); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid repository ID"})
return
}
// Get repository and provider info
var repo GitRepository
var provider GitProvider
err := db.QueryRow(`
SELECT r.id, r.provider_id, r.full_name, r.user_id,
p.id, p.name, p.access_token, p.webhook_url
FROM git_repositories r
JOIN git_providers p ON r.provider_id = p.id
WHERE r.id = $1 AND r.user_id = $2
`, req.RepoID, userID).Scan(&repo.ID, &repo.ProviderID, &repo.FullName, &repo.UserID,
&provider.ID, &provider.Name, &provider.AccessToken, &provider.WebhookUrl)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Repository not found"})
return
}
// Convert events to JSON
eventsJSON, _ := json.Marshal(req.Events)
webhookSecret := generateWebhookSecret()
// Create webhook on Git provider
webhookURL := fmt.Sprintf("%s/api/v1/webhooks/git/%s", "https://your-domain.com", req.RepoID)
remoteWebhookID, err := createGitWebhook(provider.Name, repo.FullName, provider.AccessToken,
provider.WebhookUrl, webhookURL, req.Events, webhookSecret)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create webhook on Git provider"})
return
}
// Create webhook record
webhook := GitWebhook{
ID: uuid.New().String(),
RepoID: req.RepoID,
ProviderID: provider.ID,
Events: string(eventsJSON),
Secret: webhookSecret,
Active: true,
}
_, err = db.Exec(`
INSERT INTO git_webhooks (id, repo_id, provider_id, events, webhook_secret, active, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
`, webhook.ID, webhook.RepoID, webhook.ProviderID, webhook.Events, webhook.Secret, webhook.Active)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create webhook"})
return
}
c.JSON(http.StatusCreated, gin.H{
"webhook": webhook,
"remote_webhook_id": remoteWebhookID,
})
}
func handleGetConnectedRepositories(c *gin.Context) {
userID := c.MustGet("user_id").(string)
db := c.MustGet("db").(*database.DB)
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
offset := (page - 1) * limit
rows, err := db.Query(`
SELECT r.id, r.provider_id, r.name, r.full_name, r.description, r.clone_url,
r.default_branch, r.is_private, r.user_id, r.created_at, r.updated_at,
p.name as provider_name, p.display_name
FROM git_repositories r
JOIN git_providers p ON r.provider_id = p.id
WHERE r.user_id = $1
ORDER BY r.updated_at DESC
LIMIT $2 OFFSET $3
`, userID, limit, offset)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
defer rows.Close()
var repositories []map[string]interface{}
for rows.Next() {
var repo GitRepository
var providerName, providerDisplayName string
if err := rows.Scan(&repo.ID, &repo.ProviderID, &repo.Name, &repo.FullName, &repo.Description,
&repo.CloneURL, &repo.DefaultBranch, &repo.IsPrivate, &repo.UserID, &repo.CreatedAt, &repo.UpdatedAt,
&providerName, &providerDisplayName); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
repositories = append(repositories, map[string]interface{}{
"id": repo.ID,
"provider_id": repo.ProviderID,
"name": repo.Name,
"full_name": repo.FullName,
"description": repo.Description,
"clone_url": repo.CloneURL,
"default_branch": repo.DefaultBranch,
"is_private": repo.IsPrivate,
"created_at": repo.CreatedAt,
"updated_at": repo.UpdatedAt,
"provider": map[string]string{
"name": providerName,
"display_name": providerDisplayName,
},
})
}
// Get total count
var total int
err = db.QueryRow(`
SELECT COUNT(*) FROM git_repositories WHERE user_id = $1
`, userID).Scan(&total)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"})
return
}
c.JSON(http.StatusOK, gin.H{
"repositories": repositories,
"pagination": gin.H{
"page": page,
"limit": limit,
"total": total,
},
})
}
// Helper functions (these would need to be implemented with actual Git provider API calls)
func validateGitToken(provider, token string) bool {
// TODO: Implement actual validation with Git provider APIs
// For now, just check if token is not empty
return token != ""
}
func fetchGitRepositories(provider, token, apiUrl string) ([]map[string]interface{}, error) {
// TODO: Implement actual API calls to fetch repositories
// For now, return mock data
return []map[string]interface{}{
{
"name": "example-repo",
"full_name": "user/example-repo",
"description": "An example repository",
"clone_url": "https://github.com/user/example-repo.git",
"default_branch": "main",
"private": false,
},
}, nil
}
func fetchGitRepositoryDetails(provider, repoFullName, token, apiUrl string) (map[string]interface{}, error) {
// TODO: Implement actual API call to fetch repository details
return map[string]interface{}{
"name": "example-repo",
"description": "An example repository",
"clone_url": "https://github.com/user/example-repo.git",
"default_branch": "main",
"private": false,
}, nil
}
func createGitWebhook(provider, repoFullName, token, webhookUrl, apiUrl string, events []string, secret string) (string, error) {
// TODO: Implement actual webhook creation
return uuid.New().String(), nil
}
func generateWebhookSecret() string {
// TODO: Generate a proper secret
return "webhook-secret-" + uuid.New().String()
}