Commit d8f57d9c authored by hujiebin's avatar hujiebin

feat:还有一半的group接口

parent 5742f471
...@@ -139,3 +139,19 @@ var GROUP_INTRODUCTION_LENGTH_LIMIT = 500 ...@@ -139,3 +139,19 @@ var GROUP_INTRODUCTION_LENGTH_LIMIT = 500
const ROOM_PASSWORD_LENGTH = 4 const ROOM_PASSWORD_LENGTH = 4
const SETTING_CUSTOMIZED = 2 const SETTING_CUSTOMIZED = 2
const SETTING_OFFICIAL = 1 const SETTING_OFFICIAL = 1
type AddGroupResultType = uint
const (
ADD_GROUP_DONE AddGroupResultType = 1
ADD_GROUP_DUPLICATE AddGroupResultType = 2
ADD_GROUP_PENDING AddGroupResultType = 3
ADD_GROUP_FAILED AddGroupResultType = 0
)
var GROUP_DEFAULT_JOIN_LIMIT uint = 200
var GROUP_VIP_JOIN_LIMIT uint = 500
var GROUP_NOBLE4_JOIN_LIMIT uint = 1000
var GROUP_ROLE_PERSONAL_VIEW_LIMIT = 5
var GROUP_MANAGER_LIMIT uint = 30
var GROUP_ADMIN_LIMIT uint = 50
package tim_e
// TIM相关常量
const (
SYNC_TO_SENDER = 1
NOSYNC_TO_SENDER = 2
TAG_PROFILE_IM_LEVEL = "Tag_Profile_IM_Level"
TAG_PROFILE_IM_NICK = "Tag_Profile_IM_Nick"
TAG_PROFILE_IM_IMAGE = "Tag_Profile_IM_Image"
TAG_PROFILE_IM_HILO = "Tag_Profile_Custom_Hilo"
)
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
"hilo-group/domain/model/res_m" "hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m" "hilo-group/domain/model/rocket_m"
"hilo-group/domain/service/group_s" "hilo-group/domain/service/group_s"
"hilo-group/myerr"
"sort" "sort"
) )
...@@ -379,3 +380,18 @@ func BuildJoinedGroupInfo(myService *domain.Service, myUserId uint64, groupIds [ ...@@ -379,3 +380,18 @@ func BuildJoinedGroupInfo(myService *domain.Service, myUserId uint64, groupIds [
} }
return result, len(groupInfo), nil return result, len(groupInfo), nil
} }
//检查群组中是否有有人在麦上,返回存在的Set[imGroupId]
func CheckMicHasUserByGroup(groupIds []string) (map[string]struct{}, error) {
groupMap := map[string]struct{}{}
for i := 0; i < len(groupIds); i++ {
flag, err := group_m.CheckGroupMicHasUser(groupIds[i])
if err != nil {
return nil, myerr.WrapErr(err)
}
if flag {
groupMap[groupIds[i]] = struct{}{}
}
}
return groupMap, nil
}
...@@ -1033,3 +1033,163 @@ func GetUserBases(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserBase, error) ...@@ -1033,3 +1033,163 @@ func GetUserBases(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserBase, error)
} }
return cvUserBases, nil return cvUserBases, nil
} }
func BatchGetUserExtend(model *domain.Model, userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]CvUserExtend, error) {
ub, err := GetUserBases(userIds, myUserId)
if err != nil {
return nil, err
}
wg, err := BatchGetWealthGrade(userIds)
if err != nil {
return nil, err
}
cg, err := BatchGetCharmGrade(userIds)
if err != nil {
return nil, err
}
ag, err := BatchGetActiveGrade(userIds)
if err != nil {
return nil, err
}
result := make(map[mysql.ID]CvUserExtend, 0)
for _, i := range ub {
result[*i.Id] = CvUserExtend{
CvUserBase: *i,
WealthGrade: wg[*i.Id],
CharmGrade: cg[*i.Id],
ActiveGrade: ag[*i.Id],
}
}
return result, nil
}
func GetUserBase(userId mysql.ID, myUserId mysql.ID) (*CvUserBase, error) {
var user user_m.User
if err := mysql.Db.First(&user, userId).Error; err != nil {
return nil, myerr.WrapErr(err)
}
isVip, expireTime, err := user_m.IsVip(userId)
if err != nil {
return nil, myerr.WrapErr(err)
}
cvHeadwear, err := headwear_cv.GetCvHeadwear(userId)
if err != nil {
return nil, err
}
logger := mylogrus.MyLog.WithField("func", "GetUserBase")
medals, err := user_m.GetUserMedalMerge(logger, mysql.Db, userId)
if err != nil {
return nil, err
}
medals, medalInfo, err := getMedalInfo(mysql.Db, medals)
if err != nil {
return nil, err
}
up := user_m.UserProperty{}
rides, err := up.BatchGet(mysql.Db, []uint64{userId})
if err != nil {
return nil, err
}
rp := res_m.ResProperty{}
properties, err := rp.GetAll(mysql.Db)
if err != nil {
return nil, err
}
superManagerMap, err := user_m.GetSuperManagerMap([]uint64{userId})
if err != nil {
return nil, err
}
cvUserBase := CvUserBase{
Id: &user.ID,
Avatar: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)),
DefaultAvatar: &user.DefaultAvatar,
ExternalId: StrToString(&user.ExternalId),
Nick: StrNil(IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick)),
Description: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Description)),
Sex: TypeToUint8((*mysql.Type)(&user.Sex)),
Country: StrNil(user.Country),
CountryIcon: StrNil(user.CountryIcon),
Code: StrToString(&user.Code),
IsPrettyCode: user.IsPrettyCode(),
IsVip: isVip,
IsOfficialStaff: superManagerMap[user.ID],
Medals: IfLogoutMedals(IfLogout(user.LogoutTime), []uint32{}, medals),
MedalInfo: IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo),
Headwear: IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, cvHeadwear),
Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, property_cv.CvProperty{
Id: rides[user.ID],
PicUrl: properties[rides[user.ID]].PicUrl,
EffectUrl: properties[rides[user.ID]].EffectUrl,
}),
}
noble, err := noble_m.FindActiveNoble(mysql.Db, userId)
if err != nil {
return nil, err
}
if noble != nil {
cvUserBase.Noble = noble_cv.CvNoble{
Level: noble.Level,
EndTime: noble.EndTime.Unix(),
}
}
//本人
if userId == myUserId {
cvUserBase.VipExpireTime = expireTime
cvUserBase.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge))
cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
isAgent := user_m.IsAgent(myUserId)
cvUserBase.IsAgentMgr = &isAgent
} else if user.IsShowAge == mysql.OPEN {
cvUserBase.Birthday = BirthdayToUint64(&user.Birthday)
}
//判断是不是工会
userTradeUnion, err := user_m.GetUserTradeUnion(myUserId)
if err != nil {
return nil, err
}
if userTradeUnion == nil {
isTradeUnionFlag := false
cvUserBase.IsTradeUnion = &isTradeUnionFlag
cvUserBase.IsTradeUnionMatchNotification = nil
} else {
isTradeUnionFlag := true
cvUserBase.IsTradeUnion = &isTradeUnionFlag
isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN
cvUserBase.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag
}
return &cvUserBase, nil
}
func getMedalInfo(db *gorm.DB, medals []uint32) ([]uint32, []medal_cv.CvMedal, error) {
resMedals, err := res_m.MedalGetAllMap(db)
if err != nil {
return nil, nil, err
}
// 只选择合法的勋章
validMedals := make([]uint32, 0)
medalInfo := make([]medal_cv.CvMedal, 0)
for _, i := range medals {
if e, ok := resMedals[i]; ok {
validMedals = append(validMedals, i)
medalInfo = append(medalInfo, medal_cv.CvMedal{
Id: i,
PicUrl: e.PicUrl,
EffectUrl: e.SvgaUrl,
})
}
}
return validMedals, medalInfo, nil
}
...@@ -57,11 +57,27 @@ func SetExists(groupId string) (int64, error) { ...@@ -57,11 +57,27 @@ func SetExists(groupId string) (int64, error) {
return redisCli.RedisClient.Exists(context.Background(), key).Result() return redisCli.RedisClient.Exists(context.Background(), key).Result()
} }
func AddGroupMember(groupId string, extIds []string) (int64, error) { func addGroupMember(groupId string, extIds []string) (int64, error) {
key := getGroupMemberKey(groupId) key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SAdd(context.Background(), key, extIds).Result() return redisCli.RedisClient.SAdd(context.Background(), key, extIds).Result()
} }
func AddGroupMember(model *domain.Model, groupId string, extId string) error {
key := getGroupMemberKey(groupId)
ret, err := redisCli.RedisClient.Exists(context.Background(), key).Result()
if err != nil {
model.Log.Infof("AddGroupMember %s, skip because set does not exist", groupId)
return err
}
if ret == 0 {
// 集合不存在,不要加进去!
return nil
}
ret, err = addGroupMember(groupId, []string{extId})
model.Log.Infof("AddGroupMember %s, %s ret = %d, err: %v", groupId, extId, ret, err)
return err
}
func RemoveGroupMember(groupId string, externalId string) (int64, error) { func RemoveGroupMember(groupId string, externalId string) (int64, error) {
key := getGroupMemberKey(groupId) key := getGroupMemberKey(groupId)
return redisCli.RedisClient.SRem(context.Background(), key, externalId).Result() return redisCli.RedisClient.SRem(context.Background(), key, externalId).Result()
...@@ -139,3 +155,26 @@ func SetGroupInfoCache(model *domain.Model, info *group_m.GroupInfo) error { ...@@ -139,3 +155,26 @@ func SetGroupInfoCache(model *domain.Model, info *group_m.GroupInfo) error {
} }
return nil return nil
} }
// 增加领取群组扶持ip次数
func IncrGroupSupportAwardIp(model *domain.Model, ip mysql.Str) (times int64, err error) {
key := group_k.GetGroupSupportAwardIpKey(ip)
times, err = model.Redis.Incr(model, key).Result()
if err != nil {
model.Log.Errorf("IncrGroupSupportAwardIp fail,ip:%v,err:%v", ip, err)
} else {
model.Redis.Expire(model, key, time.Hour*24*6) // 1周1次,ttl=6天吧
}
return
}
// 获取领取群组扶持ip次数
func GetGroupSupportAwardIpTimes(model *domain.Model, ip mysql.Str) (times int64, err error) {
key := group_k.GetGroupSupportAwardIpKey(ip)
times, err = model.Redis.Get(model, key).Int64()
if err != nil && err != redis.Nil {
model.Log.Errorf("GetGroupSupportAwardIpTimes fail,ip:%v,err:%v", ip, err)
return
}
return times, nil
}
package group_ev
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type GroupSupportEvent struct {
GroupSupportAwardAdmin GroupSupportItem
GroupCode string
GroupSupportAwardMgrs []GroupSupportItem
}
type GroupSupportItem struct {
GroupSupportAwardId mysql.ID
UserId mysql.ID
DiamondNum uint32
}
func InitGroupSupportEvent(size int, groupCode string) *GroupSupportEvent {
return &GroupSupportEvent{GroupSupportAwardMgrs: make([]GroupSupportItem, 0, size), GroupCode: groupCode}
}
func (groupSupportEvent *GroupSupportEvent) AddAdmin(groupSupportAwardId mysql.ID, userId mysql.ID, diamondNum uint32) *GroupSupportEvent {
groupSupportEvent.GroupSupportAwardAdmin = GroupSupportItem{
GroupSupportAwardId: groupSupportAwardId,
UserId: userId,
DiamondNum: diamondNum,
}
return groupSupportEvent
}
func (groupSupportEvent *GroupSupportEvent) AddMgr(groupSupportAwardId mysql.ID, userId mysql.ID, diamondNum uint32) *GroupSupportEvent {
groupSupportEvent.GroupSupportAwardMgrs = append(groupSupportEvent.GroupSupportAwardMgrs, GroupSupportItem{
GroupSupportAwardId: groupSupportAwardId,
UserId: userId,
DiamondNum: diamondNum,
})
return groupSupportEvent
}
//注册监听
var groupSupportListen = new(domain.EventBase)
//添加领域事件,在每个领域模型中init中添加,因为这是静态业务,非动态的。
func AddGroupSupportSync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventSync(groupSupportListen, callback)
}
//加入到异步操作中
func AddGroupSupportAsync(callback func(model *domain.Model, event interface{}) error) {
domain.AddEventAsync(groupSupportListen, callback)
}
//领域事件发布
func PublishGroupSupport(model *domain.Model, event interface{}) error {
return domain.PublishEvent(groupSupportListen, model, event)
}
...@@ -2,9 +2,16 @@ package diamond_m ...@@ -2,9 +2,16 @@ package diamond_m
import ( import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"gorm.io/gorm"
"hilo-group/_const/enum/diamond_e" "hilo-group/_const/enum/diamond_e"
"hilo-group/domain/model"
"hilo-group/myerr" "hilo-group/myerr"
"hilo-group/myerr/bizerr"
"strconv"
"time"
) )
type DiamondAccount struct { type DiamondAccount struct {
...@@ -61,3 +68,203 @@ func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAc ...@@ -61,3 +68,203 @@ func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAc
diamondAccount.Model = model diamondAccount.Model = model
return &diamondAccount, nil return &diamondAccount, nil
} }
//账号操作配置
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
}
//匹配条件扣费
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: 1, // 1:黄钻 2:粉钻
}).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 (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
}
//群组支持
func (diamondAccount *DiamondAccount) GroupSupportAdmin(groupSupportAwardId mysql.ID, diamondNum uint32) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(diamond_e.GroupSupportAdmin, groupSupportAwardId, diamondNum)
}
func (diamondAccountDetail *DiamondAccountDetail) Persistent() 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 {
mylogrus.MyLog.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
}
//群组支持
func (diamondAccount *DiamondAccount) GroupSupportMgr(groupSupportAwardId mysql.ID, diamondNum uint32) (*DiamondAccountDetail, error) {
return diamondAccount.addDiamondAccountDetail(diamond_e.GroupSupportMgr, groupSupportAwardId, diamondNum)
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"gorm.io/gorm" "gorm.io/gorm"
"hilo-group/_const/enum/game_e" "hilo-group/_const/enum/game_e"
"hilo-group/myerr"
"time" "time"
) )
...@@ -78,3 +79,22 @@ func GetNotEndGamesMap(model *domain.Model) map[string][]game_e.GameType { ...@@ -78,3 +79,22 @@ func GetNotEndGamesMap(model *domain.Model) map[string][]game_e.GameType {
} }
return res return res
} }
func IsGaming(model *domain.Model, userId uint64, txGroupId string) (bool, error) {
ids := make([]uint64, 0)
err := model.DB().Table("game_info").Where("tx_group_id = ? and battle_end_at = 0 and status in (0, 1)", txGroupId).Limit(1).Pluck("id", &ids).Error
if err != nil {
return false, myerr.WrapErr(err)
}
if len(ids) > 0 {
userIds := make([]uint64, 0)
err = model.DB().Table("game_player").Where("game_id = ? and user_id = ? and status in (0,1)", ids[0], userId).Limit(1).Pluck("id", &userIds).Error
if err != nil {
return false, myerr.WrapErr(err)
}
if len(userIds) > 0 {
return true, nil
}
}
return false, nil
}
package group_m
import (
"git.hilo.cn/hilo-common/domain"
"gorm.io/gorm"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"time"
)
type GroupInviteJoin struct {
Id uint64 `json:"id"`
UserId uint64 `json:"user_id"`
ImGroupId string `json:"im_group_id"`
CreatedTime time.Time `json:"created_time"`
UpdatedTime time.Time `json:"updated_time"`
InviteUserId uint64 `json:"invite_user_id"`
IsAccept int8 `json:"is_accept"`
}
func GetByImGroupId(model *domain.Model, imGroupId string) (*GroupInfo, error) {
if len(imGroupId) <= 0 {
return nil, myerr.WrapErr(bizerr.GroupNotFound)
}
res := new(GroupInfo)
err := model.DB().Where(&GroupInfo{ImGroupId: imGroupId}).First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return res, nil
}
func AcceptGroupInviteJoin(model *domain.Model, userId uint64, imGroupId string) error {
err := model.DB().Exec("update group_invite_join set is_accept = 1 where user_id=? and im_group_id=?", userId, imGroupId).Error
if err != nil {
return myerr.WrapErr(err)
}
return nil
}
func GetGroupInviteJoin(model *domain.Model, userId uint64, imGroupId string) (*GroupInviteJoin, error) {
res := new(GroupInviteJoin)
err := model.DB().Where(&GroupInviteJoin{UserId: userId, ImGroupId: imGroupId}).Where("is_accept=0").First(&res).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
} else {
return nil, myerr.WrapErr(err)
}
}
return res, nil
}
func InsertGroupInviteJoin(model *domain.Model, userId, inviteUserId uint64, imGroupId string) error {
nowTime := time.Now()
sql := "insert into group_invite_join(user_id,invite_user_id,im_group_id,is_accept,created_time,updated_time) " +
"value(?,?,?,?,?,?) on duplicate key update is_accept=?,created_time=?,updated_time=?"
err := model.DB().Exec(sql, userId, inviteUserId, imGroupId, 0, nowTime, nowTime, 0, nowTime, nowTime).Error
if err != nil {
return myerr.WrapErr(bizerr.GroupNotFound)
}
return nil
}
package mgr_m
import (
"database/sql/driver"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
"strings"
"time"
)
type Strs []string
func (this *Strs) Scan(val interface{}) error {
s := val.([]uint8)
ss := strings.Split(string(s), ",")
*this = ss
return nil
}
func (this Strs) Value() (driver.Value, error) {
str := strings.Join(this, ",")
return str, nil
}
//群组Banner
type GroupBanner struct {
mysql.Entity
*domain.Model `gorm:"-"`
Title mysql.Str
Image mysql.Str
Url mysql.Str
GroupCode mysql.Str //群组code
N mysql.Num
Status mysql.UserYesNo
Area int // 上线区域:0全区;1阿语区;2非阿语区;3指定国家
CountryList Strs // 指定区域的国家列表
StartAt int64 // 上架时间戳
EndAt int64 // 下架时间戳
}
func GetGroupBanner(model *domain.Model, id mysql.ID) (*GroupBanner, error) {
groupBanner := GroupBanner{}
if err := model.Db.Model(&GroupBanner{}).First(&groupBanner, id).Error; err != nil {
return &groupBanner, myerr.WrapErr(err)
}
groupBanner.Model = model
return &groupBanner, nil
}
//加入
func AddGroupBanner(model *domain.Model, title mysql.Str, image mysql.Str, url mysql.Str, groupCode mysql.Str, n mysql.Num) *GroupBanner {
return &GroupBanner{
Model: model,
Title: title,
Image: image,
Url: url,
GroupCode: groupCode,
N: n,
Status: mysql.USER,
}
}
//更新
func (groupBanner *GroupBanner) Update(title mysql.Str, image mysql.Str, url mysql.Str, groupCode mysql.Str, n mysql.Num) *GroupBanner {
groupBanner.Title = title
groupBanner.Image = image
groupBanner.Url = url
groupBanner.GroupCode = groupCode
groupBanner.N = n
return groupBanner
}
//上架
func (groupBanner *GroupBanner) User() *GroupBanner {
groupBanner.Status = mysql.USER
return groupBanner
}
//下架
func (groupBanner *GroupBanner) NoUser() *GroupBanner {
groupBanner.Status = mysql.NOUSER
return groupBanner
}
// 房间Banner
type RoomBanner struct {
mysql.Entity
Title mysql.Str
Image mysql.Str
Url mysql.Str
N mysql.Num
Status mysql.UserYesNo
Area int // 上线区域:0全区;1阿语区;2非阿语区;3指定国家
CountryList Strs // 指定区域的国家列表
}
func (rb *RoomBanner) GetRoomBanners(db *gorm.DB, vcAllow bool) ([]RoomBanner, error) {
rows := make([]RoomBanner, 0)
if err := db.Model(&RoomBanner{}).Where(rb).Order("n DESC").Find(&rows).Error; err != nil {
return nil, err
}
res := make([]RoomBanner, 0, len(rows))
for _, v := range rows {
if !vcAllow && v.ID == 241 {
continue
}
res = append(res, v)
}
return res, nil
}
func (rb *RoomBanner) Create(db *gorm.DB) error {
return db.Save(rb).Error
}
func (rb *RoomBanner) Save(db *gorm.DB) error {
return db.Omit("status").Save(rb).Error
}
func (rb *RoomBanner) SetStatus(db *gorm.DB, status uint8) error {
return db.Model(&RoomBanner{}).Where(rb).Update("status", status).Error
}
type DiscoveryBanner struct {
mysql.Entity
*domain.Model `gorm:"-"`
Title mysql.Str
Image mysql.Str
Url mysql.Str
GroupCode mysql.Str
N mysql.Num
BeginTime time.Time
EndTime time.Time
Area int // 上线区域:0全区;1阿语区;2非阿语区;3指定国家
CountryList Strs // 指定区域的国家列表
}
func GetDiscoveryBannerOrErr(model *domain.Model, id mysql.ID) (*DiscoveryBanner, error) {
discoveryBanner := DiscoveryBanner{}
if err := model.Db.Model(&DiscoveryBanner{}).First(&discoveryBanner, id).Error; err != nil {
return &discoveryBanner, myerr.WrapErr(err)
}
discoveryBanner.Model = model
return &discoveryBanner, nil
}
func InitDiscoveryBanner(model *domain.Model, title mysql.Str, image mysql.Str, url mysql.Str, groupCode mysql.Str, n mysql.Num, beginTime time.Time, endTime time.Time) *DiscoveryBanner {
return &DiscoveryBanner{
Model: model,
Title: title,
Image: image,
Url: url,
GroupCode: groupCode,
N: n,
BeginTime: beginTime,
EndTime: endTime,
}
}
//更新
func (discoveryBanner *DiscoveryBanner) Update(title mysql.Str, image mysql.Str, url mysql.Str, groupCode mysql.Str, n mysql.Num, beginTime time.Time, endTime time.Time) *DiscoveryBanner {
discoveryBanner.Title = title
discoveryBanner.Image = image
discoveryBanner.Url = url
discoveryBanner.GroupCode = groupCode
discoveryBanner.N = n
discoveryBanner.BeginTime = beginTime
discoveryBanner.EndTime = endTime
return discoveryBanner
}
func (discoveryBanner *DiscoveryBanner) EditEndTime(time time.Time) *DiscoveryBanner {
discoveryBanner.EndTime = time
return discoveryBanner
}
func (discoveryBanner *DiscoveryBanner) EditBeginTime(time time.Time) *DiscoveryBanner {
discoveryBanner.BeginTime = time
return discoveryBanner
}
package res_m package res_m
import ( import (
"fmt"
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/msg_e"
"hilo-group/myerr" "hilo-group/myerr"
) )
...@@ -28,3 +31,20 @@ func CheckCode(model *domain.Model, code string) (bool, error) { ...@@ -28,3 +31,20 @@ func CheckCode(model *domain.Model, code string) (bool, error) {
return false, nil return false, nil
} }
} }
func GetErrByLanguage(db *gorm.DB, msgId msg_e.MsgIdType, lang string, myErr *myerr.BusinessError, args ...interface{}) *myerr.BusinessError {
var msg string
if len(args) > 0 {
msg = fmt.Sprintf(myErr.GetMsg(), args...)
} else {
msg = myErr.GetMsg()
}
if resMul, _ := GetResMultiTextBy(db, msgId, lang); resMul != nil {
if len(args) > 0 {
msg = fmt.Sprintf(resMul.Content, args...)
} else {
msg = resMul.Content
}
}
return myerr.NewBusinessCodeNoCheck(myErr.GetCode(), msg, myerr.BusinessData{})
}
package tim_m
import (
"context"
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/sdk/tencentyun"
"hilo-group/_const/enum/msg_e"
"hilo-group/_const/enum/online_e"
"hilo-group/_const/enum/tim_e"
"hilo-group/_const/redis_key"
"hilo-group/domain/model/groupPower_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"runtime/debug"
"strconv"
"time"
)
func FlushGrades(userExtId string, wealthGrade uint32, charmGrade uint32) error {
level := (charmGrade & 0x000000FF << 8) | wealthGrade&0x000000FF
return tencentyun.SetUserLevel(userExtId, level)
}
func SyncWealthGrade(userExtId string, wealthGrade uint32) error {
level, err := tencentyun.GetUserLevel(userExtId)
if err != nil {
return err
}
mylogrus.MyLog.Infof("SyncWealthGrade, user %s, level before = %x, wealthGrade = %d", userExtId, level, wealthGrade)
level = level&0xFFFFFF00 | wealthGrade&0x000000FF
return tencentyun.SetUserLevel(userExtId, level)
}
func SyncCharmGrade(userExtId string, charmGrade uint32) error {
level, err := tencentyun.GetUserLevel(userExtId)
if err != nil {
return err
}
mylogrus.MyLog.Infof("SyncCharmGrade, user %s, level before = %x, charmGrade = %d", userExtId, level, charmGrade)
level = level&0xFFFF00FF | (charmGrade & 0x000000FF << 8)
return tencentyun.SetUserLevel(userExtId, level)
}
type TimHiloInfo struct {
IsVip bool `json:"isVip"`
IsPretty bool `json:"isPretty"`
Medals []uint32 `json:"medals"`
PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称
NobleLevel uint16 `json:"nobleLevel"`
}
func GetHiloInfo(extId string) (string, error) {
result, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return "", err
}
return result, nil
}
func ResetHiloInfo(extId string) error {
info := TimHiloInfo{}
buf, err := json.Marshal(info)
if err != nil {
return err
}
return tencentyun.SetUserHiloInfo(extId, string(buf))
}
func SyncIsVip(model *domain.Model, userId uint64, externalId string) error {
//detail, err := cv.GetUserVip(model, userId)
//if err != nil {
// return err
//}
isVip, _, err := user_m.IsVip(userId)
if err != nil {
return err
}
//isVip := false
//if detail != nil {
// isVip = true
//}
if err = SaveIsVip(externalId, isVip); err != nil {
model.Log.Info("Sync TIM hilo info failed: ", err)
}
return nil
}
func SaveIsVip(extId string, isVip bool) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.IsVip = isVip
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func SyncIsPretty(extId string, isPretty bool) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.IsPretty = isPretty
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func SyncMedals(model *domain.Model, userId uint64, externalId string) error {
// 同步勋章
medals, err := user_m.GetUserMedalMerge(model.Log, model.Db, userId)
if err != nil {
return nil
}
if err = SaveMedals(externalId, medals); err != nil {
mylogrus.MyLog.Info("Sync TIM hilo info failed: ", err)
}
return nil
}
// fixme:同步贵族信息,购买、续费贵族时需要
func SyncNobleLevel(extId string, nobleLevel uint16) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.NobleLevel = nobleLevel
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func SaveMedals(extId string, medals []uint32) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.Medals = medals
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
// fixme: 以下时机要同步:用户加入/退出势力;势力被取消;势力改绑定群组;群组改名称,欢迎补充
func SyncPowerName(model *domain.Model, userId uint64, externalId string) error {
_, powerName, err := groupPower_m.GetUserGroupPower(model, userId)
if err != nil {
return err
}
if err = SavePowerName(externalId, powerName); err != nil {
mylogrus.MyLog.Info("Sync TIM hilo info failed: ", err)
}
return nil
}
func SavePowerName(extId string, powerName string) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.PowerName = powerName
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func SaveNobleLevel(extId string, nobleLevel uint16) error {
value, err := tencentyun.GetUserHiloInfo(extId)
if err != nil {
return err
}
mylogrus.MyLog.Info("TIM hilo info: ", value)
info := TimHiloInfo{}
if len(value) > 0 {
if err = json.Unmarshal([]byte(value), &info); err != nil {
return err
}
}
info.NobleLevel = nobleLevel
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func FlushHiloInfo(extId string, isVip bool, isPrettyCode bool, medals []uint32, groupPowerName string, nobleLevel uint16) error {
info := TimHiloInfo{IsVip: isVip, IsPretty: isPrettyCode, Medals: medals, PowerName: groupPowerName, NobleLevel: nobleLevel}
buf, err := json.Marshal(info)
if err != nil {
return err
}
if err = tencentyun.SetUserHiloInfo(extId, string(buf)); err != nil {
return err
}
return nil
}
func SendGroupInvitationShare(model *domain.Model, fromAccount string, toAccounts []string, txGroupId, faceUrl string, lang string) error {
type TIMInviteEnterRoomMessage struct {
Identifier string `json:"identifier"`
GroupFaceUrl string `json:"groupFaceUrl"`
GroupId string `json:"groupId"`
}
msg := TIMInviteEnterRoomMessage{
Identifier: "TIMGroupInviteMessage",
GroupFaceUrl: faceUrl,
GroupId: txGroupId,
}
buf, err := json.Marshal(msg)
if err != nil {
return err
}
msgBody := string(buf)
/* mt := res_m.ResMultiText{MsgId: common.MSG_ID_GROUP_INVITE, Language: lang}
if err = mt.Get(model.Db); err != nil {
return err
}*/
mt, err := res_m.GetResMultiTextBy(model.Db, msg_e.MSG_ID_GROUP_INVITE, lang)
if err != nil {
return err
}
return tencentyun.BatchSendCustomMsg(model, tim_e.SYNC_TO_SENDER, fromAccount, toAccounts, msgBody, mt.Content)
}
func GetOnlineStatus(model *domain.Model, extIds []string) (map[string]uint, error) {
left := make([]string, 0)
result := make(map[string]uint, 0)
r, err := getOnlineStatus(extIds)
if err != nil {
model.Log.Warnf("getOnlineStatus redis failed")
left = extIds
} else {
model.Log.Infof("getOnlineStatus redis return size = %d: %v", len(r), r)
if len(r) >= len(extIds) {
for i, e := range extIds {
if r[i] == nil {
left = append(left, e)
} else {
switch r[i].(type) {
case string:
s, err := strconv.Atoi(r[i].(string))
if err == nil {
result[e] = uint(s)
} else {
left = append(left, e)
}
default:
model.Log.Infof("getOnlineStatus return unknown type %v for %s", r[i], e)
left = append(left, e)
}
}
}
} else {
left = extIds
}
}
model.Log.Debug("getOnlineStatus cache: ", result)
if len(left) > 0 {
for _, i := range left {
result[i] = online_e.IM_STATUS_OFF_LINE
}
// 异步去取TIM取数据及更新。查不到的就当离线!
go func(userIds []string) {
defer func() {
if r := recover(); r != nil {
mylogrus.MyLog.Errorf("SetOnlineStatus SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
st, err := tencentyun.BatchQueryState(model, userIds)
if err != nil {
return
}
mylogrus.MyLog.Info("getOnlineStatus db: ", st)
for k, v := range st {
if err := setOnlineStatus(k, v, time.Hour*12); err != nil {
model.Log.Warn("SetOnlineStatus failed for ", k)
} else {
model.Log.Infof("SetOnlineStatus done %s - %d", k, v)
}
}
}(left)
}
return result, nil
}
func getOnlineStatus(extIds []string) ([]interface{}, error) {
keys := make([]string, 0)
for _, e := range extIds {
keys = append(keys, redis_key.GetOnLineStatusKey(e))
}
return redisCli.RedisClient.MGet(context.Background(), keys...).Result()
}
func setOnlineStatus(extId string, status uint, ttl time.Duration) error {
key := redis_key.GetOnLineStatusKey(extId)
return redisCli.RedisClient.Set(context.Background(), key, status, ttl).Err()
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"hilo-group/myerr"
)
//获取用户的国家,和所属的区域(是否阿语区)
func GetUserCountryArea(model *domain.Model, id mysql.ID) (string, int, error) {
type info struct {
Name string
Area int
}
res := new(info)
if err := model.DB().Raw("select name, area from res_country where name = (select country from user where id = ?)", id).First(&res).Error; err != nil {
return "", 0, myerr.WrapErr(err)
}
return res.Name, res.Area, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
)
//用户设备
type UserImei struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Imei mysql.Str
}
func getUserImeiOrCreate(model *domain.Model, userId mysql.ID) (*UserImei, error) {
var userImei UserImei
if err := model.Db.Where(&UserImei{
UserId: userId,
}).First(&userImei).Error; err != nil {
if err == gorm.ErrRecordNotFound {
userImei.UserId = userId
//userImei.Imei = imei
} else {
return nil, myerr.WrapErr(err)
}
}
/* else {
if userImei.Imei == imei {
userImei.SetLasyLoad()
} else {
userImei.Imei = imei
}
}*/
userImei.Model = model
return &userImei, nil
}
func GetUserImeiStr(model *domain.Model, userId mysql.ID) (string, error) {
var userImei UserImei
if err := model.Db.Where(&UserImei{
UserId: userId,
}).First(&userImei).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return "", nil
} else {
return "", myerr.WrapErr(err)
}
}
return userImei.Imei, nil
}
func (userImei *UserImei) updateImei(imei mysql.Str) {
if userImei.Imei == imei {
userImei.SetLasyLoad()
} else {
userImei.Imei = imei
}
}
//统计imei数量
func countImei(model *domain.Model, imei string) (int64, error) {
var c int64 = 0
if err := model.Db.Model(&UserImei{}).Where(&UserImei{
Imei: imei,
}).Count(&c).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return c, nil
}
func ImeiUserIds(model *domain.Model, imei string) ([]uint64, error) {
rows := []UserImei{}
if err := model.Db.Model(&UserImei{}).Where(&UserImei{
Imei: imei,
}).Find(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userIds := make([]uint64, 0, len(rows))
for _, i := range rows {
userIds = append(userIds, i.UserId)
}
return userIds, nil
}
func GetSameImeiUsers(model *domain.Model, userId uint64) ([]uint64, error) {
userImei, err := getUserImeiOrCreate(model, userId)
if err != nil {
return nil, err
}
if len(userImei.Imei) <= 0 {
return nil, nil
}
userIds, err := ImeiUserIds(model, userImei.Imei)
if err != nil {
return nil, err
}
return userIds, nil
}
func GetSameImeiMap(model *domain.Model, userId uint64) (map[uint64]uint64, error) {
rows, err := GetSameImeiUsers(model, userId)
if err != nil {
return nil, err
}
result := make(map[uint64]uint64, 0)
for _, i := range rows {
result[i] = userId
}
return result, nil
}
package user_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/myerr"
"time"
)
//用户IP
type UserIp struct {
mysql.Entity
*domain.Model `gorm:"-"`
UserId mysql.ID
Ip mysql.Str
}
func GetUserIpOrInit(model *domain.Model, userId mysql.ID) (*UserIp, error) {
var userIp UserIp
if err := model.Db.Where(&UserImei{
UserId: userId,
}).First(&userIp).Error; err != nil {
if err == gorm.ErrRecordNotFound {
userIp.UserId = userId
} else {
return nil, myerr.WrapErr(err)
}
}
userIp.Model = model
return &userIp, nil
}
func GetUserIpMap(db *gorm.DB, userIds []uint64) (map[uint64]string, error) {
rows := make([]UserIp, 0)
if err := db.Model(&UserIp{}).Where("user_id IN ?", userIds).Find(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
//
userIpMap := map[uint64]string{}
for _, i := range rows {
userIpMap[i.UserId] = i.Ip
}
return userIpMap, nil
}
//更新Ip
func (userIp *UserIp) UpdateIp(ip string) *UserIp {
userIp.Ip = ip
return userIp
}
//统计imei数量
func countIp(model *domain.Model, ip string, beginTime time.Time) (int64, error) {
var c int64 = 0
if err := model.Db.Model(&UserIp{}).Where(&UserIp{
Ip: ip,
}).Where("created_time >= ?", beginTime).Count(&c).Error; err != nil {
return 0, myerr.WrapErr(err)
}
return c, nil
}
func IpUserIds(model *domain.Model, ip string) ([]uint64, error) {
rows := []UserIp{}
if err := model.Db.Model(&UserIp{}).Where(&UserIp{
Ip: ip,
}).Find(&rows).Error; err != nil {
return nil, myerr.WrapErr(err)
}
userIds := make([]uint64, 0, len(rows))
for _, i := range rows {
userIds = append(userIds, i.UserId)
}
return userIds, nil
}
func GetSameIpUsers(model *domain.Model, userId uint64) ([]uint64, error) {
userIp, err := GetUserIpOrInit(model, userId)
if err != nil {
return nil, err
}
userIds, err := IpUserIds(model, userIp.Ip)
if err != nil {
return nil, err
}
return userIds, nil
}
func GetSameIpUsersMap(model *domain.Model, userId uint64) (map[uint64]struct{}, error) {
rec, err := GetSameIpUsers(model, userId)
if err != nil {
return nil, err
}
result := make(map[uint64]struct{}, 0)
for _, i := range rec {
result[i] = struct{}{}
}
return result, nil
}
...@@ -106,3 +106,15 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) { ...@@ -106,3 +106,15 @@ func GetUserByExtId(model *domain.Model, externalId string) (*User, error) {
user.Model = model user.Model = model
return &user, nil return &user, nil
} }
// 通过externalId批量获取用户
func BatchGetUserByExtIds(model *domain.Model, extIds []string) ([]User, error) {
users := make([]User, 0)
if err := model.Db.Where("external_id IN ?", extIds).Find(&users).Error; err != nil {
return nil, myerr.WrapErr(err)
}
for _, i := range users {
i.Model = model
}
return users, nil
}
package version_m
import (
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/resource/mysql"
)
type VersionControl struct {
mysql.Entity
Platform mysql.Str
AuditVersion mysql.Str
Status mysql.YesNo
}
// 获取所有版本控制
func GetVersionControlByPlatform(model *domain.Model, platform string) *VersionControl {
res := new(VersionControl)
if err := model.Db.Model(VersionControl{}).Where("platform = ?", platform).First(&res).Error; err != nil {
model.Log.Errorf("GetVersionControlByPlatform fail:%v", err)
}
if res.Status != mysql.YES {
res.AuditVersion = "999.999.999" // 不生效设置为无限大
}
return res
}
...@@ -3,14 +3,87 @@ package event_s ...@@ -3,14 +3,87 @@ package event_s
import ( import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"hilo-group/_const/enum/msg_e" "hilo-group/_const/enum/msg_e"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/event/group_power_ev" "hilo-group/domain/event/group_power_ev"
"hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/groupPower_m" "hilo-group/domain/model/groupPower_m"
"hilo-group/domain/model/msg_m" "hilo-group/domain/model/msg_m"
"hilo-group/domain/model/user_m" "hilo-group/domain/model/user_m"
"strconv"
) )
func EventInit() { func EventInit() {
GroupPowerEvents() GroupPowerEvents()
GroupSupportEvents()
}
func GroupSupportEvents() {
//群组支持
group_ev.AddGroupSupportSync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupSupportEvent)
if !ok {
model.Log.Errorf("AddGroupSupportSync fail data")
return nil
}
model.Log.Infof("diamond AddGroupSupport admin:%v mgrs:%v", event.GroupSupportAwardAdmin, event.GroupSupportAwardMgrs)
diamondAccountAdmin, err := diamond_m.GetDiamondAccountByUserId(model, event.GroupSupportAwardAdmin.UserId)
if err != nil {
return err
}
diamondAccountDetailAdmin, err := diamondAccountAdmin.GroupSupportAdmin(event.GroupSupportAwardAdmin.GroupSupportAwardId, event.GroupSupportAwardAdmin.DiamondNum)
if err != nil {
return err
}
if err := diamondAccountDetailAdmin.Persistent(); err != nil {
return err
}
for i, _ := range event.GroupSupportAwardMgrs {
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, event.GroupSupportAwardMgrs[i].UserId)
if err != nil {
return err
}
diamondAccountDetail, err := diamondAccount.GroupSupportMgr(event.GroupSupportAwardMgrs[i].GroupSupportAwardId, event.GroupSupportAwardMgrs[i].DiamondNum)
if err != nil {
return err
}
if err := diamondAccountDetail.Persistent(); err != nil {
return err
}
}
return nil
})
//群组支持奖励
group_ev.AddGroupSupportAsync(func(model *domain.Model, e interface{}) error {
event, ok := e.(*group_ev.GroupSupportEvent)
if !ok {
model.Log.Errorf("AddGroupSupportSync fail data")
return nil
}
model.Log.Infof("msg AddGroupSupportAsync admin:%v, mgr:%v", event.GroupSupportAwardAdmin, event.GroupSupportAwardMgrs)
for i, _ := range event.GroupSupportAwardMgrs {
user, err := user_m.GetUser(model, event.GroupSupportAwardMgrs[i].UserId)
if err != nil {
model.Log.Errorf("msg AddGroupSupportAsync GetUser userId:%v, err:%v", event.GroupSupportAwardMgrs[i].UserId, err)
}
if err := msg_m.NewUserRecord(model, user.ID, msg_e.GroupSupport, user.Nick, user.ID, strconv.FormatUint(uint64(event.GroupSupportAwardMgrs[i].DiamondNum), 10), "", "", "", event.GroupCode).Persistent(); err != nil {
model.Log.Errorf("msg AddGroupSupportAsync NewUserRecord err:%v", err)
break
}
msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
}
user, err := user_m.GetUser(model, event.GroupSupportAwardAdmin.UserId)
if err != nil {
model.Log.Errorf("msg AddGroupSupportAsync GetUser userId:%v, err:%v", event.GroupSupportAwardAdmin.UserId, err)
}
if err := msg_m.NewUserRecord(model, user.ID, msg_e.GroupSupport, user.Nick, user.ID, strconv.FormatUint(uint64(event.GroupSupportAwardAdmin.DiamondNum), 10), "", "", "", event.GroupCode).Persistent(); err != nil {
model.Log.Errorf("msg AddGroupSupportAsync NewUserRecord err:%v", err)
return nil
}
msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType)
return nil
})
} }
func GroupPowerEvents() { func GroupPowerEvents() {
......
...@@ -20,7 +20,7 @@ func NewGroupPowerService(myContext *mycontext.MyContext) *GroupPowerService { ...@@ -20,7 +20,7 @@ func NewGroupPowerService(myContext *mycontext.MyContext) *GroupPowerService {
//用户加入国家势力 //用户加入国家势力
func (s *GroupPowerService) GroupPowerUserJoin(groupPowerId mysql.ID, userId mysql.ID) error { func (s *GroupPowerService) GroupPowerUserJoin(groupPowerId mysql.ID, userId mysql.ID) error {
return s.svc.Transactional(func() error { return s.svc.Transactional(func() error {
model := domain.CreateModelContext(s.svc.MyContext) model := domain.CreateModel(s.svc.CtxAndDb)
groupPower, err := groupPower_m.GetGroupPower(model, groupPowerId) groupPower, err := groupPower_m.GetGroupPower(model, groupPowerId)
if err != nil { if err != nil {
return err return err
...@@ -43,7 +43,7 @@ func (s *GroupPowerService) GroupPowerUserJoin(groupPowerId mysql.ID, userId mys ...@@ -43,7 +43,7 @@ func (s *GroupPowerService) GroupPowerUserJoin(groupPowerId mysql.ID, userId mys
func (s *GroupPowerService) GroupPowerUserLeave(groupPowerId mysql.ID, userId mysql.ID) (int, error) { func (s *GroupPowerService) GroupPowerUserLeave(groupPowerId mysql.ID, userId mysql.ID) (int, error) {
remainSeconds := 0 remainSeconds := 0
err := s.svc.Transactional(func() error { err := s.svc.Transactional(func() error {
model := domain.CreateModelContext(s.svc.MyContext) model := domain.CreateModel(s.svc.CtxAndDb)
groupPower, err := groupPower_m.GetGroupPower(model, groupPowerId) groupPower, err := groupPower_m.GetGroupPower(model, groupPowerId)
if err != nil { if err != nil {
return err return err
......
...@@ -4,9 +4,13 @@ import ( ...@@ -4,9 +4,13 @@ import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/config" "git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e" "hilo-group/_const/enum/group_e"
"hilo-group/_const/redis_key" "hilo-group/_const/redis_key"
"hilo-group/domain/model/group_m" "hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/user_m"
"strconv" "strconv"
"time" "time"
) )
...@@ -82,3 +86,33 @@ func GetAllSupportLevel(model *domain.Model, date string) (map[string]string, er ...@@ -82,3 +86,33 @@ func GetAllSupportLevel(model *domain.Model, date string) (map[string]string, er
key := redis_key.GetPrefixSupportLevel(date) key := redis_key.GetPrefixSupportLevel(date)
return model.Redis.HGetAll(model, key).Result() return model.Redis.HGetAll(model, key).Result()
} }
func (s *GroupService) GetJoinGroupLimit(userId mysql.ID) (uint, error) {
model := domain.CreateModelContext(s.svc.MyContext)
// 获取群用户上限
maxJoin := group_e.GROUP_DEFAULT_JOIN_LIMIT
isVip, _, err := user_m.IsVip(userId)
if err != nil {
return 0, err
}
if isVip {
maxJoin = group_e.GROUP_VIP_JOIN_LIMIT
}
isNoble4, err := noble_m.CheckNobleLevel(model.Db, userId, 4)
if err != nil {
return 0, err
}
if isNoble4 {
maxJoin = group_e.GROUP_NOBLE4_JOIN_LIMIT
}
guLimit := group_m.GroupUserLimits{UserId: userId}
if err = guLimit.Get(model); err != nil && err != gorm.ErrRecordNotFound {
return 0, err
}
if err != gorm.ErrRecordNotFound {
maxJoin = guLimit.MaxJoin
}
return maxJoin, nil
}
...@@ -2,7 +2,9 @@ package group_s ...@@ -2,7 +2,9 @@ package group_s
import ( import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mylogrus"
"hilo-group/_const/enum/group_e" "hilo-group/_const/enum/group_e"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/model/group_m" "hilo-group/domain/model/group_m"
) )
...@@ -19,3 +21,74 @@ func (s *GroupService) CreateGroup(userId uint64, g *group_m.GroupInfo) error { ...@@ -19,3 +21,74 @@ func (s *GroupService) CreateGroup(userId uint64, g *group_m.GroupInfo) error {
return nil return nil
}) })
} }
// 退群的一系列操作
func (s *GroupService) LeaveGroup(model *domain.Model, groupId string, userId uint64, externalId string) error {
//获取用户是否在麦上, 让用户离开麦
micUser, err := group_m.GetMicUserByExternalId(model, externalId)
if err != nil {
return err
}
if micUser != nil {
if err = micUser.LeaveByUser(userId, externalId); err != nil {
return err
}
}
// 退群后删除管理角色
if err = group_m.RemoveGroupRole(model, groupId, userId); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's role.", groupId, userId)
}
// 退群后删除它(可能)作为经理设置的欢迎语
gwt := group_m.GroupWelcomeText{}
if err = gwt.Remove(model.Db, groupId, userId); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's welcome text.", groupId, userId)
}
// 退群后删除小闹钟
groupUser := group_m.GroupUser{Model: model, GroupId: groupId, UserId: userId}
if err = groupUser.Delete(); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's option.", groupId, userId)
}
// 清理相关缓存
group_c.ClearGroupMemberCount(groupId)
group_c.RemoveGroupMember(groupId, externalId)
return nil
}
// 退出永久会员的一系列操作
func (s *GroupService) LeaveGroupMember(model *domain.Model, groupId string, userId uint64, externalId string) error {
gm := group_m.GroupMember{
GroupId: groupId,
UserId: userId,
}
if err := gm.Remove(model.Db); err != nil {
return err
}
// 退群后删除管理角色
if err := group_m.RemoveGroupRole(model, groupId, userId); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's role.", groupId, userId)
}
// 退群后删除它(可能)作为经理设置的欢迎语
gwt := group_m.GroupWelcomeText{}
if err := gwt.Remove(model.Db, groupId, userId); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's welcome text.", groupId, userId)
}
// 退群后删除小闹钟
groupUser := group_m.GroupUser{Model: model, GroupId: groupId, UserId: userId}
if err := groupUser.Delete(); err != nil {
mylogrus.MyLog.Warnf("Can't remove group %s user %d's option.", groupId, userId)
}
// 清理相关缓存
group_c.ClearGroupMemberCount(groupId)
group_c.RemoveGroupMember(groupId, externalId)
return nil
}
package group_s
import (
"git.hilo.cn/hilo-common/domain"
"hilo-group/_const/enum/gift_e"
"hilo-group/domain/event/group_ev"
"hilo-group/domain/model/gift_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/myerr/bizerr"
"time"
)
// 群组支持名单过滤
func (s *GroupService) GroupSupportList(groupId string, uids []uint64) ([]uint64, []uint64, error) {
if len(uids) <= 0 {
return uids, nil, nil
}
result := make([]uint64, 0)
out := make([]uint64, 0)
err := s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
// 1. 去掉非群管理者
roles, _, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return err
}
userIds := make([]uint64, 0)
for _, i := range uids {
if _, ok := roles[i]; ok {
userIds = append(userIds, i)
} else {
out = append(out, i)
model.Log.Infof("GroupSupportList: rule out %d, no role", i)
}
}
// TODO: 去掉非群成员
//(4)1个账户只能做1个群组的管理员(5)1个设备下只允许领取1个管理奖励
_, _, period := group_m.GetLastSupportPeriod(time.Now())
gsa := group_m.GroupSupportAwardMgr{Period: period}
rows, err := gsa.Get(model.Db)
if err != nil {
return err
}
awards := make(map[uint64]struct{}, 0)
for _, i := range rows {
awards[i.UserId] = struct{}{}
}
uids = userIds
userIds = make([]uint64, 0)
m := make(map[uint64]uint64)
for _, u := range uids {
m, err := user_m.GetSameImeiMap(model, u)
if err != nil {
return err
}
passed := true
for _, i := range m {
if _, ok := awards[i]; ok {
if i == u {
passed = false
model.Log.Infof("GroupSupportList: rule out %d, already awarded", i)
} else {
passed = false
model.Log.Infof("GroupSupportList: rule out %d, imei awarded", i)
}
}
}
if passed == true {
userIds = append(userIds, u)
} else {
out = append(out, u)
}
}
model.Log.Infof("GroupSupportList: uids %v, map %v", uids, m)
_, supportLevel, err := s.GetSupportLevel(groupId)
if err != nil {
return err
}
if uint32(len(userIds)) > supportLevel {
model.Log.Infof("GroupSupportList: rule out %v, limit exeeded", userIds[supportLevel:])
out = append(out, userIds[supportLevel:]...)
userIds = userIds[0:supportLevel]
}
result = userIds
return nil
})
if err == nil {
return result, out, nil
} else {
return nil, nil, err
}
}
func (s *GroupService) GetSupportLevel(groupId string) (uint64, uint32, error) {
model := domain.CreateModel(s.svc.CtxAndDb)
beginTime, endTime, _ := group_m.GetLastSupportPeriod(time.Now())
g := gift_m.GiftOperate{SceneType: gift_e.GroupSceneType, SceneUid: groupId, Model: model}
count, consume, err := g.GetConsumeByRange(beginTime, endTime)
if err != nil {
return 0, 0, err
}
rec, err := res_m.GetResGroupSupportBy(model, count, consume)
if err != nil {
return 0, 0, err
}
if rec != nil {
return rec.ID, rec.MgrNum, nil
}
return 0, 0, nil
}
//群组支持奖励
func (s *GroupService) GroupSupportAward(groupId string, profitAllocator uint64, userIds []uint64, resId uint64, period string) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
//
groupInfo, err := group_m.GetGroupInfo(model, groupId)
if groupInfo == nil {
return bizerr.GroupNotFound
}
//发放奖励
groupSupportAwardAdmin, groupSupportAwardMgrs, err := group_m.AddGroupSupportAward(model, groupId, profitAllocator, resId, userIds, period)
if err != nil {
return err
}
if err := groupSupportAwardAdmin.Persistent(); err != nil {
return err
}
groupSupportEvent := group_ev.InitGroupSupportEvent(len(groupSupportAwardMgrs), groupInfo.Code)
//数据持久化
groupSupportEvent.AddAdmin(groupSupportAwardAdmin.ID, groupSupportAwardAdmin.UserId, groupSupportAwardAdmin.DiamondNum)
for i, _ := range groupSupportAwardMgrs {
if err := groupSupportAwardMgrs[i].Persistent(); err != nil {
return err
}
groupSupportEvent.AddMgr(groupSupportAwardMgrs[i].ID, groupSupportAwardMgrs[i].UserId, groupSupportAwardMgrs[i].DiamondNum)
}
return group_ev.PublishGroupSupport(model, groupSupportEvent)
})
}
func (s *GroupService) RenewGroupSupporter(groupId string, userIds []uint64) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
gs := group_m.GroupSupporter{GroupId: groupId}
if err := gs.Delete(model.Db); err != nil {
return err
}
if len(userIds) > 0 {
gs = group_m.GroupSupporter{GroupId: groupId}
if err := gs.BatchSave(model.Db, userIds); err != nil {
return err
}
}
return nil
})
}
...@@ -46,3 +46,15 @@ func SendSignalMsg(model *domain.Model, groupId string, msg group_m.GroupSystemM ...@@ -46,3 +46,15 @@ func SendSignalMsg(model *domain.Model, groupId string, msg group_m.GroupSystemM
model.Log.Errorf("Marshall failure, msgId = %d : %s", msg.MsgId, err.Error()) model.Log.Errorf("Marshall failure, msgId = %d : %s", msg.MsgId, err.Error())
} }
} }
func SendCustomMsg(model *domain.Model, groupId string, fromAccount *string, content string) (uint, error) {
groupId, err := group_m.ToTxGroupId(model, groupId)
if err != nil {
return 0, err
}
hiloUserInfo := ""
if fromAccount != nil {
hiloUserInfo = group_m.GetHiloUserInfo(model, *fromAccount)
}
return tencentyun.SendCustomMsg(model.Log, groupId, fromAccount, content, hiloUserInfo)
}
...@@ -83,6 +83,7 @@ require ( ...@@ -83,6 +83,7 @@ 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/spf13/cast v1.5.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
......
...@@ -294,6 +294,8 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM ...@@ -294,6 +294,8 @@ github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
......
...@@ -10,8 +10,12 @@ var ( ...@@ -10,8 +10,12 @@ var (
ExternalIdNoExist = myerr.NewBusinessCode(1003, "externalId no exist", myerr.BusinessData{}) ExternalIdNoExist = myerr.NewBusinessCode(1003, "externalId no exist", myerr.BusinessData{})
CodeNoExist = myerr.NewBusinessCode(1005, "code no exist", myerr.BusinessData{}) CodeNoExist = myerr.NewBusinessCode(1005, "code no exist", myerr.BusinessData{})
ParaMissing = myerr.NewBusinessCode(1006, "parameter missing", myerr.BusinessData{}) ParaMissing = myerr.NewBusinessCode(1006, "parameter missing", myerr.BusinessData{})
EmptyContent = myerr.NewBusinessCode(1007, "Content is empty", myerr.BusinessData{})
ContentTooLong = myerr.NewBusinessCode(1008, "Content is too long", myerr.BusinessData{})
InvalidParameter = myerr.NewBusinessCode(1009, "Invalid parameter", myerr.BusinessData{}) InvalidParameter = myerr.NewBusinessCode(1009, "Invalid parameter", myerr.BusinessData{})
NotQualified = myerr.NewBusinessCode(1010, "Not qualified", myerr.BusinessData{})
IncorrectState = myerr.NewBusinessCode(1013, "Incorrect state", myerr.BusinessData{}) IncorrectState = myerr.NewBusinessCode(1013, "Incorrect state", myerr.BusinessData{})
UpgradeRequired = myerr.NewBusinessCode(1015, "Version too old. Upgrade is required", myerr.BusinessData{})
TransactionFailed = myerr.NewBusinessCode(1014, "Transaction failed", myerr.BusinessData{}) TransactionFailed = myerr.NewBusinessCode(1014, "Transaction failed", myerr.BusinessData{})
ImagePolicyViolation = myerr.NewBusinessCode(1017, "image policy violation", myerr.BusinessData{}) ImagePolicyViolation = myerr.NewBusinessCode(1017, "image policy violation", myerr.BusinessData{})
ReqTooFrequent = myerr.NewBusinessCode(1018, "Requests are too frequent", myerr.BusinessData{}) ReqTooFrequent = myerr.NewBusinessCode(1018, "Requests are too frequent", myerr.BusinessData{})
...@@ -42,11 +46,23 @@ var ( ...@@ -42,11 +46,23 @@ var (
// 群组 // 群组
GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群 GroupNotFound = myerr.NewBusinessCode(14001, "Group not found", myerr.BusinessData{}) // 找不到该群
NotGroupMember = myerr.NewBusinessCode(14002, "Not a group member", myerr.BusinessData{}) // 不是群成员
NoPrivileges = myerr.NewBusinessCode(14004, "Not enough permission", myerr.BusinessData{}) // 操作权限不够 NoPrivileges = myerr.NewBusinessCode(14004, "Not enough permission", myerr.BusinessData{}) // 操作权限不够
InBlacklist = myerr.NewBusinessCode(14005, "Can not join the group due to blacklist", myerr.BusinessData{}) // 在群黑名单中,不能进群
OwnerCannotLeave = myerr.NewBusinessCode(14008, "Owner can not leave the group", myerr.BusinessData{}) // 群主不能退群
WrongPasswordLength = myerr.NewBusinessCode(14010, "Incorrect password length", myerr.BusinessData{}) // 密码长度错误 WrongPasswordLength = myerr.NewBusinessCode(14010, "Incorrect password length", myerr.BusinessData{}) // 密码长度错误
GroupIsBanned = myerr.NewBusinessCode(14011, "group is banned by ", myerr.BusinessData{}) // 群已经被管理员封禁 GroupIsBanned = myerr.NewBusinessCode(14011, "group is banned by ", myerr.BusinessData{}) // 群已经被管理员封禁
GroupLimitReached = myerr.NewBusinessCode(14012, "Join group limit reached", myerr.BusinessData{}) // 所在群已达上限
RoleLimitReached = myerr.NewBusinessCode(14013, "Role limit reached", myerr.BusinessData{}) // 所任角色已达上限
GroupCreateLimitReached = myerr.NewBusinessCode(14014, "Create group limit reached", myerr.BusinessData{}) // 你创建的群组数已达上限 GroupCreateLimitReached = myerr.NewBusinessCode(14014, "Create group limit reached", myerr.BusinessData{}) // 你创建的群组数已达上限
GroupLimitReachedVip = myerr.NewBusinessCode(14015, "Join group limit reached. Please purchase VIP", myerr.BusinessData{}) // 所在群已达上限,请购买VIP
GroupAlreadyAwarded = myerr.NewBusinessCode(14016, "Group support awarded", myerr.BusinessData{}) // 群支持奖励已经发放过了
NotManagerOrAdmin = myerr.NewBusinessCode(14017, "Not manager or group admin", myerr.BusinessData{}) // 不是经理或管理员
UserAlreadyAwarded = myerr.NewBusinessCode(14018, "User already awarded", myerr.BusinessData{}) // 用户的群支持奖励已经发放过了
ImeiAlreadyAwarded = myerr.NewBusinessCode(14019, "Imei support awarded", myerr.BusinessData{}) // 设备的群支持奖励已经发放过了
GroupCustomThemeLimit = myerr.NewBusinessCode(14020, "Group Custom Theme Limit", myerr.BusinessData{}) //群主题定制数量只能是5个 GroupCustomThemeLimit = myerr.NewBusinessCode(14020, "Group Custom Theme Limit", myerr.BusinessData{}) //群主题定制数量只能是5个
GroupSupportIpLimit = myerr.NewBusinessCode(14024, "ID:%v is a duplicate account, please select another user to receive the reward", myerr.BusinessData{}) // 群组扶持ip限制
GroupNoPowerToSvip6 = myerr.NewBusinessCode(14026, "Cannot use this permission for SVIP6", myerr.BusinessData{}) // 踢出,无法对SVIP6使用此权限
// 家族 // 家族
GroupPowerHasJoinOther = myerr.NewBusinessCode(15001, "You already have joined power, please exit first", myerr.BusinessData{}) // 已经加入了其它国家势力 GroupPowerHasJoinOther = myerr.NewBusinessCode(15001, "You already have joined power, please exit first", myerr.BusinessData{}) // 已经加入了其它国家势力
...@@ -61,4 +77,7 @@ var ( ...@@ -61,4 +77,7 @@ var (
// 超级管理人 // 超级管理人
OfficialStaffLimit = myerr.NewBusinessCode(22001, "Operation failed", myerr.BusinessData{}) OfficialStaffLimit = myerr.NewBusinessCode(22001, "Operation failed", myerr.BusinessData{})
GamingCannotKick = myerr.NewBusinessCode(27050, "The game has already started and the user cannot be kicked out", myerr.BusinessData{}) // 游戏已经开始,不能踢出用户
) )
...@@ -7,7 +7,10 @@ import ( ...@@ -7,7 +7,10 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-group/domain/cache/user_c" "hilo-group/domain/cache/user_c"
"hilo-group/domain/model/res_m" "hilo-group/domain/model/res_m"
"hilo-group/myerr"
"hilo-group/myerr/bizerr" "hilo-group/myerr/bizerr"
"strconv"
"strings"
) )
func GetUserId(c *gin.Context) (mysql.ID, error) { func GetUserId(c *gin.Context) (mysql.ID, error) {
...@@ -107,3 +110,47 @@ func GetUserEx(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string ...@@ -107,3 +110,47 @@ func GetUserEx(c *gin.Context, myContext *mycontext.MyContext) (mysql.ID, string
} }
return 0, "", "", "", "", bizerr.ParaMissing return 0, "", "", "", "", bizerr.ParaMissing
} }
func GetAppImei(c *gin.Context) (string, error) {
imei := c.GetHeader(mycontext.IMEI)
if len(imei) <= 0 {
return "", myerr.WrapErr(bizerr.ParaMissing)
}
return imei, nil
}
func GetRequestIP(c *gin.Context) string {
reqIP := c.ClientIP()
if reqIP == "::1" {
reqIP = "127.0.0.1"
}
return reqIP
}
func GetAppVersion(c *gin.Context) (string, int, int, int, error) {
deviceType := c.GetHeader(mycontext.DEVICETYPE)
if len(deviceType) <= 0 {
return "", 0, 0, 0, bizerr.ParaMissing
}
appVerStr := c.GetHeader(mycontext.APP_VERSION)
if len(appVerStr) <= 0 {
return "", 0, 0, 0, bizerr.ParaMissing
}
s := strings.Split(appVerStr, ".")
if len(s) < 3 {
return "", 0, 0, 0, bizerr.InvalidParameter
}
major, err := strconv.Atoi(s[0])
if err != nil || major < 0 {
return "", 0, 0, 0, bizerr.InvalidParameter
}
minor, err := strconv.Atoi(s[1])
if err != nil || minor < 0 {
return "", 0, 0, 0, bizerr.InvalidParameter
}
min, err := strconv.Atoi(s[2])
if err != nil || min < 0 {
return "", 0, 0, 0, bizerr.InvalidParameter
}
return deviceType, major, minor, min, nil
}
package group_r
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"gorm.io/gorm"
"hilo-group/_const/enum/game_e"
"hilo-group/_const/enum/group_e"
"hilo-group/cv/group_cv"
"hilo-group/cv/group_power_cv"
"hilo-group/cv/medal_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/res_c"
"hilo-group/domain/cache/room_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/mgr_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/model/version_m"
"hilo-group/domain/service/group_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req"
"hilo-group/resp"
"sort"
"strings"
)
// @Tags 群组
// @Summary 查询我创建的群组
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} group_cv.JoinedGroupInfo
// @Router /v1/imGroup/ownGroup [get]
func GetOwnGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupIds, err := group_m.GetGroups(model.Db, userId, group_e.GROUP_OWNER)
if err != nil {
return myContext, err
}
if len(groupIds) <= 0 {
resp.ResponseOk(c, []group_cv.JoinedGroupInfo{})
return myContext, nil
}
myService := domain.CreateService(myContext)
result, _, err := group_cv.BuildJoinedGroupInfo(myService, userId, groupIds, 1, 1)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 查询某人的(公开)群组(新)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param userExternalId path string true "用户ExternalId"
// @Success 200 {object} group_cv.TheirGroupsInfo
// @Router /v1/imGroup/theirGroup/{userExternalId} [get]
func GetTheirGroups(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
externalId := c.Param("userExternalId")
if len(externalId) <= 0 {
return myContext, myerr.NewSysError("userExternalId 为必填项")
}
model := domain.CreateModelContext(myContext)
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
userId := user.ID
if userId == 0 {
return myContext, bizerr.InvalidParameter
}
data, err := group_m.GetJoinedGroups(model.Db, userId)
if err != nil {
return myContext, err
}
result := group_cv.TheirGroupsInfo{Total: 0}
groupIds := make([]string, 0)
for _, i := range data {
groupIds = append(groupIds, i.GroupId)
}
groupInfo, err := group_m.BatchGetGroupInfo(model, groupIds)
if err != nil {
return myContext, err
}
owners := make([]uint64, 0)
for _, i := range groupInfo {
owners = append(owners, i.Owner)
}
theirRoles, err := group_m.GetRolesByUser(model, userId)
if err != nil {
return myContext, err
}
model.Log.Info("GetTheirGroups: theirRoles - ", theirRoles)
powerIds, powerNames, err := group_power_cv.BatchGetGroupPower(model.Db, owners)
if err != nil {
return myContext, err
}
groupMedals, err := group_m.BatchGetMedals(model.Db, groupIds)
if err != nil {
return myContext, err
}
resMedal, err := res_m.MedalGetAllMap(model.Db)
if err != nil {
return myContext, err
}
roomMicUserMap, err := group_m.BatchGetAllMicUser(model, groupIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetTheirGroups: groupIds %v, roomMicUserMap %v", groupIds, roomMicUserMap)
uids := owners
micUsersMap := make(map[string][]uint64, 0)
for _, i := range groupIds {
micUsersMap[i] = make([]uint64, 0)
u := roomMicUserMap[i]
if len(u) >= 4 {
micUsersMap[i] = u[0:4]
} else {
micUsersMap[i] = u
}
uids = append(uids, micUsersMap[i]...)
}
uids = utils.UniqueSliceUInt64(uids)
userTiny, err := user_cv.GetUserTinyMap(uids)
if err != nil {
return myContext, err
}
model.Log.Infof("GetTheirGroups: userTinyMap: %v", userTiny)
roomCount, err := group_m.BatchGetRoomCount(model, groupIds)
if err != nil {
return nil, err
}
onMic, err := group_cv.CheckMicHasUserByGroup(groupIds)
if err != nil {
return myContext, err
}
model.Log.Info("GetTheirGroups: onMic - ", onMic)
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
rr := rocket_m.RocketResult{}
maxStageMap, err := rr.GetMaxStage(mysql.Db, groupIds)
if err != nil {
return myContext, err
}
visitCount, err := group_m.BatchGetRoomVisitCount(model.Log, groupIds)
if err != nil {
return myContext, err
}
roomEnterTime, err := room_c.GetUserRoomVisit(userId)
if err != nil {
return myContext, err
}
model.Log.Infof("BuildJoinedGroupInfo, roomEnterTime: %v", roomEnterTime)
// 正在进行的游戏
games := game_m.GetNotEndGamesMap(model)
for _, i := range data {
gi := groupInfo[i.GroupId]
// 只要公开的群
if len(gi.Password) == 0 {
result.Total++
role := group_e.GROUP_MEMBER
r, exists := theirRoles[i.GroupId]
if exists {
role = r
}
micUsers := make([]user_cv.CvUserTiny, 0)
for _, j := range micUsersMap[i.GroupId] {
micUsers = append(micUsers, userTiny[j])
}
var maxStage *uint16 = nil
if s, ok := maxStageMap[i.GroupId]; ok {
maxStage = &s
}
medals := make([]medal_cv.PicElement, 0)
if m, ok := groupMedals[i.GroupId]; ok {
for _, j := range m {
mId := uint32(j)
if e, ok := resMedal[mId]; ok {
medals = append(medals, medal_cv.PicElement{
PicUrl: e.PicUrl,
})
}
}
}
// 补上房间流水勋章
var pe *medal_cv.PicElement
_, pe, err = medal_cv.GetGroupConsumeMedal(model, i.GroupId)
if err != nil {
model.Log.Infof("GetTheirGroups: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
medals = append(medals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
elem := group_cv.JoinedGroupInfo{
PopularGroupInfo: group_cv.PopularGroupInfo{
GroupInfo: group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: gi.TxGroupId,
Name: gi.Name,
Introduction: gi.Introduction,
Notification: gi.Notification,
FaceUrl: gi.FaceUrl,
Code: gi.Code,
CountryIcon: countryInfo[gi.Country],
SupportLevel: supportLevels[i.GroupId],
GroupInUserDuration: visitCount[i.GroupId],
MicNumType: int(gi.MicNumType),
GroupMedals: medals,
},
//HasOnMic: onMicScore[i.GroupId] != 0,
GroupPowerId: powerIds[gi.Owner],
GroupPowerName: powerNames[gi.Owner],
},
MicUsers: micUsers,
RoomUserCount: uint(roomCount[i.GroupId]),
MaxStage: maxStage,
GameTypes: games[gi.TxGroupId],
},
LastEnterTime: roomEnterTime[i.GroupId],
}
if role == group_e.GROUP_OWNER {
result.OwnGroups = append(result.OwnGroups, elem)
} else {
result.Groups = append(result.Groups, elem)
}
}
}
// fixme: 按最近进入时间?
sort.Slice(result.OwnGroups, func(i, j int) bool {
return result.OwnGroups[i].LastEnterTime > result.OwnGroups[j].LastEnterTime ||
result.OwnGroups[i].LastEnterTime == result.OwnGroups[j].LastEnterTime && result.OwnGroups[i].GroupId < result.OwnGroups[j].GroupId
})
// fixme:按角色排?
sort.Slice(result.Groups, func(i, j int) bool {
return theirRoles[result.Groups[i].GroupId] > theirRoles[result.Groups[j].GroupId] ||
theirRoles[result.Groups[i].GroupId] == theirRoles[result.Groups[j].GroupId] && result.Groups[i].GroupId < result.Groups[j].GroupId
})
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 客户端组件加载完成
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200
// @Router /v1/imGroup/pluginReady/{groupId} [put]
func PluginReady(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
model.Log.Infof("PluginReady user %d, %s", userId, externalId)
/** fixme:这协议没用了?
go func(gi *group_m.GroupInfo) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("PluginReady SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
if err := myService.OnJoinGroup(externalId, groupId); err != nil {
model.Log.Infof("PluginReady, OnJoinGroup err %v", err)
}
}(groupInfo)*/
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 查询房间信息
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} cv.RoomInfo
// @Router /v1/imGroup/roomInfo/{groupId} [get]
func GetRoomInfo(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
groupId = groupInfo.ImGroupId
memberCount, err := group_m.GetMemberCount(model.Db, groupId)
if err != nil {
return myContext, err
}
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
// 版本控制
_deviceType, _ := c.Get(mycontext.DEVICETYPE)
_appVersion, _ := c.Get(mycontext.APP_VERSION)
deviceType, appVersion := cast.ToString(_deviceType), cast.ToString(_appVersion)
vc := version_m.GetVersionControlByPlatform(model, deviceType)
allow, err := utils.CompareVersion(appVersion, fmt.Sprintf("<= %s", vc.AuditVersion))
model.Log.Infof("GetRoomInfo CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v", appVersion, vc.AuditVersion, allow, err)
themeUrl := ""
var themeId uint64 = 0
var themeType uint8 = 1
if groupInfo.ThemeId > 0 {
//官方主题
// 找不到的,默认为空(可能被后台删了)
themeType = 1
themes, _ := res_m.GroupThemeGetAll(model.Db)
for _, i := range themes {
if i.ID == uint64(groupInfo.ThemeId) {
themeUrl = i.Url
themeId = i.ID
break
}
}
} else {
//可能是自定义主题
themeId, themeUrl, err = group_m.GetShowCustomTheme(model, groupInfo.ImGroupId)
if err != nil {
return myContext, err
}
if themeId != 0 {
themeType = 2
}
}
result := group_cv.RoomInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: groupInfo.TxGroupId,
Name: groupInfo.Name,
Introduction: groupInfo.Introduction,
Notification: groupInfo.Notification,
FaceUrl: groupInfo.FaceUrl,
MemberNum: memberCount,
Code: groupInfo.Code,
CountryIcon: countryInfo[groupInfo.Country],
MicNumType: int(groupInfo.MicNumType),
TouristMic: groupInfo.TouristMic,
TouristSendMsg: groupInfo.TouristSendMsg,
TouristSendPic: groupInfo.TouristSendPic,
MemberFee: groupInfo.MemberFee,
},
MicOn: groupInfo.MicOn,
LoadHistory: groupInfo.LoadHistory,
ThemeId: themeId,
ThemeUrl: themeUrl,
ThemeType: themeType,
Role: group_e.GROUP_VISITOR,
GameConfig: &game_m.GameConfig{Ludo: &game_m.GameConfigDiamond{Diamond: game_e.GameLudoDiamondList}, Uno: &game_m.GameConfigDiamond{Diamond: game_e.GameLudoDiamondList}},
}
roles, _, err := group_m.GetRolesInGroup(model, groupInfo.ImGroupId)
if err != nil {
return myContext, err
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
isGroupMember, err := group_m.IsGroupMember(model.Db, groupId, userId)
if err != nil {
return myContext, err
}
if isGroupMember {
result.Role = group_e.GROUP_MEMBER
}
emptyStr := ""
if len(groupInfo.Password) > 0 {
// 代表有密码
result.Password = &emptyStr
}
//userIds := make([]uint64, 0)
for u, r := range roles {
//userIds = append(userIds, u)
if u == userId {
if r == group_e.GROUP_OWNER || r == group_e.GROUP_MANAGER {
// 如果用户是OW或经理,可以看到密码,同时设置角色
result.Role = r
if len(groupInfo.Password) > 0 {
result.Password = &groupInfo.Password
}
} else if r == group_e.GROUP_ADMIN {
// 如果用户是管理员,仅设置角色
result.Role = r
}
}
}
roles, orderList, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
users, err := user_cv.GetUserTinyMap(orderList)
if err != nil {
return myContext, err
}
for _, i := range orderList {
result.RoleMembers = append(result.RoleMembers, group_cv.SimpleRoleInfo{
ExternalId: users[i].ExternalId,
Role: roles[i],
})
}
// ---- 以下部分相对没那么重要,失败也不返回 ----
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
model.Log.Infof("GetRoomInfo: GetWeekMaxSupportLevelMap: %s", err.Error())
}
result.SupportLevel = supportLevels[groupId]
result.DiceNum = group_e.GROUP_DICE_NUM_DEFAULT
result.DiceType = 1 // 1: [0-9] 2:[1-6]
gs := group_m.GroupSetting{GroupId: groupId}
err = gs.Get(model.Db)
if err == nil {
result.DiceNum = gs.DiceNum
result.DiceType = gs.DiceType
} else if err != gorm.ErrRecordNotFound {
model.Log.Infof("GetRoomInfo: GroupSetting: %s", err.Error())
}
result.WelcomeText, _, _, err = group_s.NewGroupService(myContext).GetWelcomeText(groupInfo)
if err != nil {
return myContext, err
}
result.WelcomeText = strings.ReplaceAll(result.WelcomeText, "@%s", "")
// 补上房间流水勋章
var pe *medal_cv.PicElement
result.TotalConsume, pe, err = medal_cv.GetGroupConsumeMedal(model, groupId)
if err != nil {
model.Log.Infof("GetRoomInfo: GetGroupConsumeMedal: %s", err.Error())
} else if pe != nil {
result.GroupMedals = append(result.GroupMedals, medal_cv.PicElement{PicUrl: pe.PicUrl})
}
resMedals := []res_m.ResMedal{}
err = mysql.Db.Model(&res_m.ResMedal{}).
Joins("INNER JOIN group_medal m ON m.res_medal_id = res_medal.id").
Where("m.im_group_id = ?", groupId).
Order("m.id desc").
Find(&resMedals).Error
if err == nil {
for _, r := range resMedals {
result.GroupMedals = append(result.GroupMedals, medal_cv.PicElement{
PicUrl: r.PicUrl,
SvgaUrl: r.SvgaUrl,
})
}
} else {
model.Log.Infof("GetRoomInfo: group_medal: %s", err.Error())
}
// 获取国家信息
country, area, err := user_m.GetUserCountryArea(model, userId)
if err != nil {
model.Log.Errorf("GetRoomInfo 获取国家资源错误 userId:%d, err:%v", userId, err)
return myContext, err
}
rb := mgr_m.RoomBanner{Status: mysql.YES}
rows, err := rb.GetRoomBanners(model.Db, allow)
if err == nil {
for _, i := range rows {
// 是否在banner设定区域内
if (i.Area == 1 || i.Area == 2) && area != i.Area { // 不在区域内
continue
}
if i.Area == 3 && !utils.IsInStringList(country, i.CountryList) {
continue
}
result.Banners = append(result.Banners, group_cv.BannerElement{
H5Url: i.Url,
BannerUrl: i.Image,
})
}
} else {
model.Log.Infof("GetRoomInfo: GetRoomBanners: %s", err.Error())
}
result.LuckyWheel, err = group_cv.GetLuckWheelState(model, groupId)
if err != nil {
model.Log.Infof("GetRoomInfo: GetLuckWheelState: %s", err.Error())
}
// 群主的详情
result.Owner, err = user_cv.GetUserDetail(model, groupInfo.Owner, userId)
if err != nil {
model.Log.Errorf("GetRoomInfo: GetUserBase: %s", err.Error())
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 查询群管理角色(经理、管理)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} group_cv.MemberDetail
// @Router /v1/imGroup/admin/{groupId} [get]
func GetGroupAdmin(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
roles, orderList, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
userIds := make([]uint64, 0)
for _, i := range orderList {
if roles[i] == group_e.GROUP_MANAGER || roles[i] == group_e.GROUP_ADMIN {
userIds = append(userIds, i)
}
}
result := make([]group_cv.MemberDetail, 0)
if len(userIds) > 0 {
users, err := user_cv.BatchGetUserExtend(model, userIds, myUserId)
if err != nil {
return myContext, err
}
for _, i := range userIds {
result = append(result, group_cv.MemberDetail{
CvUserExtend: users[i],
Role: roles[i],
})
}
}
resp.ResponseOk(c, result)
return myContext, nil
}
...@@ -4,9 +4,12 @@ import ( ...@@ -4,9 +4,12 @@ import (
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"git.hilo.cn/hilo-common/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"hilo-group/_const/enum/gift_e" "hilo-group/_const/enum/gift_e"
"hilo-group/_const/enum/group_e" "hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/online_e"
"hilo-group/cv/gift_cv" "hilo-group/cv/gift_cv"
"hilo-group/cv/group_cv" "hilo-group/cv/group_cv"
"hilo-group/cv/group_power_cv" "hilo-group/cv/group_power_cv"
...@@ -15,9 +18,14 @@ import ( ...@@ -15,9 +18,14 @@ import (
"hilo-group/domain/cache/res_c" "hilo-group/domain/cache/res_c"
"hilo-group/domain/model/game_m" "hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m" "hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m" "hilo-group/domain/model/res_m"
"hilo-group/domain/model/rocket_m" "hilo-group/domain/model/rocket_m"
"hilo-group/domain/model/tim_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_s" "hilo-group/domain/service/group_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req" "hilo-group/req"
"hilo-group/resp" "hilo-group/resp"
"sort" "sort"
...@@ -621,3 +629,515 @@ func GetRecommendGroup(c *gin.Context) (*mycontext.MyContext, error) { ...@@ -621,3 +629,515 @@ func GetRecommendGroup(c *gin.Context) (*mycontext.MyContext, error) {
resp.ResponseOk(c, result) resp.ResponseOk(c, result)
return myContext, nil return myContext, nil
} }
// @Tags 群组
// @Summary 获取最近访问的房间
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Success 200 {object} group_cv.JoinedGroupInfo
// @Router /v1/imGroup/myRecent [get]
func GetRecentGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
uer := group_m.UserEnterRoom{UserId: userId}
rec, err := uer.Find(model.Db)
if err != nil {
return myContext, err
}
myGroups, err := group_m.FindGroupMapByOwner(model, userId)
if err != nil {
return myContext, err
}
// 剔除自己创建的群
groupIds := make([]string, 0)
for _, i := range rec {
if _, ok := myGroups[i.GroupId]; !ok {
groupIds = append(groupIds, i.GroupId)
}
}
myService := domain.CreateService(myContext)
result, _, err := group_cv.BuildJoinedGroupInfo(myService, userId, groupIds, 30, 1)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 获取我成为永久会员的群
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} group_cv.JoinedGroupInfo
// @Router /v1/imGroup/myPermanent [get]
func GetMyGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
rec, err := group_m.GetJoinedGroups(model.Db, userId)
if err != nil {
return myContext, err
}
myGroups, err := group_m.FindGroupMapByOwner(model, userId)
if err != nil {
return myContext, err
}
// 剔除自己创建的群
groupIds := make([]string, 0)
for _, i := range rec {
if _, ok := myGroups[i.GroupId]; !ok {
groupIds = append(groupIds, i.GroupId)
}
}
myService := domain.CreateService(myContext)
result, _, err := group_cv.BuildJoinedGroupInfo(myService, userId, groupIds, pageSize, pageIndex)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 最近访问列表
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} GroupMembersRsp
// @Router /v1/imGroup/visitors/{groupId} [get]
func GetGroupVisitors(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.ParaMissing
}
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
uer := group_m.UserEnterRoom{GroupId: groupId}
rows, err := uer.Find(model.Db)
if err != nil {
return myContext, err
}
now := time.Now()
t := now.AddDate(0, 0, -15) // 只要15天内进入房间的人
userIds := make([]uint64, 0)
for _, i := range rows {
if i.EnterTime.After(t) {
userIds = append(userIds, i.UserId)
}
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupVisitors %s: memberNum = %d, user size = %d", groupId, len(rows), len(userIds))
result := GroupMembersRsp{Total: uint(len(userIds))}
beginPos := pageSize * (pageIndex - 1)
if uint(beginPos) < result.Total {
// 取在线状态
extIds := make([]string, 0)
for _, i := range users {
extIds = append(extIds, i.ExternalId)
}
statusMap, err := tim_m.GetOnlineStatus(model, extIds)
if err != nil {
return myContext, err
}
result.Online = 0
for _, v := range statusMap {
if v == online_e.IM_STATUS_ON_LINE {
result.Online++
}
}
model.Log.Infof("GetGroupVisitors %s: statusMap size = %d, onLine = %d", groupId, len(statusMap), result.Online)
roles, _, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
nobleLevels, err := noble_m.BatchGetNobleLevel(model.Db, userIds)
if err != nil {
return myContext, err
}
svipLevels, err := rpc.MGetUserSvipLevel(model, userIds)
if err != nil {
return myContext, err
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupVisitors %s, users %v, roles: %v, nobles: %v, vips: %v", groupId, userIds, roles, nobleLevels, vips)
roomUsers, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return myContext, err
}
roomUserMap := utils.SliceToMapUInt64(roomUsers)
//model.Log.Infof("GetGroupMembers %s, roomStatusMap %v", groupId, roomStatusMap)
// 排序规则 :在房间的优先,其次是在线,再次看角色,最后看贵族
sort.Slice(userIds, func(i, j int) bool {
ui := userIds[i]
uj := userIds[j]
_, ok1 := roomUserMap[ui]
_, ok2 := roomUserMap[uj]
if ok1 && !ok2 {
return true
} else if ok1 == ok2 {
ei := users[ui].ExternalId
ej := users[uj].ExternalId
if statusMap[ei] > statusMap[ej] {
return true
}
if statusMap[ei] == statusMap[ej] {
if roles[ui] > roles[uj] {
return true
}
if roles[ui] == roles[uj] {
// SVIP>贵族5>贵族4>贵族3>贵族2>VIP
if svipLevels[ui] > svipLevels[uj] {
return true
} else if svipLevels[ui] == svipLevels[uj] {
if nobleLevels[ui] > nobleLevels[uj] && nobleLevels[ui] >= 2 {
return true
}
if nobleLevels[ui] == nobleLevels[uj] || nobleLevels[ui] < 2 && nobleLevels[uj] < 2 {
if vips[ui] != nil {
if vips[uj] == nil {
return true
} else {
return users[ui].Code < users[uj].Code
}
} else if vips[uj] == nil {
return users[ui].Code < users[uj].Code
}
}
}
}
}
}
return false
})
model.Log.Infof("GetGroupVisitors %s, sorted users: %v", groupId, userIds)
endPos := pageSize * pageIndex
if endPos > len(userIds) {
endPos = len(userIds)
}
userIds = userIds[beginPos:endPos]
userExtends, err := user_cv.BatchGetUserExtend(model, userIds, userId)
if err != nil {
return myContext, err
}
for _, u := range userIds {
inRoom := false
if _, ok := roomUserMap[u]; ok {
inRoom = true
}
result.Members = append(result.Members, group_cv.MemberDetail{
CvUserExtend: userExtends[u],
Role: roles[u],
OnlineStatus: statusMap[users[u].ExternalId],
InRoom: inRoom,
})
}
}
resp.ResponseOk(c, result)
return myContext, nil
}
type OwnPublicGroupRsp struct {
Total uint `json:"total"`
MyGroups []group_cv.GroupDetail `json:"myGroups"`
}
// @Tags 群组
// @Summary 查询某人创建的(公开)群组
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param userExternalId path string true "用户ExternalID"
// @Success 200 {object} OwnPublicGroupRsp
// @Router /v1/imGroup/ownPublicGroup/{userExternalId} [get]
func GetOwnPublicGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
externalId := c.Param("userExternalId")
if len(externalId) <= 0 {
return myContext, myerr.NewSysError("userExternalId 为必填项")
}
model := domain.CreateModelContext(myContext)
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
if utils.IfLogout(user.LogoutTime) {
resp.ResponseOk(c, OwnPublicGroupRsp{Total: 0})
return myContext, nil
}
theirRoles, err := group_m.GetRolesByUser(model, user.ID)
if err != nil {
return myContext, err
}
model.Log.Info("GetOwnPublicGroup: theirRoles - ", theirRoles)
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
permanentGroups, err := group_m.GetJoinedGroups(model.Db, user.ID)
if err != nil {
return myContext, err
}
groups, err := group_m.FindGroupMapByOwner(model, user.ID)
if err != nil {
return myContext, err
}
result := OwnPublicGroupRsp{Total: uint(len(permanentGroups) + len(groups))}
groupId := ""
for i, j := range groups {
// 只要公开的群
if len(j.Password) == 0 {
if r, ok := theirRoles[j.ImGroupId]; ok && r == group_e.GROUP_OWNER {
// fixme:如果有多个群则展示群人数最多的群组
groupId = i
break
}
}
}
if len(groupId) > 0 {
groupInfo := groups[groupId]
roleMembers, myRole, err := buildRoleMembers(model, groupId, user.ID)
if err != nil {
return myContext, err
}
// 截取前N个
endPos := group_e.GROUP_ROLE_PERSONAL_VIEW_LIMIT
if endPos > len(roleMembers) {
endPos = len(roleMembers)
}
// 找不到的,默认为空(可能被后台删了)
themeUrl := ""
var themeId uint64 = 0
var themeType uint8 = 1
if groupInfo.ThemeId > 0 {
//官方主题
// 找不到的,默认为空(可能被后台删了)
themeType = 1
themes, _ := res_m.GroupThemeGetAll(model.Db)
for _, i := range themes {
if i.ID == uint64(groupInfo.ThemeId) {
themeUrl = i.Url
themeId = i.ID
break
}
}
} else {
//可能是自定义主题
themeId, themeUrl, err = group_m.GetShowCustomTheme(model, groupInfo.ImGroupId)
if err != nil {
return myContext, err
}
if themeId != 0 {
themeType = 2
}
}
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
mem, err := group_m.GetMembers(model.Db, groupId)
if err != nil {
return myContext, err
}
result.MyGroups = append(result.MyGroups, group_cv.GroupDetail{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: groupInfo.TxGroupId,
Name: groupInfo.Name,
Introduction: groupInfo.Introduction,
Notification: groupInfo.Notification,
FaceUrl: groupInfo.FaceUrl,
Code: groupInfo.Code,
MemberNum: uint(len(mem)),
CountryIcon: countryInfo[groupInfo.Country],
SupportLevel: supportLevels[groupId],
MicNumType: int(groupInfo.MicNumType),
},
MicOn: groupInfo.MicOn,
LoadHistory: groupInfo.LoadHistory,
ThemeId: themeId,
ThemeUrl: themeUrl,
ThemeType: themeType,
Role: myRole,
RoleMembers: roleMembers[0:endPos],
})
}
resp.ResponseOk(c, result)
return myContext, nil
}
func buildRoleMembers(model *domain.Model, groupId string, userId uint64) ([]group_cv.RoleMemberInfo, group_e.GroupRoleType, error) {
myRole := group_e.GROUP_VISITOR
roles, _, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return nil, myRole, err
}
model.Log.Infof("buildRoleMembers: roles - %s, %v", groupId, roles)
userIds := make([]uint64, 0)
for u, r := range roles {
userIds = append(userIds, u)
if u == userId {
myRole = r
}
}
users, err := user_cv.GetUserTinyMap(userIds)
if err != nil {
return nil, myRole, err
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return nil, myRole, err
}
extIds := make([]string, 0)
for _, i := range users {
extIds = append(extIds, i.ExternalId)
}
status, err := tim_m.GetOnlineStatus(model, extIds)
if err != nil {
return nil, myRole, err
}
superManagerMap, err := user_m.GetSuperManagerMap(userIds)
if err != nil {
return nil, myRole, err
}
roleMembers := make([]group_cv.RoleMemberInfo, 0)
for u, _ := range users {
m := users[u]
roleMembers = append(roleMembers, group_cv.RoleMemberInfo{
CvUserBase: user_cv.CvUserBase{
Avatar: &m.Avatar,
ExternalId: &m.ExternalId,
Nick: &m.Nick,
Sex: &m.Sex,
Country: &m.CountryIcon,
CountryIcon: &m.CountryIcon,
Code: &m.Code,
IsPrettyCode: m.IsPrettyCode,
IsVip: vips[m.Id] != nil,
IsOfficialStaff: superManagerMap[m.Id],
VipExpireTime: vips[m.Id],
},
Role: roles[u],
OnlineStatus: status[m.ExternalId],
})
}
sort.SliceStable(roleMembers, func(i, j int) bool {
if roleMembers[i].Role > roleMembers[j].Role {
return true
} else if roleMembers[i].Role == roleMembers[j].Role {
if roleMembers[i].OnlineStatus > roleMembers[j].OnlineStatus {
return true
} else if roleMembers[i].OnlineStatus == roleMembers[j].OnlineStatus && *roleMembers[i].Code > *roleMembers[j].Code {
return true
}
}
return false
})
return roleMembers, myRole, nil
}
...@@ -4,7 +4,9 @@ import ( ...@@ -4,7 +4,9 @@ import (
"encoding/json" "encoding/json"
"git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config" "git.hilo.cn/hilo-common/resource/config"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli" "git.hilo.cn/hilo-common/resource/redisCli"
"git.hilo.cn/hilo-common/sdk/agora" "git.hilo.cn/hilo-common/sdk/agora"
"git.hilo.cn/hilo-common/sdk/aws" "git.hilo.cn/hilo-common/sdk/aws"
...@@ -16,6 +18,8 @@ import ( ...@@ -16,6 +18,8 @@ import (
"hilo-group/_const/enum/diamond_e" "hilo-group/_const/enum/diamond_e"
"hilo-group/_const/enum/group_e" "hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/msg_e" "hilo-group/_const/enum/msg_e"
"hilo-group/_const/enum/online_e"
"hilo-group/_const/enum/user_e"
"hilo-group/_const/redis_key/group_k" "hilo-group/_const/redis_key/group_k"
"hilo-group/cv/billboard_cv" "hilo-group/cv/billboard_cv"
"hilo-group/cv/gift_cv" "hilo-group/cv/gift_cv"
...@@ -25,7 +29,9 @@ import ( ...@@ -25,7 +29,9 @@ import (
"hilo-group/domain/cache/res_c" "hilo-group/domain/cache/res_c"
"hilo-group/domain/model/diamond_m" "hilo-group/domain/model/diamond_m"
"hilo-group/domain/model/group_m" "hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m" "hilo-group/domain/model/res_m"
"hilo-group/domain/model/tim_m"
"hilo-group/domain/model/user_m" "hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_s" "hilo-group/domain/service/group_s"
"hilo-group/domain/service/signal_s" "hilo-group/domain/service/signal_s"
...@@ -33,6 +39,8 @@ import ( ...@@ -33,6 +39,8 @@ import (
"hilo-group/myerr/bizerr" "hilo-group/myerr/bizerr"
"hilo-group/req" "hilo-group/req"
"hilo-group/resp" "hilo-group/resp"
"math"
"runtime/debug"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
...@@ -825,3 +833,652 @@ func ModifyGroupInfo(c *gin.Context) (*mycontext.MyContext, error) { ...@@ -825,3 +833,652 @@ func ModifyGroupInfo(c *gin.Context) (*mycontext.MyContext, error) {
resp.ResponseOk(c, nil) resp.ResponseOk(c, nil)
return myContext, nil return myContext, nil
} }
// @Tags 群组
// @Summary 搜索群
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param code path string true "群CODE"
// @Success 200 {object} []group_cv.GroupInfo
// @Router /v1/imGroup/search/{code} [get]
func SearchGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
code := c.Param("code")
if len(code) <= 0 {
return myContext, myerr.NewSysError("code 为必填项")
}
model := domain.CreateModelContext(myContext)
result := make([]group_cv.GroupInfo, 0)
total := 0
g, err := group_m.GetGroupByCode(model, code)
if err != nil {
return myContext, err
}
if g != nil {
owner, err := user_m.GetUser(model, g.Owner)
if err != nil {
return myContext, err
}
if owner.Status == user_e.UserStatusFrozen {
if flag, _ := user_m.IsSuperManager(model, myUserId); !flag {
// 被封锁的用户,除了超管账户,其它用户搜索他的群组和个人ID,搜索结果为空
resp.ResponsePageOk(c, result, uint(total), 1)
return myContext, nil
}
}
supportLevels, err := group_s.NewGroupService(myContext).GetWeekMaxSupportLevelMap()
if err != nil {
return myContext, err
}
// 允许多个结果,虽然目前只有一个群
groupIds := []string{g.ImGroupId}
groupInfo := map[string]group_m.GroupInfo{g.ImGroupId: *g}
if len(groupIds) > 0 {
countryInfo, err := res_c.GetCountryIconMap(model)
if err != nil {
return myContext, err
}
for _, i := range groupIds {
var password *string = nil
if len(groupInfo[i].Password) > 0 && groupInfo[i].Owner != myUserId {
emptyStr := ""
password = &emptyStr
}
memberCount, err := group_m.GetMemberCount(model.Db, i)
if err != nil {
return myContext, err
}
result = append(result, group_cv.GroupInfo{
GroupBasicInfo: group_cv.GroupBasicInfo{
GroupId: groupInfo[i].TxGroupId,
Name: groupInfo[i].Name,
Introduction: groupInfo[i].Introduction,
Notification: groupInfo[i].Notification,
FaceUrl: groupInfo[i].FaceUrl,
//Owner_Account: i.Owner_Account,
MemberNum: memberCount,
Code: groupInfo[i].Code,
CountryIcon: countryInfo[groupInfo[i].Country],
Password: password,
SupportLevel: supportLevels[i],
MicNumType: int(groupInfo[i].MicNumType),
},
})
}
}
}
resp.ResponsePageOk(c, result, uint(total), 1)
return myContext, nil
}
// @Tags 群组
// @Summary 离开群组(obsolete)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} uint
// @Router /v1/imGroup/member/{groupId} [delete]
func LeaveGroup(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
if userId == groupInfo.Owner {
return myContext, bizerr.OwnerCannotLeave
}
if err = group_s.NewGroupService(myContext).LeaveGroup(model, groupId, userId, externalId); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 成为永久成员
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param isInvite formData int false "是否群邀请0否1是"
// @Success 200 {object} uint "结果:1 为新加入成功;2 为已经是群成员"
// @Router /v1/imGroup/permanent/{groupId} [put]
func AddPermanentMember(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
isInvite, err := strconv.Atoi(c.PostForm("isInvite"))
if err != nil {
isInvite = 0
}
userId, externalId, _, nick, avatar, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
ip := req.GetRequestIP(c)
imei, err := req.GetAppImei(c)
if err != nil {
imei, err = user_m.GetUserImeiStr(model, userId)
if err != nil {
return myContext, err
}
}
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
// 群是否被封禁
banned := group_m.GroupBanned{ImGroupId: groupId}
if err = banned.Get(model); err != gorm.ErrRecordNotFound {
return myContext, bizerr.GroupIsBanned
}
// 已经成员的,直接返回
rec, err := group_m.GetJoinedGroups(model.Db, userId)
if err != nil {
return myContext, err
}
for _, i := range rec {
if i.GroupId == groupId {
resp.ResponseOk(c, group_e.ADD_GROUP_DUPLICATE)
return myContext, nil
}
}
// 用户是否在群的黑名单中
if group_m.InGroupBlackList(model, groupId, imei, ip, userId) {
return myContext, bizerr.InBlacklist
}
// 检查所在群数是不是已达上限
maxJoin, err := group_s.NewGroupService(myContext).GetJoinGroupLimit(userId)
if err != nil {
return myContext, err
}
isVip, _, err := user_m.IsVip(userId)
if err != nil {
return myContext, err
}
if uint(len(rec)) >= maxJoin {
if isVip {
return myContext, bizerr.GroupLimitReached
} else {
return myContext, bizerr.GroupLimitReachedVip
}
}
// 不在房间内的不能成为永久成员
userIds, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return myContext, err
}
inRoom := false
for _, u := range userIds {
if u == userId {
inRoom = true
break
}
}
if !inRoom {
if !config.AppIsLocal() {
return myContext, bizerr.IncorrectState
}
}
// 加入群组是否需要收费
needCost, err := AddPermanentMemberCost(c, myContext, isInvite, userId, groupId)
if err != nil {
return myContext, err
}
gm := group_m.GroupMember{
GroupId: groupId,
UserId: userId,
}
if err = gm.Create(model.Db); err != nil {
return myContext, err
}
// 新进群的公屏消息
if nobleLevel, err := noble_m.GetNobleLevel(model.Db, userId); err == nil {
msg := group_m.CommonPublicMsg{Type: group_e.UserJoinPublicScreenMsg,
ExternalId: externalId, Nick: nick, Avatar: avatar, IsVip: isVip, NobleLevel: nobleLevel}
buf, err := json.Marshal(msg)
if err == nil {
go func(groupId, text string) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("SendCustomMsg SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
signal_s.SendCustomMsg(domain.CreateModelContext(model.MyContext), groupId, nil, text)
}(groupId, string(buf))
}
}
// fixme: 这些缓存还需要吗?
group_c.ClearGroupMemberCount(groupId)
group_c.AddGroupMember(model, groupId, externalId)
if isInvite == 1 && !needCost { // 已经接受了进群邀请
group_m.AcceptGroupInviteJoin(model, userId, groupId)
}
resp.ResponseOk(c, group_e.ADD_GROUP_DONE)
return myContext, nil
}
// 成员永久会议,检查是否需要收费
func AddPermanentMemberCost(c *gin.Context, myContext *mycontext.MyContext, isInvite int, userId uint64, groupId string) (bool, error) {
needCost := true
// 加入群组是否需要收费
var model = domain.CreateModelContext(myContext)
info, err := group_m.GetByImGroupId(model, groupId)
if err != nil {
return needCost, err
}
if info.MemberFee > 0 { // 需要收费
// 旧版本(2.32.0以下),提示升级
_, major, minor, _, err := req.GetAppVersion(c)
if err != nil {
return needCost, err
}
if major <= 2 && minor < 32 {
return needCost, bizerr.UpgradeRequired
}
// 验证是否邀请
if isInvite == 1 {
inviteInfo, err := group_m.GetGroupInviteJoin(model, userId, groupId)
if err != nil {
return needCost, err
}
if inviteInfo != nil && time.Now().Unix()-inviteInfo.CreatedTime.Unix() < 86400 { // 一天内的邀请才有效
needCost = false
}
}
if needCost { // 需要扣黄钻
err = ChangeDiamondAccountDetail(myContext, diamond_e.JoinGroupCost, mysql.ID(info.Id), userId, mysql.Num(info.MemberFee))
if err != nil {
return needCost, err
}
// 给一半群主
err = ChangeDiamondAccountDetail(myContext, diamond_e.JoinGroupAdd, mysql.ID(info.Id), info.Owner, mysql.Num(math.Floor(float64(info.MemberFee)/2)))
if err != nil {
return needCost, err
}
}
}
return needCost, nil
}
func ChangeDiamondAccountDetail(myContext *mycontext.MyContext, operateType diamond_e.OperateType, originId mysql.ID, userId mysql.ID, diamondNum mysql.Num) error {
db := mysql.Db.Begin()
model := domain.CreateModelContext(myContext)
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, userId)
if err != nil {
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(operateType, originId, diamondNum)
if err != nil {
db.Rollback()
return err
}
if err := diamondAccountDetail.PersistentNoInTransactional(); err != nil {
db.Rollback()
return err
}
db.Commit()
return nil
}
// @Tags 群组
// @Summary 退出永久成员
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} uint
// @Router /v1/imGroup/permanent/{groupId} [delete]
func RemovePermanentMember(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
userId, externalId, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupInfo, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if groupInfo == nil {
return myContext, bizerr.GroupNotFound
}
groupId = groupInfo.ImGroupId
if userId == groupInfo.Owner {
return myContext, bizerr.OwnerCannotLeave
}
if err = group_s.NewGroupService(myContext).LeaveGroupMember(model, groupId, userId, externalId); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
type GroupMembersRsp struct {
Members []group_cv.MemberDetail `json:"members"`
Online uint `json:"online"` // 在线人数
Total uint `json:"total"`
}
// @Tags 群组
// @Summary 获取永久成员列表
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param pageSize query int false "分页大小 默认:10" default(10)
// @Param pageIndex query int false "第几个分页,从1开始 默认:1" default(1)
// @Success 200 {object} GroupMembersRsp
// @Router /v1/imGroup/permanent/{groupId} [get]
func GetPermanentMember(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.ParaMissing
}
pageSize, err := strconv.Atoi(c.Query("pageSize"))
if err != nil || pageSize <= 0 {
pageSize = 10
}
pageIndex, err := strconv.Atoi(c.Query("pageIndex"))
if err != nil || pageIndex <= 0 {
pageIndex = 1
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
rows, err := group_m.GetMembers(model.Db, groupId)
if err != nil {
return myContext, err
}
userIds := make([]uint64, 0)
for _, i := range rows {
userIds = append(userIds, i.UserId)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupMembers %s: memberNum = %d, user size = %d", groupId, len(rows), len(userIds))
result := GroupMembersRsp{Total: uint(len(rows))}
beginPos := pageSize * (pageIndex - 1)
if uint(beginPos) < result.Total {
// 取在线状态
extIds := make([]string, 0)
for _, i := range users {
extIds = append(extIds, i.ExternalId)
}
statusMap, err := tim_m.GetOnlineStatus(model, extIds)
if err != nil {
return myContext, err
}
result.Online = 0
for _, v := range statusMap {
if v == online_e.IM_STATUS_ON_LINE {
result.Online++
}
}
model.Log.Infof("GetGroupMembers %s: statusMap size = %d, onLine = %d", groupId, len(statusMap), result.Online)
roles, _, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
nobleLevels, err := noble_m.BatchGetNobleLevel(model.Db, userIds)
if err != nil {
return myContext, err
}
vips, err := user_m.BatchGetVips(userIds)
if err != nil {
return myContext, err
}
model.Log.Infof("GetGroupMembers %s, users %v, roles: %v, nobles: %v, vips: %v", groupId, userIds, roles, nobleLevels, vips)
roomUsers, err := group_m.RoomLivingExistsUserId(groupId)
if err != nil {
return myContext, err
}
roomUserMap := utils.SliceToMapUInt64(roomUsers)
//model.Log.Infof("GetGroupMembers %s, roomStatusMap %v", groupId, roomStatusMap)
// 排序规则 :在房间的优先,其次是在线,再次看角色,最后看贵族
sort.Slice(userIds, func(i, j int) bool {
ui := userIds[i]
uj := userIds[j]
_, ok1 := roomUserMap[ui]
_, ok2 := roomUserMap[uj]
if ok1 && !ok2 {
return true
} else if ok1 == ok2 {
ei := users[ui].ExternalId
ej := users[uj].ExternalId
if statusMap[ei] > statusMap[ej] {
return true
}
if statusMap[ei] == statusMap[ej] {
if roles[ui] > roles[uj] {
return true
}
if roles[ui] == roles[uj] {
// 贵族5>贵族4>贵族3>贵族2>VIP
if nobleLevels[ui] > nobleLevels[uj] && nobleLevels[ui] >= 2 {
return true
}
if nobleLevels[ui] == nobleLevels[uj] || nobleLevels[ui] < 2 && nobleLevels[uj] < 2 {
if vips[ui] != nil {
if vips[uj] == nil {
return true
} else {
return users[ui].Code < users[uj].Code
}
} else if vips[uj] == nil {
return users[ui].Code < users[uj].Code
}
}
}
}
}
return false
})
model.Log.Infof("GetGroupMembers %s, sorted users: %v", groupId, userIds)
endPos := pageSize * pageIndex
if endPos > len(userIds) {
endPos = len(userIds)
}
userIds = userIds[beginPos:endPos]
userExtends, err := user_cv.BatchGetUserExtend(model, userIds, userId)
if err != nil {
return myContext, err
}
for _, u := range userIds {
inRoom := false
if _, ok := roomUserMap[u]; ok {
inRoom = true
}
result.Members = append(result.Members, group_cv.MemberDetail{
CvUserExtend: userExtends[u],
Role: roles[u],
OnlineStatus: statusMap[users[u].ExternalId],
InRoom: inRoom,
})
}
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 全服广播群消息(运营用,慎用)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param contentType formData int true "消息类型:1 跳转url;2 跳转房间"
// @Param content formData string true "消息内容"
// @Param h5url formData string false "要转跳的url"
// @Param groupId formData string false "群ID"
// @Success 200 {object} uint
// @Router /v1/imGroup/allGroupMsg [put]
func SendTextMsg(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
if !user_m.IsSuperUser(userId) {
return myContext, bizerr.NoPrivileges
}
contentType, err := strconv.Atoi(c.PostForm("contentType"))
if err != nil {
return myContext, bizerr.ParaMissing
}
content := c.PostForm("content")
if len(content) <= 0 {
return myContext, bizerr.ParaMissing
}
h5url := ""
groupId := ""
if contentType == 1 {
h5url = c.PostForm("h5url")
if len(h5url) == 0 {
return myContext, bizerr.InvalidParameter
}
} else if contentType == 2 {
groupId = c.PostForm("groupId")
if len(groupId) == 0 {
return myContext, bizerr.InvalidParameter
}
} else {
return myContext, bizerr.InvalidParameter
}
model := domain.CreateModelContext(myContext)
txGroupId := groupId
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
gsm := group_m.GroupCustomMsg{
CommonPublicMsg: group_m.CommonPublicMsg{Type: group_e.JumpMessage},
ContentType: contentType,
Content: content,
H5: h5url,
GroupId: txGroupId,
}
buf, err := json.Marshal(gsm)
var failedCount uint = 0
if err == nil {
groupIds, err := group_m.GetAllGroupIds(model.Db)
if err != nil {
return myContext, err
}
for i, g := range groupIds {
seq, err := signal_s.SendCustomMsg(model, g, nil, string(buf))
if err == nil {
model.Log.Infof("Succeeded in sending GroupCustomMsg to group %s, seq = %d", g, seq)
} else {
model.Log.Infof("Failed in sending GroupCustomMsg to group %s", g)
failedCount++
}
if i%100 == 0 {
time.Sleep(time.Millisecond * 500)
}
}
}
resp.ResponseOk(c, failedCount)
return myContext, nil
}
package group_r
import (
"encoding/json"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/rpc"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/model/game_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/noble_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_s"
"hilo-group/domain/service/signal_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req"
"hilo-group/resp"
"strconv"
)
// @Tags 群组
// @Summary 查询群是否有密码
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} bool
// @Router /v1/imGroup/password/{groupId} [get]
func GetGroupPassword(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
model := domain.CreateModelContext(myContext)
gi, err := group_m.GetInfoByTxGroupId(model, groupId)
if err != nil {
return myContext, err
}
if gi == nil {
return myContext, bizerr.GroupNotFound
}
groupId = gi.ImGroupId
result := false
if gi != nil && len(gi.Password) > 0 && userId != gi.Owner {
result = true
}
resp.ResponseOk(c, result)
return myContext, nil
}
type SimpleRoleInfo struct {
ExternalId string `json:"externalId"`
Role group_e.GroupRoleType `json:"role"`
}
// @Tags 群组
// @Summary 查询群角色
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param role query int false "指定的角色,不填的话代表全选"
// @Success 200 {object} []SimpleRoleInfo
// @Router /v1/imGroup/role/{groupId} [get]
func GetGroupRole(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
var role group_e.GroupRoleType = 0
r, err := strconv.Atoi(c.Query("role"))
if err == nil {
role = group_e.GroupRoleType(r)
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
roles, orderList, err := group_m.GetRolesInGroup(model, groupId)
if err != nil {
return myContext, err
}
result := make([]SimpleRoleInfo, 0)
userBases, err := user_cv.GetUserBaseMap(orderList, userId)
if err != nil {
return myContext, err
}
for _, i := range orderList {
if role == 0 || role == roles[i] {
result = append(result, SimpleRoleInfo{
ExternalId: *userBases[i].ExternalId,
Role: roles[i],
})
}
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 设置群角色/邀请游客成为群成员,邀请后需要对方同意
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param role formData int true "要赋予的角色"
// @Param externalId formData string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/role/{groupId} [put]
func SetGroupRole(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
r, err := strconv.Atoi(c.PostForm("role"))
if err != nil {
return myContext, err
}
role := group_e.GroupRoleType(r)
if role != group_e.GROUP_MANAGER && role != group_e.GROUP_ADMIN && role != group_e.GROUP_MEMBER && role != group_e.GROUP_VISITOR {
return myContext, myerr.NewSysError("Invalid role")
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
// 删除角色时没必要检查上限
if role > group_e.GROUP_MEMBER {
// 检查有没有超过上限 TODO: 如何防止并发?
count, err := group_m.GetRoleCountInGroup(model, groupId, role)
if err != nil {
return myContext, err
}
if role == group_e.GROUP_MANAGER && count >= group_e.GROUP_MANAGER_LIMIT {
return myContext, bizerr.RoleLimitReached
}
if role == group_e.GROUP_ADMIN && count >= group_e.GROUP_ADMIN_LIMIT {
return myContext, bizerr.RoleLimitReached
}
}
userId, myExtId, _, nick, avatar, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
// 检查用户是否有权限做操作
myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
if err != nil {
return myContext, err
}
// 管理员以下不能改变任何角色
if myRole <= group_e.GROUP_ADMIN {
return myContext, bizerr.NoPrivileges
}
if role == group_e.GROUP_MANAGER && myRole != group_e.GROUP_OWNER {
return myContext, bizerr.NoPrivileges
}
if role == group_e.GROUP_ADMIN && myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
return myContext, bizerr.NoPrivileges
}
if (role == group_e.GROUP_VISITOR || role == group_e.GROUP_MEMBER) && myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
return myContext, bizerr.NoPrivileges
}
externalId := c.PostForm("externalId")
model.Log.Info("externalId: ", externalId)
//
targetUser, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
isGroupMember, err := group_m.IsGroupMember(model.Db, groupId, targetUser.ID)
if err != nil && err != gorm.ErrRecordNotFound {
return myContext, err
}
// 邀请用户加入群组会员、把用户设置成游客
if role == group_e.GROUP_VISITOR || (role == group_e.GROUP_MEMBER && !isGroupMember) {
err = SetGroupMemberTourist(model, role, isGroupMember, targetUser.ID, userId, externalId, myExtId, groupId)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
if !isGroupMember {
return myContext, bizerr.NotGroupMember
}
// 先读取旧角色
oldRole, err := group_m.GetRoleInGroup(model, targetUser.ID, groupId)
if err != nil {
return myContext, err
}
if oldRole >= myRole {
// 不能调整更高级者的角色!
return myContext, bizerr.NoPrivileges
}
if role <= group_e.GROUP_MEMBER {
// 如果已经没有角色,则不需要取消
if oldRole != role {
err = RemoveGroupRole(model, groupId, myExtId, externalId, nick, avatar, targetUser.Nick, targetUser.Avatar, targetUser.ID, oldRole)
if err != nil {
return myContext, err
}
}
} else if err = group_m.CreateGroupRole(model, groupId, targetUser.ID, role); err == nil {
// 发送信令
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupRoleChangeSignal, Source: myExtId, Target: externalId, Content: "add"}
signal_s.SendSignalMsg(model, groupId, systemMsg, false)
nobleLevel, err := noble_m.GetNobleLevel(model.Db, targetUser.ID)
if err != nil {
return myContext, err
}
// 发公屏消息
msg := group_m.CommonPublicMsg{Type: group_e.RoleAssignedPublicScreenMsg,
OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
ExternalId: targetUser.ExternalId, Nick: targetUser.Nick, Avatar: targetUser.Avatar, NobleLevel: nobleLevel,
Role: role}
buf, err := json.Marshal(msg)
if err == nil {
signal_s.SendCustomMsg(model, groupId, nil, string(buf))
}
} else {
return myContext, err
}
// 发送腾讯云信令
con := &GroupRoleChangeMsg{Role: int(role)}
msgContent, _ := json.Marshal(con)
signal_s.SendSignalMsg(model, groupId, group_m.GroupSystemMsg{
MsgId: group_e.GroupRoleChange,
Source: myExtId,
Target: externalId,
Content: string(msgContent),
}, false)
// 新角色不是经理角度时,将其(可能)设置的欢迎语清除
if role < group_e.GROUP_MANAGER {
gwt := group_m.GroupWelcomeText{}
if err = gwt.Remove(model.Db, groupId, targetUser.ID); err != nil {
model.Log.Warnf("Can't remove group %s user %d's welcome text.", groupId, userId)
}
}
resp.ResponseOk(c, nil)
return myContext, nil
}
func RemoveGroupRole(model *domain.Model, groupId, myExtId, externalId, nick, avatar, targetNick, targetAvatar string,
targetUserId uint64, oldRole group_e.GroupRoleType) error {
if err := group_m.RemoveGroupRole(model, groupId, targetUserId); err == nil {
// 发送信令
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupRoleChangeSignal, Source: myExtId, Target: externalId, Content: "remove"}
signal_s.SendSignalMsg(model, groupId, systemMsg, false)
nobleLevel, err := noble_m.GetNobleLevel(model.Db, targetUserId)
if err != nil {
return err
}
// 发公屏消息
msg := group_m.CommonPublicMsg{Type: group_e.RoleRemovedPublicScreenMsg,
OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
ExternalId: externalId, Nick: targetNick, Avatar: targetAvatar, NobleLevel: nobleLevel,
Role: oldRole}
buf, err := json.Marshal(msg)
if err != nil {
return err
}
signal_s.SendCustomMsg(model, groupId, nil, string(buf))
}
return nil
}
func SetGroupMemberTourist(model *domain.Model, role group_e.GroupRoleType, isGroupMember bool, userId, inviteUserId uint64,
externalId, myExtId, imGroupId string) (err error) {
var msgId group_e.TypeSignalMsg
var msgContent string
switch role {
case group_e.GROUP_MEMBER:
if isGroupMember { // 已经是成员,直接返回
return nil
}
// 邀请对方成为成员
// 插入邀请表
err = group_m.InsertGroupInviteJoin(model, userId, inviteUserId, imGroupId)
if err != nil {
return err
}
msgId = group_e.GroupMemberInvite
case group_e.GROUP_VISITOR:
if !isGroupMember { // 不是成员,直接返回
return nil
}
// 移除成员
if err = group_s.NewGroupService(nil).LeaveGroupMember(model, imGroupId, userId, externalId); err != nil {
return err
}
msgId = group_e.GroupRoleChange
con := &GroupRoleChangeMsg{Role: int(group_e.GROUP_VISITOR)}
jData, _ := json.Marshal(con)
msgContent = string(jData)
}
if msgId > 0 {
// 发送腾讯云信令
signal_s.SendSignalMsg(model, imGroupId, group_m.GroupSystemMsg{
MsgId: msgId,
Source: myExtId,
Target: externalId,
Content: msgContent,
}, false)
}
return nil
}
type GroupRoleChangeMsg struct {
Role int `json:"role"`
}
// @Tags 群组
// @Summary 接受邀请-成为永久成员
// @Param groupId formData string true "群ID"
// @Success 200
// @Router /v1/imGroup/role/accept [post]
func AcceptMemberInvite(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
resp.ResponseOk(c, group_e.ADD_GROUP_DONE)
return myContext, nil
}
// @Tags 群组
// @Summary 添加群黑名单(封禁)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId formData string true "用户的externalId"
// @Param removeHistory formData bool true "是否删除聊天记录"
// @Param blackImei formData bool false "SVIP是否封禁设备和ip"
// @Success 200
// @Router /v1/imGroup/blacklist/{groupId} [put]
func AddGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
removeHistory, err := strconv.ParseBool(c.PostForm("removeHistory"))
if err != nil {
return myContext, myerr.NewSysError("removeHistory 为必填项")
}
blackImei, err := strconv.ParseBool(c.PostForm("blackImei"))
if err != nil {
blackImei = false
}
userId, myExtId, _, nick, avatar, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
_, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
txGroupId := groupId
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
if err != nil {
return myContext, err
}
if myRole < group_e.GROUP_ADMIN {
return myContext, bizerr.NoPrivileges
}
externalId := c.PostForm("externalId")
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
//超级管理人
if flag, err := user_m.IsSuperManager(domain.CreateModelContext(myContext), user.ID); err != nil {
return myContext, err
} else if flag {
return myContext, bizerr.OfficialStaffLimit
}
role, err := group_m.GetRoleInGroup(model, user.ID, groupId)
if err != nil {
return myContext, err
}
isGaming, err := game_m.IsGaming(model, user.ID, txGroupId)
if err != nil {
return myContext, err
}
if isGaming {
return myContext, bizerr.GamingCannotKick
}
if err = CheckOptToSvip6(model, userId, user.ID, lang, 10); err != nil {
return myContext, err
}
// svip
svipMap, err := rpc.MGetUserSvip(model, []mysql.ID{userId, user.ID})
if err != nil {
return myContext, err
}
if myRole > role {
// 是否svip封禁设备
var userImei, userIp string
if blackImei && role != group_e.GROUP_OWNER && role != group_e.GROUP_MANAGER {
if v, ok := svipMap[userId]; ok && v.SvipLevel > 0 {
userImei, err = user_m.GetUserImeiStr(model, user.ID)
if err != nil {
return myContext, err
}
userIpInfo, err := user_m.GetUserIpOrInit(model, user.ID)
if err != nil {
return myContext, err
}
userIp = userIpInfo.Ip
}
}
// TODO: 先发信令和公屏消息,避免被封之人收不到
// 发送信令
type removeHistoryParam struct {
RemoveHistory bool `json:"removeHistory"`
}
r := removeHistoryParam{RemoveHistory: removeHistory}
buf, err := json.Marshal(r)
if err == nil {
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupMemberRemoveSignal,
Source: myExtId, Target: externalId, Content: string(buf)}
signal_s.SendSignalMsg(model, groupId, systemMsg, false)
}
// 发公屏消息
msg := group_m.CommonPublicMsg{Type: group_e.UserBannedPublicScreenMsg,
OperatorExternalId: myExtId, OperatorNick: nick, OperatorAvatar: avatar,
ExternalId: user.ExternalId, Nick: user.Nick, Avatar: user.Avatar}
buf, err = json.Marshal(msg)
if err == nil {
signal_s.SendCustomMsg(model, groupId, nil, string(buf))
}
if err = group_s.NewGroupService(myContext).LeaveGroup(model, groupId, user.ID, externalId); err != nil {
return myContext, err
}
gb := group_m.GroupBlacklist{ImGroupId: groupId, UserId: user.ID, Imei: userImei, Ip: userIp}
err = group_m.AddBlacklist(model, &gb)
if err != nil {
model.Log.Errorf("AddBlacklist failed for %s, user %d", groupId, user.ID)
}
} else {
return myContext, bizerr.NoPrivileges
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// 检查是否可以对svip6进行操作 optUserId:被操作的用户id
func CheckOptToSvip6(model *domain.Model, userId, optUserId uint64, lang string, privilegeId int) error {
// 是否超管
isM, err := user_m.IsSuperManager(model, userId)
if err != nil {
return err
}
// svip
svipMap, err := rpc.MGetUserSvip(model, []mysql.ID{userId, optUserId})
if err != nil {
return err
}
if !isM {
if svip, ok := svipMap[userId]; !ok || svip.SvipLevel < 6 { // 非svip6(svip6可以对svip6进行操作)
// 是否禁止被封禁
if svip, ok := svipMap[optUserId]; ok {
for _, v := range svip.Privileges {
if v.Type == privilegeId {
return myerr.WrapErr(res_m.GetErrByLanguage(model.Db, msg_e.MSG_ID_NO_POWER_TO_SVIP6, lang, bizerr.GroupNoPowerToSvip6))
}
}
}
}
}
return nil
}
// @Tags 群组
// @Summary 移除群黑名单
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId query string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/blacklist/{groupId} [delete]
func RemoveGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
if err != nil {
return myContext, err
}
if myRole < group_e.GROUP_ADMIN {
return myContext, bizerr.NoPrivileges
}
externalId := c.Query("externalId")
if len(externalId) <= 0 {
return myContext, myerr.NewSysError("externalId 为必填项")
}
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
err = group_m.RemoveBlacklist(model, &group_m.GroupBlacklist{ImGroupId: groupId, UserId: user.ID})
if err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
//拉黑列表视图
type GroupBlackList struct {
//拉黑时间
BlockTime int64 `json:"blockTime"`
//用户基本信息
UserBase user_cv.CvUserBase `json:"userBase"`
}
// @Tags 群组
// @Summary 查询群黑名单
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} GroupBlackList
// @Router /v1/imGroup/blacklist/{groupId} [get]
func GetGroupBlacklist(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
// TODO: 非群成员不能看
rows, err := group_m.FindGroupBlackList(model, groupId)
if err != nil {
return myContext, err
}
userIds := make([]uint64, 0)
for _, i := range rows {
userIds = append(userIds, i.UserId)
}
users, err := user_cv.GetUserBaseMap(userIds, userId)
if err != nil {
return myContext, err
}
result := make([]GroupBlackList, 0)
for _, i := range rows {
result = append(result, GroupBlackList{
BlockTime: i.CreatedTime.Unix(),
UserBase: *users[i.UserId],
})
}
resp.ResponsePageOk(c, result, uint(len(result)), 1)
return myContext, nil
}
// @Tags 群组
// @Summary 踢人出群(运营操作,慎用)
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param externalId formData string true "用户的externalId"
// @Param removeHistory formData bool true "是否删除聊天记录"
// @Success 200
// @Router /v1/imGroup/kick/{groupId} [put]
func KickGroupMembers(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
removeHistory, err := strconv.ParseBool(c.PostForm("removeHistory"))
if err != nil {
return myContext, myerr.NewSysError("removeHistory 为必填项")
}
userId, myExtId, _, _, _, err := req.GetUserEx(c, myContext)
if err != nil {
return myContext, err
}
if !user_m.IsSuperUser(userId) {
return myContext, bizerr.NoPrivileges
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
externalId := c.PostForm("externalId")
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
role, err := group_m.GetRoleInGroup(model, user.ID, groupId)
if err != nil {
return myContext, err
}
if role > group_e.GROUP_MEMBER {
// 不能踢有角色的人出去
return myContext, bizerr.NoPrivileges
}
// 发送信令?
type removeHistoryParam struct {
RemoveHistory bool `json:"removeHistory"`
}
r := removeHistoryParam{RemoveHistory: removeHistory}
buf, err := json.Marshal(r)
if err == nil {
systemMsg := group_m.GroupSystemMsg{MsgId: group_e.GroupMemberRemoveSignal,
Source: myExtId, Target: externalId, Content: string(buf)}
signal_s.SendSignalMsg(model, groupId, systemMsg, false)
}
if err = group_s.NewGroupService(myContext).LeaveGroup(model, groupId, user.ID, externalId); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 设置入群欢迎语
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param text formData string true "欢迎语"
// @Success 200
// @Router /v1/imGroup/welcomeText/{groupId} [put]
func SetWelcomeText(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
text := c.PostForm("text")
if len(text) <= 0 {
return myContext, bizerr.EmptyContent
}
if len([]rune(text)) > group_e.GROUP_INTRODUCTION_LENGTH_LIMIT {
return myContext, bizerr.ContentTooLong
}
userId, _, err := req.GetUserIdAndExtId(c, myContext)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
if group_c.IsEditGroupCd(model, groupId) {
return myContext, bizerr.EditCd
}
myRole, err := group_m.GetRoleInGroup(model, userId, groupId)
if err != nil {
return myContext, err
}
if myRole != group_e.GROUP_OWNER && myRole != group_e.GROUP_MANAGER {
return myContext, bizerr.NoPrivileges
}
gwt := group_m.GroupWelcomeText{GroupId: groupId, UserId: userId, Text: text}
if err = gwt.Save(model.Db); err != nil {
return myContext, err
}
resp.ResponseOk(c, nil)
return myContext, nil
}
package group_r
import (
"fmt"
"git.hilo.cn/hilo-common/domain"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql"
"github.com/gin-gonic/gin"
"hilo-group/_const/enum/gift_e"
"hilo-group/_const/enum/group_e"
"hilo-group/_const/enum/msg_e"
"hilo-group/cv/group_cv"
"hilo-group/cv/user_cv"
"hilo-group/domain/cache/group_c"
"hilo-group/domain/model/gift_m"
"hilo-group/domain/model/group_m"
"hilo-group/domain/model/res_m"
"hilo-group/domain/model/user_m"
"hilo-group/domain/service/group_s"
"hilo-group/myerr"
"hilo-group/myerr/bizerr"
"hilo-group/req"
"hilo-group/resp"
"strings"
"time"
)
// @Tags 群组
// @Summary 查询是否能打开支持页
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Success 200 {object} bool
// @Router /v1/imGroup/support/page/{groupId} [get]
func GetSupportPage(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, bizerr.ParaMissing
}
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
pa, err := group_m.GetProfitAllocator(model, groupId)
if err != nil {
return myContext, err
}
resp.ResponseOk(c, pa == userId)
return myContext, nil
}
// @Tags 群组
// @Summary 支持页详情
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId query string false "群ID"
// @Success 200 {object} cv.SupportPageDetail
// @Router /v1/imGroup/support/detail [get]
func GetSupportDetail(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
userId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
model := domain.CreateModelContext(myContext)
groupId := c.Query("groupId")
txGroupId := groupId
if len(groupId) <= 0 {
// groupId 没填的话,用user自己的群
groups, err := group_m.FindGroupByOwner(model, userId)
if err != nil {
return myContext, err
}
if len(groups) > 0 {
groupId = groups[0].ImGroupId
txGroupId = groups[0].TxGroupId
} else {
return myContext, bizerr.GroupNotFound
}
} else {
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
}
pa, err := group_m.GetProfitAllocator(model, groupId)
if err != nil {
return myContext, err
}
if userId != pa {
return myContext, bizerr.NoPrivileges
}
result := group_cv.SupportPageDetail{GroupId: txGroupId}
now := time.Now()
beginTime, endTime, _ := group_m.GetSupportLevelTime(now)
result.RemainSecond = endTime.Unix() - now.Unix()
g := gift_m.GiftOperate{SceneType: gift_e.GroupSceneType, SceneUid: groupId, Model: model}
result.CurrentCount, result.CurrentConsume, err = g.GetConsumeByRange(beginTime, endTime)
if err != nil {
return myContext, err
}
beginTime, endTime, _ = group_m.GetSupportLevelTime(now.AddDate(0, 0, -group_e.SUPPORT_LEVEL_PERIOD_DAY))
result.LastCount, result.LastConsume, err = g.GetConsumeByRange(beginTime, endTime)
if err != nil {
return myContext, err
}
rec, err := res_m.GetResGroupSupportBy(model, result.LastCount, result.LastConsume)
if err != nil {
return myContext, err
}
if rec != nil {
result.SupportLevel = string(64 + rec.Grade)
result.SupporterLimit = rec.MgrNum
}
rec, err = res_m.GetResGroupSupportBy(model, result.CurrentCount, result.CurrentConsume)
if err != nil {
return myContext, err
}
if rec != nil {
result.CurrentSupportLevel = string(64 + rec.Grade)
}
userBase, err := user_cv.GetUserBase(pa, userId)
if err != nil {
return myContext, err
}
if userBase != nil {
result.ProfitAllocator = *userBase
}
// 判断这个周期这个群的奖金是否已经发过
_, _, period := group_m.GetLastSupportPeriod(now)
gsaa := group_m.GroupSupportAwardAdmin{Period: period, GroupUid: groupId}
rows, err := gsaa.Get(model.Db)
if err != nil {
return myContext, err
}
if len(rows) > 0 {
result.IsDispatched = true
}
resp.ResponseOk(c, result)
return myContext, nil
}
// @Tags 群组
// @Summary 检查用户能不能成为群支持者
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string false "群ID"
// @Param externalId query string true "用户的externalId"
// @Success 200
// @Router /v1/imGroup/support/award/{groupId} [get]
func TryAddSupporter(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
myUserId, err := req.GetUserId(c)
if err != nil {
return myContext, err
}
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
externalId := c.Query("externalId")
if len(externalId) <= 0 {
return myContext, myerr.NewSysError("externalId 为必填项")
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
pa, err := group_m.GetProfitAllocator(model, groupId)
if err != nil {
return myContext, err
}
if myUserId != pa {
return myContext, bizerr.NoPrivileges
}
user, err := user_m.GetUserByExtId(model, externalId)
if err != nil {
return myContext, err
}
userId := user.ID
role, err := group_m.GetRoleInGroup(model, userId, groupId)
if err != nil {
return myContext, err
}
if role != group_e.GROUP_MANAGER && role != group_e.GROUP_ADMIN {
return myContext, bizerr.NotManagerOrAdmin
}
// 判断用户是否作为助手领取过奖励
sameImeiUsers, err := user_m.GetSameImeiMap(model, userId)
if err != nil {
return myContext, err
}
_, _, period := group_m.GetLastSupportPeriod(time.Now())
gsaa := group_m.GroupSupportAwardMgr{Period: period}
awards, err := gsaa.Get(model.Db)
if err != nil {
return myContext, err
}
for _, i := range awards {
if _, ok := sameImeiUsers[i.UserId]; ok {
if i.UserId == userId {
return myContext, bizerr.UserAlreadyAwarded
} else {
return myContext, bizerr.ImeiAlreadyAwarded
}
}
}
resp.ResponseOk(c, nil)
return myContext, nil
}
// @Tags 群组
// @Summary 领取群支持奖励
// @Accept application/x-www-form-urlencoded
// @Param token header string true "token"
// @Param nonce header string true "随机数字"
// @Param groupId path string true "群ID"
// @Param supporters formData string false "群支持者的externalId,用逗号分隔"
// @Success 200 {object} cv.AwardResult
// @Router /v1/imGroup/support/award/{groupId} [post]
func TakeSupportAward(c *gin.Context) (*mycontext.MyContext, error) {
myContext := mycontext.CreateMyContext(c.Keys)
//userId, err := getUserId(c)
userId, lang, err := req.GetUserIdLang(c, myContext)
if err != nil {
return myContext, err
}
groupId := c.Param("groupId")
if len(groupId) <= 0 {
return myContext, myerr.NewSysError("groupId 为必填项")
}
model := domain.CreateModelContext(myContext)
groupId, err = group_m.ToImGroupId(model, groupId)
if err != nil {
return myContext, err
}
pa, err := group_m.GetProfitAllocator(model, groupId)
if err != nil {
return myContext, err
}
if userId != pa {
return myContext, bizerr.NoPrivileges
}
s := c.PostForm("supporters")
extIds := make([]string, 0)
extId2Uid := make(map[string]uint64, 0)
uid2extId := make(map[uint64]string, 0)
codeMap := make(map[mysql.ID]string, 0)
if len(s) > 0 {
extIds = strings.Split(s, ",")
users, err := user_m.BatchGetUserByExtIds(model, extIds)
if err != nil {
return myContext, err
}
for _, i := range users {
extId2Uid[i.ExternalId] = i.ID
uid2extId[i.ID] = i.ExternalId
codeMap[i.ID] = i.Code
}
}
userIds := make([]uint64, 0)
for _, i := range extIds {
if _, ok := extId2Uid[i]; ok {
userIds = append(userIds, extId2Uid[i])
} else {
// FIXME: report error
}
}
// 检查是否已经发放了
_, _, period := group_m.GetLastSupportPeriod(time.Now())
gsa := group_m.GroupSupportAwardAdmin{Period: period, GroupUid: groupId}
rows, err := gsa.Get(model.Db)
if err != nil {
return myContext, err
}
if len(rows) > 0 {
return myContext, bizerr.GroupAlreadyAwarded
}
userIds, outUserIds, err := group_s.NewGroupService(myContext).GroupSupportList(groupId, userIds)
model.Log.Infof("TakeSupportAward: %v, %v", userIds, outUserIds)
model = domain.CreateModelContext(myContext)
resSupportId, _, err := group_s.NewGroupService(myContext).GetSupportLevel(groupId)
if err != nil {
return myContext, err
}
if resSupportId <= 0 {
return myContext, bizerr.NotQualified
}
// 检查userIds的ip限制
userIp, err := user_m.GetUserIpMap(model.Db, userIds)
if err != nil {
return myContext, err
}
var sameIp = make(map[string]int)
var ipUser = make(map[string]mysql.ID)
for uid, ip := range userIp {
sameIp[ip]++
ipUser[ip] = uid
if len(ip) > 0 {
// IP已经领取过6次奖励,点击领奖校验则提示“ID:%s为重复账户
var msg = fmt.Sprintf(bizerr.GroupSupportIpLimit.GetMsg(), codeMap[uid])
if resMul, _ := res_m.GetResMultiTextBy(model.Db, msg_e.MSG_ID_REPEAT_ACCOUNT, lang); resMul != nil {
msg = fmt.Sprintf(resMul.Content, codeMap[uid])
}
if times, err := group_c.GetGroupSupportAwardIpTimes(model, ip); err != nil || times >= 6 {
return myContext, myerr.NewBusinessCodeNoCheck(bizerr.GroupSupportIpLimit.GetCode(), msg, myerr.BusinessData{})
}
}
}
for ip, cnt := range sameIp {
if cnt >= 6 {
var msg = fmt.Sprintf(bizerr.GroupSupportIpLimit.GetMsg(), ipUser[ip])
if resMul, _ := res_m.GetResMultiTextBy(model.Db, msg_e.MSG_ID_REPEAT_ACCOUNT, lang); resMul != nil {
msg = fmt.Sprintf(resMul.Content, ipUser[ip])
}
return myContext, myerr.NewBusinessCodeNoCheck(bizerr.GroupSupportIpLimit.GetCode(), msg, myerr.BusinessData{})
}
}
// 真正地放奖励
err = group_s.NewGroupService(myContext).GroupSupportAward(groupId, pa, userIds, resSupportId, period)
if err != nil {
return myContext, err
}
// 记录ip获奖
for _, userId := range userIds {
if ip, ok := userIp[userId]; ok && len(ip) > 0 {
_, _ = group_c.IncrGroupSupportAwardIp(model, ip)
}
}
// 保存记录
if err = group_s.NewGroupService(myContext).RenewGroupSupporter(groupId, userIds); err != nil {
model.Log.Warnf("TakeSupportAward, failed in saving group %s supporters", groupId)
}
result := group_cv.AwardResult{}
for _, i := range userIds {
result.Success = append(result.Success, uid2extId[i])
}
for _, i := range outUserIds {
result.Failed = append(result.Failed, uid2extId[i])
}
resp.ResponseOk(c, result)
return myContext, nil
}
...@@ -28,40 +28,40 @@ func InitRouter() *gin.Engine { ...@@ -28,40 +28,40 @@ func InitRouter() *gin.Engine {
imGroup.GET("/group/:code", wrapper(group_r.GetGroupInfo)) imGroup.GET("/group/:code", wrapper(group_r.GetGroupInfo))
imGroup.GET("/detail/:groupId", wrapper(group_r.GetGroupDetail)) imGroup.GET("/detail/:groupId", wrapper(group_r.GetGroupDetail))
imGroup.PUT("/group/:groupId", wrapper(group_r.ModifyGroupInfo)) imGroup.PUT("/group/:groupId", wrapper(group_r.ModifyGroupInfo))
//imGroup.GET("/search/:code", wrapper(SearchGroup)) imGroup.GET("/search/:code", wrapper(group_r.SearchGroup))
//imGroup.DELETE("/member/:groupId", wrapper(LeaveGroup)) imGroup.DELETE("/member/:groupId", wrapper(group_r.LeaveGroup))
//imGroup.PUT("/permanent/:groupId", wrapper(AddPermanentMember)) imGroup.PUT("/permanent/:groupId", wrapper(group_r.AddPermanentMember))
//imGroup.DELETE("/permanent/:groupId", wrapper(RemovePermanentMember)) imGroup.DELETE("/permanent/:groupId", wrapper(group_r.RemovePermanentMember))
//imGroup.GET("/permanent/:groupId", wrapper(GetPermanentMember)) imGroup.GET("/permanent/:groupId", wrapper(group_r.GetPermanentMember))
//imGroup.GET("/myRecent", wrapper(GetRecentGroup)) imGroup.GET("/myRecent", wrapper(group_r.GetRecentGroup))
//imGroup.GET("/myPermanent", wrapper(GetMyGroup)) imGroup.GET("/myPermanent", wrapper(group_r.GetMyGroup))
// //
//imGroup.GET("/visitors/:groupId", wrapper(GetGroupVisitors)) imGroup.GET("/visitors/:groupId", wrapper(group_r.GetGroupVisitors))
//imGroup.GET("/ownPublicGroup/:userExternalId", wrapper(GetOwnPublicGroup)) imGroup.GET("/ownPublicGroup/:userExternalId", wrapper(group_r.GetOwnPublicGroup))
//// 2.19的新接口 //// 2.19的新接口
//imGroup.GET("/ownGroup", wrapper(GetOwnGroup)) imGroup.GET("/ownGroup", wrapper(group_r.GetOwnGroup))
//imGroup.GET("/theirGroup/:userExternalId", wrapper(GetTheirGroups)) imGroup.GET("/theirGroup/:userExternalId", wrapper(group_r.GetTheirGroups))
//imGroup.PUT("/pluginReady/:groupId", wrapper(PluginReady)) imGroup.PUT("/pluginReady/:groupId", wrapper(group_r.PluginReady))
//imGroup.GET("/roomInfo/:groupId", LogRequestTime, wrapper(GetRoomInfo)) imGroup.GET("/roomInfo/:groupId", wrapper(group_r.GetRoomInfo))
// //
//imGroup.GET("/password/:groupId", wrapper(GetGroupPassword)) imGroup.GET("/password/:groupId", wrapper(group_r.GetGroupPassword))
//imGroup.GET("/role/:groupId", wrapper(GetGroupRole)) imGroup.GET("/role/:groupId", wrapper(group_r.GetGroupRole))
//imGroup.PUT("/role/:groupId", wrapper(SetGroupRole)) imGroup.PUT("/role/:groupId", wrapper(group_r.SetGroupRole))
//imGroup.POST("/role/accept", wrapper(AcceptMemberInvite)) imGroup.POST("/role/accept", wrapper(group_r.AcceptMemberInvite))
//imGroup.GET("/admin/:groupId", wrapper(GetGroupAdmin)) imGroup.GET("/admin/:groupId", wrapper(group_r.GetGroupAdmin))
// //
//imGroup.PUT("/blacklist/:groupId", wrapper(AddGroupBlacklist)) imGroup.PUT("/blacklist/:groupId", wrapper(group_r.AddGroupBlacklist))
//imGroup.DELETE("/blacklist/:groupId", wrapper(RemoveGroupBlacklist)) imGroup.DELETE("/blacklist/:groupId", wrapper(group_r.RemoveGroupBlacklist))
//imGroup.GET("/blacklist/:groupId", wrapper(GetGroupBlacklist)) imGroup.GET("/blacklist/:groupId", wrapper(group_r.GetGroupBlacklist))
//imGroup.PUT("/kick/:groupId", wrapper(KickGroupMembers)) imGroup.PUT("/kick/:groupId", wrapper(group_r.KickGroupMembers))
// //
//imGroup.PUT("/allGroupMsg", wrapper(SendTextMsg)) imGroup.PUT("/allGroupMsg", wrapper(group_r.SendTextMsg))
// //
//imGroup.PUT("/welcomeText/:groupId", wrapper(SetWelcomeText)) imGroup.PUT("/welcomeText/:groupId", wrapper(group_r.SetWelcomeText))
//imGroup.GET("/support/page/:groupId", wrapper(GetSupportPage)) imGroup.GET("/support/page/:groupId", wrapper(group_r.GetSupportPage))
//imGroup.GET("/support/detail", wrapper(GetSupportDetail)) imGroup.GET("/support/detail", wrapper(group_r.GetSupportDetail))
//imGroup.GET("/support/award/:groupId", wrapper(TryAddSupporter)) imGroup.GET("/support/award/:groupId", wrapper(group_r.TryAddSupporter))
//imGroup.POST("/support/award/:groupId", wrapper(TakeSupportAward)) imGroup.POST("/support/award/:groupId", wrapper(group_r.TakeSupportAward))
// //
//// 操作类,普通用户不用 //// 操作类,普通用户不用
//imGroup.PUT("/memberLimit", wrapper(SetGroupMemberLimit)) //imGroup.PUT("/memberLimit", wrapper(SetGroupMemberLimit))
......
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