Skip to content

Commit

Permalink
Add tag/type/optin filter options to lists and campaigns APIs. Closes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
knadh committed Dec 23, 2023
1 parent c468e7a commit 01acd38
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 33 deletions.
3 changes: 2 additions & 1 deletion cmd/campaigns.go
Expand Up @@ -57,13 +57,14 @@ func handleGetCampaigns(c echo.Context) error {
pg = app.paginator.NewFromURL(c.Request().URL.Query())

status = c.QueryParams()["status"]
tags = c.QueryParams()["tag"]
query = strings.TrimSpace(c.FormValue("query"))
orderBy = c.FormValue("order_by")
order = c.FormValue("order")
noBody, _ = strconv.ParseBool(c.QueryParam("no_body"))
)

res, total, err := app.core.QueryCampaigns(query, status, orderBy, order, pg.Offset, pg.Limit)
res, total, err := app.core.QueryCampaigns(query, status, tags, orderBy, order, pg.Offset, pg.Limit)
if err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/lists.go
Expand Up @@ -16,7 +16,10 @@ func handleGetLists(c echo.Context) error {
pg = app.paginator.NewFromURL(c.Request().URL.Query())

query = strings.TrimSpace(c.FormValue("query"))
tags = c.QueryParams()["tag"]
orderBy = c.FormValue("order_by")
typ = c.FormValue("type")
optin = c.FormValue("optin")
order = c.FormValue("order")
minimal, _ = strconv.ParseBool(c.FormValue("minimal"))
listID, _ = strconv.Atoi(c.Param("id"))
Expand Down Expand Up @@ -58,7 +61,7 @@ func handleGetLists(c echo.Context) error {
}

// Full list query.
res, total, err := app.core.QueryLists(query, orderBy, order, pg.Offset, pg.Limit)
res, total, err := app.core.QueryLists(query, typ, optin, tags, orderBy, order, pg.Offset, pg.Limit)
if err != nil {
return err
}
Expand Down
16 changes: 9 additions & 7 deletions docs/docs/content/apis/campaigns.md
Expand Up @@ -26,13 +26,15 @@ Retrieve all campaigns.

##### Parameters

| Name | Type | Required | Description |
|:---------|:-------|:---------|:---------------------------------------------------------------------|
| order | string | | Sorting order: ASC for ascending, DESC for descending. |
| order_by | string | | Result sorting field. Options: name, status, created_at, updated_at. |
| query | string | | SQL query expression to filter subscribers. |
| page | number | | Page number for paginated results. |
| per_page | number | | Results per page. Set as 'all' for all results. |
| Name | Type | Required | Description |
|:---------|:---------|:---------|:---------------------------------------------------------------------|
| order | string | | Sorting order: ASC for ascending, DESC for descending. |
| order_by | string | | Result sorting field. Options: name, status, created_at, updated_at. |
| query | string | | SQL query expression to filter campaigns. |
| status | []string | | Status to filter campaigns. Repeat in the query for multiple values. |
| tags | []string | | Tags to filter campaigns. Repeat in the query for multiple values. |
| page | number | | Page number for paginated results. |
| per_page | number | | Results per page. Set as 'all' for all results. |

##### Example Response

Expand Down
16 changes: 9 additions & 7 deletions docs/docs/content/apis/lists.md
Expand Up @@ -16,13 +16,15 @@ Retrieve lists.

##### Parameters

| Name | Type | Required | Description |
|:---------|:----------|:---------|:-----------------------------------------------------------|
| query | string | | string for list name search. |
| order_by | string | | Sort field. Options: name, status, created_at, updated_at. |
| order | string | | Sorting order. Options: ASC, DESC. |
| page | number | | Page number for pagination. |
| per_page | number | | Results per page. Set to 'all' to return all results. |
| Name | Type | Required | Description |
|:---------|:---------|:---------|:-----------------------------------------------------------------|
| query | string | | string for list name search. |
| status | []string | | Status to filter lists. Repeat in the query for multiple values. |
| tags | []string | | Tags to filter lists. Repeat in the query for multiple values. |
| order_by | string | | Sort field. Options: name, status, created_at, updated_at. |
| order | string | | Sorting order. Options: ASC, DESC. |
| page | number | | Page number for pagination. |
| per_page | number | | Results per page. Set to 'all' to return all results. |

##### Example Request

Expand Down
8 changes: 6 additions & 2 deletions internal/core/campaigns.go
Expand Up @@ -23,16 +23,20 @@ const (

// QueryCampaigns retrieves paginated campaigns optionally filtering them by the given arbitrary
// query expression. It also returns the total number of records in the DB.
func (c *Core) QueryCampaigns(searchStr string, statuses []string, orderBy, order string, offset, limit int) (models.Campaigns, int, error) {
func (c *Core) QueryCampaigns(searchStr string, statuses, tags []string, orderBy, order string, offset, limit int) (models.Campaigns, int, error) {
queryStr, stmt := makeSearchQuery(searchStr, orderBy, order, c.q.QueryCampaigns, campQuerySortFields)

if statuses == nil {
statuses = []string{}
}

if tags == nil {
tags = []string{}
}

// Unsafe to ignore scanning fields not present in models.Campaigns.
var out models.Campaigns
if err := c.db.Select(&out, stmt, 0, pq.Array(statuses), queryStr, offset, limit); err != nil {
if err := c.db.Select(&out, stmt, 0, pq.StringArray(statuses), pq.StringArray(tags), queryStr, offset, limit); err != nil {
c.log.Printf("error fetching campaigns: %v", err)
return nil, 0, echo.NewHTTPError(http.StatusInternalServerError,
c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.campaign}", "error", pqErrMsg(err)))
Expand Down
10 changes: 7 additions & 3 deletions internal/core/lists.go
Expand Up @@ -36,12 +36,16 @@ func (c *Core) GetLists(typ string) ([]models.List, error) {

// QueryLists gets multiple lists based on multiple query params. Along with the paginated and sliced
// results, the total number of lists in the DB is returned.
func (c *Core) QueryLists(searchStr, orderBy, order string, offset, limit int) ([]models.List, int, error) {
func (c *Core) QueryLists(searchStr, typ, optin string, tags []string, orderBy, order string, offset, limit int) ([]models.List, int, error) {
out := []models.List{}

queryStr, stmt := makeSearchQuery(searchStr, orderBy, order, c.q.QueryLists, listQuerySortFields)

if err := c.db.Select(&out, stmt, 0, "", queryStr, offset, limit); err != nil {
if tags == nil {
tags = []string{}
}

if err := c.db.Select(&out, stmt, 0, "", queryStr, typ, optin, pq.StringArray(tags), offset, limit); err != nil {
c.log.Printf("error fetching lists: %v", err)
return nil, 0, echo.NewHTTPError(http.StatusInternalServerError,
c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.lists}", "error", pqErrMsg(err)))
Expand Down Expand Up @@ -76,7 +80,7 @@ func (c *Core) GetList(id int, uuid string) (models.List, error) {

var res []models.List
queryStr, stmt := makeSearchQuery("", "", "", c.q.QueryLists, nil)
if err := c.db.Select(&res, stmt, id, uu, queryStr, 0, 1); err != nil {
if err := c.db.Select(&res, stmt, id, uu, queryStr, "", "", pq.StringArray{}, 0, 1); err != nil {
c.log.Printf("error fetching lists: %v", err)
return models.List{}, echo.NewHTTPError(http.StatusInternalServerError,
c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.lists}", "error", pqErrMsg(err)))
Expand Down
27 changes: 15 additions & 12 deletions queries.sql
Expand Up @@ -408,15 +408,17 @@ SELECT * FROM lists WHERE (CASE WHEN $1 = '' THEN 1=1 ELSE type=$1::list_type EN

-- name: query-lists
WITH ls AS (
SELECT COUNT(*) OVER () AS total, lists.* FROM lists
WHERE
CASE
WHEN $1 > 0 THEN id = $1
WHEN $2 != '' THEN uuid = $2::UUID
WHEN $3 != '' THEN to_tsvector(name) @@ to_tsquery ($3)
ELSE true
END
OFFSET $4 LIMIT (CASE WHEN $5 < 1 THEN NULL ELSE $5 END)
SELECT COUNT(*) OVER () AS total, lists.* FROM lists WHERE
CASE
WHEN $1 > 0 THEN id = $1
WHEN $2 != '' THEN uuid = $2::UUID
WHEN $3 != '' THEN to_tsvector(name) @@ to_tsquery ($3)
ELSE TRUE
END
AND ($4 = '' OR type = $4::list_type)
AND ($5 = '' OR optin = $5::list_optin)
AND (CARDINALITY($6::VARCHAR(100)[]) = 0 OR $6 <@ tags)
OFFSET $7 LIMIT (CASE WHEN $8 < 1 THEN NULL ELSE $8 END)
),
counts AS (
SELECT list_id, JSON_OBJECT_AGG(status, num) AS subscriber_statuses, SUM(num) AS subscriber_count
Expand Down Expand Up @@ -525,9 +527,10 @@ SELECT c.id, c.uuid, c.name, c.subject, c.from_email,
) AS lists
FROM campaigns c
WHERE ($1 = 0 OR id = $1)
AND status=ANY(CASE WHEN CARDINALITY($2::campaign_status[]) != 0 THEN $2::campaign_status[] ELSE ARRAY[status] END)
AND ($3 = '' OR TO_TSVECTOR(CONCAT(name, ' ', subject)) @@ TO_TSQUERY($3))
ORDER BY %order% OFFSET $4 LIMIT (CASE WHEN $5 < 1 THEN NULL ELSE $5 END);
AND (CARDINALITY($2::campaign_status[]) = 0 OR status = ANY($2))
AND (CARDINALITY($3::VARCHAR(100)[]) = 0 OR $3 <@ tags)
AND ($4 = '' OR TO_TSVECTOR(CONCAT(name, ' ', subject)) @@ TO_TSQUERY($4))
ORDER BY %order% OFFSET $5 LIMIT (CASE WHEN $6 < 1 THEN NULL ELSE $6 END);

-- name: get-campaign
SELECT campaigns.*,
Expand Down

0 comments on commit 01acd38

Please sign in to comment.