From 7ca08f0a3615ae079e72c238e56c64dbf09ab610 Mon Sep 17 00:00:00 2001 From: Russ Smith Date: Wed, 2 Jun 2021 10:08:12 -0700 Subject: [PATCH] Adding a subscription status option to the import. Ref #168 --- cmd/import.go | 15 ++++++---- cmd/install.go | 2 ++ frontend/src/views/Import.vue | 49 ++++++++++++++++++++++++++++++++ i18n/en.json | 5 ++++ internal/subimporter/importer.go | 27 +++++++++++------- queries.sql | 10 +++---- 6 files changed, 87 insertions(+), 21 deletions(-) diff --git a/cmd/import.go b/cmd/import.go index 5ebf12b..7f90907 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -13,10 +13,11 @@ import ( // reqImport represents file upload import params. type reqImport struct { - Mode string `json:"mode"` - Overwrite bool `json:"overwrite"` - Delim string `json:"delim"` - ListIDs []int `json:"lists"` + Mode string `json:"mode"` + SubscriptionStatus string `json:"subscriptionStatus"` + Overwrite bool `json:"overwrite"` + Delim string `json:"delim"` + ListIDs []int `json:"lists"` } // handleImportSubscribers handles the uploading and bulk importing of @@ -40,6 +41,10 @@ func handleImportSubscribers(c echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidMode")) } + if r.SubscriptionStatus != subimporter.SubscriptionStatusUnconfirmed && r.SubscriptionStatus != subimporter.SubscriptionStatusConfirmed { + return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidSubscriptionStatus")) + } + if len(r.Delim) != 1 { return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("import.invalidDelim")) } @@ -69,7 +74,7 @@ func handleImportSubscribers(c echo.Context) error { } // Start the importer session. - impSess, err := app.importer.NewSession(file.Filename, r.Mode, r.Overwrite, r.ListIDs) + impSess, err := app.importer.NewSession(file.Filename, r.Mode, r.SubscriptionStatus, r.Overwrite, r.ListIDs) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, app.i18n.Ts("import.errorStarting", "error", err.Error())) diff --git a/cmd/install.go b/cmd/install.go index 4bb9008..58cf4af 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -82,6 +82,7 @@ func install(lastVer string, db *sqlx.DB, fs stuffbin.FileSystem, prompt bool) { "John Doe", `{"type": "known", "good": true, "city": "Bengaluru"}`, pq.Int64Array{int64(defList)}, + models.SubscriptionStatusUnconfirmed, true); err != nil { lo.Fatalf("Error creating subscriber: %v", err) } @@ -91,6 +92,7 @@ func install(lastVer string, db *sqlx.DB, fs stuffbin.FileSystem, prompt bool) { "Anon Doe", `{"type": "unknown", "good": true, "city": "Bengaluru"}`, pq.Int64Array{int64(optinList)}, + models.SubscriptionStatusUnconfirmed, true); err != nil { lo.Fatalf("Error creating subscriber: %v", err) } diff --git a/frontend/src/views/Import.vue b/frontend/src/views/Import.vue index 220fefe..d815984 100644 --- a/frontend/src/views/Import.vue +++ b/frontend/src/views/Import.vue @@ -13,12 +13,46 @@ {{ $t('import.subscribe') }} +
{{ $t('import.blocklist') }} +
+ +
+
+ + {{ $t('import.unconfirmed') }} + +
+
+ + {{ $t('import.confirmed') }} + +
+
+ + {{ $t('import.unsubscribed') }} + +
+
+
+
l.id), overwrite: this.form.overwrite, diff --git a/i18n/en.json b/i18n/en.json index 8c088ad..a5cd983 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -185,9 +185,14 @@ "import.invalidDelim": "Delimiter should be a single character.", "import.invalidFile": "Invalid file: {error}", "import.invalidMode": "Invalid mode", + "import.invalidSubscriptionStatus": "Invalid subscription status", "import.invalidParams": "Invalid params: {error}", "import.listSubHelp": "Lists to subscribe to.", "import.mode": "Mode", + "import.subscriptionStatus": "Subscription Status", + "import.confirmed": "Confirmed", + "import.unconfirmed": "Unconfirmed", + "import.unsubscribed": "Unsubscribed", "import.overwrite": "Overwrite?", "import.overwriteHelp": "Overwrite name and attribs of existing subscribers?", "import.recordsCount": "{num} / {total} records", diff --git a/internal/subimporter/importer.go b/internal/subimporter/importer.go index c9b5815..4306bb7 100644 --- a/internal/subimporter/importer.go +++ b/internal/subimporter/importer.go @@ -46,6 +46,9 @@ const ( ModeSubscribe = "subscribe" ModeBlocklist = "blocklist" + + SubscriptionStatusUnconfirmed = "unconfirmed" + SubscriptionStatusConfirmed = "confirmed" ) // Importer represents the bulk CSV subscriber import system. @@ -72,9 +75,10 @@ type Session struct { subQueue chan SubReq log *log.Logger - mode string - overwrite bool - listIDs []int + mode string + subscriptionStatus string + overwrite bool + listIDs []int } // Status reporesents statistics from an ongoing import session. @@ -127,7 +131,7 @@ func New(opt Options, db *sql.DB) *Importer { // NewSession returns an new instance of Session. It takes the name // of the uploaded file, but doesn't do anything with it but retains it for stats. -func (im *Importer) NewSession(fName, mode string, overWrite bool, listIDs []int) (*Session, error) { +func (im *Importer) NewSession(fName, mode string, subscriptionStatus string, overWrite bool, listIDs []int) (*Session, error) { if im.getStatus() != StatusNone { return nil, errors.New("an import is already running") } @@ -139,12 +143,13 @@ func (im *Importer) NewSession(fName, mode string, overWrite bool, listIDs []int im.Unlock() s := &Session{ - im: im, - log: log.New(im.status.logBuf, "", log.Ldate|log.Ltime|log.Lshortfile), - subQueue: make(chan SubReq, commitBatchSize), - mode: mode, - overwrite: overWrite, - listIDs: listIDs, + im: im, + log: log.New(im.status.logBuf, "", log.Ldate|log.Ltime|log.Lshortfile), + subQueue: make(chan SubReq, commitBatchSize), + mode: mode, + subscriptionStatus: subscriptionStatus, + overwrite: overWrite, + listIDs: listIDs, } s.log.Printf("processing '%s'", fName) @@ -266,7 +271,7 @@ func (s *Session) Start() { } if s.mode == ModeSubscribe { - _, err = stmt.Exec(uu, sub.Email, sub.Name, sub.Attribs, listIDs, s.overwrite) + _, err = stmt.Exec(uu, sub.Email, sub.Name, sub.Attribs, listIDs, s.subscriptionStatus, s.overwrite) } else if s.mode == ModeBlocklist { _, err = stmt.Exec(uu, sub.Email, sub.Name, sub.Attribs) } diff --git a/queries.sql b/queries.sql index f6a6156..408d12f 100644 --- a/queries.sql +++ b/queries.sql @@ -80,20 +80,20 @@ SELECT id from sub; -- name: upsert-subscriber -- Upserts a subscriber where existing subscribers get their names and attributes overwritten. --- If $6 = true, update values, otherwise, skip. +-- If $7 = true, update values, otherwise, skip. WITH sub AS ( INSERT INTO subscribers as s (uuid, email, name, attribs, status) VALUES($1, $2, $3, $4, 'enabled') ON CONFLICT (email) DO UPDATE SET - name=(CASE WHEN $6 THEN $3 ELSE s.name END), - attribs=(CASE WHEN $6 THEN $4 ELSE s.attribs END), + name=(CASE WHEN $7 THEN $3 ELSE s.name END), + attribs=(CASE WHEN $7 THEN $4 ELSE s.attribs END), updated_at=NOW() RETURNING uuid, id ), subs AS ( - INSERT INTO subscriber_lists (subscriber_id, list_id) - VALUES((SELECT id FROM sub), UNNEST($5::INT[])) + INSERT INTO subscriber_lists (subscriber_id, list_id, status) + VALUES((SELECT id FROM sub), UNNEST($5::INT[]), $6) ON CONFLICT (subscriber_id, list_id) DO UPDATE SET updated_at=NOW() )