diff --git a/pages/admin/report.tsx b/pages/admin/report.tsx new file mode 100644 index 00000000..f04f5395 --- /dev/null +++ b/pages/admin/report.tsx @@ -0,0 +1,38 @@ +import { Box, useToast } from "@chakra-ui/react" +import Card from "components/card" + +import Sidebar from "layouts/sidebar/sidebar" +import React, { useEffect, useState } from "react" +import { adminLinks } from "src/data/links" +import { requestApi } from "utils/axios/request" +import PageContainer1 from "layouts/page-container1" + +const PostsPage = () => { + const [reports, setReports]= useState([]) + const toast = useToast() + const getConfig = async () => { + const res = await requestApi.get(`/admin/reports`) + console.log(res.data) + setReports(res.data) + } + + useEffect(() => { + getConfig() + }, []) + + return ( + <> + + + + + + + + + + + ) +} +export default PostsPage + diff --git a/server/internal/admin/report.go b/server/internal/admin/report.go index e1a50948..b57d89ae 100644 --- a/server/internal/admin/report.go +++ b/server/internal/admin/report.go @@ -1,7 +1,9 @@ package admin import ( + "database/sql" "net/http" + "sort" "time" "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" @@ -20,9 +22,45 @@ func AddReport(targetID string, content string, reporter string) *e.Error { targetID, models.GetIDType(targetID), reporter, StatusUndealed, time.Now()) if err != nil { + if e.IsErrUniqueConstraint(err) { + return e.New(http.StatusConflict, "已提交过report,请勿重复提交") + } logger.Warn("add report error", "error", err) return e.New(http.StatusInternalServerError, e.Internal) } return nil } + +func GetReports(page int) ([]*models.Report, *e.Error) { + reports := make(models.Reports, 0) + rows, err := db.Conn.Query("SELECT id,target_id,reporter,status,created FROM report") + if err != nil && err != sql.ErrNoRows { + logger.Warn("get reports error", "error", err) + return nil, e.New(http.StatusInternalServerError, e.Internal) + } + + if err == sql.ErrNoRows { + return reports, nil + } + + for rows.Next() { + r := &models.Report{ + Reporter: &models.UserSimple{}, + } + var uid string + err := rows.Scan(&r.ID, &r.TargetID, &uid, &r.Status, &r.Created) + if err != nil { + logger.Warn("scan report error", "error", err) + continue + } + + r.Reporter.ID = uid + r.Reporter.Query() + reports = append(reports, r) + } + + sort.Sort(reports) + + return reports, nil +} diff --git a/server/internal/api/admin.go b/server/internal/api/admin.go index 54cca579..0bfa4ac2 100644 --- a/server/internal/api/admin.go +++ b/server/internal/api/admin.go @@ -2,7 +2,6 @@ package api import ( "encoding/json" - "fmt" "net/http" "github.com/asaskevich/govalidator" @@ -77,7 +76,6 @@ type ReportReq struct { func SubmitReport(c *gin.Context) { req := &ReportReq{} c.Bind(&req) - fmt.Println(*req) u := user.CurrentUser(c) err := admin.AddReport(req.TargetID, req.Content, u.ID) @@ -88,3 +86,19 @@ func SubmitReport(c *gin.Context) { c.JSON(http.StatusOK, common.RespSuccess(nil)) } + +func GetReports(c *gin.Context) { + currentUser := user.CurrentUser(c) + if !currentUser.Role.IsAdmin() { + c.JSON(http.StatusForbidden, common.RespError(e.NoPermission)) + return + } + + res, err := admin.GetReports(1) + if err != nil { + c.JSON(err.Status, common.RespError(err.Message)) + return + } + + c.JSON(http.StatusOK, common.RespSuccess(res)) +} diff --git a/server/internal/server.go b/server/internal/server.go index d9b8a09d..9b743054 100644 --- a/server/internal/server.go +++ b/server/internal/server.go @@ -151,6 +151,7 @@ func (s *Server) Start() error { r.POST("/admin/user", IsLogin(), api.AdminSubmitUser) r.GET("/admin/user/all", IsLogin(), api.AdminGetUsers) r.GET("/admin/config", IsLogin(), api.AdminConfig) + r.GET("/admin/reports", IsLogin(), api.GetReports) // notification apis r.GET("/notifications/list/:type", IsLogin(), api.GetNotifications) r.GET("/notifications/unread", IsLogin(), api.GetUnread) @@ -166,6 +167,7 @@ func (s *Server) Start() error { r.POST("/sidebar", IsLogin(), SubmitSidebar) r.POST("/report", IsLogin(), api.SubmitReport) + err := router.Run(config.Data.Server.Addr) if err != nil { logger.Crit("start backend server error", "error", err) diff --git a/server/internal/storage/sql_tables.go b/server/internal/storage/sql_tables.go index dcd23cd1..ff17c3ab 100644 --- a/server/internal/storage/sql_tables.go +++ b/server/internal/storage/sql_tables.go @@ -287,6 +287,7 @@ var sqlTables = map[string]string{ created DATETIME );`, "report": `CREATE TABLE IF NOT EXISTS report ( + id INTEGER PRIMARY KEY AUTOINCREMENT, target_id VARCHAR(255), type VARCHAR(1) NOT NULL, reporter VARCHAR(255) NOT NULL, diff --git a/server/pkg/models/report.go b/server/pkg/models/report.go new file mode 100644 index 00000000..471c22e4 --- /dev/null +++ b/server/pkg/models/report.go @@ -0,0 +1,19 @@ +package models + +import "time" + +type Report struct { + ID int `json:"id"` + TargetID string `json:"target_id"` + Reporter *UserSimple + Status int `json:"status"` + Created time.Time `json:"created"` +} + +type Reports []*Report + +func (t Reports) Len() int { return len(t) } +func (t Reports) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t Reports) Less(i, j int) bool { + return t[i].Created.Unix() > t[j].Created.Unix() +} diff --git a/src/components/comments/comment.tsx b/src/components/comments/comment.tsx index 3e976630..a8136bcf 100644 --- a/src/components/comments/comment.tsx +++ b/src/components/comments/comment.tsx @@ -12,6 +12,7 @@ import CommentEditor from "./editor" import { requestApi } from "utils/axios/request" import Reply from "./reply" import Link from "next/link" +import Report from "components/report" interface Props { user: User @@ -21,6 +22,7 @@ interface Props { export const CommentCard = (props: Props) => { const { comment, user, onChange} = props const [editorVisible, setEditorVisible] = useState(false) + const [report,setReport] = useState(false) const [replyVisible,setReplyVisible] = useState(false) const [reply,setReply] = useState('') @@ -87,11 +89,13 @@ export const CommentCard = (props: Props) => { {user && setEditorVisible(true)}>Edit} {user && deleteComment(comment.id)}>Delete} - Report + setReport(true)}>Report + + {report && setReport(false)}/>} {replyVisible && {submitReply(md)}} onCancel={() => setReplyVisible(false)} />} diff --git a/src/components/comments/reply.tsx b/src/components/comments/reply.tsx index 90d67b13..653f0da6 100644 --- a/src/components/comments/reply.tsx +++ b/src/components/comments/reply.tsx @@ -11,6 +11,7 @@ import { User } from "src/types/user" import CommentEditor from "./editor" import { requestApi } from "utils/axios/request" import Link from "next/link" +import Report from "components/report" interface Props { user: User @@ -21,7 +22,8 @@ interface Props { export const Reply = (props: Props) => { const { comment, user,onChange,parent} = props const [editorVisible, setEditorVisible] = useState(false) - + const [report,setReport] = useState(false) + const [replyVisible,setReplyVisible] = useState(false) const [reply,setReply] = useState('') const submitReply = async (md) => { @@ -102,11 +104,13 @@ export const Reply = (props: Props) => { {user && setEditorVisible(true)}>Edit} {user && deleteReply(comment.id)}>Delete} - Report + setReport(true)}>Report + + {report && setReport(false)}/>} {replyVisible && diff --git a/src/data/links.tsx b/src/data/links.tsx index 2611b084..760f7659 100644 --- a/src/data/links.tsx +++ b/src/data/links.tsx @@ -1,6 +1,6 @@ import { getSvgIcon } from 'components/svg-icon' import React from 'react' -import { FaFileAlt, FaScroll, FaBookOpen, FaTags, FaUserCircle, FaRegFile, FaUser, FaRegUser, FaUserFriends, FaElementor } from 'react-icons/fa' +import { FaFileAlt, FaScroll, FaBookOpen, FaTags, FaUserCircle, FaRegFile, FaUser, FaRegUser, FaUserFriends, FaElementor, FaBug } from 'react-icons/fa' import { Route } from 'src/types/route' import { SearchFilter } from 'src/types/search' import { ReserveUrls } from './reserve-urls' @@ -93,6 +93,12 @@ export const adminLinks: Route[] = [{ icon: , disabled: false }, +{ + title: 'Report处理', + path: `${ReserveUrls.Admin}/report`, + icon: , + disabled: false +}, ]