package devcontainer import ( "strconv" "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/log" web_module "code.gitea.io/gitea/modules/web" Result "code.gitea.io/gitea/routers/entity" context "code.gitea.io/gitea/services/context" gitea_web_context "code.gitea.io/gitea/services/context" devcontainer_service "code.gitea.io/gitea/services/devcontainer" "code.gitea.io/gitea/services/forms" ) // CreateRepoDevcontainer 创建 某用户在某仓库的 DevContainer // // POST /api/devcontainer // 请求体参数: // -- repoId: 需要为哪个仓库创建 DevContainer // -- sshPublicKeyList: 列表,填入用户希望临时使用的SSH会话加密公钥 // 注意:必须携带 用户登录凭证 func CreateRepoDevcontainer(ctx *context.Context) { // 1. 检查用户登录状态,若未登录则返回未授权错误 if ctx == nil || ctx.Doer == nil { Result.RespUnauthorizedFailure.RespondJson2HttpResponseWriter(ctx.Resp) return } // 2. 检查表单校验规则是否失败 if ctx.HasError() { // POST Binding 表单正则表达式校验失败,返回 API 错误信息 failedToValidateFormData := &Result.ResultType{ Code: Result.RespFailedIllegalParams.Code, Msg: Result.RespFailedIllegalParams.Msg, Data: map[string]string{ "ErrorMsg": ctx.GetErrMsg(), }, } failedToValidateFormData.RespondJson2HttpResponseWriter(ctx.Resp) return } // 3. 解析 repoId form := web_module.GetForm(ctx).(*forms.CreateRepoDevcontainerForm) repoId, err := strconv.ParseInt(form.RepoId, 10, 64) if err != nil || repoId <= 0 { failedToParseRepoId := Result.ResultType{ Code: Result.RespFailedIllegalParams.Code, Msg: Result.RespFailedIllegalParams.Msg, Data: map[string]string{ // fix nullptr dereference of `err.Error()` when repoId == 0 "ErrorMsg": "repoId 必须是正数", }, } failedToParseRepoId.RespondJson2HttpResponseWriter(ctx.Resp) return } // 4. 调用 API Service 层创建 DevContainer repo, err := repo.GetRepositoryByID(ctx, repoId) if err != nil { errCreateDevcontainer := Result.ResultType{ Code: Result.RespFailedCreateDevcontainer.Code, Msg: Result.RespFailedCreateDevcontainer.Msg, Data: map[string]string{ "ErrorMsg": "repo not found", }, } errCreateDevcontainer.RespondJson2HttpResponseWriter(ctx.Resp) return } devcontainer_service.CreateDevcontainerJSON(ctx, repo, ctx.Doer) opts := &devcontainer_service.CreateDevcontainerOptions{ Actor: ctx.Doer, RepoId: repoId, SSHPublicKeyList: form.SSHPublicKeyList, } err = devcontainer_service.CreateDevcontainerAPIService(ctx, opts) if err != nil { errCreateDevcontainer := Result.ResultType{ Code: Result.RespFailedCreateDevcontainer.Code, Msg: Result.RespFailedCreateDevcontainer.Msg, Data: map[string]string{ "ErrorMsg": err.Error(), }, } errCreateDevcontainer.RespondJson2HttpResponseWriter(ctx.Resp) return } // 4. 创建 DevContainer 成功,直接返回 Result.RespSuccess.RespondJson2HttpResponseWriter(ctx.Resp) } // GetDevcontainer 查找某用户在某仓库的 DevContainer // // GET /api/devcontainer // 请求体参数: // -- repoId: 需要为哪个仓库创建 DevContainer // -- wait: 是否等待 DevContainer 就绪(默认为 false 直接返回“未就绪”,否则阻塞等待) // -- UserPublicKey // 注意:必须携带 用户登录凭证 func GetDevcontainer(ctx *gitea_web_context.Context) { // 1. 检查用户登录状态,若未登录则返回未授权错误 if ctx == nil || ctx.Doer == nil { Result.RespUnauthorizedFailure.RespondJson2HttpResponseWriter(ctx.Resp) return } // 2. 取得参数 wait := ctx.FormBool("wait") repoIdStr := ctx.FormString("repoId") UserPublicKey := ctx.FormString("userPublicKey") log.Info(UserPublicKey) repoId, err := strconv.ParseInt(repoIdStr, 10, 64) if err != nil || repoId <= 0 { Result.RespFailedIllegalParams.RespondJson2HttpResponseWriter(ctx.Resp) return } // 3. 准备调用 API Service 层,获取 DevContainer 信息 optsAbstractOpenDevcontainer := &devcontainer_service.AbstractOpenDevcontainerOptions{ Wait: wait, RepoId: repoId, Actor: ctx.Doer, UserPublicKey: UserPublicKey, } repoDevcontainerVO, err := devcontainer_service.OpenDevcontainerAPIService(ctx, optsAbstractOpenDevcontainer) if err != nil { failureGetDevcontainer := Result.ResultType{ Code: Result.RespFailedOpenDevcontainer.Code, Msg: Result.RespFailedOpenDevcontainer.Msg, Data: map[string]any{ "ErrorMsg": err.Error(), }, } failureGetDevcontainer.RespondJson2HttpResponseWriter(ctx.Resp) return } // 4. 封装返回成功信息 successGetDevContainer := Result.ResultType{ Code: Result.RespSuccess.Code, Msg: Result.RespSuccess.Msg, Data: repoDevcontainerVO, } successGetDevContainer.RespondJson2HttpResponseWriter(ctx.Resp) } // DeleteRepoDevcontainer 删除某仓库的 DevContainer // // DELETE /api/devcontainer // 请求体参数: // -- repoId: 需要为哪个仓库创建 DevContainer // 注意:必须携带 用户登录凭证 func DeleteRepoDevcontainer(ctx *gitea_web_context.Context) { // 1. 检查用户登录状态,若未登录则返回未授权错误 if ctx == nil || ctx.Doer == nil { Result.RespUnauthorizedFailure.RespondJson2HttpResponseWriter(ctx.Resp) return } // 2. 取得参数 repoId repoIdStr := ctx.FormString("repoId") repoId, err := strconv.ParseInt(repoIdStr, 10, 64) if err != nil || repoId <= 0 { Result.RespFailedIllegalParams.RespondJson2HttpResponseWriter(ctx.Resp) return } // 3. 调用 API Service 层,删除 DevContainer opts := &devcontainer_service.AbstractDeleteDevcontainerOptions{ Actor: ctx.Doer, RepoId: repoId, } err = devcontainer_service.DeleteDevcontainerAPIService(ctx, opts) if err != nil { failureDeleteDevcontainer := Result.ResultType{ Code: Result.RespFailedDeleteDevcontainer.Code, Msg: Result.RespFailedDeleteDevcontainer.Msg, Data: map[string]any{ "ErrorMsg": err.Error(), }, } failureDeleteDevcontainer.RespondJson2HttpResponseWriter(ctx.Resp) return } // 4. 删除成功,返回提示信息 Result.RespSuccess.RespondJson2HttpResponseWriter(ctx.Resp) }