diff --git a/backend/app/api/v1/app.go b/backend/app/api/v1/app.go index 72b060ae0..fdc11bef7 100644 --- a/backend/app/api/v1/app.go +++ b/backend/app/api/v1/app.go @@ -68,7 +68,7 @@ func (b *BaseApi) InstallApp(c *gin.Context) { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return } - if err := appService.Install(req.AppDetailId, req.Params); err != nil { + if err := appService.Install(req.Name, req.AppDetailId, req.Params); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } @@ -92,3 +92,17 @@ func (b *BaseApi) PageInstalled(c *gin.Context) { Total: total, }) } + +func (b *BaseApi) InstallOperate(c *gin.Context) { + var req dto.AppInstallOperate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := appService.Operate(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, nil) +} diff --git a/backend/app/dto/app.go b/backend/app/dto/app.go index d8decea7a..a38a227c2 100644 --- a/backend/app/dto/app.go +++ b/backend/app/dto/app.go @@ -66,6 +66,7 @@ type AppRequest struct { type AppInstallRequest struct { AppDetailId uint `json:"appDetailId" validate:"required"` Params map[string]interface{} `json:"params"` + Name string `json:"name" validate:"required"` } type AppInstalled struct { @@ -79,3 +80,16 @@ type AppInstalled struct { type AppInstalledRequest struct { PageInfo } + +type AppOperate string + +var ( + Up AppOperate = "up" + Down AppOperate = "down" + Restart AppOperate = "restart" +) + +type AppInstallOperate struct { + InstallId uint `json:"installId" validate:"required"` + Operate AppOperate `json:"operate" validate:"required"` +} diff --git a/backend/app/model/app_install.go b/backend/app/model/app_install.go index 5bdfe0400..54eda70a2 100644 --- a/backend/app/model/app_install.go +++ b/backend/app/model/app_install.go @@ -2,6 +2,7 @@ package model type AppInstall struct { BaseModel + Name string `json:"name" gorm:"type:varchar(64);not null"` ContainerName string `json:"containerName" gorm:"type:varchar(256);not null"` Version string `json:"version" gorm:"type:varchar(256);not null"` AppId uint `json:"appId" gorm:"type:integer;not null"` diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go index 899155abf..2830bc9cd 100644 --- a/backend/app/repo/app_install.go +++ b/backend/app/repo/app_install.go @@ -13,7 +13,7 @@ func (a AppInstallRepo) GetBy(opts ...DBOption) ([]model.AppInstall, error) { db = opt(db) } var install []model.AppInstall - err := db.Find(&install).Error + err := db.Preload("App").Find(&install).Error return install, err } diff --git a/backend/app/service/app.go b/backend/app/service/app.go index ec91f5031..410003a0e 100644 --- a/backend/app/service/app.go +++ b/backend/app/service/app.go @@ -3,6 +3,7 @@ package service import ( "encoding/base64" "encoding/json" + "errors" "github.com/1Panel-dev/1Panel/app/dto" "github.com/1Panel-dev/1Panel/app/model" "github.com/1Panel-dev/1Panel/app/repo" @@ -147,7 +148,51 @@ func (a AppService) GetAppDetail(appId uint, version string) (dto.AppDetailDTO, return appDetailDTO, nil } -func (a AppService) Install(appDetailId uint, params map[string]interface{}) error { +func (a AppService) Operate(req dto.AppInstallOperate) error { + appInstall, err := appInstallRepo.GetBy(commonRepo.WithByID(req.InstallId)) + if err != nil { + return err + } + if len(appInstall) == 0 { + return errors.New("not found") + } + + install := appInstall[0] + dockerComposePath := path.Join(global.CONF.System.AppDir, install.App.Key, install.ContainerName, "docker-compose.yml") + switch req.Operate { + case dto.Up: + out, err := compose.Up(dockerComposePath) + if err != nil { + return handleErr(install, err, out) + } + case dto.Down: + out, err := compose.Down(dockerComposePath) + if err != nil { + return handleErr(install, err, out) + } + case dto.Restart: + out, err := compose.Restart(dockerComposePath) + if err != nil { + return handleErr(install, err, out) + } + default: + return errors.New("operate not support") + } + return nil +} + +func handleErr(install model.AppInstall, err error, out string) error { + reErr := err + install.Message = err.Error() + if out != "" { + install.Message = out + reErr = errors.New(out) + } + _ = appInstallRepo.Save(install) + return reErr +} + +func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) error { appDetail, err := appDetailRepo.GetAppDetail(commonRepo.WithByID(appDetailId)) if err != nil { return err @@ -159,6 +204,7 @@ func (a AppService) Install(appDetailId uint, params map[string]interface{}) err } containerName := constant.ContainerPrefix + app.Key + "-" + common.RandStr(6) appInstall := model.AppInstall{ + Name: name, AppId: appDetail.AppId, AppDetailId: appDetail.ID, Version: appDetail.Version, diff --git a/backend/router/ro_app.go b/backend/router/ro_app.go index c51ed12c2..1bf9098b8 100644 --- a/backend/router/ro_app.go +++ b/backend/router/ro_app.go @@ -21,5 +21,6 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) { appRouter.GET("/detail/:appid/:version", baseApi.GetAppDetail) appRouter.POST("/install", baseApi.InstallApp) appRouter.POST("/installed", baseApi.PageInstalled) + appRouter.POST("/installed/op", baseApi.InstallOperate) } } diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts index e3413da14..76eafdd3d 100644 --- a/frontend/src/api/interface/app.ts +++ b/frontend/src/api/interface/app.ts @@ -62,6 +62,7 @@ export namespace App { } export interface AppInstalled extends CommonModel { + name: string; containerName: string; version: string; appId: string; @@ -75,4 +76,9 @@ export namespace App { ready: number; icon: string; } + + export interface AppInstalledOp { + installId: number; + operate: string; + } } diff --git a/frontend/src/api/modules/app.ts b/frontend/src/api/modules/app.ts index 5e25540e4..6e8fa80c2 100644 --- a/frontend/src/api/modules/app.ts +++ b/frontend/src/api/modules/app.ts @@ -25,3 +25,7 @@ export const InstallApp = (install: App.AppInstall) => { export const GetAppInstalled = (info: ReqPage) => { return http.post>('apps/installed', info); }; + +export const InstalledOp = (op: App.AppInstalledOp) => { + return http.post('apps/installed/op', op); +}; diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index bdb982e7d..3cd216d6f 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -61,6 +61,7 @@ export default { createSuccess: '新建成功', updateSuccess: '更新成功', uploadSuccess: '上传成功', + operate: '操作', }, login: { captchaHelper: '请输入验证码', @@ -403,5 +404,7 @@ export default { restart: '重启', up: '启动', down: '停止', + name: '名称', + description: '描述', }, }; diff --git a/frontend/src/views/app-store/detail/install.vue b/frontend/src/views/app-store/detail/install.vue index cf0dee9dc..24feae2ca 100644 --- a/frontend/src/views/app-store/detail/install.vue +++ b/frontend/src/views/app-store/detail/install.vue @@ -1,6 +1,9 @@