feat(api): implement sorting functionality for nodes and servers
This commit is contained in:
parent
d4850a73f3
commit
26b2afe06d
@ -102,6 +102,7 @@ func (adapter *Adapter) Proxies(servers []*node.Node) ([]Proxy, error) {
|
|||||||
for _, protocol := range protocols {
|
for _, protocol := range protocols {
|
||||||
if protocol.Type == item.Protocol {
|
if protocol.Type == item.Protocol {
|
||||||
proxies = append(proxies, Proxy{
|
proxies = append(proxies, Proxy{
|
||||||
|
Sort: item.Sort,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
Server: item.Address,
|
Server: item.Address,
|
||||||
Port: item.Port,
|
Port: item.Port,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
|
Sort int
|
||||||
Name string
|
Name string
|
||||||
Server string
|
Server string
|
||||||
Port uint16
|
Port uint16
|
||||||
|
|||||||
@ -165,9 +165,7 @@ type (
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
ResetSortRequest {
|
ResetSortRequest {
|
||||||
Page int `json:"page"`
|
Sort []SortItem `json:"sort"`
|
||||||
Size int `json:"size"`
|
|
||||||
Sort []int64 `json:"sort"`
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,13 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/internal/model/node"
|
||||||
"github.com/perfect-panel/server/internal/svc"
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
"github.com/perfect-panel/server/internal/types"
|
"github.com/perfect-panel/server/internal/types"
|
||||||
"github.com/perfect-panel/server/pkg/logger"
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResetSortWithNodeLogic struct {
|
type ResetSortWithNodeLogic struct {
|
||||||
@ -14,7 +18,7 @@ type ResetSortWithNodeLogic struct {
|
|||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset node sort
|
// NewResetSortWithNodeLogic Reset node sort
|
||||||
func NewResetSortWithNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetSortWithNodeLogic {
|
func NewResetSortWithNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ResetSortWithNodeLogic {
|
||||||
return &ResetSortWithNodeLogic{
|
return &ResetSortWithNodeLogic{
|
||||||
Logger: logger.WithContext(ctx),
|
Logger: logger.WithContext(ctx),
|
||||||
@ -24,7 +28,59 @@ func NewResetSortWithNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *ResetSortWithNodeLogic) ResetSortWithNode(req *types.ResetSortRequest) error {
|
func (l *ResetSortWithNodeLogic) ResetSortWithNode(req *types.ResetSortRequest) error {
|
||||||
// todo: add your logic here and delete this line
|
err := l.svcCtx.NodeModel.Transaction(l.ctx, func(db *gorm.DB) error {
|
||||||
|
// find all servers id
|
||||||
|
var existingIDs []int64
|
||||||
|
db.Model(&node.Node{}).Select("id").Find(&existingIDs)
|
||||||
|
// check if the id is valid
|
||||||
|
validIDMap := make(map[int64]bool)
|
||||||
|
for _, id := range existingIDs {
|
||||||
|
validIDMap[id] = true
|
||||||
|
}
|
||||||
|
// check if the sort is valid
|
||||||
|
var validItems []types.SortItem
|
||||||
|
for _, item := range req.Sort {
|
||||||
|
if validIDMap[item.Id] {
|
||||||
|
validItems = append(validItems, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// query all servers
|
||||||
|
var servers []*node.Node
|
||||||
|
db.Model(&node.Node{}).Order("sort ASC").Find(&servers)
|
||||||
|
// create a map of the current sort
|
||||||
|
currentSortMap := make(map[int64]int64)
|
||||||
|
for _, item := range servers {
|
||||||
|
currentSortMap[item.Id] = int64(item.Sort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// new sort map
|
||||||
|
newSortMap := make(map[int64]int64)
|
||||||
|
for _, item := range validItems {
|
||||||
|
newSortMap[item.Id] = item.Sort
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemsToUpdate []types.SortItem
|
||||||
|
for _, item := range validItems {
|
||||||
|
if oldSort, exists := currentSortMap[item.Id]; exists && oldSort != item.Sort {
|
||||||
|
itemsToUpdate = append(itemsToUpdate, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, item := range itemsToUpdate {
|
||||||
|
s, err := l.svcCtx.NodeModel.FindOneNode(l.ctx, item.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Sort = int(item.Sort)
|
||||||
|
if err = l.svcCtx.NodeModel.UpdateNode(l.ctx, s, db); err != nil {
|
||||||
|
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()), logger.Field("id", item.Id), logger.Field("sort", item.Sort))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()))
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,13 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/internal/model/node"
|
||||||
"github.com/perfect-panel/server/internal/svc"
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
"github.com/perfect-panel/server/internal/types"
|
"github.com/perfect-panel/server/internal/types"
|
||||||
"github.com/perfect-panel/server/pkg/logger"
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ResetSortWithServerLogic struct {
|
type ResetSortWithServerLogic struct {
|
||||||
@ -24,5 +28,59 @@ func NewResetSortWithServerLogic(ctx context.Context, svcCtx *svc.ServiceContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *ResetSortWithServerLogic) ResetSortWithServer(req *types.ResetSortRequest) error {
|
func (l *ResetSortWithServerLogic) ResetSortWithServer(req *types.ResetSortRequest) error {
|
||||||
|
err := l.svcCtx.NodeModel.Transaction(l.ctx, func(db *gorm.DB) error {
|
||||||
|
// find all servers id
|
||||||
|
var existingIDs []int64
|
||||||
|
db.Model(&node.Server{}).Select("id").Find(&existingIDs)
|
||||||
|
// check if the id is valid
|
||||||
|
validIDMap := make(map[int64]bool)
|
||||||
|
for _, id := range existingIDs {
|
||||||
|
validIDMap[id] = true
|
||||||
|
}
|
||||||
|
// check if the sort is valid
|
||||||
|
var validItems []types.SortItem
|
||||||
|
for _, item := range req.Sort {
|
||||||
|
if validIDMap[item.Id] {
|
||||||
|
validItems = append(validItems, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// query all servers
|
||||||
|
var servers []*node.Server
|
||||||
|
db.Model(&node.Server{}).Order("sort ASC").Find(&servers)
|
||||||
|
// create a map of the current sort
|
||||||
|
currentSortMap := make(map[int64]int64)
|
||||||
|
for _, item := range servers {
|
||||||
|
currentSortMap[item.Id] = int64(item.Sort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// new sort map
|
||||||
|
newSortMap := make(map[int64]int64)
|
||||||
|
for _, item := range validItems {
|
||||||
|
newSortMap[item.Id] = item.Sort
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemsToUpdate []types.SortItem
|
||||||
|
for _, item := range validItems {
|
||||||
|
if oldSort, exists := currentSortMap[item.Id]; exists && oldSort != item.Sort {
|
||||||
|
itemsToUpdate = append(itemsToUpdate, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, item := range itemsToUpdate {
|
||||||
|
s, err := l.svcCtx.NodeModel.FindOneServer(l.ctx, item.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Sort = int(item.Sort)
|
||||||
|
if err = l.svcCtx.NodeModel.UpdateServer(l.ctx, s, db); err != nil {
|
||||||
|
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()), logger.Field("id", item.Id), logger.Field("sort", item.Sort))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[NodeSort] Update Database Error: ", logger.Field("error", err.Error()))
|
||||||
|
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), err.Error())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package node
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,3 +36,47 @@ func (n *Node) BeforeCreate(tx *gorm.DB) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Node) BeforeDelete(tx *gorm.DB) error {
|
||||||
|
if err := tx.Exec("UPDATE `nodes` SET sort = sort - 1 WHERE sort > ?", n.Sort).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) BeforeUpdate(tx *gorm.DB) error {
|
||||||
|
var count int64
|
||||||
|
if err := tx.Set("gorm:query_option", "FOR UPDATE").Model(&Server{}).
|
||||||
|
Where("sort = ? AND id != ?", n.Sort, n.Id).Count(&count).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
// reorder sort
|
||||||
|
if err := reorderSortWithNode(tx); err != nil {
|
||||||
|
logger.Errorf("[Server] BeforeUpdate reorderSort error: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// get max sort
|
||||||
|
var maxSort int
|
||||||
|
if err := tx.Model(&Server{}).Select("MAX(sort)").Scan(&maxSort).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.Sort = maxSort + 1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reorderSortWithNode(tx *gorm.DB) error {
|
||||||
|
var nodes []Node
|
||||||
|
if err := tx.Order("sort, id").Find(&nodes).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, node := range nodes {
|
||||||
|
if node.Sort != i+1 {
|
||||||
|
if err := tx.Exec("UPDATE `nodes` SET sort = ? WHERE id = ?", i+1, node.Id).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -37,6 +38,35 @@ func (m *Server) BeforeCreate(tx *gorm.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Server) BeforeDelete(tx *gorm.DB) error {
|
||||||
|
if err := tx.Exec("UPDATE `servers` SET sort = sort - 1 WHERE sort > ?", m.Sort).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Server) BeforeUpdate(tx *gorm.DB) error {
|
||||||
|
var count int64
|
||||||
|
if err := tx.Set("gorm:query_option", "FOR UPDATE").Model(&Server{}).
|
||||||
|
Where("sort = ? AND id != ?", m.Sort, m.Id).Count(&count).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
// reorder sort
|
||||||
|
if err := reorderSortWithServer(tx); err != nil {
|
||||||
|
logger.Errorf("[Server] BeforeUpdate reorderSort error: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// get max sort
|
||||||
|
var maxSort int
|
||||||
|
if err := tx.Model(&Server{}).Select("MAX(sort)").Scan(&maxSort).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.Sort = maxSort + 1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalProtocols Marshal server protocols to json
|
// MarshalProtocols Marshal server protocols to json
|
||||||
func (m *Server) MarshalProtocols(list []Protocol) error {
|
func (m *Server) MarshalProtocols(list []Protocol) error {
|
||||||
var validate = make(map[string]bool)
|
var validate = make(map[string]bool)
|
||||||
@ -118,3 +148,18 @@ func (m *Protocol) Unmarshal(data []byte) error {
|
|||||||
}
|
}
|
||||||
return json.Unmarshal(data, &aux)
|
return json.Unmarshal(data, &aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reorderSortWithServer(tx *gorm.DB) error {
|
||||||
|
var servers []Server
|
||||||
|
if err := tx.Order("sort, id").Find(&servers).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, server := range servers {
|
||||||
|
if server.Sort != i+1 {
|
||||||
|
if err := tx.Exec("UPDATE `servers` SET sort = ? WHERE id = ?", i+1, server.Id).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -1608,9 +1608,7 @@ type ResetPasswordRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResetSortRequest struct {
|
type ResetSortRequest struct {
|
||||||
Page int `json:"page"`
|
Sort []SortItem `json:"sort"`
|
||||||
Size int `json:"size"`
|
|
||||||
Sort []int64 `json:"sort"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResetSubscribeLog struct {
|
type ResetSubscribeLog struct {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user