2025-02-17 05:36:49 +00:00
|
|
|
|
package devcontainer
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
|
2025-05-29 11:13:22 +08:00
|
|
|
|
"code.gitea.io/gitea/models/repo"
|
2025-02-17 05:36:49 +00:00
|
|
|
|
"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
|
2025-05-29 11:13:22 +08:00
|
|
|
|
repo, err := repo.GetRepositoryByID(ctx, repoId)
|
|
|
|
|
|
if err != nil {
|
2025-05-27 23:58:00 +08:00
|
|
|
|
errCreateDevcontainer := Result.ResultType{
|
|
|
|
|
|
Code: Result.RespFailedCreateDevcontainer.Code,
|
|
|
|
|
|
Msg: Result.RespFailedCreateDevcontainer.Msg,
|
|
|
|
|
|
Data: map[string]string{
|
2025-05-29 11:13:22 +08:00
|
|
|
|
"ErrorMsg": "repo not found",
|
2025-05-27 23:58:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
errCreateDevcontainer.RespondJson2HttpResponseWriter(ctx.Resp)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-05-29 11:13:22 +08:00
|
|
|
|
devcontainer_service.CreateDevcontainerJSON(ctx, repo, ctx.Doer)
|
2025-05-27 23:58:00 +08:00
|
|
|
|
|
2025-02-17 05:36:49 +00:00
|
|
|
|
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)
|
|
|
|
|
|
}
|