Skip to content

Commit

Permalink
2023/2/14 21:18 实现了粉丝和好友列表
Browse files Browse the repository at this point in the history
  • Loading branch information
ccmail committed Feb 14, 2023
1 parent c67a46f commit 4161adb
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 39 deletions.
12 changes: 11 additions & 1 deletion README_cjs.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
本文的用于记录程季晟的一些改动和疑问

# 客户端问题

1. 个人主页的关注数, 经postman与实际测试对比, 发现个人主页的关注数更新是按照"点击关注"的操作次数进行更新, 即直接发送关注请求,
不使用客户端操作, 个人主页信息不会变, **以此为前提**, 客户端发生**取消关注**操作后, 个人信息主页不变, 由此推论,
这个属于客户端的问题

# 待办

1. `videoService`中上传云服务器等内容的拆分, 目前推荐放到`util`工具包下比较合适, **暂定**

2. ~~video方面的feed()内容~~
3. ~~get请求获取不到token,不清楚原因~~
4. 抓包, 查看访问author的publishlist等页面, 客户端发送的数据
5. 没有对关注人数变更到负数的情况进行拦截
5. ~~没有对关注人数变更到负数的情况进行拦截~~
6. ~~评论之后feed流视频对应的评论数不会实时更新~~
7. 粉丝列表
8. 好友列表
9. 我不能关注我, 这一点没有做逻辑过滤

# 改动

Expand Down
3 changes: 2 additions & 1 deletion controller/commentCotroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"log"
"net/http"
"strconv"
"tiktok/mapper"
"tiktok/pkg/common"
"tiktok/pkg/middleware"
"tiktok/service"
Expand Down Expand Up @@ -54,7 +55,7 @@ func Comment(c *gin.Context) {
FollowCount: commenter.FollowCount,
FollowerCount: commenter.FollowerCount,
// TODO: IsFollowing包含了DAO操作,后面要移到mapper里去
IsFollow: service.IsFollowing(userId, author),
IsFollow: mapper.CheckFollowing(userId, author),
},
},
})
Expand Down
83 changes: 80 additions & 3 deletions controller/followerController.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
Expand Down Expand Up @@ -47,7 +48,7 @@ func Follow(ctx *gin.Context) {
if err != nil {
ctx.JSON(http.StatusOK, common.BaseResponse{
StatusCode: 1,
StatusMsg: "关注/取关失败",
StatusMsg: fmt.Sprint("关注/取关失败", err),
})
log.Panicln("关注/取关失败, 注意检查service.Follow的逻辑")
return
Expand All @@ -58,7 +59,7 @@ func Follow(ctx *gin.Context) {
})
}

// FollowList
// FollowList 关注列表
//与发布列表类似, 用户未登录应该也可以查看某位作者关注的人, 这里先做好准备, 目前走jwt鉴权, 为以后更新准备, 先做好token为空的判断
func FollowList(ctx *gin.Context) {
hostToken := ctx.Query("token")
Expand All @@ -84,7 +85,7 @@ func FollowList(ctx *gin.Context) {
StatusCode: 1,
StatusMsg: "获取关注列表失败!",
})
log.Panicln("获取发布作品详情时失败")
log.Panicln("获取关注列表时失败")
return
}
ctx.JSON(http.StatusOK, common.UserInfoListResp{
Expand All @@ -95,3 +96,79 @@ func FollowList(ctx *gin.Context) {
UserList: userInfoList,
})
}

// FollowerList 粉丝列表
//逻辑类似关注列表
func FollowerList(ctx *gin.Context) {
hostToken := ctx.Query("token")
if hostToken == "" {
log.Println("没有获取到用户token")
log.Println(hostToken)
}
var guestID uint
guestIDStr := ctx.Query("user_id")
if atoi, err := strconv.Atoi(guestIDStr); err != nil || guestIDStr == "" {
ctx.JSON(http.StatusOK, common.BaseResponse{
StatusCode: 1,
StatusMsg: "没有获取到用户ID",
})
log.Panicln("userID获取失败")
return
} else {
guestID = uint(atoi)
}
userInfoList, err := service.FollowerList(hostToken, guestID)
if err != nil {
ctx.JSON(http.StatusOK, common.BaseResponse{
StatusCode: 1,
StatusMsg: "获取粉丝列表失败!",
})
log.Panicln("获取粉丝列表时失败")
return
}
ctx.JSON(http.StatusOK, common.UserInfoListResp{
BaseResponse: common.BaseResponse{
StatusCode: 0,
StatusMsg: "请求粉丝列表成功!",
},
UserList: userInfoList,
})
}

// FriendList
//好友列表, 查询逻辑是互相关注
func FriendList(ctx *gin.Context) {
hostToken := ctx.Query("token")
if hostToken == "" {
log.Println("没有获取到用户token")
log.Println(hostToken)
}
var guestID uint
guestIDStr := ctx.Query("user_id")
if atoi, err := strconv.Atoi(guestIDStr); err != nil || guestIDStr == "" {
ctx.JSON(http.StatusOK, common.BaseResponse{
StatusCode: 1,
StatusMsg: "没有获取到用户ID",
})
log.Panicln("userID获取失败")
return
} else {
guestID = uint(atoi)
}
userInfoList, err := service.FriendList(hostToken, guestID)
if err != nil {
ctx.JSON(http.StatusOK, common.BaseResponse{
StatusCode: 1,
StatusMsg: "获取好友列表失败!",
})
log.Panicln("获取好友列表时失败")
return
}
ctx.JSON(http.StatusOK, common.UserInfoListResp{
BaseResponse: common.BaseResponse{
StatusCode: 0,
StatusMsg: "请求好友列表成功!",
},
UserList: userInfoList,
})
}
2 changes: 2 additions & 0 deletions controller/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func InitRouter() *gin.Engine {
{
followGroup.POST("/action/", middleware.JwtMiddleware(), Follow)
followGroup.GET("/follow/list/", middleware.JwtMiddleware(), FollowList)
followGroup.GET("/follower/list/", middleware.JwtMiddleware(), FollowerList)
followGroup.GET("/friend/list/", middleware.JwtMiddleware(), FriendList)
//followGroup.GET("/follow/list/", FollowList)
}
// // comment路由组
Expand Down
2 changes: 1 addition & 1 deletion mapper/connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

func TestInitDBConnector(t *testing.T) {
err := InitDBConnector()
err := InitDBConnectorSupportTest()
if err != nil {
t.Error("连接数据库失败")
}
Expand Down
11 changes: 10 additions & 1 deletion mapper/followerMapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,16 @@ func UpdateFollowRecord(hostID, guestID uint, isConcern bool) error {

// FindMultiConcern 返回关注id关注的人, 实现逻辑是将id作为粉丝id进行查询
func FindMultiConcern(id uint) (resUserIDList []uint, err error) {
tx := DBConn.Model(&model.Follower{}).Select("user_id").Where("follower_id = ?", id).Find(&resUserIDList)
tx := DBConn.Model(&model.Follower{}).Select("user_id").Where("follower_id = ? AND is_follow = ?", id, true).Find(&resUserIDList)
if tx.Error != nil {
log.Panicln("查询用户关注信息时失败")
return resUserIDList, tx.Error
}
return resUserIDList, nil
}

func FindMultiFollower(id uint) (resUserIDList []uint, err error) {
tx := DBConn.Model(&model.Follower{}).Select("follower_id").Where("user_id = ? AND is_follow = ?", id, true).Find(&resUserIDList)
if tx.Error != nil {
log.Panicln("查询用户关注信息时失败")
return resUserIDList, tx.Error
Expand Down
36 changes: 14 additions & 22 deletions mapper/userMapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mapper

import (
"errors"
"fmt"
"log"
"tiktok/model"
"tiktok/pkg/errno"
Expand Down Expand Up @@ -92,28 +93,19 @@ func FindMultiUserInfo(multiUserID []uint) (map[uint]model.User, error) {

// UpdateUserFollowCount host关注guest, 所以host是被关注的人, guest是up, 所以关注操作, host.follow+1, guest.follower+1
func UpdateUserFollowCount(hostID, guestID uint, isConcern bool) error {
if isConcern {
tx := DBConn.Model(&model.User{}).Where("id = ?", hostID).Update("follow_count", gorm.Expr("follow_count + 1"))
if tx.Error != nil {
log.Panicln("更新关注人数时出错")
return tx.Error
}
tx = DBConn.Model(&model.User{}).Where("id = ?", guestID).Update("follower_count", gorm.Expr("follower_count + 1"))
if tx.Error != nil {
log.Panicln("更新粉丝人数时出错")
return tx.Error
}
} else {
tx := DBConn.Model(&model.User{}).Where("id = ?", hostID).Update("follow_count", gorm.Expr("follow_count - 1"))
if tx.Error != nil {
log.Panicln("更新关注人数时出错")
return tx.Error
}
tx = DBConn.Model(&model.User{}).Where("id = ?", guestID).Update("follower_count", gorm.Expr("follower_count - 1"))
if tx.Error != nil {
log.Panicln("更新粉丝人数时出错")
return tx.Error
}
x := " + 1"
if !isConcern {
x = " - 1"
}
tx := DBConn.Model(&model.User{}).Where("id = ?", hostID).Update("follow_count", gorm.Expr(fmt.Sprint("follow_count", x)))
if tx.Error != nil {
log.Panicln("更新关注人数时出错")
return tx.Error
}
tx = DBConn.Model(&model.User{}).Where("id = ?", guestID).Update("follower_count", gorm.Expr(fmt.Sprint("follower_count ", x)))
if tx.Error != nil {
log.Panicln("更新粉丝人数时出错")
return tx.Error
}
return nil
}
3 changes: 2 additions & 1 deletion pkg/middleware/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package middleware
import "log"

func InitLog() {
log.SetFlags(log.Ltime | log.Lshortfile)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.SetPrefix("[tiktok]项目中发生的错误")
}
93 changes: 84 additions & 9 deletions service/followerService.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package service

import (
"errors"
"log"
"tiktok/mapper"
"tiktok/pkg/common"
Expand All @@ -15,6 +16,9 @@ func Follow(token string, guestID uint, isConcern bool) error {
if err != nil {
return err
}
if parseToken.UserId == guestID {
return errors.New("请不要自己关注自己!")
}
record, exist := mapper.ExistFollowRecord(parseToken.UserId, guestID)
//如果不存在的话, 向follow插入信息, 并更新user表的字段
if !exist {
Expand All @@ -33,8 +37,8 @@ func Follow(token string, guestID uint, isConcern bool) error {
//mapper.UpdateUserFollowCount(parseToken.UserId, guestID)
}

if record.IsFollow == isConcern {
//关注关系没有变化
if record.IsFollow == isConcern || (!record.IsFollow && !isConcern) {
//关注关系没有变化, 或者已经处于未关注状态
return nil
}
//更新host的关注数, 并增加host关注的up数量, 增加up的粉丝数量
Expand All @@ -53,26 +57,28 @@ func Follow(token string, guestID uint, isConcern bool) error {
}

// FollowList 用户token去请求guestID对应的关注列表
func FollowList(token string, guestID uint) (returnList []common.UserInfoResp, err error) {
func FollowList(token string, guestID uint) (resList []common.UserInfoResp, err error) {
hostID := getHostIDFromToken(token)
//这里请求出来有两步, 如果tokenID==guestID, 直接返回, 默认全部关注
//如果tokenID!=guestID, 还需要判断请求出来的user和token的关注关系
userIDList, err := mapper.FindMultiConcern(guestID)
if err != nil {
return returnList, err
log.Panicln("查找关注列表信息时失败")
return resList, err
}
//获取到guestID关注的up的用户信息
userInfoList, err := mapper.FindMultiUserInfo(userIDList)
if err != nil {
return returnList, err
log.Panicln("查找关注用户的个人信息时失败")
return resList, err
}

returnList = make([]common.UserInfoResp, 0, len(userInfoList))
resList = make([]common.UserInfoResp, 0, len(userInfoList))
for _, upInfo := range userInfoList {
if hostID != guestID {
returnList = append(returnList, packUserInfo(upInfo, hostID))
resList = append(resList, packUserInfo(upInfo, hostID))
} else {
returnList = append(returnList, common.UserInfoResp{
resList = append(resList, common.UserInfoResp{
AuthorId: upInfo.ID,
Name: upInfo.Name,
FollowCount: upInfo.FollowCount,
Expand All @@ -81,5 +87,74 @@ func FollowList(token string, guestID uint) (returnList []common.UserInfoResp, e
})
}
}
return returnList, nil
return resList, nil
}

// FollowerList 请求粉丝列表, 和请求关注列表逻辑一致, 不同的是需要更改一下查询数据库的信息
func FollowerList(token string, guestID uint) (resList []common.UserInfoResp, err error) {
hostID := getHostIDFromToken(token)

userIDList, err := mapper.FindMultiFollower(guestID)
if err != nil {
log.Panicln("查找粉丝列表信息时失败")
return resList, err
}
//获取到guestID关注的up的用户信息
userInfoList, err := mapper.FindMultiUserInfo(userIDList)
if err != nil {
log.Panicln("查找粉丝个人信息时失败")
return resList, err
}

resList = make([]common.UserInfoResp, 0, len(userInfoList))
for _, upInfo := range userInfoList {
resList = append(resList, packUserInfo(upInfo, hostID))
}
return resList, nil
}

// FriendList 这里要做一下过滤, 只有自己能看自己的好友列表, 当guestID与token不符时应当直接返回
func FriendList(token string, guestID uint) (resList []common.UserInfoResp, err error) {
hostID := getHostIDFromToken(token)
if hostID != guestID {
return resList, errors.New("请求好友列表的id和token不一致, 不允许偷看别人的好友列表")
}
//分别获取粉丝和关注的up列表, 对其过滤, 同时存在的为好友
fans, err := mapper.FindMultiFollower(guestID)
if err != nil {
log.Panicln("查找粉丝列表信息时失败")
return resList, err
}
ups, err := mapper.FindMultiConcern(guestID)
if err != nil {
log.Panicln("查找关注列表信息时失败")
return resList, err
}

mp := make(map[uint]interface{})
for i := 0; i < len(fans); i++ {
mp[fans[i]] = struct{}{}
}
friends := make([]uint, len(fans)>>1)
for i := 0; i < len(ups); i++ {
if _, ok := mp[ups[i]]; ok {
friends = append(friends, ups[i])
}
}
multiUserInfo, err := mapper.FindMultiUserInfo(friends)
if err != nil {
log.Panicln("获取好友信息时失败了")
return resList, err
}
resList = make([]common.UserInfoResp, 0, len(multiUserInfo))
for _, userInfo := range multiUserInfo {
resList = append(resList, common.UserInfoResp{
AuthorId: userInfo.ID,
Name: userInfo.Name,
FollowCount: userInfo.FollowCount,
FollowerCount: userInfo.FollowerCount,
IsFollow: true,
})
}
return resList, nil
}
1 change: 1 addition & 0 deletions service/userService.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func UserInfoService(rawId string) (common.UserInfoQueryResponse, error) {
userId, err := strconv.ParseUint(rawId, 10, 64)
if err != nil {
log.Panicln("service-UserInfoService: 解析rawID时发生错误, ", err)
return userInfoQueryResponse, err
}

// 获取用户信息
Expand Down

0 comments on commit 4161adb

Please sign in to comment.