Skip to content

Commit 31145b8

Browse files
authored
Merge branch 'knadh:master' into master
2 parents 28fa649 + d027cb5 commit 31145b8

File tree

20 files changed

+206
-117
lines changed

20 files changed

+206
-117
lines changed

cmd/subscribers.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,6 @@ func (a *App) BlocklistSubscribersByQuery(c echo.Context) error {
458458

459459
req.Search = strings.TrimSpace(req.Search)
460460
req.Query = formatSQLExp(req.Query)
461-
if req.Search == "" && req.Query == "" {
462-
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", "query"))
463-
}
464461

465462
// Does the user have the subscribers:sql_query permission?
466463
if req.Query != "" {
@@ -495,9 +492,6 @@ func (a *App) ManageSubscriberListsByQuery(c echo.Context) error {
495492

496493
req.Search = strings.TrimSpace(req.Search)
497494
req.Query = formatSQLExp(req.Query)
498-
if req.Search == "" && req.Query == "" {
499-
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", "query"))
500-
}
501495

502496
// Does the user have the subscribers:sql_query permission?
503497
if req.Query != "" {

cmd/templates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func (a *App) UpdateTemplate(c echo.Context) error {
157157
// Subject is only relevant for fixed tx templates. For campaigns,
158158
// the subject changes per campaign and is on models.Campaign.
159159
var funcs template.FuncMap
160-
if o.Type == models.TemplateTypeCampaign {
160+
if o.Type == models.TemplateTypeCampaign || o.Type == models.TemplateTypeCampaignVisual {
161161
o.Subject = ""
162162
funcs = a.manager.TemplateFuncs(nil)
163163
} else {

cmd/users.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
var (
16-
reUsername = regexp.MustCompile(`^[a-zA-Z0-9_\\-\\.]+$`)
16+
reUsername = regexp.MustCompile(`^[a-zA-Z0-9_\-\.@]+$`)
1717
)
1818

1919
// GetUser retrieves a single user by ID.
@@ -56,7 +56,7 @@ func (a *App) CreateUser(c echo.Context) error {
5656

5757
u.Username = strings.TrimSpace(u.Username)
5858
u.Name = strings.TrimSpace(u.Name)
59-
email := strings.TrimSpace(u.Email.String)
59+
email := strings.ToLower(strings.TrimSpace(u.Email.String))
6060

6161
// Validate fields.
6262
if !strHasLen(u.Username, 3, stdInputMaxLen) {
@@ -111,7 +111,7 @@ func (a *App) UpdateUser(c echo.Context) error {
111111

112112
u.Username = strings.TrimSpace(u.Username)
113113
u.Name = strings.TrimSpace(u.Name)
114-
email := strings.TrimSpace(u.Email.String)
114+
email := strings.ToLower(strings.TrimSpace(u.Email.String))
115115

116116
// Validate fields.
117117
if !strHasLen(u.Username, 3, stdInputMaxLen) {

docs/docs/content/oidc.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
## OIDC Single Sign On
3+
4+
Listmonk supports single sign-on with OIDC (OpenID Connect). Any standards compliant OIDC provider can be configured in Settings -> Security -> OIDC
5+
6+
!!! note "Automatic user creation"
7+
There is no support for automatic user creation via OIDC currently. The Super Admin must create users prior in Admin -> Users with the same e-mail address that is expected from the OIDC provider per user.
8+
9+
10+
# Tutorials
11+
12+
Tutorials for configuring listmonk SSO with popular OIDC providers.
13+
14+
## Keycloak
15+
Keycloak configuration for listmonk SSO integration.
16+
17+
### 1. Create a new client in Keycloak
18+
In the Keycloak admin, use an existing realm, or create a new realm. Create a new client in `Clients → Create`.
19+
20+
- **General Settings**
21+
- **Client type**: `OpenID Connect`
22+
- **Client ID**: `listmonk` (or any preferred name)
23+
- **Name**: Optional descriptive name (e.g., "listmonk SSO")
24+
- **Capability Config**:
25+
- **Client authentication**: On
26+
- **Authorization**: On
27+
- **Authentication Flow**
28+
- **Standard Flow**: On
29+
- **Direct Access grants**: On
30+
- **Login Settings**:
31+
- **Root URL**: Copy the **Redirect URL for oAuth provider** value from listmonk Admin -> Settings -> Security -> OIDC. It will look like `https://listmonk.yoursite.com/auth/oidc`
32+
- **Valid redirect URIs**: Same as the Root URL above
33+
- **Valid post logout redirect URIs**: *
34+
35+
After the client creation steps above, go to the client's `Credentials` tab and copy the `Client Secret`.
36+
37+
### 2. Configure Listmonk
38+
2. In Listmonk Admin -> Settings -> Security -> OIDC.
39+
- **Enable OIDC SSO**: Turn on
40+
- **Provider URL**: `https://keycloak.yoursite.com/auth/realms/{realm}` (replace `{realm}` with the chosen realm name)
41+
- **Provider name**: Set a name to show on the listmonk login form, eg: `Login with OrgName`
42+
- **Client ID**: Client ID set in Keycloak, eg: `listmonk`
43+
- **Client Secret**: Client Secret copied from Keycloak
44+
45+
46+
47+
## Authentik
48+
Authentik configuration for listmonk SSO integration.
49+
50+
### 1. Create a new OIDC provider in Authentik
51+
In the Authentik admin interface, create a new OIDC provider for listmonk.
52+
53+
- **Provider Settings**:
54+
- **Name**: `listmonk` (or any preferred name)
55+
- **Signing Key**: `authentik Self-signed Certificate`
56+
- **Client Type**: `Confidential`
57+
- **Client ID**: `listmonk` (or any preferred name)
58+
- **Redirect URIs**: Copy the **Redirect URL for oAuth provider** value from listmonk Admin -> Settings -> Security -> OIDC. It will look like `https://listmonk.yoursite.com/auth/oidc`
59+
60+
After creating the provider, copy the **Client Secret**.
61+
62+
### 2. Create an application in Authentik
63+
Create a new application and connect it to the newly created provider.
64+
65+
- **Application Settings**:
66+
- **Name**: `listmonk` (or any preferred name)
67+
- **Slug**: `listmonk` (or any preferred slug. Used in the redirect URL)
68+
- **Provider**: Select the OIDC provider created in the previous step
69+
70+
### 3. Configure listmonk
71+
In listmonk Admin → Settings → Security → OIDC:
72+
73+
- **Enable OIDC SSO**: Turn on
74+
- **Provider URL**: `https://authentik.yoursite.com/application/o/{slug}/` (replace `{slug}` with the application's slug)
75+
- **Provider Name**: Set a name to show on the login form (e.g., `Login with OrgName`)
76+
- **Client ID**: Client ID set in Authentik (e.g., `listmonk`)
77+
- **Client Secret**: Client Secret copied from Authentik

docs/docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ nav:
5454
- "Internationalization": "i18n.md"
5555
- "Integrating with external systems": external-integration.md
5656
- "User roles and permissions": roles-and-permissions.md
57+
- "OIDC SSO": oidc.md
5758
- "API":
5859
- "Introduction": apis/apis.md
5960
- "SDKs and libs": apis/sdks.md

docs/docs/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
mkdocs>=1.6.1
2+
mkdocs-material>=9.6.14
3+
mkdocs-material-extensions>=1.3.1
4+
pymdown-extensions>=10.15

docs/site/data/github.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"v5.0.0","date":"2025-04-28T19:00:04Z","url":"https://github.com/knadh/listmonk/releases/tag/v5.0.0","assets":[{"name":"darwin","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_darwin_amd64.tar.gz"},{"name":"freebsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_freebsd_amd64.tar.gz"},{"name":"linux","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_linux_amd64.tar.gz"},{"name":"netbsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_netbsd_amd64.tar.gz"},{"name":"openbsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_openbsd_amd64.tar.gz"},{"name":"windows","url":"https://github.com/knadh/listmonk/releases/download/v5.0.0/listmonk_5.0.0_windows_amd64.tar.gz"}]}
1+
{"version":"v5.0.1","date":"2025-05-25T09:59:32Z","url":"https://github.com/knadh/listmonk/releases/tag/v5.0.1","assets":[{"name":"darwin","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_darwin_amd64.tar.gz"},{"name":"freebsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_freebsd_amd64.tar.gz"},{"name":"linux","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_linux_amd64.tar.gz"},{"name":"netbsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_netbsd_amd64.tar.gz"},{"name":"openbsd","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_openbsd_amd64.tar.gz"},{"name":"windows","url":"https://github.com/knadh/listmonk/releases/download/v5.0.1/listmonk_5.0.1_windows_amd64.tar.gz"}]}

docs/site/layouts/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ <h3>Binary</h3>
5050

5151
<br />
5252
<h3>Hosting providers</h3>
53+
<a href="https://www.kloudbean.com/listmonk-self-hosted"><img src="https://storage-basic.kloudbean.com/opensource/deploy_on_kloudbean_listmonk.svg" alt="One-click deploy on Kloudbean" style="max-height: 32px;" /></a>
54+
<br />
5355
<a href="https://railway.app/new/template/listmonk"><img src="https://railway.app/button.svg" alt="One-click deploy on Railway" style="max-height: 32px;" /></a>
5456
<br />
5557
<a href="https://www.pikapods.com/pods?run=listmonk"><img src="https://www.pikapods.com/static/run-button.svg" alt="Deploy on PikaPod" /></a>

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"eslint-plugin-import": "^2.23.3",
5454
"eslint-plugin-vue": "^9.19.2",
5555
"sass": "^1.34.0",
56-
"vite": "^5.4.18",
56+
"vite": "^5.4.19",
5757
"vue-eslint-parser": "^9.3.2",
5858
"vue-template-compiler": "^2.6.12"
5959
},

frontend/src/components/Editor.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ export default {
318318
if (this.self.contentType === 'visual') {
319319
this.visualTemplateId = this.validTemplates[0]?.id || null;
320320
} else {
321+
if (this.templateId) {
322+
return;
323+
}
324+
321325
const defaultTemplate = this.validTemplates.find((t) => t.isDefault === true);
322326
this.templateId = defaultTemplate?.id || this.validTemplates[0]?.id || null;
323327
}

0 commit comments

Comments
 (0)