Commit 48e5c656 authored by chenweijian's avatar chenweijian

cp邀请

parent 3c6346df
package cp_e
const (
//新用户
CpRelationInviteDiamond = 18888
)
package cp_cv
type CheckCpRelationRes struct {
NoBind bool `json:"isBind"`
}
package user_cv
type CvUserTiny struct {
Id uint64 `json:"id,omitempty"`
ExternalId string `json:"externalId"`
Avatar string `json:"avatar"`
Nick string `json:"nick"`
Sex uint8 `json:"sex"`
Code string `json:"code"`
Country string `json:"country"`
CountryIcon string `json:"countryIcon"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
IsLogout bool `json:"isLogout"` //是否注销 true:已经注销, false:没有注销
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
}
package cp_m
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
"hilo-user/myerr/bizerr"
"time"
)
type CpRelation struct {
Id uint64 `json:"id"`
UserId1 uint64 `json:"userId1"`
UserId2 uint64 `json:"userId2"`
CreatedTime time.Time `json:"createdTime"`
}
func CreateCp(model *domain.Model, userId1, userId2 uint64) error {
userIds := []uint64{userId1, userId2}
result := model.DB().Exec("insert into cp_relation(user_id1, user_id2) values(?,?) where not exists (select user_id1 from cp_relation where user_id1 in (?) or user_id2 in (?));", userId1, userId2, userIds, userIds)
if result.Error != nil {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
return bizerr.TransactionFailed
}
return nil
}
func GetCp(model *domain.Model, userId uint64) (*CpRelation, error) {
res := new(CpRelation)
err := model.DB().Model(CpRelation{}).Where("user_id1 = ? or user_id2 = ?", userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return res, nil
}
model.Log.Errorf("CreateCp userId:%d, err:%v", userId, err)
return nil, err
}
return res, nil
}
package diamond_m
import (
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"strconv"
"time"
)
type DiamondAccount struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondNum mysql.Num
PinkDiamondNum mysql.Num
Status diamond_e.StatusAccount
}
//账号详情
type DiamondAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
// 粉钻详情
type DiamondPinkAccountDetail struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
DiamondAccountId mysql.ID
OperateId mysql.ID
OperateType diamond_e.OperateType
OriginId mysql.ID
AddReduce mysql.AddReduce
Num mysql.Num
Remark mysql.Str
BefNum mysql.Num
AftNum mysql.Num
diamondAccount *DiamondAccount `gorm:"-"`
}
//账号操作配置
type DiamondOperateSet struct {
mysql.Entity
*domain.Model `gorm:"-"`
DiamondNum mysql.NumAll
FrequencyNum mysql.NumAll
FrequencyDay mysql.NumAll
DiamondMaxNum mysql.NumAll
AddReduce mysql.AddReduce
Type diamond_e.OperateType
Name mysql.Str
Status mysql.UserYesNo
DiamondType diamond_e.OperateType
}
//通过userId获取帐号
func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAccount, error) {
var diamondAccount DiamondAccount
if err := model.Db.WithContext(model).Where(&DiamondAccount{
UserId: userId,
}).First(&diamondAccount).Error; err != nil {
return nil, myerr.WrapErr(err)
}
diamondAccount.Model = model
return &diamondAccount, nil
}
//匹配条件扣费
func (diamondAccount *DiamondAccount) ChangeDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(operateType, originId, diamondNum)
}
//钻石操作记录,
func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) {
var diamondOperateSet DiamondOperateSet
var err error
if err = diamondAccount.Db.Where(&DiamondOperateSet{
Type: operateType,
Status: mysql.USER,
DiamondType: mysql.DiamondYellow,
}).First(&diamondOperateSet).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//判断是增加,账号是否被冻结
if diamondAccount.Status == diamond_e.Frozen && diamondOperateSet.AddReduce == mysql.REDUCE {
return nil, bizerr.DiamondAccountFrozen
}
//无限,检查次数
var count int64
if diamondOperateSet.FrequencyDay == -1 {
if diamondOperateSet.FrequencyNum != -1 {
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
//return nil, myerr.NewSysError("钻石操作次数多大, userId:" + mysql.IdToStr(diamondAccount.UserId) + " diamondOperateSetId" + mysql.IdToStr(diamondOperateSet.ID))
}
}
} else if diamondOperateSet.FrequencyDay == 1 {
beginTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local)
if err != nil {
return nil, myerr.WrapErr(err)
}
//一天的次数
diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{
UserId: diamondAccount.UserId,
OperateType: operateType,
}).Where("created_time >= ? ", beginTime).Count(&count)
if count >= int64(diamondOperateSet.FrequencyNum) {
return nil, bizerr.DiamondFrequency
}
//终极拦截,利用
diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1) as n from diamond_account_detail d where d.user_id = " + strconv.FormatUint(diamondAccount.UserId, 10) + " and d.operate_type = " + strconv.FormatUint(uint64(operateType), 10) + " and d.created_time >= from_unixtime(" + strconv.FormatInt(utils.GetZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )")
}
//-1,代表值无效,由参数给与
var upateDiamondNum mysql.Num
if diamondOperateSet.DiamondNum == -1 {
upateDiamondNum = diamondNum
} else {
upateDiamondNum = mysql.Num(diamondOperateSet.DiamondNum)
}
var afterNum mysql.Num
if diamondOperateSet.AddReduce == mysql.ADD {
afterNum = diamondAccount.DiamondNum + upateDiamondNum
} else if diamondOperateSet.AddReduce == mysql.REDUCE {
if diamondAccount.DiamondNum < upateDiamondNum {
return nil, bizerr.DiamondNoEnough
}
afterNum = diamondAccount.DiamondNum - upateDiamondNum
} else {
return nil, myerr.NewSysError("AddReduce 值错误:" + mysql.TypeToString(mysql.Type(diamondOperateSet.AddReduce)))
}
diamondAccountDetail := &DiamondAccountDetail{
Model: diamondAccount.Model,
UserId: diamondAccount.UserId,
DiamondAccountId: diamondAccount.ID,
OperateId: diamondOperateSet.ID,
OperateType: diamondOperateSet.Type,
OriginId: originId,
AddReduce: diamondOperateSet.AddReduce,
Num: upateDiamondNum,
Remark: diamondOperateSet.Name,
BefNum: diamondAccount.DiamondNum,
AftNum: afterNum,
diamondAccount: diamondAccount,
}
return diamondAccountDetail, err
}
// 此方法必须要在事务里面调用
func ChangeDiamondAccountDetail(model *domain.Model, operateType diamond_e.OperateType, originId mysql.ID, userId mysql.ID, diamondNum mysql.Num) error {
diamondAccount, err := GetDiamondAccountByUserId(model, userId)
if err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(operateType, originId, diamondNum)
if err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
if err := diamondAccountDetail.PersistentNoInTransactional(); err != nil {
model.Log.Errorf("ChangeDiamondAccountDetail operateType:%v, originId:%v, userId:%v, diamondNum:%v, err:%v", operateType, originId, userId, diamondNum, err)
return err
}
return nil
}
package diamond_m
import (
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-user/domain/model"
"hilo-user/myerr"
"strconv"
)
func (diamondAccountDetail *DiamondAccountDetail) PersistentNoInTransactional() error {
//fixme: 这里有点奇怪, diamondAccount持久化动作在diamondAccountDetail持久化之后,RowsAffected 就一定是0
txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount)
if diamondAccountDetail.diamondAccount.CheckUpdateCondition() {
txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition())
}
if diamondAccountDetail.AddReduce == mysql.ADD {
//增加
txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num))
} else if diamondAccountDetail.AddReduce == mysql.REDUCE {
//减少,保证不能扣成负数
txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num))
} else {
myerr.NewSysError("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce)))
}
if err := txDiamondAccount.Error; err != nil {
return myerr.WrapErr(err)
}
if txDiamondAccount.RowsAffected == 0 {
diamondAccountDetail.Log.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce)
return myerr.NewWaring("gorm condition update.RowsAffected = 0")
}
//持久化diamondAccountDetail
if err := model.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil {
return myerr.WrapErr(err)
}
//改变diamondAccount值
if diamondAccountDetail.diamondAccount == nil {
return myerr.NewSysError("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID)))
}
var newDiamondAccount DiamondAccount
if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil {
return myerr.WrapErr(err)
}
if newDiamondAccount.DiamondNum < 0 {
return myerr.NewSysError("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID)))
}
return nil
}
CREATE TABLE `cp_relation` (
`id` bigint unsigned AUTO_INCREMENT NOT NULL,
`user_id1` bigint NOT NULL COMMENT 'user_id1',
`user_id2` bigint NOT NULL COMMENT 'user_id2',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uid1_idx` (`user_id1`) USING BTREE,
UNIQUE KEY `uid2_idx` (`user_id2`) USING BTREE,
KEY `ctime_idx` (`created_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp关系表';
INSERT INTO hilo.diamond_operate_set (diamond_num, frequency_num, frequency_day, diamond_max_num, add_reduce, `type`, name, status, diamond_type)
VALUES (-1, -1, -1, -1, 2, 94, 'cp邀请扣费', 1, 1),
(-1, -1, -1, -1, 1, 95, 'cp邀请退费', 1, 1);
package cp_r
import (
"encoding/json"
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/myerr/comerr"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"git.hilo.cn/hilo-common/txop/msg"
"github.com/gin-gonic/gin"
"hilo-user/_const/enum/cp_e"
"hilo-user/cv/cp_cv"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/diamond_m"
"hilo-user/domain/model/user_m"
"hilo-user/req"
"hilo-user/resp"
)
// @Tags cp关系
// @Summary 检查用户是否绑定了cp
// @Param code query int true "用户code"
// @Success 200 {object} cp_cv.CheckCpRelationRes
// @Router /v2/cp/relation/check [get]
func CheckUserCpRelation(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userCode := c.Query("code")
_, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUserByCode(model, userCode)
if err != nil {
return myCtx, err
}
cp, err := cp_m.GetCp(model, user.ID)
if err != nil {
return myCtx, err
}
if cp.Id > 0 {
return myCtx, msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
resp.ResponseOk(c, cp_cv.CheckCpRelationRes{})
return myCtx, nil
}
// @Tags cp关系
// @Summary 发送cp邀请
// @Param code formData int true "用户code"
// @Success 200
// @Router /v2/cp/relation/invite [post]
func InviteCpRelation(c *gin.Context) (*mycontext.MyContext, error) {
myCtx := mycontext.CreateMyContext(c.Keys)
userCode := c.Query("code")
myUserId, lang, err := req.GetUserIdLang(c, myCtx)
if err != nil {
return myCtx, err
}
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return myCtx, err
}
userInvite, err := user_m.GetUserByCode(model, userCode)
if err != nil {
return myCtx, err
}
// 自己是否有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return myCtx, err
}
if myCp.Id > 0 {
return myCtx, msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
// 对方是否已经有cp了
inviCp, err := cp_m.GetCp(model, userInvite.ID)
if err != nil {
return myCtx, err
}
if inviCp.Id > 0 {
return myCtx, msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
err = model.Transaction(func(model *domain.Model) error {
// 扣费
err = diamond_m.ChangeDiamondAccountDetail(model, diamond_e.CpInvite, userInvite.ID, myUserId, cp_e.CpRelationInviteDiamond)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 发送私信
type CpInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
}
data, _ := json.Marshal(CpInviteMessage{
Identifier: "CpInviteMessage",
Msg: "Do you want to be CP with me?",
})
if err := tencentyun.BatchSendCustomMsg(model, 1, user.ExternalId, []string{userInvite.ExternalId}, string(data), "cp邀请"); err != nil {
model.Log.Errorf("BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return myCtx, err
}
// socket 推送弹窗
go rpc.SendCpInviteNotice(userInvite.ID, user.Code, user.Nick, user.Avatar, "Do you want to be CP with me?")
resp.ResponseOk(c, cp_cv.CheckCpRelationRes{})
return myCtx, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment