167 lines
3.6 KiB
Go
167 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/caarlos0/env/v11"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func ping(c *gin.Context) {
|
|
c.String(http.StatusOK, "Pong!")
|
|
}
|
|
|
|
func authMiddleware(appConfig *AppConfig) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
if appConfig.Secret != "" {
|
|
if ctx.Request.Header.Get("PQM_AUTH") != appConfig.Secret {
|
|
ctx.Abort()
|
|
ctx.String(http.StatusForbidden, "拜拜")
|
|
return
|
|
}
|
|
}
|
|
ctx.Next()
|
|
}
|
|
}
|
|
|
|
type AppConfig struct {
|
|
Secret string `env:"PQM_SECRET"`
|
|
DataPath string `env:"PQM_DATA_PATH" envDefault:"data.json"`
|
|
}
|
|
|
|
type PMemo struct {
|
|
Content string `json:"content"`
|
|
CreatedDate time.Time `json:"created_date"`
|
|
}
|
|
|
|
type PMemoFilter struct {
|
|
Till time.Time `json:"till"`
|
|
}
|
|
|
|
type AppData struct {
|
|
Memos []PMemo `json:"memos"`
|
|
}
|
|
|
|
func SaveData(appConfig *AppConfig, data *AppData) error {
|
|
dat, err := json.Marshal(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = os.WriteFile(appConfig.DataPath, dat, os.FileMode(0o666))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func LoadData(appConfig *AppConfig) AppData {
|
|
var appData AppData
|
|
|
|
dat, err := os.ReadFile(appConfig.DataPath)
|
|
if err != nil {
|
|
appData = AppData{Memos: []PMemo{}}
|
|
SaveData(appConfig, &appData)
|
|
return appData
|
|
}
|
|
|
|
err = json.Unmarshal(dat, &appData)
|
|
if err != nil {
|
|
appData = AppData{Memos: []PMemo{}}
|
|
}
|
|
|
|
return appData
|
|
}
|
|
|
|
func main() {
|
|
var config AppConfig
|
|
err := env.Parse(&config)
|
|
if err != nil {
|
|
fmt.Println("读取环境变量出错啦!")
|
|
panic(err)
|
|
}
|
|
|
|
appData := LoadData(&config)
|
|
|
|
r := gin.Default()
|
|
r.Use(authMiddleware(&config))
|
|
r.GET("/", func(ctx *gin.Context) {
|
|
ping(ctx)
|
|
})
|
|
r.GET("/all", func(ctx *gin.Context) {
|
|
ctx.AsciiJSON(http.StatusOK, appData)
|
|
})
|
|
r.PUT("/create", func(ctx *gin.Context) {
|
|
var content string
|
|
if err := ctx.BindPlain(&content); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
memo := PMemo{
|
|
Content: content,
|
|
CreatedDate: time.Now(),
|
|
}
|
|
appData.Memos = append(appData.Memos, memo)
|
|
if err := SaveData(&config, &appData); err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": memo})
|
|
})
|
|
r.DELETE("/all", func(ctx *gin.Context) {
|
|
appData.Memos = []PMemo{}
|
|
if err := SaveData(&config, &appData); err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, gin.H{"error": "ok"})
|
|
})
|
|
r.POST("/filtered", func(ctx *gin.Context) {
|
|
var filter PMemoFilter
|
|
if err := ctx.BindJSON(&filter); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
memos := slices.Collect(func(yield func(PMemo) bool) {
|
|
for _, memo := range appData.Memos {
|
|
if filter.Till.After(memo.CreatedDate) {
|
|
if !yield(memo) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
})
|
|
ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": gin.H{"memos": memos}})
|
|
})
|
|
r.DELETE("/filtered", func(ctx *gin.Context) {
|
|
var filter PMemoFilter
|
|
if err := ctx.BindJSON(&filter); err != nil {
|
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
appData.Memos = slices.Collect(func(yield func(PMemo) bool) {
|
|
for _, memo := range appData.Memos {
|
|
if !filter.Till.After(memo.CreatedDate) {
|
|
if !yield(memo) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
})
|
|
if err := SaveData(&config, &appData); err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": appData})
|
|
})
|
|
|
|
r.Run()
|
|
}
|