From faaf0a7178e5ce84d71e8f09c61fcd8349ed922c Mon Sep 17 00:00:00 2001 From: hawklin2017 <32898629+hawklin2017@users.noreply.github.com> Date: Tue, 7 Apr 2026 20:33:18 +0800 Subject: [PATCH] =?UTF-8?q?sn=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/api/phone_sn.go | 82 +++++++++++++++++++++ internal/api/router.go | 12 +++ pkg/common/storage/database/mgo/phone_sn.go | 69 +++++++++++++++++ pkg/common/storage/database/name.go | 1 + pkg/common/storage/database/phone_sn.go | 20 +++++ pkg/common/storage/model/phone_sn.go | 14 ++++ protocol | 2 +- 7 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 internal/api/phone_sn.go create mode 100644 pkg/common/storage/database/mgo/phone_sn.go create mode 100644 pkg/common/storage/database/phone_sn.go create mode 100644 pkg/common/storage/model/phone_sn.go diff --git a/internal/api/phone_sn.go b/internal/api/phone_sn.go new file mode 100644 index 000000000..3302ef215 --- /dev/null +++ b/internal/api/phone_sn.go @@ -0,0 +1,82 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package api + +import ( + "strings" + + "github.com/gin-gonic/gin" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/errs" +) + +type PhoneSNApi struct { + db database.PhoneSN +} + +func NewPhoneSNApi(db database.PhoneSN) *PhoneSNApi { + return &PhoneSNApi{db: db} +} + +type phoneGetSNInfoReq struct { + Phone string `json:"phone" binding:"required"` +} + +type phoneGetSNInfoResp struct { + IsSnd bool `json:"is_snd"` + UserID int64 `json:"userID"` +} + +type phoneSetSNInfoReq struct { + Phone string `json:"phone" binding:"required"` + UserID int64 `json:"userID"` + IsSnd bool `json:"is_snd"` +} + +// GetSNInfo POST /phone/get_sn_info +func (a *PhoneSNApi) GetSNInfo(c *gin.Context) { + var req phoneGetSNInfoReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg(err.Error())) + return + } + phone := strings.TrimSpace(req.Phone) + if phone == "" { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("phone is empty")) + return + } + info, err := a.db.GetByPhone(c, phone) + if err != nil { + apiresp.GinError(c, err) + return + } + resp := phoneGetSNInfoResp{IsSnd: false, UserID: 0} + if info != nil { + resp.IsSnd = info.IsSnd + resp.UserID = info.UserID + } + apiresp.GinSuccess(c, resp) +} + +// SetSNInfo POST /phone/set_sn_info +func (a *PhoneSNApi) SetSNInfo(c *gin.Context) { + var req phoneSetSNInfoReq + if err := c.ShouldBindJSON(&req); err != nil { + apiresp.GinError(c, errs.ErrArgs.WrapMsg(err.Error())) + return + } + phone := strings.TrimSpace(req.Phone) + if phone == "" { + apiresp.GinError(c, errs.ErrArgs.WrapMsg("phone is empty")) + return + } + if err := a.db.Upsert(c, phone, req.UserID, req.IsSnd); err != nil { + apiresp.GinError(c, err) + return + } + apiresp.GinSuccess(c, nil) +} diff --git a/internal/api/router.go b/internal/api/router.go index 6f474a67f..0a0e0763b 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -69,6 +69,10 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co if err != nil { return nil, err } + phoneSNDB, err := mgo.NewPhoneSNMongo(mgocli.GetDB()) + if err != nil { + return nil, err + } blacklistCtrl := controller.NewUserGlobalBlackDatabase(userGlobalBlackDB) authConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Auth) @@ -122,6 +126,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), config.Share.IMAdminUserID) cp := NewCaptchaApi(pbcaptcha.NewCaptchaClient(captchaConn)) bl := NewUserGlobalBlackApi(blacklistCtrl, userDB, config.Share.IMAdminUserID, rpcli.NewAuthClient(authConn)) + phoneSN := NewPhoneSNApi(phoneSNDB) userRouterGroup := r.Group("/user") { userRouterGroup.POST("/user_register", u.UserRegister) @@ -301,6 +306,12 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co captchaGroup.POST("/verify", cp.VerifyCaptcha) } + { + phoneGroup := r.Group("/phone") + phoneGroup.POST("/get_sn_info", phoneSN.GetSNInfo) + phoneGroup.POST("/set_sn_info", phoneSN.SetSNInfo) + } + { statisticsGroup := r.Group("/statistics") statisticsGroup.POST("/user/register", u.UserRegisterCount) @@ -370,4 +381,5 @@ var Whitelist = []string{ "/auth/get_admin_token", "/auth/parse_token", "/captcha", + "/phone/get_sn_info", } diff --git a/pkg/common/storage/database/mgo/phone_sn.go b/pkg/common/storage/database/mgo/phone_sn.go new file mode 100644 index 000000000..fa09f3657 --- /dev/null +++ b/pkg/common/storage/database/mgo/phone_sn.go @@ -0,0 +1,69 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package mgo + +import ( + "context" + "time" + + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/database" + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/errs" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func NewPhoneSNMongo(db *mongo.Database) (database.PhoneSN, error) { + coll := db.Collection(database.PhoneSNInfoName) + _, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ + Keys: bson.D{{Key: "phone", Value: 1}}, + Options: options.Index().SetUnique(true), + }) + if err != nil { + return nil, errs.Wrap(err) + } + return &phoneSNMgo{coll: coll}, nil +} + +type phoneSNMgo struct { + coll *mongo.Collection +} + +func (p *phoneSNMgo) GetByPhone(ctx context.Context, phone string) (*model.PhoneSNInfo, error) { + if phone == "" { + return nil, nil + } + doc, err := mongoutil.FindOne[*model.PhoneSNInfo](ctx, p.coll, bson.M{"phone": phone}) + if err != nil { + if errs.ErrRecordNotFound.Is(err) { + return nil, nil + } + return nil, err + } + return doc, nil +} + +func (p *phoneSNMgo) Upsert(ctx context.Context, phone string, userID int64, isSnd bool) error { + if phone == "" { + return errs.ErrArgs.WrapMsg("phone is empty") + } + now := time.Now().UnixMilli() + filter := bson.M{"phone": phone} + setDoc := bson.M{ + "is_snd": isSnd, + "user_id": userID, + "update_time": now, + } + update := bson.M{ + "$set": setDoc, + "$setOnInsert": bson.M{"phone": phone}, + } + opts := options.Update().SetUpsert(true) + _, err := p.coll.UpdateOne(ctx, filter, update, opts) + return errs.Wrap(err) +} diff --git a/pkg/common/storage/database/name.go b/pkg/common/storage/database/name.go index 4b1af74a8..a4ec9b099 100644 --- a/pkg/common/storage/database/name.go +++ b/pkg/common/storage/database/name.go @@ -18,4 +18,5 @@ const ( SeqConversationName = "seq" SeqUserName = "seq_user" UserGlobalBlackName = "user_global_black_list" + PhoneSNInfoName = "phone_sn_info" ) diff --git a/pkg/common/storage/database/phone_sn.go b/pkg/common/storage/database/phone_sn.go new file mode 100644 index 000000000..3ded66b0f --- /dev/null +++ b/pkg/common/storage/database/phone_sn.go @@ -0,0 +1,20 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package database + +import ( + "context" + + "github.com/openimsdk/open-im-server/v3/pkg/common/storage/model" +) + +// PhoneSN 手机号 is_snd 持久化 +type PhoneSN interface { + // GetByPhone 按手机号查询;无记录时返回 (nil, nil) + GetByPhone(ctx context.Context, phone string) (*model.PhoneSNInfo, error) + // Upsert 写入或更新 is_snd 与 user_id + Upsert(ctx context.Context, phone string, userID int64, isSnd bool) error +} diff --git a/pkg/common/storage/model/phone_sn.go b/pkg/common/storage/model/phone_sn.go new file mode 100644 index 000000000..60a572d7f --- /dev/null +++ b/pkg/common/storage/model/phone_sn.go @@ -0,0 +1,14 @@ +// Copyright © 2024 OpenIM. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package model + +// PhoneSNInfo 手机号与 is_snd、关联 user_id(每条以 phone 唯一) +type PhoneSNInfo struct { + Phone string `bson:"phone"` + UserID int64 `bson:"user_id"` + IsSnd bool `bson:"is_snd"` + UpdateTime int64 `bson:"update_time"` +} diff --git a/protocol b/protocol index 91e8d26ed..9f0b38eb5 160000 --- a/protocol +++ b/protocol @@ -1 +1 @@ -Subproject commit 91e8d26ed5b8ebd2711483bb558e797fa40f4612 +Subproject commit 9f0b38eb5c5015da3969d6711a140c3ba12956bb