add new ledger api
This commit is contained in:
parent
529f60e549
commit
4de286d8f7
22
config.go
22
config.go
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"title": "我的账本",
|
"title": "我的账本",
|
||||||
"dataPath": "/beancount",
|
"dataPath": "D:\\beancount",
|
||||||
"operatingCurrency": "CNY",
|
"operatingCurrency": "CNY",
|
||||||
"startDate": "1970-01-01",
|
"startDate": "1970-01-01",
|
||||||
"isBak": true
|
"isBak": true
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -16,26 +16,43 @@ func FileIfExist(filePath string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadFile(filePath string) []byte {
|
func ReadFile(filePath string) ([]byte, error) {
|
||||||
content, err := ioutil.ReadFile(filePath)
|
content, err := ioutil.ReadFile(filePath)
|
||||||
if nil != err {
|
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)
|
f, err := os.Create(filePath)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
LogError(filePath + " create failed")
|
LogError(filePath + " create failed")
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
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)
|
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
LogError(dirPath + " mkdir failed")
|
LogError("Failed mkdir " + dirPath)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
LogInfo("Success mkdir " + dirPath)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func LogInfo(message string) {
|
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) {
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
51
server.go
51
server.go
|
|
@ -2,40 +2,55 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/beancount-gs/script"
|
"github.com/beancount-gs/script"
|
||||||
|
"github.com/beancount-gs/service"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GlobalConfig Config
|
func InitServerFiles() error {
|
||||||
|
dataPath := script.GetServerConfig().DataPath
|
||||||
func InitLedgerFiles() {
|
|
||||||
// 账本目录不存在,则创建
|
// 账本目录不存在,则创建
|
||||||
if !script.FileIfExist(GlobalConfig.DataPath) {
|
if !script.FileIfExist(dataPath) {
|
||||||
script.MkDir(GlobalConfig.DataPath)
|
return script.MkDir(dataPath)
|
||||||
script.LogInfo("Success mkdir " + GlobalConfig.DataPath)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadLedgerCache() {
|
func LoadServerCache() error {
|
||||||
|
return script.LoadLedgerConfigMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterRoute(route *gin.Engine) {
|
func RegisterRouter(router *gin.Engine) {
|
||||||
route.StaticFS("/", http.Dir("./public"))
|
router.StaticFS("/", http.Dir("./public"))
|
||||||
|
router.POST("/api/ledger", service.OpenOrCreateLedger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 默认端口号
|
|
||||||
var port = ":3001"
|
|
||||||
// 读取配置文件
|
// 读取配置文件
|
||||||
GlobalConfig = LoadConfig(GlobalConfig)
|
err := script.LoadServerConfig()
|
||||||
|
if err != nil {
|
||||||
|
script.LogError("Failed to load server config, " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
// 初始化账本文件结构
|
// 初始化账本文件结构
|
||||||
InitLedgerFiles()
|
err = InitServerFiles()
|
||||||
|
if err != nil {
|
||||||
|
script.LogError("Failed to init server files, " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
// 加载缓存
|
// 加载缓存
|
||||||
LoadLedgerCache()
|
err = LoadServerCache()
|
||||||
route := gin.Default()
|
if err != nil {
|
||||||
|
script.LogError("Failed to load server cache, " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router := gin.Default()
|
||||||
// 注册路由
|
// 注册路由
|
||||||
RegisterRoute(route)
|
RegisterRouter(router)
|
||||||
// 启动服务
|
// 启动服务
|
||||||
_ = http.ListenAndServe(port, nil)
|
var port = ":3001"
|
||||||
|
err = router.Run(port)
|
||||||
|
if err != nil {
|
||||||
|
script.LogError("Failed to start server, " + err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"})
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue