mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 12:39:01 +08:00
feat: 应用商店对接远程应用服务
This commit is contained in:
parent
d443103e2c
commit
aeabed70db
@ -31,20 +31,42 @@ type AppVersion struct {
|
|||||||
DetailId uint `json:"detailId"`
|
DetailId uint `json:"detailId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//type AppList struct {
|
||||||
|
// Version string `json:"version"`
|
||||||
|
// Tags []Tag `json:"tags"`
|
||||||
|
// Items []AppDefine `json:"items"`
|
||||||
|
//}
|
||||||
|
|
||||||
type AppList struct {
|
type AppList struct {
|
||||||
Version string `json:"version"`
|
Valid bool `json:"valid"`
|
||||||
Tags []Tag `json:"tags"`
|
Violations []string `json:"violations"`
|
||||||
Items []AppDefine `json:"items"`
|
LastModified int `json:"lastModified"`
|
||||||
|
|
||||||
|
Apps []AppDefine `json:"apps"`
|
||||||
|
Extra ExtraProperties `json:"additionalProperties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppDefine struct {
|
type AppDefine struct {
|
||||||
Key string `json:"key"`
|
Icon string `json:"icon"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ReadMe string `json:"readMe"`
|
||||||
|
LastModified int `json:"lastModified"`
|
||||||
|
|
||||||
|
AppProperty AppProperty `json:"additionalProperties"`
|
||||||
|
Versions []AppConfigVersion `json:"versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtraProperties struct {
|
||||||
|
Tags []Tag `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppProperty struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
Versions []string `json:"versions"`
|
|
||||||
ShortDescZh string `json:"shortDescZh"`
|
ShortDescZh string `json:"shortDescZh"`
|
||||||
ShortDescEn string `json:"shortDescEn"`
|
ShortDescEn string `json:"shortDescEn"`
|
||||||
Type string `json:"type"`
|
Key string `json:"key"`
|
||||||
Required []string `json:"Required"`
|
Required []string `json:"Required"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
@ -54,8 +76,16 @@ type AppDefine struct {
|
|||||||
Document string `json:"document"`
|
Document string `json:"document"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (define AppDefine) GetRequired() string {
|
type AppConfigVersion struct {
|
||||||
by, _ := json.Marshal(define.Required)
|
Name string `json:"name"`
|
||||||
|
LastModified int `json:"lastModified"`
|
||||||
|
DownloadUrl string `json:"downloadUrl"`
|
||||||
|
DownloadCallBackUrl string `json:"downloadCallBackUrl"`
|
||||||
|
AppForm interface{} `json:"additionalProperties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config AppProperty) GetRequired() string {
|
||||||
|
by, _ := json.Marshal(config.Required)
|
||||||
return string(by)
|
return string(by)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +109,7 @@ type AppFormFields struct {
|
|||||||
Edit bool `json:"edit"`
|
Edit bool `json:"edit"`
|
||||||
Rule string `json:"rule"`
|
Rule string `json:"rule"`
|
||||||
Multiple bool `json:"multiple"`
|
Multiple bool `json:"multiple"`
|
||||||
|
Child interface{} `json:"child"`
|
||||||
Values []AppFormValue `json:"values"`
|
Values []AppFormValue `json:"values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package response
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
@ -12,9 +13,11 @@ type AppRes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AppUpdateRes struct {
|
type AppUpdateRes struct {
|
||||||
Version string `json:"version"`
|
//Version string `json:"version"`
|
||||||
CanUpdate bool `json:"canUpdate"`
|
//DownloadPath string `json:"downloadPath"`
|
||||||
DownloadPath string `json:"downloadPath"`
|
CanUpdate bool `json:"canUpdate"`
|
||||||
|
AppStoreLastModified int `json:"appStoreLastModified"`
|
||||||
|
List dto.AppList `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppDTO struct {
|
type AppDTO struct {
|
||||||
|
@ -33,7 +33,8 @@ type SettingInfo struct {
|
|||||||
WeChatVars string `json:"weChatVars"`
|
WeChatVars string `json:"weChatVars"`
|
||||||
DingVars string `json:"dingVars"`
|
DingVars string `json:"dingVars"`
|
||||||
|
|
||||||
AppStoreVersion string `json:"appStoreVersion"`
|
AppStoreVersion string `json:"appStoreVersion"`
|
||||||
|
AppStoreLastModified string `json:"appStoreLastModified"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingUpdate struct {
|
type SettingUpdate struct {
|
||||||
|
@ -2,22 +2,25 @@ package model
|
|||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
||||||
Key string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex"`
|
Key string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex"`
|
||||||
ShortDescZh string `json:"shortDescZh" gorm:"type:longtext;"`
|
ShortDescZh string `json:"shortDescZh" gorm:"type:longtext;"`
|
||||||
ShortDescEn string `json:"shortDescEn" gorm:"type:longtext;"`
|
ShortDescEn string `json:"shortDescEn" gorm:"type:longtext;"`
|
||||||
Icon string `json:"icon" gorm:"type:longtext;"`
|
Icon string `json:"icon" gorm:"type:longtext;"`
|
||||||
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
||||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||||
Required string `json:"required" gorm:"type:varchar(64);not null"`
|
Required string `json:"required" gorm:"type:varchar(64);not null"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||||
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
||||||
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
||||||
Github string `json:"github" gorm:"type:varchar(64);not null"`
|
Github string `json:"github" gorm:"type:varchar(64);not null"`
|
||||||
Document string `json:"document" gorm:"type:varchar(64);not null"`
|
Document string `json:"document" gorm:"type:varchar(64);not null"`
|
||||||
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
|
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
|
||||||
Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
|
Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
|
||||||
Details []AppDetail `json:"-" gorm:"-:migration"`
|
ReadMe string `json:"readMe" gorm:"type:varchar;"`
|
||||||
TagsKey []string `json:"-" gorm:"-"`
|
LastModified int `json:"lastModified" gorm:"type:Integer;"`
|
||||||
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
|
||||||
|
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||||
|
TagsKey []string `json:"-" gorm:"-"`
|
||||||
|
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,14 @@ package model
|
|||||||
|
|
||||||
type AppDetail struct {
|
type AppDetail struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
AppId uint `json:"appId" gorm:"type:integer;not null"`
|
AppId uint `json:"appId" gorm:"type:integer;not null"`
|
||||||
Version string `json:"version" gorm:"type:varchar(64);not null"`
|
Version string `json:"version" gorm:"type:varchar(64);not null"`
|
||||||
Params string `json:"-" gorm:"type:longtext;"`
|
Params string `json:"-" gorm:"type:longtext;"`
|
||||||
DockerCompose string `json:"-" gorm:"type:longtext;not null"`
|
DockerCompose string `json:"-" gorm:"type:longtext;"`
|
||||||
Readme string `json:"readme" gorm:"type:longtext;"`
|
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"`
|
||||||
LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"`
|
LastModified int `json:"lastModified" gorm:"type:integer;"`
|
||||||
|
DownloadUrl string `json:"downloadUrl" gorm:"type:varchar;"`
|
||||||
|
DownloadCallBackUrl string `json:"downloadCallBackUrl" gorm:"type:longtext;"`
|
||||||
|
Update bool `json:"update"`
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type IAppRepo interface {
|
|||||||
GetByKey(ctx context.Context, key string) (model.App, error)
|
GetByKey(ctx context.Context, key string) (model.App, error)
|
||||||
Create(ctx context.Context, app *model.App) error
|
Create(ctx context.Context, app *model.App) error
|
||||||
Save(ctx context.Context, app *model.App) error
|
Save(ctx context.Context, app *model.App) error
|
||||||
|
BatchDelete(ctx context.Context, apps []model.App) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppRepo() IAppRepo {
|
func NewIAppRepo() IAppRepo {
|
||||||
@ -106,3 +107,7 @@ func (a AppRepo) Create(ctx context.Context, app *model.App) error {
|
|||||||
func (a AppRepo) Save(ctx context.Context, app *model.App) error {
|
func (a AppRepo) Save(ctx context.Context, app *model.App) error {
|
||||||
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppRepo) BatchDelete(ctx context.Context, apps []model.App) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Delete(&apps).Error
|
||||||
|
}
|
||||||
|
@ -5,14 +5,12 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
@ -253,7 +251,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
}
|
}
|
||||||
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if err = checkRequiredAndLimit(app); err != nil {
|
if err = checkRequiredAndLimit(app); err != nil {
|
||||||
return
|
return
|
||||||
@ -276,7 +274,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
|
|
||||||
value, ok := composeMap["services"]
|
value, ok := composeMap["services"]
|
||||||
if !ok {
|
if !ok {
|
||||||
err = buserr.New("")
|
err = buserr.New(constant.ErrFileParse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
servicesMap := value.(map[string]interface{})
|
servicesMap := value.(map[string]interface{})
|
||||||
@ -318,20 +316,11 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileOp := files.NewFileOp()
|
|
||||||
if err = fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
paramByte, err = json.Marshal(req.Params)
|
paramByte, err = json.Marshal(req.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
appInstall.Env = string(paramByte)
|
appInstall.Env = string(paramByte)
|
||||||
|
|
||||||
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -341,7 +330,13 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
if err = upAppPre(app, appInstall); err != nil {
|
if err = upAppPre(app, appInstall); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go upApp(appInstall)
|
go func() {
|
||||||
|
if err = downloadApp(app, appDetail, appInstall, req); err != nil {
|
||||||
|
_ = appInstallRepo.Save(ctx, appInstall)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
upApp(appInstall)
|
||||||
|
}()
|
||||||
go updateToolApp(appInstall)
|
go updateToolApp(appInstall)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -354,7 +349,7 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
|
versionUrl := fmt.Sprintf("%s/%s/1panel.json", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
||||||
versionRes, err := http.Get(versionUrl)
|
versionRes, err := http.Get(versionUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -368,162 +363,165 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
if err = json.Unmarshal(body, list); err != nil {
|
if err = json.Unmarshal(body, list); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res.Version = list.Version
|
res.AppStoreLastModified = list.LastModified
|
||||||
if setting.AppStoreVersion == "" || common.CompareVersion(list.Version, setting.AppStoreVersion) {
|
res.List = *list
|
||||||
|
|
||||||
|
appStoreLastModified, _ := strconv.Atoi(setting.AppStoreLastModified)
|
||||||
|
if setting.AppStoreLastModified == "" || list.LastModified > appStoreLastModified {
|
||||||
res.CanUpdate = true
|
res.CanUpdate = true
|
||||||
res.DownloadPath = fmt.Sprintf("%s/%s/%s/appstore/apps-%s.tar.gz", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion, list.Version)
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.CanUpdate = true
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) SyncAppListFromLocal() {
|
func (a AppService) SyncAppListFromLocal() {
|
||||||
fileOp := files.NewFileOp()
|
//fileOp := files.NewFileOp()
|
||||||
appDir := constant.LocalAppResourceDir
|
//appDir := constant.LocalAppResourceDir
|
||||||
listFile := path.Join(appDir, "list.json")
|
//listFile := path.Join(appDir, "list.json")
|
||||||
if !fileOp.Stat(listFile) {
|
//if !fileOp.Stat(listFile) {
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
global.LOG.Infof("start sync local apps...")
|
//global.LOG.Infof("start sync local apps...")
|
||||||
content, err := fileOp.GetContent(listFile)
|
//content, err := fileOp.GetContent(listFile)
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
global.LOG.Errorf("get list.json content failed %s", err.Error())
|
// global.LOG.Errorf("get list.json content failed %s", err.Error())
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
list := &dto.AppList{}
|
//list := &dto.AppList{}
|
||||||
if err := json.Unmarshal(content, list); err != nil {
|
//if err := json.Unmarshal(content, list); err != nil {
|
||||||
global.LOG.Errorf("unmarshal list.json failed %s", err.Error())
|
// global.LOG.Errorf("unmarshal list.json failed %s", err.Error())
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
|
//oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
|
||||||
appsMap := getApps(oldApps, list.Items, true)
|
//appsMap := getApps(oldApps, list.Apps, true)
|
||||||
for _, l := range list.Items {
|
//for _, l := range list.Apps {
|
||||||
localKey := "local" + l.Key
|
// localKey := "local" + l.Config.Key
|
||||||
app := appsMap[localKey]
|
// app := appsMap[localKey]
|
||||||
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
// icon, err := os.ReadFile(path.Join(appDir, l.Config.Key, "metadata", "logo.png"))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
|
// global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
iconStr := base64.StdEncoding.EncodeToString(icon)
|
// iconStr := base64.StdEncoding.EncodeToString(icon)
|
||||||
app.Icon = iconStr
|
// app.Icon = iconStr
|
||||||
app.TagsKey = append(l.Tags, "Local")
|
// app.TagsKey = append(l.Tags, "Local")
|
||||||
app.Recommend = 9999
|
// app.Recommend = 9999
|
||||||
versions := l.Versions
|
// versions := l.Versions
|
||||||
detailsMap := getAppDetails(app.Details, versions)
|
// detailsMap := getAppDetails(app.Details, versions)
|
||||||
|
//
|
||||||
for _, v := range versions {
|
// for _, v := range versions {
|
||||||
detail := detailsMap[v]
|
// detail := detailsMap[v]
|
||||||
detailPath := path.Join(appDir, l.Key, "versions", v)
|
// detailPath := path.Join(appDir, l.Key, "versions", v)
|
||||||
if _, err := os.Stat(detailPath); err != nil {
|
// if _, err := os.Stat(detailPath); err != nil {
|
||||||
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
|
// global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
|
// readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
|
// global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
|
||||||
}
|
// }
|
||||||
detail.Readme = string(readmeStr)
|
// detail.Readme = string(readmeStr)
|
||||||
dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
|
// dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
|
// global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
|
||||||
continue
|
// continue
|
||||||
}
|
// }
|
||||||
detail.DockerCompose = string(dockerComposeStr)
|
// detail.DockerCompose = string(dockerComposeStr)
|
||||||
paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
|
// paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
|
// global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
|
||||||
}
|
// }
|
||||||
detail.Params = string(paramStr)
|
// detail.Params = string(paramStr)
|
||||||
detailsMap[v] = detail
|
// detailsMap[v] = detail
|
||||||
}
|
// }
|
||||||
var newDetails []model.AppDetail
|
// var newDetails []model.AppDetail
|
||||||
for _, v := range detailsMap {
|
// for _, v := range detailsMap {
|
||||||
newDetails = append(newDetails, v)
|
// newDetails = append(newDetails, v)
|
||||||
}
|
// }
|
||||||
app.Details = newDetails
|
// app.Details = newDetails
|
||||||
appsMap[localKey] = app
|
// appsMap[localKey] = app
|
||||||
}
|
//}
|
||||||
var (
|
//var (
|
||||||
addAppArray []model.App
|
// addAppArray []model.App
|
||||||
updateArray []model.App
|
// updateArray []model.App
|
||||||
appIds []uint
|
// appIds []uint
|
||||||
)
|
//)
|
||||||
for _, v := range appsMap {
|
//for _, v := range appsMap {
|
||||||
if v.ID == 0 {
|
// if v.ID == 0 {
|
||||||
addAppArray = append(addAppArray, v)
|
// addAppArray = append(addAppArray, v)
|
||||||
} else {
|
// } else {
|
||||||
updateArray = append(updateArray, v)
|
// updateArray = append(updateArray, v)
|
||||||
appIds = append(appIds, v.ID)
|
// appIds = append(appIds, v.ID)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
tx, ctx := getTxAndContext()
|
//tx, ctx := getTxAndContext()
|
||||||
if len(addAppArray) > 0 {
|
//if len(addAppArray) > 0 {
|
||||||
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
// if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
for _, update := range updateArray {
|
//for _, update := range updateArray {
|
||||||
if err := appRepo.Save(ctx, &update); err != nil {
|
// if err := appRepo.Save(ctx, &update); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
if err := appTagRepo.DeleteByAppIds(ctx, appIds); err != nil {
|
//if err := appTagRepo.DeleteByAppIds(ctx, appIds); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
apps := append(addAppArray, updateArray...)
|
//apps := append(addAppArray, updateArray...)
|
||||||
var (
|
//var (
|
||||||
addDetails []model.AppDetail
|
// addDetails []model.AppDetail
|
||||||
updateDetails []model.AppDetail
|
// updateDetails []model.AppDetail
|
||||||
appTags []*model.AppTag
|
// appTags []*model.AppTag
|
||||||
)
|
//)
|
||||||
tags, _ := tagRepo.All()
|
//tags, _ := tagRepo.All()
|
||||||
tagMap := make(map[string]uint, len(tags))
|
//tagMap := make(map[string]uint, len(tags))
|
||||||
for _, app := range tags {
|
//for _, app := range tags {
|
||||||
tagMap[app.Key] = app.ID
|
// tagMap[app.Key] = app.ID
|
||||||
}
|
//}
|
||||||
for _, a := range apps {
|
//for _, a := range apps {
|
||||||
for _, t := range a.TagsKey {
|
// for _, t := range a.TagsKey {
|
||||||
tagId, ok := tagMap[t]
|
// tagId, ok := tagMap[t]
|
||||||
if ok {
|
// if ok {
|
||||||
appTags = append(appTags, &model.AppTag{
|
// appTags = append(appTags, &model.AppTag{
|
||||||
AppId: a.ID,
|
// AppId: a.ID,
|
||||||
TagId: tagId,
|
// TagId: tagId,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
for _, d := range a.Details {
|
// for _, d := range a.Details {
|
||||||
d.AppId = a.ID
|
// d.AppId = a.ID
|
||||||
if d.ID == 0 {
|
// if d.ID == 0 {
|
||||||
addDetails = append(addDetails, d)
|
// addDetails = append(addDetails, d)
|
||||||
} else {
|
// } else {
|
||||||
updateDetails = append(updateDetails, d)
|
// updateDetails = append(updateDetails, d)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
if len(addDetails) > 0 {
|
//if len(addDetails) > 0 {
|
||||||
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
// if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
for _, u := range updateDetails {
|
//for _, u := range updateDetails {
|
||||||
if err := appDetailRepo.Update(ctx, u); err != nil {
|
// if err := appDetailRepo.Update(ctx, u); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
if len(appTags) > 0 {
|
//if len(appTags) > 0 {
|
||||||
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
// if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
||||||
tx.Rollback()
|
// tx.Rollback()
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
tx.Commit()
|
//tx.Commit()
|
||||||
global.LOG.Infof("sync local apps success")
|
//global.LOG.Infof("sync local apps success")
|
||||||
}
|
}
|
||||||
func (a AppService) SyncAppListFromRemote() error {
|
func (a AppService) SyncAppListFromRemote() error {
|
||||||
updateRes, err := a.GetAppUpdate()
|
updateRes, err := a.GetAppUpdate()
|
||||||
@ -531,28 +529,15 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !updateRes.CanUpdate {
|
if !updateRes.CanUpdate {
|
||||||
global.LOG.Infof("The latest version is [%s] The app store is already up to date", updateRes.Version)
|
//global.LOG.Infof("The latest version is [%s] The app store is already up to date", updateRes.Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := getAppFromRepo(updateRes.DownloadPath, updateRes.Version); err != nil {
|
|
||||||
global.LOG.Errorf("get app from oss error: %s", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
appDir := constant.AppResourceDir
|
|
||||||
listFile := path.Join(appDir, "list.json")
|
|
||||||
content, err := os.ReadFile(listFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
list := &dto.AppList{}
|
|
||||||
if err := json.Unmarshal(content, list); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
tags []*model.Tag
|
tags []*model.Tag
|
||||||
appTags []*model.AppTag
|
appTags []*model.AppTag
|
||||||
|
list = updateRes.List
|
||||||
)
|
)
|
||||||
for _, t := range list.Tags {
|
for _, t := range list.Extra.Tags {
|
||||||
tags = append(tags, &model.Tag{
|
tags = append(tags, &model.Tag{
|
||||||
Key: t.Key,
|
Key: t.Key,
|
||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
@ -562,70 +547,86 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
appsMap := getApps(oldApps, list.Items, false)
|
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
||||||
for _, l := range list.Items {
|
appsMap := getApps(oldApps, list.Apps, false)
|
||||||
app := appsMap[l.Key]
|
for _, l := range list.Apps {
|
||||||
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
app := appsMap[l.AppProperty.Key]
|
||||||
|
iconRes, err := http.Get(l.Icon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
|
return err
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
iconStr := base64.StdEncoding.EncodeToString(icon)
|
body, err := io.ReadAll(iconRes.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iconStr := base64.StdEncoding.EncodeToString(body)
|
||||||
app.Icon = iconStr
|
app.Icon = iconStr
|
||||||
app.TagsKey = l.Tags
|
app.TagsKey = l.AppProperty.Tags
|
||||||
if l.Recommend > 0 {
|
if l.AppProperty.Recommend > 0 {
|
||||||
app.Recommend = l.Recommend
|
app.Recommend = l.AppProperty.Recommend
|
||||||
} else {
|
} else {
|
||||||
app.Recommend = 9999
|
app.Recommend = 9999
|
||||||
}
|
}
|
||||||
|
app.ReadMe = l.ReadMe
|
||||||
|
app.LastModified = l.LastModified
|
||||||
versions := l.Versions
|
versions := l.Versions
|
||||||
detailsMap := getAppDetails(app.Details, versions)
|
detailsMap := getAppDetails(app.Details, versions)
|
||||||
|
|
||||||
for _, v := range versions {
|
for _, v := range versions {
|
||||||
detail := detailsMap[v]
|
version := v.Name
|
||||||
detailPath := path.Join(appDir, l.Key, "versions", v)
|
detail := detailsMap[version]
|
||||||
if _, err := os.Stat(detailPath); err != nil {
|
|
||||||
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
|
dockerComposeUrl := fmt.Sprintf("%s/%s/%s/%s", baseRemoteUrl, app.Key, version, "docker-compose.yml")
|
||||||
continue
|
composeRes, err := http.Get(dockerComposeUrl)
|
||||||
}
|
|
||||||
readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
|
return err
|
||||||
}
|
}
|
||||||
detail.Readme = string(readmeStr)
|
bodyContent, err := io.ReadAll(composeRes.Body)
|
||||||
dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
|
return err
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
detail.DockerCompose = string(dockerComposeStr)
|
detail.DockerCompose = string(bodyContent)
|
||||||
paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
|
|
||||||
if err != nil {
|
paramByte, _ := json.Marshal(v.AppForm)
|
||||||
global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
|
detail.Params = string(paramByte)
|
||||||
|
detail.DownloadUrl = v.DownloadUrl
|
||||||
|
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
|
||||||
|
if v.LastModified > detail.LastModified {
|
||||||
|
detail.Update = true
|
||||||
|
detail.LastModified = v.LastModified
|
||||||
}
|
}
|
||||||
detail.Params = string(paramStr)
|
detailsMap[version] = detail
|
||||||
detailsMap[v] = detail
|
|
||||||
}
|
}
|
||||||
var newDetails []model.AppDetail
|
var newDetails []model.AppDetail
|
||||||
for _, v := range detailsMap {
|
for _, detail := range detailsMap {
|
||||||
newDetails = append(newDetails, v)
|
newDetails = append(newDetails, detail)
|
||||||
}
|
}
|
||||||
app.Details = newDetails
|
app.Details = newDetails
|
||||||
appsMap[l.Key] = app
|
appsMap[l.AppProperty.Key] = app
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
addAppArray []model.App
|
addAppArray []model.App
|
||||||
updateArray []model.App
|
updateAppArray []model.App
|
||||||
tagMap = make(map[string]uint, len(tags))
|
deleteAppArray []model.App
|
||||||
|
deleteIds []uint
|
||||||
|
tagMap = make(map[string]uint, len(tags))
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, v := range appsMap {
|
for _, v := range appsMap {
|
||||||
if v.ID == 0 {
|
if v.ID == 0 {
|
||||||
addAppArray = append(addAppArray, v)
|
addAppArray = append(addAppArray, v)
|
||||||
} else {
|
} else {
|
||||||
updateArray = append(updateArray, v)
|
if v.Status == constant.AppTakeDown {
|
||||||
|
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(v.ID))
|
||||||
|
if len(installs) > 0 {
|
||||||
|
updateAppArray = append(updateAppArray, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
deleteAppArray = append(deleteAppArray, v)
|
||||||
|
deleteIds = append(deleteIds, v.ID)
|
||||||
|
} else {
|
||||||
|
updateAppArray = append(updateAppArray, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx, ctx := getTxAndContext()
|
tx, ctx := getTxAndContext()
|
||||||
@ -635,6 +636,16 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(deleteAppArray) > 0 {
|
||||||
|
if err := appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := tagRepo.DeleteAll(ctx); err != nil {
|
if err := tagRepo.DeleteAll(ctx); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
@ -648,34 +659,39 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
tagMap[t.Key] = t.ID
|
tagMap[t.Key] = t.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, update := range updateArray {
|
for _, update := range updateAppArray {
|
||||||
if err := appRepo.Save(ctx, &update); err != nil {
|
if err := appRepo.Save(ctx, &update); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apps := append(addAppArray, updateArray...)
|
apps := append(addAppArray, updateAppArray...)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
addDetails []model.AppDetail
|
addDetails []model.AppDetail
|
||||||
updateDetails []model.AppDetail
|
updateDetails []model.AppDetail
|
||||||
|
deleteDetails []model.AppDetail
|
||||||
)
|
)
|
||||||
for _, a := range apps {
|
for _, app := range apps {
|
||||||
for _, t := range a.TagsKey {
|
for _, t := range app.TagsKey {
|
||||||
tagId, ok := tagMap[t]
|
tagId, ok := tagMap[t]
|
||||||
if ok {
|
if ok {
|
||||||
appTags = append(appTags, &model.AppTag{
|
appTags = append(appTags, &model.AppTag{
|
||||||
AppId: a.ID,
|
AppId: app.ID,
|
||||||
TagId: tagId,
|
TagId: tagId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, d := range a.Details {
|
for _, d := range app.Details {
|
||||||
d.AppId = a.ID
|
d.AppId = app.ID
|
||||||
if d.ID == 0 {
|
if d.ID == 0 {
|
||||||
addDetails = append(addDetails, d)
|
addDetails = append(addDetails, d)
|
||||||
} else {
|
} else {
|
||||||
updateDetails = append(updateDetails, d)
|
if d.Status == constant.AppTakeDown {
|
||||||
|
deleteDetails = append(deleteDetails, d)
|
||||||
|
} else {
|
||||||
|
updateDetails = append(updateDetails, d)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -691,6 +707,7 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := appTagRepo.DeleteAll(ctx); err != nil {
|
if err := appTagRepo.DeleteAll(ctx); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
@ -702,5 +719,8 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
|
if err := NewISettingService().Update("AppStoreLastModified", strconv.Itoa(list.LastModified)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -183,6 +184,9 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !req.ForceDelete && !files.NewFileOp().Stat(install.GetPath()) {
|
||||||
|
return buserr.New(constant.ErrInstallDirNotFound)
|
||||||
|
}
|
||||||
dockerComposePath := install.GetComposePath()
|
dockerComposePath := install.GetComposePath()
|
||||||
switch req.Operate {
|
switch req.Operate {
|
||||||
case constant.Rebuild:
|
case constant.Rebuild:
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/compose-spec/compose-go/types"
|
"github.com/compose-spec/compose-go/types"
|
||||||
"github.com/subosito/gotenv"
|
"github.com/subosito/gotenv"
|
||||||
"math"
|
"math"
|
||||||
@ -225,7 +226,7 @@ func upgradeInstall(installId uint, detailId uint) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Key, "versions", detail.Version)
|
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
|
||||||
if install.App.Resource == constant.AppResourceLocal {
|
if install.App.Resource == constant.AppResourceLocal {
|
||||||
detailDir = path.Join(constant.ResourceDir, "localApps", strings.TrimPrefix(install.App.Key, "local"), "versions", detail.Version)
|
detailDir = path.Join(constant.ResourceDir, "localApps", strings.TrimPrefix(install.App.Key, "local"), "versions", detail.Version)
|
||||||
}
|
}
|
||||||
@ -359,24 +360,48 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyAppData(key, version, installName string, params map[string]interface{}, isLocal bool) (err error) {
|
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, req request.AppInstallCreate) (err error) {
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
appResourceDir := constant.AppResourceDir
|
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
|
||||||
installAppDir := path.Join(constant.AppInstallDir, key)
|
|
||||||
appKey := key
|
if app.Resource == constant.AppResourceRemote && appDetail.Update {
|
||||||
if isLocal {
|
appDownloadDir := path.Join(appResourceDir, app.Key)
|
||||||
|
if !fileOp.Stat(appDownloadDir) {
|
||||||
|
_ = fileOp.CreateDir(appDownloadDir, 0755)
|
||||||
|
}
|
||||||
|
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
|
||||||
|
if !fileOp.Stat(appVersionDir) {
|
||||||
|
_ = fileOp.CreateDir(appVersionDir, 0755)
|
||||||
|
}
|
||||||
|
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
|
||||||
|
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
|
||||||
|
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
|
||||||
|
appInstall.Status = constant.DownloadErr
|
||||||
|
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
|
||||||
|
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
|
||||||
|
appInstall.Status = constant.DownloadErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = fileOp.DeleteFile(filePath)
|
||||||
|
}
|
||||||
|
appKey := app.Key
|
||||||
|
installAppDir := path.Join(constant.AppInstallDir, app.Key)
|
||||||
|
if app.Resource == constant.AppResourceLocal {
|
||||||
appResourceDir = constant.LocalAppResourceDir
|
appResourceDir = constant.LocalAppResourceDir
|
||||||
appKey = strings.TrimPrefix(key, "local")
|
appKey = strings.TrimPrefix(app.Resource, "local")
|
||||||
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
||||||
}
|
}
|
||||||
resourceDir := path.Join(appResourceDir, appKey, "versions", version)
|
resourceDir := path.Join(appResourceDir, appKey, appDetail.Version)
|
||||||
|
|
||||||
if !fileOp.Stat(installAppDir) {
|
if !fileOp.Stat(installAppDir) {
|
||||||
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appDir := path.Join(installAppDir, installName)
|
appDir := path.Join(installAppDir, req.Name)
|
||||||
if fileOp.Stat(appDir) {
|
if fileOp.Stat(appDir) {
|
||||||
if err = fileOp.DeleteDir(appDir); err != nil {
|
if err = fileOp.DeleteDir(appDir); err != nil {
|
||||||
return
|
return
|
||||||
@ -385,14 +410,14 @@ func copyAppData(key, version, installName string, params map[string]interface{}
|
|||||||
if err = fileOp.Copy(resourceDir, installAppDir); err != nil {
|
if err = fileOp.Copy(resourceDir, installAppDir); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
versionDir := path.Join(installAppDir, version)
|
versionDir := path.Join(installAppDir, appDetail.Version)
|
||||||
if err = fileOp.Rename(versionDir, appDir); err != nil {
|
if err = fileOp.Rename(versionDir, appDir); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
envPath := path.Join(appDir, ".env")
|
envPath := path.Join(appDir, ".env")
|
||||||
|
|
||||||
envParams := make(map[string]string, len(params))
|
envParams := make(map[string]string, len(req.Params))
|
||||||
handleMap(params, envParams)
|
handleMap(req.Params, envParams)
|
||||||
if err = env.Write(envParams, envPath); err != nil {
|
if err = env.Write(envParams, envPath); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -473,21 +498,21 @@ func rebuildApp(appInstall model.AppInstall) error {
|
|||||||
return syncById(appInstall.ID)
|
return syncById(appInstall.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
|
func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) map[string]model.AppDetail {
|
||||||
appDetails := make(map[string]model.AppDetail, len(details))
|
appDetails := make(map[string]model.AppDetail, len(details))
|
||||||
for _, old := range details {
|
for _, old := range details {
|
||||||
old.Status = constant.AppTakeDown
|
old.Status = constant.AppTakeDown
|
||||||
appDetails[old.Version] = old
|
appDetails[old.Version] = old
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range versions {
|
for _, v := range versions {
|
||||||
detail, ok := appDetails[v]
|
version := v.Name
|
||||||
|
detail, ok := appDetails[version]
|
||||||
if ok {
|
if ok {
|
||||||
detail.Status = constant.AppNormal
|
detail.Status = constant.AppNormal
|
||||||
appDetails[v] = detail
|
appDetails[version] = detail
|
||||||
} else {
|
} else {
|
||||||
appDetails[v] = model.AppDetail{
|
appDetails[version] = model.AppDetail{
|
||||||
Version: v,
|
Version: version,
|
||||||
Status: constant.AppNormal,
|
Status: constant.AppNormal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,7 +527,8 @@ func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[strin
|
|||||||
apps[old.Key] = old
|
apps[old.Key] = old
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
key := item.Key
|
config := item.AppProperty
|
||||||
|
key := config.Key
|
||||||
if isLocal {
|
if isLocal {
|
||||||
key = "local" + key
|
key = "local" + key
|
||||||
}
|
}
|
||||||
@ -516,17 +542,19 @@ func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[strin
|
|||||||
app.Resource = constant.AppResourceRemote
|
app.Resource = constant.AppResourceRemote
|
||||||
}
|
}
|
||||||
app.Name = item.Name
|
app.Name = item.Name
|
||||||
app.Limit = item.Limit
|
app.Limit = config.Limit
|
||||||
app.Key = key
|
app.Key = key
|
||||||
app.ShortDescZh = item.ShortDescZh
|
app.ShortDescZh = config.ShortDescZh
|
||||||
app.ShortDescEn = item.ShortDescEn
|
app.ShortDescEn = config.ShortDescEn
|
||||||
app.Website = item.Website
|
app.Website = config.Website
|
||||||
app.Document = item.Document
|
app.Document = config.Document
|
||||||
app.Github = item.Github
|
app.Github = config.Github
|
||||||
app.Type = item.Type
|
app.Type = config.Type
|
||||||
app.CrossVersionUpdate = item.CrossVersionUpdate
|
app.CrossVersionUpdate = config.CrossVersionUpdate
|
||||||
app.Required = item.GetRequired()
|
app.Required = config.GetRequired()
|
||||||
app.Status = constant.AppNormal
|
app.Status = constant.AppNormal
|
||||||
|
app.LastModified = item.LastModified
|
||||||
|
app.ReadMe = item.ReadMe
|
||||||
apps[key] = app
|
apps[key] = app
|
||||||
}
|
}
|
||||||
return apps
|
return apps
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
package configs
|
package configs
|
||||||
|
|
||||||
type System struct {
|
type System struct {
|
||||||
Port string `mapstructure:"port"`
|
Port string `mapstructure:"port"`
|
||||||
SSL string `mapstructure:"ssl"`
|
SSL string `mapstructure:"ssl"`
|
||||||
DbFile string `mapstructure:"db_file"`
|
DbFile string `mapstructure:"db_file"`
|
||||||
DbPath string `mapstructure:"db_path"`
|
DbPath string `mapstructure:"db_path"`
|
||||||
LogPath string `mapstructure:"log_path"`
|
LogPath string `mapstructure:"log_path"`
|
||||||
DataDir string `mapstructure:"data_dir"`
|
DataDir string `mapstructure:"data_dir"`
|
||||||
TmpDir string `mapstructure:"tmp_dir"`
|
TmpDir string `mapstructure:"tmp_dir"`
|
||||||
Cache string `mapstructure:"cache"`
|
Cache string `mapstructure:"cache"`
|
||||||
Backup string `mapstructure:"backup"`
|
Backup string `mapstructure:"backup"`
|
||||||
EncryptKey string `mapstructure:"encrypt_key"`
|
EncryptKey string `mapstructure:"encrypt_key"`
|
||||||
BaseDir string `mapstructure:"base_dir"`
|
BaseDir string `mapstructure:"base_dir"`
|
||||||
Mode string `mapstructure:"mode"`
|
Mode string `mapstructure:"mode"`
|
||||||
RepoUrl string `mapstructure:"repo_url"`
|
RepoUrl string `mapstructure:"repo_url"`
|
||||||
Version string `mapstructure:"version"`
|
Version string `mapstructure:"version"`
|
||||||
Username string `mapstructure:"username"`
|
Username string `mapstructure:"username"`
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
Entrance string `mapstructure:"entrance"`
|
Entrance string `mapstructure:"entrance"`
|
||||||
IsDemo bool `mapstructure:"is_demo"`
|
IsDemo bool `mapstructure:"is_demo"`
|
||||||
|
AppRepo string `mapstructure:"app_repo"`
|
||||||
ChangeUserInfo bool `mapstructure:"change_user_info"`
|
ChangeUserInfo bool `mapstructure:"change_user_info"`
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Running = "Running"
|
Running = "Running"
|
||||||
UnHealthy = "UnHealthy"
|
UnHealthy = "UnHealthy"
|
||||||
Error = "Error"
|
Error = "Error"
|
||||||
Stopped = "Stopped"
|
Stopped = "Stopped"
|
||||||
Installing = "Installing"
|
Installing = "Installing"
|
||||||
Syncing = "Syncing"
|
Syncing = "Syncing"
|
||||||
|
DownloadErr = "DownloadErr"
|
||||||
|
DirNotFound = "DirNotFound"
|
||||||
|
|
||||||
ContainerPrefix = "1Panel-"
|
ContainerPrefix = "1Panel-"
|
||||||
|
|
||||||
|
@ -30,23 +30,16 @@ var (
|
|||||||
ErrInvalidParams = errors.New("ErrInvalidParams")
|
ErrInvalidParams = errors.New("ErrInvalidParams")
|
||||||
|
|
||||||
ErrTokenParse = errors.New("ErrTokenParse")
|
ErrTokenParse = errors.New("ErrTokenParse")
|
||||||
|
|
||||||
ErrPageGenerate = errors.New("generate page info failed")
|
|
||||||
ErrRepoNotValid = "ErrRepoNotValid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// api
|
// api
|
||||||
var (
|
var (
|
||||||
ErrTypeInternalServer = "ErrInternalServer"
|
ErrTypeInternalServer = "ErrInternalServer"
|
||||||
ErrTypeInvalidParams = "ErrInvalidParams"
|
ErrTypeInvalidParams = "ErrInvalidParams"
|
||||||
ErrTypeToken = "ErrToken"
|
|
||||||
ErrTypeTokenTimeOut = "ErrTokenTimeOut"
|
|
||||||
ErrTypeNotLogin = "ErrNotLogin"
|
ErrTypeNotLogin = "ErrNotLogin"
|
||||||
ErrTypePasswordExpired = "ErrPasswordExpired"
|
ErrTypePasswordExpired = "ErrPasswordExpired"
|
||||||
ErrTypeNotSafety = "ErrNotSafety"
|
|
||||||
ErrNameIsExist = "ErrNameIsExist"
|
ErrNameIsExist = "ErrNameIsExist"
|
||||||
ErrDemoEnvironment = "ErrDemoEnvironment"
|
ErrDemoEnvironment = "ErrDemoEnvironment"
|
||||||
ErrInitUser = "ErrInitUser"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// app
|
// app
|
||||||
@ -55,20 +48,20 @@ var (
|
|||||||
ErrAppLimit = "ErrAppLimit"
|
ErrAppLimit = "ErrAppLimit"
|
||||||
ErrAppRequired = "ErrAppRequired"
|
ErrAppRequired = "ErrAppRequired"
|
||||||
ErrFileCanNotRead = "ErrFileCanNotRead"
|
ErrFileCanNotRead = "ErrFileCanNotRead"
|
||||||
ErrFileToLarge = "ErrFileToLarge"
|
|
||||||
ErrNotInstall = "ErrNotInstall"
|
ErrNotInstall = "ErrNotInstall"
|
||||||
ErrPortInOtherApp = "ErrPortInOtherApp"
|
ErrPortInOtherApp = "ErrPortInOtherApp"
|
||||||
ErrDbUserNotValid = "ErrDbUserNotValid"
|
ErrDbUserNotValid = "ErrDbUserNotValid"
|
||||||
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
||||||
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
|
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
|
||||||
ErrCmdTimeout = "ErrCmdTimeout"
|
ErrCmdTimeout = "ErrCmdTimeout"
|
||||||
|
ErrFileParse = "ErrFileParse"
|
||||||
|
ErrInstallDirNotFound = "ErrInstallDirNotFound"
|
||||||
)
|
)
|
||||||
|
|
||||||
// website
|
// website
|
||||||
var (
|
var (
|
||||||
ErrDomainIsExist = "ErrDomainIsExist"
|
ErrDomainIsExist = "ErrDomainIsExist"
|
||||||
ErrAliasIsExist = "ErrAliasIsExist"
|
ErrAliasIsExist = "ErrAliasIsExist"
|
||||||
ErrAppDelete = "ErrAppDelete"
|
|
||||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||||
ErrUsernameIsExist = "ErrUsernameIsExist"
|
ErrUsernameIsExist = "ErrUsernameIsExist"
|
||||||
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
|
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
|
||||||
|
@ -29,6 +29,8 @@ ErrDbUserNotValid: "Stock database, username and password do not match!"
|
|||||||
ErrDockerComposeNotValid: "docker-compose file format error!"
|
ErrDockerComposeNotValid: "docker-compose file format error!"
|
||||||
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
|
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
|
||||||
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
|
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
|
||||||
|
ErrFileParse: 'Application docker-compose file parsing failed!'
|
||||||
|
ErrInstallDirNotFound: 'installation directory does not exist'
|
||||||
|
|
||||||
#file
|
#file
|
||||||
ErrFileCanNotRead: "File can not read"
|
ErrFileCanNotRead: "File can not read"
|
||||||
|
@ -29,6 +29,8 @@ ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
|
|||||||
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
|
||||||
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
|
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
|
||||||
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
|
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
|
||||||
|
ErrFileParse: '应用 docker-compose 文件解析失败!'
|
||||||
|
ErrInstallDirNotFound: '安装目录不存在'
|
||||||
|
|
||||||
#file
|
#file
|
||||||
ErrFileCanNotRead: "此文件不支持预览"
|
ErrFileCanNotRead: "此文件不支持预览"
|
||||||
|
@ -26,6 +26,8 @@ func Init() {
|
|||||||
migrations.UpdateTableHost,
|
migrations.UpdateTableHost,
|
||||||
migrations.UpdateTableWebsite,
|
migrations.UpdateTableWebsite,
|
||||||
migrations.AddEntranceAndSSL,
|
migrations.AddEntranceAndSSL,
|
||||||
|
migrations.UpdateTableSetting,
|
||||||
|
migrations.UpdateTableAppDetail,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
@ -312,3 +312,26 @@ var AddEntranceAndSSL = &gormigrate.Migration{
|
|||||||
return tx.AutoMigrate(&model.Website{})
|
return tx.AutoMigrate(&model.Website{})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateTableSetting = &gormigrate.Migration{
|
||||||
|
ID: "20200511-update-table-setting",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.App{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Create(&model.Setting{Key: "AppStoreLastModified", Value: ""}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var UpdateTableAppDetail = &gormigrate.Migration{
|
||||||
|
ID: "20200513-update-table-app-detail",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.AppDetail{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ system:
|
|||||||
base_dir: /opt
|
base_dir: /opt
|
||||||
mode: dev
|
mode: dev
|
||||||
repo_url: https://resource.fit2cloud.com/1panel/package
|
repo_url: https://resource.fit2cloud.com/1panel/package
|
||||||
|
app_repo: https://apps-assets.fit2cloud.com
|
||||||
is_demo: false
|
is_demo: false
|
||||||
port: 9999
|
port: 9999
|
||||||
username: admin
|
username: admin
|
||||||
|
@ -11,6 +11,7 @@ export namespace App {
|
|||||||
author: string;
|
author: string;
|
||||||
source: string;
|
source: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppDTO extends App {
|
export interface AppDTO extends App {
|
||||||
|
@ -84,6 +84,9 @@
|
|||||||
{{ language == 'zh' ? tag.name : tag.key }}
|
{{ language == 'zh' ? tag.name : tag.key }}
|
||||||
</span>
|
</span>
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
<el-tag v-if="app.status === 'TakeDown'" style="margin-right: 5px">
|
||||||
|
<span style="color: red">已废弃</span>
|
||||||
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -82,12 +82,8 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-loading="loadingDetail" style="margin-left: 10px">
|
<div style="margin-left: 10px">
|
||||||
<MdEditor
|
<MdEditor v-model="app.readMe" previewOnly :theme="globalStore.$state.themeConfig.theme || 'light'" />
|
||||||
v-model="appDetail.readme"
|
|
||||||
previewOnly
|
|
||||||
:theme="globalStore.$state.themeConfig.theme || 'light'"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
|
Loading…
Reference in New Issue
Block a user