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 && }
{user && }
-
+
+
+ {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 && }
{user && }
-
+
+
+ {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
+},
]