package userctrl import ( "91porn-server/common/db" "91porn-server/models/v/productmod" "91porn-server/models/v/txnmod" "91porn-server/models/v/walletmod" "91porn-server/web/webg" "encoding/json" "fmt" "strings" "time" "go.mongodb.org/mongo-driver/bson/primitive" "91porn-server/common" "91porn-server/common/constant" "91porn-server/common/log" "91porn-server/common/pageopt" "91porn-server/common/stderr" v10 "91porn-server/common/v10" "91porn-server/common/ysphone" "91porn-server/models/commod" "91porn-server/models/l/operatorlgmod" "91porn-server/models/v/operationlogmod" "91porn-server/models/v/usermod" "91porn-server/web/middleware/authweb" "91porn-server/web/service/userser" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" ) // List doc // @Summary 获取用户列表 // @Description 获取用户列表 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param pageNumber query integer true "当前页" // @Param pageSize query integer true "每页条数" // @Param uid query integer false "过滤条件-uid" // @Param devID query string false "过滤条件-设备ID" // @Param vipLevel query integer false "过滤条件-VIP等级" // @Param hasPromotionCode query bool false "过滤条件-有邀请码" // @Param name query string false "过滤条件-用户昵称" // @Param mobile query string false "过滤条件-手机号" // @Param promotionCode query string false "过滤条件-邀请码" // @Param hasLocked query bool false "过滤条件-已禁止登陆" // @Param hasBanned query bool false "过滤条件-已禁言" // @Param forbidUpload query bool false "过滤条件-禁止上传文件" // @Param districtCode query bool false "过滤条件-商区码" // @Param startTime query integer false "过滤条件-开始时间" // @Param endTime query integer false "过滤条件-结束时间" // @Param isPretendAcc query string false "过滤条件-是否马甲账号" // @Param autoFollow query string false "过滤条件-是否配置被自动关注" // @Param registerIP query string false "过滤条件-指定某IP地址注册的用户" // @Success 200 {string} json "{"msg": "操作成功", "date": { "total":10, "list":[] }}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/list [get] func List(c *gin.Context) { type Filter struct { UID *uint64 `form:"uid" json:"uid" binding:""` //uid DevID *string `form:"devID" json:"devID" binding:""` //设备ID VipLevel *int `form:"vipLevel" json:"vipLevel" binding:""` //vip等级 Name *string `form:"name" json:"name" binding:""` //用户名 Mobile *string `form:"mobile" json:"mobile" binding:""` //手机号 PromotionCode *string `form:"promotionCode" json:"promotionCode" binding:""` //推广码 HasPromotionCode *bool `form:"hasPromotionCode" json:"hasPromotionCode" binding:""` //有推广码 HasLocked *bool `form:"hasLocked" json:"hasLocked" binding:""` //已禁止登陆 HasBanned *bool `form:"hasBanned" json:"hasBanned" binding:""` //已禁言 ForbidUpload *bool `form:"forbidUpload" json:"forbidUpload" binding:""` //是否禁止上传文件 StartTime *time.Time `form:"startTime" json:"startTime" binding:""` //开始时间 EndTime *time.Time `form:"endTime" json:"endTime" binding:""` //结束时间 DistrictCode *string `form:"districtCode" json:"districtCode" binding:""` //商区码 IsPretendAcc *int `form:"isPretendAcc" json:"isPretendAcc"` //是否马甲账号 AutoFollow *bool `form:"autoFollow" json:"autoFollow" binding:""` //是否配置被自动关注 RegisterIP *string `form:"registerIP" json:"registerIP" binding:"-"` // IP过滤 } var arg struct { commod.Page Filter } if err := c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "user List arg error "+err.Error()) return } //马甲账户 if arg.IsPretendAcc != nil && *arg.IsPretendAcc == 1 { devID := "^" + usermod.SystemDevIDPrex arg.DevID = &devID } if arg.Name != nil { name := "^" + *arg.Name arg.Name = &name } sort := bson.D{{Key: "createdAt", Value: -1}} skip := int64((arg.PageNumber - 1) * arg.PageSize) limit := int64(arg.PageSize) page, err := userser.UserPages(sort, skip, limit, pageopt.UIDMatch{UID: arg.UID}, usermod.DevIDRegexMatch{DevID: arg.DevID}, usermod.VipLevelMatch{VipLevel: arg.VipLevel}, usermod.NameRegexMatch{Name: arg.Name}, usermod.MobileMatch{Mobile: arg.Mobile}, usermod.PromotionCodeMatch{PromotionCode: arg.PromotionCode}, usermod.HasPromotionCodeMatch{IsExisted: arg.HasPromotionCode}, usermod.LockedMatch{Locked: arg.HasLocked}, usermod.BannedMatch{Banned: arg.HasBanned}, usermod.ForbidUploadMatch{ForbidUpload: arg.ForbidUpload}, usermod.CreatedAtGTEAndLTMatch{GTE: arg.StartTime, LT: arg.EndTime}, usermod.DistrictCodeMatch{DistrictCode: arg.DistrictCode}, usermod.AutoFollowMatch{AutoFollow: arg.AutoFollow}, usermod.RegisterIpMatch{RegisterIp: arg.RegisterIP}, ) if err != nil { common.ServeJSON(c, stderr.Failure, "user List error: "+err.Error()) return } common.ServeJSON(c, stderr.Success, page) } // Update doc // @Summary 用户编辑 // @Description 用户编辑 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData string false "uid" // @Param vipLevel formData integer false "vip等级" // @Param mobile formData integer false "手机号" // @Param vipExpireDate formData string false "vip到期时间 format:2001-09-07T03:14:54.072Z" // @Param dramaExpire formData string false "短剧权益有效期 format:2001-09-07T03:14:54.072Z" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/update [post] func Update(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } type Update struct { VipExpireDate *string `form:"vipExpireDate" json:"vipExpireDate" binding:""` //vip到期时间 VipExpireDateModifyReason *string `form:"vipExpireDateModifyReason" json:"vipExpireDateModifyReason"` // 修改VIP到期时间原因 VipLevel *int `form:"vipLevel" json:"vipLevel" binding:""` //vip等级 Amount *int64 `form:"amount" json:"amount"` Background *[]string `form:"background" json:"background"` //背景图 //web端零值不传,导致无法将电话改为空 //web端正确情况应是 空值不传(web后台无修改时), 零值应传(web后台修改为""后) Mobile *string `form:"mobile" json:"mobile" binding:""` //手机号 Portrait *string `form:"portrait" json:"portrait"` Region *string `form:"region" json:"region"` //地区 Summary *string `form:"summary" json:"summary"` Name *string `form:"name" json:"name"` SuperUser *bool `form:"superUser" json:"superUser"` //大v OfficialCert *bool `form:"officialCert" json:"officialCert"` //是否官方认证 IsMadou *bool `form:"isMadou" json:"isMadou"` //是否麻豆账号 TaxLevel *int64 `form:"taxLevel" json:"taxLevel"` //扣税等级,默认0,3.7; AutoFollow *bool `form:"autoFollow" json:"autoFollow"` //是否配置被自动关注 BankActName *string `json:"bankActName,omitempty" bson:"bankActName,omitempty"` //银行卡绑定名字 OriginalSort *int `json:"originalSort" bson:"originalSort"` // 新版原创排序 VideoDeduction *float64 `json:"videoDeduction" bson:"videoDeduction"` //视频扣量,1:博主10单扣1单, 以此类推 VideoDeductionPayCount *int `json:"videoDeductionPayCount" bson:"videoDeductionPayCount"` //视频扣量购买次数 VideoDeductionCount *int `json:"videoDeductionCount" bson:"videoDeductionCount"` //视频扣量次数 MerchantAccount *string `json:"merchantAccount,omitempty" bson:"merchantAccount,omitempty"` //商家账号 VipID *string `form:"vipID" json:"vipID" bson:"vipID,omitempty"` // 会员卡ID AllGoldVideoFree *bool `json:"allGoldVideoFree" bson:"allGoldVideoFree"` // 是否所有金币视频免费 GoldVideoFreeExpire *time.Time `json:"goldVideoFreeExpire" bson:"goldVideoFreeExpire,omitempty"` // 金币视频免费日期 GoldVideoFreeLimit *int64 `json:"goldVideoFreeLimit" bson:"goldVideoFreeLimit"` // 金币视频免费限制门槛(包含acg) ChatPrice *int64 `form:"chatPrice" json:"chatPrice"` // 私信价格 BroadcastExpire *time.Time `json:"broadcastExpire" bson:"broadcastExpire,omitempty"` //直播有效期 DramaExpire *time.Time `json:"dramaExpire" bson:"dramaExpire,omitempty"` //短剧权益有效期 } var arg struct { UID uint64 `form:"uid" json:"uid" binding:"required"` Update } if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Update arg error "+err.Error()) return } if arg.VipExpireDate != nil && (arg.VipExpireDateModifyReason == nil || *arg.VipExpireDateModifyReason == "") { common.ServeJSON(c, stderr.ErrParamError, "web user Update arg error: "+"请填写更新用户VIP到期时间的原因") return } //获取更新用户信息 u, err := usermod.FindUserByUIDForNoCache(arg.UID) if err != nil || u == nil { common.ServeJSON(c, stderr.UserIsNotExists, "web user Update arg error: 更新用户不存在 ") return } //视频扣量更新, 则充值扣量次数 if arg.Update.VideoDeduction != nil && *arg.Update.VideoDeduction != 0 && *arg.Update.VideoDeduction != u.VideoDeduction { var n int = 0 arg.Update.VideoDeductionPayCount = &n arg.Update.VideoDeductionCount = &n } //修改账号金币 opLogs := []operationlogmod.OperationLog{} if arg.Amount != nil && *arg.Amount != 0 { opLog, err := userser.ModifyUserAmount(arg.UID, *arg.Amount, manager, "") if err != nil { common.ServeJSON(c, stderr.Failure, err) return } opLogs = []operationlogmod.OperationLog{opLog} } if arg.VipID != nil { oid, err := primitive.ObjectIDFromHex(*arg.VipID) if err != nil { log.Error(fmt.Sprintf("admin add vip param VipID err:%v, VipID:%v", err, *arg.VipID)) common.ServeJSON(c, stderr.ErrParamError, nil) return } code := AddVIP(arg.UID, oid, u.DevType) if code != stderr.Success { log.Error(fmt.Sprintf("admin add vip err:%v,code:%v", code.Error(), code)) common.ServeJSON(c, code, nil) return } } //修改用户手机 if arg.Mobile != nil && u.Mobile != *arg.Mobile { //注意会有空字符串的情况 mobile := *arg.Mobile if *arg.Mobile != "" && (len(mobile) > 6 && mobile[:len(constant.FakeMobilePrefix)] != constant.FakeMobilePrefix) { if !v10.IsGlobalizationPhoneNumber(mobile) { common.ServeJSON(c, stderr.ErrParamError, "web user Update arg.Mobile error") return } } if err = userser.ModifyUserMobile(arg.UID, ysphone.FormatPhoneNumber(*arg.Mobile)); err != nil { switch err.(type) { case usermod.MobileHasBindError: common.ServeJSON(c, stderr.ErrMobileHasBind, err) return } if strings.Contains(err.Error(), "mobile_1") { common.ServeJSON(c, stderr.ErrMobileHasBindByOther, err) return } common.ServeJSON(c, stderr.Failure, err) return } } doc := usermod.UserSelector{ VipLevel: arg.VipLevel, Portrait: arg.Portrait, Summary: arg.Summary, Name: arg.Name, Region: arg.Region, Background: arg.Background, SuperUser: arg.SuperUser, OfficialCert: arg.OfficialCert, TaxLevel: arg.TaxLevel, AutoFollow: arg.AutoFollow, BankActName: arg.BankActName, OriginalSort: arg.OriginalSort, VideoDeduction: arg.VideoDeduction, VideoDeductionCount: arg.VideoDeductionCount, VideoDeductionPayCount: arg.VideoDeductionPayCount, ChatPrice: arg.ChatPrice, BroadcastExpire: arg.BroadcastExpire, DramaExpire: arg.DramaExpire, } if arg.AllGoldVideoFree != nil { doc.AllGoldVideoFree = arg.AllGoldVideoFree } if arg.GoldVideoFreeExpire != nil { doc.GoldVideoFreeExpire = arg.GoldVideoFreeExpire } if arg.GoldVideoFreeLimit != nil { doc.GoldVideoFreeLimit = arg.GoldVideoFreeLimit } if arg.MerchantAccount != nil { doc.MerchantAccount = arg.MerchantAccount } //修改vip到期时间 if arg.VipExpireDate != nil { vipExpireDate, err := time.Parse(time.RFC3339, *arg.VipExpireDate) if err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Update arg.VipExpireDate error "+err.Error()) return } doc.VipExpireDate = &vipExpireDate opLog := operationlogmod.OperationLog{ UserID: int64(arg.UID), OperationAPI: c.Request.URL.Path, OperationType: constant.User_Edit_VIP_Expire, BeforeContent: u.VipExpireDate.Local().String(), AfterContent: vipExpireDate.Local().String(), Reason: *arg.VipExpireDateModifyReason, CreatedUser: manager, CreatedID: 0, CreatedAt: time.Now(), } opLogs = append(opLogs, opLog) } user, err := usermod.Update(arg.UID, doc) if err != nil { common.ServeJSON(c, stderr.ErrServerUnavailable, err) return } if user.UID <= 0 { common.ServeJSON(c, stderr.UserIsNotExists, nil) return } common.Go(func() { if err := operationlogmod.InsertMany(opLogs); err != nil { log.ErrorX(c, "insert operation log failed", log.Any("logs", opLogs), log.Any("req", arg), log.Any("operator", manager), log.E(err)) } log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) }) common.ServeJSON(c, stderr.Success, "") } // Banned doc // @Summary 批量使能用户禁言 // @Description 批量使能用户禁言 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uidList formData array true "uid数组" // @Param enable formData bool true "ture:开始禁言,false:关闭禁言" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/banned [post] func Banned(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } var arg userser.UserCommentBanned if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error()) return } code := arg.Banned() log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) common.ServeJSON(c, code, "") } // SetAdvertiser doc // @Summary 批设置用户为打广告用户 // @Description 批设置用户为打广告用户 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData array true "uid数组" // @Param enable formData bool true "ture:开启,false:关闭" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/advertiser [post] func SetAdvertiser(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } var arg usermod.SetAdvertiseCond if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user SetAdvertiser arg error "+err.Error()) return } err = userser.SetAdvertiser(&arg) if err != nil { common.ServeJSON(c, stderr.Failure, err) return } log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) common.ServeJSON(c, stderr.Success, "") } // Lock doc // @Summary 批量使能禁止用户登陆 // @Description 批量使能禁止用户登陆 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uidList formData array true "uid数组" // @Param enable formData bool true "ture:禁止用户登陆,false:允许用户登陆" // @Param reason formData string false "封禁原因" // @Param lockAt formData string false "封禁开始时间,format:2006-01-02T15:04:05Z07:00" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/lock [post] func Lock(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } var arg userser.LockUserReq if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error()) return } code := arg.Lock() if code != stderr.Success { common.ServeJSON(c, code, "") return } authweb.RevokeTokenCache(arg.UID) log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) common.ServeJSON(c, stderr.Success, "") } // ForbidUpload doc // @Summary 批量使用户禁止上传文件 // @Description 批量使用户禁止上传文件 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uidList formData array true "uid数组" // @Param enable formData bool true "true:开始禁止上传文件,false:取消禁止上传文件" // @Param reason formData string false "true:开始禁止上传文件,false:取消禁止上传文件" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/forbid [post] func Forbid(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } var arg struct { UIDList []uint64 `form:"uidList" json:"uidList" binding:"required"` Enable *bool `form:"enable" json:"enable" binding:"required"` Reason *string `form:"reason" json:"reason"` } if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Forbid arg error "+err.Error()) return } doc := usermod.UserSelector{ForbidUpload: arg.Enable} if _, err = usermod.UpdateMany(arg.UIDList, doc); err != nil { common.ServeJSON(c, stderr.ErrServerUnavailable, err) return } log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) common.ServeJSON(c, stderr.Success, "") } // PlayRecord doc // @Summary 用户播放记录表 // @Description 用户播放记录表 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/devID/reset [get] func DevIDReset(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } role, err := common.GetAdminRole(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminRole error "+err.Error()) return } if role != "superAdmin" { common.ServeJSON(ctx, stderr.ErrAccessForbid, "") return } type Info struct { UID uint64 `form:"uid" json:"uid"` } param := Info{} if err = ctx.ShouldBind(¶m); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } _uuid, err := uuid.NewRandom() if err != nil { common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset uuid NewRandom error "+err.Error()) return } if err = usermod.ResetDevID(param.UID, _uuid.String()); err != nil { common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error()) return } log, _ := json.Marshal(param) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // CreditAmount doc // @Summary 修改用户金币 // @Description 修改用户金币 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param amount formData integer true "增减金额" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/devID/reset [get] func CreditAmount(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var p struct { UID uint64 `json:"uid"` Amount int64 `json:"amount"` Reason string `json:"reason"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } if err = userser.CreditAmount(p.UID, p.Amount, adminID, p.Reason); err != nil { if err.Error() == "Insufficient balance" { common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error()) return } common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error()) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } func FruitCoinChange(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var p struct { UID uint64 `json:"uid"` FruitCoin int64 `json:"fruitCoin"` Reason string `json:"reason"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } if err = userser.FruitCoinChange(p.UID, p.FruitCoin, adminID, p.Reason); err != nil { if err.Error() == "Insufficient balance" { common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error()) return } common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error()) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // PlayRecord doc // @Summary 用户VIP权益 // @Description 用户VIP权益 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param pageNumber query integer true "当前页" // @Param pageSize query integer true "每页条数" // @Success 200 {object} usermod.UserVipInfoRes "success" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/user/vipInfo [get] func VipInfo(c *gin.Context) { var arg struct { UID uint64 `form:"uid" json:"uid" binding:"required"` } if err := c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user VipInfo arg error "+err.Error()) return } //查询 userInfo, err := userser.Info(arg.UID) if err != nil { common.ServeJSON(c, stderr.ErrServerUnavailable, "web user VipInfo userser.Info error "+err.Error()) return } common.ServeJSON(c, stderr.Success, userInfo) } // CreditGold doc // @Summary 用户金币回收 // @Description 用户金币回收 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param amount formData integer true "增减金额" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/credit/gold [post] func CreditGold(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var p struct { UID uint64 `json:"uid"` Amount int64 `json:"amount"` Income int64 `json:"income"` Mark string `json:"mark"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } if err = userser.CreditGold(p.UID, p.Amount, p.Income, adminID, p.Mark); err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // GenerateQRCode doc // @Summary 生成用户登录用二维码 // @Description 生成用户登录用二维码 // @Tags vid // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户ID" // @Success 200 {string} string "qr content" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /api/web/admin/user/qr_code [post] func GenerateQRCode(ctx *gin.Context) { manager, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.AdminIDErr, err.Error()) return } var p struct { UID uint64 `json:"uid" binding:"required"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, nil) return } content, err := userser.GenerateQRCode(p.UID) if err != nil { common.ServeJSON(ctx, stderr.ErrInterServerError, err) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(manager, constant.VideoManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, content) } // UpdateFreeTimes doc // @Summary 修改用户AI脱衣免费次数 // @Description 修改用户AI脱衣免费次数 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param freeTimes formData integer true "增减免费次数" // @Param mark formData string true "备注" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/update/freeTimes [post] func UpdateFreeTimes(ctx *gin.Context) { adminAct, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var in usermod.UpdateFreeTimesCond err = ctx.ShouldBind(&in) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } err = userser.UpdateFreeTimes(&in, adminAct) if err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(in) _ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // UpdateDownload doc // @Summary 修改用户下载次数 // @Description 修改用户下载次数 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param download formData integer true "增减下载次数" // @Param mark formData string true "备注" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/update/download [post] func UpdateDownload(ctx *gin.Context) { adminAct, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var in usermod.UpdateDownloadCond err = ctx.ShouldBind(&in) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } err = userser.UpdateDownloadCounts(&in, adminAct) if err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(in) _ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // DeleteComment doc // @Summary 删除用户评论 // @Description 删除用户评论 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/deleteComment [post] func DeleteComment(ctx *gin.Context) { adminAct, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var in usermod.DeleteCommentCond err = ctx.ShouldBind(&in) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } err = userser.DeleteComment(&in, adminAct) if err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(in) _ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Delete, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // QueryGameCode doc // @Summary 查询用户游戏码 // @Description 查询用户游戏码 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param q query usermod.QueryGameCodeCond false "请求参数" // @Success 200 object game.QueryData "成功" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/queryGameCode [get] func QueryGameCode(ctx *gin.Context) { var in usermod.QueryGameCodeCond err := ctx.ShouldBind(&in) if err != nil { log.Error(fmt.Sprintf("web user QueryGameCode param error:%v", err)) common.ServeJSON(ctx, stderr.ErrParamError, "web user QueryGameCode param error "+err.Error()) return } data, err := userser.QueryGameCode(&in) if err != nil { log.Error(fmt.Sprintf("web user QueryGameCode error:%v", err)) common.ServeJSON(ctx, stderr.Failure, err.Error()) return } common.ServeJSON(ctx, stderr.Success, data) } // UpdateLotteryTimes doc // @Summary 修改用户抽奖次数 // @Description 修改用户抽奖次数 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param lotteryTimes formData integer true "增减抽奖次数" // @Param mark formData string true "备注" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/update/lotteryTimes [post] func UpdateLotteryTimes(ctx *gin.Context) { adminAct, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var in usermod.UpdateLotteryTimesCond err = ctx.ShouldBind(&in) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } err = userser.UpdateLotteryTimes(&in, adminAct) if err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(in) _ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // AddVIP 新增产品产生的行为 func AddVIP(uid uint64, productID primitive.ObjectID, sys string) stderr.Code { p, err := productmod.FindProduct(productID, sys) if err != nil || p == nil { return stderr.ErrParamError } u, err := usermod.FindUserByUID(uid) if err != nil || u == nil { return stderr.ErrNetWorkBusy } w, err := walletmod.GetWallet(uid) if err != nil || w == nil { return stderr.ErrNetWorkBusy } vipExpire, vipLevel, payVidDiscount, vName := checkVipRenew(u, p) sel := usermod.UserSelector{VipExpireDate: &vipExpire, VipLevel: &vipLevel, PayVidDiscount: &payVidDiscount, VipName: &vName} if p.GoldVideoFreeDay > 0 { expire := time.Time{} if u.GoldVideoFreeExpire.IsZero() || u.GoldVideoFreeExpire.Before(time.Now()) { expire = time.Now().AddDate(0, 0, p.GoldVideoFreeDay) } else { expire = u.GoldVideoFreeExpire.AddDate(0, 0, p.GoldVideoFreeDay) } sel.GoldVideoFreeExpire = &expire } var plan walletmod.CreditPlan if p.DownloadCount > 0 { plan.DownloadCount = &p.DownloadCount } if p.AiUndressCount > 0 { aiUndressFreeTimes := int64(p.AiUndressCount) plan.AiUndressFreeTimes = &aiUndressFreeTimes } if p.LuckyDrawCount > 0 { plan.LotteryTimes = &p.LuckyDrawCount } if p.ChatPrice > 0 { sel.ChatPrice = &p.ChatPrice } if p.GiveCoin > 0 { plan.Amount = &p.GiveCoin } if p.BroadcastDays > 0 { expire := time.Time{} if u.BroadcastExpire.IsZero() || u.BroadcastExpire.Before(time.Now()) { expire = time.Now().AddDate(0, 0, p.BroadcastDays) } else { expire = u.BroadcastExpire.AddDate(0, 0, p.BroadcastDays) } sel.BroadcastExpire = &expire } if p.DramaDays > 0 { expire := usermod.RenewDramaExpire(u.DramaExpire, time.Now(), p.DramaDays) sel.DramaExpire = &expire } if err = webg.VideoDB.Trans(func(t *db.MongoTool) error { var err error if err = usermod.UpdateVIP(t, uid, u.VipExpireDate, sel); err != nil { return err } txnLogs := []txnmod.TransactionLog{ { UID: uid, TranType: txnmod.AdminAddVIP.Key(), TranTypeInt: int64(txnmod.AdminAddVIP), Desc: "官方添加VIP-" + p.Name, SysType: u.SysType, RealAmount: w.RealAmount(), }, } if p.AiUndressCount > 0 || p.GiveCoin > 0 || p.DownloadCount > 0 || p.LuckyDrawCount > 0 { wallet, err := walletmod.Credit(t, plan, uid) if err != nil { return err } // 插入购买会员卡赠送金币流水 if p.GiveCoin > 0 { giveLog := txnmod.TransactionLog{ UID: uid, Amount: p.GiveCoin, ActualAmount: float64(p.GiveCoin), TranType: txnmod.VipCardGive.Key(), TranTypeInt: int64(txnmod.VipCardGive), Desc: "官方添加VIP-" + p.Name + "-赠送金币", SysType: u.SysType, RealAmount: walletmod.GetRealAmount(wallet), } txnLogs = append(txnLogs, giveLog) } if p.AiUndressCount > 0 { aiLog := txnmod.TransactionLog{ UID: uid, Amount: int64(p.AiUndressCount), ActualAmount: float64(p.AiUndressCount), TranType: txnmod.VipCardGiveAiUndressFreeCount.Key(), TranTypeInt: int64(txnmod.VipCardGiveAiUndressFreeCount), Desc: fmt.Sprintf("官方添加VIP%s-赠送AI脱衣免费次数[%v次]", p.Name, p.AiUndressCount), DiscDoc: u.DiscDoc, SysType: u.SysType, RealAmount: walletmod.GetRealAmount(wallet), } txnLogs = append(txnLogs, aiLog) } if p.DownloadCount > 0 { txnLogs = append(txnLogs, txnmod.TransactionLog{ UID: uid, DownloadCount: p.DownloadCount, TranType: txnmod.GiveDownload.Key(), TranTypeInt: int64(txnmod.GiveDownload), Desc: fmt.Sprintf("官方添加VIP-%v", p.Name) + fmt.Sprintf("-赠送视频下载[%d]次", p.DownloadCount), DiscDoc: u.DiscDoc, SysType: u.SysType, RealAmount: walletmod.GetRealAmount(wallet), }) } if p.LuckyDrawCount > 0 { txnLogs = append(txnLogs, txnmod.TransactionLog{ UID: uid, DownloadCount: p.LuckyDrawCount, TranType: txnmod.GiveLotteryTimesCount.Key(), TranTypeInt: int64(txnmod.GiveLotteryTimesCount), Desc: fmt.Sprintf("官方添加VIP-%v", p.Name) + fmt.Sprintf("-赠送[%d]次数", p.LuckyDrawCount), DiscDoc: u.DiscDoc, SysType: u.SysType, }) } } if len(txnLogs) > 0 { if err = txnmod.InsertManyTransactionLog(t, txnLogs); err != nil { log.Warn(fmt.Sprintf("productser addVIP Transaction err %s", err.Error())) return err } } return nil }); err != nil { log.Warn(fmt.Sprintf("productser addVIP Transaction err %s", err.Error())) return stderr.BuyFailed //通知消息 } return stderr.Success } func checkVipRenew(u *usermod.User, p *productmod.Product) (time.Time, int, int, string) { var ( end time.Time now = time.Now() level = p.VipLevel payVidDiscount = p.PayVidDiscount d = time.Hour * 24 * time.Duration(p.Duration) vipName = p.Name ) if u.VipExpireDate.After(now) { //renew // 判断用户VIP等级 if p.VipLevel > u.VipLevel { end = now.Add(d) } else if p.VipLevel == u.VipLevel { end = u.VipExpireDate.Add(d) } else if p.VipLevel < u.VipLevel { end = u.VipExpireDate } if u.VipLevel > p.VipLevel { //当前用户的vip等级比这次购买的大,使用用户的 level = u.VipLevel vipName = u.VipName } //当前用户的折扣比这次购买的大,使用用户的 if u.PayVidDiscount < payVidDiscount && u.PayVidDiscount > 0 { payVidDiscount = u.PayVidDiscount } } else { end = now.Add(time.Duration(d)) } return end, level, payVidDiscount, vipName } // SetaiMateBalance doc // @Summary 设置用户AI伴侣积分 // @Description 设置用户AI伴侣积分 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param amount formData integer true "增减金额" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/credit/aiMateBalance [post] func SetAiMateBalance(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var p struct { UID uint64 `json:"uid"` AiMateBalance float64 `json:"aiMateBalance"` //ai伴侣余额 Reason string `json:"reason"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } if p.AiMateBalance < 0 { common.ServeJSON(ctx, stderr.ErrParamError, nil) return } if err = userser.SetAiMateBalance(p.UID, p.AiMateBalance, p.Reason); err != nil { common.ServeJSON(ctx, stderr.Failure, err.Error()) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) } // PrivateZone doc // @Summary 批量使用户开启私密圈权限 // @Description 批量使用户开启私密圈权限 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uidList formData array true "uid数组" // @Param enable formData bool true "ture:开启私密圈权限,false:关闭私密圈权限" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/privateZone [post] func PrivateZone(c *gin.Context) { manager, err := common.GetAdminAct(c) if err != nil { common.ServeJSON(c, stderr.AdminIDErr, err.Error()) return } var arg struct { UIDList []uint64 `form:"uidList" json:"uidList" binding:"required"` Enable *bool `form:"enable" json:"enable" binding:"required"` } if err = c.ShouldBind(&arg); err != nil { common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error()) return } doc := usermod.UserSelector{HasPrivateZone: arg.Enable} if _, err = usermod.UpdateMany(arg.UIDList, doc); err != nil { common.ServeJSON(c, stderr.ErrServerUnavailable, err) return } log, _ := json.Marshal(arg) _ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI()) common.ServeJSON(c, stderr.Success, "") } // CreditIntegral doc // @Summary 修改用户积分 // @Description 修改用户积分 // @Tags web-用户管理 // @Accept mpfd,json // @Produce json,html // @Param uid formData integer true "用户id" // @Param integral formData integer true "增减积分" // @Success 200 {string} json "{"msg": "操作成功"}" // @Failure 400 {string} json "{"msg": "操作失败"}" // @Router /web/admin/user/integral [post] func CreditIntegral(ctx *gin.Context) { adminID, err := common.GetAdminAct(ctx) if err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error()) return } var p struct { UID uint64 `json:"uid"` Integral int64 `json:"integral"` Reason string `json:"reason"` } if err = ctx.ShouldBind(&p); err != nil { common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error()) return } if err = userser.CreditIntegral(p.UID, p.Integral, adminID, p.Reason); err != nil { if err.Error() == "Insufficient balance" { common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error()) return } common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error()) return } log, _ := json.Marshal(p) _ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI()) common.ServeJSON(ctx, stderr.Success, nil) }