pull/50/head
sunface 4 years ago
parent 5717798903
commit a7833a50c0

@ -3,6 +3,7 @@ common:
version: 0.1.0
log_level: "info"
is_prod: false
app_name: "im.dev"
#################################### Server ##############################
server:

@ -16,7 +16,7 @@ export let config = {
}
export function initUIConfig() {
requestApi.get("/uiconfig").then((res) => {
requestApi.get("/config").then((res) => {
console.log("初始化UI config:", res.data)
config = res.data
})}

@ -69,7 +69,7 @@ import { getSvgIcon } from "components/svg-icon"
<VStack pt="6" ml={{ base: 1, md: 4, lg: 12 }} fontSize="1rem" alignItems="left">
{navLinks.map(link =>
<Link href={link.url}>
<Link href={link.url} key={link.title}>
<HStack cursor="pointer" px="4" py="0.7rem" rounded="md" key={link.url} color={useColorModeValue("gray.700", "whiteAlpha.900")} aria-current={asPath === link.url ? "page" : undefined} _activeLink={{ bg: useColorModeValue("transparent", "rgba(48, 140, 122, 0.3)"), color: useColorModeValue("teal.500", "teal.200"), fontWeight: "bold", }} >
<Box width="25px">{link.icon}</Box><Text>{link.title}</Text>
</HStack>

@ -47,7 +47,7 @@ const PostPage = () => {
}, [router])
const getData = async () => {
const res = await requestApi.get(`/post/${id}`)
const res = await requestApi.get(`/story/post/${id}`)
setPost(res.data)
getComments(res.data.id)

@ -71,8 +71,11 @@ const UserPage = () => {
<HStack spacing={[0, 0, 4, 4]} mt="4" alignItems="top">
<VStack alignItems="left" spacing="4" width="350px" display={{ base: "none", md: "flex" }}>
<Card>
{user.about &&
<>
<Text layerStyle="textSecondary">{user.about}</Text>
<Divider my="4" />
</>}
{user.location && <HStack>
<chakra.span layerStyle="textSecondary" width="90px">Location: </chakra.span>
<chakra.span fontWeight="500" ml="2">{user.location}</chakra.span>
@ -96,9 +99,9 @@ const UserPage = () => {
{user.zhihu && <chakra.a href={user.zhihu} target="_blank"><FaZhihu /></chakra.a>}
{user.weibo && <chakra.a href={user.weibo} target="_blank"><FaWeibo /></chakra.a>}
</HStack>
<Divider my="4" />
{user.availFor && <Box>
<Divider my="4" />
<Text fontWeight="600" layerStyle="textSecondary">I am available for</Text>
<Text mt="2">{user.availFor}</Text>
</Box>}

@ -47,7 +47,7 @@ function PostEditPage() {
const publish = async () => {
const res = await requestApi.post(`/admin/tag`, tag)
const res = await requestApi.post(`/tag`, tag)
toast({
description: "发布成功",
status: "success",

@ -21,7 +21,7 @@ const PostsPage = () => {
const router = useRouter()
const toast = useToast()
const getTags = () => {
requestApi.get(`/tags`).then((res) => setTags(res.data)).catch(_ => setTags([]))
requestApi.get(`/tag/all`).then((res) => setTags(res.data)).catch(_ => setTags([]))
}
useEffect(() => {
@ -33,7 +33,7 @@ const PostsPage = () => {
}
const deleteTag= async (id) => {
await requestApi.delete(`/admin/tag/${id}`)
await requestApi.delete(`/tag/${id}`)
getTags()
toast({
description: "删除成功",

@ -43,7 +43,7 @@ import Empty from "components/empty"
}, [filter])
const getBookmarkPosts = async() => {
const res = await requestApi.get(`/bookmark/posts`)
const res = await requestApi.get(`/story/bookmark/posts`)
setRawPosts(res.data)
setPosts(res.data)
const ts = [{id:-1,title:'All Tags',icon: 'https://cdn.hashnode.com/res/hashnode/image/upload/v1605105898259/3vuMFM8qM.png?w=200&h=200&fit=crop&crop=entropy&auto=compress&auto=compress'}]

@ -28,7 +28,7 @@ function PostEditPage() {
const toast = useToast()
useEffect(() => {
if (id && id !== 'new') {
requestApi.get(`/editor/post/${id}`).then(res => setAr(res.data))
requestApi.get(`/story/post/${id}`).then(res => setAr(res.data))
}
}, [id])
@ -58,7 +58,7 @@ function PostEditPage() {
}
const publish = async () => {
const res = await requestApi.post(`/editor/post`, ar)
const res = await requestApi.post(`/story/post`, ar)
toast({
description: "发布成功",
status: "success",

@ -26,7 +26,7 @@ const PostsPage = () => {
const router = useRouter()
const toast = useToast()
const getPosts = () => {
requestApi.get(`/editor/posts`).then((res) => setPosts(res.data)).catch(_ => setPosts([]))
requestApi.get(`/story/posts/editor`).then((res) => setPosts(res.data)).catch(_ => setPosts([]))
}
useEffect(() => {
@ -64,7 +64,7 @@ const PostsPage = () => {
}
const submitPost = async (values, _) => {
await requestApi.post(`/editor/post`, values)
await requestApi.post(`/story/post`, values)
onClose()
toast({
description: "提交成功",
@ -78,7 +78,7 @@ const PostsPage = () => {
const editPost = (post: Post) => {
if (post.url.trim() === "") {
router.push(`/editor/post/${post.id}`)
router.push(`/story/post/${post.id}`)
} else {
setCurrentPost(post)
onOpen()
@ -86,7 +86,7 @@ const PostsPage = () => {
}
const onDeletePost= async (id) => {
await requestApi.delete(`/editor/post/${id}`)
await requestApi.delete(`/storyt/post/${id}`)
getPosts()
toast({
description: "删除成功",

@ -24,7 +24,7 @@ const HomePage = () => {
const [posts, setPosts] = useState([])
const [filter, setFilter] = useState(PostFilter.Best)
const initData = async () => {
const res = await requestApi.get(`/home/posts/${filter}`)
const res = await requestApi.get(`/story/posts/home/${filter}`)
setPosts(res.data)
}
@ -86,7 +86,7 @@ export const HomeSidebar = () => {
const [posts, setPosts] = useState([])
const [filter, setFilter] = useState(PostFilter.Best)
const initData = async () => {
const res = await requestApi.get(`/home/posts/${filter}`)
const res = await requestApi.get(`/story/posts/home/${filter}`)
setPosts(res.data)
}

@ -20,7 +20,7 @@ import { useRouter } from "next/router"
const LoginPage = () => {
const router = useRouter()
const login = async () => {
const res = await requestApi.post("/login")
const res = await requestApi.post("/user/login")
saveToken(res.data.token)
storage.set('session', res.data)
const oldPage = storage.get('current-page')

@ -298,11 +298,11 @@ const UserProfilePage = () => {
</Card>
<Box mt={6}>
<Button
// colorScheme="teal"
// variant="outline"
colorScheme="cyan"
variant="outline"
type="submit"
_focus={null}
layerStyle="colorButton"
>
</Button>

@ -40,7 +40,7 @@ const TagsPage = () => {
const [filter, setFilter] = useState(tagsFilter[0])
const [tags, setTags]: [Tag[], any] = useState([])
const getTags = () => {
requestApi.get(`/tags`).then((res) => setTags(res.data)).catch(_ => setTags([]))
requestApi.get(`/tag/all`).then((res) => setTags(res.data)).catch(_ => setTags([]))
}
useEffect(() => {
@ -81,7 +81,7 @@ const TagsPage = () => {
/>
<MenuList>
{
tagsFilter.map(f => <MenuItem onClick={() => setFilter(f)}>
tagsFilter.map(f => <MenuItem key={f.name} onClick={() => setFilter(f)}>
{f.name}
</MenuItem>)
}
@ -91,7 +91,7 @@ const TagsPage = () => {
<Divider mt="3" mb="5" />
<VStack alignItems="left" spacing="3">
{tags.map(t => <TagCard tag={t}/>)}
{tags.map(t => <TagCard key={t.id} tag={t}/>)}
</VStack>
</Card>
</VStack>

@ -34,7 +34,7 @@ func SubmitComment(c *gin.Context) {
if comment.ID == "" { //add comment
user := user.CurrentUser(c)
comment.CreatorID = user.ID
comment.ID = utils.GenStoryID(models.StoryComment)
comment.ID = utils.GenID(models.IDTypeComment)
err = story.AddComment(comment)
} else { // update comment
err = story.EditComment(comment)
@ -78,7 +78,7 @@ func GetStoryComments(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(comments))
}
func DeleteComment(c *gin.Context) {
func DeleteStoryComment(c *gin.Context) {
id := c.Param("id")
//only admin and owner can delete comment
comment, err := story.GetComment(id)

@ -12,7 +12,7 @@ import (
func GetEditorPosts(c *gin.Context) {
user := user.CurrentUser(c)
ars, err := story.UserPosts(user, int64(user.ID))
ars, err := story.UserPosts(user, user.ID)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
@ -22,7 +22,7 @@ func GetEditorPosts(c *gin.Context) {
}
func GetUserPosts(c *gin.Context) {
userID, _ := strconv.ParseInt(c.Param("userID"), 10, 64)
userID := c.Param("userID")
user := user.CurrentUser(c)

@ -47,7 +47,7 @@ func DeletePost(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(nil))
}
func GetPost(c *gin.Context) {
func GetStoryPost(c *gin.Context) {
id := c.Param("id")
user := user.CurrentUser(c)
@ -95,31 +95,3 @@ func Bookmark(c *gin.Context) {
c.JSON(http.StatusOK, common.RespSuccess(nil))
}
func GetEditorPost(c *gin.Context) {
id := c.Param("id")
if id == "" {
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
return
}
user := user.CurrentUser(c)
creator, err := story.GetPostCreator(id)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
}
if user.ID != creator {
c.JSON(http.StatusForbidden, common.RespError(e.NoPermission))
return
}
ar, err := story.GetPost(id, "")
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return
}
c.JSON(http.StatusOK, common.RespSuccess(ar))
}

@ -14,7 +14,7 @@ import (
func GetTag(c *gin.Context) {
name := c.Param("name")
res, err := tags.GetTag(0, name)
res, err := tags.GetTag("", name)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return

@ -36,7 +36,7 @@ func GetUserSelf(c *gin.Context) {
func GetUser(c *gin.Context) {
username := c.Param("username")
userDetail, err := user.GetUserDetail(0, username)
userDetail, err := user.GetUserDetail("", username)
if err != nil {
c.JSON(err.Status, common.RespError(err.Message))
return

@ -8,7 +8,7 @@ import (
"github.com/imdotdev/im.dev/server/pkg/config"
)
type UIConfig struct {
type Config struct {
AppName string `json:"appName"`
CommonMaxLen int `json:"commonMaxlen"`
Posts *PostsConfig `json:"posts"`
@ -28,8 +28,8 @@ type UserConfig struct {
}
// 在后台页面配置存储到mysql中
func GetUIConfig(c *gin.Context) {
conf := &UIConfig{
func GetConfig(c *gin.Context) {
conf := &Config{
AppName: config.Data.Common.AppName,
CommonMaxLen: 255,
Posts: &PostsConfig{

@ -43,45 +43,39 @@ func (s *Server) Start() error {
router.Use(Cors())
r := router.Group("/api")
{
r.POST("/login", user.Login)
r.POST("/logout", user.Logout)
r.GET("/uiconfig", GetUIConfig)
}
r.GET("/post/:id", api.GetPost)
//story apis
r.GET("/story/post/:id", api.GetStoryPost)
r.POST("/story/like/:id", IsLogin(), api.LikeStory)
r.GET("/story/comments/:id", api.GetStoryComments)
r.POST("/story/comment", IsLogin(), api.SubmitComment)
r.DELETE("/comment/:id", IsLogin(), api.DeleteComment)
r.GET("/editor/posts", IsLogin(), api.GetEditorPosts)
r.POST("/editor/post", IsLogin(), api.SubmitPost)
r.DELETE("/editor/post/:id", IsLogin(), api.DeletePost)
r.GET("/editor/post/:id", IsLogin(), api.GetEditorPost)
r.POST("/admin/tag", IsLogin(), api.SubmitTag)
r.DELETE("/admin/tag/:id", IsLogin(), api.DeleteTag)
r.GET("/tags", api.GetTags)
r.DELETE("/story/comment/:id", IsLogin(), api.DeleteStoryComment)
r.GET("/story/posts/editor", IsLogin(), api.GetEditorPosts)
r.GET("/story/posts/home/:filter", api.GetHomePosts)
r.POST("/story/post", IsLogin(), api.SubmitPost)
r.DELETE("/story/post/:id", IsLogin(), api.DeletePost)
r.POST("/story/bookmark/:storyID", IsLogin(), api.Bookmark)
r.GET("/story/bookmark/posts", IsLogin(), api.GetBookmarkPosts)
// tag apis
r.POST("/tag", IsLogin(), api.SubmitTag)
r.DELETE("/tag/:id", IsLogin(), api.DeleteTag)
r.GET("/tag/all", api.GetTags)
r.GET("/tag/posts/:id", api.GetTagPosts)
r.GET("/tag/info/:name", api.GetTag)
r.GET("/users", api.GetUsers)
// user apis
r.GET("/user/all", api.GetUsers)
r.GET("/user/self", IsLogin(), api.GetUserSelf)
r.GET("/user/info/:username", api.GetUser)
r.POST("/user/update", IsLogin(), api.UpdateUser)
r.GET("/user/posts/:userID", api.GetUserPosts)
r.GET("/user/session", IsLogin(), api.GetSession)
r.POST("/user/login", user.Login)
r.POST("/user/logout", user.Logout)
r.GET("/home/posts/:filter", api.GetHomePosts)
r.GET("/session", IsLogin(), api.GetSession)
r.POST("/bookmark/:storyID", IsLogin(), api.Bookmark)
r.GET("/bookmark/posts", IsLogin(), api.GetBookmarkPosts)
// other apis
r.GET("/config", GetConfig)
err := router.Run(config.Data.Server.Addr)
if err != nil {

@ -2,7 +2,7 @@ package storage
var sqlTables = map[string]string{
"user": `CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
id VARCHAR(255) PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
nickname VARCHAR(255) DEFAULT '',
avatar VARCHAR(255) DEFAULT '',
@ -23,7 +23,7 @@ var sqlTables = map[string]string{
ON user (email);`,
"user_profile": `CREATE TABLE IF NOT EXISTS user_profile (
id INTEGER PRIMARY KEY,
id VARCHAR(255) PRIMARY KEY,
tagline VARCHAR(255),
cover VARCHAR(255),
@ -43,7 +43,7 @@ var sqlTables = map[string]string{
);`,
"user_skills": `CREATE TABLE IF NOT EXISTS user_skills (
user_id INTEGER,
user_id VARCHAR(255),
skill_id INTEGER
);
CREATE INDEX IF NOT EXISTS user_skills_userid
@ -54,13 +54,13 @@ var sqlTables = map[string]string{
"sessions": `CREATE TABLE IF NOT EXISTS sessions (
sid VARCHAR(255) primary key,
user_id INTEGER
user_id VARCHAR(255)
);
`,
"posts": `CREATE TABLE IF NOT EXISTS posts (
id VARCHAR(255) PRIMARY KEY,
creator INTEGER NOT NULL,
creator VARCHAR(255) NOT NULL,
slug VARCHAR(64) NOT NULL,
title VARCHAR(255) NOT NULL,
md TEXT,
@ -82,20 +82,20 @@ var sqlTables = map[string]string{
ON posts (creator, slug);
`,
"like": `CREATE TABLE IF NOT EXISTS like (
id VARCHAR(255),
user_id INTEGER,
"likes": `CREATE TABLE IF NOT EXISTS likes (
user_id VARCHAR(255),
story_id VARCHAR(255),
created DATETIME NOT NULL
);
CREATE INDEX IF NOT EXISTS like_id
ON like (id);
CREATE INDEX IF NOT EXISTS like_userid
ON like (user_id);
CREATE INDEX IF NOT EXISTS likes_userid
ON likes (user_id);
CREATE INDEX IF NOT EXISTS likes_storyid
ON likes (story_id);
`,
"tags": `CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
creator INTEGER NOT NULL,
id VARCHAR(255) PRIMARY KEY,
creator VARCHAR(255) NOT NULL,
title VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
icon VARCHAR(255),
@ -112,7 +112,7 @@ var sqlTables = map[string]string{
`,
"tag_post": `CREATE TABLE IF NOT EXISTS tag_post (
tag_id INTEGER,
tag_id VARCHAR(255),
post_id VARCHAR(255)
);
CREATE INDEX IF NOT EXISTS tag_post_tagid
@ -124,7 +124,7 @@ var sqlTables = map[string]string{
"comments": `CREATE TABLE IF NOT EXISTS comments (
id VARCHAR(255) PRIMARY KEY,
target_id VARCHAR(255),
creator INTEGER,
creator VARCHAR(255),
MD TEXT,
likes INTEGER DEFAULT 0,
created DATETIME NOT NULL,
@ -143,7 +143,7 @@ var sqlTables = map[string]string{
`,
"bookmarks": `CREATE TABLE IF NOT EXISTS bookmarks (
user_id INTEGER,
user_id VARCHAR(255),
story_id VARCHAR(255),
created DATETIME
);

@ -8,7 +8,7 @@ import (
"github.com/imdotdev/im.dev/server/pkg/e"
)
func Bookmark(userID int64, storyID string) *e.Error {
func Bookmark(userID string, storyID string) *e.Error {
storyExist := Exist(storyID)
if !storyExist {
return e.New(http.StatusNotFound, e.NotFound)
@ -36,7 +36,7 @@ func Bookmark(userID int64, storyID string) *e.Error {
return nil
}
func Bookmarked(userID int64, storyID string) (bool, error) {
func Bookmarked(userID string, storyID string) (bool, error) {
var nid string
err := db.Conn.QueryRow("select story_id from bookmarks where user_id=? and story_id=?", userID, storyID).Scan(&nid)
if err != nil && err != sql.ErrNoRows {

@ -195,9 +195,9 @@ func GetStoryIDByCommentID(cid string) (string, bool, error) {
}
switch targetID[:1] {
case models.StoryPost:
case models.IDTypePost:
return targetID, true, nil
case models.StoryComment:
case models.IDTypeComment:
var nid string
err := db.Conn.QueryRow("select target_id from comments where id=?", targetID).Scan(&nid)
if err != nil {

@ -10,7 +10,7 @@ import (
"github.com/imdotdev/im.dev/server/pkg/e"
)
func Like(storyID string, userId int64) *e.Error {
func Like(storyID string, userId string) *e.Error {
exist := Exist(storyID)
if !exist {
return e.New(http.StatusNotFound, e.NotFound)
@ -22,14 +22,14 @@ func Like(storyID string, userId int64) *e.Error {
if liked {
// 已经喜欢过该篇文章,更改为不喜欢
_, err := db.Conn.Exec("DELETE FROM like WHERE id=? and user_id=?", storyID, userId)
_, err := db.Conn.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)
} else {
_, err := db.Conn.Exec("INSERT INTO like (id,user_id,created) VALUES (?,?,?)", storyID, userId, time.Now())
_, err := db.Conn.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)
@ -40,10 +40,10 @@ func Like(storyID string, userId int64) *e.Error {
return nil
}
func GetLiked(storyID string, userID int64) bool {
func GetLiked(storyID string, userID string) bool {
liked := false
var nid string
err := db.Conn.QueryRow("SELECT id FROM like WHERE id=? and user_id=?", storyID, userID).Scan(&nid)
err := db.Conn.QueryRow("SELECT story_id FROM likes WHERE story_id=? and user_id=?", storyID, userID).Scan(&nid)
if err != nil && err != sql.ErrNoRows {
logger.Warn("query story like error", "error", err)
return false

@ -70,7 +70,7 @@ func SubmitPost(c *gin.Context) (map[string]string, *e.Error) {
setSlug(user.ID, post)
if post.ID == "" {
post.ID = utils.GenStoryID(models.StoryPost)
post.ID = utils.GenID(models.IDTypePost)
//create
_, err := db.Conn.Exec("INSERT INTO posts (id,creator,slug, title, md, url, cover, brief,status, created, updated) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
post.ID, user.ID, post.Slug, post.Title, md, post.URL, post.Cover, post.Brief, models.StatusPublished, now, now)
@ -148,7 +148,7 @@ func GetPost(id string, slug string) (*models.Post, *e.Error) {
err = ar.Creator.Query()
// get tags
t := make([]int64, 0)
t := make([]string, 0)
rows, err := db.Conn.Query("SELECT tag_id FROM tag_post WHERE post_id=?", ar.ID)
if err != nil && err != sql.ErrNoRows {
return nil, e.New(http.StatusInternalServerError, e.Internal)
@ -156,7 +156,7 @@ func GetPost(id string, slug string) (*models.Post, *e.Error) {
ar.RawTags = make([]*models.Tag, 0)
for rows.Next() {
var tag int64
var tag string
err = rows.Scan(&tag)
t = append(t, tag)
@ -177,15 +177,15 @@ func GetPost(id string, slug string) (*models.Post, *e.Error) {
return ar, nil
}
func GetPostCreator(id string) (int64, *e.Error) {
var uid int64
func GetPostCreator(id string) (string, *e.Error) {
var uid string
err := db.Conn.QueryRow("SELECT creator FROM posts WHERE id=?", id).Scan(&uid)
if err != nil {
if err == sql.ErrNoRows {
return 0, e.New(http.StatusNotFound, e.NotFound)
return "", e.New(http.StatusNotFound, e.NotFound)
}
logger.Warn("get post creator error", "error", err)
return 0, e.New(http.StatusInternalServerError, e.Internal)
return "", e.New(http.StatusInternalServerError, e.Internal)
}
return uid, nil
@ -210,7 +210,7 @@ func postExist(id string) bool {
// 1. 长度不能超过127
// 2. 每次title更新都要重新生成slug
// 3. 单个用户下的slug不能重复如果已经存在需要加上-1这种字符
func setSlug(creator int64, post *models.Post) error {
func setSlug(creator string, post *models.Post) error {
slug := utils.Slugify(post.Title)
if len(slug) > 100 {
slug = slug[:100]

@ -27,7 +27,7 @@ func HomePosts(user *models.User, filter string) (models.Posts, *e.Error) {
return posts, nil
}
func UserPosts(user *models.User, uid int64) (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)
if err != nil && err != sql.ErrNoRows {
logger.Warn("get user posts error", "error", err)

@ -9,9 +9,9 @@ var logger = log.RootLogger.New("logger", "story")
func Exist(id string) bool {
switch id[:1] {
case models.StoryPost:
case models.IDTypePost:
return postExist(id)
case models.StoryComment:
case models.IDTypeComment:
return commentExist(id)
default:
return false
@ -20,9 +20,9 @@ func Exist(id string) bool {
func getStorySqlTable(id string) string {
switch id[:1] {
case models.StoryPost:
case models.IDTypePost:
return "posts"
case models.StoryComment:
case models.IDTypeComment:
return "comments"
default:
return "unknown"

@ -42,10 +42,11 @@ func SubmitTag(tag *models.Tag) *e.Error {
md := utils.Compress(tag.Md)
if tag.ID == 0 {
if tag.ID == "" {
tag.ID = utils.GenID(models.IDTypeTag)
//create
_, err := db.Conn.Exec("INSERT INTO tags (creator,name, title, md, icon, cover, created, updated) VALUES(?,?,?,?,?,?,?,?)",
tag.Creator, tag.Name, tag.Title, md, tag.Icon, tag.Cover, now, now)
_, err := db.Conn.Exec("INSERT INTO tags (id,creator,name, title, md, icon, cover, created, updated) VALUES(?,?,?,?,?,?,?,?,?)",
tag.ID, tag.Creator, tag.Name, tag.Title, md, tag.Icon, tag.Cover, now, now)
if err != nil {
if e.IsErrUniqueConstraint(err) {
return e.New(http.StatusConflict, "同样的Tag name已存在")
@ -111,7 +112,7 @@ func DeleteTag(id int64) *e.Error {
return nil
}
func GetTag(id int64, name string) (*models.Tag, *e.Error) {
func GetTag(id string, name string) (*models.Tag, *e.Error) {
tag := &models.Tag{}
var rawmd []byte
err := db.Conn.QueryRow("SELECT id,creator,title,name,icon,cover,created,updated,md from tags where id=? or name=?", id, name).Scan(

@ -24,7 +24,7 @@ type Session struct {
func Login(c *gin.Context) {
user := &models.User{}
err := user.Query(0, config.Data.User.SuperAdminUsername, "")
err := user.Query("", config.Data.User.SuperAdminUsername, "")
if err != nil {
if err == sql.ErrNoRows {
c.String(http.StatusNotFound, "")
@ -132,7 +132,7 @@ func GetSession(c *gin.Context) *Session {
}
func loadSession(sid string) *Session {
var userid int64
var userid string
q := `SELECT user_id FROM sessions WHERE sid=?`
err := db.Conn.QueryRow(q, sid).Scan(&userid)
if err != nil {

@ -32,7 +32,7 @@ func GetUsers(q string) ([]*models.User, *e.Error) {
return users, nil
}
func GetUserDetail(id int64, username string) (*models.User, *e.Error) {
func GetUserDetail(id string, username string) (*models.User, *e.Error) {
user := &models.User{}
err := user.Query(id, username, "")
if err != nil {
@ -54,14 +54,14 @@ func GetUserDetail(id int64, username string) (*models.User, *e.Error) {
}
// get user skills
user.Skills = make([]int64, 0)
user.Skills = make([]string, 0)
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 int64
var skill string
rows.Scan(&skill)
user.Skills = append(user.Skills, skill)

@ -5,7 +5,7 @@ import "time"
type Comment struct {
ID string `json:"id"`
TargetID string `json:"targetID"` // 被评论的文章、书籍等ID
CreatorID int64 `json:"creatorID"`
CreatorID string `json:"creatorID"`
Creator *UserSimple `json:"creator"`
Md string `json:"md"`
Likes int `json:"likes"`

@ -0,0 +1,8 @@
package models
const (
IDTypePost = "1"
IDTypeComment = "2"
IDTypeUser = "3"
IDTypeTag = "4"
)

@ -11,14 +11,14 @@ const (
type Post struct {
ID string `json:"id"`
Creator *UserSimple `json:"creator"`
CreatorID int64 `json:"creatorId"`
CreatorID string `json:"creatorId"`
Title string `json:"title"`
Slug string `json:"slug"`
Md string `json:"md"`
URL string `json:"url"`
Cover string `json:"cover"`
Brief string `json:"brief"`
Tags []int64 `json:"tags"`
Tags []string `json:"tags"`
RawTags []*Tag `json:"rawTags"`
Likes int `json:"likes"`
Liked bool `json:"liked"`

@ -1,6 +0,0 @@
package models
const (
StoryPost = "1"
StoryComment = "2"
)

@ -3,8 +3,8 @@ package models
import "time"
type Tag struct {
ID int64 `json:"id"`
Creator int64 `json:"creator,omitempty"`
ID string `json:"id"`
Creator string `json:"creator,omitempty"`
Title string `json:"title"`
Name string `json:"name,omitempty"`
Md string `json:"md,omitempty"`

@ -7,7 +7,7 @@ import (
)
type User struct {
ID int64 `json:"id"`
ID string `json:"id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
@ -20,7 +20,7 @@ type User struct {
AvailFor string `json:"availFor"`
About string `json:"about"`
RawSkills []*Tag `json:"rawSkills"`
Skills []int64 `json:"skills"`
Skills []string `json:"skills"`
Website string `json:"website"`
Twitter string `json:"twitter"`
@ -34,7 +34,7 @@ type User struct {
Created time.Time `json:"created"`
}
func (user *User) Query(id int64, username string, email string) error {
func (user *User) Query(id string, username string, email string) error {
err := db.Conn.QueryRow(`SELECT id,username,role,nickname,email,avatar,last_seen_at,created FROM user WHERE id=? or username=? or email=?`,
id, username, email).Scan(&user.ID, &user.Username, &user.Role, &user.Nickname, &user.Email, &user.Avatar, &user.LastSeenAt, &user.Created)
@ -46,7 +46,7 @@ func (user *User) Query(id int64, username string, email string) error {
}
type UserSimple struct {
ID int64 `json:"id"`
ID string `json:"id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`

@ -2,7 +2,7 @@ package utils
import "github.com/lithammer/shortuuid/v3"
func GenStoryID(storyType string) string {
func GenID(idType string) string {
u := shortuuid.New()
return storyType + u
return idType + u
}

@ -36,7 +36,7 @@ export const CommentCard = (props: Props) => {
}
const deleteComment = async id => {
await requestApi.delete(`/comment/${id}`)
await requestApi.delete(`/story/comment/${id}`)
onChange()
}

@ -37,7 +37,7 @@ export const Reply = (props: Props) => {
}
const deleteReply = async id => {
await requestApi.delete(`/comment/${id}`)
await requestApi.delete(`/story/comment/${id}`)
onChange()
}

@ -42,7 +42,7 @@ export function MarkdownEditor(props: Props) {
useEffect(() => {
if (at !== '') {
requestApi.get(`/users?query=${at.trim()}`).then(res => setAtUsers(res.data))
requestApi.get(`/user/all?query=${at.trim()}`).then(res => setAtUsers(res.data))
}
},[at])

@ -15,7 +15,7 @@ const Bookmark = (props: Props) => {
const [bookmarked,setBookmarked] = useState(props.bookmarked)
const bookmark = async () => {
await requestApi.post(`/bookmark/${storyID}`)
await requestApi.post(`/story/bookmark/${storyID}`)
setBookmarked(!bookmarked)
}

@ -6,6 +6,7 @@ import Link from "next/link"
import UnicornLike from "./like"
import { FaHeart, FaRegBookmark, FaRegComment, FaRegHeart } from "react-icons/fa"
import SvgButton from "components/svg-button"
import Bookmark from "./bookmark"
interface Props {
post: Post
@ -40,7 +41,7 @@ export const SimplePostCard = (props: Props) => {
<SvgButton icon="bookmark" height="1rem" onClick={null} style={{marginLeft: '4px'}}/>
<Box style={{marginLeft: '4px'}}><Bookmark storyID={post.id} bookmarked={post.bookmarked} height=".95rem"/></Box>
</HStack>
</VStack>
)

@ -18,7 +18,7 @@ export const Tags = (props: Props) => {
const [tags, setTags]: [Tag[], any] = useState([])
useEffect(() => {
requestApi.get('/tags').then(res => {
requestApi.get('/tag/all').then(res => {
setOptions(res.data)
const t = []
props.tags?.forEach(id => {
@ -60,7 +60,7 @@ export const Tags = (props: Props) => {
{tags.length > 0 && <Box mt={props.size === 'lg' ? 4 : 2}>
{
tags.map(tag =>
<ChakraTag key={tag.id} mr="2" colorScheme="teal" variant="solid" px="2" py={props.size === 'lg' ? 2 : 1}>
<ChakraTag key={tag.id} mr="2" colorScheme="cyan" variant="solid" px="2" py={props.size === 'lg' ? 2 : 1}>
<TagLabel>{tag.title}</TagLabel>
<TagCloseButton onClick={_ => removeTag(tag)} />
</ChakraTag>)

@ -11,7 +11,7 @@ function useSession(): Session{
if (sess) {
setSession(sess)
// 页面重新进入时,跟服务器端进行信息同步
requestApi.get(`/session`).then(res => {
requestApi.get(`/user/session`).then(res => {
setSession(res.data)
})
}

@ -3,7 +3,7 @@ import { requestApi } from "./axios/request"
import events from "./events"
export const logout = async () => {
await requestApi.post("/logout")
await requestApi.post("/user/logout")
removeToken()
events.emit('set-session', null)
}

@ -44,6 +44,7 @@ const customTheme = extendTheme({
},
body: {
background: mode("white","gray.800" )(props),
minHeight: '100vh',
color: mode("gray.700", "whiteAlpha.900")(props),
".deleted": {
color: "#ff8383 !important",

Loading…
Cancel
Save