1513 lines
41 KiB
Go
1513 lines
41 KiB
Go
package usermod
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common"
|
|
"91porn-server/common/constant"
|
|
"91porn-server/common/constant/redisconst"
|
|
"91porn-server/common/db"
|
|
"91porn-server/common/log"
|
|
"91porn-server/common/pageopt"
|
|
"91porn-server/common/redis"
|
|
"91porn-server/common/timeutil/timerange"
|
|
"91porn-server/models"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/skd/skdg"
|
|
"91porn-server/web/webg"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
// SystemDevIDPrex 马甲账号devID前缀
|
|
const SystemDevIDPrex = "system-5rG1eq35Y0F102Qt3BwN2y"
|
|
|
|
const table = models.UserTable
|
|
|
|
func coll(t *db.MongoTool) *db.MongoTool {
|
|
if t == nil {
|
|
return mdb.Coll(table)
|
|
}
|
|
return t.Coll(table)
|
|
}
|
|
|
|
// initIndex 索引设置
|
|
func initIndex() {
|
|
many := []mongo.IndexModel{ //batch set indexes //value is the type 1 or -1
|
|
{
|
|
Keys: bson.D{{Key: "uid", Value: 1}},
|
|
Options: options.Index().SetUnique(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "devID", Value: 1}},
|
|
Options: options.Index().SetUnique(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "channel", Value: 1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "token", Value: 1}},
|
|
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"token": bson.M{"$gt": ""}}),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "promotionCode", Value: 1}},
|
|
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"promotionCode": bson.M{"$gt": ""}}),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "vipExpireDate", Value: 1}},
|
|
Options: options.Index().SetPartialFilterExpression(bson.M{"vipExpireDate": bson.M{"$gt": time.Time{}}}),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "mobile", Value: 1}},
|
|
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{"mobile": bson.M{"$gt": ""}}),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "mobileBindAt", Value: -1}},
|
|
Options: options.Index().SetSparse(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "mobileUnBindAt", Value: -1}},
|
|
Options: options.Index().SetSparse(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "updatedAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "discBindAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "name", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "hasBanned", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
Options: options.Index().SetSparse(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "hasLocked", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
Options: options.Index().SetSparse(true),
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "discBindAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "trueScore", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "isDirect", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "isDirect", Value: 1}, {Key: "discBindAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "promotionSeqe", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "promotionSeqe", Value: 1}, {Key: "discBindAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "isDirect", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "districtCode", Value: 1}, {Key: "isDirect", Value: 1}, {Key: "discBindAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "autoFollow", Value: 1}, {Key: "createdAt", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "registerIP", Value: 1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "officialCert", Value: 1}, {Key: "originalSort", Value: -1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "account", Value: 1}},
|
|
},
|
|
{
|
|
Keys: bson.D{{Key: "imUserId", Value: 1}},
|
|
Options: options.Index().SetSparse(true),
|
|
},
|
|
{
|
|
// 用于筛选
|
|
Keys: bson.D{{Key: "userType", Value: 1}, {Key: "createdAt", Value: 1}},
|
|
},
|
|
}
|
|
if _, err := coll(nil).CreateIndex(many); err != nil {
|
|
panic(fmt.Sprintf("user model set index err ==>[%+v]", err))
|
|
}
|
|
}
|
|
|
|
func findUser(cond bson.M) (*User, error) {
|
|
var u User
|
|
if err := coll(nil).FindOne(&u, cond); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "findUser", table, "FindOne", err),
|
|
log.Any("cond", cond),
|
|
)
|
|
return nil, err
|
|
}
|
|
if u.UID == 0 {
|
|
return nil, nil
|
|
}
|
|
return &u, nil
|
|
}
|
|
|
|
func findUsers(cond bson.M, opts ...*options.FindOptions) ([]*User, error) {
|
|
var u []*User
|
|
if err := coll(nil).Find(&u, cond, opts...); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "findUsers", table, "Find", err),
|
|
log.Any("cond", cond),
|
|
)
|
|
return u, err
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func findUsersMap(cond bson.M) (map[uint64]*User, error) {
|
|
us, err := findUsers(cond)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
m := make(map[uint64]*User)
|
|
for _, u := range us {
|
|
if u == nil {
|
|
continue
|
|
}
|
|
m[u.UID] = u
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func UserMap(uidList []uint64) (map[uint64]*User, error) {
|
|
if len(uidList) == 0 {
|
|
return make(map[uint64]*User), nil
|
|
}
|
|
filter := bson.M{"uid": bson.M{"$in": uidList}}
|
|
return findUsersMap(filter)
|
|
}
|
|
|
|
func userCount(cond bson.M) (int64, error) {
|
|
return coll(nil).Count(cond)
|
|
}
|
|
|
|
func FindUIDByCreateTime(start time.Time, end time.Time) ([]uint64, error) {
|
|
filter := bson.M{
|
|
"createdAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
users, err := findUsers(filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
uidList := make([]uint64, len(users))
|
|
for i, user := range users {
|
|
uidList[i] = user.UID
|
|
}
|
|
return uidList, nil
|
|
}
|
|
|
|
// FindUsersByUID uids查找用户
|
|
func FindUsersByUID(uids []uint64) ([]*User, error) {
|
|
return findUsers(bson.M{"uid": bson.M{"$in": uids}})
|
|
}
|
|
|
|
// FindUsersByUID uids查找用户
|
|
func FindUsersMapByUID(uids []uint64) (map[uint64]*User, error) {
|
|
users, err := findUsers(bson.M{"uid": bson.M{"$in": uids}})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var uMap = make(map[uint64]*User)
|
|
for _, v := range users {
|
|
_v := v
|
|
uMap[v.UID] = _v
|
|
}
|
|
return uMap, nil
|
|
}
|
|
|
|
// FindUsersByKeyword 通过关键字获取用户列表
|
|
func FindUsersByKeyword(keyword string, skip int64, limit int64) ([]*User, error) {
|
|
opt := (&options.FindOptions{}).SetSkip(skip).SetLimit(limit)
|
|
filter := bson.M{
|
|
"name": bson.M{
|
|
"$regex": fmt.Sprintf("^%s", keyword),
|
|
},
|
|
}
|
|
return findUsers(filter, opt)
|
|
}
|
|
|
|
// FindUsersByCreateTime 新用户列表
|
|
func NewUserList(skip int64, limit int64) ([]*User, error) {
|
|
sort := bson.D{{Key: "updatedAt", Value: -1}}
|
|
opt := (&options.FindOptions{}).SetSort(sort).SetSkip(skip).SetLimit(limit)
|
|
return findUsers(bson.M{}, opt)
|
|
}
|
|
|
|
// InsertUser 插入用户
|
|
func InsertUser(u *User) error {
|
|
now := time.Now()
|
|
u.CreatedAt = now
|
|
u.UpdatedAt = now
|
|
if u.Mobile != "" {
|
|
u.MobileBindAt = &now
|
|
}
|
|
if _, err := coll(nil).InsertOne(u); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertUser", table, "InsertOne", err),
|
|
log.Any("u", u),
|
|
)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FindUserByDevID 设备id查找用户
|
|
func FindUserByDevID(devID string) (*User, error) {
|
|
return findUser(bson.M{"devID": devID})
|
|
}
|
|
|
|
// FindUserByToken token查找用户
|
|
func FindUserByToken(token string) (*User, error) {
|
|
return findUser(bson.M{"token": token})
|
|
}
|
|
|
|
func FindUserByUIDForNoCache(uid uint64) (*User, error) {
|
|
return findUser(bson.M{"uid": uid})
|
|
}
|
|
|
|
func RefreshCache(uid uint64) {
|
|
redisCachDel(uid)
|
|
}
|
|
|
|
func RefreshCacheAndGetUser(uid uint64) (*User, error) {
|
|
redisCachDel(uid)
|
|
return FindUserByUID(uid)
|
|
}
|
|
|
|
func FindUserByUIDTrans(t *db.MongoTool, uid uint64) (*User, error) {
|
|
var u User
|
|
if err := coll(t).FindOne(&u, bson.M{"uid": uid}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "findUser", table, "FindUserByUIDTrans", err))
|
|
return nil, err
|
|
}
|
|
if u.UID == 0 {
|
|
return nil, nil
|
|
}
|
|
return &u, nil
|
|
}
|
|
|
|
// FindUserByUID 根据uid获取用户信息。首先尝试缓存,若从缓存中获取失败,再去DB获取用户信息。
|
|
func FindUserByUID(uid uint64) (*User, error) {
|
|
redisKey := redisconst.DataCachKey(table, strconv.FormatUint(uid, 10))
|
|
redisc := getRedis()
|
|
str, err := redisc.Get(redisKey)
|
|
if err != nil { // redis 错误不向上报告
|
|
log.Error("FindUserByUID redisc.Get", log.Any("uid", uid), log.Any("redisKey", redisKey), log.E(err))
|
|
}
|
|
user := &User{}
|
|
if str != nil {
|
|
if err = json.Unmarshal([]byte(*str), user); err == nil {
|
|
return user, nil
|
|
}
|
|
// json.Unmarshal的错误不向上报告,而是尝试去DB获取用户
|
|
log.Error("FindUserByUID json.Unmarshal", log.Any("uid", uid), log.Any("redisKey", redisKey), log.E(err))
|
|
}
|
|
user, err = findUser(bson.M{"uid": uid})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if user == nil {
|
|
return nil, errors.New("empty user")
|
|
}
|
|
common.Go(func() {
|
|
jsonBytes, err := json.Marshal(user)
|
|
if err != nil {
|
|
log.Error("FindUserByUID json.Marshal", log.Any("uid", uid), log.E(err))
|
|
return
|
|
}
|
|
if err := redisc.Set(redisKey, string(jsonBytes), redisconst.DataCachExpire); err != nil {
|
|
log.Error("FindUserByUID redisc.Set", log.Any("uid", uid), log.Any("redisKey", redisKey), log.E(err))
|
|
}
|
|
})
|
|
return user, err
|
|
}
|
|
|
|
// FindUserPromotionCode uid查找用户
|
|
func FindUserPromotionCode(promotionCode string) (*User, error) {
|
|
return findUser(bson.M{"promotionCode": promotionCode})
|
|
}
|
|
|
|
// FindUserByMobile手机号查找用户
|
|
func FindUserByMobile(mobile string) (*User, error) {
|
|
return findUser(bson.M{"mobile": mobile})
|
|
}
|
|
|
|
// FindUserByAccount 根据账号查找用户
|
|
func FindUserByAccount(account string) (*User, error) {
|
|
return findUser(bson.M{"account": account})
|
|
}
|
|
|
|
func findOneAndUpdateUser(t *db.MongoTool, filter bson.M, up bson.M) (*User, error) {
|
|
up["updatedAt"] = time.Now()
|
|
u := &User{}
|
|
if err := coll(t).FindOneAndUpdate(u, filter, bson.M{"$set": up}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "findOneAndUpdateUser", table, "FindOneAndUpdate", err))
|
|
return u, err
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func updateUsers(t *db.MongoTool, filter bson.M, up bson.M) (*mongo.UpdateResult, error) {
|
|
up["updatedAt"] = time.Now()
|
|
return coll(t).UpdateMany(filter, bson.M{"$set": up})
|
|
}
|
|
|
|
// UpdateTrans 修改用户信息(开启事务)
|
|
func UpdateTrans(t *db.MongoTool, uid uint64, set UserSelector) (*User, error) {
|
|
defer redisCachDel(uid)
|
|
setM, err := common.ToBsonM(&set)
|
|
if err != nil {
|
|
log.ZapLog.Warn("user UpdateTrans ToBsonM fail", log.E(err))
|
|
return nil, err
|
|
}
|
|
return findOneAndUpdateUser(t, bson.M{"uid": uid}, setM)
|
|
}
|
|
|
|
// UpdateTrans 修改用户信息(开启事务)
|
|
func UpdateVIP(t *db.MongoTool, uid uint64, vipExpireDate time.Time, set UserSelector) error {
|
|
defer redisCachDel(uid)
|
|
now := time.Now()
|
|
set.UpdatedAt = &now
|
|
res, err := coll(t).UpdateOne(bson.M{"uid": uid, "vipExpireDate": vipExpireDate}, bson.M{"$set": set})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateVIP", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
log.Any("vipExpireDate", vipExpireDate.String()),
|
|
log.Any("set", set),
|
|
)
|
|
return err
|
|
}
|
|
if res.ModifiedCount == 0 {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateVIP", table, "res.ModifiedCount == 0", err),
|
|
log.Any("uid", uid),
|
|
log.Any("set", set),
|
|
)
|
|
return errors.New("user UpdateVIP ModifiedCount err")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func UpdateManyTrans(t *db.MongoTool, uid []uint64, set UserSelector) (*mongo.UpdateResult, error) {
|
|
defer redisCachDelMany(uid)
|
|
setM, err := common.ToBsonM(&set)
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateManyTrans", table, "ToBsonM", err),
|
|
log.Any("uid", uid),
|
|
log.Any("set", set),
|
|
)
|
|
return nil, err
|
|
}
|
|
return updateUsers(t, bson.M{"uid": bson.M{"$in": uid}}, setM)
|
|
}
|
|
|
|
func UpdateMany(uids []uint64, set UserSelector) (*mongo.UpdateResult, error) {
|
|
return UpdateManyTrans(nil, uids, set)
|
|
}
|
|
|
|
// Update ()修改用户信息
|
|
func Update(uid uint64, set UserSelector) (*User, error) {
|
|
t := time.Now()
|
|
set.UpdatedAt = &t
|
|
return UpdateTrans(nil, uid, set)
|
|
}
|
|
|
|
// UpdateSnapVip ()修改用户信息
|
|
func UpdateSnapVip(uid uint64, set UserSelector) (*User, error) {
|
|
t := time.Now()
|
|
set.UpdatedAt = &t
|
|
s, _ := common.ToBsonM(set)
|
|
return findOneAndUpdateUser(nil, bson.M{"uid": uid, "snapVip": 0}, s)
|
|
}
|
|
|
|
// UpdateUserCountWorks 更新用户作品数
|
|
func UpdateUserCountWorks(m map[uint64]int64) error {
|
|
var writes []mongo.WriteModel
|
|
for uid, n := range m {
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
}
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"totalWorks": n,
|
|
},
|
|
} // 这里不去更新 updatedAt(更新时间),以免引起连锁更新,导致服务器高负载
|
|
writes = append(writes, mongo.NewUpdateOneModel().
|
|
SetFilter(filter).
|
|
SetUpdate(update),
|
|
)
|
|
if len(writes) > 100 {
|
|
opt := options.BulkWrite().SetOrdered(false)
|
|
_, err := coll(nil).Bulk(writes, opt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
writes = writes[:0]
|
|
}
|
|
}
|
|
if len(writes) == 0 {
|
|
return nil
|
|
}
|
|
opt := options.BulkWrite().SetOrdered(false)
|
|
_, err := coll(nil).Bulk(writes, opt)
|
|
return err
|
|
}
|
|
|
|
func ChangeVisit(uid uint64, lastVer, lastSysType string, lastVisitAt time.Time) error {
|
|
update := bson.M{
|
|
"$set": bson.M{"lastVisitAt": lastVisitAt, "lastVer": lastVer, "lastSysType": lastSysType},
|
|
"$inc": bson.M{"loginDays": 1},
|
|
}
|
|
if _, err := coll(nil).UpdateOne(bson.M{"uid": uid}, update); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ChangeVisit", table, "UpdateOne", err))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ClaimDefaultEntryVersion 将当前 App 版本标记为已处理默认入口。
|
|
// 同一用户同一版本只有第一次调用会返回 true,用于避免重复触发默认入口。
|
|
func ClaimDefaultEntryVersion(uid uint64, ver string) (bool, error) {
|
|
if uid == 0 || ver == "" {
|
|
return false, nil
|
|
}
|
|
cacheKey := redisconst.DataCachKey("default_entry_version", strconv.FormatUint(uid, 10))
|
|
redisc := getRedis()
|
|
if redisc != nil {
|
|
cachedVer, err := redisc.Get(cacheKey)
|
|
if err != nil {
|
|
log.Warn("ClaimDefaultEntryVersion cache get failed", log.Any("uid", uid), log.E(err))
|
|
} else if cachedVer != nil && *cachedVer == ver {
|
|
return false, nil
|
|
}
|
|
}
|
|
res, err := coll(nil).UpdateOne(
|
|
bson.M{"uid": uid, "defaultEntryHandledVer": bson.M{"$ne": ver}},
|
|
bson.M{"$set": bson.M{"defaultEntryHandledVer": ver}},
|
|
)
|
|
if err != nil {
|
|
log.Warn("ClaimDefaultEntryVersion failed", log.Any("uid", uid), log.E(err))
|
|
return false, err
|
|
}
|
|
if res.ModifiedCount == 0 {
|
|
if redisc != nil {
|
|
_ = redisc.Set(cacheKey, ver, 30*24*time.Hour)
|
|
}
|
|
return false, nil
|
|
}
|
|
redisCachDel(uid)
|
|
if redisc != nil {
|
|
if err := redisc.Set(cacheKey, ver, 30*24*time.Hour); err != nil {
|
|
log.Warn("ClaimDefaultEntryVersion cache set failed", log.Any("uid", uid), log.E(err))
|
|
}
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func BulkWrite(models []mongo.WriteModel) error {
|
|
_, err := coll(nil).Bulk(models, options.BulkWrite().SetOrdered(false))
|
|
return err
|
|
}
|
|
|
|
func ChangeEmail(uid uint64, email string) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"emailCheckedAt": bson.M{"$exists": true},
|
|
}
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"email": email,
|
|
"updatedAt": time.Now(),
|
|
},
|
|
}
|
|
res, err := coll(nil).UpdateOne(filter, update)
|
|
if err != nil {
|
|
return false, errors.Wrap(err, fmt.Sprintf("change user[%d] email[%s] falied", uid, email))
|
|
}
|
|
return res.ModifiedCount > 0, nil
|
|
}
|
|
|
|
func ChangeMobile(uid uint64, mobile string) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
//mobileBindAt存在,更换手机号
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"mobileBindAt": bson.M{"$exists": true},
|
|
}
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"mobile": mobile,
|
|
"updatedAt": time.Now(),
|
|
},
|
|
}
|
|
ret, err := coll(nil).UpdateOne(filter, update)
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ChangeMobile", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
log.Any("mobile", mobile),
|
|
)
|
|
switch exception := err.(type) {
|
|
case mongo.WriteException:
|
|
for _, e := range exception.WriteErrors {
|
|
if e.Code == 11000 { //https://docs.mongodb.com/manual/reference/method/db.collection.insert/index.html
|
|
return false, MobileHasBindError{uid, mobile}
|
|
}
|
|
}
|
|
}
|
|
return false, err
|
|
}
|
|
return ret.MatchedCount+ret.ModifiedCount > 0, nil
|
|
}
|
|
|
|
func BindAccount(uid, newUid uint64, account, password, devID string) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"$or": []bson.M{
|
|
{"accountBindAt": bson.M{"$exists": false}},
|
|
{"accountBindAt": nil},
|
|
},
|
|
}
|
|
now := time.Now()
|
|
set := bson.M{
|
|
"account": account,
|
|
"passWord": password,
|
|
"uid": newUid,
|
|
"userType": UserUnkown,
|
|
"devID": devID,
|
|
"accountBindAt": now,
|
|
"updatedAt": now,
|
|
"createdAt": now,
|
|
}
|
|
res, err := coll(nil).UpdateOne(filter, bson.M{"$set": set})
|
|
if err != nil {
|
|
return false, errors.Wrap(err, fmt.Sprintf("bind user[%d] account[%s] failed", uid, account))
|
|
}
|
|
return res.ModifiedCount > 0, nil
|
|
}
|
|
|
|
func BindEmail(uid uint64, email, password string) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"$or": []bson.M{
|
|
{"emailCheckedAt": bson.M{"$exists": false}},
|
|
{"emailCheckedAt": nil},
|
|
},
|
|
}
|
|
now := time.Now()
|
|
set := bson.M{
|
|
"email": email,
|
|
"emailCheckedAt": now,
|
|
"updatedAt": now,
|
|
}
|
|
if password != "" {
|
|
set["passWord"] = password
|
|
}
|
|
res, err := coll(nil).UpdateOne(filter, bson.M{"$set": set})
|
|
if err != nil {
|
|
return false, errors.Wrap(err, fmt.Sprintf("bind user[%d] email[%s] failed", uid, email))
|
|
}
|
|
return res.ModifiedCount > 0, nil
|
|
}
|
|
|
|
func BindMobile(t *db.MongoTool, uid uint64, mobile, passWord string) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
now := time.Now()
|
|
//mobileBindAt不存在,绑定手机号
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"$or": bson.A{
|
|
bson.M{"mobileBindAt": bson.M{"$exists": false}},
|
|
bson.M{"mobileBindAt": nil},
|
|
},
|
|
}
|
|
set := bson.M{
|
|
"mobile": mobile,
|
|
"mobileBindAt": now,
|
|
"updatedAt": now,
|
|
}
|
|
if passWord != "" {
|
|
set["passWord"] = passWord
|
|
}
|
|
update := bson.M{
|
|
"$set": set,
|
|
}
|
|
if _, err := coll(t).UpdateOne(filter, update); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BindMobile", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
log.Any("mobile", mobile),
|
|
)
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func UnBindMobile(uid uint64) (bool, error) {
|
|
defer redisCachDel(uid)
|
|
//mobileBindAt存在,解绑手机号
|
|
now := time.Now()
|
|
filter := bson.M{
|
|
"uid": uid,
|
|
"mobileBindAt": bson.M{"$exists": true},
|
|
}
|
|
update := bson.M{
|
|
"$set": bson.M{
|
|
"mobile": "",
|
|
"mobileUnBindAt": now,
|
|
"updatedAt": now,
|
|
},
|
|
}
|
|
ret, err := coll(nil).UpdateOne(filter, update)
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UnBindMobile", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return false, err
|
|
}
|
|
return ret.MatchedCount+ret.ModifiedCount > 0, nil
|
|
}
|
|
|
|
func UpdateUserToken(uid uint64, token string) (*User, error) {
|
|
return Update(uid, UserSelector{Token: &token})
|
|
}
|
|
|
|
func UpdateUserVipLevel(uid uint64, lvl int) (*User, error) {
|
|
return Update(uid, UserSelector{VipLevel: &lvl})
|
|
}
|
|
|
|
func UpdateSelf(uid uint64, set UserModifyReq) (*User, error) {
|
|
defer redisCachDel(uid)
|
|
return Update(uid, UserSelector{
|
|
Gender: set.Gender,
|
|
Name: set.Name,
|
|
Portrait: set.Portrait,
|
|
Background: set.Background,
|
|
Summary: set.Summary,
|
|
Region: set.Region,
|
|
Birthday: set.Birthday,
|
|
AppLock: set.AppLock,
|
|
UpdatedAt: set.UpdatedAt,
|
|
})
|
|
}
|
|
|
|
// 扣减次数
|
|
func DincUserWatchCount(uid uint64) (*User, error) {
|
|
defer redisCachDel(uid)
|
|
filter := bson.M{"uid": uid, "watchCount": bson.M{"$gte": 1}}
|
|
u := &User{}
|
|
if err := coll(nil).FindOneAndUpdate(u, filter, bson.M{"$inc": bson.M{"watchCount": -1}}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DincUserWatchCount", table, "FindOneAndUpdate", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return u, err
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func UpdateUserWatchCount(uid uint64, count int64) (*User, error) {
|
|
defer redisCachDel(uid)
|
|
filter := bson.M{"uid": uid, "watchCount": bson.M{"$gte": 0}}
|
|
u := &User{}
|
|
if err := coll(nil).FindOneAndUpdate(u, filter, bson.M{"$set": bson.M{"watchCount": count}}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateUserWatchCount", table, "FindOneAndUpdate", err),
|
|
log.Any("uid", uid),
|
|
)
|
|
return u, err
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
// 后台devID重置
|
|
func ResetDevID(uid uint64, devID string) error {
|
|
defer redisCachDel(uid)
|
|
if _, err := coll(nil).UpdateOne(bson.M{"uid": uid}, bson.M{"$set": bson.M{"devID": devID}}); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ResetDevID", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
log.Any("devID", devID),
|
|
)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetUsersBaseInfo(uids []uint64) ([]*BaseInfo, error) {
|
|
var data []*BaseInfo
|
|
if len(uids) == 0 {
|
|
return data, nil
|
|
}
|
|
us, err := findUsers(bson.M{"uid": bson.M{"$in": uids}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetUsersBaseInfo", table, "findUsers", err),
|
|
log.Any("uids", uids),
|
|
)
|
|
return data, err
|
|
}
|
|
data = make([]*BaseInfo, len(us))
|
|
for i, u := range us {
|
|
data[i] = &BaseInfo{
|
|
UID: u.UID,
|
|
Name: u.Name,
|
|
Gender: u.Gender,
|
|
Portrait: u.Portrait,
|
|
HasBanned: u.HasBanned,
|
|
HasLocked: u.HasLocked,
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func GetUsersBaseInfoWithVip(uids []uint64) ([]*BaseInfoVip, error) {
|
|
var data []*BaseInfoVip
|
|
if len(uids) == 0 {
|
|
return data, nil
|
|
}
|
|
us, err := findUsers(bson.M{"uid": bson.M{"$in": uids}})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetUsersBaseInfoWithVip", table, "findUsers", err),
|
|
log.Any("uids", uids),
|
|
)
|
|
return data, err
|
|
}
|
|
data = make([]*BaseInfoVip, len(us))
|
|
for i, u := range us {
|
|
isVip := false
|
|
if u.VipExpireDate.After(time.Now()) {
|
|
isVip = true
|
|
}
|
|
data[i] = &BaseInfoVip{
|
|
UID: u.UID,
|
|
Name: u.Name,
|
|
Gender: u.Gender,
|
|
Portrait: u.Portrait,
|
|
HasLocked: u.HasLocked,
|
|
HasBanned: u.HasBanned,
|
|
VipLevel: u.VipLevel,
|
|
IsVip: isVip,
|
|
//RechargeLevel: ,
|
|
SuperUser: u.SuperUser,
|
|
ActiveValue: u.ActiveValue,
|
|
OfficialCert: u.OfficialCert,
|
|
Age: u.Age(),
|
|
Follows: u.Follows,
|
|
Fans: u.Fans,
|
|
TotalWorks: u.TotalWorks,
|
|
Summary: &u.Summary,
|
|
Awards: u.Awards,
|
|
UpTag: u.UpTag,
|
|
VipName: u.VipName,
|
|
VipExpireDate: u.VipExpireDate,
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func GetUsersBaseInfoVIPMap(uids []uint64) (map[uint64]*BaseInfoVip, error) {
|
|
m := make(map[uint64]*BaseInfoVip)
|
|
infos, err := GetUsersBaseInfoWithVip(uids)
|
|
if err != nil {
|
|
return m, err
|
|
}
|
|
for _, info := range infos {
|
|
m[info.UID] = info
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func GetUsersBaseInfoMap(uids []uint64) (map[uint64]*BaseInfo, error) {
|
|
m := make(map[uint64]*BaseInfo)
|
|
infos, err := GetUsersBaseInfo(uids)
|
|
if err != nil {
|
|
return m, err
|
|
}
|
|
for _, info := range infos {
|
|
m[info.UID] = info
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// CountByCreatedAt 时间内注册数
|
|
func CountByCreatedAt(start, end time.Time, mats ...Matcher) (int64, error) {
|
|
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
|
return Count(mats...)
|
|
}
|
|
|
|
// NewAndBindInfoCountByTime
|
|
func BindCountByTime(start time.Time, end time.Time) (int64, error) {
|
|
filter := bson.M{
|
|
"mobileBindAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
return userCount(filter)
|
|
}
|
|
|
|
func UnBindCountByTime(start time.Time, end time.Time) (int64, error) {
|
|
filter := bson.M{
|
|
"mobileUnBindAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
return userCount(filter)
|
|
}
|
|
|
|
// NewAndBindCountByTime
|
|
func NewAndBindCountByTime(createStart, createEnd, start, end time.Time) (int64, error) {
|
|
filter := bson.M{
|
|
"mobile": bson.M{
|
|
"$ne": "",
|
|
},
|
|
"createdAt": bson.M{
|
|
"$gte": createStart,
|
|
"$lt": createEnd,
|
|
},
|
|
"mobileBindAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
return userCount(filter)
|
|
}
|
|
|
|
// ChannelNewUserCountByTime 时间内渠道注册数
|
|
func ChannelNewUserCountByTime(start time.Time, end time.Time) (map[string]int64, error) {
|
|
pipeLine := []bson.M{
|
|
{"$match": bson.M{"createdAt": bson.M{"$gte": start, "$lt": end}}},
|
|
{"$group": bson.M{"_id": "$channel", "count": bson.M{"$sum": 1}}},
|
|
}
|
|
docList := []struct {
|
|
Channel string `bson:"_id"`
|
|
Count int64 `bson:"count"`
|
|
}{}
|
|
if err := coll(nil).Aggregate(&docList, pipeLine); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ChannelNewUserCountByTime", table, "Aggregate", err),
|
|
log.Any("start", start),
|
|
log.Any("end", end),
|
|
)
|
|
return nil, err
|
|
}
|
|
ret := make(map[string]int64, len(docList))
|
|
for _, doc := range docList {
|
|
ret[doc.Channel] = doc.Count
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
// ChannelBindUserCountByTime 渠道绑定用户数
|
|
func ChannelBindUserCountByTime(start time.Time, end time.Time) (map[string]int64, error) {
|
|
pipeLine := []bson.M{
|
|
{
|
|
"$match": bson.M{
|
|
"mobile": bson.M{
|
|
"$ne": "",
|
|
},
|
|
"mobileBindAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"$group": bson.M{
|
|
"_id": "$channel", "count": bson.M{"$sum": 1},
|
|
},
|
|
},
|
|
}
|
|
docList := []struct {
|
|
Channel string `bson:"_id"`
|
|
Count int64 `bson:"count"`
|
|
}{}
|
|
if err := coll(nil).Aggregate(&docList, pipeLine); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ChannelBindUserCountByTime", table, "Aggregate", err),
|
|
log.Any("start", start),
|
|
log.Any("end", end),
|
|
)
|
|
return nil, err
|
|
}
|
|
ret := make(map[string]int64, len(docList))
|
|
for _, doc := range docList {
|
|
ret[doc.Channel] = doc.Count
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
// ChannelNewAndBindUserCountByTime 渠道新增并绑定用户数
|
|
func ChannelNewAndBindUserCountByTime(start time.Time, end time.Time) (map[string]int64, error) {
|
|
dayRange := timerange.LocDayRange(start)
|
|
pipeLine := []bson.M{
|
|
{
|
|
"$match": bson.M{
|
|
"mobile": bson.M{
|
|
"$ne": "",
|
|
},
|
|
"createdAt": bson.M{
|
|
"$gte": dayRange.Head,
|
|
"$lt": dayRange.Tail,
|
|
},
|
|
"mobileBindAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"$group": bson.M{
|
|
"_id": "$channel", "count": bson.M{"$sum": 1},
|
|
},
|
|
},
|
|
}
|
|
docList := []struct {
|
|
Channel string `bson:"_id"`
|
|
Count int64 `bson:"count"`
|
|
}{}
|
|
if err := coll(nil).Aggregate(&docList, pipeLine); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ChannelNewAndBindUserCountByTime", table, "Aggregate", err),
|
|
log.Any("start", start),
|
|
log.Any("end", end),
|
|
)
|
|
return nil, err
|
|
}
|
|
ret := make(map[string]int64, len(docList))
|
|
for _, doc := range docList {
|
|
ret[doc.Channel] = doc.Count
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func UIDList(mats ...Matcher) ([]uint64, error) {
|
|
filter := pageopt.MergeM(mats)
|
|
list := []struct {
|
|
UID uint64 `bson:"uid"`
|
|
}{}
|
|
opt := (&options.FindOptions{}).SetProjection(bson.M{
|
|
"uid": 1,
|
|
})
|
|
if err := coll(nil).Find(&list, filter, opt); err != nil {
|
|
return nil, err
|
|
}
|
|
uidList := make([]uint64, len(list))
|
|
for i, v := range list {
|
|
uidList[i] = v.UID
|
|
}
|
|
return uidList, nil
|
|
}
|
|
|
|
func UIDListByCreateTime(start, end time.Time, mats ...Matcher) ([]uint64, error) {
|
|
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
|
return UIDList(mats...)
|
|
}
|
|
|
|
func UIDListByCreateTimeAndUIDS(start, end time.Time, uids []uint64, mats ...Matcher) ([]uint64, error) {
|
|
mats = append(mats, (&UIDInMatch{UIDS: uids}).New())
|
|
return UIDListByCreateTime(start, end, mats...)
|
|
}
|
|
|
|
func UserListByCreateTimeAndUIDS(start, end time.Time, uids []uint64, mats ...Matcher) ([]User, error) {
|
|
mats = append(mats,
|
|
(&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New(),
|
|
(&UIDInMatch{UIDS: uids}).New())
|
|
filter := pageopt.MergeM(mats)
|
|
list := make([]User, 0, len(uids))
|
|
return list, coll(nil).Find(&list, filter)
|
|
}
|
|
|
|
func ChannelMapByCreateTime(start, end time.Time) (map[uint64]string, error) {
|
|
filter := bson.M{
|
|
"createdAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
list := make([]struct {
|
|
Channel string `bson:"channel"`
|
|
UID uint64 `bson:"uid"`
|
|
}, 0)
|
|
if err := coll(nil).Find(&list, filter); err != nil {
|
|
return nil, err
|
|
}
|
|
m := make(map[uint64]string, len(list))
|
|
for _, v := range list {
|
|
m[v.UID] = v.Channel
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// 获取ES同步数据
|
|
func GetUserListByUpdateTimeRange(start time.Time, end time.Time, page int, size int) (data []User, hasNext bool, err error) {
|
|
var query = bson.M{
|
|
"updatedAt": bson.M{"$gte": start, "$lt": end},
|
|
}
|
|
opts := options.FindOptions{}
|
|
opts.SetSort(bson.D{{Key: "_id", Value: 1}})
|
|
opts.SetSkip(int64((page - 1) * size)).SetLimit(int64(size) + 1)
|
|
if err = coll(nil).Find(&data, query, &opts); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetUserListByUpdateTimeRange", table, "Find", err),
|
|
log.Any("start", start),
|
|
log.Any("end", end),
|
|
)
|
|
return
|
|
}
|
|
if len(data) > size {
|
|
hasNext = true
|
|
data = data[:size]
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func redisCachDel(uid uint64) {
|
|
redisKey := redisconst.DataCachKey(table, strconv.FormatUint(uid, 10))
|
|
if _, err := getRedis().Del(redisKey); err != nil {
|
|
log.Error("redis del user, ", log.Any("err:", err.Error()), log.Any("uid:", uid))
|
|
}
|
|
}
|
|
|
|
func redisCachDelMany(uids []uint64) {
|
|
keys := make([]string, len(uids))
|
|
for i, v := range uids {
|
|
keys[i] = redisconst.DataCachKey(table, strconv.FormatUint(v, 10))
|
|
}
|
|
_, _ = getRedis().Del(keys...)
|
|
}
|
|
|
|
func getRedis() *redis.Client {
|
|
if appg.Redis != nil {
|
|
return appg.Redis
|
|
}
|
|
if webg.Redis != nil {
|
|
return webg.Redis
|
|
}
|
|
if skdg.Redis != nil {
|
|
return skdg.Redis
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetLockedUIDMap() (map[uint64]byte, error) {
|
|
filter := bson.M{
|
|
"hasLocked": true,
|
|
}
|
|
list := make([]struct {
|
|
UID uint64 `bson:"uid"`
|
|
}, 0)
|
|
opt := (&options.FindOptions{}).SetProjection(bson.M{
|
|
"uid": 1,
|
|
})
|
|
if err := coll(nil).Find(&list, filter, opt); err != nil {
|
|
return nil, err
|
|
}
|
|
uidMap := make(map[uint64]byte, len(list))
|
|
for _, v := range list {
|
|
uidMap[v.UID] = 1
|
|
}
|
|
return uidMap, nil
|
|
}
|
|
|
|
func DistrictCodeMap(uidList []uint64) (map[uint64]string, error) {
|
|
if len(uidList) == 0 {
|
|
return make(map[uint64]string), nil
|
|
}
|
|
filter := bson.M{"uid": bson.M{"$in": uidList}}
|
|
userList, err := findUsers(filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
m := make(map[uint64]string, len(userList))
|
|
for _, v := range userList {
|
|
m[v.UID] = v.DistrictCode
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func GetSystemUsers() (data []User, err error) {
|
|
if err = coll(nil).Find(&data, bson.M{"uid": bson.M{"$lte": constant.RobotUIDLimit}}); err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetSystemUsers", table, "Find", err))
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// SetDeductType 设置扣量类型
|
|
func SetDeductType(t *db.MongoTool, uid uint64, deductType commod.DeductType) error {
|
|
filter := bson.M{"uid": uid}
|
|
update := bson.M{"$unset": bson.M{"deductType": deductType}}
|
|
if deductType != commod.NotDed {
|
|
update = bson.M{"$set": bson.M{"deductType": deductType}}
|
|
}
|
|
_, err := coll(t).UpdateOne(filter, update)
|
|
return err
|
|
}
|
|
|
|
func GetCountMapByHour(discCode string, start, end time.Time, mats ...Matcher) ([]int, map[int]int64, int64, error) {
|
|
mats = append(mats,
|
|
(&DistrictCodeMatch{&discCode}).New(),
|
|
(&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New(),
|
|
)
|
|
filter := pageopt.MergeM(mats)
|
|
opt := (&options.FindOptions{}).SetProjection(bson.M{
|
|
"createdAt": 1,
|
|
})
|
|
var list []struct {
|
|
CreatedAt time.Time `bson:"createdAt"` //创建时间
|
|
}
|
|
if err := coll(nil).Find(&list, filter, opt); err != nil {
|
|
log.Error("usermod GetBuyVipCountMap error", log.E(err))
|
|
return nil, nil, 0, err
|
|
}
|
|
m := make(map[int]int64)
|
|
startH := start.Hour()
|
|
lastH := end.Hour() + (end.Day()-start.Day())*24
|
|
hs := make([]int, lastH-startH+1)
|
|
for i, j := startH, 0; i <= lastH; i++ {
|
|
m[i] = 0
|
|
hs[j] = i
|
|
j++
|
|
}
|
|
var total int64
|
|
for _, v := range list {
|
|
hour := v.CreatedAt.Hour() + (v.CreatedAt.Day()-start.Day())*24
|
|
m[hour] += 1
|
|
total++
|
|
}
|
|
return hs, m, total, nil
|
|
}
|
|
|
|
// IncFollow 增加关注数
|
|
func IncFollow(uid uint64) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"follows": 1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// IncFollowByNum 增加关注数
|
|
func IncFollowByNum(uid uint64, num int64) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"follows": num}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// DecFollow 减去关注数
|
|
func DecFollow(uid uint64) error {
|
|
cond := bson.M{"uid": uid, "follows": bson.M{"$gt": 0}}
|
|
update := bson.M{"$inc": bson.M{"follows": -1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// IncFans 增加粉丝数
|
|
func IncFans(uid uint64) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"fans": 1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// IncLikeCount 增加点赞数
|
|
func IncLikeCount(uid uint64) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"likeCount": 1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// DecFans 减去粉丝数
|
|
func DecFans(uid uint64) error {
|
|
cond := bson.M{"uid": uid, "fans": bson.M{"$gt": 0}}
|
|
update := bson.M{"$inc": bson.M{"fans": -1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// InitFansFollows 初始化关注数和粉丝数
|
|
func InitFansFollows(uid uint64, followCnt int64, fansCnt int64) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$set": bson.M{"follows": followCnt, "fans": fansCnt, "followsSetFlag": true}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// 添加ai脱衣次数
|
|
func IncUserAiUndress(t *db.MongoTool, uid uint64, count uint64) error {
|
|
_, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"aiUndressCount": count}})
|
|
return err
|
|
}
|
|
|
|
// UpdateById 修改用户信息
|
|
func UpdateById(t *db.MongoTool, uid uint64, bannedTime time.Time) error {
|
|
defer redisCachDel(uid)
|
|
_, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{"$set": bson.M{"bannedTime": bannedTime}})
|
|
return err
|
|
}
|
|
|
|
func DecUserAiUndress(t *db.MongoTool, uid uint64, count uint64) error {
|
|
_, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"aiUndressCount": -int64(count)}})
|
|
return err
|
|
}
|
|
|
|
// IncRewarded 增加打赏金额
|
|
func IncRewarded(uid uint64, decimal decimal.Decimal) error {
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"rewarded": decimal}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
func StatcenterSyncList(uid uint64, size int64) (UserSlice, error) {
|
|
opt := (&options.FindOptions{})
|
|
opt.SetLimit(size)
|
|
opt.SetSort(bson.M{"uid": 1})
|
|
filter := bson.M{"uid": bson.M{"$gt": uid}, "userType": bson.M{"$in": []UserType{UserUnkown, UserLoufengAgent}}}
|
|
userList := UserSlice{}
|
|
return userList, coll(nil).Find(&userList, filter, opt)
|
|
}
|
|
|
|
func GetRandomSystemUsers(size uint64) (data []*User, err error) {
|
|
data = make([]*User, 0)
|
|
var pipeline = []bson.M{
|
|
{"$match": bson.M{"uid": bson.M{"$lte": constant.RobotUIDLimit}}},
|
|
{"$sample": bson.M{"size": size}},
|
|
}
|
|
if err = coll(nil).Aggregate(&data, pipeline); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetRandomSystemUsers", table, "Aggregate", err), log.Any("pipeline", pipeline))
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// GetOriginalBlogger 获取原创博主
|
|
func GetOriginalBlogger(skip, limit int64) (data []*User, hasNext bool, err error) {
|
|
opts := options.Find().SetSort(bson.D{{Key: "originalSort", Value: -1}}).SetSkip(skip).SetLimit(limit + 1)
|
|
cond := bson.M{"officialCert": true}
|
|
if err = coll(nil).Find(&data, cond, opts); err != nil {
|
|
return
|
|
}
|
|
if len(data) == int(limit)+1 {
|
|
hasNext = true
|
|
data = data[:limit]
|
|
}
|
|
return
|
|
}
|
|
|
|
// 同步数据查询绑定手机用户
|
|
func StatcenterSyncBindUserList(time time.Time, size int64) (UserSlice, error) {
|
|
opt := (&options.FindOptions{})
|
|
opt.SetLimit(size)
|
|
opt.SetSort(bson.M{"mobileBindAt": 1})
|
|
filter := bson.M{"mobileBindAt": bson.M{"$gt": time}}
|
|
userList := UserSlice{}
|
|
return userList, coll(nil).Find(&userList, filter, opt)
|
|
}
|
|
|
|
func OfficialCertList(page, size uint64, subType int) ([]*User, bool, error) {
|
|
cond := bson.M{}
|
|
// 原创---工作室
|
|
cond["officialCert"] = true
|
|
opts := options.Find().SetLimit(int64(size + 1)).SetSkip(int64((page - 1) * size)).SetSort(bson.D{{Key: "originalSort", Value: -1}})
|
|
var users []*User
|
|
if err := coll(nil).Find(&users, cond, opts); err != nil {
|
|
return nil, false, err
|
|
}
|
|
var hasNext bool
|
|
if uint64(len(users)) > size {
|
|
hasNext = true
|
|
users = users[:size]
|
|
}
|
|
return users, hasNext, nil
|
|
}
|
|
|
|
// PretendList 获取马甲号列表
|
|
func PretendList(skip int64, limit int64) ([]*User, error) {
|
|
filter := bson.M{
|
|
"uid": bson.M{
|
|
"$gt": 100001,
|
|
"$lt": 100200,
|
|
},
|
|
}
|
|
return findUsers(filter, options.Find().SetLimit(limit).SetSkip(skip))
|
|
}
|
|
|
|
// 获取马甲号总数
|
|
func PretendCount() (int64, error) {
|
|
return coll(nil).Count(bson.M{
|
|
"uid": bson.M{
|
|
"$gt": 100001,
|
|
"$lt": 100200,
|
|
},
|
|
})
|
|
}
|
|
|
|
// IncVideoDeduction 视频播放量更新
|
|
func IncVideoDeduction(uid uint64, check bool) error {
|
|
defer redisCachDel(uid)
|
|
cond := bson.M{"uid": uid}
|
|
inc := bson.M{"videoDeductionPayCount": 1}
|
|
if check {
|
|
inc["videoDeductionCount"] = 1
|
|
}
|
|
update := bson.M{"$inc": inc}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// IncCoverCount 出售图片量更新
|
|
func IncCoverCount(uid uint64) error {
|
|
_, err := coll(nil).UpdateOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"coverPayCount": 1}})
|
|
return err
|
|
}
|
|
|
|
// IncUploadCount 上传次数更新
|
|
func IncUploadCount(uid uint64, inc UploadCountInc) error {
|
|
defer redisCachDel(uid)
|
|
_, err := coll(nil).UpdateOne(bson.M{"uid": uid}, bson.M{"$inc": inc})
|
|
return err
|
|
}
|
|
|
|
// LouFengUnlockTimesIncr 增加楼凤解锁次数
|
|
func LouFengUnlockTimesIncr(t *db.MongoTool, uid uint64, times int) error {
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"louFengUnlockTimes": times}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount == 0 {
|
|
return errors.New("result.ModifiedCount is 0")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// VipInfoChange 会员信息变更
|
|
func VipInfoChange(t *db.MongoTool, uid uint64, levle int, expire time.Time) error {
|
|
result, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{
|
|
"$set": bson.M{
|
|
"vipExpireDate": expire,
|
|
"vipLevel": levle,
|
|
}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.ModifiedCount == 0 {
|
|
return errors.New("result.ModifiedCount is 0")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func FindByCreateTime(start time.Time, end time.Time) (data []UserStat, err error) {
|
|
filter := bson.M{
|
|
"createdAt": bson.M{
|
|
"$gte": start,
|
|
"$lt": end,
|
|
},
|
|
}
|
|
if err = coll(nil).Find(&data, filter); err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "findUsers", table, "Find", err),
|
|
log.Any("cond", filter),
|
|
)
|
|
}
|
|
return
|
|
}
|
|
|
|
// IncDynamic 增加动态数
|
|
func IncDynamic(uid uint64) error {
|
|
defer redisCachDel(uid)
|
|
cond := bson.M{"uid": uid}
|
|
update := bson.M{"$inc": bson.M{"dynamics": 1}}
|
|
_, err := coll(nil).UpdateOne(cond, update)
|
|
return err
|
|
}
|
|
|
|
// UpdateUserById 修改用户信息(开启事务)
|
|
func UpdateUserById(t *db.MongoTool, uid uint64, set UserSelector) error {
|
|
defer redisCachDel(uid)
|
|
now := time.Now()
|
|
set.UpdatedAt = &now
|
|
res, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{"$set": set})
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateVIP", table, "UpdateOne", err),
|
|
log.Any("uid", uid),
|
|
log.Any("set", set),
|
|
)
|
|
return err
|
|
}
|
|
if res.ModifiedCount == 0 {
|
|
err = errors.New("user UpdateVIP ModifiedCount err")
|
|
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateVIP", table, "res.ModifiedCount == 0", err),
|
|
log.Any("uid", uid),
|
|
log.Any("set", set),
|
|
)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteGuestBeforeDate 删除游客数据
|
|
func DeleteGuestBeforeDate(t *db.MongoTool, tm time.Time) error {
|
|
_, err := coll(t).DeleteMany(bson.M{"updatedAt": bson.M{"$lt": tm}, "userType": UserTourists})
|
|
return err
|
|
}
|
|
|
|
// FetchList 条件获取列表
|
|
func FetchList(filter primitive.M, opts *options.FindOptions, count ...*int64) (out []*User, hasNext bool, err error) {
|
|
if opts == nil {
|
|
opts = options.Find()
|
|
}
|
|
|
|
if opts.Limit == nil {
|
|
opts.SetLimit(1000)
|
|
}
|
|
|
|
if opts.Sort == nil {
|
|
opts.SetSort(bson.D{{Key: "_id", Value: -1}})
|
|
}
|
|
|
|
// 不需要统计总条数 就不要创建count,避免无用的查询
|
|
if len(count) == 1 && count[0] != nil {
|
|
*count[0], err = coll(nil).Count(filter)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
}
|
|
|
|
limit := int(*opts.Limit)
|
|
opts.SetLimit(int64(limit + 1))
|
|
|
|
err = coll(nil).Find(&out, filter, opts)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("[METHOD-FetchList]==> Model %s Find fail error:%+v:", table, err), log.Any("filter", filter))
|
|
return out, false, err
|
|
}
|
|
|
|
hasNext = len(out) > limit
|
|
if hasNext {
|
|
out = out[:limit]
|
|
}
|
|
|
|
return out, hasNext, nil
|
|
}
|