forked from pocketbase/pocketbase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[pocketbase#75] added option to test s3 connection and send test emails
- Loading branch information
1 parent
3f4f4cf
commit 587cfc3
Showing
49 changed files
with
1,539 additions
and
838 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import ( | |
"strings" | ||
"testing" | ||
|
||
"github.com/labstack/echo/v5" | ||
"github.com/pocketbase/pocketbase/tests" | ||
) | ||
|
||
|
@@ -183,3 +184,192 @@ func TestSettingsSet(t *testing.T) { | |
scenario.Test(t) | ||
} | ||
} | ||
|
||
func TestSettingsTestS3(t *testing.T) { | ||
scenarios := []tests.ApiScenario{ | ||
{ | ||
Name: "unauthorized", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/s3", | ||
ExpectedStatus: 401, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
{ | ||
Name: "authorized as user", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/s3", | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "User eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRkMDE5N2NjLTJiNGEtM2Y4My1hMjZiLWQ3N2JjODQyM2QzYyIsInR5cGUiOiJ1c2VyIiwiZXhwIjoxODkzNDc0MDAwfQ.Wq5ac1q1f5WntIzEngXk22ydMj-eFgvfSRg7dhmPKic", | ||
}, | ||
ExpectedStatus: 401, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
{ | ||
Name: "authorized as admin (no s3)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/s3", | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
ExpectedStatus: 400, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
// @todo consider creating a test S3 filesystem | ||
} | ||
|
||
for _, scenario := range scenarios { | ||
scenario.Test(t) | ||
} | ||
} | ||
|
||
func TestSettingsTestEmail(t *testing.T) { | ||
scenarios := []tests.ApiScenario{ | ||
{ | ||
Name: "unauthorized", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{ | ||
"template": "verification", | ||
"email": "[email protected]" | ||
}`), | ||
ExpectedStatus: 401, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
{ | ||
Name: "authorized as user", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{ | ||
"template": "verification", | ||
"email": "[email protected]" | ||
}`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "User eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjRkMDE5N2NjLTJiNGEtM2Y4My1hMjZiLWQ3N2JjODQyM2QzYyIsInR5cGUiOiJ1c2VyIiwiZXhwIjoxODkzNDc0MDAwfQ.Wq5ac1q1f5WntIzEngXk22ydMj-eFgvfSRg7dhmPKic", | ||
}, | ||
ExpectedStatus: 401, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
{ | ||
Name: "authorized as admin (invalid body)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
ExpectedStatus: 400, | ||
ExpectedContent: []string{`"data":{}`}, | ||
}, | ||
{ | ||
Name: "authorized as admin (empty json)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{}`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
ExpectedStatus: 400, | ||
ExpectedContent: []string{ | ||
`"email":{"code":"validation_required"`, | ||
`"template":{"code":"validation_required"`, | ||
}, | ||
}, | ||
{ | ||
Name: "authorized as admin (verifiation template)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{ | ||
"template": "verification", | ||
"email": "[email protected]" | ||
}`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
AfterFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { | ||
if app.TestMailer.TotalSend != 1 { | ||
t.Fatalf("[verification] Expected 1 sent email, got %d", app.TestMailer.TotalSend) | ||
} | ||
|
||
if app.TestMailer.LastToAddress.Address != "[email protected]" { | ||
t.Fatalf("[verification] Expected the email to be sent to %s, got %s", "[email protected]", app.TestMailer.LastToAddress.Address) | ||
} | ||
|
||
if !strings.Contains(app.TestMailer.LastHtmlBody, "Verify") { | ||
t.Fatalf("[verification] Expected to sent a verification email, got \n%v\n%v", app.TestMailer.LastHtmlSubject, app.TestMailer.LastHtmlBody) | ||
} | ||
}, | ||
ExpectedStatus: 204, | ||
ExpectedContent: []string{}, | ||
ExpectedEvents: map[string]int{ | ||
"OnMailerBeforeUserVerificationSend": 1, | ||
"OnMailerAfterUserVerificationSend": 1, | ||
}, | ||
}, | ||
{ | ||
Name: "authorized as admin (password reset template)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{ | ||
"template": "password-reset", | ||
"email": "[email protected]" | ||
}`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
AfterFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { | ||
if app.TestMailer.TotalSend != 1 { | ||
t.Fatalf("[password-reset] Expected 1 sent email, got %d", app.TestMailer.TotalSend) | ||
} | ||
|
||
if app.TestMailer.LastToAddress.Address != "[email protected]" { | ||
t.Fatalf("[password-reset] Expected the email to be sent to %s, got %s", "[email protected]", app.TestMailer.LastToAddress.Address) | ||
} | ||
|
||
if !strings.Contains(app.TestMailer.LastHtmlBody, "Reset password") { | ||
t.Fatalf("[password-reset] Expected to sent a password-reset email, got \n%v\n%v", app.TestMailer.LastHtmlSubject, app.TestMailer.LastHtmlBody) | ||
} | ||
}, | ||
ExpectedStatus: 204, | ||
ExpectedContent: []string{}, | ||
ExpectedEvents: map[string]int{ | ||
"OnMailerBeforeUserResetPasswordSend": 1, | ||
"OnMailerAfterUserResetPasswordSend": 1, | ||
}, | ||
}, | ||
{ | ||
Name: "authorized as admin (email change)", | ||
Method: http.MethodPost, | ||
Url: "/api/settings/test/email", | ||
Body: strings.NewReader(`{ | ||
"template": "email-change", | ||
"email": "[email protected]" | ||
}`), | ||
RequestHeaders: map[string]string{ | ||
"Authorization": "Admin eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjJiNGE5N2NjLTNmODMtNGQwMS1hMjZiLTNkNzdiYzg0MmQzYyIsInR5cGUiOiJhZG1pbiIsImV4cCI6MTg3MzQ2Mjc5Mn0.AtRtXR6FHBrCUGkj5OffhmxLbSZaQ4L_Qgw4gfoHyfo", | ||
}, | ||
AfterFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) { | ||
if app.TestMailer.TotalSend != 1 { | ||
t.Fatalf("[email-change] Expected 1 sent email, got %d", app.TestMailer.TotalSend) | ||
} | ||
|
||
if app.TestMailer.LastToAddress.Address != "[email protected]" { | ||
t.Fatalf("[email-change] Expected the email to be sent to %s, got %s", "[email protected]", app.TestMailer.LastToAddress.Address) | ||
} | ||
|
||
if !strings.Contains(app.TestMailer.LastHtmlBody, "Confirm new email") { | ||
t.Fatalf("[email-change] Expected to sent a confirm new email email, got \n%v\n%v", app.TestMailer.LastHtmlSubject, app.TestMailer.LastHtmlBody) | ||
} | ||
}, | ||
ExpectedStatus: 204, | ||
ExpectedContent: []string{}, | ||
ExpectedEvents: map[string]int{ | ||
"OnMailerBeforeUserChangeEmailSend": 1, | ||
"OnMailerAfterUserChangeEmailSend": 1, | ||
}, | ||
}, | ||
} | ||
|
||
for _, scenario := range scenarios { | ||
scenario.Test(t) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package forms | ||
|
||
import ( | ||
validation "github.com/go-ozzo/ozzo-validation/v4" | ||
"github.com/go-ozzo/ozzo-validation/v4/is" | ||
"github.com/pocketbase/pocketbase/core" | ||
"github.com/pocketbase/pocketbase/mails" | ||
"github.com/pocketbase/pocketbase/models" | ||
) | ||
|
||
const ( | ||
templateVerification = "verification" | ||
templatePasswordReset = "password-reset" | ||
templateEmailChange = "email-change" | ||
) | ||
|
||
// TestEmailSend is a email template test request form. | ||
type TestEmailSend struct { | ||
app core.App | ||
|
||
Template string `form:"template" json:"template"` | ||
Email string `form:"email" json:"email"` | ||
} | ||
|
||
// NewTestEmailSend creates and initializes new TestEmailSend form. | ||
func NewTestEmailSend(app core.App) *TestEmailSend { | ||
return &TestEmailSend{app: app} | ||
} | ||
|
||
// Validate makes the form validatable by implementing [validation.Validatable] interface. | ||
func (form *TestEmailSend) Validate() error { | ||
return validation.ValidateStruct(form, | ||
validation.Field( | ||
&form.Email, | ||
validation.Required, | ||
validation.Length(1, 255), | ||
is.Email, | ||
), | ||
validation.Field( | ||
&form.Template, | ||
validation.Required, | ||
validation.In(templateVerification, templateEmailChange, templatePasswordReset), | ||
), | ||
) | ||
} | ||
|
||
// Submit validates and sends a test email to the form.Email address. | ||
func (form *TestEmailSend) Submit() error { | ||
if err := form.Validate(); err != nil { | ||
return err | ||
} | ||
|
||
// create a test user | ||
user := &models.User{} | ||
user.Id = "__pb_test_id__" | ||
user.Email = form.Email | ||
user.RefreshTokenKey() | ||
|
||
switch form.Template { | ||
case templateVerification: | ||
return mails.SendUserVerification(form.app, user) | ||
case templatePasswordReset: | ||
return mails.SendUserPasswordReset(form.app, user) | ||
case templateEmailChange: | ||
return mails.SendUserChangeEmail(form.app, user, form.Email) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.