148 lines
4.7 KiB
Go
148 lines
4.7 KiB
Go
package user
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
userdomain "hyapp/services/user-service/internal/domain/user"
|
|
)
|
|
|
|
const (
|
|
maxPushDeviceIDLen = 128
|
|
maxPushTokenLen = 512
|
|
maxPushProviderLen = 32
|
|
maxPushPlatformLen = 16
|
|
maxPushAppVersionLen = 64
|
|
maxPushLanguageLen = 32
|
|
maxPushTimezoneLen = 64
|
|
)
|
|
|
|
// BindPushToken 绑定当前登录用户的系统推送 token。
|
|
// 该能力不影响 App 进入主界面;失败只影响离线消息触达。
|
|
func (s *Service) BindPushToken(ctx context.Context, userID int64, deviceID string, pushToken string, provider string, platform string, appVersion string, language string, timezone string, requestID string) (int64, error) {
|
|
if s.deviceRepository == nil {
|
|
return 0, xerr.New(xerr.Unavailable, "device repository is not configured")
|
|
}
|
|
if err := s.requireActiveCompletedUser(ctx, userID); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
command, err := normalizePushTokenCommand(ctx, userID, deviceID, pushToken, provider, platform, appVersion, language, timezone, requestID, s.now().UnixMilli())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if err := s.deviceRepository.BindPushToken(ctx, command); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return command.UpdatedAtMs, nil
|
|
}
|
|
|
|
// DeletePushToken 失效当前登录用户某个设备的推送 token。
|
|
func (s *Service) DeletePushToken(ctx context.Context, userID int64, deviceID string, pushToken string, requestID string) (bool, int64, error) {
|
|
if s.deviceRepository == nil {
|
|
return false, 0, xerr.New(xerr.Unavailable, "device repository is not configured")
|
|
}
|
|
if userID <= 0 {
|
|
return false, 0, xerr.New(xerr.InvalidArgument, "user_id is required")
|
|
}
|
|
|
|
deviceID = strings.TrimSpace(deviceID)
|
|
pushToken = strings.TrimSpace(pushToken)
|
|
if deviceID == "" || len(deviceID) > maxPushDeviceIDLen {
|
|
return false, 0, xerr.New(xerr.InvalidArgument, "device_id is invalid")
|
|
}
|
|
if len(pushToken) > maxPushTokenLen {
|
|
return false, 0, xerr.New(xerr.InvalidArgument, "push_token is invalid")
|
|
}
|
|
|
|
nowMs := s.now().UnixMilli()
|
|
deleted, err := s.deviceRepository.DeletePushToken(ctx, userdomain.DeletePushTokenCommand{
|
|
AppCode: appcode.FromContext(ctx),
|
|
UserID: userID,
|
|
DeviceID: deviceID,
|
|
PushToken: pushToken,
|
|
RequestID: strings.TrimSpace(requestID),
|
|
UpdatedAtMs: nowMs,
|
|
})
|
|
if err != nil {
|
|
return false, 0, err
|
|
}
|
|
|
|
return deleted, nowMs, nil
|
|
}
|
|
|
|
func (s *Service) requireActiveCompletedUser(ctx context.Context, userID int64) error {
|
|
if userID <= 0 {
|
|
return xerr.New(xerr.InvalidArgument, "user_id is required")
|
|
}
|
|
user, err := s.GetUser(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !user.ProfileCompleted {
|
|
return xerr.New(xerr.ProfileRequired, "profile required")
|
|
}
|
|
if user.Status != userdomain.StatusActive {
|
|
return xerr.New(xerr.UserDisabled, "user disabled")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func normalizePushTokenCommand(ctx context.Context, userID int64, deviceID string, pushToken string, provider string, platform string, appVersion string, language string, timezone string, requestID string, nowMs int64) (userdomain.PushTokenCommand, error) {
|
|
deviceID = strings.TrimSpace(deviceID)
|
|
pushToken = strings.TrimSpace(pushToken)
|
|
platform = strings.ToLower(strings.TrimSpace(platform))
|
|
provider = strings.ToLower(strings.TrimSpace(provider))
|
|
if provider == "" {
|
|
provider = defaultPushProvider(platform)
|
|
}
|
|
|
|
if deviceID == "" || len(deviceID) > maxPushDeviceIDLen {
|
|
return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "device_id is invalid")
|
|
}
|
|
if pushToken == "" || len(pushToken) > maxPushTokenLen {
|
|
return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "push_token is invalid")
|
|
}
|
|
if provider == "" || len(provider) > maxPushProviderLen {
|
|
return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "provider is invalid")
|
|
}
|
|
if platform != "android" && platform != "ios" {
|
|
return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "platform is invalid")
|
|
}
|
|
|
|
appVersion = strings.TrimSpace(appVersion)
|
|
language = strings.TrimSpace(language)
|
|
timezone = strings.TrimSpace(timezone)
|
|
if len(appVersion) > maxPushAppVersionLen || len(language) > maxPushLanguageLen || len(timezone) > maxPushTimezoneLen {
|
|
return userdomain.PushTokenCommand{}, xerr.New(xerr.InvalidArgument, "push token metadata is invalid")
|
|
}
|
|
|
|
return userdomain.PushTokenCommand{
|
|
AppCode: appcode.FromContext(ctx),
|
|
UserID: userID,
|
|
DeviceID: deviceID,
|
|
PushToken: pushToken,
|
|
Provider: provider,
|
|
Platform: platform,
|
|
AppVersion: appVersion,
|
|
Language: language,
|
|
Timezone: timezone,
|
|
RequestID: strings.TrimSpace(requestID),
|
|
UpdatedAtMs: nowMs,
|
|
}, nil
|
|
}
|
|
|
|
func defaultPushProvider(platform string) string {
|
|
switch platform {
|
|
case "android":
|
|
return "fcm"
|
|
case "ios":
|
|
return "apns"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|