mirror of https://github.com/sunface/rust-course
parent
00d9d1e56e
commit
e0c35fae98
@ -0,0 +1,61 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/imdotdev/im.dev/server/internal/interaction"
|
||||
"github.com/imdotdev/im.dev/server/internal/user"
|
||||
"github.com/imdotdev/im.dev/server/pkg/common"
|
||||
"github.com/imdotdev/im.dev/server/pkg/e"
|
||||
)
|
||||
|
||||
func Follow(c *gin.Context) {
|
||||
user := user.CurrentUser(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
|
||||
return
|
||||
}
|
||||
|
||||
err := interaction.Follow(id, user.ID)
|
||||
if err != nil {
|
||||
c.JSON(err.Status, common.RespError(err.Message))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.RespSuccess(nil))
|
||||
}
|
||||
|
||||
func Followed(c *gin.Context) {
|
||||
user := user.CurrentUser(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
|
||||
return
|
||||
}
|
||||
|
||||
followed := false
|
||||
if user != nil {
|
||||
followed = interaction.GetFollowed(id, user.ID)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.RespSuccess(followed))
|
||||
}
|
||||
|
||||
func Like(c *gin.Context) {
|
||||
user := user.CurrentUser(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(http.StatusBadRequest, common.RespError(e.ParamInvalid))
|
||||
return
|
||||
}
|
||||
|
||||
err := interaction.Like(id, user.ID)
|
||||
if err != nil {
|
||||
c.JSON(err.Status, common.RespError(err.Message))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.RespSuccess(nil))
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package interaction
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/imdotdev/im.dev/server/pkg/db"
|
||||
"github.com/imdotdev/im.dev/server/pkg/e"
|
||||
"github.com/imdotdev/im.dev/server/pkg/models"
|
||||
)
|
||||
|
||||
func Follow(targetID string, userId string) *e.Error {
|
||||
exist := models.IdExist(targetID)
|
||||
if !exist {
|
||||
return e.New(http.StatusNotFound, e.NotFound)
|
||||
}
|
||||
|
||||
followed := GetFollowed(targetID, userId)
|
||||
|
||||
var count int
|
||||
err := db.Conn.QueryRow("SELECT count FROM follows_count WHERE target_id=?", targetID).Scan(&count)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Warn("query follows 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 sql transaction error", "error", err)
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
if followed {
|
||||
// 已经喜欢过该篇文章,更改为不喜欢
|
||||
_, err := tx.Exec("DELETE FROM follows WHERE user_id=? and target_id=?", userId, targetID)
|
||||
if err != nil {
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
count = count - 1
|
||||
} else {
|
||||
_, err := tx.Exec("INSERT INTO follows (user_id,target_id,target_type,created) VALUES (?,?,?,?)", userId, targetID, models.GetIDType(targetID), time.Now())
|
||||
if err != nil {
|
||||
logger.Warn("add follows error", "error", err)
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
count = count + 1
|
||||
}
|
||||
|
||||
var err0 error
|
||||
if !exist {
|
||||
_, err0 = tx.Exec("INSERT INTO follows_count (target_id,count) VALUES (?,?)", targetID, count)
|
||||
} else {
|
||||
_, err0 = tx.Exec("UPDATE follows_count SET count=? WHERE target_id=?", count, targetID)
|
||||
}
|
||||
|
||||
if err0 != nil {
|
||||
logger.Warn("add follows_count error", "error", err0)
|
||||
tx.Rollback()
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetFollowed(targetID string, userID string) bool {
|
||||
followed := false
|
||||
var nid string
|
||||
err := db.Conn.QueryRow("SELECT target_id FROM follows WHERE user_id=? and target_id=?", userID, targetID).Scan(&nid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Warn("query folloed error", "error", err)
|
||||
return false
|
||||
}
|
||||
|
||||
if nid == targetID {
|
||||
followed = true
|
||||
}
|
||||
|
||||
return followed
|
||||
}
|
||||
|
||||
func GetFollows(targetID string) int {
|
||||
var follows int
|
||||
err := db.Conn.QueryRow("SELECT count FROM follows_count WHERE target_id=?", targetID).Scan(&follows)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Warn("get follow count error", "error", err)
|
||||
}
|
||||
|
||||
return follows
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package interaction
|
||||
|
||||
import "github.com/imdotdev/im.dev/server/pkg/log"
|
||||
|
||||
var logger = log.RootLogger.New("logger", "api")
|
||||
@ -0,0 +1,30 @@
|
||||
import { Button } from "@chakra-ui/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FaCheck, FaPlus, FaUserPlus } from "react-icons/fa";
|
||||
import { requestApi } from "utils/axios/request";
|
||||
|
||||
interface Props {
|
||||
targetID: string
|
||||
followed: boolean
|
||||
fontSize?: string
|
||||
}
|
||||
const Follow = (props: Props) => {
|
||||
const [followed, setFollowed] = useState(props.followed)
|
||||
|
||||
const follow = async () => {
|
||||
await requestApi.post(`/interaction/follow/${props.targetID}`)
|
||||
setFollowed(!followed)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{followed ?
|
||||
<Button colorScheme="teal" onClick={follow} _focus={null} leftIcon={<FaCheck />}>Following</Button>
|
||||
:
|
||||
<Button colorScheme="teal" variant="outline" leftIcon={<FaPlus />} onClick={follow} _focus={null}>Follow</Button>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Follow
|
||||
Loading…
Reference in new issue