package handlers import ( "encoding/json" "net/http" "strconv" "github.com/go-chi/chi/v5" "github.com/hanxuanyu/gitcodestatic/internal/logger" "github.com/hanxuanyu/gitcodestatic/internal/service" ) // RepoHandler 仓库API处理器 type RepoHandler struct { repoService *service.RepoService } // NewRepoHandler 创建仓库处理器 func NewRepoHandler(repoService *service.RepoService) *RepoHandler { return &RepoHandler{ repoService: repoService, } } // AddBatch 批量添加仓库 // @Summary 批量添加仓库 // @Description 批量添加多个Git仓库,异步克隆到本地 // @Tags 仓库管理 // @Accept json // @Produce json // @Param request body service.AddReposRequest true "仓库URL列表" // @Success 200 {object} Response{data=service.AddReposResponse} // @Failure 400 {object} Response // @Router /repos/batch [post] func (h *RepoHandler) AddBatch(w http.ResponseWriter, r *http.Request) { var req service.AddReposRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid request body") return } if len(req.Repos) == 0 { respondError(w, http.StatusBadRequest, 40001, "repos cannot be empty") return } resp, err := h.repoService.AddRepos(r.Context(), &req) if err != nil { logger.Logger.Error().Err(err).Msg("failed to add repositories") respondError(w, http.StatusInternalServerError, 50000, "failed to add repositories") return } respondJSON(w, http.StatusOK, 0, "success", resp) } // List 获取仓库列表 // @Summary 获取仓库列表 // @Description 分页查询仓库列表,支持按状态筛选 // @Tags 仓库管理 // @Accept json // @Produce json // @Param status query string false "状态筛选(pending/cloning/ready/failed)" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(20) // @Success 200 {object} Response // @Router /repos [get] func (h *RepoHandler) List(w http.ResponseWriter, r *http.Request) { status := r.URL.Query().Get("status") page, _ := strconv.Atoi(r.URL.Query().Get("page")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) if page <= 0 { page = 1 } if pageSize <= 0 || pageSize > 100 { pageSize = 20 } repos, total, err := h.repoService.ListRepos(r.Context(), status, page, pageSize) if err != nil { logger.Logger.Error().Err(err).Msg("failed to list repositories") respondError(w, http.StatusInternalServerError, 50000, "failed to list repositories") return } data := map[string]interface{}{ "total": total, "page": page, "page_size": pageSize, "repositories": repos, } respondJSON(w, http.StatusOK, 0, "success", data) } // Get 获取仓库详情 // @Summary 获取仓库详情 // @Description 根据ID获取仓库详细信息 // @Tags 仓库管理 // @Accept json // @Produce json // @Param id path int true "仓库ID" // @Success 200 {object} Response{data=models.Repository} // @Failure 404 {object} Response // @Router /repos/{id} [get] func (h *RepoHandler) Get(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } repo, err := h.repoService.GetRepo(r.Context(), id) if err != nil { respondError(w, http.StatusNotFound, 40400, "repository not found") return } respondJSON(w, http.StatusOK, 0, "success", repo) } // SwitchBranch 切换分支 // @Summary 切换仓库分支 // @Description 异步切换仓库到指定分支 // @Tags 仓库管理 // @Accept json // @Produce json // @Param id path int true "仓库ID" // @Param request body object{branch=string} true "分支名称" // @Success 200 {object} Response{data=models.Task} // @Failure 400 {object} Response // @Router /repos/{id}/switch-branch [post] func (h *RepoHandler) SwitchBranch(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } var req struct { Branch string `json:"branch"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid request body") return } if req.Branch == "" { respondError(w, http.StatusBadRequest, 40001, "branch cannot be empty") return } task, err := h.repoService.SwitchBranch(r.Context(), id, req.Branch) if err != nil { logger.Logger.Error().Err(err).Int64("repo_id", id).Msg("failed to switch branch") respondError(w, http.StatusInternalServerError, 50000, err.Error()) return } respondJSON(w, http.StatusOK, 0, "branch switch task submitted", task) } // Update 更新仓库 // @Summary 更新仓库 // @Description 异步拉取仓库最新代码(git pull) // @Tags 仓库管理 // @Accept json // @Produce json // @Param id path int true "仓库ID" // @Success 200 {object} Response{data=models.Task} // @Failure 400 {object} Response // @Router /repos/{id}/update [post] func (h *RepoHandler) Update(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } task, err := h.repoService.UpdateRepo(r.Context(), id) if err != nil { logger.Logger.Error().Err(err).Int64("repo_id", id).Msg("failed to update repository") respondError(w, http.StatusInternalServerError, 50000, err.Error()) return } respondJSON(w, http.StatusOK, 0, "update task submitted", task) } // Reset 重置仓库 // @Summary 重置仓库 // @Description 异步重置仓库到最新状态 // @Tags 仓库管理 // @Produce json // @Param id path int true "仓库ID" // @Success 200 {object} Response{data=models.Task} // @Failure 400 {object} Response // @Router /repos/{id}/reset [post] func (h *RepoHandler) Reset(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } task, err := h.repoService.ResetRepo(r.Context(), id) if err != nil { logger.Logger.Error().Err(err).Int64("repo_id", id).Msg("failed to reset repository") respondError(w, http.StatusInternalServerError, 50000, err.Error()) return } respondJSON(w, http.StatusOK, 0, "reset task submitted", task) } // Delete 删除仓库 // @Summary 删除仓库 // @Description 删除指定仓库 // @Tags 仓库管理 // @Produce json // @Param id path int true "仓库ID" // @Success 200 {object} Response // @Failure 400 {object} Response // @Router /repos/{id} [delete] func (h *RepoHandler) Delete(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } if err := h.repoService.DeleteRepo(r.Context(), id); err != nil { logger.Logger.Error().Err(err).Int64("repo_id", id).Msg("failed to delete repository") respondError(w, http.StatusInternalServerError, 50000, "failed to delete repository") return } respondJSON(w, http.StatusOK, 0, "repository deleted successfully", nil) } // GetBranches 获取仓库分支列表 // @Summary 获取仓库分支列表 // @Description 获取指定仓库的所有分支 // @Tags 仓库管理 // @Produce json // @Param id path int true "仓库ID" // @Success 200 {object} Response{data=object} // @Failure 400 {object} Response // @Failure 404 {object} Response // @Router /repos/{id}/branches [get] func (h *RepoHandler) GetBranches(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64) if err != nil { respondError(w, http.StatusBadRequest, 40001, "invalid repository id") return } branches, err := h.repoService.GetBranches(r.Context(), id) if err != nil { logger.Logger.Error().Err(err).Int64("repo_id", id).Msg("failed to get branches") respondError(w, http.StatusInternalServerError, 50000, err.Error()) return } data := map[string]interface{}{ "branches": branches, "count": len(branches), } respondJSON(w, http.StatusOK, 0, "success", data) }