分组概念
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m58s
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m58s
This commit is contained in:
parent
e5e9f93f68
commit
f703b5089a
@ -15,10 +15,10 @@ Logger: # 日志配置
|
|||||||
Level: debug # 日志级别: debug, info, warn, error, panic, fatal
|
Level: debug # 日志级别: debug, info, warn, error, panic, fatal
|
||||||
|
|
||||||
MySQL:
|
MySQL:
|
||||||
Addr: 103.150.215.44:3306 # host 网络模式; bridge 模式改为 mysql:3306
|
Addr: 154.12.35.103:3306 # host 网络模式; bridge 模式改为 mysql:3306
|
||||||
Username: root # MySQL用户名
|
Username: root # MySQL用户名
|
||||||
Password: jpcV41ppanel # MySQL密码,与 .env MYSQL_ROOT_PASSWORD 一致
|
Password: jpcV41ppanel # MySQL密码,与 .env MYSQL_ROOT_PASSWORD 一致
|
||||||
Dbname: hifast # MySQL数据库名
|
Dbname: ppanel # MySQL数据库名
|
||||||
Config: charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
Config: charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
||||||
MaxIdleConns: 10
|
MaxIdleConns: 10
|
||||||
MaxOpenConns: 100
|
MaxOpenConns: 100
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/perfect-panel/server/internal/logic/auth"
|
"github.com/perfect-panel/server/internal/logic/auth"
|
||||||
"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/result"
|
"github.com/perfect-panel/server/pkg/result"
|
||||||
|
"github.com/perfect-panel/server/pkg/turnstile"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User Telephone login
|
// User Telephone login
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
commonLogic "github.com/perfect-panel/server/internal/logic/common"
|
||||||
|
"github.com/perfect-panel/server/internal/model/group"
|
||||||
"github.com/perfect-panel/server/internal/model/node"
|
"github.com/perfect-panel/server/internal/model/node"
|
||||||
"github.com/perfect-panel/server/internal/model/user"
|
"github.com/perfect-panel/server/internal/model/user"
|
||||||
"github.com/perfect-panel/server/internal/svc"
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
@ -117,20 +118,24 @@ func (l *QueryUserSubscribeNodeListLogic) getServers(userSub *user.Subscribe) (u
|
|||||||
l.Debugw("[GetServers] Failed to check group enabled", logger.Field("error", err.Error()))
|
l.Debugw("[GetServers] Failed to check group enabled", logger.Field("error", err.Error()))
|
||||||
// Continue with tag-based filtering
|
// Continue with tag-based filtering
|
||||||
}
|
}
|
||||||
nodeIds := tool.StringToInt64Slice(subDetails.Nodes)
|
|
||||||
tags := normalizeSubscribeNodeTags(subDetails.NodeTags)
|
|
||||||
|
|
||||||
isGroupEnabled := (groupEnabled == "true" || groupEnabled == "1")
|
isGroupEnabled := (groupEnabled == "true" || groupEnabled == "1")
|
||||||
|
|
||||||
enable := true
|
var nodes []*node.Node
|
||||||
|
if isGroupEnabled {
|
||||||
_, nodes, err := l.svcCtx.NodeModel.FilterNodeList(l.ctx, &node.FilterNodeParams{
|
// Group mode: use group_ids to filter nodes
|
||||||
Page: 1,
|
nodes, err = l.getNodesByGroup(userSub)
|
||||||
Size: 1000,
|
if err != nil {
|
||||||
NodeId: nodeIds,
|
l.Errorw("[GetServers] Failed to get nodes by group", logger.Field("error", err.Error()))
|
||||||
Tag: tags,
|
return nil, err
|
||||||
Enabled: &enable, // Only get enabled nodes
|
}
|
||||||
})
|
} else {
|
||||||
|
// Tag mode: use node_ids and tags to filter nodes
|
||||||
|
nodes, err = l.getNodesByTag(userSub)
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[GetServers] Failed to get nodes by tag", logger.Field("error", err.Error()))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process nodes and create response
|
// Process nodes and create response
|
||||||
if len(nodes) > 0 {
|
if len(nodes) > 0 {
|
||||||
|
|||||||
@ -70,6 +70,9 @@ type Subscribe struct {
|
|||||||
NewUserOnly *bool `gorm:"type:tinyint(1);default:0;comment:New user only: allow purchase within 24h of registration, once per user"`
|
NewUserOnly *bool `gorm:"type:tinyint(1);default:0;comment:New user only: allow purchase within 24h of registration, once per user"`
|
||||||
Nodes string `gorm:"type:varchar(255);comment:Node Ids"`
|
Nodes string `gorm:"type:varchar(255);comment:Node Ids"`
|
||||||
NodeTags string `gorm:"type:varchar(255);comment:Node Tags"`
|
NodeTags string `gorm:"type:varchar(255);comment:Node Tags"`
|
||||||
|
NodeGroupIds JSONInt64Slice `gorm:"type:json;comment:Node Group IDs (JSON array, multiple groups)"`
|
||||||
|
NodeGroupId int64 `gorm:"default:0;index:idx_node_group_id;comment:Default Node Group ID (single ID)"`
|
||||||
|
TrafficLimit string `gorm:"type:text;comment:Traffic Limit Rules"`
|
||||||
Show *bool `gorm:"type:tinyint(1);not null;default:0;comment:Show portal page"`
|
Show *bool `gorm:"type:tinyint(1);not null;default:0;comment:Show portal page"`
|
||||||
Sell *bool `gorm:"type:tinyint(1);not null;default:0;comment:Sell"`
|
Sell *bool `gorm:"type:tinyint(1);not null;default:0;comment:Sell"`
|
||||||
Sort int64 `gorm:"type:int;not null;default:0;comment:Sort"`
|
Sort int64 `gorm:"type:int;not null;default:0;comment:Sort"`
|
||||||
|
|||||||
@ -561,6 +561,13 @@ type DeleteAccountResponse struct {
|
|||||||
Code int64 `json:"code"`
|
Code int64 `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DailyTrafficStats struct {
|
||||||
|
Date string `json:"date"`
|
||||||
|
Upload int64 `json:"upload"`
|
||||||
|
Download int64 `json:"download"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
type DeleteAdsRequest struct {
|
type DeleteAdsRequest struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
}
|
}
|
||||||
@ -681,6 +688,10 @@ type EmailAuthticateConfig struct {
|
|||||||
DomainSuffixList string `json:"domain_suffix_list"`
|
DomainSuffixList string `json:"domain_suffix_list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExportGroupResultRequest struct {
|
||||||
|
HistoryId *int64 `form:"history_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ErrorLogMessage struct {
|
type ErrorLogMessage struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Platform string `json:"platform"`
|
Platform string `json:"platform"`
|
||||||
@ -1114,6 +1125,37 @@ type GetInviteSalesResponse struct {
|
|||||||
List []InvitedUserSale `json:"list"`
|
List []InvitedUserSale `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetGroupConfigRequest struct {
|
||||||
|
Keys []string `form:"keys,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGroupConfigResponse struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
Config map[string]interface{} `json:"config"`
|
||||||
|
State RecalculationState `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGroupHistoryDetailRequest struct {
|
||||||
|
Id int64 `form:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGroupHistoryDetailResponse struct {
|
||||||
|
GroupHistoryDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGroupHistoryRequest struct {
|
||||||
|
Page int `form:"page"`
|
||||||
|
Size int `form:"size"`
|
||||||
|
GroupMode string `form:"group_mode,omitempty"`
|
||||||
|
TriggerType string `form:"trigger_type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGroupHistoryResponse struct {
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
List []GroupHistory `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
type GetLoginLogRequest struct {
|
type GetLoginLogRequest struct {
|
||||||
Page int `form:"page"`
|
Page int `form:"page"`
|
||||||
Size int `form:"size"`
|
Size int `form:"size"`
|
||||||
@ -2881,6 +2923,26 @@ type UpdateFamilyMaxMembersRequest struct {
|
|||||||
MaxMembers int64 `json:"max_members" validate:"required,gt=0"`
|
MaxMembers int64 `json:"max_members" validate:"required,gt=0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateGroupConfigRequest struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
Config map[string]interface{} `json:"config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateNodeGroupRequest struct {
|
||||||
|
Id int64 `json:"id" validate:"required"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Sort int `json:"sort"`
|
||||||
|
ForCalculation *bool `json:"for_calculation"`
|
||||||
|
IsExpiredGroup *bool `json:"is_expired_group"`
|
||||||
|
ExpiredDaysLimit *int `json:"expired_days_limit"`
|
||||||
|
MaxTrafficGBExpired *int64 `json:"max_traffic_gb_expired,omitempty"`
|
||||||
|
SpeedLimit *int `json:"speed_limit"`
|
||||||
|
MinTrafficGB *int64 `json:"min_traffic_gb,omitempty"`
|
||||||
|
MaxTrafficGB *int64 `json:"max_traffic_gb,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpdateNodeRequest struct {
|
type UpdateNodeRequest struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -3171,6 +3233,7 @@ type UserStatisticsResponse struct {
|
|||||||
|
|
||||||
type UserSubscribe struct {
|
type UserSubscribe struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
|
IdStr string `json:"id_str"`
|
||||||
UserId int64 `json:"user_id"`
|
UserId int64 `json:"user_id"`
|
||||||
OrderId int64 `json:"order_id"`
|
OrderId int64 `json:"order_id"`
|
||||||
SubscribeId int64 `json:"subscribe_id"`
|
SubscribeId int64 `json:"subscribe_id"`
|
||||||
|
|||||||
@ -134,6 +134,11 @@ const (
|
|||||||
DeviceBindLimitExceeded uint32 = 90019
|
DeviceBindLimitExceeded uint32 = 90019
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Permission error
|
||||||
|
const (
|
||||||
|
PermissionDenied uint32 = 40300
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OrderNotExist uint32 = 61001
|
OrderNotExist uint32 = 61001
|
||||||
PaymentMethodNotFound uint32 = 61002
|
PaymentMethodNotFound uint32 = 61002
|
||||||
|
|||||||
@ -102,6 +102,9 @@ func init() {
|
|||||||
PaymentMethodNotFound: "Payment method not found",
|
PaymentMethodNotFound: "Payment method not found",
|
||||||
OrderStatusError: "Order status error",
|
OrderStatusError: "Order status error",
|
||||||
InsufficientOfPeriod: "Insufficient number of period",
|
InsufficientOfPeriod: "Insufficient number of period",
|
||||||
|
|
||||||
|
// Permission error
|
||||||
|
PermissionDenied: "Permission denied",
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user