diff --git a/README.md b/README.md index 2efeac0..17bd354 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ -# GoDance -字节跳动青训营GoDance队大项目开发 +项目包含自动迁移建表功能,请大家修改model/mysql.go中的数据库信息后再运行 + +controller/publish 中的ResourceDir也请修改成自己的本机IP + +目前项目仍存在问题: + +- 视频缩略图无法展示,本机上传的视频无法播放 +- 喜欢列表与点赞列表还未完成 +- 视频点赞数量与评论数量没有实时更新 +- 用户点赞视频没有持久化 \ No newline at end of file diff --git a/controller/comment.go b/controller/comment.go new file mode 100644 index 0000000..8d31ad3 --- /dev/null +++ b/controller/comment.go @@ -0,0 +1,106 @@ +package controller + +import ( + "GoDance/model" + "GoDance/service" + "fmt" + "net/http" + "strconv" + "time" + + "github.com/gin-gonic/gin" +) + +// CommentAction no practical effect, just check if token is valid +// CommentAction +// @Summary 评论操作 +// @Description 登录用户对视频进行评论 +// @Tags 互动接口 +// @param token query string true "用户鉴权token" +// @param video_id query string true "视频id" +// @param action_type query string true "1-发布评论,2-删除评论" +// @param comment_text query string false "用户填写的评论内容,在action_type=1的时候使用" +// @param comment_id query string false "要删除的评论id,在action_type=2的时候使用" +// @Success 200 {string} success +// @Router /comment/action/ [post] +func CommentAction(c *gin.Context) { + token := c.Query("token") + actionType := c.Query("action_type") + videoId, _ := strconv.Atoi(c.Query("video_id")) + user, err := service.FindUserByToken(token) + if err == nil { //改动了user的访问 + var comment model.CommentData + if actionType == "1" { //新增 + comment.UserId = user.Id + comment.VideoId = int64(videoId) + text := c.Query("comment_text") + comment.CommentText = text + comment.CreateDate = time.Now() + if err := model.InsertComment(&comment); err != nil { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "评论失败"}) + } + c.JSON(http.StatusOK, CommentActionResponse{Response: Response{StatusCode: 0, StatusMsg: "评论成功"}, + Comment: model.Comment{ + Id: comment.Id, + User: user, + Content: text, + CreateDate: comment.CreateDate.Format("01-02"), + }}) + return + } else if actionType == "2" { //删除 + commentId, _ := strconv.Atoi(c.Query("comment_id")) + comment, err := model.FindCommentById(int64(commentId)) //补充删除不存在的情况 + if comment.Cancel == 1 || err != nil { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "评论已删除或不存在"}) + return + } + if comment.UserId == user.Id { //是该评论主人 + if err = model.DeleteComment(int64(commentId), int64(comment.VideoId)); err != nil { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "评论删除失败"}) + } else { + c.JSON(http.StatusOK, Response{StatusCode: 0, StatusMsg: "评论删除成功"}) + } + } else { //不能删除他人评论 + c.JSON(http.StatusForbidden, Response{StatusCode: 1, StatusMsg: "没有权限删除他人评论"}) + } + } else { + c.JSON(http.StatusBadRequest, Response{StatusCode: 1, StatusMsg: "评论状态参数错误"}) + } + } else { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: err.Error()}) + } +} + +// CommentList all videos have same demo comment list +// CommentList +// @Summary 评论列表 +// @Description 查看视频的所有评论,按发布时间倒序 +// @Tags 互动接口 +// @param token query string true "用户鉴权token" +// @param video_id query string true "视频id" +// @Success 200 {string} success +// @Router /comment/list/ [get] +func CommentList(c *gin.Context) { + token := c.Query("token") + videoId, _ := strconv.Atoi(c.Query("video_id")) + _, err := service.FindUserByToken(token) + if err == nil { + comments := model.FindCommentsByVideoId(int64(videoId)) + var commentsVO = make([]model.Comment, len(comments)) + for i := 0; i < len(comments); i++ { + comment := comments[i] + commentOwner, err := service.FindUserById(comment.UserId) + if err != nil { + fmt.Printf(err.Error()) + return + } + commentsVO[i] = model.Comment{Id: comment.Id, User: commentOwner, Content: comment.CommentText, CreateDate: comment.CreateDate.Format("01-02")} + } + c.JSON(http.StatusOK, CommentListResponse{ + Response: Response{StatusCode: 0, StatusMsg: "获取评论列表成功"}, + CommentList: commentsVO, + }) + } else { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: err.Error()}) + } +} diff --git a/controller/common.go b/controller/common.go new file mode 100644 index 0000000..6158c4f --- /dev/null +++ b/controller/common.go @@ -0,0 +1,50 @@ +package controller + +import "GoDance/model" + +type Response struct { + StatusCode int32 `json:"status_code"` + StatusMsg string `json:"status_msg,omitempty"` +} + +// Comment About comment + +type CommentListResponse struct { + Response + CommentList []model.Comment `json:"comment_list,omitempty"` +} + +type CommentActionResponse struct { + Response + Comment model.Comment `json:"comment,omitempty"` +} + +// Video About Video + +type FeedResponse struct { + Response + VideoList []model.Video `json:"video_list,omitempty"` + NextTime int64 `json:"next_time,omitempty"` +} + +type VideoListResponse struct { + Response + VideoList []model.Video `json:"video_list"` +} +type PublishVideoListResponse struct { + Response + PublishVideoList []model.PublishListVideoStruct `json:"video_list"` +} + +// User About User + +type UserResponse struct { + Response + User model.User `json:"user"` +} + +type LoginResponse struct { + Response + Id int64 `json:"user_id,omitempty"` + Token string `json:"token,omitempty"` +} diff --git a/controller/favorite.go b/controller/favorite.go new file mode 100644 index 0000000..597eb01 --- /dev/null +++ b/controller/favorite.go @@ -0,0 +1,43 @@ +package controller + +import ( + "GoDance/model" + "GoDance/service" + "github.com/gin-gonic/gin" + "net/http" +) + +func FavoriteAction(c *gin.Context) { + token := c.Query("token") + videoId := c.Query("video_id") + actionType := c.Query("action_type") + _, err := service.FindUserByToken(token) + if err == nil { + if actionType == "2" { //delete the favorite + favorite := model.FavoriteData{Token: token, VideoId: videoId} + model.Db.Table("favorite_data").Where("token=?", token).Delete(&favorite) + c.JSON(http.StatusOK, Response{StatusCode: 0}) + } else if actionType == "1" { + favorite := model.FavoriteData{Token: token, VideoId: videoId} + model.Db.Create(&favorite) + c.JSON(http.StatusOK, Response{StatusCode: 0}) + } else { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "The entry doesn't exist"}) + } + } else { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "User doesn't exist"}) + } +} + +// FavoriteList all users have same favorite video list +func FavoriteList(c *gin.Context) { + var video_list []model.VideoData + token := c.Query("token") + model.Db.Table("favorite_data").Find(&video_list, "token=?", token) + c.JSON(http.StatusOK, VideoListResponse{ + Response: Response{ + StatusCode: 0, + }, + //VideoList: video_list, + }) +} diff --git a/controller/feed.go b/controller/feed.go new file mode 100644 index 0000000..e04d73d --- /dev/null +++ b/controller/feed.go @@ -0,0 +1,41 @@ +package controller + +import ( + "GoDance/service" + "github.com/gin-gonic/gin" + "net/http" + "strconv" + "time" +) + +// Feed same demo video list for every request +func Feed(c *gin.Context) { + + //token := c.Query("token") + //userIds, _ := c.Get("UserId") + //userId := userIds.(int64) + currentTime, err := strconv.ParseInt(c.Query("latest_time"), 10, 64) + + if err != nil || currentTime == 0 { + currentTime = time.Now().Unix() + } + //FeedGet的参数二是userId,这里测试所以设置为0 + feedList, nextTime, _ := service.FeedGet(currentTime, 0) + + c.JSON(http.StatusOK, FeedResponse{ + Response: Response{StatusCode: 0}, //成功 + VideoList: feedList, + NextTime: nextTime, + }) +} + +//demo +/* +func Feed(c *gin.Context) { + c.JSON(http.StatusOK, FeedResponse{ + Response: Response{StatusCode: 0}, + VideoList: DemoVideos, + NextTime: time.Now().Unix(), + }) +} +*/ diff --git a/controller/publish.go b/controller/publish.go new file mode 100644 index 0000000..7798691 --- /dev/null +++ b/controller/publish.go @@ -0,0 +1,153 @@ +package controller + +import ( + "GoDance/model" + "GoDance/service" + "bytes" + "fmt" + "github.com/disintegration/imaging" + "github.com/gin-gonic/gin" + ffmpeg "github.com/u2takey/ffmpeg-go" + "net/http" + "os" + "path/filepath" + "strconv" + "time" +) + +var ResourceDir = "http://192.168.2.9:8080/public/" + +// convert video into cover using ffmpeg +func Video2Cover(VideoName string) (CoverPath string, err error) { + VideoPath := filepath.Join("E:\\GoDance\\public\\videos", VideoName) + buf := bytes.NewBuffer(nil) + err = ffmpeg.Input(VideoPath).Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,1)")}). + Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}). + WithOutput(buf, os.Stdout). + Run() + if err != nil { + fmt.Println(err.Error()) + return "", err + } + cover, err := imaging.Decode(buf) + if err != nil { + return "", err + } + CoverPath = ".\\public\\covers\\" + VideoName + ".png" + //fmt.Println("CoverPath: "+ CoverPath) + err = imaging.Save(cover, CoverPath) + if err != nil { + fmt.Printf("Saving cover error\n %s\n", err) + return "", err + } + return CoverPath, nil +} + +// Publish !! Title didn't use !! +// Publish check token then save upload file to public directory +func Publish(c *gin.Context) { + if model.Err != nil { + c.JSON(http.StatusOK, Response{ + StatusCode: 1, + StatusMsg: model.Err.Error(), + }) + fmt.Printf("database error\n") + return + } + token := c.PostForm("token") + + login_user, err := service.FindUserByToken(token) + //fmt.Println(login_user) + if err != nil { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: err.Error()}) + return + } + data, err := c.FormFile("data") + if err != nil { + c.JSON(http.StatusOK, Response{ + StatusCode: 1, + StatusMsg: err.Error(), + }) + return + } + //fmt.Println(login_user.Id) + filename := filepath.Base(data.Filename) + finalName := fmt.Sprintf("%d_%s", login_user.Id, filename) + saveFile := filepath.Join("./public/videos", finalName) + if err := c.SaveUploadedFile(data, saveFile); err != nil { + c.JSON(http.StatusOK, Response{ + StatusCode: 1, + StatusMsg: err.Error(), + }) + return + } + + if err != nil { + c.JSON(http.StatusOK, Response{ + StatusCode: 1, + StatusMsg: err.Error(), + }) + return + } + //title := c.PostForm("title") + VideoUrl := filepath.Join(ResourceDir, "videos", finalName) + CoverUrl, err := Video2Cover(finalName) + CoverUrl = filepath.Join(ResourceDir, "covers", finalName+".png") + //fmt.Printf("video: %s cover: %s\n", VideoUrl, CoverUrl) + new_video := model.VideoData{ + Author: login_user.Id, + PlayUrl: VideoUrl, + CoverUrl: CoverUrl, + FavoriteCount: 0, + CommentCount: 0, + IsFavorite: false, + CreateTime: time.Now().Unix(), + } + model.Db.Create(&new_video) + c.JSON(http.StatusOK, Response{ + StatusCode: 0, + StatusMsg: finalName + " uploaded successfully", + }) +} + +// PublishList all users have same publish video list +func PublishList(c *gin.Context) { + VideoList := []model.VideoData{} + + author_id := c.Query("user_id") + model.Db.Table("video_data").Find(&VideoList, "author=?", author_id) + fmt.Println(VideoList) + //search author row + authorid, _ := strconv.ParseInt(author_id, 10, 64) + author, err := service.FindUserById(authorid) + if err != nil { + c.JSON(http.StatusOK, Response{StatusCode: 1, StatusMsg: "Author doesn't exist"}) + return + } + + var PublishVideoList []model.PublishListVideoStruct //[]PublishListVideoStruct{} //video list used for publish list interface + for i := 0; i < len(VideoList); i++ { + var tmp = model.PublishListVideoStruct{ + Id: VideoList[i].Id, + Author: author, + PlayUrl: VideoList[i].PlayUrl, + CoverUrl: VideoList[i].CoverUrl, + FavoriteCount: VideoList[i].FavoriteCount, + CommentCount: VideoList[i].CommentCount, + IsFavorite: VideoList[i].IsFavorite, + } + // fmt.Println("!!!") + PublishVideoList = append(PublishVideoList, tmp) + } + // fmt.Print("Orginal: ") + // fmt.Println(VideoList) + // fmt.Print("After: ") + // fmt.Println(PublishVideoList) + c.JSON(http.StatusOK, PublishVideoListResponse{ + Response: Response{ + StatusCode: 0, + }, + PublishVideoList: PublishVideoList, + }) + //fmt.Printf("publish list\n") +} diff --git a/controller/user.go b/controller/user.go new file mode 100644 index 0000000..d93e314 --- /dev/null +++ b/controller/user.go @@ -0,0 +1,59 @@ +package controller + +import ( + "GoDance/service" + "fmt" + "github.com/gin-gonic/gin" + "net/http" +) + +func Register(c *gin.Context) { + username := c.Query("username") + password := c.Query("password") + user, err := service.Register(username, password) + if err != nil { + c.JSON(http.StatusOK, LoginResponse{ + Response: Response{StatusCode: 1, StatusMsg: err.Error()}, + }) + } else { + c.JSON(http.StatusOK, LoginResponse{ + Response: Response{StatusCode: 0, StatusMsg: "Register success"}, + Id: user.Id, + Token: user.Token, + }) + } +} + +func Login(c *gin.Context) { + username := c.Query("username") + password := c.Query("password") + user, err := service.Login(username, password) + if err == nil { + fmt.Printf("success1") + c.JSON(http.StatusOK, LoginResponse{ + Response: Response{StatusCode: 0, StatusMsg: "Login success!"}, + Id: user.Id, + Token: user.Token, + }) + } else { + c.JSON(http.StatusOK, LoginResponse{ + Response: Response{StatusCode: 1, StatusMsg: err.Error()}, + }) + } +} + +func UserInfo(c *gin.Context) { + token := c.Query("token") + user, err := service.FindUserByToken(token) + if err == nil { + c.JSON(http.StatusOK, UserResponse{ + Response: Response{StatusCode: 0}, + User: user, + }) + } else { + c.JSON(http.StatusOK, UserResponse{ + Response: Response{StatusCode: 1, StatusMsg: err.Error()}, + User: user, + }) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fefe7d8 --- /dev/null +++ b/go.mod @@ -0,0 +1,39 @@ +module GoDance + +go 1.19 + +require ( + github.com/disintegration/imaging v1.6.2 + github.com/gin-gonic/gin v1.8.2 + github.com/u2takey/ffmpeg-go v0.4.1 + gorm.io/driver/mysql v1.4.5 + gorm.io/gorm v1.24.5 +) + +require ( + github.com/aws/aws-sdk-go v1.44.203 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.9.11 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/u2takey/go-utils v0.3.1 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect + golang.org/x/image v0.5.0 // indirect + golang.org/x/net v0.4.0 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/text v0.7.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f0e1508 --- /dev/null +++ b/go.sum @@ -0,0 +1,180 @@ +github.com/aws/aws-sdk-go v1.38.20 h1:QbzNx/tdfATbdKfubBpkt84OM6oBkxQZRw6+bW2GyeA= +github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.44.203 h1:pcsP805b9acL3wUqa4JR2vg1k2wnItkDYNvfmcy6F+U= +github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY= +github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/u2takey/ffmpeg-go v0.4.1 h1:l5ClIwL3N2LaH1zF3xivb3kP2HW95eyG5xhHE1JdZ9Y= +github.com/u2takey/ffmpeg-go v0.4.1/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc= +github.com/u2takey/go-utils v0.3.1 h1:TaQTgmEZZeDHQFYfd+AdUT1cT4QJgJn/XVPELhHw4ys= +github.com/u2takey/go-utils v0.3.1/go.mod h1:6e+v5vEZ/6gu12w/DC2ixZdZtCrNokVxD0JUklcqdCs= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.4.5 h1:u1lytId4+o9dDaNcPCFzNv7h6wvmc92UjNk3z8enSBU= +gorm.io/driver/mysql v1.4.5/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE= +gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/main.go b/main.go new file mode 100644 index 0000000..304336c --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "GoDance/model" + "github.com/gin-gonic/gin" +) + +func main() { + r := gin.Default() + + initRouter(r) + + model.InitDB() + + model.InitTable() + + r.Run() +} diff --git a/model/comment.go b/model/comment.go new file mode 100644 index 0000000..d6b0f4d --- /dev/null +++ b/model/comment.go @@ -0,0 +1,72 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +// 用于返回的comment结构 +type Comment struct { + Id int64 `json:"id,omitempty"` + User User `json:"user"` + Content string `json:"content,omitempty"` + CreateDate string `json:"create_date,omitempty"` +} + +// 存储在数据库中的comment结构 +type CommentData struct { + Id int64 `json:"id,omitempty"` + UserId int64 `json:"userId,omitempty"` + VideoId int64 `json:"videoId,omitempty"` + CommentText string `json:"commentText,omitempty"` + CreateDate time.Time `json:"createDate,omitempty"` + Cancel int8 `json:"cancel,omitempty"` +} + +func InsertComment(comment *CommentData) error { + err1 := Db.Transaction(func(db *gorm.DB) error { + if err := db.Create(comment).Error; err != nil { + return err + } + if err := db.Model(&VideoData{}).Where("Id = ?", comment.VideoId).Update("CommentCount", gorm.Expr("comment_count + ?", 1)).Error; err != nil { + return err + } + return nil + }) + return err1 + +} + +func DeleteComment(id int64, videoid int64) error { + err1 := Db.Transaction(func(db *gorm.DB) error { + + if err := db.Model(&CommentData{}).Where("Id = ?", id).Update("cancel", 1).Error; err != nil { + return err + } + + if err := db.Model(&VideoData{}).Where("Id = ?", videoid).Update("CommentCount", gorm.Expr("comment_count - ?", 1)).Error; err != nil { + return err + } + return nil + }) + return err1 +} + +func FindCommentById(id int64) (CommentData, error) { + var comment CommentData + if err := Db.Where(&CommentData{Id: id}).First(&comment).Error; err != nil { + return CommentData{}, err + } + return comment, nil + +} + +func FindCommentsByVideoId(viderId int64) []CommentData { + var comments []CommentData + //当使用结构作为条件查询时,GORM 只会查询非零值字段,更新也是如此。 + //config.DB.Where(&Comment{Cancel: 0, VideoId: viderId}).Order("create_date desc").Find(&comments) + //解决办法:使用 map 来构建更新条件,而不是结构体 &Comment{} + Db.Where(map[string]interface{}{"video_id": viderId, "cancel": 0}).Order("create_date desc").Find(&comments) + return comments +} diff --git a/model/favorite.go b/model/favorite.go new file mode 100644 index 0000000..b35c51d --- /dev/null +++ b/model/favorite.go @@ -0,0 +1,10 @@ +package model + +type FavoriteData struct { + Token string `json:"column:token"` + VideoId string `json:"column:video_id"` + //user_id int64 `gorm:"column:user_id"` //because FavoriteAction has no req para named user_id +} + +type Favorite struct { +} diff --git a/model/feed.go b/model/feed.go new file mode 100644 index 0000000..d11df1f --- /dev/null +++ b/model/feed.go @@ -0,0 +1,7 @@ +package model + +type Following struct { + Id int64 `gorm:"column:relation_id; primary_key;"` + AuthorId int64 `gorm:"column:author_id"` //视频发布者id + Follower int64 `gorm:"column:follower_id"` //关注者id +} diff --git a/model/mysql.go b/model/mysql.go new file mode 100644 index 0000000..4444b10 --- /dev/null +++ b/model/mysql.go @@ -0,0 +1,31 @@ +package model + +import ( + "fmt" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +var Db *gorm.DB +var Err error + +func InitDB() { + host := "localhost" + port := "3306" + database := "godance" + + username := "root" + password := "rac1104" + + charset := "utf8" + dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true", username, password, host, port, database, charset) + Db, Err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if Err != nil { + panic("Error to DB connection, err: " + Err.Error()) + } +} + +func InitTable() { + Db.AutoMigrate(&CommentData{}, &UserData{}, &VideoData{}, &FavoriteData{}) +} diff --git a/model/user.go b/model/user.go new file mode 100644 index 0000000..534dbf8 --- /dev/null +++ b/model/user.go @@ -0,0 +1,27 @@ +package model + +// 存储在数据库中的User结构 +type UserData struct { + Id int64 `gorm:"column:user_id; primary_key;""` + Name string `json:"name"` + Password string `json:"password"` + FollowCount int64 `json:"follow_count"` + FollowerCount int64 `json:"follower_count"` + TotalFav int64 `json:"total_favorited"` + FavCount int64 `json:"favorite_count"` + IsFollow bool `json:"is_follow,omitempty"` + Token string `json:"token,omitempty"` +} + +// 用于返回的User结构 +type User struct { + Id int64 `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Password string `json:"password,omitempty"` + FollowCount int64 `json:"follow_count,omitempty"` + FollowerCount int64 `json:"follower_count,omitempty"` + TotalFav int64 `json:"total_favorited,omitempty"` + FavCount int64 `json:"favorite_count,omitempty"` + IsFollow bool `json:"is_follow,omitempty"` + Token string `json:"token,omitempty"` +} diff --git a/model/video.go b/model/video.go new file mode 100644 index 0000000..840ca50 --- /dev/null +++ b/model/video.go @@ -0,0 +1,37 @@ +package model + +// 存储在数据库中的Video结构 +type VideoData struct { + Id int64 `json:"id,omitempty" grom:"autoIncrement"` + Author int64 `json:"author"` + PlayUrl string `json:"play_url" json:"play_url,omitempty" gorm:"default:https://www.w3schools.com/html/movie.mp4"` + CoverUrl string `json:"cover_url,omitempty" gorm:"default:https://cdn.pixabay.com/photo/2016/03/27/18/10/bear-1283347_1280.jpg"` + FavoriteCount int64 `json:"favorite_count,omitempty" gorm:"default:0"` + CommentCount int64 `json:"comment_count,omitempty" gorm:"default:0"` + IsFavorite bool `json:"is_favorite,omitempty" gorm:"type:tinyint(1);default:0"` + CreateTime int64 `gorm:"column:create_at;"` +} + +// 用于返回的Video结构 +type Video struct { + Id int64 `json:"id,omitempty"` + Author User `json:"author"` + PlayUrl string `json:"play_url,omitempty"` + CoverUrl string `json:"cover_url,omitempty"` + CreateTime int64 `gorm:"column:create_at;"` + FavoriteCount int64 `json:"favorite_count,omitempty"` + CommentCount int64 `json:"comment_count,omitempty"` + IsFavorite bool `json:"is_favorite,omitempty"` + //Title string `json:"title,omitempty"` +} + +// PublishListVideoStruct as just store author's id in database, need another struct to meet the interface of PublishList +type PublishListVideoStruct struct { + Id int64 `json:"id,omitempty"` + Author User `json:"author"` + PlayUrl string `json:"play_url" json:"play_url,omitempty"` + CoverUrl string `json:"cover_url,omitempty"` + FavoriteCount int64 `json:"favorite_count,omitempty"` + CommentCount int64 `json:"comment_count,omitempty"` + IsFavorite bool `json:"is_favorite,omitempty"` +} diff --git a/router.go b/router.go new file mode 100644 index 0000000..e9c1430 --- /dev/null +++ b/router.go @@ -0,0 +1,22 @@ +package main + +import ( + "GoDance/controller" + "github.com/gin-gonic/gin" +) + +func initRouter(r *gin.Engine) { + + apiRouter := r.Group("/douyin") + + apiRouter.GET("/user/", controller.UserInfo) + apiRouter.GET("/feed/", controller.Feed) + apiRouter.GET("/publish/list/", controller.PublishList) + apiRouter.GET("/comment/list/", controller.CommentList) + //apiRouter.GET("/favorite/list/", controller.FavoriteList) + apiRouter.POST("/user/register/", controller.Register) + apiRouter.POST("/user/login/", controller.Login) + apiRouter.POST("/publish/action/", controller.Publish) + apiRouter.POST("/comment/action/", controller.CommentAction) + apiRouter.POST("/favorite/action/", controller.FavoriteAction) +} diff --git a/service/favoriteService.go b/service/favoriteService.go new file mode 100644 index 0000000..8c1133f --- /dev/null +++ b/service/favoriteService.go @@ -0,0 +1,15 @@ +package service + +import ( + "GoDance/model" +) + +func isFavorite(UserId int64, VideoId int64) bool { + fol := model.FavoriteData{} + if err := model.Db.Table("favorite").Where("user_id=? AND guest_id=?", UserId, VideoId).Find(&fol).Error; err != nil { + //没点喜欢 + return false + } + //点了喜欢 + return true +} diff --git a/service/followingService.go b/service/followingService.go new file mode 100644 index 0000000..425c38f --- /dev/null +++ b/service/followingService.go @@ -0,0 +1,15 @@ +package service + +import ( + "GoDance/model" +) + +func isFollowing(AuthorId int64, Follower int64) bool { + fol := model.Following{} + if err := model.Db.Table("following").Where("author_id=? AND follower_id=?", AuthorId, Follower).Find(&fol).Error; err != nil { + //没有关注 + return false + } + //已关注 + return true +} diff --git a/service/userService.go b/service/userService.go new file mode 100644 index 0000000..afec601 --- /dev/null +++ b/service/userService.go @@ -0,0 +1,121 @@ +package service + +import ( + "GoDance/model" + "errors" + "fmt" + "sync/atomic" +) + +var UserIdSequence = int64(1) + +func FeedResponseUser(user model.User) model.User { + return model.User{ + Id: user.Id, + Name: user.Name, + FollowCount: user.FollowCount, + FollowerCount: user.FollowerCount, + IsFollow: false, + TotalFav: user.TotalFav, + FavCount: user.FavCount, + } +} + +func GetUserInfoVO(userId int64) (model.User, error) { + db := model.Db + user := model.UserData{} + var userVO model.User + if err := db.Table("user_data").Where("user_id= ?", userId).Find(&user).Error; err != nil { + return userVO, err + } + fmt.Println(user) + userVO.FollowCount = user.FollowCount + userVO.Id = user.Id + userVO.Name = user.Name + userVO.FollowerCount = user.FollowerCount + userVO.IsFollow = user.IsFollow + return userVO, nil +} + +func Login(username string, password string) (model.UserData, error) { + var user model.UserData + model.Db.Where("name=? AND password=?", username, password).Find(&user) + fmt.Println(user) + if user.Id == 0 { + return model.UserData{}, errors.New("login failed,please check your username or password") + } else { + fmt.Println("success") + return user, nil + } +} + +func Register(username string, password string) (model.UserData, error) { + var user model.UserData + model.Db.Find(&user, "name=?", username) + if user.Id != 0 { + return model.UserData{}, errors.New("user already exist") + } else { + atomic.AddInt64(&UserIdSequence, 1) + user := model.UserData{ + Id: UserIdSequence, + Name: username, + Password: password, + FollowCount: 0, + FollowerCount: 0, + TotalFav: 0, + FavCount: 0, + IsFollow: false, + Token: username + password, + } + if model.Db.Create(&user).RowsAffected == 1 { + return user, nil + } else { + return model.UserData{}, errors.New("register failed") + } + } +} +func FindUserByToken(token string) (model.User, error) { + var user model.UserData + fmt.Println(token) + model.Db.Table("user_data").Find(&user, "token=?", token) + fmt.Println(user) + if user.Id == 0 { + return model.User{}, errors.New("user doesn't exist") + } else { + ret_user := model.User{ + Id: user.Id, + Name: user.Name, + Password: user.Password, + FollowCount: user.FollowCount, + FollowerCount: user.FollowCount, + TotalFav: user.TotalFav, + FavCount: user.FavCount, + IsFollow: user.IsFollow, + Token: user.Token, + } + fmt.Println(ret_user) + return ret_user, nil + } +} + +func FindUserById(id int64) (model.User, error) { + var user model.UserData + model.Db.Table("user_data").Find(&user, "user_id=?", id) + if user.Id == 0 { + return model.User{}, errors.New("user doesn't exist") + } else { + ret_user := model.User{ + Id: user.Id, + Name: user.Name, + Password: user.Password, + FollowCount: user.FollowCount, + FollowerCount: user.FollowCount, + TotalFav: user.TotalFav, + FavCount: user.FavCount, + IsFollow: user.IsFollow, + Token: user.Token, + } + fmt.Println(ret_user) + return ret_user, nil + } +} diff --git a/service/videoService.go b/service/videoService.go new file mode 100644 index 0000000..74cd308 --- /dev/null +++ b/service/videoService.go @@ -0,0 +1,66 @@ +package service + +import ( + "GoDance/model" + "fmt" +) + +const videoNum = 2 //单次最多返回的视频数量 + +// FeedGet 获得视频列表 +func FeedGet(currentTime int64, userId int64) (feedVideoList []model.Video, nextTime int64, err error) { + var videoList []model.VideoData + videoList = make([]model.VideoData, 0) + videoList, err = GetFeedVideoList(currentTime) + if err != nil { + fmt.Println("获取视频列表出错") + fmt.Println(err.Error()) + return nil, 0, err + } + + feedVideoList, nextTime = FeedResponseVideoList(videoList, userId) + fmt.Println(feedVideoList) + return feedVideoList, nextTime, nil +} + +func GetFeedVideoList(currentTime int64) (videoList []model.VideoData, err error) { + //按照发布时间获取视频 + err = model.Db.Table("video_data").Where("create_at < ?", currentTime).Order("create_at desc").Limit(videoNum).Find(&videoList).Error + return videoList, err +} + +// 把gorm操作的结构体转换成视频流推送的结构体 +func FeedResponseVideoList(videoList []model.VideoData, userId int64) ([]model.Video, int64) { + feedVideoList := make([]model.Video, len(videoList)) + var nextTime int64 + for i, v := range videoList { + author, _ := FindUserById(v.Author) + temp := model.Video{ + Id: v.Id, + Author: author, + PlayUrl: v.PlayUrl, + CoverUrl: v.CoverUrl, + FavoriteCount: v.FavoriteCount, + CommentCount: v.CommentCount, + IsFavorite: false, + //Title: v.Title, + //Author: FeedResponseUser(author), + } + //判断是否关注 + //if ok := isFollowing(v.AuthorId, userId); ok { + // temp.Author.IsFollow = true + //} + + //判断是否点赞 + //if ok := isFavorite(userId, v.Id); ok { + // temp.Author.IsFollow = true + //} + feedVideoList[i] = temp + + //获取最后的时间 + nextTime = v.CreateTime + } + fmt.Println(feedVideoList) + fmt.Println(nextTime) + return feedVideoList, nextTime +}