Przeglądaj źródła

Add support for importing unzipped CSV

Kailash Nadh 6 lat temu
rodzic
commit
8a0a7a195e
2 zmienionych plików z 25 dodań i 17 usunięć
  1. 5 5
      frontend/my/src/Import.js
  2. 20 12
      import.go

+ 5 - 5
frontend/my/src/Import.js

@@ -118,7 +118,7 @@ class TheFormDef extends React.PureComponent {
                     </Form.Item>
                     <Form.Item
                         {...formItemLayout}
-                        label="ZIP file">
+                        label="CSV or ZIP file">
                         <div className="dropbox">
                             {getFieldDecorator("file", {
                                 valuePropName: "file",
@@ -129,11 +129,11 @@ class TheFormDef extends React.PureComponent {
                                     multiple={ false }
                                     fileList={ this.state.fileList }
                                     beforeUpload={ this.onFileChange }
-                                    accept=".zip">
+                                    accept=".zip,.csv">
                                     <p className="ant-upload-drag-icon">
                                         <Icon type="inbox" />
                                     </p>
-                                    <p className="ant-upload-text">Click or drag the ZIP file here</p>
+                                    <p className="ant-upload-text">Click or drag a CSV or ZIP file here</p>
                                 </Upload.Dragger>
                             )}
                         </div>
@@ -316,8 +316,8 @@ class Import extends React.PureComponent {
                 <hr />
                 <div className="help">
                     <h2>Instructions</h2>
-                    <p>Upload a ZIP file with a single CSV file in it
-                        to bulk import a large number of subscribers in a single shot.
+                    <p>Upload a CSV file or a ZIP file with a single CSV file in it
+                        to bulk import a subscribers.
                     </p>
                     <p>
                         The CSV file should have the following headers with the exact column names

+ 20 - 12
import.go

@@ -6,6 +6,7 @@ import (
 	"io"
 	"io/ioutil"
 	"net/http"
+	"strings"
 
 	"github.com/knadh/listmonk/subimporter"
 	"github.com/labstack/echo"
@@ -37,8 +38,7 @@ func handleImportSubscribers(c echo.Context) error {
 	}
 
 	if r.Mode != subimporter.ModeSubscribe && r.Mode != subimporter.ModeBlacklist {
-		return echo.NewHTTPError(http.StatusBadRequest,
-			"Invalid `mode`")
+		return echo.NewHTTPError(http.StatusBadRequest, "Invalid `mode`")
 	}
 
 	if len(r.Delim) != 1 {
@@ -78,17 +78,25 @@ func handleImportSubscribers(c echo.Context) error {
 	}
 	go impSess.Start()
 
-	// For now, we only extract 1 CSV from the ZIP. Handling async CSV
-	// imports is more trouble than it's worth.
-	dir, files, err := impSess.ExtractZIP(out.Name(), 1)
-	if err != nil {
-		return echo.NewHTTPError(http.StatusInternalServerError,
-			fmt.Sprintf("Error extracting ZIP file: %v", err))
-	} else if len(files) == 0 {
-		return echo.NewHTTPError(http.StatusBadRequest,
-			"No CSV files found to import.")
+	if strings.HasSuffix(strings.ToLower(file.Filename), ".csv") {
+		go impSess.LoadCSV(out.Name(), rune(r.Delim[0]))
+	} else {
+		// Only 1 CSV from the ZIP is considered. If multiple files have
+		// to be processed, counting the net number of lines (to track progress),
+		// keeping the global import state (failed / successful) etc. across
+		// multiple files becomes complex. Instead, it's just easier for the
+		// end user to concat multiple CSVs (if there are multiple in the first)
+		// place and uploada as one in the first place.
+		dir, files, err := impSess.ExtractZIP(out.Name(), 1)
+		if err != nil {
+			return echo.NewHTTPError(http.StatusInternalServerError,
+				fmt.Sprintf("Error extracting ZIP file: %v", err))
+		} else if len(files) == 0 {
+			return echo.NewHTTPError(http.StatusBadRequest,
+				"No CSV files found to import.")
+		}
+		go impSess.LoadCSV(dir+"/"+files[0], rune(r.Delim[0]))
 	}
-	go impSess.LoadCSV(dir+"/"+files[0], rune(r.Delim[0]))
 
 	return c.JSON(http.StatusOK, okResp{app.Importer.GetStats()})
 }