From 7e150eb673ed95c44f19ecb0e876c8257a670410 Mon Sep 17 00:00:00 2001 From: hujiebin Date: Tue, 20 Jun 2023 16:03:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E8=BF=81=E7=A7=BB=E5=BE=88ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _const/redis_key/user_k/keys.go | 8 ++ cv/user_cv/user.go | 92 +++++++------ domain/model/country_m/country_mgr.go | 40 ++++++ domain/model/groupPower_m/groupPower.go | 17 +++ domain/model/group_m/groupInfo.go | 56 ++++++++ domain/model/group_m/role.go | 80 +++++++++++ domain/model/tim_m/user.go | 27 ++++ domain/model/user_m/count.go | 19 +++ domain/model/user_m/superManager.go | 24 ++-- domain/model/user_m/userBindInfo.go | 38 ++++++ domain/model/user_m/userOauth.go | 35 +++++ domain/model/user_m/user_trade_union.go | 44 ++++++ domain/model/visit_m/repo.go | 7 + domain/model/visit_m/visit.go | 36 +++++ domain/service/cp_s/cp.go | 83 ++++++++++++ domain/service/user_s/user.go | 173 ++++++++++++++++++++++-- domain/service/user_s/util.go | 98 ++++++++++++++ route/router.go | 3 +- route/user_r/user.go | 76 ++++++++++- 19 files changed, 889 insertions(+), 67 deletions(-) create mode 100644 domain/model/country_m/country_mgr.go create mode 100644 domain/model/group_m/role.go create mode 100644 domain/model/tim_m/user.go create mode 100644 domain/model/user_m/count.go create mode 100644 domain/model/user_m/userBindInfo.go create mode 100644 domain/model/user_m/userOauth.go create mode 100644 domain/model/user_m/user_trade_union.go create mode 100644 domain/model/visit_m/repo.go create mode 100644 domain/model/visit_m/visit.go create mode 100644 domain/service/cp_s/cp.go create mode 100644 domain/service/user_s/util.go diff --git a/_const/redis_key/user_k/keys.go b/_const/redis_key/user_k/keys.go index c8af465..4792bb2 100755 --- a/_const/redis_key/user_k/keys.go +++ b/_const/redis_key/user_k/keys.go @@ -4,6 +4,8 @@ import ( "fmt" "git.hilo.cn/hilo-common/resource/mysql" "hilo-user/_const/redis_key" + "strconv" + "strings" ) const ( @@ -28,3 +30,9 @@ func GetExternalIdToUidKey(externalId mysql.Str) string { func GetCodeToUidKey(code mysql.Str) string { return redis_key.ReplaceKey(UserCodeToUIdStr, code) } + +const syncTimHiloLock = "sync_tim_hilo_{userId}" + +func GetKeySyncTimHilo(userId uint64) string { + return strings.Replace(syncTimHiloLock, "{userId}", strconv.FormatUint(userId, 10), -1) +} diff --git a/cv/user_cv/user.go b/cv/user_cv/user.go index 7c21fbd..ca92a6e 100644 --- a/cv/user_cv/user.go +++ b/cv/user_cv/user.go @@ -1,12 +1,14 @@ package user_cv import ( + "git.hilo.cn/hilo-common/_const/common" "git.hilo.cn/hilo-common/domain" "git.hilo.cn/hilo-common/mylogrus" "git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/rpc" "gorm.io/gorm" "hilo-user/_const/enum/country_e" + "hilo-user/_const/enum/cp_e" "hilo-user/cv/headwear_cv" "hilo-user/cv/medal_cv" "hilo-user/cv/noble_cv" @@ -102,6 +104,7 @@ type CvUserBase struct { Headwear *headwear_cv.CvHeadwear `json:"headwear"` // 当前使用的头饰 Ride property_cv.CvProperty `json:"ride"` // 当前使用的座驾 Noble noble_cv.CvNoble `json:"noble"` // 当前的 + GroupRole common.GroupRoleType `json:"groupRole"` // 在群组的角色 } //批量获取用户基本信息 @@ -157,7 +160,7 @@ func GetUserBases(userIds []mysql.ID, myUserId mysql.ID) ([]*CvUserBase, error) return nil, err } - superManagerMap, err := GetSuperManagerMap(userIds) + superManagerMap, err := user_m.GetSuperManagerMap(userIds) if err != nil { return nil, err } @@ -310,25 +313,6 @@ func GetPropertyAll(db *gorm.DB) (map[uint64]property_cv.CvProperty, error) { return result, nil } -func GetSuperManagerMap(userIds []uint64) (map[uint64]bool, error) { - if len(userIds) == 0 { - return map[uint64]bool{}, nil - } - var superManagers []user_m.SuperManager - if err := mysql.Db.Model(&user_m.SuperManager{}).Where("user_id in (?)", userIds).Find(&superManagers).Error; err != nil { - return nil, myerr.WrapErr(err) - } - //转换成map - rs := map[uint64]bool{} - for i, _ := range userIds { - rs[userIds[i]] = false - } - for i, _ := range superManagers { - rs[superManagers[i].UserId] = true - } - return rs, nil -} - func GetUserBaseMap(userIds []mysql.ID, myUserId mysql.ID) (map[mysql.ID]*CvUserBase, error) { userBases, err := GetUserBases(userIds, myUserId) if err != nil { @@ -383,29 +367,22 @@ type CvUserDetail struct { //是否可以免费通话,自己本人没有数据 //IsVideoFreeCan *bool `json:"isVideoCanFree"` //别人是否喜欢我,自己本人没有数据 (20210205 已废弃nil,产品说:可以自己喜欢自己) - IsLikeMe *bool `json:"isLikeMe"` - HeartValue uint32 `json:"heartValue"` // 与我之间永恒之心的值 - HeartValueMax uint32 `json:"heartValueMax"` // 与我之间永恒之心的最大值(0代表没有永恒之心,即没有相互关注) - MeetDays uint `json:"meetDays"` // 成长关系建立的时间(天数) - WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级 - CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级 - ActivityUserGrade uint32 `json:"activityUserGrade"` //活跃等级 - CurrentRoom string `json:"currentRoom"` // 当前用户所在房间(产品叫“群组”) - MyGroupPower uint64 `json:"myGroupPower"` // 当前用户所在势力 - MyGroupPowerName string `json:"myGroupPowerName"` // 当前用户所在势力绑定群组的名称 - GroupPower rpc.CvGroupPowerInfo `json:"groupPower"` // 家族 - GroupId string `json:"groupId"` // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个 - PhoneInfo *UserPhoneInfo `json:"phoneInfo"` // 用户绑定的手机信息 - ThirdList []int8 `json:"thirdList"` // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5) - CountryManager *CVCountryManager `json:"countryManager,omitempty"` // 国家管理员 - Cp *rpc.CvCp `json:"cp,omitempty"` // cp信息 -} - -type UserPhoneInfo struct { - Phone string `json:"phone"` - PhoneCountry string `json:"phoneCountry"` - AreaCode string `json:"areaCode"` - Icon string `json:"icon"` + IsLikeMe *bool `json:"isLikeMe"` + HeartValue uint32 `json:"heartValue"` // 与我之间永恒之心的值 + HeartValueMax uint32 `json:"heartValueMax"` // 与我之间永恒之心的最大值(0代表没有永恒之心,即没有相互关注) + MeetDays uint `json:"meetDays"` // 成长关系建立的时间(天数) + WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级 + CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级 + ActivityUserGrade uint32 `json:"activityUserGrade"` //活跃等级 + CurrentRoom string `json:"currentRoom"` // 当前用户所在房间(产品叫“群组”) + MyGroupPower uint64 `json:"myGroupPower"` // 当前用户所在势力 + MyGroupPowerName string `json:"myGroupPowerName"` // 当前用户所在势力绑定群组的名称 + GroupPower rpc.CvGroupPowerInfo `json:"groupPower"` // 家族 + GroupId string `json:"groupId"` // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个 + PhoneInfo *user_m.UserPhoneInfo `json:"phoneInfo"` // 用户绑定的手机信息 + ThirdList []int8 `json:"thirdList"` // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5) + CountryManager *CVCountryManager `json:"countryManager,omitempty"` // 国家管理员 + Cp *CvCp `json:"cp,omitempty"` // cp信息 } // cv国家管理人员 @@ -413,3 +390,32 @@ type CVCountryManager struct { Country string `json:"country"` // 国家name Role country_e.CountryMgrRole `json:"role" swaggertype:"integer"` // 角色 1:国家管理员 2:国家助理 } + +// cp信息 +type CvCp struct { + CpUserInfo *CvUserBase `json:"cpUserInfo"` // cp用户信息 + CpLevel CvCpLevel `json:"cpLevel"` // cp等级 + MyPrivilegeList []CvPrivilege `json:"myPrivilegeList"` // 等级特权 + CreatedUnix int64 `json:"createdUnix"` // cp创建时间 + CpDays int `json:"cpDays"` // cp天数 +} + +// cp关系 +type CvCpRelation struct { + CpId uint64 `json:"cpId"` + UserId uint64 `json:"userId"` + CpUserId uint64 `json:"cpUserId"` + CpUserAvatar string `json:"cpUserAvatar,omitempty"` +} + +// cp等级 +type CvCpLevel struct { + Level cp_e.CpLevel `json:"level"` // 等级 0:无称号 1:恋爱CP 2:甜蜜CP 3:忠诚CP 4:炽热CP 5:荣耀CP + Points uint32 `json:"points"` // CP值 + Title string `json:"title,omitempty"` // 称号翻译 +} + +// 特权信息 +type CvPrivilege struct { + Type cp_e.CpPrivilege `json:"type"` // 特权id 1:空间 2:横幅 3:等级勋章 4:证书 5:进场特效 6:头像头饰 7:动态资料卡 8:麦位特效 +} diff --git a/domain/model/country_m/country_mgr.go b/domain/model/country_m/country_mgr.go new file mode 100644 index 0000000..d568e97 --- /dev/null +++ b/domain/model/country_m/country_mgr.go @@ -0,0 +1,40 @@ +package country_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "hilo-user/_const/enum/country_e" + "hilo-user/myerr" +) + +type CountryMgrUser struct { + mysql.Entity + Country string + UserId mysql.ID + Role country_e.CountryMgrRole +} + +// 获取国家管理人员 +func GetCountryMgr(model *domain.Model, userId mysql.ID) (*CountryMgrUser, error) { + cmu := new(CountryMgrUser) + if err := model.Db.WithContext(model.MyContext.Context).Where("user_id = ?", userId).First(&cmu).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, myerr.WrapErr(err) + } + } + return cmu, nil +} + +// 更新国家管理人员 +func (cmu *CountryMgrUser) UpdateCountryMgr(userId mysql.ID, role country_e.CountryMgrRole, country string) *CountryMgrUser { + cmu.UserId, cmu.Role, cmu.Country = userId, role, country + return cmu +} + +// 删除国家管理人员 +func (cmu *CountryMgrUser) DeleteCountryMgr() { + cmu.SetDel() +} diff --git a/domain/model/groupPower_m/groupPower.go b/domain/model/groupPower_m/groupPower.go index a427d5a..054d4d1 100644 --- a/domain/model/groupPower_m/groupPower.go +++ b/domain/model/groupPower_m/groupPower.go @@ -17,6 +17,14 @@ type GroupPowerUser struct { Role groupPower_e.GroupPowerUserRole } +type GroupPower struct { + mysql.Entity + *domain.Model `gorm:"-"` + GroupUid mysql.Str + Name mysql.Str + Status groupPower_e.GroupPowerStatus +} + // 查询用户加入的国家势力ID及名称(势力绑定的群组的名称) func GetUserGroupPower(model *domain.Model, userId uint64) (uint64, string, error) { gpu, err := GetGroupPowerUserOrNil(model, userId) @@ -65,3 +73,12 @@ func GetGroupPowerUserOrNil(model *domain.Model, userId mysql.ID) (*GroupPowerUs groupPowerUser.Model = model return &groupPowerUser, nil } + +func GetGroupPowerOrErr(model *domain.Model, id uint64) (*GroupPower, error) { + groupPower := GroupPower{} + if err := model.Db.Model(&GroupPower{}).First(&groupPower, id).Error; err != nil { + return nil, myerr.WrapErr(err) + } + groupPower.Model = model + return &groupPower, nil +} diff --git a/domain/model/group_m/groupInfo.go b/domain/model/group_m/groupInfo.go index d51ac9f..cf0c798 100644 --- a/domain/model/group_m/groupInfo.go +++ b/domain/model/group_m/groupInfo.go @@ -51,3 +51,59 @@ func GetGroupInfo(model *domain.Model, groupId string) (*GroupInfo, error) { } return &r, nil } + +func FindGroupByOwner(model *domain.Model, ownerId uint64) ([]GroupInfo, error) { + rows := make([]GroupInfo, 0) + err := model.Db.Where(&GroupInfo{Owner: ownerId}).Find(&rows).Error + if err != nil { + return nil, err + } + return rows, nil +} + +func ToTxGroupId(model *domain.Model, imGroupId string) (string, error) { + if len(imGroupId) <= 0 { + return "", nil + } + + gi, err := GetGroupInfo(model, imGroupId) + if err != nil { + return "", err + } + if gi == nil { + return "", bizerr.GroupNotFound + } + return gi.TxGroupId, nil +} + +func ToImGroupId(model *domain.Model, txGroupId string) (string, error) { + if len(txGroupId) <= 0 { + return "", nil + } + + gi, err := GetInfoByTxGroupId(model, txGroupId) + if err != nil { + return "", err + } + if gi == nil { + return "", bizerr.GroupNotFound + } + return gi.ImGroupId, nil +} + +func GetInfoByTxGroupId(model *domain.Model, txGroupId string) (*GroupInfo, error) { + if len(txGroupId) <= 0 { + return nil, bizerr.GroupNotFound + } + + r := GroupInfo{} + err := model.Db.Where(&GroupInfo{TxGroupId: txGroupId}).First(&r).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } + return &r, nil +} diff --git a/domain/model/group_m/role.go b/domain/model/group_m/role.go new file mode 100644 index 0000000..bd0bf77 --- /dev/null +++ b/domain/model/group_m/role.go @@ -0,0 +1,80 @@ +package group_m + +import ( + "git.hilo.cn/hilo-common/_const/common" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" +) + +type GroupRoles struct { + mysql.Entity + UserId uint64 + ImGroupId string + Role common.GroupRoleType +} + +type GroupMember struct { + GroupId string + UserId uint64 +} + +func (gm *GroupMember) Find(db *gorm.DB) ([]GroupMember, error) { + rows := make([]GroupMember, 0) + if err := db.Where(gm).Order("created_time DESC").Find(&rows).Error; err != nil { + return nil, err + } + return rows, nil +} + +func GetGroupRoleById(model *domain.Model, imGroupId string, userId uint64) (role common.GroupRoleType, err error) { + role = common.GROUP_VISITOR + roles, _, err := GetRolesInGroup(model, imGroupId) + if err != nil { + return + } + for u, r := range roles { + if u == userId { + role = r + return + } + } + + isGroupMember, err := IsGroupMember(model.Db, imGroupId, userId) + if err != nil { + return + } + if isGroupMember { + role = common.GROUP_MEMBER + } + return +} + +// 查询群组中所有有角色的成员,由级别高到低、创建时间由早到晚排列 +func GetRolesInGroup(model *domain.Model, groupId string) (map[uint64]uint16, []uint64, error) { + data := make([]GroupRoles, 0) + err := model.Db.Where(&GroupRoles{ImGroupId: groupId}).Order("role DESC, created_time").Find(&data).Error + if err != nil { + return nil, nil, err + } + + result := make(map[uint64]uint16, 0) + orders := make([]uint64, 0) + for _, i := range data { + orders = append(orders, i.UserId) + result[i.UserId] = i.Role + } + return result, orders, nil +} + +func IsGroupMember(db *gorm.DB, groupId string, userId uint64) (bool, error) { + gm := GroupMember{ + GroupId: groupId, + UserId: userId, + } + rows, err := gm.Find(db) + if err != nil { + return false, err + } + return len(rows) > 0, nil +} diff --git a/domain/model/tim_m/user.go b/domain/model/tim_m/user.go new file mode 100644 index 0000000..f26b72d --- /dev/null +++ b/domain/model/tim_m/user.go @@ -0,0 +1,27 @@ +package tim_m + +import ( + "encoding/json" + "git.hilo.cn/hilo-common/sdk/tencentyun" +) + +type TimHiloInfo struct { + IsVip bool `json:"isVip"` + IsPretty bool `json:"isPretty"` + Medals []uint32 `json:"medals"` + PowerName string `json:"powerName"` // 用户加入的国家势力的绑定群组的名称 + NobleLevel uint16 `json:"nobleLevel"` +} + +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 +} diff --git a/domain/model/user_m/count.go b/domain/model/user_m/count.go new file mode 100644 index 0000000..766ac6f --- /dev/null +++ b/domain/model/user_m/count.go @@ -0,0 +1,19 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "hilo-user/_const/enum/user_e" +) + +//用户统计 +type UserCount struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + Type user_e.CountType + Num mysql.Num + isAdd bool `gorm:"-"` + isReduce bool `gorm:"-"` + addReduceNum mysql.Num `gorm:"-"` +} diff --git a/domain/model/user_m/superManager.go b/domain/model/user_m/superManager.go index 12e4483..e558088 100644 --- a/domain/model/user_m/superManager.go +++ b/domain/model/user_m/superManager.go @@ -65,15 +65,21 @@ func GetSuperManagerAll(model *domain.Model) ([]uint64, error) { return userIds, nil } -/* -func GetSuperManagerMap(model *domain.Model) (map[uint64]struct{}, error) { - userIds, err := GetSuperManagerAll(model) - if err != nil { - return nil, err +func GetSuperManagerMap(userIds []uint64) (map[uint64]bool, error) { + if len(userIds) == 0 { + return map[uint64]bool{}, nil + } + var superManagers []SuperManager + if err := mysql.Db.Model(&SuperManager{}).Where("user_id in (?)", userIds).Find(&superManagers).Error; err != nil { + return nil, myerr.WrapErr(err) } - userIdMap := map[uint64]struct{}{} + //转换成map + rs := map[uint64]bool{} for i, _ := range userIds { - userIdMap[userIds[i]] = struct{}{} + rs[userIds[i]] = false } - return userIdMap, nil -}*/ + for i, _ := range superManagers { + rs[superManagers[i].UserId] = true + } + return rs, nil +} diff --git a/domain/model/user_m/userBindInfo.go b/domain/model/user_m/userBindInfo.go new file mode 100644 index 0000000..41cc2df --- /dev/null +++ b/domain/model/user_m/userBindInfo.go @@ -0,0 +1,38 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "time" +) + +type UserBindInfo struct { + UserId uint64 `json:"user_id"` + Phone string `json:"phone"` + PhoneCountry string `json:"phone_country"` + Pwd string `json:"pwd"` + AreaCode string `json:"area_code"` + Icon string `json:"icon"` + CreateAt time.Time `json:"create_at"` + UpdateAt time.Time `json:"update_at"` +} + +func (*UserBindInfo) TableName() string { + return "user_bind_info" +} + +type UserPhoneInfo struct { + Phone string `json:"phone"` + PhoneCountry string `json:"phoneCountry"` + AreaCode string `json:"areaCode"` + Icon string `json:"icon"` +} + +// 获取用户手机号绑定信息 +func GetUserBindInfoByUserId(model *domain.Model, userId uint64) (*UserBindInfo, error) { + res := new(UserBindInfo) + err := model.DB().Where(&UserBindInfo{UserId: userId}).First(&res).Error + if err != nil { + return nil, err + } + return res, nil +} diff --git a/domain/model/user_m/userOauth.go b/domain/model/user_m/userOauth.go new file mode 100644 index 0000000..d1769f0 --- /dev/null +++ b/domain/model/user_m/userOauth.go @@ -0,0 +1,35 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "gorm.io/gorm" + "hilo-user/myerr" +) + +type UserOauth struct { + UserId uint64 `json:"user_id"` + ThirdPartyId string `json:"third_party_id"` + ThirdPartyType int8 `json:"third_party_type"` +} + +func (*UserOauth) TableName() string { + return "user_oauth" +} + +// 根据id获取第三方登录信息 +func GetUserOauthByUserId(model *domain.Model, userId uint64, thirdType uint8) ([]*UserOauth, error) { + res := make([]*UserOauth, 0) + db := model.DB().Where(&UserOauth{UserId: userId}) + if thirdType > 0 { + db = db.Where(&UserOauth{ThirdPartyType: int8(thirdType)}) + } + err := db.Find(&res).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, myerr.WrapErr(err) + } + } + return res, nil +} diff --git a/domain/model/user_m/user_trade_union.go b/domain/model/user_m/user_trade_union.go new file mode 100644 index 0000000..df3d697 --- /dev/null +++ b/domain/model/user_m/user_trade_union.go @@ -0,0 +1,44 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "hilo-user/myerr" +) + +type UserTradeUnion struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + MatchNotification mysql.OpenClose + AgentId mysql.ID + StarchatId mysql.ID + Avatar string +} + +func GetUserTradeUnion(userId mysql.ID) (*UserTradeUnion, error) { + var userTradeUnion UserTradeUnion + if err := mysql.Db.Where(UserTradeUnion{ + UserId: userId, + }).First(&userTradeUnion).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, myerr.WrapErr(err) + } + } + return &userTradeUnion, nil +} + +type AgentMgr struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + AgentId mysql.ID +} + +func IsAgent(userId uint64) bool { + data := AgentMgr{} + return mysql.Db.Where(&AgentMgr{UserId: userId}).First(&data).Error == nil +} diff --git a/domain/model/visit_m/repo.go b/domain/model/visit_m/repo.go new file mode 100644 index 0000000..d677ea5 --- /dev/null +++ b/domain/model/visit_m/repo.go @@ -0,0 +1,7 @@ +package visit_m + +import "hilo-user/domain/model" + +func (userVisit *UserVisit) Persistent() error { + return model.Persistent(userVisit.Db, userVisit) +} diff --git a/domain/model/visit_m/visit.go b/domain/model/visit_m/visit.go new file mode 100644 index 0000000..a38f38b --- /dev/null +++ b/domain/model/visit_m/visit.go @@ -0,0 +1,36 @@ +package visit_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "hilo-user/myerr" +) + +type UserVisit struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + VisitUserId mysql.ID + N mysql.Num +} + +func GetVisitInstanceOrInit(model *domain.Model, userId mysql.ID, visitUserId mysql.ID) (*UserVisit, error) { + var userVisit UserVisit + if err := model.Db.Where(&UserVisit{ + UserId: userId, + VisitUserId: visitUserId, + }).FirstOrInit(&userVisit, UserVisit{ + UserId: userId, + VisitUserId: visitUserId, + N: 0, + }).Error; err != nil { + return nil, myerr.WrapErr(err) + } + userVisit.Model = model + return &userVisit, nil +} + +func (userVisit *UserVisit) UserVisitAdd() *UserVisit { + userVisit.N = userVisit.N + 1 + return userVisit +} diff --git a/domain/service/cp_s/cp.go b/domain/service/cp_s/cp.go new file mode 100644 index 0000000..5a7d890 --- /dev/null +++ b/domain/service/cp_s/cp.go @@ -0,0 +1,83 @@ +package cp_s + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mycontext" + "hilo-user/_const/enum/cp_e" + "hilo-user/cv/cp_cv" + "hilo-user/cv/user_cv" + "hilo-user/domain/model/cp_m" + "time" +) + +type CpService struct { + svc *domain.Service +} + +func NewCpService(myContext *mycontext.MyContext) *CpService { + svc := domain.CreateService(myContext) + return &CpService{svc} +} + +// 获取用户cp信息 +func (s *CpService) GetUserCp(userId uint64, lang string) (*user_cv.CvCp, error) { + var model = domain.CreateModelContext(s.svc.MyContext) + cpLevel := cp_e.CpLevel0 + cpRelation, exists := cp_m.GetCpRelation(model, userId) + if !exists { + return nil, nil + } + var myPrivilegeList []user_cv.CvPrivilege + level := cp_m.GetCpLevel(model, cpRelation.Id) + if level.ExpireAt.Before(time.Now()) { + level.ExpireAt = time.Now().AddDate(0, 1, 0) + } + cpLevel = level.Level + cpUserId := cpRelation.UserId2 + if cpUserId == userId { + cpUserId = cpRelation.UserId1 + } + userPrivileges, err := cp_m.MGetUserSvipPrivilege(model, []uint64{userId}) + if err != nil { + return nil, err + } + privilegeList := cp_cv.CopyCpLevelPrivilegeList(level.Level, "en") + for i, v := range privilegeList { + if v.CanSwitch { + privilegeList[i].UserSwitch = userPrivileges[userId][v.Type] + } + } + // 我的特权,有开关并且打开才返回 + for _, v := range privilegeList { + if !v.CanSwitch { + myPrivilegeList = append(myPrivilegeList, user_cv.CvPrivilege{Type: v.Type}) + } else if v.UserSwitch { + myPrivilegeList = append(myPrivilegeList, user_cv.CvPrivilege{Type: v.Type}) + } + } + userBases, err := user_cv.GetUserBaseMap([]uint64{cpUserId}, userId) + if err != nil { + return nil, err + } + // 返回值 + title := cp_cv.GetTranslate(237, lang) + if msgId, ok := cp_e.CpLevelTitle[level.Level]; ok { + title = cp_cv.GetTranslate(msgId, lang) + } + var oldScore uint32 + if oldCp, _ := cp_m.GetOldConnectCp(model, cpRelation.UserId1, cpRelation.UserId2); oldCp != nil { + oldScore = uint32(oldCp.Score) + } + response := &user_cv.CvCp{ + CpUserInfo: userBases[cpUserId], + CpLevel: user_cv.CvCpLevel{ + Level: cpLevel, + Points: oldScore + cp_m.SumCpPoints(model, cpRelation.Id), // 历史分数 + Title: title, + }, + MyPrivilegeList: myPrivilegeList, + CpDays: int(time.Now().Sub(cpRelation.CreatedTime).Hours()/24) + 1, + CreatedUnix: cpRelation.CreatedTime.Unix(), + } + return response, nil +} diff --git a/domain/service/user_s/user.go b/domain/service/user_s/user.go index 0cb7214..f8f0e8c 100644 --- a/domain/service/user_s/user.go +++ b/domain/service/user_s/user.go @@ -6,13 +6,20 @@ import ( "git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/rpc" "gorm.io/gorm" + "hilo-user/_const/enum/user_e" "hilo-user/cv/headwear_cv" "hilo-user/cv/medal_cv" + "hilo-user/cv/noble_cv" "hilo-user/cv/property_cv" "hilo-user/cv/user_cv" + "hilo-user/domain/model/country_m" + "hilo-user/domain/model/diamond_m" + "hilo-user/domain/model/groupPower_m" "hilo-user/domain/model/group_m" "hilo-user/domain/model/noble_m" "hilo-user/domain/model/user_m" + "hilo-user/domain/model/visit_m" + "hilo-user/domain/service/cp_s" "hilo-user/myerr" ) @@ -26,7 +33,7 @@ func NewUserService(myContext *mycontext.MyContext) *UserService { } //用户基本信息 -func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ...string) (*user_cv.CvUserDetail, error) { +func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang string) (*user_cv.CvUserDetail, error) { model := domain.CreateModelContext(s.svc.MyContext) model.Log.Infof("GetUserDetail %d begin", userId) var user user_m.User @@ -56,7 +63,7 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... rel[userId], _ = user_m.GetRelation(model, myUserId, userId) var wealthUserScore user_m.MatchWealthUserScore - if err := mysql.Db.Model(&user_m.MatchWealthUserScore{}).Where(&user_m.MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil { + if err := model.DB().Model(&user_m.MatchWealthUserScore{}).Where(&user_m.MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil { if err != nil { if err == gorm.ErrRecordNotFound { wealthUserScore = user_m.MatchWealthUserScore{ @@ -71,7 +78,7 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... } var charmUserScore user_m.MatchCharmUserScore - if err := mysql.Db.Model(&user_m.MatchCharmUserScore{}).Where(&user_m.MatchCharmUserScore{ + if err := model.DB().Model(&user_m.MatchCharmUserScore{}).Where(&user_m.MatchCharmUserScore{ UserId: userId, }).First(&charmUserScore).Error; err != nil { if err != nil { @@ -88,7 +95,7 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... } var activityUserScore user_m.MatchActityUserScore - if err := mysql.Db.Model(&user_m.MatchActityUserScore{}).Where(&user_m.MatchActityUserScore{ + if err := model.DB().Model(&user_m.MatchActityUserScore{}).Where(&user_m.MatchActityUserScore{ UserId: userId, }).First(&activityUserScore).Error; err != nil { if err != nil { @@ -142,7 +149,10 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... rooms[userId] = "" } } - cp, _ := rpc.GetUserCp(model, userId, lang...) // todo last + cp, err := cp_s.NewCpService(s.svc.MyContext).GetUserCp(userId, lang) + if err != nil { + return nil, err + } groupPowerId, groupPowerName, err := groupPower_m.GetUserGroupPower(model, userId) if err != nil { @@ -178,12 +188,12 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... } //判断是不是工会 - userTradeUnion, err := bv.GetUserTradeUnion(myUserId) + userTradeUnion, err := user_m.GetUserTradeUnion(myUserId) if err != nil { return nil, err } - superManagerMap, err := GetSuperManagerMap([]uint64{userId}) + superManagerMap, err := user_m.GetSuperManagerMap([]uint64{userId}) if err != nil { return nil, err } @@ -196,12 +206,12 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... // 手机绑定信息 // 第三方账号绑定信息 - phoneInfo := new(model2.UserPhoneInfo) + phoneInfo := new(user_m.UserPhoneInfo) var thirdList []int8 if userId == myUserId { thirdList = make([]int8, 0, 5) // 手机绑定信息 - bindInfo, err := dao.UserBindInfoDb.GetByUserId(userId) + bindInfo, err := user_m.GetUserBindInfoByUserId(model, userId) if err != nil && err != gorm.ErrRecordNotFound { return nil, err } @@ -215,7 +225,7 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... thirdList = append(thirdList, 1) } // 第三方账号绑定信息 - thirdInfoList, err := dao.UserOauthDb.GetByUserId(userId, 0) + thirdInfoList, err := user_m.GetUserOauthByUserId(model, userId, 0) if err != nil { return nil, err } @@ -230,9 +240,9 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... if err != nil { return nil, err } - var cvCountryManager *CVCountryManager + var cvCountryManager *user_cv.CVCountryManager if countryManager != nil { - cvCountryManager = &CVCountryManager{ + cvCountryManager = &user_cv.CVCountryManager{ Country: countryManager.Country, Role: countryManager.Role, } @@ -243,3 +253,142 @@ func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ... activityUserScore.Grade, medals[userId], medalInfo[userId], rooms[userId], powers[userId], powerNames[userId], groupPower, noble, superManagerMap[userId], myGroups, phoneInfo, thirdList, cvCountryManager, cp) } + +// 单用户版,简化参数 +func userToDetailOne(model *domain.Model, user *user_m.User, myUserId mysql.ID, userTradeUnion *user_m.UserTradeUnion, isLike bool, likeMe bool, hvMap map[mysql.ID]user_m.Relation, + isVip bool, vipExpireTime *int64, svip rpc.CvSvip, headwear *headwear_cv.CvHeadwear, ride property_cv.CvProperty, wealthGrade uint32, charmGrade uint32, activityGrade uint32, + medals []uint32, medalInfo []medal_cv.CvMedal, room string, power uint64, powerName string, groupPower rpc.CvGroupPowerInfo, noble *noble_m.UserNoble, isOfficialStaff bool, + myGroups []group_m.GroupInfo, phoneInfo *user_m.UserPhoneInfo, thirdList []int8, countryManager *user_cv.CVCountryManager, cp *user_cv.CvCp) (*user_cv.CvUserDetail, error) { + + room, err := group_m.ToTxGroupId(model, room) + if err != nil { + model.Log.Warnf("ToTxGroupId failed for %s, err:%v", room, err) + room = "" + } + + cvUserDetail := &user_cv.CvUserDetail{ + CvUserBase: user_cv.CvUserBase{ + Id: &user.ID, + Avatar: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar)), + DefaultAvatar: &user.DefaultAvatar, + ExternalId: StrToString(&user.ExternalId), + Nick: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), user.Code, user.Nick)), + Description: StrNil(IfLogoutStr(IfLogout(user.LogoutTime), "", user.Description)), + Sex: TypeToUint8(&user.Sex), + Country: StrNil(user.Country), + CountryIcon: StrNil(user.CountryIcon), + Code: StrToString(&user.Code), + IsPrettyCode: user.IsPrettyCode(), + IsVip: isVip, + IsOfficialStaff: isOfficialStaff, + VipExpireTime: vipExpireTime, + Svip: svip, + MedalInfo: IfLogoutMedalInfo(IfLogout(user.LogoutTime), []medal_cv.CvMedal{}, medalInfo), + Headwear: IfLogoutHeadwear(IfLogout(user.LogoutTime), nil, headwear), + Ride: IfLogoutRide(IfLogout(user.LogoutTime), property_cv.CvProperty{}, ride), + }, + IsPush: TypeToUint8(&user.IsPush), + IsLike: &isLike, + IsLikeMe: &likeMe, + WealthUserGrade: wealthGrade, + CharmUserGrade: charmGrade, + ActivityUserGrade: activityGrade, + CurrentRoom: room, + MyGroupPower: power, + MyGroupPowerName: powerName, + GroupPower: groupPower, + PhoneInfo: phoneInfo, + ThirdList: thirdList, + CountryManager: countryManager, + Cp: cp, + } + if noble != nil { + cvUserDetail.Noble = noble_cv.CvNoble{ + Level: noble.Level, + EndTime: noble.EndTime.Unix(), + } + } + + //本人,计算,喜欢统计,钻石数量 + if user.ID == myUserId { + cvUserDetail.IsShowAge = TypeToUint8((*mysql.Type)(&user.IsShowAge)) + cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday) + + //喜欢统计 + var userCount user_m.UserCount + err := model.DB().Where(&user_m.UserCount{ + UserId: myUserId, + Type: user_e.CountTypeLikeMe, + }).First(&userCount).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, myerr.WrapErr(err) + } + cvUserDetail.LikeCount = NumToUint32(&userCount.Num) + + //我喜欢统计 + var userILikeCount user_m.UserCount + err = mysql.Db.Where(&user_m.UserCount{ + UserId: myUserId, + Type: user_e.CountTypeLike, + }).First(&userILikeCount).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, myerr.WrapErr(err) + } + cvUserDetail.ILikeCount = NumToUint32(&userILikeCount.Num) + + //访问统计 + var visitCount int64 + err = mysql.Db.Model(&visit_m.UserVisit{}).Where(&visit_m.UserVisit{ + VisitUserId: myUserId, + }).Count(&visitCount).Error + if err != nil && err != gorm.ErrRecordNotFound { + return nil, myerr.WrapErr(err) + } + vc := uint32(visitCount) + cvUserDetail.VisitCount = NumToUint32((*mysql.Num)(&vc)) + + //钻石数量 + cvDiamond, err := diamond_m.GetDiamondAccountByUserId(model, myUserId) + if err != nil { + return nil, err + } + cvUserDetail.DiamondNum = &cvDiamond.DiamondNum + cvUserDetail.PinkDiamondNum = &cvDiamond.PinkDiamondNum + + isAgent := user_m.IsAgent(myUserId) + cvUserDetail.IsAgentMgr = &isAgent + } else { + //不是本人 + if user.IsShowAge == mysql.OPEN { + cvUserDetail.Birthday = BirthdayToUint64(&user.Birthday) + } + } + + if userTradeUnion == nil { + isTradeUnionFlag := false + cvUserDetail.IsTradeUnion = &isTradeUnionFlag + cvUserDetail.IsTradeUnionMatchNotification = nil + } else { + isTradeUnionFlag := true + cvUserDetail.IsTradeUnion = &isTradeUnionFlag + isTradeUnionMatchNotificationFlag := userTradeUnion.MatchNotification == mysql.OPEN + cvUserDetail.IsTradeUnionMatchNotification = &isTradeUnionMatchNotificationFlag + } + + // 永恒之心的值 + hv, ok := hvMap[user.ID] + if ok { + cvUserDetail.HeartValue = hv.HeartValue + cvUserDetail.HeartValueMax = hv.HeartValueMax + cvUserDetail.MeetDays = hv.MeetDays + } else { + cvUserDetail.HeartValueMax = 0 + } + + // 拥有的群组id + if len(myGroups) > 0 { + cvUserDetail.GroupId = myGroups[0].TxGroupId + } + + return cvUserDetail, nil +} diff --git a/domain/service/user_s/util.go b/domain/service/user_s/util.go new file mode 100644 index 0000000..7ff0777 --- /dev/null +++ b/domain/service/user_s/util.go @@ -0,0 +1,98 @@ +package user_s + +import ( + "git.hilo.cn/hilo-common/resource/mysql" + "hilo-user/cv/headwear_cv" + "hilo-user/cv/medal_cv" + "hilo-user/cv/property_cv" + "time" +) + +//空字符串转成nil +func StrNil(msg string) *string { + if msg == "" { + return nil + } + return &msg +} + +func TypeToUint8(t *mysql.Type) *uint8 { + if *t == 0 { + return nil + } else { + return (*uint8)(t) + } +} + +func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 { + if *birthday == 0 { + return nil + } + return (*uint64)(birthday) +} + +func NumToUint32(num *mysql.Num) *uint32 { + return (*uint32)(num) +} + +func TimeToUint64(t *time.Time) *uint64 { + a := uint64(t.Unix()) + return &a +} + +func StrToString(str *mysql.Str) *string { + return (*string)(str) +} + +func IndexToUint16(i *mysql.Index) *uint16 { + return (*uint16)(i) +} + +func IdToUint64(id *mysql.ID) *uint64 { + return (*uint64)(id) +} + +func IfLogout(logoutTime int64) bool { + return logoutTime > 0 && time.Now().Unix() > logoutTime +} +func IfLogoutMedals(condition bool, trueVal, falseVal []uint32) []uint32 { + if condition { + return trueVal + } + return falseVal +} + +func IfLogoutMedalInfo(condition bool, trueVal, falseVal []medal_cv.CvMedal) []medal_cv.CvMedal { + if condition { + return trueVal + } + return falseVal +} + +func IfLogoutHeadwear(condition bool, trueVal, falseVal *headwear_cv.CvHeadwear) *headwear_cv.CvHeadwear { + if condition { + return trueVal + } + return falseVal +} + +func IfLogoutRide(condition bool, trueVal, falseVal property_cv.CvProperty) property_cv.CvProperty { + if condition { + return trueVal + } + return falseVal +} + +func IfLogoutStr(condition bool, trueVal, falseVal string) string { + if condition { + return trueVal + } + return falseVal +} + +func IfLogoutNick(condition bool, code string, nick string) string { + if condition { + return "Hilo No." + code + } + return nick +} diff --git a/route/router.go b/route/router.go index c558200..60311fe 100755 --- a/route/router.go +++ b/route/router.go @@ -28,7 +28,8 @@ func InitRouter() *gin.Engine { { user.GET("/nameplate", wrapper(user_r.UserNameplate)) user.GET("/bag/:resType", wrapper(user_r.UserBag)) - + user.GET("/detail", wrapper(user_r.UserDetail)) + user.GET("/detail/:userExternalId", wrapper(user_r.UserDetailByExternalId)) } cp := v2.Group("/cp") { diff --git a/route/user_r/user.go b/route/user_r/user.go index 8c8d6cb..a21243d 100644 --- a/route/user_r/user.go +++ b/route/user_r/user.go @@ -3,9 +3,16 @@ package user_r import ( "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" "github.com/gin-gonic/gin" + "hilo-user/_const/redis_key/user_k" + "hilo-user/domain/model/group_m" + "hilo-user/domain/model/tim_m" + "hilo-user/domain/service/user_s" "hilo-user/req" "hilo-user/resp" + "time" ) // @Tags 用户 @@ -20,17 +27,82 @@ import ( // @Router /v1/user/detail [get] func UserDetail(c *gin.Context) (*mycontext.MyContext, error) { myContext := mycontext.CreateMyContext(c.Keys) - userId, err := req.GetUserId(c) + userId, lang, err := req.GetUserIdLang(c, myContext) if err != nil { return myContext, err } + cvUserDetail, err := user_s.NewUserService(myContext).GetUserDetail(userId, userId, lang) + if err != nil { + return myContext, err + } + resp.ResponseOk(c, cvUserDetail) + return myContext, nil +} + +// @Tags 用户 +// @Summary 获取用户详细信息 +// @Param token header string true "token" +// @Param timestamp header string true "时间戳" +// @Param nonce header string true "随机数字" +// @Param signature header string true "sha1加密结果" +// @Param deviceType header string true "系统类型 ios android" +// @Param deviceVersion header string true "系统版本" +// @Param userExternalId path string true "userExternalId" +// @Param groupId query string false "群组id,当传了该id,则返回该用户在该群组的身份" +// @Success 200 {object} user_cv.CvUserDetail +// @Router /v1/user/detail/{userExternalId} [get] +func UserDetailByExternalId(c *gin.Context) (*mycontext.MyContext, error) { + myContext := mycontext.CreateMyContext(c.Keys) + userId, lang, err := req.GetUserIdLang(c, myContext) + if err != nil { + return myContext, err + } + otherUserId, err := req.ToUserId(myContext, mysql.Str(c.Param("userExternalId"))) + if err != nil { + return nil, err + } model := domain.CreateModelContext(myContext) - cvUserDetail, err := cv.GetUserDetail(model, userId, userId) + imGroupId := c.Query("groupId") + if imGroupId != "" { + imGroupId, err = group_m.ToImGroupId(model, imGroupId) + if err != nil { + return myContext, err + } + } + + cvUserDetail, err := user_s.NewUserService(myContext).GetUserDetail(otherUserId, userId, lang) if err != nil { return myContext, err } + if imGroupId != "" { + cvUserDetail.GroupRole, err = group_m.GetGroupRoleById(model, imGroupId, otherUserId) + if err != nil { + return myContext, err + } + } + + if cvUserDetail != nil { + // 检查是否需要同步 + if n, err := redisCli.GetRedis().Exists(model, user_k.GetKeySyncTimHilo(userId)).Result(); err == nil { + if n == 0 { + // FIXME:转异步执行 + err = tim_m.FlushHiloInfo(*cvUserDetail.ExternalId, cvUserDetail.IsVip, cvUserDetail.IsPrettyCode, + nil, cvUserDetail.MyGroupPowerName, cvUserDetail.Noble.Level) + if err == nil { + redisCli.GetRedis().Set(model, user_k.GetKeySyncTimHilo(userId), "1", time.Minute) + } else { + model.Log.Info("UserBaseByExternalId, FlushHiloInfo failed: ", err) + } + } else { + model.Log.Info("UserDetailByExternalId, no need to sync yet: ", userId) + } + } else { + model.Log.Info("UserDetailByExternalId, check KeySyncTimHilo failed", err) + } + } + resp.ResponseOk(c, cvUserDetail) return myContext, nil } -- 2.22.0