Skip to content

Commit adbf44a

Browse files
fix: Fix issue where website group can still be deleted even if it contains other websites (#8049)
1 parent 451b690 commit adbf44a

File tree

27 files changed

+619
-13
lines changed

27 files changed

+619
-13
lines changed

agent/app/api/v2/entry.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,5 @@ var (
6767

6868
websiteCAService = service.NewIWebsiteCAService()
6969
taskService = service.NewITaskService()
70+
groupService = service.NewIGroupService()
7071
)

agent/app/api/v2/group.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package v2
2+
3+
import (
4+
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
5+
"github.com/1Panel-dev/1Panel/agent/app/dto"
6+
"github.com/gin-gonic/gin"
7+
)
8+
9+
// @Tags System Group
10+
// @Summary Create group
11+
// @Accept json
12+
// @Param request body dto.GroupCreate true "request"
13+
// @Success 200
14+
// @Security ApiKeyAuth
15+
// @Security Timestamp
16+
// @Router /agent/groups [post]
17+
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
18+
func (b *BaseApi) CreateGroup(c *gin.Context) {
19+
var req dto.GroupCreate
20+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
21+
return
22+
}
23+
24+
if err := groupService.Create(req); err != nil {
25+
helper.InternalServer(c, err)
26+
return
27+
}
28+
helper.SuccessWithOutData(c)
29+
}
30+
31+
// @Tags System Group
32+
// @Summary Delete group
33+
// @Accept json
34+
// @Param request body dto.OperateByID true "request"
35+
// @Success 200
36+
// @Security ApiKeyAuth
37+
// @Security Timestamp
38+
// @Router /agent/groups/del [post]
39+
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
40+
func (b *BaseApi) DeleteGroup(c *gin.Context) {
41+
var req dto.OperateByID
42+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
43+
return
44+
}
45+
46+
if err := groupService.Delete(req.ID); err != nil {
47+
helper.InternalServer(c, err)
48+
return
49+
}
50+
helper.SuccessWithOutData(c)
51+
}
52+
53+
// @Tags System Group
54+
// @Summary Update group
55+
// @Accept json
56+
// @Param request body dto.GroupUpdate true "request"
57+
// @Success 200
58+
// @Security ApiKeyAuth
59+
// @Security Timestamp
60+
// @Router /agent/groups/update [post]
61+
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
62+
func (b *BaseApi) UpdateGroup(c *gin.Context) {
63+
var req dto.GroupUpdate
64+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
65+
return
66+
}
67+
68+
if err := groupService.Update(req); err != nil {
69+
helper.InternalServer(c, err)
70+
return
71+
}
72+
helper.SuccessWithOutData(c)
73+
}
74+
75+
// @Tags System Group
76+
// @Summary List groups
77+
// @Accept json
78+
// @Param request body dto.GroupSearch true "request"
79+
// @Success 200 {array} dto.OperateByType
80+
// @Security ApiKeyAuth
81+
// @Security Timestamp
82+
// @Router /agent/groups/search [post]
83+
func (b *BaseApi) ListGroup(c *gin.Context) {
84+
var req dto.OperateByType
85+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
86+
return
87+
}
88+
89+
list, err := groupService.List(req)
90+
if err != nil {
91+
helper.InternalServer(c, err)
92+
return
93+
}
94+
95+
helper.SuccessWithData(c, list)
96+
}

agent/app/dto/group.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package dto
2+
3+
type GroupCreate struct {
4+
ID uint `json:"id"`
5+
Name string `json:"name" validate:"required"`
6+
Type string `json:"type" validate:"required"`
7+
}
8+
9+
type GroupSearch struct {
10+
Type string `json:"type" validate:"required"`
11+
}
12+
13+
type GroupUpdate struct {
14+
ID uint `json:"id"`
15+
Name string `json:"name"`
16+
Type string `json:"type" validate:"required"`
17+
IsDefault bool `json:"isDefault"`
18+
}
19+
20+
type GroupInfo struct {
21+
ID uint `json:"id"`
22+
Name string `json:"name"`
23+
Type string `json:"type"`
24+
IsDefault bool `json:"isDefault"`
25+
}
26+
27+
type OperateByType struct {
28+
Type string `json:"type"`
29+
}

agent/app/model/group.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package model
2+
3+
type Group struct {
4+
BaseModel
5+
IsDefault bool `json:"isDefault"`
6+
Name string `json:"name"`
7+
Type string `json:"type"`
8+
}

agent/app/repo/group.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package repo
2+
3+
import (
4+
"github.com/1Panel-dev/1Panel/agent/app/model"
5+
"github.com/1Panel-dev/1Panel/agent/global"
6+
)
7+
8+
type GroupRepo struct{}
9+
10+
type IGroupRepo interface {
11+
Get(opts ...DBOption) (model.Group, error)
12+
GetList(opts ...DBOption) ([]model.Group, error)
13+
Create(group *model.Group) error
14+
Update(id uint, vars map[string]interface{}) error
15+
Delete(opts ...DBOption) error
16+
}
17+
18+
func NewIGroupRepo() IGroupRepo {
19+
return &GroupRepo{}
20+
}
21+
22+
func (g *GroupRepo) Get(opts ...DBOption) (model.Group, error) {
23+
var group model.Group
24+
db := global.DB
25+
for _, opt := range opts {
26+
db = opt(db)
27+
}
28+
err := db.First(&group).Error
29+
return group, err
30+
}
31+
32+
func (g *GroupRepo) GetList(opts ...DBOption) ([]model.Group, error) {
33+
var groups []model.Group
34+
db := global.DB.Model(&model.Group{})
35+
for _, opt := range opts {
36+
db = opt(db)
37+
}
38+
err := db.Find(&groups).Error
39+
return groups, err
40+
}
41+
42+
func (g *GroupRepo) Create(group *model.Group) error {
43+
return global.DB.Create(group).Error
44+
}
45+
46+
func (g *GroupRepo) Update(id uint, vars map[string]interface{}) error {
47+
return global.DB.Model(&model.Group{}).Where("id = ?", id).Updates(vars).Error
48+
}
49+
50+
func (g *GroupRepo) Delete(opts ...DBOption) error {
51+
db := global.DB
52+
for _, opt := range opts {
53+
db = opt(db)
54+
}
55+
return db.Delete(&model.Group{}).Error
56+
}

agent/app/service/entry.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,6 @@ var (
4545
favoriteRepo = repo.NewIFavoriteRepo()
4646

4747
taskRepo = repo.NewITaskRepo()
48+
49+
groupRepo = repo.NewIGroupRepo()
4850
)

agent/app/service/group.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package service
2+
3+
import (
4+
"github.com/1Panel-dev/1Panel/agent/app/dto"
5+
"github.com/1Panel-dev/1Panel/agent/app/model"
6+
"github.com/1Panel-dev/1Panel/agent/app/repo"
7+
"github.com/1Panel-dev/1Panel/agent/buserr"
8+
"github.com/jinzhu/copier"
9+
)
10+
11+
type GroupService struct{}
12+
13+
type IGroupService interface {
14+
List(req dto.OperateByType) ([]dto.GroupInfo, error)
15+
Create(req dto.GroupCreate) error
16+
Update(req dto.GroupUpdate) error
17+
Delete(id uint) error
18+
}
19+
20+
func NewIGroupService() IGroupService {
21+
return &GroupService{}
22+
}
23+
24+
func (u *GroupService) List(req dto.OperateByType) ([]dto.GroupInfo, error) {
25+
options := []repo.DBOption{
26+
repo.WithOrderBy("is_default desc"),
27+
repo.WithOrderBy("created_at desc"),
28+
}
29+
if len(req.Type) != 0 {
30+
options = append(options, repo.WithByType(req.Type))
31+
}
32+
var (
33+
groups []model.Group
34+
err error
35+
)
36+
groups, err = groupRepo.GetList(options...)
37+
if err != nil {
38+
return nil, buserr.New("ErrRecordNotFound")
39+
}
40+
var dtoUsers []dto.GroupInfo
41+
for _, group := range groups {
42+
var item dto.GroupInfo
43+
if err := copier.Copy(&item, &group); err != nil {
44+
return nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
45+
}
46+
dtoUsers = append(dtoUsers, item)
47+
}
48+
return dtoUsers, err
49+
}
50+
51+
func (u *GroupService) Create(req dto.GroupCreate) error {
52+
group, _ := groupRepo.Get(repo.WithByName(req.Name), repo.WithByType(req.Type))
53+
if group.ID != 0 {
54+
return buserr.New("ErrRecordExist")
55+
}
56+
if err := copier.Copy(&group, &req); err != nil {
57+
return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
58+
}
59+
if err := groupRepo.Create(&group); err != nil {
60+
return err
61+
}
62+
return nil
63+
}
64+
65+
func (u *GroupService) Delete(id uint) error {
66+
group, _ := groupRepo.Get(repo.WithByID(id))
67+
if group.ID == 0 {
68+
return buserr.New("ErrRecordNotFound")
69+
}
70+
if group.IsDefault {
71+
return buserr.New("ErrGroupIsDefault")
72+
}
73+
if group.Type == "website" {
74+
websites, _ := websiteRepo.List(websiteRepo.WithGroupID(group.ID))
75+
if len(websites) > 0 {
76+
return buserr.New("ErrGroupIsInWebsiteUse")
77+
}
78+
}
79+
return groupRepo.Delete(repo.WithByID(id))
80+
}
81+
82+
func (u *GroupService) Update(req dto.GroupUpdate) error {
83+
upMap := make(map[string]interface{})
84+
upMap["name"] = req.Name
85+
upMap["is_default"] = req.IsDefault
86+
return groupRepo.Update(req.ID, upMap)
87+
}

agent/i18n/lang/en.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ ErrTypePort: "Port {{ .name }} format error"
1919
Success: "Success"
2020
Failed: "Failed"
2121
SystemRestart: "System restart causes task interruption"
22+
ErrGroupIsDefault: "Default group, cannot be deleted"
23+
ErrGroupIsInWebsiteUse: "Group is being used by other websites, cannot be deleted"
2224

2325
#backup
2426
ErrBackupLocalDelete: "Deleting local server backup accounts is not currently supported."

agent/i18n/lang/ja.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ ErrTypePortRange: 'ポートレンジは1-65535の間である必要がありま
2828
Success: "成功"
2929
Failed: "失敗した"
3030
SystemRestart: "システムの再起動により、タスクが中断されます"
31+
ErrGroupIsDefault: "デフォルトグループ、削除できません"
32+
ErrGroupIsInWebsiteUse: "グループは他のウェブサイトで使用されています、削除できません"
3133

3234
#app
3335
ErrPortInUsed: "{{.Detail}}ポートはすでに使用されています"

agent/i18n/lang/ko.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ ErrTypePortRange: '포트 범위는 1-65535 사이여야 합니다'
2929
Success: "성공"
3030
Failed: "실패"
3131
SystemRestart: "시스템 재시작으로 인해 작업이 중단되었습니다"
32+
ErrGroupIsDefault: "기본 그룹, 삭제할 수 없습니다"
33+
ErrGroupIsInWebsiteUse: "그룹이 다른 웹사이트에서 사용 중입니다, 삭제할 수 없습니다"
3234

3335
# 애플리케이션
3436
ErrPortInUsed: "{{ .detail }} 포트가 이미 사용 중입니다"

0 commit comments

Comments
 (0)