Commit graph

256 commits

Author SHA1 Message Date
Bowrna
42c74a8d93 fixing the PR by removing API added 2025-07-30 17:29:59 +05:30
Bowrna
db9b10d09a blocklist the bounces option 2025-07-28 15:09:08 +05:30
Vivek R
c9c678c04f
Add support for OIDC user auto-creation (#2578)
This patch adds 3 new options to OIDC settings.

Toggle user auto-creation, and select default user/list roles
for auto-created users.

Co-authored-by: Kailash Nadh <kailash@nadh.in>
2025-07-20 16:11:45 +05:30
Kailash Nadh
a424f01fc6 Print full line with error in the importer log. Close #2549. 2025-07-05 18:47:10 +05:30
Kailash Nadh
4f6880d38e Fix opt-in send errors silently ignored on signup form. Closes #2535. 2025-07-05 18:43:17 +05:30
Adam Howard
419f88a9c3
Fix incorrect line counts due to empty lines in CSV importer (#2542) 2025-06-30 16:15:51 +05:30
Kailash Nadh
d27d2c32cf Remove dangerous tpl funcs in Sprig that's enabled by default.
`env` and `expandenv` template functions in the Sprig library allow
accessing system environment variables within campaign templates.
2025-06-08 15:06:56 +05:30
Kailash Nadh
71ae2bbc09 Fix scheduled campaigns not finishing. Closes #2480. 2025-05-25 11:57:48 +05:30
Kailash Nadh
b04fe6b6b9 Fix bounces not being sorted by type field. Closes #2444. 2025-05-24 18:27:03 +05:30
Kailash Nadh
11f52ee8a3 Switch migration version to v5 2025-04-28 23:32:29 +05:30
Kailash Nadh
db81dc1dad Remove default dummy admin notification email settings. 2025-04-28 18:12:58 +05:30
Kailash Nadh
81b62a4aa9 Fix race condition in immediate campaign pause-start actions.
Pausing a campaign and starting it within the interval where campaign manager
pipe cleanup happens would cause a campaign to be marked as finished. This
patch addresses that by only doing the 'finished' state update if the campaign
wasn't stopped (cancel, pause) manually.

Potentially closes #2278 as this is the only reproducible scenario where a
campaign prematurely gets marked as finished.
2025-04-24 22:40:00 +05:30
Kailash Nadh
12bc79866f Make OIDC provider name display on login button configurable. Closes #2211 2025-04-23 00:09:24 +05:30
Kailash Nadh
53d79297ca Prepare first RC. 2025-04-20 20:48:51 +05:30
Kailash Nadh
ffbda019e4 Add sample visual campaign template on install and upgrade. 2025-04-20 20:48:51 +05:30
Kailash Nadh
20e4b100ca Fix DB state issues in visual campaign cloning. 2025-04-20 20:48:51 +05:30
Kailash Nadh
f1fbadf6a6 Fix incorrect template states in DB in campaign creation and broken preview. 2025-04-20 20:48:51 +05:30
Kailash Nadh
7786b18473 Add DB migrations for visual editor. 2025-04-20 20:48:51 +05:30
Kailash Nadh
c1f81cfadd Fix compatibility issues with master.
- Fix merge conflicts.
- Simply logic in campaign preview handler.
- Remove redundant `GetCampaignForPreviewWithTemplate()` and switch to the old
  query that optionally takes a template.
- Fix Vue linting issues.
2025-04-20 20:48:51 +05:30
Vivek R
ae98280858 feat: Integrate email-builder on campaign/template editor UI and backend. 2025-04-20 20:48:51 +05:30
Kailash Nadh
4b805f885b Fix broken subscribers:sql_query permission.
This permission was never checked for and had an unintended consequence of
allowing a non-superadmin user to execute arbitrary queries (expected), but
getting a superadmin session by joining the `sessions` table.

This patch:
- Introduces a table allowlist that uses the Postgres query plan (JSON)
  and validate the referenced tables against the allowed ones on arbitrary
  queries issued to the various `/subscribers` APIs.
- Explicitly adds the missing `subscribers:sql_query` permission check to all
  handlers that accept `query`.
- Introduces a new `search` parameter on all handlers that accept `query`.
  This parameter is an interface over the default name/email substring search
  instead of relying on `query`.
2025-04-18 14:15:47 +05:30
Kailash Nadh
562e52cd22 Introduce LISTMONK_ADMIN_API_USER to --install. Closes #2314, #2322.
- During install, listmonk now accepts the env `LISTMONK_ADMIN_API_USER`
  and creates an API user (with username $LISTMONK_ADMIN_API_USER)
  with full superadmin permissions. This requires LISTMONK_ADMIN_USER and
  LISTMONK_ADMIN_API_PASSWORD to be set so that that there's always a superadmin
  user to avoid bad states, mainly: bot superadmin exists, but no admin user
  exists, leaving the installation perpetually open with the superadmin user
  creation UI on the first login.
  The API user's token is printed to stderr in the following format:
  `export LISTMONK_ADMIN_API_TOKEN="7I81VSd90UWhKDj5Kq9c6YopToRduyDF"`
  This can be redirected to a file with ./listmonk 2> /tmp/token or captured
  directly and then source()'d.
- Add new function `core.GetRole(id)`.
- Fix `at least one super admin` query in user deletion.
2025-04-10 13:06:04 +05:30
Kailash Nadh
e2f24a140e Turn notifs into a special stateful global singleton package, removing clunky deps. 2025-04-05 22:45:19 +05:30
Kailash Nadh
b3d46a8c85 Refactor system notification callbacks into a new notifs package. 2025-04-05 19:07:06 +05:30
Kailash Nadh
007f4de850 Fix a number of cosmetic inconsistenies across handlers and functions.
- Make the beginning of handlers consistent with uniform variable declaration
  and grouping.
- Add missing comments.
- Fix staticcheck/vet warnings and idiom issues.
2025-04-05 13:41:31 +05:30
Kailash Nadh
fcf2449a70 Replace awkward auth user object access in handlers with an explicit func. 2025-04-05 00:26:05 +05:30
Kailash Nadh
17998fbff5 Refactor user auth models and permission checks.
- 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.
2025-04-05 00:19:27 +05:30
Kailash Nadh
a271bf54d5 Introduce per-campaign filter permissions. Closes #2325.
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.
2025-03-31 16:39:42 +05:30
Kailash Nadh
a5f8b28cb1 Fix inconsistent behaviour in campaign scheduling on the UI.
- Fix status/button state management issues when `Send at` was toggled
  under various scenarios.
- Allow paused campaigns to be edited and turned into scheduled campaigns.
- Add Cypress UI tests for unscheduling.
2025-03-31 13:00:51 +05:30
Kailash Nadh
b8f50eafa3 Add support for domain allowlists in addition to blocklists. Closes #2230.
This patch introduces a new `Domain allowlist` input in Settings -> Privacy UI
as a new tab alongside domain `Domain blocklist`. If any domains are entered
here, then only subscriptions/imports/additions of e-mails from those particular
domains are accepted. blocklist is mutually exclusive with allowlist when there
are values in the allowlist.
2025-03-29 23:31:34 +05:30
Kailash Nadh
6efb6e7600 Upgrade smtppool to v2 and add support for concrete SSL options. 2025-03-29 17:05:03 +05:30
Kailash Nadh
e4a18dabc3 Remove forcing unique filename on all media uploads.
This patch removes the forced suffixing of all media upload filenames with
random strings. The upload handler now checks the `media` table to ensure that
the filename being uploaded doesn't exist before forcing a suffix.

Outright rejecting duplicate filenames cannot be done to maintain backwards
compatibility with the old behaviour.

Closes #2277.
2025-03-29 15:21:32 +05:30
Kailash Nadh
0be7a79dac Fix broken log rendering on importer UI. 2025-03-29 13:10:46 +05:30
Kailash Nadh
a9869612dc Disallow private list UUIDs on public sub endpoints. Closes #2296. 2025-03-12 22:00:35 +05:30
lcd1232
d055cc5311
Add support for selecting SMTP per campaign (#2290)
This patch adds a new optional `name` field to SMTP server config on the UI.
When a name is given to an SMTP server, it's initialized as a standalone messenger
which shows up as a sub-group item under the main "email" messenger
on the campaign page.

Co-authored-by: Kailash Nadh <kailash@nadh.in>
2025-02-11 22:41:45 +05:30
Kailash Nadh
61c6b7e15a Add explicit Unschedule button on campaign UI. 2025-01-19 16:27:39 +05:30
Kailash Nadh
fd31ac6f58 Remove redundant send_later param in campaign POST/PUT. 2025-01-19 16:06:39 +05:30
Shaun Warman
a5e56c3446
fix: forwardemail bounce processing invalid signature issue (#2250) 2025-01-10 10:40:21 +05:30
ANU MADHAV
2abc0a8651
Apply minor Go code fixes (#2219)
- replace deprecated 'strings.Title' with 'cases.Title'
- remove unreachable return and fix syntax issue
2024-12-25 19:57:14 +05:30
Kailash Nadh
97fde64461 Make CSV (import) header fields agnostic of surrounding spaces. Closes #2189. 2024-12-04 23:11:51 +05:30
Kailash Nadh
63712285aa Fix schema and add migration for incorrect subscriber count (null) in materialized view. 2024-12-04 23:06:49 +05:30
Kailash Nadh
5c0de6ef0b Fix broken sorting lists by subscriber_count. Closes #2151. 2024-12-04 22:40:13 +05:30
Kailash Nadh
894d284309 Fix GET subscribers not filtering by list permissions. Closes #2129. 2024-11-12 22:59:33 +05:30
Kailash Nadh
18edc653a8 Add v4.1.0 migrations. 2024-11-11 16:11:56 +05:30
Shaun Warman
cb8b54fd00
Add ForwardEmail (provider) bounce integration (#2016)
* Add ForwardEmail one-click SMTP form option.
* Add bounce webhook integration.

---------

Co-authored-by: Kailash Nadh <kailash@nadh.in>
2024-11-10 21:45:07 +05:30
Kailash Nadh
b8ae4f6f9e Change v4.0.0 migration script to not auto-generate credentials. 2024-10-27 17:18:28 +05:30
Kailash Nadh
1e4b3a26f2 Separate get individual user and get all users queries. 2024-10-26 17:03:02 +05:30
Kailash Nadh
25cdb7b18e Pull e-mail from userinfo endpoint if OIDC token endpoint doesn't return it. 2024-10-23 15:09:05 +05:30
Kailash Nadh
8c07a2a1c4 Fix broken status in subscriber export query. 2024-10-20 23:50:06 +05:30
Kailash Nadh
cea65c009d Fix and refactor subscriber batch fetching in campaign processing.
This has been a hair-pulling rabbit hole of an issue. #1931 and others.
When the `next-campaign-subscribers` query that fetches $n subscribers
per batch for a campaign returns no results, the manager assumes
that the campaign is done and marks as finished.

Marathon debugging revealed fundamental flaws in qyery's logic that
would incorrectly return 0 rows under certain conditions.
- Based on the "layout" of subscribers for eg: a series of blocklisted
  subscribers between confirmed subscribers.
  A series of unconfirmed subscribers in a batch belonging to a double
  opt-in list.
- Bulk import blocklisting users, but not marking their subscriptions
  as 'unsubscribed'.
- Conditions spread across multiple CTEs resulted in returning an
  arbitrary number of rows and $N per batch as the selected $N rows
  would get filtered out elsewhere, possibly even becoming 0.

After fixing this and testing it on our prod instance that has
15 million subscribers and ~70 million subscriptions in the
`subscriber_lists` table, ended up discovered significant inefficiences
in Postgres query planning. When `subscriber_lists` and campaign list IDs
are joined dynamically (CTE or ANY() or any kind of JOIN that involves)
a query, the Postgres query planner is unable to use the right indexes.

After testing dozens of approaches, discovered that statically passing
the values to join on (hardcoding or passing via parametrized $1 vars),
the query uses the right indexes. The difference is staggering.
For the particular scenario on our large prod DB to pull a batch,
~15 seconds vs. ~50ms, a whopping 300x improvement!

This patch splits `next-campaign-subscribers` into two separate queries,
one which fetches campaign metadata and list_ids, whose values are then
passed statically to the next query to fetch subscribers by batch.

In addition, it fixes and refactors broken filtering and counting logic
in `create-campaign` and `next-campaign` queries.

Closes #1931, #1993, #1986.
2024-10-13 17:03:59 +05:30