feat: 修改应用文件

This commit is contained in:
zhengkunwang223 2022-11-18 14:27:40 +08:00 committed by zhengkunwang223
parent c7e0e3320a
commit 13bc73ac3c
52 changed files with 584 additions and 535 deletions

View File

@ -1,4 +1,4 @@
{
"version": "0.0.3",
"package": ""
"version": "0.0.6",
"package": "https://1panel.oss-cn-hangzhou.aliyuncs.com/apps-0.0.6.zip"
}

View File

@ -1,4 +0,0 @@
version: '3'
networks:
1panel:
driver: bridge

View File

@ -1,5 +1,5 @@
{
"version": "0.0.2",
"version": "0.0.6",
"tags": [
{
"key": "WebSite",
@ -21,10 +21,9 @@
"tags": ["Database"],
"versions": ["5.7.39"],
"short_desc": "常用关系型数据库",
"icon": "mysql.png",
"author": "Oracle",
"type": "runtime",
"required": [""],
"required": [],
"crossVersionUpdate": false,
"limit": 1,
"source": "https://www.mysql.com"
@ -35,10 +34,9 @@
"tags": ["Database"],
"versions": ["8.0.30"],
"short_desc": "常用关系型数据库",
"icon": "mysql.png",
"author": "Oracle",
"type": "runtime",
"required": [""],
"required": [],
"crossVersionUpdate": false,
"limit": 1,
"source": "https://www.mysql.com"
@ -49,10 +47,9 @@
"tags": ["Server"],
"versions": ["1.23.1"],
"short_desc": "高性能的HTTP和反向代理web服务器",
"icon": "nginx.png",
"author": "Nginx",
"type": "runtime",
"required": [""],
"required": [],
"limit": 1,
"crossVersionUpdate": true,
"source": "http://nginx.org/"
@ -63,7 +60,6 @@
"tags": ["WebSite"],
"versions": ["6.0.1","6.0.2"],
"short_desc": "老牌博客网站模版",
"icon": "wordpress.png",
"author": "Wordpress",
"type": "website",
"required": ["mysql8.0"],
@ -77,10 +73,9 @@
"tags": ["Database"],
"versions": ["7.0.5","6.0.16"],
"short_desc": "缓存数据库",
"icon": "redis.png",
"author": "Salvatore Sanfilippo",
"type": "runtime",
"required": [""],
"required": [],
"limit": 0,
"crossVersionUpdate": true,
"source": "https://redis.io/"

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

View File

@ -4,9 +4,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
"reflect"
)
func (b *BaseApi) SearchApp(c *gin.Context) {
@ -78,133 +76,3 @@ func (b *BaseApi) InstallApp(c *gin.Context) {
helper.SuccessWithData(c, install)
}
func (b *BaseApi) DeleteAppBackup(c *gin.Context) {
var req dto.AppBackupDeleteRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := appService.DeleteBackup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) SearchInstalled(c *gin.Context) {
var req dto.AppInstalledRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if !reflect.DeepEqual(req.PageInfo, dto.PageInfo{}) {
total, list, err := appService.PageInstalled(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
} else {
list, err := appService.SearchInstalled(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
}
func (b *BaseApi) SearchInstalledBackup(c *gin.Context) {
var req dto.AppBackupRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
total, list, err := appService.PageInstallBackups(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
func (b *BaseApi) OperateInstalled(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.OperateInstall(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) SyncInstalled(c *gin.Context) {
if err := appService.SyncAllInstalled(); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, "")
}
func (b *BaseApi) GetServices(c *gin.Context) {
key := c.Param("key")
services, err := appService.GetServices(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, services)
}
func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
versions, err := appService.GetUpdateVersions(appInstallId)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, versions)
}
func (b *BaseApi) ChangeAppPort(c *gin.Context) {
var req dto.PortUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := appService.ChangeAppPort(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -0,0 +1,139 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
"reflect"
)
func (b *BaseApi) SearchAppInstalled(c *gin.Context) {
var req dto.AppInstalledRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if !reflect.DeepEqual(req.PageInfo, dto.PageInfo{}) {
total, list, err := appInstallService.Page(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
} else {
list, err := appInstallService.Search(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
}
func (b *BaseApi) SyncInstalled(c *gin.Context) {
if err := appInstallService.SyncAll(); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, "")
}
func (b *BaseApi) SearchInstalledBackup(c *gin.Context) {
var req dto.AppBackupRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
total, list, err := appInstallService.PageInstallBackups(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, dto.PageResult{
Items: list,
Total: total,
})
}
func (b *BaseApi) OperateInstalled(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 := appInstallService.Operate(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) DeleteAppBackup(c *gin.Context) {
var req dto.AppBackupDeleteRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := appInstallService.DeleteBackup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) GetServices(c *gin.Context) {
key := c.Param("key")
services, err := appInstallService.GetServices(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, services)
}
func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
appInstallId, err := helper.GetIntParamByKey(c, "appInstallId")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
versions, err := appInstallService.GetUpdateVersions(appInstallId)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, versions)
}
func (b *BaseApi) ChangeAppPort(c *gin.Context) {
var req dto.PortUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := appInstallService.ChangeAppPort(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -12,6 +12,7 @@ var (
authService = service.ServiceGroupApp.AuthService
appService = service.ServiceGroupApp.AppService
appInstallService = service.ServiceGroupApp.AppInstallService
containerService = service.ServiceGroupApp.ContainerService
composeTemplateService = service.ServiceGroupApp.ComposeTemplateService

View File

@ -130,7 +130,7 @@ type AppDefine struct {
Name string `json:"name"`
Tags []string `json:"tags"`
Versions []string `json:"versions"`
Icon string `json:"icon"`
//Icon string `json:"icon"`
Author string `json:"author"`
Source string `json:"source"`
ShortDesc string `json:"short_desc"`

View File

@ -3,31 +3,26 @@ package repo
import (
"context"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
type AppTagRepo struct {
}
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
db := ctx.Value("db").(*gorm.DB)
return db.Create(&tags).Error
return getTx(ctx).Create(&tags).Error
}
func (a AppTagRepo) DeleteByAppIds(ctx context.Context, appIds []uint) error {
db := ctx.Value("db").(*gorm.DB)
return db.Where("app_id in (?)", appIds).Delete(&model.AppTag{}).Error
return getTx(ctx).Where("app_id in (?)", appIds).Delete(&model.AppTag{}).Error
}
func (a AppTagRepo) DeleteAll(ctx context.Context) error {
db := ctx.Value("db").(*gorm.DB)
return db.Where("1 = 1").Delete(&model.AppTag{}).Error
return getTx(ctx).Where("1 = 1").Delete(&model.AppTag{}).Error
}
func (a AppTagRepo) GetByAppId(appId uint) ([]model.AppTag, error) {
var appTags []model.AppTag
if err := global.DB.Where("app_id = ?", appId).Find(&appTags).Error; err != nil {
if err := getDb().Where("app_id = ?", appId).Find(&appTags).Error; err != nil {
return nil, err
}
return appTags, nil
@ -35,7 +30,7 @@ func (a AppTagRepo) GetByAppId(appId uint) ([]model.AppTag, error) {
func (a AppTagRepo) GetByTagIds(tagIds []uint) ([]model.AppTag, error) {
var appTags []model.AppTag
if err := global.DB.Where("tag_id in (?)", tagIds).Find(&appTags).Error; err != nil {
if err := getDb().Where("tag_id in (?)", tagIds).Find(&appTags).Error; err != nil {
return nil, err
}
return appTags, nil

View File

@ -3,26 +3,22 @@ package repo
import (
"context"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
type TagRepo struct {
}
func (t TagRepo) BatchCreate(ctx context.Context, tags []*model.Tag) error {
db := ctx.Value("db").(*gorm.DB)
return db.Create(&tags).Error
return getTx(ctx).Create(&tags).Error
}
func (t TagRepo) DeleteAll(ctx context.Context) error {
db := ctx.Value("db").(*gorm.DB)
return db.Where("1 = 1 ").Delete(&model.Tag{}).Error
return getTx(ctx).Where("1 = 1 ").Delete(&model.Tag{}).Error
}
func (t TagRepo) All() ([]model.Tag, error) {
var tags []model.Tag
if err := global.DB.Where("1 = 1 ").Find(&tags).Error; err != nil {
if err := getDb().Where("1 = 1 ").Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
@ -30,7 +26,7 @@ func (t TagRepo) All() ([]model.Tag, error) {
func (t TagRepo) GetByIds(ids []uint) ([]model.Tag, error) {
var tags []model.Tag
if err := global.DB.Where("id in (?)", ids).Find(&tags).Error; err != nil {
if err := getDb().Where("id in (?)", ids).Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
@ -38,7 +34,7 @@ func (t TagRepo) GetByIds(ids []uint) ([]model.Tag, error) {
func (t TagRepo) GetByKeys(keys []string) ([]model.Tag, error) {
var tags []model.Tag
if err := global.DB.Where("key in (?)", keys).Find(&tags).Error; err != nil {
if err := getDb().Where("key in (?)", keys).Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil
@ -46,7 +42,7 @@ func (t TagRepo) GetByKeys(keys []string) ([]model.Tag, error) {
func (t TagRepo) GetByAppId(appId uint) ([]model.Tag, error) {
var tags []model.Tag
if err := global.DB.Where("id in (select tag_id from app_tags where app_id = ?)", appId).Find(&tags).Error; err != nil {
if err := getDb().Where("id in (select tag_id from app_tags where app_id = ?)", appId).Find(&tags).Error; err != nil {
return nil, err
}
return tags, nil

View File

@ -3,12 +3,9 @@ package service
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@ -17,10 +14,8 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"golang.org/x/net/context"
"gopkg.in/yaml.v3"
)
@ -114,56 +109,6 @@ func (a AppService) GetApp(id uint) (dto.AppDTO, error) {
return appDTO, nil
}
func (a AppService) PageInstalled(req dto.AppInstalledRequest) (int64, []dto.AppInstalled, error) {
total, installed, err := appInstallRepo.Page(req.Page, req.PageSize)
if err != nil {
return 0, nil, err
}
var installDTOs []dto.AppInstalled
for _, in := range installed {
installDto := dto.AppInstalled{
AppInstall: in,
}
installDTOs = append(installDTOs, installDto)
}
return total, installDTOs, nil
}
func (a AppService) SearchInstalled(req dto.AppInstalledRequest) ([]dto.AppInstalled, error) {
var installs []model.AppInstall
var err error
if req.Type != "" {
apps, err := appRepo.GetBy(appRepo.WithType(req.Type))
if err != nil {
return nil, err
}
var ids []uint
for _, app := range apps {
ids = append(ids, app.ID)
}
installs, err = appInstallRepo.GetBy(appInstallRepo.WithAppIdsIn(ids))
if err != nil {
return nil, err
}
} else {
installs, err = appInstallRepo.GetBy()
if err != nil {
return nil, err
}
}
var installDTOs []dto.AppInstalled
for _, in := range installs {
installDto := dto.AppInstalled{
AppInstall: in,
}
installDTOs = append(installDTOs, installDto)
}
return installDTOs, nil
}
func (a AppService) GetAppDetail(appId uint, version string) (dto.AppDetailDTO, error) {
var (
@ -183,120 +128,6 @@ func (a AppService) GetAppDetail(appId uint, version string) (dto.AppDetailDTO,
return appDetailDTO, nil
}
func (a AppService) PageInstallBackups(req dto.AppBackupRequest) (int64, []model.AppInstallBackup, error) {
return appInstallBackupRepo.Page(req.Page, req.PageSize, appInstallBackupRepo.WithAppInstallID(req.AppInstallID))
}
func (a AppService) OperateInstall(req dto.AppInstallOperate) error {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
if err != nil {
return err
}
dockerComposePath := install.GetComposePath()
switch req.Operate {
case dto.Up:
out, err := compose.Up(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Running
case dto.Down:
out, err := compose.Down(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Stopped
case dto.Restart:
out, err := compose.Restart(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Running
case dto.Delete:
tx, ctx := getTxAndContext()
if err := deleteAppInstall(ctx, install); err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
case dto.Sync:
return a.SyncInstalled(install.ID)
case dto.Backup:
tx, ctx := getTxAndContext()
if err := backupInstall(ctx, install); err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
case dto.Restore:
return restoreInstall(install, req.BackupId)
case dto.Update:
return updateInstall(install.ID, req.DetailId)
default:
return errors.New("operate not support")
}
return appInstallRepo.Save(&install)
}
func (a AppService) ChangeAppPort(req dto.PortUpdate) error {
var (
files []string
newFiles []string
)
app, err := mysqlRepo.LoadBaseInfoByName(req.Name)
if err != nil {
return err
}
ComposeDir := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, req.Key, req.Name)
ComposeFile := fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Key, req.Name)
path := fmt.Sprintf("%s/.env", ComposeDir)
lineBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
} else {
files = strings.Split(string(lineBytes), "\n")
}
for _, line := range files {
if strings.HasPrefix(line, "PANEL_APP_PORT_HTTP=") {
newFiles = append(newFiles, fmt.Sprintf("PANEL_APP_PORT_HTTP=%v", req.Port))
} else {
newFiles = append(newFiles, line)
}
}
file, err := os.OpenFile(path, os.O_WRONLY, 0666)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(strings.Join(newFiles, "\n"))
if err != nil {
return err
}
if err := mysqlRepo.UpdateDatabaseInfo(app.ID, map[string]interface{}{
"env": strings.ReplaceAll(app.Env, strconv.FormatInt(app.Port, 10), strconv.FormatInt(req.Port, 10)),
}); err != nil {
return err
}
stdout, err := compose.Down(ComposeFile)
if err != nil {
return errors.New(stdout)
}
stdout, err = compose.Up(ComposeFile)
if err != nil {
return errors.New(stdout)
}
return nil
}
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) (*model.AppInstall, error) {
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", params)
@ -384,46 +215,6 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
return &appInstall, nil
}
func (a AppService) SyncAllInstalled() error {
allList, err := appInstallRepo.GetBy()
if err != nil {
return err
}
go func() {
for _, i := range allList {
if err := a.SyncInstalled(i.ID); err != nil {
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
}
}
}()
return nil
}
func (a AppService) DeleteBackup(req dto.AppBackupDeleteRequest) error {
backups, err := appInstallBackupRepo.GetBy(commonRepo.WithIdsIn(req.Ids))
if err != nil {
return err
}
fileOp := files.NewFileOp()
var errStr strings.Builder
for _, backup := range backups {
dst := path.Join(backup.Path, backup.Name)
if err := fileOp.DeleteFile(dst); err != nil {
errStr.WriteString(err.Error())
continue
}
if err := appInstallBackupRepo.Delete(context.TODO(), commonRepo.WithIdsIn(req.Ids)); err != nil {
errStr.WriteString(err.Error())
}
}
if errStr.String() != "" {
return errors.New(errStr.String())
}
return nil
}
func (a AppService) SyncInstalled(installId uint) error {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
if err != nil {
@ -520,7 +311,6 @@ func (a AppService) SyncAppList() error {
}
appDir := constant.AppResourceDir
iconDir := path.Join(appDir, "icons")
listFile := path.Join(appDir, "list.json")
content, err := os.ReadFile(listFile)
@ -553,7 +343,7 @@ func (a AppService) SyncAppList() error {
for _, l := range list.Items {
app := appsMap[l.Key]
icon, err := os.ReadFile(path.Join(iconDir, l.Icon))
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
if err != nil {
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
continue
@ -567,7 +357,7 @@ func (a AppService) SyncAppList() error {
for _, v := range versions {
detail := detailsMap[v]
detailPath := path.Join(appDir, l.Key, v)
detailPath := path.Join(appDir, l.Key, "versions", v)
if _, err := os.Stat(detailPath); err != nil {
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
continue
@ -611,8 +401,7 @@ func (a AppService) SyncAppList() error {
}
}
tx := global.DB.Begin()
ctx := context.WithValue(context.Background(), "db", tx)
tx, ctx := getTxAndContext()
if len(addAppArray) > 0 {
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
@ -742,47 +531,3 @@ func syncCanUpdate() {
}
}
func (a AppService) GetServices(key string) ([]dto.AppService, error) {
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
}
installs, err := appInstallRepo.GetBy(appInstallRepo.WithAppId(app.ID), appInstallRepo.WithStatus(constant.Running))
if err != nil {
return nil, err
}
var res []dto.AppService
for _, install := range installs {
res = append(res, dto.AppService{
Label: install.Name,
Value: install.ServiceName,
})
}
return res, nil
}
func (a AppService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
var versions []dto.AppVersion
if err != nil {
return versions, err
}
app, err := appRepo.GetFirst(commonRepo.WithByID(install.AppId))
if err != nil {
return versions, err
}
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
if err != nil {
return versions, err
}
for _, detail := range details {
if common.CompareVersion(detail.Version, install.Version) {
versions = append(versions, dto.AppVersion{
Version: detail.Version,
DetailId: detail.ID,
})
}
}
return versions, nil
}

View File

@ -0,0 +1,358 @@
package service
import (
"context"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
"io/ioutil"
"os"
"path"
"strconv"
"strings"
)
type AppInstallService struct {
}
func (a AppInstallService) Page(req dto.AppInstalledRequest) (int64, []dto.AppInstalled, error) {
total, installed, err := appInstallRepo.Page(req.Page, req.PageSize)
if err != nil {
return 0, nil, err
}
var installDTOs []dto.AppInstalled
for _, in := range installed {
installDto := dto.AppInstalled{
AppInstall: in,
}
installDTOs = append(installDTOs, installDto)
}
return total, installDTOs, nil
}
func (a AppInstallService) Search(req dto.AppInstalledRequest) ([]dto.AppInstalled, error) {
var installs []model.AppInstall
var err error
if req.Type != "" {
apps, err := appRepo.GetBy(appRepo.WithType(req.Type))
if err != nil {
return nil, err
}
var ids []uint
for _, app := range apps {
ids = append(ids, app.ID)
}
installs, err = appInstallRepo.GetBy(appInstallRepo.WithAppIdsIn(ids))
if err != nil {
return nil, err
}
} else {
installs, err = appInstallRepo.GetBy()
if err != nil {
return nil, err
}
}
var installDTOs []dto.AppInstalled
for _, in := range installs {
installDto := dto.AppInstalled{
AppInstall: in,
}
installDTOs = append(installDTOs, installDto)
}
return installDTOs, nil
}
func (a AppInstallService) Operate(req dto.AppInstallOperate) error {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
if err != nil {
return err
}
dockerComposePath := install.GetComposePath()
switch req.Operate {
case dto.Up:
out, err := compose.Up(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Running
case dto.Down:
out, err := compose.Down(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Stopped
case dto.Restart:
out, err := compose.Restart(dockerComposePath)
if err != nil {
return handleErr(install, err, out)
}
install.Status = constant.Running
case dto.Delete:
tx, ctx := getTxAndContext()
if err := deleteAppInstall(ctx, install); err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
case dto.Sync:
return syncById(install.ID)
case dto.Backup:
tx, ctx := getTxAndContext()
if err := backupInstall(ctx, install); err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
case dto.Restore:
return restoreInstall(install, req.BackupId)
case dto.Update:
return updateInstall(install.ID, req.DetailId)
default:
return errors.New("operate not support")
}
return appInstallRepo.Save(&install)
}
func (a AppInstallService) SyncAll() error {
allList, err := appInstallRepo.GetBy()
if err != nil {
return err
}
go func() {
for _, i := range allList {
if err := syncById(i.ID); err != nil {
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
}
}
}()
return nil
}
func (a AppInstallService) PageInstallBackups(req dto.AppBackupRequest) (int64, []model.AppInstallBackup, error) {
return appInstallBackupRepo.Page(req.Page, req.PageSize, appInstallBackupRepo.WithAppInstallID(req.AppInstallID))
}
func (a AppInstallService) DeleteBackup(req dto.AppBackupDeleteRequest) error {
backups, err := appInstallBackupRepo.GetBy(commonRepo.WithIdsIn(req.Ids))
if err != nil {
return err
}
fileOp := files.NewFileOp()
var errStr strings.Builder
for _, backup := range backups {
dst := path.Join(backup.Path, backup.Name)
if err := fileOp.DeleteFile(dst); err != nil {
errStr.WriteString(err.Error())
continue
}
if err := appInstallBackupRepo.Delete(context.TODO(), commonRepo.WithIdsIn(req.Ids)); err != nil {
errStr.WriteString(err.Error())
}
}
if errStr.String() != "" {
return errors.New(errStr.String())
}
return nil
}
func (a AppInstallService) GetServices(key string) ([]dto.AppService, error) {
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
}
installs, err := appInstallRepo.GetBy(appInstallRepo.WithAppId(app.ID), appInstallRepo.WithStatus(constant.Running))
if err != nil {
return nil, err
}
var res []dto.AppService
for _, install := range installs {
res = append(res, dto.AppService{
Label: install.Name,
Value: install.ServiceName,
})
}
return res, nil
}
func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
var versions []dto.AppVersion
if err != nil {
return versions, err
}
app, err := appRepo.GetFirst(commonRepo.WithByID(install.AppId))
if err != nil {
return versions, err
}
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(app.ID))
if err != nil {
return versions, err
}
for _, detail := range details {
if common.CompareVersion(detail.Version, install.Version) {
versions = append(versions, dto.AppVersion{
Version: detail.Version,
DetailId: detail.ID,
})
}
}
return versions, nil
}
func (a AppInstallService) ChangeAppPort(req dto.PortUpdate) error {
var (
files []string
newFiles []string
)
app, err := mysqlRepo.LoadBaseInfoByName(req.Name)
if err != nil {
return err
}
ComposeDir := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, req.Key, req.Name)
ComposeFile := fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Key, req.Name)
path := fmt.Sprintf("%s/.env", ComposeDir)
lineBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
} else {
files = strings.Split(string(lineBytes), "\n")
}
for _, line := range files {
if strings.HasPrefix(line, "PANEL_APP_PORT_HTTP=") {
newFiles = append(newFiles, fmt.Sprintf("PANEL_APP_PORT_HTTP=%v", req.Port))
} else {
newFiles = append(newFiles, line)
}
}
file, err := os.OpenFile(path, os.O_WRONLY, 0666)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(strings.Join(newFiles, "\n"))
if err != nil {
return err
}
if err := mysqlRepo.UpdateDatabaseInfo(app.ID, map[string]interface{}{
"env": strings.ReplaceAll(app.Env, strconv.FormatInt(app.Port, 10), strconv.FormatInt(req.Port, 10)),
}); err != nil {
return err
}
stdout, err := compose.Down(ComposeFile)
if err != nil {
return errors.New(stdout)
}
stdout, err = compose.Up(ComposeFile)
if err != nil {
return errors.New(stdout)
}
return nil
}
func syncById(installId uint) error {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
if err != nil {
return err
}
containerNames, err := getContainerNames(appInstall)
if err != nil {
return err
}
cli, err := docker.NewClient()
if err != nil {
return err
}
containers, err := cli.ListContainersByName(containerNames)
if err != nil {
return err
}
var (
errorContainers []string
notFoundContainers []string
runningContainers []string
)
for _, n := range containers {
if n.State != "running" {
errorContainers = append(errorContainers, n.Names[0])
} else {
runningContainers = append(runningContainers, n.Names[0])
}
}
for _, old := range containerNames {
exist := false
for _, new := range containers {
if common.ExistWithStrArray(old, new.Names) {
exist = true
break
}
}
if !exist {
notFoundContainers = append(notFoundContainers, old)
}
}
containerCount := len(containers)
errCount := len(errorContainers)
notFoundCount := len(notFoundContainers)
normalCount := len(containerNames)
runningCount := len(runningContainers)
if containerCount == 0 {
appInstall.Status = constant.Error
appInstall.Message = "container is not found"
return appInstallRepo.Save(&appInstall)
}
if errCount == 0 && notFoundCount == 0 {
appInstall.Status = constant.Running
return appInstallRepo.Save(&appInstall)
}
if errCount == normalCount {
appInstall.Status = constant.Error
}
if notFoundCount == normalCount {
appInstall.Status = constant.Stopped
}
if runningCount < normalCount {
appInstall.Status = constant.UnHealthy
}
var errMsg strings.Builder
if errCount > 0 {
errMsg.Write([]byte(string(rune(errCount)) + " error containers:"))
for _, e := range errorContainers {
errMsg.Write([]byte(e))
}
errMsg.Write([]byte("\n"))
}
if notFoundCount > 0 {
errMsg.Write([]byte(string(rune(notFoundCount)) + " not found containers:"))
for _, e := range notFoundContainers {
errMsg.Write([]byte(e))
}
errMsg.Write([]byte("\n"))
}
appInstall.Message = errMsg.String()
return appInstallRepo.Save(&appInstall)
}

View File

@ -411,7 +411,7 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
}
func copyAppData(key, version, installName string, params map[string]interface{}) (err error) {
resourceDir := path.Join(constant.AppResourceDir, key, version)
resourceDir := path.Join(constant.AppResourceDir, key, "versions", version)
installDir := path.Join(constant.AppInstallDir, key)
installVersionDir := path.Join(installDir, version)
fileOp := files.NewFileOp()

View File

@ -6,6 +6,7 @@ type ServiceGroup struct {
AuthService
AppService
AppInstallService
ContainerService
ImageService

View File

@ -21,7 +21,7 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
appRouter.GET("/detail/:appId/:version", baseApi.GetAppDetail)
appRouter.POST("/install", baseApi.InstallApp)
appRouter.GET("/installed/:appInstallId/versions", baseApi.GetUpdateVersions)
appRouter.POST("/installed", baseApi.SearchInstalled)
appRouter.POST("/installed", baseApi.SearchAppInstalled)
appRouter.POST("/installed/op", baseApi.OperateInstalled)
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
appRouter.POST("/installed/backups", baseApi.SearchInstalledBackup)

View File

@ -720,5 +720,6 @@ export default {
renewSSL: '续签',
renewHelper: '确定续签证书',
renewSuccess: '续签证书',
config: '配置',
},
};

View File

@ -9,8 +9,9 @@
<el-tab-pane :label="$t('website.rate')">
<LimitConn :id="id" v-if="index == '2'"></LimitConn>
</el-tab-pane>
<el-tab-pane :label="'HTTPS'"></el-tab-pane>
<el-tab-pane :label="$t('website.other')">
<Other :id="id" v-if="index == '3'"></Other>
<Other :id="id" v-if="index == '4'"></Other>
</el-tab-pane>
</el-tabs>
</template>

View File

@ -2,9 +2,11 @@
<LayoutContent :header="'网站设置'" :back-name="'Website'">
<el-tabs v-model="index" @click="changeTab(index)">
<el-tab-pane label="基本" name="basic">
<Basic :id="id" v-if="index === 'basic'"></Basic>
<Basic :key="id" :id="id" v-if="index === 'basic'"></Basic>
</el-tab-pane>
<el-tab-pane label="安全" name="safety">
<Safety :key="id" :id="id" v-if="index === 'safety'"></Safety>
</el-tab-pane>
<el-tab-pane label="安全">反代</el-tab-pane>
<el-tab-pane label="备份">反代</el-tab-pane>
<el-tab-pane label="源文">反代</el-tab-pane>
</el-tabs>
@ -15,6 +17,7 @@
import LayoutContent from '@/layout/layout-content.vue';
import { onMounted, ref } from 'vue';
import Basic from './basic/index.vue';
import Safety from './safety/index.vue';
import router from '@/routers';
const props = defineProps({
@ -36,9 +39,7 @@ const changeTab = (index: string) => {
};
onMounted(() => {
id.value = Number(props.id);
if (props.tab !== index.value) {
index.value = props.tab;
}
id.value = Number(props.id);
});
</script>

View File

@ -0,0 +1,26 @@
<template>
<el-tabs tab-position="left" type="border-card" v-model="index">
<el-tab-pane :label="'CC 防护'" :id="id"></el-tab-pane>
<el-tab-pane :label="'白名单'"></el-tab-pane>
<el-tab-pane :label="'黑名单'"></el-tab-pane>
<el-tab-pane :label="'并发限制'"></el-tab-pane>
<el-tab-pane :label="'请求限制'"></el-tab-pane>
<el-tab-pane :label="'禁止爬虫'"></el-tab-pane>
</el-tabs>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
let index = ref('0');
</script>

View File

@ -4,8 +4,8 @@
<template #toolbar>
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
<el-button type="primary" plain @click="openGroup">{{ $t('website.group') }}</el-button>
<el-button type="primary" plain>{{ '修改默认页' }}</el-button>
<el-button type="primary" plain>{{ '默认站点' }}</el-button>
<!-- <el-button type="primary" plain>{{ '修改默认页' }}</el-button>
<el-button type="primary" plain>{{ '默认站点' }}</el-button> -->
</template>
<el-table-column :label="$t('commons.table.name')" fix show-overflow-tooltip prop="primaryDomain">
<template #default="{ row }">
@ -13,9 +13,9 @@
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"></el-table-column>
<el-table-column :label="'备份'" prop="backup"></el-table-column>
<!-- <el-table-column :label="'备份'" prop="backup"></el-table-column> -->
<el-table-column :label="'备注'" prop="remark"></el-table-column>
<el-table-column :label="'SSL证书'" prop="ssl"></el-table-column>
<!-- <el-table-column :label="'SSL证书'" prop="ssl"></el-table-column> -->
<fu-table-operations
:ellipsis="1"
:buttons="buttons"
@ -73,8 +73,10 @@ const openConfig = (id: number) => {
const buttons = [
{
label: '设置',
click: open,
label: i18n.global.t('website.config'),
click: function (row: WebSite.WebSite) {
openConfig(row.id);
},
},
{
label: i18n.global.t('app.delete'),

76
package-lock.json generated
View File

@ -1,76 +0,0 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@codemirror/commands": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.1.1.tgz",
"integrity": "sha512-ibDohwkk7vyu3VsnZNlQhwk0OETBtlkYV+6AHfn5Zgq0sxa+yGVX+apwtC3M4wh6AH7yU5si/NysoECs5EGS3Q==",
"requires": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0"
}
},
"@codemirror/language": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz",
"integrity": "sha512-MC3svxuvIj0MRpFlGHxLS6vPyIdbTr2KKPEW46kCoCXw2ktb4NTkpkPBI/lSP/FoNXLCBJ0mrnUi1OoZxtpW1Q==",
"requires": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"@codemirror/state": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.2.tgz",
"integrity": "sha512-Mxff85Hp5va+zuj+H748KbubXjrinX/k28lj43H14T2D0+4kuvEFIEIO7hCEcvBT8ubZyIelt9yGOjj2MWOEQA=="
},
"@codemirror/view": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.3.0.tgz",
"integrity": "sha512-jMN9OGKmzRPJ+kksfMrB5e/A9heQncirHsz8XNBpgEbYONCk5tWHMKVWKTNwznkUGD5mnigXI1i5YIcWpscSPg==",
"requires": {
"@codemirror/state": "^6.0.0",
"style-mod": "^4.0.0",
"w3c-keyname": "^2.2.4"
}
},
"@lezer/common": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.1.tgz",
"integrity": "sha512-8TR5++Q/F//tpDsLd5zkrvEX5xxeemafEaek7mUp7Y+bI8cKQXdSqhzTOBaOogETcMOVr0pT3BBPXp13477ciw=="
},
"@lezer/highlight": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.1.tgz",
"integrity": "sha512-duv9D23O9ghEDnnUDmxu+L8pJy4nYo4AbCOHIudUhscrLSazqeJeK1V50EU6ZufWF1zv0KJwu/frFRyZWXxHBQ==",
"requires": {
"@lezer/common": "^1.0.0"
}
},
"@lezer/lr": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.3.tgz",
"integrity": "sha512-qpB7rBzH8f6Mzjv2AVZRahcm+2Cf7nbIH++uXbvVOL1yIRvVWQ3HAM/saeBLCyz/togB7LGo76qdJYL1uKQlqA==",
"requires": {
"@lezer/common": "^1.0.0"
}
},
"style-mod": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz",
"integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw=="
},
"w3c-keyname": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
"integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg=="
}
}
}