diff --git a/pages/editor/posts.tsx b/pages/editor/posts.tsx index 38de0749..a1da2a91 100644 --- a/pages/editor/posts.tsx +++ b/pages/editor/posts.tsx @@ -78,7 +78,7 @@ const PostsPage = () => { const editPost = (post: Post) => { if (post.url.trim() === "") { - router.push(`/story/post/${post.id}`) + router.push(`/editor/post/${post.id}`) } else { setCurrentPost(post) onOpen() @@ -86,7 +86,7 @@ const PostsPage = () => { } const onDeletePost= async (id) => { - await requestApi.delete(`/storyt/post/${id}`) + await requestApi.delete(`/story/post/${id}`) getPosts() toast({ description: "删除成功", diff --git a/server/internal/storage/sql_tables.go b/server/internal/storage/sql_tables.go index aab10fb2..6ee2bc32 100644 --- a/server/internal/storage/sql_tables.go +++ b/server/internal/storage/sql_tables.go @@ -57,9 +57,6 @@ var sqlTables = map[string]string{ url VARCHAR(255), cover VARCHAR(255), brief TEXT, - likes INTEGER DEFAULT 0, - views INTEGER DEFAULT 0, - comments INTEGER DEFAULT 0, status tinyint NOT NULL, created DATETIME NOT NULL, updated DATETIME @@ -112,7 +109,6 @@ var sqlTables = map[string]string{ icon VARCHAR(255), cover VARCHAR(255), md TEXT, - follower_count INTEGER DEFAULT 0, created DATETIME NOT NULL, updated DATETIME ); @@ -124,12 +120,15 @@ var sqlTables = map[string]string{ "tags_using": `CREATE TABLE IF NOT EXISTS tags_using ( tag_id VARCHAR(255), + target_type VARCHAR(1), target_id VARCHAR(255) ); CREATE INDEX IF NOT EXISTS tags_using_tagid ON tags_using (tag_id); CREATE INDEX IF NOT EXISTS tags_using_targetid ON tags_using (target_id); + CREATE INDEX IF NOT EXISTS tags_using_idtype + ON tags_using (tag_id,target_type); `, "comments": `CREATE TABLE IF NOT EXISTS comments ( @@ -137,7 +136,6 @@ var sqlTables = map[string]string{ target_id VARCHAR(255), creator VARCHAR(255), MD TEXT, - likes INTEGER DEFAULT 0, created DATETIME NOT NULL, updated DATETIME ); diff --git a/server/internal/story/comment.go b/server/internal/story/comment.go index 76fa9ffa..ad554f5f 100644 --- a/server/internal/story/comment.go +++ b/server/internal/story/comment.go @@ -73,7 +73,7 @@ func EditComment(c *models.Comment) *e.Error { func GetComments(storyID string) (models.Comments, *e.Error) { comments := make(models.Comments, 0) - rows, err := db.Conn.Query("SELECT id,target_id,creator,md,likes,created,updated FROM comments WHERE target_id=?", storyID) + rows, err := db.Conn.Query("SELECT id,target_id,creator,md,created,updated FROM comments WHERE target_id=?", storyID) if err != nil && err != sql.ErrNoRows { logger.Warn("get comments error", "error", err) return comments, e.New(http.StatusInternalServerError, e.Internal) @@ -82,7 +82,7 @@ func GetComments(storyID string) (models.Comments, *e.Error) { for rows.Next() { c := &models.Comment{} var rawMd []byte - err := rows.Scan(&c.ID, &c.TargetID, &c.CreatorID, &rawMd, &c.Likes, &c.Created, &c.Updated) + err := rows.Scan(&c.ID, &c.TargetID, &c.CreatorID, &rawMd, &c.Created, &c.Updated) if err != nil { logger.Warn("scan comment error", "error", err) continue @@ -94,6 +94,8 @@ func GetComments(storyID string) (models.Comments, *e.Error) { c.Creator = &models.UserSimple{ID: c.CreatorID} err = c.Creator.Query() + c.Likes = GetLikes(c.ID) + comments = append(comments, c) } @@ -105,8 +107,8 @@ func GetComments(storyID string) (models.Comments, *e.Error) { func GetComment(id string) (*models.Comment, *e.Error) { c := &models.Comment{} var rawMd []byte - err := db.Conn.QueryRow("SELECT id,target_id,creator,md,likes,created,updated FROM comments WHERE id=?", id).Scan( - &c.ID, &c.TargetID, &c.CreatorID, &rawMd, &c.Likes, &c.Created, &c.Updated, + err := db.Conn.QueryRow("SELECT id,target_id,creator,md,created,updated FROM comments WHERE id=?", id).Scan( + &c.ID, &c.TargetID, &c.CreatorID, &rawMd, &c.Created, &c.Updated, ) if err != nil { logger.Warn("get comment error", "error", err) @@ -116,6 +118,7 @@ func GetComment(id string) (*models.Comment, *e.Error) { md, _ := utils.Uncompress(rawMd) c.Md = string(md) + c.Likes = GetLikes(c.ID) return c, nil } @@ -140,25 +143,35 @@ func DeleteComment(id string) *e.Error { } count += 1 - _, err = db.Conn.Exec("UPDATE comments_count SET count=count-? WHERE story_id=?", count, storyID) + tx, err := db.Conn.Begin() + if err != nil { + logger.Warn("start sql transaction error", "error", err) + return e.New(http.StatusInternalServerError, e.Internal) + } + + _, err = tx.Exec("UPDATE comments_count SET count=count-? WHERE story_id=?", count, storyID) if err != nil { logger.Warn("update comments_count error", "error", err) return e.New(http.StatusInternalServerError, e.Internal) } // delete children replies - _, err = db.Conn.Exec("DELETE FROM comments WHERE target_id=?", id) + _, err = tx.Exec("DELETE FROM comments WHERE target_id=?", id) if err != nil { logger.Warn("delete comment replies error", "error", err) + tx.Rollback() return e.New(http.StatusInternalServerError, e.Internal) } - _, err = db.Conn.Exec("DELETE FROM comments WHERE id=?", id) + _, err = tx.Exec("DELETE FROM comments WHERE id=?", id) if err != nil { logger.Warn("delete comment error", "error", err) + tx.Rollback() return e.New(http.StatusInternalServerError, e.Internal) } + tx.Commit() + return nil } diff --git a/server/internal/story/like.go b/server/internal/story/like.go index b88768a3..66f53f5d 100644 --- a/server/internal/story/like.go +++ b/server/internal/story/like.go @@ -2,7 +2,6 @@ package story import ( "database/sql" - "fmt" "net/http" "time" @@ -16,27 +15,53 @@ func Like(storyID string, userId string) *e.Error { return e.New(http.StatusNotFound, e.NotFound) } - tbl := getStorySqlTable(storyID) // 查询当前like状态 liked := GetLiked(storyID, userId) + var count int + err := db.Conn.QueryRow("SELECT count FROM likes_count WHERE story_id=?", storyID).Scan(&count) + if err != nil && err != sql.ErrNoRows { + logger.Warn("query likes count error", "error", err) + return e.New(http.StatusInternalServerError, e.Internal) + } + exist = !(err == sql.ErrNoRows) + + tx, err := db.Conn.Begin() + if err != nil { + logger.Warn("start like transaction error", "error", err) + return e.New(http.StatusInternalServerError, e.Internal) + } + if liked { // 已经喜欢过该篇文章,更改为不喜欢 - _, err := db.Conn.Exec("DELETE FROM likes WHERE story_id=? and user_id=?", storyID, userId) + _, err := tx.Exec("DELETE FROM likes WHERE story_id=? and user_id=?", storyID, userId) if err != nil { return e.New(http.StatusInternalServerError, e.Internal) } - - db.Conn.Exec(fmt.Sprintf("UPDATE %s SET likes=likes-1 WHERE id=?", tbl), storyID) + count = count - 1 } else { - _, err := db.Conn.Exec("INSERT INTO likes (story_id,user_id,created) VALUES (?,?,?)", storyID, userId, time.Now()) + _, err := tx.Exec("INSERT INTO likes (story_id,user_id,created) VALUES (?,?,?)", storyID, userId, time.Now()) if err != nil { logger.Warn("add like error", "error", err) return e.New(http.StatusInternalServerError, e.Internal) } - db.Conn.Exec(fmt.Sprintf("UPDATE %s SET likes=likes+1 WHERE id=?", tbl), storyID) + count = count + 1 } + var err0 error + if !exist { + _, err0 = tx.Exec("INSERT INTO likes_count (story_id,count) VALUES (?,?)", storyID, count) + } else { + _, err0 = tx.Exec("UPDATE likes_count SET count=? WHERE story_id=?", count, storyID) + } + + if err0 != nil { + logger.Warn("add like error", "error", err0) + tx.Rollback() + return e.New(http.StatusInternalServerError, e.Internal) + } + + tx.Commit() return nil } @@ -55,3 +80,13 @@ func GetLiked(storyID string, userID string) bool { return liked } + +func GetLikes(storyID string) int { + var likes int + err := db.Conn.QueryRow("SELECT count FROM likes_count WHERE story_id=?", storyID).Scan(&likes) + if err != nil && err != sql.ErrNoRows { + logger.Warn("get like count error", "error", err) + } + + return likes +} diff --git a/server/internal/story/post.go b/server/internal/story/post.go index fda15908..b14930f9 100644 --- a/server/internal/story/post.go +++ b/server/internal/story/post.go @@ -107,26 +107,35 @@ func SubmitPost(c *gin.Context) (map[string]string, *e.Error) { } func DeletePost(id string) *e.Error { - _, err := db.Conn.Exec("DELETE FROM posts WHERE id=?", id) + tx, err := db.Conn.Begin() + if err != nil { + logger.Warn("start sql transaction error", "error", err) + return e.New(http.StatusInternalServerError, e.Internal) + } + + _, err = tx.Exec("DELETE FROM posts WHERE id=?", id) if err != nil { logger.Warn("delete post error", "error", err) return e.New(http.StatusInternalServerError, e.Internal) } // delete tags - err = tags.DeleteTargetTags(id) + err = tags.DeleteTargetTags(tx, id) if err != nil { logger.Warn("delete post tags error", "error", err) + tx.Rollback() } + tx.Commit() + return nil } func GetPost(id string, slug string) (*models.Post, *e.Error) { ar := &models.Post{} var rawmd []byte - err := db.Conn.QueryRow("select id,slug,title,md,url,cover,brief,creator,likes,views,created,updated from posts where id=? or slug=?", id, slug).Scan( - &ar.ID, &ar.Slug, &ar.Title, &rawmd, &ar.URL, &ar.Cover, &ar.Brief, &ar.CreatorID, &ar.Likes, &ar.Views, &ar.Created, &ar.Updated, + err := db.Conn.QueryRow("select id,slug,title,md,url,cover,brief,creator,created,updated from posts where id=? or slug=?", id, slug).Scan( + &ar.ID, &ar.Slug, &ar.Title, &rawmd, &ar.URL, &ar.Cover, &ar.Brief, &ar.CreatorID, &ar.Created, &ar.Updated, ) if err != nil { if err == sql.ErrNoRows { @@ -149,13 +158,7 @@ func GetPost(id string, slug string) (*models.Post, *e.Error) { ar.Tags = t ar.RawTags = rawTags - // add views count - _, err = db.Conn.Exec("UPDATE posts SET views=? WHERE id=?", ar.Views+1, ar.ID) - if err != nil { - logger.Warn("update post view count error", "error", err) - } - - //get bookmared + ar.Likes = GetLikes(ar.ID) return ar, nil } diff --git a/server/internal/story/posts.go b/server/internal/story/posts.go index 795f5f95..83ae6669 100644 --- a/server/internal/story/posts.go +++ b/server/internal/story/posts.go @@ -15,7 +15,7 @@ import ( func HomePosts(user *models.User, filter string) (models.Posts, *e.Error) { - rows, err := db.Conn.Query("select id,slug,title,url,cover,brief,likes,views,creator,created,updated from posts") + rows, err := db.Conn.Query("select id,slug,title,url,cover,brief,creator,created,updated from posts") if err != nil && err != sql.ErrNoRows { logger.Warn("get user posts error", "error", err) return nil, e.New(http.StatusInternalServerError, e.Internal) @@ -28,7 +28,7 @@ func HomePosts(user *models.User, filter string) (models.Posts, *e.Error) { } func UserPosts(user *models.User, uid string) (models.Posts, *e.Error) { - rows, err := db.Conn.Query("select id,slug,title,url,cover,brief,likes,views,creator,created,updated from posts where creator=?", uid) + rows, err := db.Conn.Query("select id,slug,title,url,cover,brief,creator,created,updated from posts where creator=?", uid) if err != nil && err != sql.ErrNoRows { logger.Warn("get user posts error", "error", err) return nil, e.New(http.StatusInternalServerError, e.Internal) @@ -50,7 +50,7 @@ func TagPosts(user *models.User, tagID string) (models.Posts, *e.Error) { ids := strings.Join(postIDs, "','") - q := fmt.Sprintf("select id,slug,title,url,cover,brief,likes,views,creator,created,updated from posts where id in ('%s')", ids) + q := fmt.Sprintf("select id,slug,title,url,cover,brief,creator,created,updated from posts where id in ('%s')", ids) rows, err := db.Conn.Query(q) if err != nil && err != sql.ErrNoRows { logger.Warn("get user posts error", "error", err) @@ -80,7 +80,7 @@ func BookmarkPosts(user *models.User, filter string) (models.Posts, *e.Error) { ids := strings.Join(postIDs, "','") - q := fmt.Sprintf("select id,slug,title,url,cover,brief,likes,views,creator,created,updated from posts where id in ('%s')", ids) + q := fmt.Sprintf("select id,slug,title,url,cover,brief,creator,created,updated from posts where id in ('%s')", ids) rows, err = db.Conn.Query(q) if err != nil && err != sql.ErrNoRows { logger.Warn("get user posts error", "error", err) @@ -107,7 +107,7 @@ func getPosts(user *models.User, rows *sql.Rows) models.Posts { posts := make(models.Posts, 0) for rows.Next() { ar := &models.Post{} - err := rows.Scan(&ar.ID, &ar.Slug, &ar.Title, &ar.URL, &ar.Cover, &ar.Brief, &ar.Likes, &ar.Views, &ar.CreatorID, &ar.Created, &ar.Updated) + err := rows.Scan(&ar.ID, &ar.Slug, &ar.Title, &ar.URL, &ar.Cover, &ar.Brief, &ar.CreatorID, &ar.Created, &ar.Updated) if err != nil { logger.Warn("scan post error", "error", err) continue @@ -125,9 +125,11 @@ func getPosts(user *models.User, rows *sql.Rows) models.Posts { if user != nil { ar.Liked = GetLiked(ar.ID, user.ID) } + ar.Likes = GetLikes(ar.ID) // 获取当前登录用户的bookmark ar.Bookmarked, _ = Bookmarked(user.ID, ar.ID) + posts = append(posts, ar) } diff --git a/server/internal/story/story.go b/server/internal/story/story.go index f94e3107..8bcecc74 100644 --- a/server/internal/story/story.go +++ b/server/internal/story/story.go @@ -17,14 +17,3 @@ func Exist(id string) bool { return false } } - -func getStorySqlTable(id string) string { - switch id[:1] { - case models.IDTypePost: - return "posts" - case models.IDTypeComment: - return "comments" - default: - return "unknown" - } -} diff --git a/server/internal/tags/tags.go b/server/internal/tags/tags.go index 894edd5f..efb5d896 100644 --- a/server/internal/tags/tags.go +++ b/server/internal/tags/tags.go @@ -180,7 +180,7 @@ func UpdateTargetTags(targetID string, tags []string) error { } for _, tag := range tags { - _, err = db.Conn.Exec("INSERT INTO tags_using (tag_id,target_id) VALUES (?,?)", tag, targetID) + _, err = db.Conn.Exec("INSERT INTO tags_using (tag_id,target_type,target_id) VALUES (?,?,?)", tag, models.GetIDType(targetID), targetID) if err != nil { logger.Warn("add post tag error", "error", err) } @@ -189,8 +189,14 @@ func UpdateTargetTags(targetID string, tags []string) error { return nil } -func DeleteTargetTags(targetID string) error { - _, err := db.Conn.Exec("DELETE FROM tags_using WHERE target_id=?", targetID) +func DeleteTargetTags(tx *sql.Tx, targetID string) error { + var err error + if tx != nil { + _, err = tx.Exec("DELETE FROM tags_using WHERE target_id=?", targetID) + } else { + _, err = db.Conn.Exec("DELETE FROM tags_using WHERE target_id=?", targetID) + } + if err != nil { return err } diff --git a/server/pkg/models/id_type.go b/server/pkg/models/id_type.go index cdbfb994..4a109361 100644 --- a/server/pkg/models/id_type.go +++ b/server/pkg/models/id_type.go @@ -6,3 +6,26 @@ const ( IDTypeUser = "3" IDTypeTag = "4" ) + +func GetIDType(id string) string { + if id == "" { + return "" + } + + return id[:1] +} + +func GetIdTypeTable(id string) string { + switch id[:1] { + case IDTypePost: + return "posts" + case IDTypeComment: + return "comments" + case IDTypeUser: + return "user" + case IDTypeTag: + return "tags" + default: + return "unknown" + } +} diff --git a/src/components/comments/comment.tsx b/src/components/comments/comment.tsx index 0cf97441..b6441ba4 100644 --- a/src/components/comments/comment.tsx +++ b/src/components/comments/comment.tsx @@ -5,7 +5,7 @@ import Card from "components/card" import { getUserName } from "utils/user" import moment from 'moment' import { MarkdownRender } from "components/markdown-editor/render" -import Like from "components/story/like" +import Like from "components/story/like" import { FaRegEdit, FaRegFlag, FaRegTrashAlt, FaReply, FaTrash } from "react-icons/fa" import { User } from "src/types/session" import CommentEditor from "./editor"