212 lines
6.7 KiB
Go
212 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type nodeBlockingRequest struct {
|
|
NodeID string `json:"node_id"`
|
|
NodeNum *int64 `json:"node_num"`
|
|
Reason string `json:"reason"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
type ipBlockingRequest struct {
|
|
IPValue string `json:"ip_value"`
|
|
Reason string `json:"reason"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
type forbiddenWordBlockingRequest struct {
|
|
Word string `json:"word"`
|
|
MatchType string `json:"match_type"`
|
|
CaseSensitive bool `json:"case_sensitive"`
|
|
Reason string `json:"reason"`
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
func registerAdminBlockingRoutes(r gin.IRouter, store *store) {
|
|
r.GET("/blocking/nodes", func(c *gin.Context) {
|
|
opts, ok := parseListOptions(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
rows, err := store.ListNodeBlocking(opts)
|
|
if err != nil {
|
|
writeListResponse(c, rows, opts, err, nodeBlockingDTO)
|
|
return
|
|
}
|
|
total, err := store.CountNodeBlocking(opts)
|
|
writeListResponseWithTotal(c, rows, opts, total, err, nodeBlockingDTO)
|
|
})
|
|
r.POST("/blocking/nodes", func(c *gin.Context) {
|
|
var req nodeBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid node blocking request"})
|
|
return
|
|
}
|
|
row, err := store.CreateNodeBlocking(req.NodeID, req.NodeNum, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusCreated, row, err, nodeBlockingDTO)
|
|
})
|
|
r.PUT("/blocking/nodes/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req nodeBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid node blocking request"})
|
|
return
|
|
}
|
|
row, err := store.UpdateNodeBlocking(id, req.NodeID, req.NodeNum, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusOK, row, err, nodeBlockingDTO)
|
|
})
|
|
r.DELETE("/blocking/nodes/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
writeBlockingDeleteResponse(c, store.DeleteNodeBlocking(id))
|
|
})
|
|
|
|
r.GET("/blocking/ips", func(c *gin.Context) {
|
|
opts, ok := parseListOptions(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
rows, err := store.ListIPBlocking(opts)
|
|
if err != nil {
|
|
writeListResponse(c, rows, opts, err, ipBlockingDTO)
|
|
return
|
|
}
|
|
total, err := store.CountIPBlocking(opts)
|
|
writeListResponseWithTotal(c, rows, opts, total, err, ipBlockingDTO)
|
|
})
|
|
r.POST("/blocking/ips", func(c *gin.Context) {
|
|
var req ipBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ip blocking request"})
|
|
return
|
|
}
|
|
row, err := store.CreateIPBlocking(req.IPValue, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusCreated, row, err, ipBlockingDTO)
|
|
})
|
|
r.PUT("/blocking/ips/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req ipBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ip blocking request"})
|
|
return
|
|
}
|
|
row, err := store.UpdateIPBlocking(id, req.IPValue, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusOK, row, err, ipBlockingDTO)
|
|
})
|
|
r.DELETE("/blocking/ips/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
writeBlockingDeleteResponse(c, store.DeleteIPBlocking(id))
|
|
})
|
|
|
|
r.GET("/blocking/words", func(c *gin.Context) {
|
|
opts, ok := parseListOptions(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
rows, err := store.ListForbiddenWordBlocking(opts)
|
|
if err != nil {
|
|
writeListResponse(c, rows, opts, err, forbiddenWordBlockingDTO)
|
|
return
|
|
}
|
|
total, err := store.CountForbiddenWordBlocking(opts)
|
|
writeListResponseWithTotal(c, rows, opts, total, err, forbiddenWordBlockingDTO)
|
|
})
|
|
r.POST("/blocking/words", func(c *gin.Context) {
|
|
var req forbiddenWordBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid forbidden word blocking request"})
|
|
return
|
|
}
|
|
row, err := store.CreateForbiddenWordBlocking(req.Word, req.MatchType, req.CaseSensitive, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusCreated, row, err, forbiddenWordBlockingDTO)
|
|
})
|
|
r.PUT("/blocking/words/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req forbiddenWordBlockingRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid forbidden word blocking request"})
|
|
return
|
|
}
|
|
row, err := store.UpdateForbiddenWordBlocking(id, req.Word, req.MatchType, req.CaseSensitive, req.Reason, req.Enabled)
|
|
writeBlockingMutationResponse(c, http.StatusOK, row, err, forbiddenWordBlockingDTO)
|
|
})
|
|
r.DELETE("/blocking/words/:id", func(c *gin.Context) {
|
|
id, ok := parseBlockingID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
writeBlockingDeleteResponse(c, store.DeleteForbiddenWordBlocking(id))
|
|
})
|
|
}
|
|
|
|
func parseBlockingID(c *gin.Context) (uint64, bool) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil || id == 0 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid blocking rule id"})
|
|
return 0, false
|
|
}
|
|
return id, true
|
|
}
|
|
|
|
func writeBlockingMutationResponse[T any](c *gin.Context, status int, row *T, err error, convert func(T) gin.H) {
|
|
if errors.Is(err, errBlockingAlreadyExists) {
|
|
c.JSON(http.StatusConflict, gin.H{"error": "blocking rule already exists"})
|
|
return
|
|
}
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "blocking rule not found"})
|
|
return
|
|
}
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(status, gin.H{"item": convert(*row)})
|
|
}
|
|
|
|
func writeBlockingDeleteResponse(c *gin.Context, err error) {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "blocking rule not found"})
|
|
return
|
|
}
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
|
}
|
|
|
|
func nodeBlockingDTO(row nodeBlockingRecord) gin.H {
|
|
return gin.H{"id": row.ID, "node_id": row.NodeID, "node_num": ptrInt64(row.NodeNum), "reason": row.Reason, "enabled": row.Enabled, "created_at": row.CreatedAt, "updated_at": row.UpdatedAt}
|
|
}
|
|
|
|
func ipBlockingDTO(row ipBlockingRecord) gin.H {
|
|
return gin.H{"id": row.ID, "ip_value": row.IPValue, "reason": row.Reason, "enabled": row.Enabled, "created_at": row.CreatedAt, "updated_at": row.UpdatedAt}
|
|
}
|
|
|
|
func forbiddenWordBlockingDTO(row forbiddenWordBlockingRecord) gin.H {
|
|
return gin.H{"id": row.ID, "word": row.Word, "match_type": row.MatchType, "case_sensitive": row.CaseSensitive, "reason": row.Reason, "enabled": row.Enabled, "created_at": row.CreatedAt, "updated_at": row.UpdatedAt}
|
|
}
|