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,21 +82,21 @@ 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,
title VARCHAR(255) 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),
cover 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,20 +7,20 @@ import (
)
type User struct {
ID int64 `json:"id"`
ID string `json:"id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Email string `json:"email"`
Role RoleType `json:"role"`
Tagline string `json:"tagline"`
Cover string `json:"cover"`
Location string `json:"location"`
AvailFor string `json:"availFor"`
About string `json:"about"`
RawSkills []*Tag `json:"rawSkills"`
Skills []int64 `json:"skills"`
Tagline string `json:"tagline"`
Cover string `json:"cover"`
Location string `json:"location"`
AvailFor string `json:"availFor"`
About string `json:"about"`
RawSkills []*Tag `json:"rawSkills"`
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