优化代码/支持IP名单的更多格式的导入、导出

This commit is contained in:
刘祥超
2021-08-07 18:26:50 +08:00
parent d97f4da7fa
commit c3e68915a3
11 changed files with 272 additions and 21 deletions

View File

@@ -39,6 +39,10 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
recipientMaps := []maps.Map{}
for _, recipient := range recipientsResp.MessageRecipients {

View File

@@ -35,6 +35,10 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
instanceMaps := []maps.Map{}
for _, instance := range instancesResp.MessageMediaInstances {

View File

@@ -62,6 +62,10 @@ func (this *LogsAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
logs := []maps.Map{}
for _, log := range logsResp.NodeLogs {

View File

@@ -51,6 +51,10 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
logs := []maps.Map{}
for _, log := range logsResp.NodeLogs {

View File

@@ -3,10 +3,15 @@
package iplists
import (
"bytes"
"encoding/csv"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/golang/protobuf/proto"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/tealeg/xlsx/v3"
"strconv"
)
@@ -20,10 +25,55 @@ func (this *ExportDataAction) Init() {
func (this *ExportDataAction) RunGet(params struct {
ListId int64
Format string
}) {
defer this.CreateLogInfo("导出IP名单 %d", params.ListId)
resp := &pb.ListIPItemsWithListIdResponse{}
var err error
var ext = ""
var jsonMaps = []maps.Map{}
var xlsxFile *xlsx.File
var xlsxSheet *xlsx.Sheet
var csvWriter *csv.Writer
var csvBuffer *bytes.Buffer
var data []byte
switch params.Format {
case "xlsx":
ext = ".xlsx"
xlsxFile = xlsx.NewFile()
if err != nil {
this.ErrorPage(err)
return
}
xlsxSheet, err = xlsxFile.AddSheet("IP名单")
if err != nil {
this.ErrorPage(err)
return
}
row := xlsxSheet.AddRow()
row.SetHeight(26)
row.AddCell().SetValue("开始IP")
row.AddCell().SetValue("结束IP")
row.AddCell().SetValue("过期时间戳")
row.AddCell().SetValue("类型")
row.AddCell().SetValue("级别")
row.AddCell().SetValue("备注")
case "csv":
ext = ".csv"
csvBuffer = &bytes.Buffer{}
csvWriter = csv.NewWriter(csvBuffer)
case "txt":
ext = ".txt"
case "json":
ext = ".json"
default:
this.WriteString("请选择正确的导出格式")
return
}
var offset int64 = 0
var size int64 = 1000
for {
@@ -40,18 +90,60 @@ func (this *ExportDataAction) RunGet(params struct {
break
}
for _, item := range itemsResp.IpItems {
resp.IpItems = append(resp.IpItems, item)
switch params.Format {
case "xlsx":
row := xlsxSheet.AddRow()
row.SetHeight(26)
row.AddCell().SetValue(item.IpFrom)
row.AddCell().SetValue(item.IpTo)
row.AddCell().SetValue(types.String(item.ExpiredAt))
row.AddCell().SetValue(item.Type)
row.AddCell().SetValue(item.EventLevel)
row.AddCell().SetValue(item.Reason)
case "csv":
err = csvWriter.Write([]string{item.IpFrom, item.IpTo, types.String(item.ExpiredAt), item.Type, item.EventLevel, item.Reason})
if err != nil {
this.ErrorPage(err)
return
}
case "txt":
data = append(data, item.IpFrom+","+item.IpTo+","+types.String(item.ExpiredAt)+","+item.Type+","+item.EventLevel+","+item.Reason...)
data = append(data, '\n')
case "json":
jsonMaps = append(jsonMaps, maps.Map{
"ipFrom": item.IpFrom,
"ipTo": item.IpTo,
"expiredAt": item.ExpiredAt,
"type": item.Type,
"eventLevel": item.EventLevel,
"reason": item.Reason,
})
}
}
offset += size
}
data, err := proto.Marshal(resp)
if err != nil {
this.ErrorPage(err)
return
switch params.Format {
case "xlsx":
var buf = &bytes.Buffer{}
err = xlsxFile.Write(buf)
if err != nil {
this.ErrorPage(err)
return
}
data = buf.Bytes()
case "csv":
csvWriter.Flush()
data = csvBuffer.Bytes()
case "json":
data, err = json.Marshal(jsonMaps)
if err != nil {
this.ErrorPage(err)
return
}
}
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+".data\";")
this.AddHeader("Content-Disposition", "attachment; filename=\"ip-list-"+numberutils.FormatInt64(params.ListId)+ext+"\";")
this.AddHeader("Content-Length", strconv.Itoa(len(data)))
this.Write(data)
}

View File

@@ -3,10 +3,19 @@
package iplists
import (
"bytes"
"encoding/csv"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/golang/protobuf/proto"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
"github.com/tealeg/xlsx/v3"
"io"
"net"
"regexp"
"strings"
)
type ImportAction struct {
@@ -51,20 +60,92 @@ func (this *ImportAction) RunPost(params struct {
this.Fail("请选择要导入的IP文件")
}
// 检查文件扩展名
if !regexp.MustCompile(`(?i)\.(xlsx|csv|json|txt)$`).MatchString(params.File.Filename) {
this.Fail("不支持当前格式的文件导入")
}
var ext = strings.ToLower(params.File.Ext)
data, err := params.File.Read()
if err != nil {
this.ErrorPage(err)
return
}
resp := &pb.ListIPItemsWithListIdResponse{}
err = proto.Unmarshal(data, resp)
if err != nil {
this.Fail("导入失败,文件格式错误:" + err.Error())
var countIgnore = 0
var items = []*pb.IPItem{}
switch ext {
case ".xlsx":
file, err := xlsx.OpenBinary(data)
if err != nil {
this.Fail("Excel读取错误" + err.Error())
}
if len(file.Sheets) > 0 {
var sheet = file.Sheets[0]
err = sheet.ForEachRow(func(r *xlsx.Row) error {
var values = []string{}
err = r.ForEachCell(func(c *xlsx.Cell) error {
values = append(values, c.Value)
return nil
})
if err != nil {
return err
}
if len(values) == 0 {
return nil
}
if values[0] == "开始IP" || values[0] == "IP" {
return nil
}
item := this.createItemFromValues(values, &countIgnore)
if item != nil {
items = append(items, item)
}
return nil
})
if err != nil {
this.Fail("Excel读取错误" + err.Error())
}
}
case ".csv":
reader := csv.NewReader(bytes.NewBuffer(data))
for {
values, err := reader.Read()
if err != nil {
if err == io.EOF {
break
}
this.Fail("CSV读取错误" + err.Error())
}
item := this.createItemFromValues(values, &countIgnore)
if item != nil {
items = append(items, item)
}
}
case ".json":
err = json.Unmarshal(data, &items)
if err != nil {
this.Fail("导入失败:" + err.Error())
}
case ".txt":
lines := bytes.Split(data, []byte{'\n'})
for _, line := range lines {
if len(line) == 0 {
continue
}
item := this.createItemFromValues(strings.SplitN(string(line), ",", 6), &countIgnore)
if item != nil {
items = append(items, item)
}
}
}
var count = 0
var countIgnore = 0
for _, item := range resp.IpItems {
lists.Reverse(items)
for _, item := range items {
_, err = this.RPC().IPItemRPC().CreateIPItem(this.AdminContext(), &pb.CreateIPItemRequest{
IpListId: params.ListId,
IpFrom: item.IpFrom,
@@ -85,3 +166,48 @@ func (this *ImportAction) RunPost(params struct {
this.Success()
}
func (this *ImportAction) createItemFromValues(values []string, countIgnore *int) *pb.IPItem {
// ipFrom, ipTo, expiredAt, type, eventType, reason
var item = &pb.IPItem{}
switch len(values) {
case 1:
item.IpFrom = values[0]
case 2:
item.IpFrom = values[0]
item.IpTo = values[1]
case 3:
item.IpFrom = values[0]
item.IpTo = values[1]
item.ExpiredAt = types.Int64(values[2])
case 4:
item.IpFrom = values[0]
item.IpTo = values[1]
item.ExpiredAt = types.Int64(values[2])
item.Type = values[3]
case 5:
item.IpFrom = values[0]
item.IpTo = values[1]
item.ExpiredAt = types.Int64(values[2])
item.Type = values[3]
item.EventLevel = values[4]
case 6:
item.IpFrom = values[0]
item.IpTo = values[1]
item.ExpiredAt = types.Int64(values[2])
item.Type = values[3]
item.EventLevel = values[4]
item.Reason = values[5]
}
if net.ParseIP(item.IpFrom) == nil {
*countIgnore++
return nil
}
if len(item.IpTo) > 0 && net.ParseIP(item.IpTo) == nil {
*countIgnore++
return nil
}
return item
}

View File

@@ -27,6 +27,7 @@ func (this *SortAction) RunPost(params struct {
}
if webConfig == nil {
this.Success()
return
}
refMap := map[int64]*serverconfigs.HTTPLocationRef{}
for _, ref := range webConfig.LocationRefs {

View File

@@ -121,6 +121,10 @@ func (this *SettingAction) RunPost(params struct {
MaxConns: types.Int32(reverseProxyConfig.MaxConns),
MaxIdleConns: types.Int32(reverseProxyConfig.MaxIdleConns),
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}