This commit is contained in:
2026-09-15 16:02:45 +08:00
parent 112c5f8e46
commit ade2453083
70 changed files with 1441 additions and 707 deletions
+33 -1
View File
@@ -7,6 +7,7 @@ import (
"io"
"log/slog"
"mime/multipart"
"os"
"strings"
"time"
@@ -143,6 +144,7 @@ func (s *UserService) InfoGetBySelf(ctx context.Context, userID int64) (*dto.Use
if user, err := redisdao.UserInfoGet(ctx, userID); err == nil && user != nil {
info := buildUserInfoResponse(user)
s.consumeNewUserFlag(userID, &info)
return &info, nil
} else if err != nil && !isCacheMiss(err) {
// 缓存异常不阻断,继续回落 DB。
@@ -158,9 +160,22 @@ func (s *UserService) InfoGetBySelf(ctx context.Context, userID int64) (*dto.Use
_ = redisdao.UserInfoSet(ctx, user, 0)
info := buildUserInfoResponse(user)
s.consumeNewUserFlag(userID, &info)
return &info, nil
}
// consumeNewUserFlag 消费「新用户」标记。
// is_new_user 只在注册时写 true,此前没有任何复位路径,会让客户端「新用户引导」反复触发。
// 首次读取用户信息即视为引导已消费:本次响应返回 false,并异步复位 DB(best-effort,失败只告警)。
// 只在「获取用户信息」路径调用——WxLogin 的 is_new_user 表示「本次是否新注册」,语义保持不变。
func (s *UserService) consumeNewUserFlag(userID int64, info *dto.UserInfoGetBySelfResponse) {
if !info.IsNewUser {
return
}
info.IsNewUser = false
go s.resetNewUserFlag(userID)
}
// ProfileUpdate 修改当前用户资料。
func (s *UserService) ProfileUpdate(ctx context.Context, userID int64, request *dto.UserProfileUpdateBySelfRequest) (*dto.UserProfileUpdateBySelfResponse, *errcode.Error) {
ctx, span := global.Tracer.Start(ctx, "svc.UserProfileUpdate")
@@ -257,9 +272,13 @@ func (s *UserService) AvatarUpload(ctx context.Context, userID int64, fileHeader
return nil, errcode.UploadFileSaveFailed
}
subDir := fmt.Sprintf("%s/%d/avatar", user.UserUUID, userID)
if _, serr := upload.FileSaveTmpBytes(ctx, imageData, fileName, subDir); serr != nil {
tmpPath, serr := upload.FileSaveTmpBytes(ctx, imageData, fileName, subDir)
if serr != nil {
return nil, errcode.UploadFileSaveFailed
}
// 头像不消耗额度、上传接口也无限流,临时文件必须清理,
// 否则单个认证用户循环上传即可把磁盘写满(此前返回值被丢弃,文件从不删除)。
defer func() { _ = os.Remove(tmpPath) }()
cosKey := fmt.Sprintf("%s/%s", subDir, fileName)
if cerr := upload.FileUploadCos(ctx, cosKey); cerr != nil {
return nil, errcode.UploadFileSaveFailed
@@ -415,3 +434,16 @@ func buildUserInfoResponse(user *mysqlmodel.User) dto.UserInfoGetBySelfResponse
VIPExpire: user.VIPExpire,
}
}
// resetNewUserFlag 异步复位 is_new_user(best-effort,失败仅告警)。
// 使用独立 context,避免请求结束后 ctx 被取消导致复位失败。
func (s *UserService) resetNewUserFlag(userID int64) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.userDao.UserUpdateByID(ctx, userID, map[string]any{"is_new_user": false}); err != nil {
slog.WarnContext(ctx, "reset is_new_user failed", "user_id", userID, "error", err)
return
}
_ = redisdao.UserInfoDel(ctx, userID)
}