diff --git a/internal/handler/server.go b/internal/handler/server.go new file mode 100644 index 0000000..a39460f --- /dev/null +++ b/internal/handler/server.go @@ -0,0 +1,238 @@ +package handler + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gin-gonic/gin" + "gitm/internal/database" + "gitm/internal/gitea" + "gitm/internal/models" + "gitm/internal/sync" +) + +func HandleListServers(c *gin.Context) { + servers, err := database.GetServers() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, servers) +} + +func HandleCreateServer(c *gin.Context) { + var req struct { + Name string `json:"name" binding:"required"` + URL string `json:"url" binding:"required"` + Token string `json:"token" binding:"required"` + SyncInterval int `json:"sync_interval"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + server := &models.GiteaServer{ + Name: req.Name, + URL: req.URL, + Token: req.Token, + SyncInterval: req.SyncInterval, + Status: "active", + } + if err := database.CreateServer(server); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusCreated, server) +} + +func HandleUpdateServer(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + server, err := database.GetServer(id) + if err != nil || server == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Server not found"}) + return + } + var req struct { + Name *string `json:"name"` + URL *string `json:"url"` + Token *string `json:"token"` + SyncInterval *int `json:"sync_interval"` + Status *string `json:"status"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + if req.Name != nil { + server.Name = *req.Name + } + if req.URL != nil { + server.URL = *req.URL + } + if req.Token != nil { + server.Token = *req.Token + } + if req.SyncInterval != nil { + server.SyncInterval = *req.SyncInterval + } + if req.Status != nil { + server.Status = *req.Status + } + if err := database.UpdateServer(server); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, server) +} + +func HandleDeleteServer(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + if err := database.DeleteServer(id); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "Server deleted"}) +} + +func HandleTestConnection(c *gin.Context) { + var req struct { + URL string `json:"url" binding:"required"` + Token string `json:"token" binding:"required"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + client, err := gitea.NewClient(req.URL, req.Token) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + user, err := client.ValidateToken() + if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"error": "Authentication failed"}) + return + } + c.JSON(http.StatusOK, gin.H{"message": "Connection successful", "user": user.Login}) +} + +func HandleListRepos(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + repos, err := database.GetReposByServer(id) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, repos) +} + +func HandleDiscoverRepos(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + server, err := database.GetServer(id) + if err != nil || server == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "Server not found"}) + return + } + client, err := gitea.NewClient(server.URL, server.Token) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + giteaRepos, err := client.GetAllRepos() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + reposDir, _ := database.GetSetting("repos_dir") + if reposDir == "" { + reposDir = "./data/repos" + } + serverDir := reposDir + "/" + strconv.FormatInt(id, 10) + "_" + server.Name + discovered := 0 + for _, gr := range giteaRepos { + existing, _ := database.GetRepoByFullName(id, gr.FullName) + if existing == nil { + repo := &models.Repo{ + ServerID: id, + Name: gr.Name, + FullName: gr.FullName, + CloneURL: gr.CloneURL, + LocalPath: serverDir + "/" + gr.FullName + ".git", + SyncStatus: "pending", + } + database.CreateRepo(repo) + discovered++ + } + } + c.JSON(http.StatusOK, gin.H{ + "message": fmt.Sprintf("Discovered %d new repositories", discovered), + "total_repos": len(giteaRepos), + "new_repos": discovered, + }) +} + +func HandleSyncServer(engine *sync.Engine) gin.HandlerFunc { + return func(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + if engine.IsSyncing(id) { + c.JSON(http.StatusConflict, gin.H{"error": "Sync already in progress"}) + return + } + go engine.SyncServer(id) + c.JSON(http.StatusAccepted, gin.H{"message": "Sync started", "server_id": id}) + } +} + +func HandleSyncAll(engine *sync.Engine) gin.HandlerFunc { + return func(c *gin.Context) { + servers, err := database.GetServers() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + started := 0 + for _, server := range servers { + if server.Status == "active" && !engine.IsSyncing(server.ID) { + go engine.SyncServer(server.ID) + started++ + } + } + c.JSON(http.StatusAccepted, gin.H{"message": fmt.Sprintf("Started sync for %d servers", started)}) + } +} + +func HandleGetSyncStatus(engine *sync.Engine) gin.HandlerFunc { + return func(c *gin.Context) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server ID"}) + return + } + status := "idle" + if engine.IsSyncing(id) { + status = "syncing" + } + c.JSON(http.StatusOK, gin.H{"server_id": id, "status": status}) + } +}