add data export to cli
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
clis "github.com/mayswind/lab/pkg/cli"
|
clis "github.com/mayswind/lab/pkg/cli"
|
||||||
"github.com/mayswind/lab/pkg/log"
|
"github.com/mayswind/lab/pkg/log"
|
||||||
|
"github.com/mayswind/lab/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserData represents the data command
|
// UserData represents the data command
|
||||||
@@ -24,6 +27,23 @@ var UserData = &cli.Command{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "export",
|
||||||
|
Usage: "Export user all transactions to csv file",
|
||||||
|
Action: exportUserTransaction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Aliases: []string{"n"},
|
||||||
|
Usage: "Specific user name",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "file",
|
||||||
|
Aliases: []string{"f"},
|
||||||
|
Usage: "Specific exported file path (e.g. transaction.csv)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,3 +75,53 @@ func checkUserTransactionAndAccount(c *cli.Context) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func exportUserTransaction(c *cli.Context) error {
|
||||||
|
_, err := initializeSystem(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userName := c.String("username")
|
||||||
|
uid, err := clis.UserData.GetUserIdByUsername(c, userName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.exportUserTransaction] error occurs when getting user id by user name")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := c.String("file")
|
||||||
|
|
||||||
|
if filePath == "" {
|
||||||
|
log.BootErrorf("[user_data.exportUserTransaction] export file path is not specified")
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
fileExists, err := utils.IsExists(filePath)
|
||||||
|
|
||||||
|
if fileExists {
|
||||||
|
log.BootErrorf("[user_data.exportUserTransaction] specified file path already exists")
|
||||||
|
return os.ErrExist
|
||||||
|
}
|
||||||
|
|
||||||
|
log.BootInfof("[user_data.exportUserTransaction] starting exporting user \"%s\" data", userName)
|
||||||
|
|
||||||
|
content, err := clis.UserData.ExportTransaction(c, uid)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.exportUserTransaction] error occurs when exporting user data")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = utils.WriteFile(filePath, content)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.exportUserTransaction] failed to write to %s", filePath)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.BootInfof("[user_data.exportUserTransaction] user transactions have been exported to %s", filePath)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ import (
|
|||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/mayswind/lab/pkg/errs"
|
"github.com/mayswind/lab/pkg/errs"
|
||||||
|
"github.com/mayswind/lab/pkg/exporters"
|
||||||
"github.com/mayswind/lab/pkg/log"
|
"github.com/mayswind/lab/pkg/log"
|
||||||
"github.com/mayswind/lab/pkg/models"
|
"github.com/mayswind/lab/pkg/models"
|
||||||
"github.com/mayswind/lab/pkg/services"
|
"github.com/mayswind/lab/pkg/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
const pageCountForGettingTransactions = 1000
|
const pageCountForGettingTransactions = 1000
|
||||||
|
const pageCountForDataExport = 1000
|
||||||
|
|
||||||
// UserDataCli represents user data cli
|
// UserDataCli represents user data cli
|
||||||
type UserDataCli struct {
|
type UserDataCli struct {
|
||||||
|
csvExporter *exporters.CSVFileExporter
|
||||||
accounts *services.AccountService
|
accounts *services.AccountService
|
||||||
transactions *services.TransactionService
|
transactions *services.TransactionService
|
||||||
categories *services.TransactionCategoryService
|
categories *services.TransactionCategoryService
|
||||||
@@ -23,6 +26,7 @@ type UserDataCli struct {
|
|||||||
// Initialize an user data cli singleton instance
|
// Initialize an user data cli singleton instance
|
||||||
var (
|
var (
|
||||||
UserData = &UserDataCli{
|
UserData = &UserDataCli{
|
||||||
|
csvExporter: &exporters.CSVFileExporter{},
|
||||||
accounts: services.Accounts,
|
accounts: services.Accounts,
|
||||||
transactions: services.Transactions,
|
transactions: services.Transactions,
|
||||||
users: services.Users,
|
users: services.Users,
|
||||||
@@ -139,6 +143,32 @@ func (a *UserDataCli) CheckTransactionAndAccount(c *cli.Context, uid int64) (boo
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExportTransaction returns csv file content according user all transactions
|
||||||
|
func (a *UserDataCli) ExportTransaction(c *cli.Context, uid int64) ([]byte, error) {
|
||||||
|
accountMap, categoryMap, tagMap, tagIndexs, err := a.getUserEssentialData(uid)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.ExportTransaction] failed to get essential data for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransactions, err := a.transactions.GetAllTransactions(uid, pageCountForDataExport, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.ExportTransaction] failed to all transactions for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := a.csvExporter.GetOutputContent(uid, allTransactions, accountMap, categoryMap, tagMap, tagIndexs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.BootErrorf("[user_data.ExportTransaction] failed to get csv format exported data for \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserIdByUsername returns user id by user name
|
// GetUserIdByUsername returns user id by user name
|
||||||
func (a *UserDataCli) GetUserIdByUsername(c *cli.Context, username string) (int64, error) {
|
func (a *UserDataCli) GetUserIdByUsername(c *cli.Context, username string) (int64, error) {
|
||||||
if username == "" {
|
if username == "" {
|
||||||
|
|||||||
+38
-1
@@ -1,6 +1,43 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "io"
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsExists returns whether specified file or directory path exits
|
||||||
|
func IsExists(path string) (bool, error) {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFile would write file according to specified content
|
||||||
|
func WriteFile(path string, data []byte) error {
|
||||||
|
file, err := os.Create(path)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
n, err := file.Write(data)
|
||||||
|
|
||||||
|
if err == nil && n < len(data) {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// IdentReader returns the original io reader
|
// IdentReader returns the original io reader
|
||||||
func IdentReader(encoding string, input io.Reader) (io.Reader, error) {
|
func IdentReader(encoding string, input io.Reader) (io.Reader, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user