package group_r import ( "context" "encoding/json" "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/resource/redisCli" "git.hilo.cn/hilo-common/rpc" "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/_const/enum/mgr_e" "hilo-group/_const/enum/msg_e" "hilo-group/_const/redis_key" "hilo-group/cv/gift_cv" "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/noble_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" "net/url" "sort" "strconv" "strings" "time" ) // @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, powerNameplates, powerGrades, 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], GroupPowerNameplate: powerNameplates[gi.Owner], GroupPower: group_cv.GroupPower{ Id: powerIds[gi.Owner], Name: powerNames[gi.Owner], Nameplate: powerNameplates[gi.Owner], Grade: powerGrades[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} group_cv.RoomInfo // @Router /v1/imGroup/roomInfo/{groupId} [get] func GetRoomInfo(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) start := time.Now() 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 cost 0:%v", time.Now().Sub(start).Seconds()) 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}, Domino: &game_m.GameConfigDiamond{Diamond: game_e.GameLudoDiamondList}, }, } model.Log.Infof("GetRoomInfo cost 1:%v", time.Now().Sub(start).Seconds()) roles, orderList, err := group_m.GetRolesInGroup(model, groupId) 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 } } } model.Log.Infof("GetRoomInfo cost 2:%v", time.Now().Sub(start).Seconds()) 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", "") model.Log.Infof("GetRoomInfo cost 3:%v", time.Now().Sub(start).Seconds()) // 补上房间流水勋章 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}) } var 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). Where("(expire_at is null or expire_at > ?)", time.Now().Format(utils.DATETIME_FORMAT)). Order("res_medal.sort"). 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.Errorf("GetRoomInfo: group_medal: %s", err.Error()) } model.Log.Infof("GetRoomInfo cost 4:%v", time.Now().Sub(start).Seconds()) // 获取国家信息 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, ActionUrl: i.Url, // 支持direction=1横屏 }) } } else { model.Log.Errorf("GetRoomInfo: GetRoomBanners: %s", err.Error()) } model.Log.Infof("GetRoomInfo cost 5:%v", time.Now().Sub(start).Seconds()) result.LuckyWheel, err = group_cv.GetLuckWheelState(model, groupId) // todo check 耗时 if err != nil { model.Log.Errorf("GetRoomInfo: GetLuckWheelState: %s", err.Error()) } model.Log.Infof("GetRoomInfo cost 6:%v", time.Now().Sub(start).Seconds()) // 群主的详情 owner, err := user_cv.GetRoomInfoOwner(model, groupInfo.Owner, userId) result.Owner = user_cv.UserDetailToRoomInfoOwner(owner) if err != nil { model.Log.Errorf("GetRoomInfo: GetUserBase: %s", err.Error()) } model.Log.Infof("GetRoomInfo cost 7:%v", time.Now().Sub(start).Seconds()) // 进场特效类型 var entryEffectType int // 进场特效类型 1: CP 2:神秘人 3:贵族 4:vip ,顺序从小到大 var cpEntryEffect bool if cp, _ := rpc.GetUserCpEntryEffect(model, userId); cp != nil { cpEntryEffect = cp.CpEntryEffect result.CpLevel = cp.CpLevel result.CpUserAvatar = cp.CpUserAvatar } if user, _ := user_cv.GetUserDetail(model, userId, userId); user != nil { if user.IsVip { entryEffectType = 4 } if user.Noble.Level > 0 { entryEffectType = 3 } for _, v := range user.Svip.Privileges { if len(v.MysteryCode) > 0 { entryEffectType = 2 } } } if cpEntryEffect { entryEffectType = 1 } result.EntryEffectType = entryEffectType model.Log.Infof("GetRoomInfo cost 8:%v", time.Now().Sub(start).Seconds()) 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 } // @Tags 群组 // @Summary 修改群消息设置(默认,静音,免打扰)(obsolete) // @Accept application/x-www-form-urlencoded // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Param groupId formData string true "群ID" // @Param status formData string true "消息状态 0:默认 1:静音 2:免打扰" // @Success 200 // @Router /v1/imGroup/user/msg/status [put] func GroupUserMsg(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) userId, err := req.GetUserId(c) if err != nil { return myContext, err } status, err := strconv.ParseUint(c.PostForm("status"), 10, 64) if err != nil { return myContext, err } groupId := c.PostForm("groupId") if err := group_s.NewGroupService(myContext).GroupUserMsgStatus(userId, groupId, mysql.Type(status)); 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 formData string true "群ID" // @Param reasonType formData int false "投诉原因 1:语言骚扰(verbal harassment)2:Nudity 3:不良消息 4:不雅图片" Enums(1, 2, 3, 4) // @Param imageUrl formData string false "证据图片url" // @Param reason formData string false "投诉内容" // @Success 200 // @Router /v1/imGroup/report [post] func GroupReport(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) userId, err := req.GetUserId(c) if err != nil { return myContext, err } groupId := c.PostForm("groupId") if len(groupId) <= 0 { return myContext, bizerr.InvalidParameter } model := domain.CreateModelContext(myContext) groupId, err = group_m.ToImGroupId(model, groupId) if err != nil { return myContext, err } reasonTypeStr := c.PostForm("reasonType") var reasonType uint64 = 0 if reasonTypeStr != "" { reasonType, err = strconv.ParseUint(reasonTypeStr, 10, 64) if err != nil { return myContext, myerr.WrapErr(err) } } imageUrl := c.PostForm("imageUrl") reason := c.PostForm("reason") if err = group_s.NewGroupService(myContext).ReportGroup(userId, groupId, mgr_e.ReportReasonType(reasonType), imageUrl, reason); err != nil { return myContext, err } resp.ResponseOk(c, nil) return myContext, nil } type GroupBanner struct { //h5链接 H5Url string `json:"h5Url"` //图片地址 BannerUrl string `json:"bannerUrl"` //群主Id GroupId string `json:"groupId"` //统跳地址 http开头:web页面,query参数direction(0:竖屏 1:横屏); hilo开头:原生页面 ActionUrl string `json:"actionUrl"` } // @Tags 群组 // @Summary banner列表 // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Success 200 {object} GroupBanner // @Router /v1/imGroup/banner/list [get] func GroupBannerList(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) var groupBanners []GroupBanner userId, err := req.GetUserId(c) if err != nil { return myContext, err } mgrGroupBanners := []mgr_m.GroupBanner{} if err := mysql.Db.Model(&mgr_m.GroupBanner{}).Where(&mgr_m.GroupBanner{ Status: mysql.YES, }).Order("n desc").Find(&mgrGroupBanners).Error; err != nil { return myContext, err } _deviceType, _ := c.Get(mycontext.DEVICETYPE) _appVersion, _ := c.Get(mycontext.APP_VERSION) model := domain.CreateModelNil() 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("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v", appVersion, vc.AuditVersion, allow, err) // 获取国家信息 country, area, err := user_m.GetUserCountryArea(model, userId) if err != nil { model.Log.Errorf("GroupBannerList 获取国家资源错误 userId:%d, err:%v", userId, err) return myContext, err } groupCodes := []string{} for i := 0; i < len(mgrGroupBanners); i++ { groupCodes = append(groupCodes, mgrGroupBanners[i].GroupCode) } groupMap := map[string]string{} if len(groupCodes) > 0 { var groupInfos []group_m.GroupInfo if err := mysql.Db.Model(&group_m.GroupInfo{}).Where("code in (?) ", groupCodes).Find(&groupInfos).Error; err != nil { return myContext, err } for i := 0; i < len(groupInfos); i++ { groupMap[groupInfos[i].Code] = groupInfos[i].TxGroupId } } nowUnix := time.Now().Unix() for _, v := range mgrGroupBanners { if !allow && v.Url == "https://h5.whoisamy.shop/action/hiloHtml/22_05_30_recharge/topup.html" { model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v,skip top recharge", appVersion, vc.AuditVersion, allow, err) continue } // 版本控制 if !allow && (v.ID == 2301 || v.ID == 4711 || v.ID == 2321 || v.ID == 5341 || v.ID == 5331 || v.ID == 5631 || v.ID == 5471 || v.ID == 5461 || v.ID == 5771 || v.ID == 5811 || v.ID == 5881 || v.ID == 8781 || v.ID == 10351) { model.Log.Infof("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v,skip top recharge", appVersion, vc.AuditVersion, allow, err) continue } // 是否在上架时间内 if (v.StartAt > 0 && v.EndAt > 0) && (nowUnix < v.StartAt || nowUnix > v.EndAt) { continue } // 是否在上架区域内 if (v.Area == 1 || v.Area == 2) && area != v.Area { // 不在区域内 continue } if v.Area == 3 && !utils.IsInStringList(country, v.CountryList) { continue } actionUrl := v.Url if uri, err := url.Parse(actionUrl); err == nil { query := uri.RawQuery queryArr := strings.Split(query, "&") v := url.Values{} if len(queryArr) > 0 { for _, q := range queryArr { if arr := strings.Split(q, "="); len(arr) == 2 { v.Add(arr[0], arr[1]) } } } //v.Add("direction", "1") // 横屏的需要这样 uri.RawQuery = v.Encode() actionUrl = uri.String() } groupBanners = append(groupBanners, GroupBanner{ H5Url: v.Url, BannerUrl: v.Image, GroupId: groupMap[v.GroupCode], ActionUrl: actionUrl, }) } resp.ResponseOk(c, groupBanners) return myContext, nil } type RoomBanner struct { H5Url string `json:"h5Url"` // h5链接 BannerUrl string `json:"bannerUrl"` // 图片地址 ActionUrl string `json:"actionUrl"` // 统跳地址 http开头:web页面,query参数direction(0:竖屏 1:横屏); hilo开头:原生页面 } // @Tags 群组 // @Summary banner列表 // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Success 200 {object} RoomBanner // @Router /v1/imGroup/roomBanners [get] func RoomBannerList(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) model := domain.CreateModelContext(myContext) userId, err := req.GetUserId(c) 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("CompareVersion appVersion:%v,auditVersion:%v,allow:%v,err:%v", appVersion, vc.AuditVersion, allow, err) result := make([]RoomBanner, 0) // 获取国家信息 country, area, err := user_m.GetUserCountryArea(model, userId) if err != nil { model.Log.Errorf("GroupBannerList 获取国家资源错误 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 { return myContext, err } 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 = append(result, RoomBanner{ H5Url: i.Url, BannerUrl: i.Image, ActionUrl: i.Url, }) } resp.ResponseOk(c, result) return myContext, nil } // @Tags 群组 // @Summary 通知客户端banner列表更新 // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Success 200 // @Router /v1/imGroup/roomBanners [put] func NotifyRoomBannerListChange(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 } if err = rpc.SendConfigChange(userId, rpc.RoomBannerChange); err != nil { return myContext, err } resp.ResponseOk(c, nil) return myContext, nil } // @Tags 群组 // @Summary 获取房间内的在线用户 // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Param groupId query string true "群ID" // @Success 200 {object} OnlineUserResult // @Router /v1/imGroup/online/users [get] func GroupInUsers(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) groupId := c.Query("groupId") if len(groupId) <= 0 { return myContext, bizerr.InvalidParameter } model := domain.CreateModelContext(myContext) groupId, err := group_m.ToImGroupId(model, groupId) if err != nil { return myContext, err } myContext.Log.WithField("groupId", groupId) userIds, err := group_m.RoomLivingExistsUserId(groupId) if err != nil { return myContext, err } myContext.Log.Infof("GroupInUsers userIds:%v", userIds) cacheDate, err := redisCli.GetRedis().Get(context.Background(), redis_key.GetGroupOnlineUser(groupId)).Result() if err != nil { //myContext.Log.Errorf("GroupInUsers GetRedis Get err:%v, groupId:%v", err, groupId) //查找数据库 return GroupInUsersDb(c, myContext, userIds, groupId) } else if cacheDate == "" { //查找数据库 return GroupInUsersDb(c, myContext, userIds, groupId) } else { onlineUserResult := OnlineUserResult{} if err := json.Unmarshal([]byte(cacheDate), &onlineUserResult); err != nil { myContext.Log.Errorf("GroupInUsers Unmarshal err:%v", err) //查找数据库 return GroupInUsersDb(c, myContext, userIds, groupId) } //对比数量 if len(userIds) != len(onlineUserResult.RedisUserIds) { myContext.Log.Infof("GroupInUsers cache groupId:%v size:%v RedisUserIds size:%v", groupId, len(userIds), len(onlineUserResult.RedisUserIds)) //查找数据库 return GroupInUsersDb(c, myContext, userIds, groupId) } else { //对比顺序 for i, _ := range userIds { //出现不一致 if userIds[i] != onlineUserResult.RedisUserIds[i] { myContext.Log.Infof("GroupInUsers cache groupId:%v RedisUserIds userId no same", groupId) return GroupInUsersDb(c, myContext, userIds, groupId) } } myContext.Log.Infof("GroupInUsers cache groupId:%v hit", groupId) resp.ResponseOk(c, onlineUserResult) return myContext, nil } } } type OnlineUserResult struct { Total int `json:"total"` Users []*user_cv.CvUserBase `json:"users"` ServiceTime int64 `json:"serviceTime"` //利用这个来判断是否要更新缓存 RedisUserIds []uint64 `json:"redisUserIds"` } //显示的最大数量是15个。 func GroupInUsersDb(c *gin.Context, myContext *mycontext.MyContext, userIds []uint64, groupId string) (*mycontext.MyContext, error) { userId, err := req.GetUserId(c) if err != nil { return myContext, err } if len(userIds) == 0 { if err != nil { return myContext, err } resp.ResponseOk(c, OnlineUserResult{ Total: len(userIds), Users: nil, }) return myContext, nil } //贵族 nobleLevelMap, err := noble_m.BatchGetNobleLevel(mysql.Db, userIds) if err != nil { return myContext, err } vipMap, err := user_m.BatchGetVips(userIds) if err != nil { return myContext, err } // var maxNum int = 15 vipList := make([]uint64, 0, maxNum) userList := make([]uint64, 0, maxNum) //认为需求中,不会再增加贵族6,贵族7了 nobleLevel5 := make([]uint64, 0, maxNum) nobleLevel4 := make([]uint64, 0, maxNum) nobleLevel3 := make([]uint64, 0, maxNum) nobleLevel2 := make([]uint64, 0, maxNum) nobleLevel1 := make([]uint64, 0, maxNum) // for i, userId := range userIds { if len(vipList)+len(userList) >= maxNum { break } if level, flag := nobleLevelMap[userId]; flag { if level == 5 { nobleLevel5 = append(nobleLevel5, userId) } else if level == 4 { nobleLevel4 = append(nobleLevel4, userId) } else if level == 3 { nobleLevel3 = append(nobleLevel3, userId) } else if level == 2 { nobleLevel2 = append(nobleLevel2, userId) } else if level == 1 { nobleLevel1 = append(nobleLevel1, userId) } else if level == 0 { if vipMap[userIds[i]] != nil { vipList = append(vipList, userIds[i]) } else { userList = append(userList, userIds[i]) } } } } myContext.Log.Infof("GroupInUsers vip and noble ready") //进入房间时间排序 roomUsers := []uint64{} if err := mysql.Db.Model(&group_m.GroupUser{}).Select("user_id").Where(&group_m.GroupUser{ GroupId: groupId, }).Where("user_id IN (?)", userList).Order("in_room_time DESC").Find(&roomUsers).Error; err != nil { return myContext, err } //转换成map roomUserMap := map[uint64]struct{}{} for i, _ := range roomUsers { roomUserMap[roomUsers[i]] = struct{}{} } // resultList := make([]uint64, 0, maxNum) resultList = append(resultList, nobleLevel5...) resultList = append(resultList, nobleLevel4...) resultList = append(resultList, nobleLevel3...) resultList = append(resultList, nobleLevel2...) resultList = append(resultList, nobleLevel1...) resultList = append(resultList, vipList...) resultList = append(resultList, roomUsers...) //预防groupRoom中没有数据的,毕竟进入房间的时候,异常没有处理 for i, _ := range userList { if _, flag := roomUserMap[userList[i]]; !flag { resultList = append(resultList, userList[i]) } } myContext.Log.Infof("GroupInUsers resultList ready") userBaseMap, err := user_cv.GetUserBaseMap(resultList, userId) if err != nil { return myContext, err } users := make([]*user_cv.CvUserBase, 0, maxNum) for i, _ := range resultList { if u, flag := userBaseMap[resultList[i]]; flag { users = append(users, u) } } onlineUserResult := OnlineUserResult{ Total: len(userIds), Users: users, ServiceTime: time.Now().Unix(), RedisUserIds: userIds, } resp.ResponseOk(c, onlineUserResult) if bytes, err := json.Marshal(onlineUserResult); err != nil { myContext.Log.Errorf("GroupInUsers Marshal err:%v", err) } else { if _, err := redisCli.GetRedis().Set(context.Background(), redis_key.GetGroupOnlineUser(groupId), string(bytes), 5*time.Minute).Result(); err != nil { myContext.Log.Infof("GroupInUsers cache Set groupId:%v, err:%v", groupId, err) } else { myContext.Log.Infof("GroupInUsers cache success groupId:%v", groupId) } } return myContext, nil } // @Tags 群组 // @Summary 获取房间内的在线用户 // @Param token header string true "token" // @Param nonce header string true "随机数字" // @Param groupId query string true "群ID" // @Success 200 {object} group_m.RoomOnlineUser // @Router /v1/imGroup/online/users/new [get] func GroupInUserNew(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) groupId := c.Query("groupId") if len(groupId) <= 0 { return myContext, bizerr.InvalidParameter } model := domain.CreateModelContext(myContext) groupId, err := group_m.ToImGroupId(model, groupId) if err != nil { return myContext, err } roomOnlineUser, err := group_m.GetRoomOnlineUser(myContext, groupId) //roomOnlineUser, err := cv.GetGroupInUser(myContext, groupId) if err != nil { return myContext, err } resp.ResponseOk(c, roomOnlineUser) 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 true "群ID" // @Success 200 {object} ResultGroupTheme // @Router /v1/imGroup/medal/all [get] func GroupMedalAll(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) groupId := c.Query("groupId") if len(groupId) <= 0 { return myContext, bizerr.InvalidParameter } model := domain.CreateModelContext(myContext) groupId, err := group_m.ToImGroupId(model, groupId) if err != nil { return myContext, err } resMedals := []res_m.ResMedal{} if 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). Where("(expire_at is null or expire_at > ?)", time.Now().Format(utils.DATETIME_FORMAT)). Order("res_medal.sort").Find(&resMedals).Error; err != nil { return myContext, err } returnGroupMedals := make([]medal_cv.ReturnGroupMedal, 0, len(resMedals)+1) // 补上房间流水勋章 var pe *medal_cv.PicElement _, pe, err = medal_cv.GetGroupConsumeMedal(model, groupId) if err != nil { model.Log.Infof("GetGroupConsumeMedal: %s", err.Error()) } else if pe != nil { returnGroupMedals = append(returnGroupMedals, medal_cv.ReturnGroupMedal{PicUrl: pe.PicUrl}) } for _, r := range resMedals { returnGroupMedals = append(returnGroupMedals, medal_cv.ReturnGroupMedal{ PicUrl: r.PicUrl, SvgaUrl: r.SvgaUrl, }) } resp.ResponseOk(c, returnGroupMedals) return myContext, nil } // @Tags 群组 // @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} group_cv.RoomMedalInfo // @Router /v1/imGroup/medal/room [get] func GetRoomMedal(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) userId, err := req.GetUserId(c) if err != nil { return myContext, err } groupId := c.Query("groupId") result := make([]group_cv.RoomMedalInfo, 0) model := domain.CreateModelContext(myContext) var consumeTotal uint64 if len(groupId) > 0 { groupId, err = group_m.ToImGroupId(model, groupId) if err != nil { return myContext, bizerr.GroupNotFound } } else { groups, err := group_m.FindGroupByOwner(model, userId) if err != nil { return myContext, err } if len(groups) > 0 { groupId = groups[0].ImGroupId } } if len(groupId) > 0 { consumeTotal, err = gift_cv.GetGroupConsumeTotal(model, groupId) if err != nil { return myContext, err } } model.Log.Infof("Room %s totoal consume = %d", groupId, consumeTotal) rec, err := res_m.GetRoomMedalConfig(model.Db) if err != nil { return myContext, err } ui, err := user_m.GetUser(model, userId) if err != nil { return myContext, err } lang := utils.DEFAULT_LANG if len(ui.Language) > 0 { lang = ui.Language } template, err := res_m.GetResMultiTextBy(model.Db, msg_e.MSG_ID_ROOM_MEADAL, lang) if err != nil { template = nil } for _, i := range rec { previewUrl := i.InactiveUrl if consumeTotal >= i.Threshold { previewUrl = i.ActiveUrl } desc := i.Desc if template != nil { num := strconv.Itoa(int(i.Threshold)/1000000) + "M" desc = fmt.Sprintf(template.Content, num) } result = append(result, group_cv.RoomMedalInfo{ Level: i.Level, PreviewUrl: previewUrl, PicUrl: i.ActiveUrl, Desc: desc, }) } resp.ResponseOk(c, result) return myContext, nil }