abstract tags module

pull/50/head
sunface 4 years ago
parent a7833a50c0
commit 956adfb8eb

@ -1,10 +1,10 @@
import { Box, chakra, Divider, Flex, Heading, HStack, IconButton, Image, storageKey, VStack } from "@chakra-ui/react" import { Box, chakra, Divider, Flex, Heading, HStack, IconButton, Image, storageKey, VStack } from "@chakra-ui/react"
import Comments from "components/comments/comments" import Comments from "components/comments/comments"
import Container from "components/container" import Container from "components/container"
import LikeButton from "components/posts/unicorn-like" import LikeButton from "components/story/unicorn-like"
import { MarkdownRender } from "components/markdown-editor/render" import { MarkdownRender } from "components/markdown-editor/render"
import PostAuthor from "components/posts/post-author" import PostAuthor from "components/story/post-author"
import TagTextCard from "components/posts/tag-text-card" import TagTextCard from "components/story/tag-text-card"
import SEO from "components/seo" import SEO from "components/seo"
import siteConfig from "configs/site-config" import siteConfig from "configs/site-config"
import useSession from "hooks/use-session" import useSession from "hooks/use-session"
@ -21,10 +21,10 @@ import { Comment } from "src/types/comments"
import { Post } from "src/types/posts" import { Post } from "src/types/posts"
import { Tag } from "src/types/tag" import { Tag } from "src/types/tag"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import UnicornLike from "components/posts/unicorn-like" import UnicornLike from "components/story/unicorn-like"
import SvgButton from "components/svg-button" import SvgButton from "components/svg-button"
import Bookmark from "components/posts/bookmark" import Bookmark from "components/story/bookmark"
import PostSidebar from "components/posts/post-sidebar" import PostSidebar from "components/story/post-sidebar"
const PostPage = () => { const PostPage = () => {
const router = useRouter() const router = useRouter()

@ -16,9 +16,9 @@ import { User } from "src/types/session"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import moment from 'moment' import moment from 'moment'
import { Post } from "src/types/posts" import { Post } from "src/types/posts"
import PostCard from "components/posts/post-card" import PostCard from "components/story/post-card"
import userCustomTheme from "theme/user-custom" import userCustomTheme from "theme/user-custom"
import Posts from "components/posts/posts" import Posts from "components/story/posts"
import Link from "next/link" import Link from "next/link"
import Empty from "components/empty" import Empty from "components/empty"
import Count from "components/count" import Count from "components/count"
@ -111,7 +111,7 @@ const UserPage = () => {
<Wrap mt="4" p="1"> <Wrap mt="4" p="1">
{ {
user.rawSkills.map(skill => user.rawSkills.map(skill =>
<Link href={`${ReserveUrls.Tags}/${skill.name}`}> <Link key={skill.id} href={`${ReserveUrls.Tags}/${skill.name}`}>
<HStack spacing="1" mr="4" mb="2" cursor="pointer"> <HStack spacing="1" mr="4" mb="2" cursor="pointer">
<Avatar src={skill.icon} size="sm" /> <Avatar src={skill.icon} size="sm" />
<Text>{skill.title}</Text> <Text>{skill.title}</Text>

@ -21,7 +21,7 @@ import {
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import TagCard from 'src/components/tags/tag-card' import TagCard from 'src/components/tags/tag-card'
import { Post } from "src/types/posts" import { Post } from "src/types/posts"
import Posts from "components/posts/posts" import Posts from "components/story/posts"
import { find } from "lodash" import { find } from "lodash"
import userCustomTheme from "theme/user-custom" import userCustomTheme from "theme/user-custom"
import Empty from "components/empty" import Empty from "components/empty"

@ -9,7 +9,7 @@ import { requestApi } from "utils/axios/request"
import { useDisclosure } from "@chakra-ui/react" import { useDisclosure } from "@chakra-ui/react"
import { Field, Form, Formik } from "formik" import { Field, Form, Formik } from "formik"
import { config } from "configs/config" import { config } from "configs/config"
import TextPostCard from "components/posts/text-post-card" import TextPostCard from "components/story/text-post-card"
import { Post } from "src/types/posts" import { Post } from "src/types/posts"
import { FaExternalLinkAlt, FaRegEdit } from "react-icons/fa" import { FaExternalLinkAlt, FaRegEdit } from "react-icons/fa"
import { useRouter } from "next/router" import { useRouter } from "next/router"

@ -9,9 +9,9 @@ import {
Divider Divider
} from "@chakra-ui/react" } from "@chakra-ui/react"
import Card from "components/card" import Card from "components/card"
import PostCard from "components/posts/post-card" import PostCard from "components/story/post-card"
import Posts from "components/posts/posts" import Posts from "components/story/posts"
import SimplePostCard from "components/posts/simple-post-card" import SimplePostCard from "components/story/simple-post-card"
import SEO from "components/seo" import SEO from "components/seo"
import { getSvgIcon } from "components/svg-icon" import { getSvgIcon } from "components/svg-icon"
import siteConfig from "configs/site-config" import siteConfig from "configs/site-config"

@ -3,7 +3,7 @@ import Card from "components/card"
import Container from "components/container" import Container from "components/container"
import Empty from "components/empty" import Empty from "components/empty"
import { MarkdownRender } from "components/markdown-editor/render" import { MarkdownRender } from "components/markdown-editor/render"
import Posts from "components/posts/posts" import Posts from "components/story/posts"
import SEO from "components/seo" import SEO from "components/seo"
import siteConfig from "configs/site-config" import siteConfig from "configs/site-config"
import useSession from "hooks/use-session" import useSession from "hooks/use-session"

@ -2,7 +2,6 @@ package api
import ( import (
"net/http" "net/http"
"strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/imdotdev/im.dev/server/internal/story" "github.com/imdotdev/im.dev/server/internal/story"
@ -36,7 +35,7 @@ func GetUserPosts(c *gin.Context) {
} }
func GetTagPosts(c *gin.Context) { func GetTagPosts(c *gin.Context) {
tagID, _ := strconv.ParseInt(c.Param("id"), 10, 64) tagID := c.Param("id")
user := user.CurrentUser(c) user := user.CurrentUser(c)
posts, err := story.TagPosts(user, tagID) posts, err := story.TagPosts(user, tagID)
if err != nil { if err != nil {

@ -42,16 +42,6 @@ var sqlTables = map[string]string{
updated DATETIME updated DATETIME
);`, );`,
"user_skills": `CREATE TABLE IF NOT EXISTS user_skills (
user_id VARCHAR(255),
skill_id INTEGER
);
CREATE INDEX IF NOT EXISTS user_skills_userid
ON user_skills (user_id);
CREATE INDEX IF NOT EXISTS user_skills_skillid
ON user_skills (skill_id);
`,
"sessions": `CREATE TABLE IF NOT EXISTS sessions ( "sessions": `CREATE TABLE IF NOT EXISTS sessions (
sid VARCHAR(255) primary key, sid VARCHAR(255) primary key,
user_id VARCHAR(255) user_id VARCHAR(255)
@ -78,13 +68,11 @@ var sqlTables = map[string]string{
ON posts (creator); ON posts (creator);
CREATE INDEX IF NOT EXISTS posts_created CREATE INDEX IF NOT EXISTS posts_created
ON posts (created); ON posts (created);
CREATE UNIQUE INDEX IF NOT EXISTS posts_creator_slug
ON posts (creator, slug);
`, `,
"likes": `CREATE TABLE IF NOT EXISTS likes ( "likes": `CREATE TABLE IF NOT EXISTS likes (
user_id VARCHAR(255),
story_id VARCHAR(255), story_id VARCHAR(255),
user_id VARCHAR(255),
created DATETIME NOT NULL created DATETIME NOT NULL
); );
CREATE INDEX IF NOT EXISTS likes_userid CREATE INDEX IF NOT EXISTS likes_userid
@ -93,6 +81,29 @@ var sqlTables = map[string]string{
ON likes (story_id); ON likes (story_id);
`, `,
"likes_count": `CREATE TABLE IF NOT EXISTS likes_count (
story_id VARCHAR(255) PRIMARY KEY,
count INTEGER
);
`,
"follows": `CREATE TABLE IF NOT EXISTS follows (
user_id VARCHAR(255),
target_id VARCHAR(255),
created DATETIME NOT NULL
);
CREATE INDEX IF NOT EXISTS follows_userid
ON follows (user_id);
CREATE INDEX IF NOT EXISTS follows_targetid
ON follows (target_id);
`,
"follows_count": `CREATE TABLE IF NOT EXISTS follows_count (
target_id VARCHAR(255) PRIMARY KEY,
count INTEGER
);
`,
"tags": `CREATE TABLE IF NOT EXISTS tags ( "tags": `CREATE TABLE IF NOT EXISTS tags (
id VARCHAR(255) PRIMARY KEY, id VARCHAR(255) PRIMARY KEY,
creator VARCHAR(255) NOT NULL, creator VARCHAR(255) NOT NULL,
@ -111,14 +122,14 @@ var sqlTables = map[string]string{
ON tags (created); ON tags (created);
`, `,
"tag_post": `CREATE TABLE IF NOT EXISTS tag_post ( "tags_using": `CREATE TABLE IF NOT EXISTS tags_using (
tag_id VARCHAR(255), tag_id VARCHAR(255),
post_id VARCHAR(255) target_id VARCHAR(255)
); );
CREATE INDEX IF NOT EXISTS tag_post_tagid CREATE INDEX IF NOT EXISTS tags_using_tagid
ON tag_post (tag_id); ON tags_using (tag_id);
CREATE INDEX IF NOT EXISTS tag_post_postid CREATE INDEX IF NOT EXISTS tags_using_targetid
ON tag_post (post_id); ON tags_using (target_id);
`, `,
"comments": `CREATE TABLE IF NOT EXISTS comments ( "comments": `CREATE TABLE IF NOT EXISTS comments (

@ -94,16 +94,10 @@ func SubmitPost(c *gin.Context) (map[string]string, *e.Error) {
} }
//update tags //update tags
_, err = db.Conn.Exec("DELETE FROM tag_post WHERE post_id=?", post.ID) err = tags.UpdateTargetTags(post.ID, post.Tags)
if err != nil { if err != nil {
logger.Warn("delete post tags error", "error", err) logger.Warn("upate tags error", "error", err)
} return nil, e.New(http.StatusInternalServerError, e.Internal)
for _, tag := range post.Tags {
_, err = db.Conn.Exec("INSERT INTO tag_post (tag_id,post_id) VALUES (?,?)", tag, post.ID)
if err != nil {
logger.Warn("add post tag error", "error", err)
}
} }
return map[string]string{ return map[string]string{
@ -120,7 +114,7 @@ func DeletePost(id string) *e.Error {
} }
// delete tags // delete tags
_, err = db.Conn.Exec("DELETE FROM tag_post WHERE post_id=?", id) err = tags.DeleteTargetTags(id)
if err != nil { if err != nil {
logger.Warn("delete post tags error", "error", err) logger.Warn("delete post tags error", "error", err)
} }
@ -148,24 +142,12 @@ func GetPost(id string, slug string) (*models.Post, *e.Error) {
err = ar.Creator.Query() err = ar.Creator.Query()
// get tags // get tags
t := make([]string, 0) t, rawTags, err := tags.GetTargetTags(ar.ID)
rows, err := db.Conn.Query("SELECT tag_id FROM tag_post WHERE post_id=?", ar.ID) if err != nil {
if err != nil && err != sql.ErrNoRows {
return nil, e.New(http.StatusInternalServerError, e.Internal) return nil, e.New(http.StatusInternalServerError, e.Internal)
} }
ar.RawTags = make([]*models.Tag, 0)
for rows.Next() {
var tag string
err = rows.Scan(&tag)
t = append(t, tag)
rawTag, err := tags.GetTag(tag, "")
if err == nil {
ar.RawTags = append(ar.RawTags, rawTag)
}
}
ar.Tags = t ar.Tags = t
ar.RawTags = rawTags
// add views count // add views count
_, err = db.Conn.Exec("UPDATE posts SET views=? WHERE id=?", ar.Views+1, ar.ID) _, err = db.Conn.Exec("UPDATE posts SET views=? WHERE id=?", ar.Views+1, ar.ID)

@ -40,25 +40,18 @@ func UserPosts(user *models.User, uid string) (models.Posts, *e.Error) {
return posts, nil return posts, nil
} }
func TagPosts(user *models.User, tagID int64) (models.Posts, *e.Error) { func TagPosts(user *models.User, tagID string) (models.Posts, *e.Error) {
// get post ids // get post ids
rows, err := db.Conn.Query("select post_id from tag_post where tag_id=?", tagID) postIDs, err := tags.GetTargetIDs(tagID)
if err != nil { if err != nil {
logger.Warn("get user posts error", "error", err) logger.Warn("get user posts error", "error", err)
return nil, e.New(http.StatusInternalServerError, e.Internal) return nil, e.New(http.StatusInternalServerError, e.Internal)
} }
postIDs := make([]string, 0)
for rows.Next() {
var id string
rows.Scan(&id)
postIDs = append(postIDs, id)
}
ids := strings.Join(postIDs, "','") 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,likes,views,creator,created,updated from posts where id in ('%s')", ids)
rows, err = db.Conn.Query(q) rows, err := db.Conn.Query(q)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
logger.Warn("get user posts error", "error", err) logger.Warn("get user posts error", "error", err)
return nil, e.New(http.StatusInternalServerError, e.Internal) return nil, e.New(http.StatusInternalServerError, e.Internal)
@ -97,13 +90,13 @@ func BookmarkPosts(user *models.User, filter string) (models.Posts, *e.Error) {
posts := getPosts(user, rows) posts := getPosts(user, rows)
for _, post := range posts { for _, post := range posts {
ts, err := tags.GetStoryTags(post.ID) _, rawTags, err := tags.GetTargetTags(post.ID)
if err != nil { if err != nil {
logger.Warn("get story tags error", "error", err) logger.Warn("get story tags error", "error", err)
continue continue
} }
post.RawTags = ts post.RawTags = rawTags
} }
sort.Sort(posts) sort.Sort(posts)

@ -94,7 +94,7 @@ func GetTags() (models.Tags, *e.Error) {
tag.SetCover() tag.SetCover()
tags = append(tags, tag) tags = append(tags, tag)
db.Conn.QueryRow("SELECT count(*) FROM tag_post WHERE tag_id=?", tag.ID).Scan(&tag.PostCount) db.Conn.QueryRow("SELECT count(*) FROM tags_using WHERE tag_id=?", tag.ID).Scan(&tag.PostCount)
} }
sort.Sort(tags) sort.Sort(tags)
@ -129,16 +129,16 @@ func GetTag(id string, name string) (*models.Tag, *e.Error) {
md, _ := utils.Uncompress(rawmd) md, _ := utils.Uncompress(rawmd)
tag.Md = string(md) tag.Md = string(md)
db.Conn.QueryRow("SELECT count(*) FROM tag_post WHERE tag_id=?", tag.ID).Scan(&tag.PostCount) db.Conn.QueryRow("SELECT count(*) FROM tags_using WHERE tag_id=?", tag.ID).Scan(&tag.PostCount)
tag.SetCover() tag.SetCover()
return tag, nil return tag, nil
} }
func GetSimpleTag(id int64, name string) (*models.Tag, *e.Error) { func GetSimpleTag(id string, name string) (*models.Tag, *e.Error) {
tag := &models.Tag{} tag := &models.Tag{}
err := db.Conn.QueryRow("SELECT id,title,icon from tags where id=? or name=?", id, name).Scan( err := db.Conn.QueryRow("SELECT id,name,title,icon from tags where id=? or name=?", id, name).Scan(
&tag.ID, &tag.Title, &tag.Icon, &tag.ID, &tag.Name, &tag.Title, &tag.Icon,
) )
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
@ -151,16 +151,16 @@ func GetSimpleTag(id int64, name string) (*models.Tag, *e.Error) {
return tag, nil return tag, nil
} }
func GetStoryTags(storyID string) ([]*models.Tag, error) { func GetTargetTags(targetID string) ([]string, []*models.Tag, error) {
ids := make([]int64, 0) ids := make([]string, 0)
rows, err := db.Conn.Query("SELECT tag_id FROM tag_post WHERE post_id=?", storyID) rows, err := db.Conn.Query("SELECT tag_id FROM tags_using WHERE target_id=?", targetID)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
rawTags := make([]*models.Tag, 0) rawTags := make([]*models.Tag, 0)
for rows.Next() { for rows.Next() {
var id int64 var id string
err = rows.Scan(&id) err = rows.Scan(&id)
ids = append(ids, id) ids = append(ids, id)
@ -170,5 +170,46 @@ func GetStoryTags(storyID string) ([]*models.Tag, error) {
} }
} }
return rawTags, nil return ids, rawTags, nil
}
func UpdateTargetTags(targetID string, tags []string) error {
_, err := db.Conn.Exec("DELETE FROM tags_using WHERE target_id=?", targetID)
if err != nil {
return err
}
for _, tag := range tags {
_, err = db.Conn.Exec("INSERT INTO tags_using (tag_id,target_id) VALUES (?,?)", tag, targetID)
if err != nil {
logger.Warn("add post tag error", "error", err)
}
}
return nil
}
func DeleteTargetTags(targetID string) error {
_, err := db.Conn.Exec("DELETE FROM tags_using WHERE target_id=?", targetID)
if err != nil {
return err
}
return nil
}
func GetTargetIDs(tagID string) ([]string, error) {
rows, err := db.Conn.Query("select target_id from tags_using where tag_id=?", tagID)
if err != nil {
return nil, err
}
ids := make([]string, 0)
for rows.Next() {
var id string
rows.Scan(&id)
ids = append(ids, id)
}
return ids, nil
} }

@ -54,24 +54,13 @@ func GetUserDetail(id string, username string) (*models.User, *e.Error) {
} }
// get user skills // get user skills
user.Skills = make([]string, 0) skills, rawSkills, err := tags.GetTargetTags(user.ID)
user.RawSkills = make([]*models.Tag, 0)
rows, err := db.Conn.Query("SELECT skill_id from user_skills WHERE user_id=?", user.ID)
if err != nil && err != sql.ErrNoRows {
logger.Warn("query user skills error", "error", err)
}
for rows.Next() {
var skill string
rows.Scan(&skill)
user.Skills = append(user.Skills, skill)
rawTag, err := tags.GetTag(skill, "")
if err != nil { if err != nil {
logger.Warn("get tag error", "error", err) logger.Warn("get user skills error", "error", err)
continue return nil, e.New(http.StatusInternalServerError, e.Internal)
}
user.RawSkills = append(user.RawSkills, rawTag)
} }
user.RawSkills = rawSkills
user.Skills = skills
return user, nil return user, nil
} }
@ -108,16 +97,10 @@ func UpdateUser(u *models.User) *e.Error {
} }
//update user skills //update user skills
_, err = db.Conn.Exec("DELETE FROM user_skills WHERE user_id=?", u.ID) err = tags.UpdateTargetTags(u.ID, u.Skills)
if err != nil { if err != nil {
logger.Warn("delete user skills error", "error", err) logger.Warn("upate tags error", "error", err)
} return e.New(http.StatusInternalServerError, e.Internal)
for _, skill := range u.Skills {
_, err = db.Conn.Exec("INSERT INTO user_skills (user_id,skill_id) VALUES (?,?)", u.ID, skill)
if err != nil {
logger.Warn("add user skill error", "error", err)
}
} }
return nil return nil

@ -5,7 +5,7 @@ import Card from "components/card"
import { getUserName } from "utils/user" import { getUserName } from "utils/user"
import moment from 'moment' import moment from 'moment'
import { MarkdownRender } from "components/markdown-editor/render" import { MarkdownRender } from "components/markdown-editor/render"
import Like from "components/posts/like" import Like from "components/story/like"
import { FaRegEdit, FaRegFlag, FaRegTrashAlt, FaReply, FaTrash } from "react-icons/fa" import { FaRegEdit, FaRegFlag, FaRegTrashAlt, FaReply, FaTrash } from "react-icons/fa"
import { User } from "src/types/session" import { User } from "src/types/session"
import CommentEditor from "./editor" import CommentEditor from "./editor"

@ -5,7 +5,7 @@ import Card from "components/card"
import { getUserName } from "utils/user" import { getUserName } from "utils/user"
import moment from 'moment' import moment from 'moment'
import { MarkdownRender } from "components/markdown-editor/render" import { MarkdownRender } from "components/markdown-editor/render"
import Like from "components/posts/like" import Like from "components/story/like"
import { FaRegEdit, FaRegFlag, FaRegTrashAlt, FaReply, FaTrash } from "react-icons/fa" import { FaRegEdit, FaRegFlag, FaRegTrashAlt, FaReply, FaTrash } from "react-icons/fa"
import { User } from "src/types/session" import { User } from "src/types/session"
import CommentEditor from "./editor" import CommentEditor from "./editor"

@ -3,7 +3,7 @@ import { Box, Popover, PopoverTrigger, Button, PopoverContent, PopoverBody, Inpu
import { Tag } from "src/types/tag" import { Tag } from "src/types/tag"
import { requestApi } from "utils/axios/request" import { requestApi } from "utils/axios/request"
import { cloneDeep, findIndex } from "lodash" import { cloneDeep, findIndex } from "lodash"
import TagCard from 'src/components/posts/tag-list-card' import TagCard from 'components/story/tag-list-card'
import { config } from "configs/config" import { config } from "configs/config"
interface Props { interface Props {
options: Tag[] options: Tag[]

Loading…
Cancel
Save