add new ledger api

This commit is contained in:
leo 2021-11-18 16:27:28 +08:00
parent 529f60e549
commit 4de286d8f7
9 changed files with 311 additions and 50 deletions

View File

@ -1,22 +0,0 @@
package main
import (
"encoding/json"
"github.com/beancount-gs/script"
)
type Config struct {
Title string `json:"title"`
DataPath string `json:"dataPath"`
OperatingCurrency string `json:"operatingCurrency"`
StartDate string `json:"startDate"`
IsBak bool `json:"isBak"`
}
func LoadConfig(globalConfig Config) Config {
err := json.Unmarshal(script.ReadFile("./config/config.json"), &globalConfig)
if err != nil {
script.LogError("config file (/config/config.json) unmarshall failed")
}
return globalConfig
}

View File

@ -1,6 +1,6 @@
{
"title": "我的账本",
"dataPath": "/beancount",
"dataPath": "D:\\beancount",
"operatingCurrency": "CNY",
"startDate": "1970-01-01",
"isBak": true

108
script/config.go Normal file
View File

@ -0,0 +1,108 @@
package script
import (
"encoding/json"
)
var serverConfig Config
var ledgerConfigMap ConfigMap
var whiteList []string
type Config struct {
Id string `json:"id"`
Mail string `json:"mail"`
Title string `json:"title"`
DataPath string `json:"dataPath"`
OperatingCurrency string `json:"operatingCurrency"`
StartDate string `json:"startDate"`
IsBak bool `json:"isBak"`
}
type ConfigMap map[string]Config
func GetServerConfig() Config {
return serverConfig
}
func GetLedgerConfigMap() map[string]Config {
return ledgerConfigMap
}
func GetLedgerConfig(ledgerId string) Config {
return ledgerConfigMap[ledgerId]
}
func GetLedgerConfigByMail(mail string) *Config {
for _, v := range ledgerConfigMap {
if v.Mail == mail {
return &v
}
}
return nil
}
func IsInWhiteList(ledgerId string) bool {
// ledger white list is empty, return true
if whiteList == nil || len(whiteList) == 0 {
return true
}
for i := range whiteList {
if whiteList[i] == ledgerId {
return true
}
}
return false
}
func LoadServerConfig() error {
fileContent, err := ReadFile("./config/config.json")
if err != nil {
return err
}
err = json.Unmarshal(fileContent, &serverConfig)
if err != nil {
LogError("Failed unmarshall config file (/config/config.json)")
return err
}
LogInfo("Success load config file (/config/config.json)")
// load white list
fileContent, err = ReadFile("./config/white_list.json")
if err != nil {
return err
}
err = json.Unmarshal(fileContent, &whiteList)
if err != nil {
LogError("Failed unmarshal whitelist file (/config/white_list.json)")
return err
}
LogInfo("Success load whitelist file (/config/white_list.json)")
return nil
}
func LoadLedgerConfigMap() error {
path := GetServerLedgerConfigFilePath()
fileContent, err := ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(fileContent, &ledgerConfigMap)
if err != nil {
LogError("Failed unmarshal config file (" + path + ")")
return err
}
LogInfo("Success load ledger_config file (" + path + ")")
return nil
}
func WriteLedgerConfigMap(newLedgerConfigMap ConfigMap) error {
path := GetServerLedgerConfigFilePath()
mapBytes, err := json.Marshal(ledgerConfigMap)
if err != nil {
LogError("Failed marshal ConfigMap")
return err
}
err = WriteFile(path, string(mapBytes))
ledgerConfigMap = newLedgerConfigMap
LogInfo("Success write ledger_config file (" + path + ")")
return err
}

View File

@ -16,26 +16,43 @@ func FileIfExist(filePath string) bool {
return true
}
func ReadFile(filePath string) []byte {
func ReadFile(filePath string) ([]byte, error) {
content, err := ioutil.ReadFile(filePath)
if nil != err {
LogError(filePath + " read failed")
LogError("Failed to read file (" + filePath + ")")
return content, err
}
return content
LogInfo("Success read file (" + filePath + ")")
return content, nil
}
func CreateFile(filePath string) {
func WriteFile(filePath string, content string) error {
err := ioutil.WriteFile(filePath, []byte(content), os.ModePerm)
if err != nil {
LogError("Failed to write file (" + filePath + ")")
return err
}
LogInfo("Success write file (" + filePath + ")")
return nil
}
func CreateFile(filePath string) error {
f, err := os.Create(filePath)
if nil != err {
LogError(filePath + " create failed")
return
return err
}
defer f.Close()
LogInfo("Success create file " + filePath)
return nil
}
func MkDir(dirPath string) {
func MkDir(dirPath string) error {
err := os.MkdirAll(dirPath, os.ModePerm)
if nil != err {
LogError(dirPath + " mkdir failed")
LogError("Failed mkdir " + dirPath)
return err
}
LogInfo("Success mkdir " + dirPath)
return nil
}

View File

@ -6,9 +6,9 @@ import (
)
func LogInfo(message string) {
fmt.Printf("[Info] %s System: %s\n", time.Now().Format("2006-01-02 15:04:05"), message)
fmt.Printf("[Info] [%s] System: %s\n", time.Now().Format("2006-01-02 15:04:05"), message)
}
func LogError(message string) {
fmt.Printf("[Error] %s System: %s\n", time.Now().Format("2006-01-02 15:04:05"), message)
fmt.Printf("[Error] [%s] System: %s\n", time.Now().Format("2006-01-02 15:04:05"), message)
}

15
script/paths.go Normal file
View File

@ -0,0 +1,15 @@
package script
import "os"
func GetServerLedgerConfigFilePath() string {
return GetServerConfig().DataPath + "/ledger_config.json"
}
func GetExampleLedgerConfigDirPath() string {
currentPath, err := os.Getwd()
if err != nil {
return ""
}
return currentPath + "/example"
}

View File

@ -2,40 +2,55 @@ package main
import (
"github.com/beancount-gs/script"
"github.com/beancount-gs/service"
"github.com/gin-gonic/gin"
"net/http"
)
var GlobalConfig Config
func InitLedgerFiles() {
func InitServerFiles() error {
dataPath := script.GetServerConfig().DataPath
// 账本目录不存在,则创建
if !script.FileIfExist(GlobalConfig.DataPath) {
script.MkDir(GlobalConfig.DataPath)
script.LogInfo("Success mkdir " + GlobalConfig.DataPath)
if !script.FileIfExist(dataPath) {
return script.MkDir(dataPath)
}
return nil
}
func LoadLedgerCache() {
func LoadServerCache() error {
return script.LoadLedgerConfigMap()
}
func RegisterRoute(route *gin.Engine) {
route.StaticFS("/", http.Dir("./public"))
func RegisterRouter(router *gin.Engine) {
router.StaticFS("/", http.Dir("./public"))
router.POST("/api/ledger", service.OpenOrCreateLedger)
}
func main() {
// 默认端口号
var port = ":3001"
// 读取配置文件
GlobalConfig = LoadConfig(GlobalConfig)
// 初始化账本文件结构
InitLedgerFiles()
// 加载缓存
LoadLedgerCache()
route := gin.Default()
// 注册路由
RegisterRoute(route)
// 启动服务
_ = http.ListenAndServe(port, nil)
err := script.LoadServerConfig()
if err != nil {
script.LogError("Failed to load server config, " + err.Error())
return
}
// 初始化账本文件结构
err = InitServerFiles()
if err != nil {
script.LogError("Failed to init server files, " + err.Error())
return
}
// 加载缓存
err = LoadServerCache()
if err != nil {
script.LogError("Failed to load server cache, " + err.Error())
return
}
router := gin.Default()
// 注册路由
RegisterRouter(router)
// 启动服务
var port = ":3001"
err = router.Run(port)
if err != nil {
script.LogError("Failed to start server, " + err.Error())
}
}

26
service/error.go Normal file
View File

@ -0,0 +1,26 @@
package service
import (
"github.com/gin-gonic/gin"
"net/http"
)
func OK(c *gin.Context, data string) {
c.JSON(http.StatusOK, gin.H{"code": 200, "message": "ok", "data": data})
}
func BadRequest(c *gin.Context, message string) {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": message})
}
func InternalError(c *gin.Context, message string) {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": message})
}
func LedgerIsNotExist(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 1006, "message": "ledger is not exist"})
}
func LedgerIsNotAllowAccess(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 1006, "message": "ledger is not allow access"})
}

102
service/ledger.go Normal file
View File

@ -0,0 +1,102 @@
package service
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"github.com/beancount-gs/script"
"github.com/gin-gonic/gin"
"io"
"io/ioutil"
"strings"
)
type LoginForm struct {
Mail string `form:"mail" binding:"required"`
Secret string `form:"secret" binding:"required"`
}
func OpenOrCreateLedger(c *gin.Context) {
var loginForm LoginForm
if err := c.ShouldBindJSON(&loginForm); err != nil {
BadRequest(c, err.Error())
return
}
// is mail exist white list
if !script.IsInWhiteList(loginForm.Mail) {
LedgerIsNotExist(c)
return
}
t := sha1.New()
_, err := io.WriteString(t, loginForm.Mail+loginForm.Secret)
if err != nil {
LedgerIsNotAllowAccess(c)
return
}
ledgerId := hex.EncodeToString(t.Sum(nil))
fmt.Println(ledgerId)
userLedger := script.GetLedgerConfigByMail(loginForm.Mail)
if userLedger != nil {
if ledgerId != userLedger.Id {
LedgerIsNotAllowAccess(c)
return
}
}
// create new ledger
serverConfig := script.GetServerConfig()
ledgerConfigMap := script.GetLedgerConfigMap()
ledgerConfig := script.Config{
Id: ledgerId,
Mail: loginForm.Mail,
Title: serverConfig.Title,
DataPath: serverConfig.DataPath + "/" + ledgerId,
OperatingCurrency: serverConfig.OperatingCurrency,
StartDate: serverConfig.StartDate,
IsBak: serverConfig.IsBak,
}
// init ledger files
err = initLedgerFiles(script.GetExampleLedgerConfigDirPath(), ledgerConfig.DataPath, ledgerConfig.StartDate)
if err != nil {
InternalError(c, err.Error())
return
}
// add ledger config to ledger_config.json
ledgerConfigMap[ledgerId] = ledgerConfig
err = script.WriteLedgerConfigMap(ledgerConfigMap)
if err != nil {
InternalError(c, err.Error())
return
}
OK(c, ledgerId)
}
func initLedgerFiles(sourceFilePath string, targetFilePath string, startDate string) error {
return copyFile(sourceFilePath, targetFilePath, startDate)
}
func copyFile(sourceFilePath string, targetFilePath string, startDate string) error {
rd, err := ioutil.ReadDir(sourceFilePath)
if err != nil {
return err
}
for _, fi := range rd {
newSourceFilePath := sourceFilePath + "/" + fi.Name()
newTargetFilePath := targetFilePath + "/" + fi.Name()
if fi.IsDir() {
err = script.MkDir(newTargetFilePath)
err = copyFile(newSourceFilePath, newTargetFilePath, startDate)
} else {
fileContent, err := script.ReadFile(newSourceFilePath)
if err != nil {
return err
}
err = script.WriteFile(newTargetFilePath, strings.Replace(string(fileContent), "%startDate%", startDate, -1))
}
if err != nil {
return err
}
}
return nil
}