From dca32cd11cdd013424d958cfa1238c9bb65d4c3f Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Tue, 14 Oct 2025 08:17:02 -0700 Subject: [PATCH] -f --- 1.conf | 67 ------ Dockerfile | 2 +- apis/public/subscribe.api | 41 ++++ apis/types.api | 3 +- .../migrate/database/02115_ads.down.sql | 0 initialize/migrate/database/02115_ads.up.sql | 2 + .../database/02116_site_custom_data.down.sql | 7 + .../database/02116_site_custom_data.up.sql | 7 + .../queryUserSubscribeNodeListHandler.go | 18 ++ internal/handler/routes.go | 3 + internal/logic/auth/deviceLoginLogic.go | 8 +- .../queryUserSubscribeNodeListLogic.go | 195 ++++++++++++++++++ .../logic/public/user/unbindDeviceLogic.go | 32 ++- internal/middleware/deviceMiddleware.go | 22 +- internal/model/announcement/model.go | 2 +- internal/model/node/default.go | 1 + internal/model/node/model.go | 6 + internal/model/user/device.go | 2 +- internal/types/types.go | 39 +++- pkg/xerr/errCode.go | 1 + pkg/xerr/errMsg.go | 1 + 21 files changed, 374 insertions(+), 85 deletions(-) delete mode 100644 1.conf create mode 100644 initialize/migrate/database/02115_ads.down.sql create mode 100644 initialize/migrate/database/02115_ads.up.sql create mode 100644 initialize/migrate/database/02116_site_custom_data.down.sql create mode 100644 initialize/migrate/database/02116_site_custom_data.up.sql create mode 100644 internal/handler/public/subscribe/queryUserSubscribeNodeListHandler.go create mode 100644 internal/logic/public/subscribe/queryUserSubscribeNodeListLogic.go diff --git a/1.conf b/1.conf deleted file mode 100644 index 6e7a5e3..0000000 --- a/1.conf +++ /dev/null @@ -1,67 +0,0 @@ -server { - listen 80; - server_name api.hifast.biz 4d3vsw8.88xgaen.hifast.biz; - - location / { - return 301 https://$host$request_uri; - } -} - -server { - listen 443 ssl http2; - server_name api.hifast.biz; - client_max_body_size 150M; - - ssl_certificate /etc/letsencrypt/live/api.hifast.biz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/api.hifast.biz/privkey.pem; - # 安全头 - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; - - location / { - proxy_pass http://127.0.0.1:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} - -# de99e242子域名指向3001 (管理界面) -server { - listen 443 ssl http2; - server_name 4d3vsw8.88xgaen.hifast.biz; - client_max_body_size 150M; - - ssl_certificate /etc/letsencrypt/live/4d3vsw8.88xgaen.hifast.biz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/4d3vsw8.88xgaen.hifast.biz/privkey.pem; - - # 安全头 - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; - - # Gzip压缩 - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json image/svg+xml; - - location ^~ / { - proxy_pass http://127.0.0.1:3001; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header REMOTE-HOST $remote_addr; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Port $server_port; - proxy_http_version 1.1; - add_header X-Cache $upstream_cache_status; - add_header Cache-Control no-cache; - proxy_ssl_server_name off; - proxy_ssl_name $proxy_host; - } -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c040309..8c4321c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ RUN BUILD_TIME=$(date -u +"%Y-%m-%d %H:%M:%S") && \ go build -ldflags="-s -w -X 'github.com/perfect-panel/server/pkg/constant.Version=${VERSION}' -X 'github.com/perfect-panel/server/pkg/constant.BuildTime=${BUILD_TIME}'" -o /app/ppanel ppanel.go # Final minimal image -FROM scratch +FROM alpine:latest # Copy CA certificates and timezone data COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ diff --git a/apis/public/subscribe.api b/apis/public/subscribe.api index 13024f8..7ab01c2 100644 --- a/apis/public/subscribe.api +++ b/apis/public/subscribe.api @@ -14,6 +14,43 @@ type ( QuerySubscribeListRequest { Language string `form:"language"` } + + QueryUserSubscribeNodeListResponse { + List []UserSubscribeInfo `json:"list"` + } + + UserSubscribeInfo { + Id int64 `json:"id"` + UserId int64 `json:"user_id"` + OrderId int64 `json:"order_id"` + SubscribeId int64 `json:"subscribe_id"` + StartTime int64 `json:"start_time"` + ExpireTime int64 `json:"expire_time"` + FinishedAt int64 `json:"finished_at"` + ResetTime int64 `json:"reset_time"` + Traffic int64 `json:"traffic"` + Download int64 `json:"download"` + Upload int64 `json:"upload"` + Token string `json:"token"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + IsTryOut bool `json:"is_try_out"` + Nodes []*UserSubscribeNodeInfo `json:"nodes"` + } + + UserSubscribeNodeInfo{ + Id int64 `json:"id"` + Name string `json:"name"` + Uuid string `json:"uuid"` + Protocol string `json:"protocol"` + Port uint16 `json:"port"` + Address string `json:"address"` + Tags []string `json:"tags"` + Country string `json:"country"` + City string `json:"city"` + CreatedAt int64 `json:"created_at"` + } ) @server ( @@ -25,5 +62,9 @@ service ppanel { @doc "Get subscribe list" @handler QuerySubscribeList get /list (QuerySubscribeListRequest) returns (QuerySubscribeListResponse) + + @doc "Get user subscribe node info" + @handler QueryUserSubscribeNodeList + get /node/list returns (QueryUserSubscribeNodeListResponse) } diff --git a/apis/types.api b/apis/types.api index 477e150..c55a5df 100644 --- a/apis/types.api +++ b/apis/types.api @@ -656,7 +656,7 @@ type ( // public announcement QueryAnnouncementRequest { Page int `form:"page"` - Size int `form:"size"` + Size int `form:"size,default=15"` Pinned *bool `form:"pinned"` Popup *bool `form:"popup"` } @@ -673,6 +673,7 @@ type ( List []SubscribeGroup `json:"list"` Total int64 `json:"total"` } + GetUserSubscribeTrafficLogsRequest { Page int `form:"page"` Size int `form:"size"` diff --git a/initialize/migrate/database/02115_ads.down.sql b/initialize/migrate/database/02115_ads.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/initialize/migrate/database/02115_ads.up.sql b/initialize/migrate/database/02115_ads.up.sql new file mode 100644 index 0000000..341bc84 --- /dev/null +++ b/initialize/migrate/database/02115_ads.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE `ads` + ADD COLUMN `description` VARCHAR(255) DEFAULT '' COMMENT 'Description'; diff --git a/initialize/migrate/database/02116_site_custom_data.down.sql b/initialize/migrate/database/02116_site_custom_data.down.sql new file mode 100644 index 0000000..b959fa7 --- /dev/null +++ b/initialize/migrate/database/02116_site_custom_data.down.sql @@ -0,0 +1,7 @@ +INSERT INTO `ppanel`.`system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +SELECT 'site', 'CustomData', '{ + "kr_website_id": "" +}', 'string', 'Custom Data', '2025-04-22 14:25:16.637', '2025-10-14 15:47:19.187' + WHERE NOT EXISTS ( + SELECT 1 FROM `ppanel`.`system` WHERE `category` = 'site' AND `key` = 'CustomData' +); diff --git a/initialize/migrate/database/02116_site_custom_data.up.sql b/initialize/migrate/database/02116_site_custom_data.up.sql new file mode 100644 index 0000000..b959fa7 --- /dev/null +++ b/initialize/migrate/database/02116_site_custom_data.up.sql @@ -0,0 +1,7 @@ +INSERT INTO `ppanel`.`system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +SELECT 'site', 'CustomData', '{ + "kr_website_id": "" +}', 'string', 'Custom Data', '2025-04-22 14:25:16.637', '2025-10-14 15:47:19.187' + WHERE NOT EXISTS ( + SELECT 1 FROM `ppanel`.`system` WHERE `category` = 'site' AND `key` = 'CustomData' +); diff --git a/internal/handler/public/subscribe/queryUserSubscribeNodeListHandler.go b/internal/handler/public/subscribe/queryUserSubscribeNodeListHandler.go new file mode 100644 index 0000000..16c67fa --- /dev/null +++ b/internal/handler/public/subscribe/queryUserSubscribeNodeListHandler.go @@ -0,0 +1,18 @@ +package subscribe + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/public/subscribe" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/result" +) + +// Get user subscribe node info +func QueryUserSubscribeNodeListHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + + l := subscribe.NewQueryUserSubscribeNodeListLogic(c.Request.Context(), svcCtx) + resp, err := l.QueryUserSubscribeNodeList() + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index c6832ec..d42ac7e 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -739,6 +739,9 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { { // Get subscribe list publicSubscribeGroupRouter.GET("/list", publicSubscribe.QuerySubscribeListHandler(serverCtx)) + + // Get user subscribe node info + publicSubscribeGroupRouter.GET("/node/list", publicSubscribe.QueryUserSubscribeNodeListHandler(serverCtx)) } publicTicketGroupRouter := router.Group("/v1/public/ticket") diff --git a/internal/logic/auth/deviceLoginLogic.go b/internal/logic/auth/deviceLoginLogic.go index 8f7807a..2e2b6ae 100644 --- a/internal/logic/auth/deviceLoginLogic.go +++ b/internal/logic/auth/deviceLoginLogic.go @@ -35,11 +35,9 @@ func NewDeviceLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Devic } func (l *DeviceLoginLogic) DeviceLogin(req *types.DeviceLoginRequest) (resp *types.LoginResponse, err error) { - //TODO : check device login rate limit - // Check if device login is enabled - //if !l.svcCtx.Config.Register.EnableDevice { - // return nil, xerr.NewErrMsg("Device login is disabled") - //} + if !l.svcCtx.Config.Device.Enable { + return nil, xerr.NewErrMsg("Device login is disabled") + } loginStatus := false var userInfo *user.User diff --git a/internal/logic/public/subscribe/queryUserSubscribeNodeListLogic.go b/internal/logic/public/subscribe/queryUserSubscribeNodeListLogic.go new file mode 100644 index 0000000..2ad05b8 --- /dev/null +++ b/internal/logic/public/subscribe/queryUserSubscribeNodeListLogic.go @@ -0,0 +1,195 @@ +package subscribe + +import ( + "context" + "strings" + "time" + + "github.com/perfect-panel/server/internal/model/node" + "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/constant" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/tool" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type QueryUserSubscribeNodeListLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Get user subscribe node info +func NewQueryUserSubscribeNodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryUserSubscribeNodeListLogic { + return &QueryUserSubscribeNodeListLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *QueryUserSubscribeNodeListLogic) QueryUserSubscribeNodeList() (resp *types.QueryUserSubscribeNodeListResponse, err error) { + u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) + if !ok { + logger.Error("current user is not found in context") + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") + } + + userSubscribes, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, u.Id, 1, 2) + if err != nil { + logger.Errorw("failed to query user subscribe", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "DB_ERROR") + } + + resp = &types.QueryUserSubscribeNodeListResponse{} + for _, us := range userSubscribes { + userSubscribe, err := l.getUserSubscribe(us.Token) + if err != nil { + l.Errorw("[SubscribeLogic] Get user subscribe failed", logger.Field("error", err.Error()), logger.Field("token", userSubscribe.Token)) + return nil, err + } + nodes, err := l.getServers(userSubscribe) + if err != nil { + return nil, err + } + userSubscribeInfo := types.UserSubscribeInfo{ + Id: userSubscribe.Id, + Nodes: nodes, + Traffic: userSubscribe.Traffic, + Upload: userSubscribe.Upload, + Download: userSubscribe.Download, + Token: userSubscribe.Token, + UserId: userSubscribe.UserId, + OrderId: userSubscribe.OrderId, + SubscribeId: userSubscribe.SubscribeId, + StartTime: userSubscribe.StartTime.Unix(), + ExpireTime: userSubscribe.ExpireTime.Unix(), + Status: userSubscribe.Status, + CreatedAt: userSubscribe.CreatedAt.Unix(), + UpdatedAt: userSubscribe.UpdatedAt.Unix(), + } + + if userSubscribe.FinishedAt != nil { + userSubscribeInfo.FinishedAt = userSubscribe.FinishedAt.Unix() + } + + if l.svcCtx.Config.Register.EnableTrial && l.svcCtx.Config.Register.TrialSubscribe == userSubscribe.SubscribeId { + userSubscribeInfo.IsTryOut = true + } + + resp.List = append(resp.List, userSubscribeInfo) + } + + return +} + +func (l *QueryUserSubscribeNodeListLogic) getServers(userSub *user.Subscribe) (userSubscribeNodes []*types.UserSubscribeNodeInfo, err error) { + userSubscribeNodes = make([]*types.UserSubscribeNodeInfo, 0) + if l.isSubscriptionExpired(userSub) { + return l.createExpiredServers(), nil + } + + subDetails, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, userSub.SubscribeId) + if err != nil { + l.Errorw("[Generate Subscribe]find subscribe details error: %v", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe details error: %v", err.Error()) + } + nodeIds := tool.StringToInt64Slice(subDetails.Nodes) + tags := strings.Split(subDetails.NodeTags, ",") + + l.Debugf("[Generate Subscribe]nodes: %v, NodeTags: %v", nodeIds, tags) + + enable := true + + _, nodes, err := l.svcCtx.NodeModel.FilterNodeList(l.ctx, &node.FilterNodeParams{ + Page: 0, + Size: 1000, + NodeId: nodeIds, + Enabled: &enable, // Only get enabled nodes + }) + + if len(nodes) > 0 { + var serverMapIds = make(map[int64]*node.Server) + for _, n := range nodes { + serverMapIds[n.ServerId] = nil + } + var serverIds []int64 + for k := range serverMapIds { + serverIds = append(serverIds, k) + } + + servers, err := l.svcCtx.NodeModel.QueryServerList(l.ctx, serverIds) + if err != nil { + l.Errorw("[Generate Subscribe]find server details error: %v", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server details error: %v", err.Error()) + } + + for _, s := range servers { + serverMapIds[s.Id] = s + } + + for _, n := range nodes { + server := serverMapIds[n.ServerId] + if server == nil { + continue + } + userSubscribeNode := &types.UserSubscribeNodeInfo{ + Id: n.Id, + Name: n.Name, + Uuid: userSub.UUID, + Protocol: n.Protocol, + Port: n.Port, + Address: n.Address, + Tags: strings.Split(n.Tags, ","), + Country: server.Country, + City: server.City, + CreatedAt: n.CreatedAt.Unix(), + } + userSubscribeNodes = append(userSubscribeNodes, userSubscribeNode) + } + } + + l.Debugf("[Query Subscribe]found servers: %v", len(nodes)) + + if err != nil { + l.Errorw("[Generate Subscribe]find server details error: %v", logger.Field("error", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find server details error: %v", err.Error()) + } + logger.Debugf("[Generate Subscribe]found servers: %v", len(nodes)) + return userSubscribeNodes, nil +} + +func (l *QueryUserSubscribeNodeListLogic) isSubscriptionExpired(userSub *user.Subscribe) bool { + return userSub.ExpireTime.Unix() < time.Now().Unix() && userSub.ExpireTime.Unix() != 0 +} + +func (l *QueryUserSubscribeNodeListLogic) createExpiredServers() []*types.UserSubscribeNodeInfo { + return nil +} + +func (l *QueryUserSubscribeNodeListLogic) getFirstHostLine() string { + host := l.svcCtx.Config.Host + lines := strings.Split(host, "\n") + if len(lines) > 0 { + return lines[0] + } + return host +} +func (l *QueryUserSubscribeNodeListLogic) getUserSubscribe(token string) (*user.Subscribe, error) { + userSub, err := l.svcCtx.UserModel.FindOneSubscribeByToken(l.ctx, token) + if err != nil { + l.Infow("[Generate Subscribe]find subscribe error: %v", logger.Field("error", err.Error()), logger.Field("token", token)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find subscribe error: %v", err.Error()) + } + + // Ignore expiration check + //if userSub.Status > 1 { + // l.Infow("[Generate Subscribe]subscribe is not available", logger.Field("status", int(userSub.Status)), logger.Field("token", token)) + // return nil, errors.Wrapf(xerr.NewErrCode(xerr.SubscribeNotAvailable), "subscribe is not available") + //} + + return userSub, nil +} diff --git a/internal/logic/public/user/unbindDeviceLogic.go b/internal/logic/public/user/unbindDeviceLogic.go index e081871..57218cc 100644 --- a/internal/logic/public/user/unbindDeviceLogic.go +++ b/internal/logic/public/user/unbindDeviceLogic.go @@ -2,7 +2,9 @@ package user import ( "context" + "fmt" + "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -10,6 +12,7 @@ import ( "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" + "gorm.io/gorm" ) type UnbindDeviceLogic struct { @@ -38,5 +41,32 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error { return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user") } - return l.svcCtx.UserModel.DeleteDevice(l.ctx, req.Id) + return l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { + var deleteDevice user.Device + err = tx.Model(&deleteDevice).Where("id = ?", req.Id).First(&deleteDevice).Error + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.QueueEnqueueError), "find device err: %v", err) + } + err = tx.Delete(deleteDevice).Error + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device err: %v", err) + } + var userAuth user.AuthMethods + err = tx.Model(&userAuth).Where("auth_identifier = ? and auth_type = ?", deleteDevice.Identifier, "device").First(&userAuth).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil + } + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find device online record err: %v", err) + } + + err = tx.Delete(&userAuth).Error + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device online record err: %v", err) + } + sessionId := l.ctx.Value(constant.CtxKeySessionID) + sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) + l.svcCtx.Redis.Del(l.ctx, sessionIdCacheKey) + return nil + }) } diff --git a/internal/middleware/deviceMiddleware.go b/internal/middleware/deviceMiddleware.go index 501d4d0..b66ccb0 100644 --- a/internal/middleware/deviceMiddleware.go +++ b/internal/middleware/deviceMiddleware.go @@ -28,22 +28,30 @@ const ( func DeviceMiddleware(srvCtx *svc.ServiceContext) func(c *gin.Context) { return func(c *gin.Context) { - loginType := c.GetString(string(constant.LoginType)) - if loginType == "" { - loginType = c.GetHeader("Login-Type") - } - if loginType != "device" { + if !srvCtx.Config.Device.Enable { c.Next() return } - c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), constant.LoginType, loginType)) + if srvCtx.Config.Device.SecuritySecret == "" { + result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.SecretIsEmpty), "Secret is empty")) + c.Abort() + return + } - if !srvCtx.Config.Device.Enable || srvCtx.Config.Device.SecuritySecret == "" { + ctx := c.Request.Context() + if ctx.Value(constant.CtxKeyUser) == nil && c.GetHeader("Login-Type") != "" { + ctx = context.WithValue(ctx, constant.LoginType, c.GetHeader("Login-Type")) + c.Request = c.Request.WithContext(ctx) + } + + loginType, ok := ctx.Value(constant.LoginType).(string) + if !ok || loginType != "device" { c.Next() return } + rw := NewResponseWriter(c, srvCtx) if !rw.Decrypt() { result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidCiphertext), "Invalid ciphertext")) diff --git a/internal/model/announcement/model.go b/internal/model/announcement/model.go index f5575a8..973fc97 100644 --- a/internal/model/announcement/model.go +++ b/internal/model/announcement/model.go @@ -43,7 +43,7 @@ func (m *customAnnouncementModel) GetAnnouncementListByPage(ctx context.Context, if filter.Search != "" { conn = conn.Where("`title` LIKE ? OR `content` LIKE ?", "%"+filter.Search+"%", "%"+filter.Search+"%") } - return conn.Count(&total).Offset((page - 1) * size).Limit(size).Find(v).Error + return conn.Count(&total).Offset((page - 1) * size).Limit(size).Find(&list).Error }) return total, list, err } diff --git a/internal/model/node/default.go b/internal/model/node/default.go index 575ea5f..ebdf331 100644 --- a/internal/model/node/default.go +++ b/internal/model/node/default.go @@ -23,6 +23,7 @@ type ( UpdateServer(ctx context.Context, data *Server, tx ...*gorm.DB) error DeleteServer(ctx context.Context, id int64, tx ...*gorm.DB) error Transaction(ctx context.Context, fn func(db *gorm.DB) error) error + QueryServerList(ctx context.Context, ids []int64) (servers []*Server, err error) } NodeModel interface { diff --git a/internal/model/node/model.go b/internal/model/node/model.go index 30eba18..ddfa736 100644 --- a/internal/model/node/model.go +++ b/internal/model/node/model.go @@ -65,6 +65,12 @@ func (m *customServerModel) FilterServerList(ctx context.Context, params *Filter return total, servers, err } +func (m *customServerModel) QueryServerList(ctx context.Context, ids []int64) (servers []*Server, err error) { + query := m.WithContext(ctx).Model(&Server{}) + err = query.Where("id IN (?)", ids).Find(&servers).Error + return +} + // FilterNodeList Filter Node List func (m *customServerModel) FilterNodeList(ctx context.Context, params *FilterNodeParams) (int64, []*Node, error) { var nodes []*Node diff --git a/internal/model/user/device.go b/internal/model/user/device.go index f823991..b1194a7 100644 --- a/internal/model/user/device.go +++ b/internal/model/user/device.go @@ -51,7 +51,7 @@ func (m *customUserModel) QueryDeviceList(ctx context.Context, userId int64) ([] var list []*Device var total int64 err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&Device{}).Where("`user_id` = ? and `subscribe_id` = ?", userId).Count(&total).Find(&list).Error + return conn.Model(&Device{}).Where("`user_id` = ?", userId).Count(&total).Find(&list).Error }) return list, total, err } diff --git a/internal/types/types.go b/internal/types/types.go index 89d404c..4e481ff 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -1540,7 +1540,7 @@ type PurchaseOrderResponse struct { type QueryAnnouncementRequest struct { Page int `form:"page"` - Size int `form:"size"` + Size int `form:"size,default=15"` Pinned *bool `form:"pinned"` Popup *bool `form:"popup"` } @@ -1697,6 +1697,10 @@ type QueryUserSubscribeListResponse struct { Total int64 `json:"total"` } +type QueryUserSubscribeNodeListResponse struct { + List []UserSubscribeInfo `json:"list"` +} + type QuotaTask struct { Id int64 `json:"id"` Subscribers []int64 `json:"subscribers"` @@ -2595,6 +2599,26 @@ type UserSubscribeDetail struct { UpdatedAt int64 `json:"updated_at"` } +type UserSubscribeInfo struct { + Id int64 `json:"id"` + UserId int64 `json:"user_id"` + OrderId int64 `json:"order_id"` + SubscribeId int64 `json:"subscribe_id"` + StartTime int64 `json:"start_time"` + ExpireTime int64 `json:"expire_time"` + FinishedAt int64 `json:"finished_at"` + ResetTime int64 `json:"reset_time"` + Traffic int64 `json:"traffic"` + Download int64 `json:"download"` + Upload int64 `json:"upload"` + Token string `json:"token"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` + IsTryOut bool `json:"is_try_out"` + Nodes []*UserSubscribeNodeInfo `json:"nodes"` +} + type UserSubscribeLog struct { Id int64 `json:"id"` UserId int64 `json:"user_id"` @@ -2605,6 +2629,19 @@ type UserSubscribeLog struct { Timestamp int64 `json:"timestamp"` } +type UserSubscribeNodeInfo struct { + Id int64 `json:"id"` + Name string `json:"name"` + Uuid string `json:"uuid"` + Protocol string `json:"protocol"` + Port uint16 `json:"port"` + Address string `json:"address"` + Tags []string `json:"tags"` + Country string `json:"country"` + City string `json:"city"` + CreatedAt int64 `json:"created_at"` +} + type UserSubscribeTrafficLog struct { SubscribeId int64 `json:"subscribe_id"` // Subscribe ID UserId int64 `json:"user_id"` // User ID diff --git a/pkg/xerr/errCode.go b/pkg/xerr/errCode.go index 64cbd6a..b708ac4 100644 --- a/pkg/xerr/errCode.go +++ b/pkg/xerr/errCode.go @@ -47,6 +47,7 @@ const ( ErrorTokenExpire uint32 = 40004 InvalidAccess uint32 = 40005 InvalidCiphertext uint32 = 40006 + SecretIsEmpty uint32 = 40007 ) //coupon error diff --git a/pkg/xerr/errMsg.go b/pkg/xerr/errMsg.go index a259e54..f4f73a3 100644 --- a/pkg/xerr/errMsg.go +++ b/pkg/xerr/errMsg.go @@ -14,6 +14,7 @@ func init() { ErrorTokenEmpty: "User token is empty", ErrorTokenInvalid: "User token is invalid", ErrorTokenExpire: "User token is expired", + SecretIsEmpty: "Secret is empty", InvalidAccess: "Invalid access", InvalidCiphertext: "Invalid ciphertext", // Database error