Commit 0f6ba56f authored by chenweijian's avatar chenweijian

cp

parents f3b584cd b308b069
package cp_e
import "git.hilo.cn/hilo-common/resource/mysql"
type CpInviteStatus mysql.Type
type CpCancelStatus mysql.Type
const (
//新用户
CpRelationInviteDiamond = 18888
//1.未接受2.已接受3.拒接导致退费4.过期导致退费
CpInvite CpInviteStatus = 1
CpInviteAccept CpInviteStatus = 2
CpInviteRefuse CpInviteStatus = 3
CpInviteExpired CpInviteStatus = 4
//1.未处理2.发起者已撤销3.对方已确认4.到期自动确认
CpCancel CpCancelStatus = 1
CpCancelRevoke CpCancelStatus = 2
CpCancelAccept CpCancelStatus = 3
CpCancelAcceptAuto CpCancelStatus = 4
)
package cp_corn
import (
"git.hilo.cn/hilo-common/_const/enum/diamond_e"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/utils"
"github.com/robfig/cron"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/diamond_m"
"time"
)
// cp邀请、解除到期结算
func CpInviteCancelInit() {
if !config.IsMaster() {
return
}
mylogrus.MyLog.Infof("CpInviteCancelInit")
// 每2min监测一次
c := cron.New()
spec := "0 */2 * * * *"
if !config.AppIsRelease() {
spec = "0 */1 * * * ?" // 测服每1分钟
}
_ = c.AddFunc(spec, func() {
defer utils.CheckGoPanic()
model := domain.CreateModelNil()
// 获取超过24小时没被处理的cp邀请
inviteList, err := cp_m.GetCpInviteByTime(model, time.Now().AddDate(0, 0, -1))
if err != nil {
model.Log.Errorf("CpInviteCancelInit err:%v", err)
return
}
for _, v := range inviteList {
model.Log.Infof("CpInviteCancelInit invite:%+v", v)
err = model.Transaction(func(model *domain.Model) error {
// 更新邀请记录
err = cp_m.UpdateStatusCpInvite(model, v.Id, cp_e.CpInviteExpired)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
// 退费
err = diamond_m.ChangeDiamondAccountDetail(model, diamond_e.CpInviteRefund, v.Id, v.UserId, v.DiamondNum)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CpInviteCancelInit invite:%+v, err:%v", v, err)
return
}
time.Sleep(time.Millisecond * 10)
}
// 获取超过24小时没被处理的cp解除申请
cancelList, err := cp_m.GetCpCancelByTime(model, time.Now().AddDate(0, 0, -1))
if err != nil {
model.Log.Errorf("CpInviteCancelInit err:%v", err)
return
}
for _, v := range cancelList {
model.Log.Infof("CpInviteCancelInit cancel:%+v", v)
err = model.Transaction(func(model *domain.Model) error {
// 更新解除记录
err = cp_m.UpdateStatusCpCancel(model, v.Id, cp_e.CpCancelAcceptAuto)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
// 删除cp关系表的记录
err = cp_m.DelCpRelation(model, v.UserId, v.RecUserId)
if err != nil {
model.Log.Errorf("CpInviteCancelInit Id:%d, err:%v", v.Id, err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CpInviteCancelInit cancel:%+v, err:%v", v, err)
return
}
time.Sleep(time.Millisecond * 10)
}
})
c.Start()
}
package cron
import "hilo-user/corn/cp_corn"
func Init() {
cp_corn.CpInviteCancelInit()
}
package cp_cv
type CheckCpRelationRes struct {
NoBind bool `json:"isBind"`
}
...@@ -326,3 +326,18 @@ func GetUserBaseMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUser ...@@ -326,3 +326,18 @@ func GetUserBaseMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUser
} }
return mapIdUser, nil return mapIdUser, nil
} }
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"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/user_m"
"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"`
}
type CpInvite struct {
Id uint64 `json:"id"`
UserId uint64 `json:"userId"`
InviteUserId uint64 `json:"inviteUserId"`
DiamondNum uint32 `json:"diamondNum"`
Status cp_e.CpInviteStatus `json:"status"`
}
// 发送私信-发起邀请
type CpInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Sender *user_m.UserTiny `json:"sender"`
}
// 发送私信-接受邀请
type CpAcceptInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Sender *user_m.UserTiny `json:"sender"`
Receiver *user_m.UserTiny `json:"receiver"`
}
// 发送私信-拒绝邀请
type CpDenyInviteMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Sender *user_m.UserTiny `json:"sender"`
}
type CpCancel struct {
Id uint64 `json:"id"`
UserId uint64 `json:"userId"`
RecUserId uint64 `json:"recUserId"`
Status cp_e.CpCancelStatus `json:"status"`
}
// 发送私信(解除)
type CpCancelMessage struct {
Identifier string `json:"identifier"`
Msg string `json:"msg"`
Status uint8 `json:"status"` //1.发起解除2.撤销解除3.接受解除
}
type Cp struct {
Id uint64 `json:"id"`
UserId1 uint64 `json:"userId1"`
UserId2 uint64 `json:"userId2"`
DisconnectSecond int64 `json:"disconnectSecond"`
Score int32 `json:"score"`
DayScore int32 `json:"dayScore"`
PeriodDay string `json:"periodDay"`
WeekScore int32 `json:"weekScore"`
PeriodWeek string `json:"periodWeek"`
MonthScore int32 `json:"monthScore"`
PeriodMonth string `json:"periodMonth"`
Status int8 `json:"status"`
CreatedTime time.Time `json:"createdTime"`
}
func CreateCp(model *domain.Model, userId1, userId2 uint64) error {
userIds := []uint64{userId1, userId2}
oldCp := make([]*Cp, 0)
// 这两个人以前是否有旧的cp关系
err := model.DB().Model(Cp{}).Where("status = 1 and user_id1 in (?) and user_id2 in (?)", userIds, userIds).Find(&oldCp).Error
if err != nil {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, err)
return err
}
createdTime := time.Now()
if len(oldCp) > 0 {
// 旧的cp关系,有效的时间给他加回去
oldSecond := time.Duration(time.Now().Unix() - oldCp[0].CreatedTime.Unix() - oldCp[0].DisconnectSecond)
if oldSecond > 0 {
createdTime = createdTime.Add(-1 * time.Second * time.Duration(time.Now().Unix()-oldCp[0].CreatedTime.Unix()-oldCp[0].DisconnectSecond))
}
}
result := model.DB().Exec("insert into cp_relation(user_id1, user_id2, created_time) select ?,?,? where not exists (select user_id1 from cp_relation where user_id1 in (?) or user_id2 in (?));", userId1, userId2, createdTime.Format(utils.DATETIME_FORMAT), 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 {
model.Log.Errorf("CreateCp user1:%d, user2:%d, err:%v", userId1, userId2, bizerr.TransactionFailed)
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
}
func GetCpInvite(model *domain.Model, userId, userIdInvite uint64, status cp_e.CpInviteStatus) (*CpInvite, error) {
res := new(CpInvite)
err := model.DB().Model(CpInvite{}).Where(CpInvite{UserId: userId, InviteUserId: userIdInvite, Status: status}).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpInvite user1:%d, user2:%d, err:%v", userId, userIdInvite, err)
return nil, err
}
return res, nil
}
func CreateCpInvite(model *domain.Model, userId, userIdInvite uint64, diamondNum uint32) (uint64, error) {
cpInvite := CpInvite{UserId: userId, InviteUserId: userIdInvite, DiamondNum: diamondNum, Status: cp_e.CpInvite}
err := model.DB().Model(CpInvite{}).Create(&cpInvite).Error
if err != nil {
model.Log.Errorf("CreateCpInvite user1:%d, user2:%d, diamondNum:%d, err:%v", userId, userIdInvite, diamondNum, err)
return 0, err
}
return cpInvite.Id, nil
}
// userId:发起邀请者
func UpdateStatusCpInvite(model *domain.Model, id uint64, status cp_e.CpInviteStatus) error {
result := model.DB().Exec("update cp_invite set status=? where id=? and status=? limit 1", status, id, cp_e.CpInvite)
if result.Error != nil {
model.Log.Errorf("UpdateStatusCpInvite id:%d, status:%d, err:%v", id, status, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("UpdateStatusCpInvite id:%d, status:%d, err:%v", id, status, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func CreateCpCancel(model *domain.Model, userId, recUserId uint64) (uint64, error) {
cpCancel := CpCancel{UserId: userId, RecUserId: recUserId, Status: cp_e.CpCancel}
err := model.DB().Model(CpCancel{}).Create(&cpCancel).Error
if err != nil {
model.Log.Errorf("CreateCpCancel user1:%d, user2:%d, err:%v", userId, recUserId, err)
return 0, err
}
return cpCancel.Id, nil
}
func GetCpCancel(model *domain.Model, userIds []uint64, status cp_e.CpCancelStatus) (*CpCancel, error) {
res := new(CpCancel)
err := model.DB().Model(CpCancel{}).Where("status = ? and user_id in (?) and rec_user_id in (?)", status, userIds, userIds).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpCancel users:%d, err:%v", userIds, err)
return nil, err
}
return res, nil
}
func GetCpCancelWithMe(model *domain.Model, userId uint64, status cp_e.CpCancelStatus) (*CpCancel, error) {
res := new(CpCancel)
err := model.DB().Model(CpCancel{}).Where("status = ? and (user_id = ? or rec_user_id = ?)", status, userId, userId).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
model.Log.Errorf("GetCpCancel user1:%d, err:%v", userId, err)
return nil, err
}
return res, nil
}
func UpdateStatusCpCancel(model *domain.Model, id uint64, status cp_e.CpCancelStatus) error {
result := model.DB().Exec("update cp_cancel set status=? where id=? and status=? limit 1", status, id, cp_e.CpCancel)
if result.Error != nil {
model.Log.Errorf("UpdateStatusCpCancel id:%d, status:%d, err:%v", id, status, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("UpdateStatusCpCancel id:%d, status:%d, err:%v", id, status, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func DelCpRelation(model *domain.Model, userId1, userId2 uint64) error {
userIds := []uint64{userId1, userId2}
result := model.DB().Exec("delete from cp_relation where user_id1 in (?) and user_id2 in (?) limit 1;", userIds, userIds)
if result.Error != nil {
model.Log.Errorf("DelCpRelation user1:%d, user2:%d, err:%v", userId1, userId2, result.Error)
return result.Error
}
if result.RowsAffected <= 0 {
model.Log.Errorf("DelCpRelation user1:%d, user2:%d, err:%v", userId1, userId2, bizerr.TransactionFailed)
return bizerr.TransactionFailed
}
return nil
}
func GetCpInviteByTime(model *domain.Model, expTime time.Time) ([]*CpInvite, error) {
res := make([]*CpInvite, 0)
err := model.DB().Model(CpInvite{}).Where("status = ? and created_time <= ?", cp_e.CpInvite, expTime.Format(utils.DATETIME_FORMAT)).Find(&res).Error
if err != nil {
model.Log.Errorf("GetCpInviteByTime err:%v", err)
return nil, err
}
return res, nil
}
func GetCpCancelByTime(model *domain.Model, expTime time.Time) ([]*CpCancel, error) {
res := make([]*CpCancel, 0)
err := model.DB().Model(CpCancel{}).Where("status = ? and created_time <= ?", cp_e.CpCancel, expTime.Format(utils.DATETIME_FORMAT)).Find(&res).Error
if err != nil {
model.Log.Errorf("GetCpCancelByTime err:%v", 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
}
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"hilo-user/_const/enum/user_e" "hilo-user/_const/enum/user_e"
"hilo-user/myerr" "hilo-user/myerr"
"hilo-user/myerr/bizerr" "hilo-user/myerr/bizerr"
"time"
) )
//用户信息 //用户信息
...@@ -106,3 +107,31 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) { ...@@ -106,3 +107,31 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) {
user.Model = model user.Model = model
return &user, nil return &user, nil
} }
func ToUserTiny(user *User) *UserTiny {
return &UserTiny{
ID: user.ID,
ExternalId: user.ExternalId,
Avatar: user.Avatar,
Nick: user.Nick,
Sex: user.Sex,
Code: user.Code,
Description: user.Description,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode(),
IsLogout: IfLogout(user.LogoutTime),
Birthday: BirthdayToUint64(&user.Birthday),
}
}
func IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 {
if *birthday == 0 {
return nil
}
return (*uint64)(birthday)
}
package cp_s
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"
"hilo-user/_const/enum/cp_e"
"hilo-user/domain/model/cp_m"
"hilo-user/domain/model/diamond_m"
"hilo-user/domain/model/user_m"
"hilo-user/myerr/bizerr"
)
func InviteCpRelation(myCtx *mycontext.MyContext, myUserId uint64, externalId, lang string) error {
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return err
}
userInvite, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return err
}
if userInvite.ID == myUserId {
return bizerr.InvalidParameter
}
// 自己是否有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return err
}
if myCp.Id > 0 {
return msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
// 对方是否已经有cp了
inviCp, err := cp_m.GetCp(model, userInvite.ID)
if err != nil {
return err
}
if inviCp.Id > 0 {
return msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
// 我是否发起过cp邀请,且还未被处理
myInvite, err := cp_m.GetCpInvite(model, user.ID, 0, cp_e.CpInvite)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
if myInvite != nil && myInvite.Id > 0 {
return bizerr.CpAlreadyInvite
}
err = model.Transaction(func(model *domain.Model) error {
// 创建邀请记录
cpInvId, err := cp_m.CreateCpInvite(model, myUserId, userInvite.ID, cp_e.CpRelationInviteDiamond)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 扣费
err = diamond_m.ChangeDiamondAccountDetail(model, diamond_e.CpInvite, cpInvId, myUserId, cp_e.CpRelationInviteDiamond)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 发送私信-邀请
data, _ := json.Marshal(cp_m.CpInviteMessage{
Identifier: "CpInviteMessage",
Msg: "Do you want to be CP with me?",
Sender: user_m.ToUserTiny(user),
})
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 err
}
// socket 推送弹窗
go rpc.SendCpInviteNotice(userInvite.ID, user.Code, user.Nick, user.Avatar, "Do you want to be CP with me?")
return nil
}
func CancelCpRelation(myCtx *mycontext.MyContext, myUserId uint64, externalId, lang string) error {
model := domain.CreateModelContext(myCtx)
user, err := user_m.GetUser(model, myUserId)
if err != nil {
return err
}
userRec, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return err
}
if userRec.ID == myUserId {
return bizerr.InvalidParameter
}
// 自己没有cp了
myCp, err := cp_m.GetCp(model, myUserId)
if err != nil {
return err
}
if myCp.Id == 0 {
return msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
// 对方没有cp了
inviCp, err := cp_m.GetCp(model, userRec.ID)
if err != nil {
return err
}
if inviCp.Id == 0 {
return msg.GetErrByLanguage(model, 0, lang, comerr.InvalidParameter)
}
// 是否有关于我的cp解除申请,且还未被处理
myCancel, err := cp_m.GetCpCancelWithMe(model, user.ID, cp_e.CpCancel)
if err != nil {
model.Log.Errorf("InviteCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
if myCancel != nil && myCancel.Id > 0 {
return bizerr.CpHaveCancelNoDeal
}
err = model.Transaction(func(model *domain.Model) error {
// 创建邀请记录
_, err = cp_m.CreateCpCancel(model, myUserId, userRec.ID)
if err != nil {
model.Log.Errorf("CancelCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
// 发送私信
data, _ := json.Marshal(cp_m.CpCancelMessage{
Identifier: "CpCancelMessage",
Msg: "I want to unbind the CP relationship",
Status: 1,
})
if err := tencentyun.BatchSendCustomMsg(model, 1, user.ExternalId, []string{userRec.ExternalId}, string(data), "cp解除"); err != nil {
model.Log.Errorf("CancelCpRelation BatchSendCustomMsg fail:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CancelCpRelation myUserId:%d, err:%v", myUserId, err)
return err
}
return nil
}
...@@ -19,13 +19,22 @@ require ( ...@@ -19,13 +19,22 @@ require (
gorm.io/gorm v1.23.8 gorm.io/gorm v1.23.8
) )
require (
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/robfig/cron v1.2.0
)
require (
github.com/bluele/gcache v0.0.2
github.com/jinzhu/now v1.1.5
)
require ( require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274 // indirect github.com/aliyun/alibaba-cloud-sdk-go v1.61.1274 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/bluele/gcache v0.0.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.9.0 // indirect github.com/fatih/color v1.9.0 // indirect
...@@ -38,7 +47,8 @@ require ( ...@@ -38,7 +47,8 @@ require (
github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.2.0 // indirect github.com/go-playground/validator/v10 v10.2.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/golang/protobuf v1.5.0 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/hashicorp/consul/api v1.7.0 // indirect github.com/hashicorp/consul/api v1.7.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect github.com/hashicorp/go-hclog v0.12.0 // indirect
...@@ -48,11 +58,10 @@ require ( ...@@ -48,11 +58,10 @@ require (
github.com/hashicorp/golang-lru v0.5.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/serf v0.9.3 // indirect github.com/hashicorp/serf v0.9.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/joho/godotenv v1.3.0 // indirect github.com/joho/godotenv v1.3.0 // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect github.com/json-iterator/go v1.1.9 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/leodido/go-urn v1.2.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect
...@@ -64,7 +73,6 @@ require ( ...@@ -64,7 +73,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
github.com/robfig/cron v1.2.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.479 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.479 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ims v1.0.479 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ims v1.0.479 // indirect
github.com/tencentyun/tls-sig-api-v2-golang v1.0.0 // indirect github.com/tencentyun/tls-sig-api-v2-golang v1.0.0 // indirect
...@@ -72,7 +80,7 @@ require ( ...@@ -72,7 +80,7 @@ require (
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.6 // indirect golang.org/x/text v0.3.6 // indirect
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 // indirect golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/grpc v1.42.0 // indirect google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
......
This diff is collapsed.
...@@ -23,4 +23,9 @@ var ( ...@@ -23,4 +23,9 @@ var (
ResPropertyDiamondNoUse = myerr.NewBusinessCode(5004, "Property can not buy", myerr.BusinessData{}) //头饰不能买 ResPropertyDiamondNoUse = myerr.NewBusinessCode(5004, "Property can not buy", myerr.BusinessData{}) //头饰不能买
CpNotRelation = myerr.NewBusinessCode(6000, "cp not relation", myerr.BusinessData{}) CpNotRelation = myerr.NewBusinessCode(6000, "cp not relation", myerr.BusinessData{})
// 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
CpAlreadyInvite = myerr.NewBusinessCode(50120, "Already invited", myerr.BusinessData{}) // 已经发送过邀请了
CpHaveCancelNoDeal = myerr.NewBusinessCode(50121, "You have a cancel apply", myerr.BusinessData{}) // 有接触申请需要处理
) )
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);
CREATE TABLE `cp_invite` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '发起邀请者',
`invite_user_id` bigint NOT NULL COMMENT '被邀请的人',
`diamond_num` int unsigned NOT NULL COMMENT '邀请者花费的钻石',
`status` tinyint unsigned NOT NULL COMMENT '状态1.未接受2.已接受3.拒接导致退费4.过期导致退费',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `uid_idx` (`user_id`) USING BTREE,
KEY `uid2_idx` (`invite_user_id`) USING BTREE,
KEY `status_idx` (`status`) USING BTREE,
KEY `created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp邀请发起记录';
CREATE TABLE `cp_cancel` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_id` bigint NOT NULL COMMENT '发起者',
`rec_user_id` bigint NOT NULL COMMENT '接收者',
`status` tinyint unsigned NOT NULL COMMENT '状态1.未处理2.发起者已撤销3.对方已确认4.到期自动确认',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `uid_idx` (`user_id`) USING BTREE,
KEY `uid2_idx` (`rec_user_id`) USING BTREE,
KEY `status_idx` (`status`) USING BTREE,
KEY `created_time` (`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='cp解除发起记录';
\ No newline at end of file
...@@ -30,6 +30,20 @@ func GetUserId(c *gin.Context) (mysql.ID, error) { ...@@ -30,6 +30,20 @@ func GetUserId(c *gin.Context) (mysql.ID, error) {
return 0, bizerr.ParaMissing return 0, bizerr.ParaMissing
} }
func ToUserId(myContext *mycontext.MyContext, externalId mysql.Str) (mysql.ID, error) {
return user_c.ToUserId(domain.CreateModelContext(myContext), externalId)
//if externalId == "" {
// return 0, myerr.NewSysError("externalId 不能为空")
//}
//var user user_m.User
//if err := mysql.Db.Where(&user_m.User{
// ExternalId: externalId,
//}).First(&user).Error; err != nil {
// return 0, bizerr.ExternalIdNoExist
//}
//return user.ID, nil
}
// 获取userId和externalId // 获取userId和externalId
func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) { func GetUserIdAndExtId(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string, error) {
if userIdStr, ok := c.Keys[mycontext.USERID]; ok { if userIdStr, ok := c.Keys[mycontext.USERID]; ok {
......
This diff is collapsed.
...@@ -42,6 +42,12 @@ func InitRouter() *gin.Engine { ...@@ -42,6 +42,12 @@ func InitRouter() *gin.Engine {
cp.PUT("/anniversary/:id", wrapper(cp_r.PutAnniversary)) cp.PUT("/anniversary/:id", wrapper(cp_r.PutAnniversary))
cp.GET("/anniversary", wrapper(cp_r.PageAnniversary)) cp.GET("/anniversary", wrapper(cp_r.PageAnniversary))
cp.DELETE("/anniversary/:id", wrapper(cp_r.DelAnniversary)) cp.DELETE("/anniversary/:id", wrapper(cp_r.DelAnniversary))
cp.GET("/relation/check", wrapper(cp_r.CheckUserCpRelation))
cp.POST("/relation", wrapper(cp_r.CpRelation))
cp.POST("/relation/invite/reply", wrapper(cp_r.ReplyCpInvite))
cp.POST("/relation/cancel/reply", wrapper(cp_r.ReplyCpCancel))
cp.GET("/relation/detail", wrapper(cp_r.CpDetailPage))
} }
inner := r.Group("/inner") inner := r.Group("/inner")
inner.Use(ExceptionHandle, LoggerHandle) inner.Use(ExceptionHandle, LoggerHandle)
......
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