123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- package main
- import (
- "encoding/json"
- "io"
- "io/ioutil"
- "net/http"
- "strings"
- "github.com/knadh/listmonk/internal/subimporter"
- "github.com/knadh/listmonk/models"
- "github.com/labstack/echo"
- )
- // handleImportSubscribers handles the uploading and bulk importing of
- // a ZIP file of one or more CSV files.
- func handleImportSubscribers(c echo.Context) error {
- app := c.Get("app").(*App)
- // Is an import already running?
- if app.importer.GetStats().Status == subimporter.StatusImporting {
- return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.alreadyRunning"))
- }
- // Unmarsal the JSON params.
- var opt subimporter.SessionOpt
- if err := json.Unmarshal([]byte(c.FormValue("params")), &opt); err != nil {
- return echo.NewHTTPError(http.StatusBadRequest,
- app.i18n.Ts("import.invalidParams", "error", err.Error()))
- }
- // Validate mode.
- if opt.Mode != subimporter.ModeSubscribe && opt.Mode != subimporter.ModeBlocklist {
- return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidMode"))
- }
- // If no status is specified, pick a default one.
- if opt.SubStatus == "" {
- switch opt.Mode {
- case subimporter.ModeSubscribe:
- opt.SubStatus = models.SubscriptionStatusUnconfirmed
- case subimporter.ModeBlocklist:
- opt.SubStatus = models.SubscriptionStatusUnsubscribed
- }
- }
- if opt.SubStatus != models.SubscriptionStatusUnconfirmed &&
- opt.SubStatus != models.SubscriptionStatusConfirmed &&
- opt.SubStatus != models.SubscriptionStatusUnsubscribed {
- return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidSubStatus"))
- }
- if len(opt.Delim) != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidDelim"))
- }
- file, err := c.FormFile("file")
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest,
- app.i18n.Ts("import.invalidFile", "error", err.Error()))
- }
- src, err := file.Open()
- if err != nil {
- return err
- }
- defer src.Close()
- out, err := ioutil.TempFile("", "listmonk")
- if err != nil {
- return echo.NewHTTPError(http.StatusInternalServerError,
- app.i18n.Ts("import.errorCopyingFile", "error", err.Error()))
- }
- defer out.Close()
- if _, err = io.Copy(out, src); err != nil {
- return echo.NewHTTPError(http.StatusInternalServerError,
- app.i18n.Ts("import.errorCopyingFile", "error", err.Error()))
- }
- // Start the importer session.
- opt.Filename = file.Filename
- impSess, err := app.importer.NewSession(opt)
- if err != nil {
- return echo.NewHTTPError(http.StatusInternalServerError,
- app.i18n.Ts("import.errorStarting", "error", err.Error()))
- }
- go impSess.Start()
- if strings.HasSuffix(strings.ToLower(file.Filename), ".csv") {
- go impSess.LoadCSV(out.Name(), rune(opt.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,
- app.i18n.Ts("import.errorProcessingZIP", "error", err.Error()))
- }
- go impSess.LoadCSV(dir+"/"+files[0], rune(opt.Delim[0]))
- }
- return c.JSON(http.StatusOK, okResp{app.importer.GetStats()})
- }
- // handleGetImportSubscribers returns import statistics.
- func handleGetImportSubscribers(c echo.Context) error {
- var (
- app = c.Get("app").(*App)
- s = app.importer.GetStats()
- )
- return c.JSON(http.StatusOK, okResp{s})
- }
- // handleGetImportSubscriberStats returns import statistics.
- func handleGetImportSubscriberStats(c echo.Context) error {
- app := c.Get("app").(*App)
- return c.JSON(http.StatusOK, okResp{string(app.importer.GetLogs())})
- }
- // handleStopImportSubscribers sends a stop signal to the importer.
- // If there's an ongoing import, it'll be stopped, and if an import
- // is finished, it's state is cleared.
- func handleStopImportSubscribers(c echo.Context) error {
- app := c.Get("app").(*App)
- app.importer.Stop()
- return c.JSON(http.StatusOK, okResp{app.importer.GetStats()})
- }
|