diff --git a/cmd/bounce.go b/cmd/bounce.go index b8858c0d..4d30af20 100644 --- a/cmd/bounce.go +++ b/cmd/bounce.go @@ -84,6 +84,7 @@ func (a *App) DeleteBounces(c echo.Context) error { ids = res } + // Delete bounces from the DB. if err := a.core.DeleteBounces(ids); err != nil { return err @@ -247,38 +248,3 @@ func (a *App) validateBounceFields(b models.Bounce) (models.Bounce, error) { return b, nil } - -func (a *App) BlocklistSubscriberBounces(c echo.Context) error { - var ( - app = c.Get("app").(*App) - pID = c.Param("id") - all, _ = strconv.ParseBool(c.QueryParam("all")) - IDs = []int{} - ) - // Is it an /:id call? - if pID != "" { - id, _ := strconv.Atoi(pID) - if id < 1 { - return echo.NewHTTPError(http.StatusBadRequest, app.i18n.T("globals.messages.invalidID")) - } - IDs = append(IDs, id) - } else if !all { - // Multiple IDs. - i, err := parseStringIDs(c.Request().URL.Query()["id"]) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, - app.i18n.Ts("globals.messages.invalidID", "error", err.Error())) - } - - if len(i) == 0 { - return echo.NewHTTPError(http.StatusBadRequest, - app.i18n.Ts("globals.messages.invalidID")) - } - IDs = i - } - - if err := app.core.BlocklistSubscriberBounces(IDs); err != nil { - return err - } - return c.JSON(http.StatusOK, okResp{true}) -} diff --git a/cmd/handlers.go b/cmd/handlers.go index 09ad6916..f3aa6b51 100644 --- a/cmd/handlers.go +++ b/cmd/handlers.go @@ -124,8 +124,6 @@ func initHTTPHandlers(e *echo.Echo, a *App) { g.GET("/api/bounces/:id", pm(hasID(a.GetBounce), "bounces:get")) g.DELETE("/api/bounces", pm(a.DeleteBounces, "bounces:manage")) g.DELETE("/api/bounces/:id", pm(hasID(a.DeleteBounce), "bounces:manage")) - g.PUT("/api/bounces/blocklist", pm(a.BlocklistSubscriberBounces, "bounces:manage")) - g.PUT("/api/bounces/:id/blocklist", pm(hasID(a.BlocklistSubscriberBounces), "bounces:manage")) // Subscriber operations based on arbitrary SQL queries. // These aren't very REST-like. diff --git a/cmd/subscribers.go b/cmd/subscribers.go index 7675f1f6..8beb2640 100644 --- a/cmd/subscribers.go +++ b/cmd/subscribers.go @@ -458,7 +458,13 @@ func (a *App) BlocklistSubscribersByQuery(c echo.Context) error { req.Search = strings.TrimSpace(req.Search) req.Query = formatSQLExp(req.Query) - + if req.All { + // If the "all" flag is set, ignore any subquery that may be present. + req.Search = "" + req.Query = "" + } else if req.Search == "" && req.Query == "" { + return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", "query")) + } // Does the user have the subscribers:sql_query permission? if req.Query != "" { if !user.HasPerm(auth.PermSubscribersSqlQuery) { diff --git a/docs/swagger/collections.yaml b/docs/swagger/collections.yaml index 41a32884..f2cfb060 100644 --- a/docs/swagger/collections.yaml +++ b/docs/swagger/collections.yaml @@ -889,58 +889,6 @@ paths: properties: data: type: boolean - - /bounces/blocklist: - put: - description: handles blocklisting of bounces - operationId: manageBlocklistBounces - tags: - - Bounces - parameters: - - in: query - name: all - description: flag for multiple bounce records to blocklist - schema: - type: boolean - - in: query - name: id - description: list of bounce ids to blocklist - schema: - type: string - responses: - "200": - description: OK - content: - application/json: - schema: - type: object - properties: - data: - type: boolean - - "/bounces/{id}/blocklist": - put: - description: handles the blocklisting of one or more bounces. - operationId: manageBlocklistBouncesById - tags: - - Bounces - parameters: - - in: path - name: id - required: true - description: The id value of the bounce you want to blocklist. - schema: - type: integer - responses: - "200": - description: OK - content: - application/json: - schema: - type: object - properties: - data: - type: boolean /lists: get: diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 2d8ff833..9c9435df 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -179,18 +179,6 @@ export const deleteSubscriberBounces = async (id) => http.delete( { loading: models.bounces }, ); -export const blocklistSubscriberBounce = async (id) => http.put( - `/api/bounces/${id}/blocklist`, - null, - { loading: models.bounces }, -); - -export const blocklistSubscriberBounces = async (params) => http.put( - '/api/bounces/blocklist', - null, - { params, loading: models.bounces }, -); - export const deleteBounce = async (id) => http.delete( `/api/bounces/${id}`, { loading: models.bounces }, diff --git a/frontend/src/views/Bounces.vue b/frontend/src/views/Bounces.vue index 5b8f65d0..7c1242c4 100644 --- a/frontend/src/views/Bounces.vue +++ b/frontend/src/views/Bounces.vue @@ -169,7 +169,7 @@ export default Vue.extend({ }, deleteBounces() { - const count = this.bulk.checked.length; + const count = this.numSelectedBounces; const fnSuccess = () => { this.getBounces(); this.$utils.toast(this.$t( @@ -182,10 +182,10 @@ export default Vue.extend({ this.$api.deleteBounces({ id: ids }).then(fnSuccess); return; } - this.$api.deleteBounces({ all: true }).then(fnSuccess); + this.$api.deleteSubscribersByQuery({ all: true }).then(fnSuccess); }, blocklistBounces() { - const count = this.bulk.checked.length; + const count = this.numSelectedBounces; const fnSuccess = () => { this.getBounces(); this.$utils.toast(this.$t( @@ -194,11 +194,11 @@ export default Vue.extend({ )); }; if (!this.bulk.all && this.bulk.checked.length > 0) { - const ids = this.bulk.checked.map((s) => s.id); - this.$api.blocklistSubscriberBounces({ id: ids }).then(fnSuccess); + const subscriberIds = this.bulk.checked.map((s) => s.id); + this.$api.blocklistSubscribers({ ids: subscriberIds }).then(fnSuccess); return; } - this.$api.blocklistSubscriberBounces({ all: true }).then(fnSuccess); + this.$api.blocklistSubscribersByQuery({ all: true }).then(fnSuccess); }, }, diff --git a/internal/core/bounces.go b/internal/core/bounces.go index aa9053ab..4ba61d11 100644 --- a/internal/core/bounces.go +++ b/internal/core/bounces.go @@ -100,13 +100,3 @@ func (c *Core) DeleteBounces(ids []int) error { } return nil } - -// BlocklistSubscriberBounces blocklists the subscribers whose message bounces. -func (c *Core) BlocklistSubscriberBounces(ids []int) error { - if _, err := c.q.BlocklistSubscribersByBounces.Exec(pq.Array(ids)); err != nil { - c.log.Printf("error blocklisting subscribers by bounces: %v", err) - return echo.NewHTTPError(http.StatusInternalServerError, - c.i18n.Ts("globals.messages.errorUpdating", "name", "{globals.terms.bounce}", "error", pqErrMsg(err))) - } - return nil -} diff --git a/models/queries.go b/models/queries.go index 6e92a9b2..506f44ba 100644 --- a/models/queries.go +++ b/models/queries.go @@ -106,12 +106,11 @@ type Queries struct { UpdateSettings *sqlx.Stmt `query:"update-settings"` // GetStats *sqlx.Stmt `query:"get-stats"` - RecordBounce *sqlx.Stmt `query:"record-bounce"` - QueryBounces string `query:"query-bounces"` - DeleteBounces *sqlx.Stmt `query:"delete-bounces"` - DeleteBouncesBySubscriber *sqlx.Stmt `query:"delete-bounces-by-subscriber"` - BlocklistSubscribersByBounces *sqlx.Stmt `query:"blocklist-subscribers-by-bounces"` - GetDBInfo string `query:"get-db-info"` + RecordBounce *sqlx.Stmt `query:"record-bounce"` + QueryBounces string `query:"query-bounces"` + DeleteBounces *sqlx.Stmt `query:"delete-bounces"` + DeleteBouncesBySubscriber *sqlx.Stmt `query:"delete-bounces-by-subscriber"` + GetDBInfo string `query:"get-db-info"` CreateUser *sqlx.Stmt `query:"create-user"` UpdateUser *sqlx.Stmt `query:"update-user"` diff --git a/queries.sql b/queries.sql index 5a35d79b..95365403 100644 --- a/queries.sql +++ b/queries.sql @@ -1106,17 +1106,6 @@ ORDER BY %order% OFFSET $5 LIMIT $6; -- name: delete-bounces DELETE FROM bounces WHERE CARDINALITY($1::INT[]) = 0 OR id = ANY($1); ---name: blocklist-subscribers-by-bounces -WITH subscriber_ids_to_blocklist AS ( - SELECT DISTINCT b.subscriber_id - FROM bounces b - WHERE CARDINALITY($1::INT[]) = 0 OR b.id = ANY($1) -) -UPDATE subscribers -SET status = 'blocklisted' -WHERE id IN (SELECT subscriber_id FROM subscriber_ids_to_blocklist) -RETURNING id, email, status; - -- name: delete-bounces-by-subscriber WITH sub AS ( SELECT id FROM subscribers WHERE CASE WHEN $1 > 0 THEN id = $1 ELSE uuid = $2 END