This patch significantly cleans up clunky, repetitive, and pervasive
validation logic across HTTP handlers.
- Rather than dozens of handlers checking and using strconv to validate ID,
the handlers with `:id` are now wrapped in a `hasID()` middleware that does
the validation and sets an int `id` in the handler context that the wrapped
handlers can now access with `getID()`.
- Handlers that handled both single + multi resource requests
(eg: GET `/api/lists`) with single/multiple id checking conditions are all now
split into separate handlers, eg: `getList()`, `getLists()`.
- Attach all HTTP handlers to a new `Handlers{}` struct.
- Remove all `handle*` function prefixes.
- Remove awkward, repetitive `app = c.Get("app").(*App)` from all handlers
and instead, simply access it from `h.app` from `Handlers{}`
Originally proposed in #2292.
- Make the beginning of handlers consistent with uniform variable declaration
and grouping.
- Add missing comments.
- Fix staticcheck/vet warnings and idiom issues.
- Move user models from `/models` to `internal/auth`.
- Move and refactor various permission check functions into `User.()`
- Refactor awkward `get, manage bool` function args into `Get|Manage` bitflags.
This patch introduces new `campaigns:get_all` and `campaigns:manage_all`
permissions which alter the behaviour of the the old `campaigns:get` and
`campaigns:manage` permissions. This is a subtle breaking behavioural change.
Old:
- `campaigns:get` -> View all campaigns irrespective of a user's list
permissions.
- `campaigns:manage` -> Manage all campaigns irrespective of a user's list
permissions.
New:
- `campaigns:get_all` -> View all campaigns irrespective of a user's list
permissions.
- `campaigns:manage_all` -> Manage all campaigns irrespective of a user's list
permissions.
- `campaigns:get` -> View only the campaigns that have at least one list to
which which a user has get or manage access.
- `campaigns:manage` -> Manage only the campaigns that have at list one list
to which a user has get or manage access.
In addition, this patch refactors and cleans up certain permission related
logic and functions.
- Filter lists by permitted list IDs in DB get calls.
- Split getLists() handlers into two (one, all) for clarity.
- Introduce new `subscribers:get_by_list` permission.
- Tweak UI rendering to work with new per-list permssions.
This is a long pending refactor. All the DB, query, CRUD, and related
logic scattered across HTTP handlers are now moved into a central
`core` package with clean, abstracted methods, decoupling HTTP
handlers from executing direct DB queries and other business logic.
eg: `core.CreateList()`, `core.GetLists()` etc.
- Remove obsolete subscriber methods.
- Move optin hook queries to core.
- Move campaign methods to `core`.
- Move all campaign methods to `core`.
- Move public page functions to `core`.
- Move all template functions to `core`.
- Move media and settings function to `core`.
- Move handler middleware functions to `core`.
- Move all bounce functions to `core`.
- Move all dashboard functions to `core`.
- Fix GetLists() not honouring type
- Fix unwrapped JSON responses.
- Clean up obsolete pre-core util function.
- Replace SQL array null check with cardinality check.
- Fix missing validations in `core` queries.
- Remove superfluous deps on internal `subimporter`.
- Add dashboard functions to `core`.
- Fix broken domain ban check.
- Fix broken subscriber check middleware.
- Remove redundant error handling.
- Remove obsolete functions.
- Remove obsolete structs.
- Remove obsolete queries and DB functions.
- Document the `core` package.
- Change `query-lists` query to aggregate the subscriber count by
status (confirmed, unsubscribed etc.) and expose them under a new
`subscriber_statuses: {}` field in the `GET /lists` API.
- Display the statuses and counts in the lists table on the UI.
Closes#616
- echo is now on v4 with major changes including a few breaking changes
- bind() behaviour is now strict. JSON / form etc. unmarshalling of
request data need appropriate `json`, `form` tags. Missing tags for
the public subscription page is added in this commit.
- This also closes#602.
Passing `?minimal=true` to the /lists API returns all lists without
additional metadata (subscriber count) which is orders of magnitude
faster than counting subscribers per list in large DBs.
The frontend intitialization always calls the GET /lists API on load
to keep it available in multiple contexts like the new campaign page.
However, this "boot up" call does not need additional metdata. This
initialization GET /lists call now calls /lists?minimal=true.
- Blocklist or unsubscribe subscribers based on a bounce threshold
- Add /bounces UI for viewing bounces and in the subscriber view
- Add settings UI for managing bounce settings
- Add support for scanning POP3 bounce mailboxes
- Add a generic webhook for posting custom bounces at /webhooks/bounce
- Add SES bounce webhook support at /webhooks/services/ses
- Add Sendgrid bounce webhook support at /webhooks/services/sendgrid
In addition to generating HTML forms for selected public lists,
the form page now shows a URL (/subscription/form) that can be
publicly shared to solicit subscriptions. The page lists all
public lists in the database. This page can be disabled on the
Settings UI.
Lists, campaigns, and subscribers tables now support server-side
sorting from the UI. This significantly changes the internal
queries from prepared to string interpolated to support dynamic
sort params.