[#75] added option to test s3 connection and send test emails
This commit is contained in:
parent
3f4f4cf031
commit
587cfc335c
|
@ -3,10 +3,12 @@ package apis
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
"github.com/labstack/echo/v5"
|
"github.com/labstack/echo/v5"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/forms"
|
"github.com/pocketbase/pocketbase/forms"
|
||||||
"github.com/pocketbase/pocketbase/tools/rest"
|
"github.com/pocketbase/pocketbase/tools/rest"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BindSettingsApi registers the settings api endpoints.
|
// BindSettingsApi registers the settings api endpoints.
|
||||||
|
@ -16,6 +18,8 @@ func BindSettingsApi(app core.App, rg *echo.Group) {
|
||||||
subGroup := rg.Group("/settings", ActivityLogger(app), RequireAdminAuth())
|
subGroup := rg.Group("/settings", ActivityLogger(app), RequireAdminAuth())
|
||||||
subGroup.GET("", api.list)
|
subGroup.GET("", api.list)
|
||||||
subGroup.PATCH("", api.set)
|
subGroup.PATCH("", api.set)
|
||||||
|
subGroup.POST("/test/s3", api.testS3)
|
||||||
|
subGroup.POST("/test/email", api.testEmail)
|
||||||
}
|
}
|
||||||
|
|
||||||
type settingsApi struct {
|
type settingsApi struct {
|
||||||
|
@ -43,7 +47,7 @@ func (api *settingsApi) set(c echo.Context) error {
|
||||||
|
|
||||||
// load request
|
// load request
|
||||||
if err := c.Bind(form); err != nil {
|
if err := c.Bind(form); err != nil {
|
||||||
return rest.NewBadRequestError("An error occurred while reading the submitted data.", err)
|
return rest.NewBadRequestError("An error occurred while loading the submitted data.", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
event := &core.SettingsUpdateEvent{
|
event := &core.SettingsUpdateEvent{
|
||||||
|
@ -76,3 +80,49 @@ func (api *settingsApi) set(c echo.Context) error {
|
||||||
|
|
||||||
return submitErr
|
return submitErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *settingsApi) testS3(c echo.Context) error {
|
||||||
|
if !api.app.Settings().S3.Enabled {
|
||||||
|
return rest.NewBadRequestError("S3 storage is not enabled.", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := api.app.NewFilesystem()
|
||||||
|
if err != nil {
|
||||||
|
return rest.NewBadRequestError("Failed to initialize the S3 storage. Raw error: \n"+err.Error(), nil)
|
||||||
|
}
|
||||||
|
defer fs.Close()
|
||||||
|
|
||||||
|
testFileKey := "pb_test_" + security.RandomString(5) + "/test.txt"
|
||||||
|
|
||||||
|
if err := fs.Upload([]byte("test"), testFileKey); err != nil {
|
||||||
|
return rest.NewBadRequestError("Failed to upload a test file. Raw error: \n"+err.Error(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fs.Delete(testFileKey); err != nil {
|
||||||
|
return rest.NewBadRequestError("Failed to delete a test file. Raw error: \n"+err.Error(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.NoContent(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *settingsApi) testEmail(c echo.Context) error {
|
||||||
|
form := forms.NewTestEmailSend(api.app)
|
||||||
|
|
||||||
|
// load request
|
||||||
|
if err := c.Bind(form); err != nil {
|
||||||
|
return rest.NewBadRequestError("An error occurred while loading the submitted data.", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send
|
||||||
|
if err := form.Submit(); err != nil {
|
||||||
|
if fErr, ok := err.(validation.Errors); ok {
|
||||||
|
// form error
|
||||||
|
return rest.NewBadRequestError("Failed to send the test email.", fErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mailer error
|
||||||
|
return rest.NewBadRequestError("Failed to send the test email. Raw error: \n"+err.Error(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.NoContent(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v5"
|
||||||
"github.com/pocketbase/pocketbase/tests"
|
"github.com/pocketbase/pocketbase/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -183,3 +184,192 @@ func TestSettingsSet(t *testing.T) {
|
||||||
scenario.Test(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": "test@example.com"
|
||||||
|
}`),
|
||||||
|
ExpectedStatus: 401,
|
||||||
|
ExpectedContent: []string{`"data":{}`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "authorized as user",
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Url: "/api/settings/test/email",
|
||||||
|
Body: strings.NewReader(`{
|
||||||
|
"template": "verification",
|
||||||
|
"email": "test@example.com"
|
||||||
|
}`),
|
||||||
|
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": "test@example.com"
|
||||||
|
}`),
|
||||||
|
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 != "test@example.com" {
|
||||||
|
t.Fatalf("[verification] Expected the email to be sent to %s, got %s", "test@example.com", 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": "test@example.com"
|
||||||
|
}`),
|
||||||
|
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 != "test@example.com" {
|
||||||
|
t.Fatalf("[password-reset] Expected the email to be sent to %s, got %s", "test@example.com", 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": "test@example.com"
|
||||||
|
}`),
|
||||||
|
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 != "test@example.com" {
|
||||||
|
t.Fatalf("[email-change] Expected the email to be sent to %s, got %s", "test@example.com", 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RealtimeSubscribe specifies a RealtimeSubscribe request form.
|
// RealtimeSubscribe is a realtime subscriptions request form.
|
||||||
type RealtimeSubscribe struct {
|
type RealtimeSubscribe struct {
|
||||||
ClientId string `form:"clientId" json:"clientId"`
|
ClientId string `form:"clientId" json:"clientId"`
|
||||||
Subscriptions []string `form:"subscriptions" json:"subscriptions"`
|
Subscriptions []string `form:"subscriptions" json:"subscriptions"`
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package forms_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
|
"github.com/pocketbase/pocketbase/forms"
|
||||||
|
"github.com/pocketbase/pocketbase/tests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEmailSendValidate(t *testing.T) {
|
||||||
|
app, _ := tests.NewTestApp()
|
||||||
|
defer app.Cleanup()
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
template string
|
||||||
|
email string
|
||||||
|
expectedErrors []string
|
||||||
|
}{
|
||||||
|
{"", "", []string{"template", "email"}},
|
||||||
|
{"invalid", "test@example.com", []string{"template"}},
|
||||||
|
{"verification", "invalid", []string{"email"}},
|
||||||
|
{"verification", "test@example.com", nil},
|
||||||
|
{"password-reset", "test@example.com", nil},
|
||||||
|
{"email-change", "test@example.com", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
form := forms.NewTestEmailSend(app)
|
||||||
|
form.Email = s.email
|
||||||
|
form.Template = s.template
|
||||||
|
|
||||||
|
result := form.Validate()
|
||||||
|
|
||||||
|
// parse errors
|
||||||
|
errs, ok := result.(validation.Errors)
|
||||||
|
if !ok && result != nil {
|
||||||
|
t.Errorf("(%d) Failed to parse errors %v", i, result)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check errors
|
||||||
|
if len(errs) > len(s.expectedErrors) {
|
||||||
|
t.Errorf("(%d) Expected error keys %v, got %v", i, s.expectedErrors, errs)
|
||||||
|
}
|
||||||
|
for _, k := range s.expectedErrors {
|
||||||
|
if _, ok := errs[k]; !ok {
|
||||||
|
t.Errorf("(%d) Missing expected error key %q in %v", i, k, errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmailSendSubmit(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
template string
|
||||||
|
email string
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{"", "", true},
|
||||||
|
{"invalid", "test@example.com", true},
|
||||||
|
{"verification", "invalid", true},
|
||||||
|
{"verification", "test@example.com", false},
|
||||||
|
{"password-reset", "test@example.com", false},
|
||||||
|
{"email-change", "test@example.com", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
app, _ := tests.NewTestApp()
|
||||||
|
defer app.Cleanup()
|
||||||
|
|
||||||
|
form := forms.NewTestEmailSend(app)
|
||||||
|
form.Email = s.email
|
||||||
|
form.Template = s.template
|
||||||
|
|
||||||
|
err := form.Submit()
|
||||||
|
|
||||||
|
hasErr := err != nil
|
||||||
|
if hasErr != s.expectError {
|
||||||
|
t.Errorf("(%d) Expected hasErr to be %v, got %v (%v)", i, s.expectError, hasErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasErr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if app.TestMailer.TotalSend != 1 {
|
||||||
|
t.Errorf("(%d) Expected one email to be sent, got %d", i, app.TestMailer.TotalSend)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedContent := "Verify"
|
||||||
|
if s.template == "password-reset" {
|
||||||
|
expectedContent = "Reset password"
|
||||||
|
} else if s.template == "email-change" {
|
||||||
|
expectedContent = "Confirm new email"
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(app.TestMailer.LastHtmlBody, expectedContent) {
|
||||||
|
t.Errorf("(%d) Expected the email to contains %s, got \n%v", i, expectedContent, app.TestMailer.LastHtmlBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
go.mod
26
go.mod
|
@ -4,20 +4,20 @@ go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.5
|
github.com/AlecAivazis/survey/v2 v2.3.5
|
||||||
github.com/aws/aws-sdk-go v1.44.76
|
github.com/aws/aws-sdk-go v1.44.81
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/domodwyer/mailyak/v3 v3.3.3
|
github.com/domodwyer/mailyak/v3 v3.3.4
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.13.0
|
||||||
github.com/ganigeorgiev/fexpr v0.1.1
|
github.com/ganigeorgiev/fexpr v0.1.1
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||||
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
|
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
|
||||||
github.com/mattn/go-sqlite3 v1.14.14
|
github.com/mattn/go-sqlite3 v1.14.15
|
||||||
github.com/pocketbase/dbx v1.6.0
|
github.com/pocketbase/dbx v1.6.0
|
||||||
github.com/spf13/cast v1.5.0
|
github.com/spf13/cast v1.5.0
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.5.0
|
||||||
gocloud.dev v0.26.0
|
gocloud.dev v0.26.0
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
|
||||||
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7
|
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7
|
||||||
modernc.org/sqlite v1.18.1
|
modernc.org/sqlite v1.18.1
|
||||||
)
|
)
|
||||||
|
@ -26,10 +26,10 @@ require (
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.11 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.16.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.16.1 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.17.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.13 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // indirect
|
||||||
|
@ -39,7 +39,7 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
|
||||||
github.com/aws/smithy-go v1.12.1 // indirect
|
github.com/aws/smithy-go v1.12.1 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
@ -50,8 +50,8 @@ require (
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
@ -61,15 +61,15 @@ require (
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect
|
||||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||||
google.golang.org/api v0.92.0 // indirect
|
google.golang.org/api v0.93.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424 // indirect
|
google.golang.org/genproto v0.0.0-20220819174105-e9f053255caa // indirect
|
||||||
google.golang.org/grpc v1.48.0 // indirect
|
google.golang.org/grpc v1.48.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.1 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
|
|
51
go.sum
51
go.sum
|
@ -122,8 +122,8 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W
|
||||||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||||
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/aws/aws-sdk-go v1.44.76 h1:5e8yGO/XeNYKckOjpBKUd5wStf0So3CrQIiOMCVLpOI=
|
github.com/aws/aws-sdk-go v1.44.81 h1:C8oBZ+a+ka0qk3Q24MohQIFq0tkbO8IAu5tfpAMKVWE=
|
||||||
github.com/aws/aws-sdk-go v1.44.76/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.44.81/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.11 h1:xM1ZPSvty3xVmdxiGr7ay/wlqv+MWhH0rMlyLdbC0YQ=
|
github.com/aws/aws-sdk-go-v2 v1.16.11 h1:xM1ZPSvty3xVmdxiGr7ay/wlqv+MWhH0rMlyLdbC0YQ=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.11/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo=
|
github.com/aws/aws-sdk-go-v2 v1.16.11/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo=
|
||||||
|
@ -131,17 +131,17 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 h1:zfT11pa7ifu/VlLDpmc5OY2W4nYmnKkFDGeMVnmqAI0=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 h1:zfT11pa7ifu/VlLDpmc5OY2W4nYmnKkFDGeMVnmqAI0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4/go.mod h1:ES0I1GBs+YYgcDS1ek47Erbn4TOL811JKqBXtgzqyZ8=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4/go.mod h1:ES0I1GBs+YYgcDS1ek47Erbn4TOL811JKqBXtgzqyZ8=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
|
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.16.1 h1:jasqFPOoNPXHOYGEEuvyT87ACiXhD3OkQckIm5uqi5I=
|
github.com/aws/aws-sdk-go-v2/config v1.17.1 h1:BWxTjokU/69BZ4DnLrZco6OvBDii6ToEdfBL/y5I1nA=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.16.1/go.mod h1:4SKzBMiB8lV0fw2w7eDBo/LjQyHFITN4vUUuqpurFmI=
|
github.com/aws/aws-sdk-go-v2/config v1.17.1/go.mod h1:uOxDHjBemNTF2Zos+fgG0NNfE86wn1OAHDTGxjMEYi0=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
|
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.13 h1:cuPzIsjKAWBUAAk8ZUR2l02Sxafl9hiaMsc7tlnjwAY=
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.14 h1:AtVG/amkjbDBfnPr/tuW2IG18HGNznP6L12Dx0rLz+Q=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.13/go.mod h1:9fDEemXizwXrxPU1MTzv69LP/9D8HVl5qHAQO9A9ikY=
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.14/go.mod h1:opAndTyq+YN7IpVG57z2CeNuXSQMqTYxGGlYH0m0RMY=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 h1:wgJBHO58Pc1V1QAnzdVM3JK3WbE/6eUF0JxCZ+/izz0=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 h1:wgJBHO58Pc1V1QAnzdVM3JK3WbE/6eUF0JxCZ+/izz0=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12/go.mod h1:aZ4vZnyUuxedC7eD4JyEHpGnCz+O2sHQEx3VvAwklSE=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12/go.mod h1:aZ4vZnyUuxedC7eD4JyEHpGnCz+O2sHQEx3VvAwklSE=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25 h1:ShUxLkMxarXylGxfYwg8p+xEKY+C1y54oUU3wFsUMFo=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27 h1:xFXIMBci0UXStoOHq/8w0XIZPB2hgb9CD7uATJhqt10=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25/go.mod h1:cam5wV1ebd3ZVuh2r2CA8FtSAA/eUMtRH4owk0ygfFs=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.27/go.mod h1:+tj2cHQkChanggNZn1J2fJ1Cv6RO1TV0AA3472do31I=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 h1:OmiwoVyLKEqqD5GvB683dbSqxiOfvx4U2lDZhG2Esc4=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 h1:OmiwoVyLKEqqD5GvB683dbSqxiOfvx4U2lDZhG2Esc4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18/go.mod h1:348MLhzV1GSlZSMusdwQpXKbhD7X2gbI/TxwAPKkYZQ=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18/go.mod h1:348MLhzV1GSlZSMusdwQpXKbhD7X2gbI/TxwAPKkYZQ=
|
||||||
|
@ -174,8 +174,8 @@ github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZP
|
||||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
|
github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16 h1:YK8L7TNlGwMWHYqLs+i6dlITpxqzq08FqQUy26nm+T8=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17 h1:pXxu9u2z1UqSbjO9YA8kmFJBhFc1EVTDaf7A+S+Ivq8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16/go.mod h1:mS5xqLZc/6kc06IpXn5vRxdLaED+jEuaSRv5BxtnsiY=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.17/go.mod h1:mS5xqLZc/6kc06IpXn5vRxdLaED+jEuaSRv5BxtnsiY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 h1:dl8T0PJlN92rvEGOEUiD0+YPYdPEaCZK0TqHukvSfII=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 h1:dl8T0PJlN92rvEGOEUiD0+YPYdPEaCZK0TqHukvSfII=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13/go.mod h1:Ru3QVMLygVs/07UQ3YDur1AQZZp2tUNje8wfloFttC0=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13/go.mod h1:Ru3QVMLygVs/07UQ3YDur1AQZZp2tUNje8wfloFttC0=
|
||||||
|
@ -218,8 +218,8 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
|
||||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
github.com/domodwyer/mailyak/v3 v3.3.3 h1:E9cjqDUiwY1QSE5G2CbWHM7EJV5FybKPHnGovc2iaA8=
|
github.com/domodwyer/mailyak/v3 v3.3.4 h1:AG/pvcz2/ocFqZkPEG7lPAa0MhCq1warfUEKJt6Fagk=
|
||||||
github.com/domodwyer/mailyak/v3 v3.3.3/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
github.com/domodwyer/mailyak/v3 v3.3.4/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
@ -460,18 +460,19 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
||||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
|
@ -576,8 +577,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -763,7 +764,6 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -783,8 +783,9 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U=
|
||||||
|
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||||
|
@ -924,8 +925,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
|
||||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||||
google.golang.org/api v0.92.0 h1:8JHk7q/+rJla+iRsWj9FQ9/wjv2M1SKtpKSdmLhxPT0=
|
google.golang.org/api v0.93.0 h1:T2xt9gi0gHdxdnRkVQhT8mIvPaXKNsDNWz+L696M66M=
|
||||||
google.golang.org/api v0.92.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
@ -1028,8 +1029,8 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
|
||||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424 h1:zZnTt15U44/Txe/9cN/tVbteBkPMiyXK48hPsKRmqj4=
|
google.golang.org/genproto v0.0.0-20220819174105-e9f053255caa h1:Ux9yJCyf598uEniFPSyp8g1jtGTt77m+lzYyVgrWQaQ=
|
||||||
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
google.golang.org/genproto v0.0.0-20220819174105-e9f053255caa/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
|
|
@ -12,17 +12,26 @@ var _ mailer.Mailer = (*TestMailer)(nil)
|
||||||
// TestMailer is a mock `mailer.Mailer` implementation.
|
// TestMailer is a mock `mailer.Mailer` implementation.
|
||||||
type TestMailer struct {
|
type TestMailer struct {
|
||||||
TotalSend int
|
TotalSend int
|
||||||
|
LastFromAddress mail.Address
|
||||||
|
LastToAddress mail.Address
|
||||||
|
LastHtmlSubject string
|
||||||
LastHtmlBody string
|
LastHtmlBody string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears any previously test collected data.
|
// Reset clears any previously test collected data.
|
||||||
func (m *TestMailer) Reset() {
|
func (m *TestMailer) Reset() {
|
||||||
m.LastHtmlBody = ""
|
|
||||||
m.TotalSend = 0
|
m.TotalSend = 0
|
||||||
|
m.LastFromAddress = mail.Address{}
|
||||||
|
m.LastToAddress = mail.Address{}
|
||||||
|
m.LastHtmlSubject = ""
|
||||||
|
m.LastHtmlBody = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send implements `mailer.Mailer` interface.
|
// Send implements `mailer.Mailer` interface.
|
||||||
func (m *TestMailer) Send(fromEmail mail.Address, toEmail mail.Address, subject string, html string, attachments map[string]io.Reader) error {
|
func (m *TestMailer) Send(fromEmail mail.Address, toEmail mail.Address, subject string, html string, attachments map[string]io.Reader) error {
|
||||||
|
m.LastFromAddress = fromEmail
|
||||||
|
m.LastToAddress = toEmail
|
||||||
|
m.LastHtmlSubject = subject
|
||||||
m.LastHtmlBody = html
|
m.LastHtmlBody = html
|
||||||
m.TotalSend++
|
m.TotalSend++
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -12,7 +12,7 @@ type Mailer interface {
|
||||||
fromEmail mail.Address,
|
fromEmail mail.Address,
|
||||||
toEmail mail.Address,
|
toEmail mail.Address,
|
||||||
subject string,
|
subject string,
|
||||||
htmlBody string,
|
htmlContent string,
|
||||||
attachments map[string]io.Reader,
|
attachments map[string]io.Reader,
|
||||||
) error
|
) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (m *Sendmail) Send(
|
||||||
fromEmail mail.Address,
|
fromEmail mail.Address,
|
||||||
toEmail mail.Address,
|
toEmail mail.Address,
|
||||||
subject string,
|
subject string,
|
||||||
htmlBody string,
|
htmlContent string,
|
||||||
attachments map[string]io.Reader,
|
attachments map[string]io.Reader,
|
||||||
) error {
|
) error {
|
||||||
headers := make(http.Header)
|
headers := make(http.Header)
|
||||||
|
@ -50,7 +50,7 @@ func (m *Sendmail) Send(
|
||||||
if _, err := buffer.Write([]byte("\r\n")); err != nil {
|
if _, err := buffer.Write([]byte("\r\n")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := buffer.Write([]byte(htmlBody)); err != nil {
|
if _, err := buffer.Write([]byte(htmlContent)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// ---
|
// ---
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/domodwyer/mailyak/v3"
|
"github.com/domodwyer/mailyak/v3"
|
||||||
)
|
)
|
||||||
|
@ -43,7 +44,7 @@ func (m *SmtpClient) Send(
|
||||||
fromEmail mail.Address,
|
fromEmail mail.Address,
|
||||||
toEmail mail.Address,
|
toEmail mail.Address,
|
||||||
subject string,
|
subject string,
|
||||||
htmlBody string,
|
htmlContent string,
|
||||||
attachments map[string]io.Reader,
|
attachments map[string]io.Reader,
|
||||||
) error {
|
) error {
|
||||||
smtpAuth := smtp.PlainAuth("", m.username, m.password, m.host)
|
smtpAuth := smtp.PlainAuth("", m.username, m.password, m.host)
|
||||||
|
@ -64,9 +65,12 @@ func (m *SmtpClient) Send(
|
||||||
yak.FromName(fromEmail.Name)
|
yak.FromName(fromEmail.Name)
|
||||||
}
|
}
|
||||||
yak.From(fromEmail.Address)
|
yak.From(fromEmail.Address)
|
||||||
yak.To(toEmail.Address)
|
|
||||||
|
// wrap in brackets as workaround for spamassasin "TO_NO_BRKTS_HTML_ONLY" rule
|
||||||
|
yak.To(strings.TrimSpace(fmt.Sprintf("%s <%s>", toEmail.Name, toEmail.Address)))
|
||||||
|
|
||||||
yak.Subject(subject)
|
yak.Subject(subject)
|
||||||
yak.HTML().Set(htmlBody)
|
yak.HTML().Set(htmlContent)
|
||||||
|
|
||||||
for name, data := range attachments {
|
for name, data := range attachments {
|
||||||
yak.Attach(name, data)
|
yak.Attach(name, data)
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
||||||
import{S as E,i as G,s as I,F as K,c as A,m as B,t as H,a as N,d as T,C as M,q as J,e as c,w as q,b as k,f as u,r as L,g as b,h as _,u as h,v as O,j as Q,l as U,o as w,A as V,p as W,B as X,D as Y,x as Z,z as S}from"./index.46518141.js";function y(f){let e,o,s;return{c(){e=q("for "),o=c("strong"),s=q(f[3]),u(o,"class","txt-nowrap")},m(l,t){b(l,e,t),b(l,o,t),_(o,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&w(e),l&&w(o)}}}function x(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0,t.autofocus=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[0]),t.focus(),p||(d=h(t,"input",f[6]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&1&&t.value!==n[0]&&S(t,n[0])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function ee(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password confirm"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[1]),p||(d=h(t,"input",f[7]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&2&&t.value!==n[1]&&S(t,n[1])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function te(f){let e,o,s,l,t,r,p,d,n,i,g,R,C,v,P,F,j,m=f[3]&&y(f);return r=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),d=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),{c(){e=c("form"),o=c("div"),s=c("h4"),l=q(`Reset your admin password
|
import{S as E,i as G,s as I,F as K,c as A,m as B,t as H,a as N,d as T,C as M,q as J,e as c,w as q,b as k,f as u,r as L,g as b,h as _,u as h,v as O,j as Q,l as U,o as w,A as V,p as W,B as X,D as Y,x as Z,z as S}from"./index.33005af5.js";function y(f){let e,o,s;return{c(){e=q("for "),o=c("strong"),s=q(f[3]),u(o,"class","txt-nowrap")},m(l,t){b(l,e,t),b(l,o,t),_(o,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&w(e),l&&w(o)}}}function x(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0,t.autofocus=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[0]),t.focus(),p||(d=h(t,"input",f[6]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&1&&t.value!==n[0]&&S(t,n[0])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function ee(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password confirm"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[1]),p||(d=h(t,"input",f[7]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&2&&t.value!==n[1]&&S(t,n[1])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function te(f){let e,o,s,l,t,r,p,d,n,i,g,R,C,v,P,F,j,m=f[3]&&y(f);return r=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),d=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),{c(){e=c("form"),o=c("div"),s=c("h4"),l=q(`Reset your admin password
|
||||||
`),m&&m.c(),t=k(),A(r.$$.fragment),p=k(),A(d.$$.fragment),n=k(),i=c("button"),g=c("span"),g.textContent="Set new password",R=k(),C=c("div"),v=c("a"),v.textContent="Back to login",u(s,"class","m-b-xs"),u(o,"class","content txt-center m-b-sm"),u(g,"class","txt"),u(i,"type","submit"),u(i,"class","btn btn-lg btn-block"),i.disabled=f[2],L(i,"btn-loading",f[2]),u(e,"class","m-b-base"),u(v,"href","/login"),u(v,"class","link-hint"),u(C,"class","content txt-center")},m(a,$){b(a,e,$),_(e,o),_(o,s),_(s,l),m&&m.m(s,null),_(e,t),B(r,e,null),_(e,p),B(d,e,null),_(e,n),_(e,i),_(i,g),b(a,R,$),b(a,C,$),_(C,v),P=!0,F||(j=[h(e,"submit",O(f[4])),Q(U.call(null,v))],F=!0)},p(a,$){a[3]?m?m.p(a,$):(m=y(a),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const z={};$&769&&(z.$$scope={dirty:$,ctx:a}),r.$set(z);const D={};$&770&&(D.$$scope={dirty:$,ctx:a}),d.$set(D),(!P||$&4)&&(i.disabled=a[2]),$&4&&L(i,"btn-loading",a[2])},i(a){P||(H(r.$$.fragment,a),H(d.$$.fragment,a),P=!0)},o(a){N(r.$$.fragment,a),N(d.$$.fragment,a),P=!1},d(a){a&&w(e),m&&m.d(),T(r),T(d),a&&w(R),a&&w(C),F=!1,V(j)}}}function se(f){let e,o;return e=new K({props:{$$slots:{default:[te]},$$scope:{ctx:f}}}),{c(){A(e.$$.fragment)},m(s,l){B(e,s,l),o=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){o||(H(e.$$.fragment,s),o=!0)},o(s){N(e.$$.fragment,s),o=!1},d(s){T(e,s)}}}function le(f,e,o){let s,{params:l}=e,t="",r="",p=!1;async function d(){if(!p){o(2,p=!0);try{await W.admins.confirmPasswordReset(l==null?void 0:l.token,t,r),X("Successfully set a new admin password."),Y("/")}catch(g){W.errorResponseHandler(g)}o(2,p=!1)}}function n(){t=this.value,o(0,t)}function i(){r=this.value,o(1,r)}return f.$$set=g=>{"params"in g&&o(5,l=g.params)},f.$$.update=()=>{f.$$.dirty&32&&o(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,r,p,s,d,l,n,i]}class ae extends E{constructor(e){super(),G(this,e,le,se,I,{params:5})}}export{ae as default};
|
`),m&&m.c(),t=k(),A(r.$$.fragment),p=k(),A(d.$$.fragment),n=k(),i=c("button"),g=c("span"),g.textContent="Set new password",R=k(),C=c("div"),v=c("a"),v.textContent="Back to login",u(s,"class","m-b-xs"),u(o,"class","content txt-center m-b-sm"),u(g,"class","txt"),u(i,"type","submit"),u(i,"class","btn btn-lg btn-block"),i.disabled=f[2],L(i,"btn-loading",f[2]),u(e,"class","m-b-base"),u(v,"href","/login"),u(v,"class","link-hint"),u(C,"class","content txt-center")},m(a,$){b(a,e,$),_(e,o),_(o,s),_(s,l),m&&m.m(s,null),_(e,t),B(r,e,null),_(e,p),B(d,e,null),_(e,n),_(e,i),_(i,g),b(a,R,$),b(a,C,$),_(C,v),P=!0,F||(j=[h(e,"submit",O(f[4])),Q(U.call(null,v))],F=!0)},p(a,$){a[3]?m?m.p(a,$):(m=y(a),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const z={};$&769&&(z.$$scope={dirty:$,ctx:a}),r.$set(z);const D={};$&770&&(D.$$scope={dirty:$,ctx:a}),d.$set(D),(!P||$&4)&&(i.disabled=a[2]),$&4&&L(i,"btn-loading",a[2])},i(a){P||(H(r.$$.fragment,a),H(d.$$.fragment,a),P=!0)},o(a){N(r.$$.fragment,a),N(d.$$.fragment,a),P=!1},d(a){a&&w(e),m&&m.d(),T(r),T(d),a&&w(R),a&&w(C),F=!1,V(j)}}}function se(f){let e,o;return e=new K({props:{$$slots:{default:[te]},$$scope:{ctx:f}}}),{c(){A(e.$$.fragment)},m(s,l){B(e,s,l),o=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){o||(H(e.$$.fragment,s),o=!0)},o(s){N(e.$$.fragment,s),o=!1},d(s){T(e,s)}}}function le(f,e,o){let s,{params:l}=e,t="",r="",p=!1;async function d(){if(!p){o(2,p=!0);try{await W.admins.confirmPasswordReset(l==null?void 0:l.token,t,r),X("Successfully set a new admin password."),Y("/")}catch(g){W.errorResponseHandler(g)}o(2,p=!1)}}function n(){t=this.value,o(0,t)}function i(){r=this.value,o(1,r)}return f.$$set=g=>{"params"in g&&o(5,l=g.params)},f.$$.update=()=>{f.$$.dirty&32&&o(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,r,p,s,d,l,n,i]}class ae extends E{constructor(e){super(),G(this,e,le,se,I,{params:5})}}export{ae as default};
|
|
@ -1,2 +1,2 @@
|
||||||
import{S as M,i as T,s as j,F as z,c as H,m as L,t as w,a as y,d as S,b as g,e as _,f as p,g as k,h as d,j as A,l as B,k as N,n as D,o as v,p as C,q as G,r as F,u as E,v as I,w as h,x as J,y as P,z as R}from"./index.46518141.js";function K(c){let e,s,n,l,t,o,f,m,i,a,b,u;return l=new G({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:r})=>({5:r}),({uniqueId:r})=>r?32:0]},$$scope:{ctx:c}}}),{c(){e=_("form"),s=_("div"),s.innerHTML=`<h4 class="m-b-xs">Forgotten admin password</h4>
|
import{S as M,i as T,s as j,F as z,c as H,m as L,t as w,a as y,d as S,b as g,e as _,f as p,g as k,h as d,j as A,l as B,k as N,n as D,o as v,p as C,q as G,r as F,u as E,v as I,w as h,x as J,y as P,z as R}from"./index.33005af5.js";function K(c){let e,s,n,l,t,o,f,m,i,a,b,u;return l=new G({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:r})=>({5:r}),({uniqueId:r})=>r?32:0]},$$scope:{ctx:c}}}),{c(){e=_("form"),s=_("div"),s.innerHTML=`<h4 class="m-b-xs">Forgotten admin password</h4>
|
||||||
<p>Enter the email associated with your account and we\u2019ll send you a recovery link:</p>`,n=g(),H(l.$$.fragment),t=g(),o=_("button"),f=_("i"),m=g(),i=_("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(f,"class","ri-mail-send-line"),p(i,"class","txt"),p(o,"type","submit"),p(o,"class","btn btn-lg btn-block"),o.disabled=c[1],F(o,"btn-loading",c[1]),p(e,"class","m-b-base")},m(r,$){k(r,e,$),d(e,s),d(e,n),L(l,e,null),d(e,t),d(e,o),d(o,f),d(o,m),d(o,i),a=!0,b||(u=E(e,"submit",I(c[3])),b=!0)},p(r,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:r}),l.$set(q),(!a||$&2)&&(o.disabled=r[1]),$&2&&F(o,"btn-loading",r[1])},i(r){a||(w(l.$$.fragment,r),a=!0)},o(r){y(l.$$.fragment,r),a=!1},d(r){r&&v(e),S(l),b=!1,u()}}}function O(c){let e,s,n,l,t,o,f,m,i;return{c(){e=_("div"),s=_("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=g(),l=_("div"),t=_("p"),o=h("Check "),f=_("strong"),m=h(c[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(f,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,o),d(t,f),d(f,m),d(t,i)},p(a,b){b&1&&J(m,a[0])},i:P,o:P,d(a){a&&v(e)}}}function Q(c){let e,s,n,l,t,o,f,m;return{c(){e=_("label"),s=h("Email"),l=g(),t=_("input"),p(e,"for",n=c[5]),p(t,"type","email"),p(t,"id",o=c[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),R(t,c[0]),t.focus(),f||(m=E(t,"input",c[4]),f=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&o!==(o=i[5])&&p(t,"id",o),a&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&v(e),i&&v(l),i&&v(t),f=!1,m()}}}function U(c){let e,s,n,l,t,o,f,m;const i=[O,K],a=[];function b(u,r){return u[2]?0:1}return e=b(c),s=a[e]=i[e](c),{c(){s.c(),n=g(),l=_("div"),t=_("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(u,r){a[e].m(u,r),k(u,n,r),k(u,l,r),d(l,t),o=!0,f||(m=A(B.call(null,t)),f=!0)},p(u,r){let $=e;e=b(u),e===$?a[e].p(u,r):(N(),y(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(u,r):(s=a[e]=i[e](u),s.c()),w(s,1),s.m(n.parentNode,n))},i(u){o||(w(s),o=!0)},o(u){y(s),o=!1},d(u){a[e].d(u),u&&v(n),u&&v(l),f=!1,m()}}}function V(c){let e,s;return e=new z({props:{$$slots:{default:[U]},$$scope:{ctx:c}}}),{c(){H(e.$$.fragment)},m(n,l){L(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(w(e.$$.fragment,n),s=!0)},o(n){y(e.$$.fragment,n),s=!1},d(n){S(e,n)}}}function W(c,e,s){let n="",l=!1,t=!1;async function o(){if(!l){s(1,l=!0);try{await C.admins.requestPasswordReset(n),s(2,t=!0)}catch(m){C.errorResponseHandler(m)}s(1,l=!1)}}function f(){n=this.value,s(0,n)}return[n,l,t,o,f]}class Y extends M{constructor(e){super(),T(this,e,W,V,j,{})}}export{Y as default};
|
<p>Enter the email associated with your account and we\u2019ll send you a recovery link:</p>`,n=g(),H(l.$$.fragment),t=g(),o=_("button"),f=_("i"),m=g(),i=_("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(f,"class","ri-mail-send-line"),p(i,"class","txt"),p(o,"type","submit"),p(o,"class","btn btn-lg btn-block"),o.disabled=c[1],F(o,"btn-loading",c[1]),p(e,"class","m-b-base")},m(r,$){k(r,e,$),d(e,s),d(e,n),L(l,e,null),d(e,t),d(e,o),d(o,f),d(o,m),d(o,i),a=!0,b||(u=E(e,"submit",I(c[3])),b=!0)},p(r,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:r}),l.$set(q),(!a||$&2)&&(o.disabled=r[1]),$&2&&F(o,"btn-loading",r[1])},i(r){a||(w(l.$$.fragment,r),a=!0)},o(r){y(l.$$.fragment,r),a=!1},d(r){r&&v(e),S(l),b=!1,u()}}}function O(c){let e,s,n,l,t,o,f,m,i;return{c(){e=_("div"),s=_("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=g(),l=_("div"),t=_("p"),o=h("Check "),f=_("strong"),m=h(c[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(f,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,o),d(t,f),d(f,m),d(t,i)},p(a,b){b&1&&J(m,a[0])},i:P,o:P,d(a){a&&v(e)}}}function Q(c){let e,s,n,l,t,o,f,m;return{c(){e=_("label"),s=h("Email"),l=g(),t=_("input"),p(e,"for",n=c[5]),p(t,"type","email"),p(t,"id",o=c[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),R(t,c[0]),t.focus(),f||(m=E(t,"input",c[4]),f=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&o!==(o=i[5])&&p(t,"id",o),a&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&v(e),i&&v(l),i&&v(t),f=!1,m()}}}function U(c){let e,s,n,l,t,o,f,m;const i=[O,K],a=[];function b(u,r){return u[2]?0:1}return e=b(c),s=a[e]=i[e](c),{c(){s.c(),n=g(),l=_("div"),t=_("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(u,r){a[e].m(u,r),k(u,n,r),k(u,l,r),d(l,t),o=!0,f||(m=A(B.call(null,t)),f=!0)},p(u,r){let $=e;e=b(u),e===$?a[e].p(u,r):(N(),y(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(u,r):(s=a[e]=i[e](u),s.c()),w(s,1),s.m(n.parentNode,n))},i(u){o||(w(s),o=!0)},o(u){y(s),o=!1},d(u){a[e].d(u),u&&v(n),u&&v(l),f=!1,m()}}}function V(c){let e,s;return e=new z({props:{$$slots:{default:[U]},$$scope:{ctx:c}}}),{c(){H(e.$$.fragment)},m(n,l){L(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(w(e.$$.fragment,n),s=!0)},o(n){y(e.$$.fragment,n),s=!1},d(n){S(e,n)}}}function W(c,e,s){let n="",l=!1,t=!1;async function o(){if(!l){s(1,l=!0);try{await C.admins.requestPasswordReset(n),s(2,t=!0)}catch(m){C.errorResponseHandler(m)}s(1,l=!1)}}function f(){n=this.value,s(0,n)}return[n,l,t,o,f]}class Y extends M{constructor(e){super(),T(this,e,W,V,j,{})}}export{Y as default};
|
|
@ -0,0 +1,4 @@
|
||||||
|
import{S as J,i as M,s as N,F as R,c as T,m as L,t as v,a as y,d as z,C as U,E as W,g as _,k as Y,n as j,o as b,_ as A,p as B,q as D,e as m,w as C,b as h,f as d,r as F,h as k,u as q,v as G,y as E,x as I,z as H}from"./index.33005af5.js";function K(r){let e,t,s,l,n,o,c,a,i,u,g,$,p=r[3]&&S(r);return o=new D({props:{class:"form-field required",name:"password",$$slots:{default:[Q,({uniqueId:f})=>({8:f}),({uniqueId:f})=>f?256:0]},$$scope:{ctx:r}}}),{c(){e=m("form"),t=m("div"),s=m("h5"),l=C(`Type your password to confirm changing your email address
|
||||||
|
`),p&&p.c(),n=h(),T(o.$$.fragment),c=h(),a=m("button"),i=m("span"),i.textContent="Confirm new email",d(t,"class","content txt-center m-b-base"),d(i,"class","txt"),d(a,"type","submit"),d(a,"class","btn btn-lg btn-block"),a.disabled=r[1],F(a,"btn-loading",r[1])},m(f,w){_(f,e,w),k(e,t),k(t,s),k(s,l),p&&p.m(s,null),k(e,n),L(o,e,null),k(e,c),k(e,a),k(a,i),u=!0,g||($=q(e,"submit",G(r[4])),g=!0)},p(f,w){f[3]?p?p.p(f,w):(p=S(f),p.c(),p.m(s,null)):p&&(p.d(1),p=null);const P={};w&769&&(P.$$scope={dirty:w,ctx:f}),o.$set(P),(!u||w&2)&&(a.disabled=f[1]),w&2&&F(a,"btn-loading",f[1])},i(f){u||(v(o.$$.fragment,f),u=!0)},o(f){y(o.$$.fragment,f),u=!1},d(f){f&&b(e),p&&p.d(),z(o),g=!1,$()}}}function O(r){let e,t,s,l,n;return{c(){e=m("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
|
<div class="content txt-bold"><p>Successfully changed the user email address.</p>
|
||||||
|
<p>You can now sign in with your new email address.</p></div>`,t=h(),s=m("button"),s.textContent="Close",d(e,"class","alert alert-success"),d(s,"type","button"),d(s,"class","btn btn-secondary btn-block")},m(o,c){_(o,e,c),_(o,t,c),_(o,s,c),l||(n=q(s,"click",r[6]),l=!0)},p:E,i:E,o:E,d(o){o&&b(e),o&&b(t),o&&b(s),l=!1,n()}}}function S(r){let e,t,s;return{c(){e=C("to "),t=m("strong"),s=C(r[3]),d(t,"class","txt-nowrap")},m(l,n){_(l,e,n),_(l,t,n),k(t,s)},p(l,n){n&8&&I(s,l[3])},d(l){l&&b(e),l&&b(t)}}}function Q(r){let e,t,s,l,n,o,c,a;return{c(){e=m("label"),t=C("Password"),l=h(),n=m("input"),d(e,"for",s=r[8]),d(n,"type","password"),d(n,"id",o=r[8]),n.required=!0,n.autofocus=!0},m(i,u){_(i,e,u),k(e,t),_(i,l,u),_(i,n,u),H(n,r[0]),n.focus(),c||(a=q(n,"input",r[7]),c=!0)},p(i,u){u&256&&s!==(s=i[8])&&d(e,"for",s),u&256&&o!==(o=i[8])&&d(n,"id",o),u&1&&n.value!==i[0]&&H(n,i[0])},d(i){i&&b(e),i&&b(l),i&&b(n),c=!1,a()}}}function V(r){let e,t,s,l;const n=[O,K],o=[];function c(a,i){return a[2]?0:1}return e=c(r),t=o[e]=n[e](r),{c(){t.c(),s=W()},m(a,i){o[e].m(a,i),_(a,s,i),l=!0},p(a,i){let u=e;e=c(a),e===u?o[e].p(a,i):(Y(),y(o[u],1,1,()=>{o[u]=null}),j(),t=o[e],t?t.p(a,i):(t=o[e]=n[e](a),t.c()),v(t,1),t.m(s.parentNode,s))},i(a){l||(v(t),l=!0)},o(a){y(t),l=!1},d(a){o[e].d(a),a&&b(s)}}}function X(r){let e,t;return e=new R({props:{nobranding:!0,$$slots:{default:[V]},$$scope:{ctx:r}}}),{c(){T(e.$$.fragment)},m(s,l){L(e,s,l),t=!0},p(s,[l]){const n={};l&527&&(n.$$scope={dirty:l,ctx:s}),e.$set(n)},i(s){t||(v(e.$$.fragment,s),t=!0)},o(s){y(e.$$.fragment,s),t=!1},d(s){z(e,s)}}}function Z(r,e,t){let s,{params:l}=e,n="",o=!1,c=!1;async function a(){if(o)return;t(1,o=!0);const g=new A("../");try{await g.users.confirmEmailChange(l==null?void 0:l.token,n),t(2,c=!0)}catch($){B.errorResponseHandler($)}t(1,o=!1)}const i=()=>window.close();function u(){n=this.value,t(0,n)}return r.$$set=g=>{"params"in g&&t(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&t(3,s=U.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[n,o,c,s,a,l,i,u]}class ee extends J{constructor(e){super(),M(this,e,Z,X,N,{params:5})}}export{ee as default};
|
|
@ -1,4 +0,0 @@
|
||||||
import{S as M,i as N,s as R,F as U,c as L,m as z,t as $,a as v,d as J,C as W,E as Y,g as _,k as j,n as A,o as b,p as F,q as B,e as m,w as y,b as C,f as d,r as H,h as k,u as E,v as D,y as h,x as G,z as S}from"./index.46518141.js";function I(r){let e,s,t,l,n,o,c,a,i,u,g,q,p=r[3]&&T(r);return o=new B({props:{class:"form-field required",name:"password",$$slots:{default:[O,({uniqueId:f})=>({8:f}),({uniqueId:f})=>f?256:0]},$$scope:{ctx:r}}}),{c(){e=m("form"),s=m("div"),t=m("h4"),l=y(`Type your password to confirm changing your email address
|
|
||||||
`),p&&p.c(),n=C(),L(o.$$.fragment),c=C(),a=m("button"),i=m("span"),i.textContent="Confirm new email",d(t,"class","m-b-xs"),d(s,"class","content txt-center m-b-sm"),d(i,"class","txt"),d(a,"type","submit"),d(a,"class","btn btn-lg btn-block"),a.disabled=r[1],H(a,"btn-loading",r[1])},m(f,w){_(f,e,w),k(e,s),k(s,t),k(t,l),p&&p.m(t,null),k(e,n),z(o,e,null),k(e,c),k(e,a),k(a,i),u=!0,g||(q=E(e,"submit",D(r[4])),g=!0)},p(f,w){f[3]?p?p.p(f,w):(p=T(f),p.c(),p.m(t,null)):p&&(p.d(1),p=null);const P={};w&769&&(P.$$scope={dirty:w,ctx:f}),o.$set(P),(!u||w&2)&&(a.disabled=f[1]),w&2&&H(a,"btn-loading",f[1])},i(f){u||($(o.$$.fragment,f),u=!0)},o(f){v(o.$$.fragment,f),u=!1},d(f){f&&b(e),p&&p.d(),J(o),g=!1,q()}}}function K(r){let e,s,t,l,n;return{c(){e=m("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
|
||||||
<div class="content txt-bold"><p>Successfully changed the user email address.</p>
|
|
||||||
<p>You can now sign in with your new email address.</p></div>`,s=C(),t=m("button"),t.textContent="Close",d(e,"class","alert alert-success"),d(t,"type","button"),d(t,"class","btn btn-secondary btn-block")},m(o,c){_(o,e,c),_(o,s,c),_(o,t,c),l||(n=E(t,"click",r[6]),l=!0)},p:h,i:h,o:h,d(o){o&&b(e),o&&b(s),o&&b(t),l=!1,n()}}}function T(r){let e,s,t;return{c(){e=y("to "),s=m("strong"),t=y(r[3]),d(s,"class","txt-nowrap")},m(l,n){_(l,e,n),_(l,s,n),k(s,t)},p(l,n){n&8&&G(t,l[3])},d(l){l&&b(e),l&&b(s)}}}function O(r){let e,s,t,l,n,o,c,a;return{c(){e=m("label"),s=y("Password"),l=C(),n=m("input"),d(e,"for",t=r[8]),d(n,"type","password"),d(n,"id",o=r[8]),n.required=!0,n.autofocus=!0},m(i,u){_(i,e,u),k(e,s),_(i,l,u),_(i,n,u),S(n,r[0]),n.focus(),c||(a=E(n,"input",r[7]),c=!0)},p(i,u){u&256&&t!==(t=i[8])&&d(e,"for",t),u&256&&o!==(o=i[8])&&d(n,"id",o),u&1&&n.value!==i[0]&&S(n,i[0])},d(i){i&&b(e),i&&b(l),i&&b(n),c=!1,a()}}}function Q(r){let e,s,t,l;const n=[K,I],o=[];function c(a,i){return a[2]?0:1}return e=c(r),s=o[e]=n[e](r),{c(){s.c(),t=Y()},m(a,i){o[e].m(a,i),_(a,t,i),l=!0},p(a,i){let u=e;e=c(a),e===u?o[e].p(a,i):(j(),v(o[u],1,1,()=>{o[u]=null}),A(),s=o[e],s?s.p(a,i):(s=o[e]=n[e](a),s.c()),$(s,1),s.m(t.parentNode,t))},i(a){l||($(s),l=!0)},o(a){v(s),l=!1},d(a){o[e].d(a),a&&b(t)}}}function V(r){let e,s;return e=new U({props:{nobranding:!0,$$slots:{default:[Q]},$$scope:{ctx:r}}}),{c(){L(e.$$.fragment)},m(t,l){z(e,t,l),s=!0},p(t,[l]){const n={};l&527&&(n.$$scope={dirty:l,ctx:t}),e.$set(n)},i(t){s||($(e.$$.fragment,t),s=!0)},o(t){v(e.$$.fragment,t),s=!1},d(t){J(e,t)}}}function X(r,e,s){let t,{params:l}=e,n="",o=!1,c=!1;async function a(){if(!o){s(1,o=!0);try{await F.users.confirmEmailChange(l==null?void 0:l.token,n),s(2,c=!0)}catch(g){F.errorResponseHandler(g)}s(1,o=!1)}}const i=()=>window.close();function u(){n=this.value,s(0,n)}return r.$$set=g=>{"params"in g&&s(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&s(3,t=W.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[n,o,c,t,a,l,i,u]}class x extends M{constructor(e){super(),N(this,e,X,V,R,{params:5})}}export{x as default};
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import{S as U,i as W,s as Y,F as j,c as H,m as N,t as P,a as q,d as L,C as A,E as B,g as _,k as D,n as G,o as m,_ as I,p as K,q as E,e as b,w as y,b as C,f as c,r as J,h as w,u as S,v as O,y as F,x as Q,z as R}from"./index.33005af5.js";function V(i){let e,l,s,n,t,o,p,u,r,a,v,g,k,h,d=i[4]&&M(i);return o=new E({props:{class:"form-field required",name:"password",$$slots:{default:[Z,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),u=new E({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[x,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),{c(){e=b("form"),l=b("div"),s=b("h5"),n=y(`Reset your user password
|
||||||
|
`),d&&d.c(),t=C(),H(o.$$.fragment),p=C(),H(u.$$.fragment),r=C(),a=b("button"),v=b("span"),v.textContent="Set new password",c(l,"class","content txt-center m-b-base"),c(v,"class","txt"),c(a,"type","submit"),c(a,"class","btn btn-lg btn-block"),a.disabled=i[2],J(a,"btn-loading",i[2])},m(f,$){_(f,e,$),w(e,l),w(l,s),w(s,n),d&&d.m(s,null),w(e,t),N(o,e,null),w(e,p),N(u,e,null),w(e,r),w(e,a),w(a,v),g=!0,k||(h=S(e,"submit",O(i[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=M(f),d.c(),d.m(s,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const z={};$&3074&&(z.$$scope={dirty:$,ctx:f}),u.$set(z),(!g||$&4)&&(a.disabled=f[2]),$&4&&J(a,"btn-loading",f[2])},i(f){g||(P(o.$$.fragment,f),P(u.$$.fragment,f),g=!0)},o(f){q(o.$$.fragment,f),q(u.$$.fragment,f),g=!1},d(f){f&&m(e),d&&d.d(),L(o),L(u),k=!1,h()}}}function X(i){let e,l,s,n,t;return{c(){e=b("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
|
<div class="content txt-bold"><p>Successfully changed the user password.</p>
|
||||||
|
<p>You can now sign in with your new password.</p></div>`,l=C(),s=b("button"),s.textContent="Close",c(e,"class","alert alert-success"),c(s,"type","button"),c(s,"class","btn btn-secondary btn-block")},m(o,p){_(o,e,p),_(o,l,p),_(o,s,p),n||(t=S(s,"click",i[7]),n=!0)},p:F,i:F,o:F,d(o){o&&m(e),o&&m(l),o&&m(s),n=!1,t()}}}function M(i){let e,l,s;return{c(){e=y("for "),l=b("strong"),s=y(i[4])},m(n,t){_(n,e,t),_(n,l,t),w(l,s)},p(n,t){t&16&&Q(s,n[4])},d(n){n&&m(e),n&&m(l)}}}function Z(i){let e,l,s,n,t,o,p,u;return{c(){e=b("label"),l=y("New password"),n=C(),t=b("input"),c(e,"for",s=i[10]),c(t,"type","password"),c(t,"id",o=i[10]),t.required=!0,t.autofocus=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,t,a),R(t,i[0]),t.focus(),p||(u=S(t,"input",i[8]),p=!0)},p(r,a){a&1024&&s!==(s=r[10])&&c(e,"for",s),a&1024&&o!==(o=r[10])&&c(t,"id",o),a&1&&t.value!==r[0]&&R(t,r[0])},d(r){r&&m(e),r&&m(n),r&&m(t),p=!1,u()}}}function x(i){let e,l,s,n,t,o,p,u;return{c(){e=b("label"),l=y("New password confirm"),n=C(),t=b("input"),c(e,"for",s=i[10]),c(t,"type","password"),c(t,"id",o=i[10]),t.required=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,t,a),R(t,i[1]),p||(u=S(t,"input",i[9]),p=!0)},p(r,a){a&1024&&s!==(s=r[10])&&c(e,"for",s),a&1024&&o!==(o=r[10])&&c(t,"id",o),a&2&&t.value!==r[1]&&R(t,r[1])},d(r){r&&m(e),r&&m(n),r&&m(t),p=!1,u()}}}function ee(i){let e,l,s,n;const t=[X,V],o=[];function p(u,r){return u[3]?0:1}return e=p(i),l=o[e]=t[e](i),{c(){l.c(),s=B()},m(u,r){o[e].m(u,r),_(u,s,r),n=!0},p(u,r){let a=e;e=p(u),e===a?o[e].p(u,r):(D(),q(o[a],1,1,()=>{o[a]=null}),G(),l=o[e],l?l.p(u,r):(l=o[e]=t[e](u),l.c()),P(l,1),l.m(s.parentNode,s))},i(u){n||(P(l),n=!0)},o(u){q(l),n=!1},d(u){o[e].d(u),u&&m(s)}}}function te(i){let e,l;return e=new j({props:{nobranding:!0,$$slots:{default:[ee]},$$scope:{ctx:i}}}),{c(){H(e.$$.fragment)},m(s,n){N(e,s,n),l=!0},p(s,[n]){const t={};n&2079&&(t.$$scope={dirty:n,ctx:s}),e.$set(t)},i(s){l||(P(e.$$.fragment,s),l=!0)},o(s){q(e.$$.fragment,s),l=!1},d(s){L(e,s)}}}function se(i,e,l){let s,{params:n}=e,t="",o="",p=!1,u=!1;async function r(){if(p)return;l(2,p=!0);const k=new I("../");try{await k.users.confirmPasswordReset(n==null?void 0:n.token,t,o),l(3,u=!0)}catch(h){K.errorResponseHandler(h)}l(2,p=!1)}const a=()=>window.close();function v(){t=this.value,l(0,t)}function g(){o=this.value,l(1,o)}return i.$$set=k=>{"params"in k&&l(6,n=k.params)},i.$$.update=()=>{i.$$.dirty&64&&l(4,s=A.getJWTPayload(n==null?void 0:n.token).email||"")},[t,o,p,u,s,r,n,a,v,g]}class ne extends U{constructor(e){super(),W(this,e,se,te,Y,{params:6})}}export{ne as default};
|
|
@ -1,4 +0,0 @@
|
||||||
import{S as W,i as Y,s as j,F as A,c as F,m as H,t as P,a as q,d as N,C as B,E as D,g as _,k as G,n as I,o as m,p as E,q as J,e as b,w as y,b as C,f as c,r as M,h as w,u as R,v as K,y as S,x as O,z as h}from"./index.46518141.js";function Q(i){let e,l,t,n,s,o,p,u,r,a,v,g,k,L,d=i[4]&&U(i);return o=new J({props:{class:"form-field required",name:"password",$$slots:{default:[X,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),u=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[Z,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),{c(){e=b("form"),l=b("div"),t=b("h4"),n=y(`Reset your user password
|
|
||||||
`),d&&d.c(),s=C(),F(o.$$.fragment),p=C(),F(u.$$.fragment),r=C(),a=b("button"),v=b("span"),v.textContent="Set new password",c(t,"class","m-b-xs"),c(l,"class","content txt-center m-b-sm"),c(v,"class","txt"),c(a,"type","submit"),c(a,"class","btn btn-lg btn-block"),a.disabled=i[2],M(a,"btn-loading",i[2])},m(f,$){_(f,e,$),w(e,l),w(l,t),w(t,n),d&&d.m(t,null),w(e,s),H(o,e,null),w(e,p),H(u,e,null),w(e,r),w(e,a),w(a,v),g=!0,k||(L=R(e,"submit",K(i[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=U(f),d.c(),d.m(t,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const z={};$&3074&&(z.$$scope={dirty:$,ctx:f}),u.$set(z),(!g||$&4)&&(a.disabled=f[2]),$&4&&M(a,"btn-loading",f[2])},i(f){g||(P(o.$$.fragment,f),P(u.$$.fragment,f),g=!0)},o(f){q(o.$$.fragment,f),q(u.$$.fragment,f),g=!1},d(f){f&&m(e),d&&d.d(),N(o),N(u),k=!1,L()}}}function V(i){let e,l,t,n,s;return{c(){e=b("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
|
||||||
<div class="content txt-bold"><p>Successfully changed the user password.</p>
|
|
||||||
<p>You can now sign in with your new password.</p></div>`,l=C(),t=b("button"),t.textContent="Close",c(e,"class","alert alert-success"),c(t,"type","button"),c(t,"class","btn btn-secondary btn-block")},m(o,p){_(o,e,p),_(o,l,p),_(o,t,p),n||(s=R(t,"click",i[7]),n=!0)},p:S,i:S,o:S,d(o){o&&m(e),o&&m(l),o&&m(t),n=!1,s()}}}function U(i){let e,l,t;return{c(){e=y("for "),l=b("strong"),t=y(i[4])},m(n,s){_(n,e,s),_(n,l,s),w(l,t)},p(n,s){s&16&&O(t,n[4])},d(n){n&&m(e),n&&m(l)}}}function X(i){let e,l,t,n,s,o,p,u;return{c(){e=b("label"),l=y("New password"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0,s.autofocus=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,s,a),h(s,i[0]),s.focus(),p||(u=R(s,"input",i[8]),p=!0)},p(r,a){a&1024&&t!==(t=r[10])&&c(e,"for",t),a&1024&&o!==(o=r[10])&&c(s,"id",o),a&1&&s.value!==r[0]&&h(s,r[0])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,u()}}}function Z(i){let e,l,t,n,s,o,p,u;return{c(){e=b("label"),l=y("New password confirm"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,s,a),h(s,i[1]),p||(u=R(s,"input",i[9]),p=!0)},p(r,a){a&1024&&t!==(t=r[10])&&c(e,"for",t),a&1024&&o!==(o=r[10])&&c(s,"id",o),a&2&&s.value!==r[1]&&h(s,r[1])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,u()}}}function x(i){let e,l,t,n;const s=[V,Q],o=[];function p(u,r){return u[3]?0:1}return e=p(i),l=o[e]=s[e](i),{c(){l.c(),t=D()},m(u,r){o[e].m(u,r),_(u,t,r),n=!0},p(u,r){let a=e;e=p(u),e===a?o[e].p(u,r):(G(),q(o[a],1,1,()=>{o[a]=null}),I(),l=o[e],l?l.p(u,r):(l=o[e]=s[e](u),l.c()),P(l,1),l.m(t.parentNode,t))},i(u){n||(P(l),n=!0)},o(u){q(l),n=!1},d(u){o[e].d(u),u&&m(t)}}}function ee(i){let e,l;return e=new A({props:{nobranding:!0,$$slots:{default:[x]},$$scope:{ctx:i}}}),{c(){F(e.$$.fragment)},m(t,n){H(e,t,n),l=!0},p(t,[n]){const s={};n&2079&&(s.$$scope={dirty:n,ctx:t}),e.$set(s)},i(t){l||(P(e.$$.fragment,t),l=!0)},o(t){q(e.$$.fragment,t),l=!1},d(t){N(e,t)}}}function te(i,e,l){let t,{params:n}=e,s="",o="",p=!1,u=!1;async function r(){if(!p){l(2,p=!0);try{await E.users.confirmPasswordReset(n==null?void 0:n.token,s,o),l(3,u=!0)}catch(k){E.errorResponseHandler(k)}l(2,p=!1)}}const a=()=>window.close();function v(){s=this.value,l(0,s)}function g(){o=this.value,l(1,o)}return i.$$set=k=>{"params"in k&&l(6,n=k.params)},i.$$.update=()=>{i.$$.dirty&64&&l(4,t=B.getJWTPayload(n==null?void 0:n.token).email||"")},[s,o,p,u,t,r,n,a,v,g]}class le extends W{constructor(e){super(),Y(this,e,te,ee,j,{params:6})}}export{le as default};
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import{S as k,i as v,s as y,F as w,c as x,m as C,t as g,a as $,d as L,_ as H,E as M,g as r,o as a,e as u,b as m,f,u as _,y as p}from"./index.33005af5.js";function P(c){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-error-warning-line"></i></div>
|
||||||
|
<div class="content txt-bold"><p>Invalid or expired verification token.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-danger"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,o){r(l,t,o),r(l,s,o),r(l,e,o),n||(i=_(e,"click",c[4]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function S(c){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
|
<div class="content txt-bold"><p>Successfully verified email address.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-success"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,o){r(l,t,o),r(l,s,o),r(l,e,o),n||(i=_(e,"click",c[3]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function T(c){let t;return{c(){t=u("div"),t.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',f(t,"class","txt-center")},m(s,e){r(s,t,e)},p,d(s){s&&a(t)}}}function F(c){let t;function s(i,l){return i[1]?T:i[0]?S:P}let e=s(c),n=e(c);return{c(){n.c(),t=M()},m(i,l){n.m(i,l),r(i,t,l)},p(i,l){e===(e=s(i))&&n?n.p(i,l):(n.d(1),n=e(i),n&&(n.c(),n.m(t.parentNode,t)))},d(i){n.d(i),i&&a(t)}}}function V(c){let t,s;return t=new w({props:{nobranding:!0,$$slots:{default:[F]},$$scope:{ctx:c}}}),{c(){x(t.$$.fragment)},m(e,n){C(t,e,n),s=!0},p(e,[n]){const i={};n&67&&(i.$$scope={dirty:n,ctx:e}),t.$set(i)},i(e){s||(g(t.$$.fragment,e),s=!0)},o(e){$(t.$$.fragment,e),s=!1},d(e){L(t,e)}}}function q(c,t,s){let{params:e}=t,n=!1,i=!1;l();async function l(){s(1,i=!0);const d=new H("../");try{await d.users.confirmVerification(e==null?void 0:e.token),s(0,n=!0)}catch{s(0,n=!1)}s(1,i=!1)}const o=()=>window.close(),b=()=>window.close();return c.$$set=d=>{"params"in d&&s(2,e=d.params)},[n,i,e,o,b]}class N extends k{constructor(t){super(),v(this,t,q,V,y,{params:2})}}export{N as default};
|
|
@ -1,3 +0,0 @@
|
||||||
import{S as k,i as v,s as y,F as w,c as x,m as C,t as g,a as $,d as L,p as H,E as M,g as r,o as a,e as u,b as m,f,u as _,y as p}from"./index.46518141.js";function P(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-error-warning-line"></i></div>
|
|
||||||
<div class="content txt-bold"><p>Invalid or expired verification token.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-danger"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[4]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function S(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
|
||||||
<div class="content txt-bold"><p>Successfully verified email address.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-success"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[3]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function T(o){let t;return{c(){t=u("div"),t.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',f(t,"class","txt-center")},m(s,e){r(s,t,e)},p,d(s){s&&a(t)}}}function F(o){let t;function s(i,l){return i[1]?T:i[0]?S:P}let e=s(o),n=e(o);return{c(){n.c(),t=M()},m(i,l){n.m(i,l),r(i,t,l)},p(i,l){e===(e=s(i))&&n?n.p(i,l):(n.d(1),n=e(i),n&&(n.c(),n.m(t.parentNode,t)))},d(i){n.d(i),i&&a(t)}}}function V(o){let t,s;return t=new w({props:{nobranding:!0,$$slots:{default:[F]},$$scope:{ctx:o}}}),{c(){x(t.$$.fragment)},m(e,n){C(t,e,n),s=!0},p(e,[n]){const i={};n&67&&(i.$$scope={dirty:n,ctx:e}),t.$set(i)},i(e){s||(g(t.$$.fragment,e),s=!0)},o(e){$(t.$$.fragment,e),s=!1},d(e){L(t,e)}}}function q(o,t,s){let{params:e}=t,n=!1,i=!1;l();async function l(){s(1,i=!0);try{await H.users.confirmVerification(e==null?void 0:e.token),s(0,n=!0)}catch(d){console.warn(d),s(0,n=!1)}s(1,i=!1)}const c=()=>window.close(),b=()=>window.close();return o.$$set=d=>{"params"in d&&s(2,e=d.params)},[n,i,e,c,b]}class I extends k{constructor(t){super(),v(this,t,q,V,y,{params:2})}}export{I as default};
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -24,8 +24,8 @@
|
||||||
window.Prism = window.Prism || {};
|
window.Prism = window.Prism || {};
|
||||||
window.Prism.manual = true;
|
window.Prism.manual = true;
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="./assets/index.46518141.js"></script>
|
<script type="module" crossorigin src="./assets/index.33005af5.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index.74115736.css">
|
<link rel="stylesheet" href="./assets/index.8992dfa3.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^3.7.1",
|
||||||
"chartjs-adapter-luxon": "^1.1.0",
|
"chartjs-adapter-luxon": "^1.1.0",
|
||||||
"luxon": "^2.3.2",
|
"luxon": "^2.3.2",
|
||||||
"pocketbase": "^0.4.1",
|
"pocketbase": "^0.5.0",
|
||||||
"prismjs": "^1.28.0",
|
"prismjs": "^1.28.0",
|
||||||
"sass": "^1.45.0",
|
"sass": "^1.45.0",
|
||||||
"svelte": "^3.44.0",
|
"svelte": "^3.44.0",
|
||||||
|
@ -47,9 +47,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.0.1",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.1.0.tgz",
|
||||||
"integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==",
|
"integrity": "sha512-qCj2YqmbBjj0P1iumnlL5lBqZvJPzT+t2UvgjcaXErp5ZvMqFRVgQyrEfdXX6SX5UcvcHKBjXqno+MkUp0aYvQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
|
@ -948,9 +948,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pocketbase": {
|
"node_modules/pocketbase": {
|
||||||
"version": "0.4.1",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.5.0.tgz",
|
||||||
"integrity": "sha512-aDuN8ySDTRnY6P+jcNcOpb72yHojcdzSzU+3hDiXWxbERYDZP1+drVb9OEufFzbIlMaG7fhcth5ejdEK6sRELA==",
|
"integrity": "sha512-qgPBAp7BB4OmgPJAj65tA8VuvvSH7glDI4yIbqKh86f4jfeLYC0ITwnhnCobNGgkr0ER2P25BTYQeU1aGbTOyQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
|
@ -1040,9 +1040,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.54.4",
|
"version": "1.54.5",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.5.tgz",
|
||||||
"integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==",
|
"integrity": "sha512-p7DTOzxkUPa/63FU0R3KApkRHwcVZYC0PLnLm5iyZACyp15qSi32x7zVUhRdABAATmkALqgGrjCJAcWvobmhHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
@ -1147,9 +1147,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||||
"integrity": "sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==",
|
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.14.47",
|
"esbuild": "^0.14.47",
|
||||||
|
@ -1208,9 +1208,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@codemirror/commands": {
|
"@codemirror/commands": {
|
||||||
"version": "6.0.1",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.1.0.tgz",
|
||||||
"integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==",
|
"integrity": "sha512-qCj2YqmbBjj0P1iumnlL5lBqZvJPzT+t2UvgjcaXErp5ZvMqFRVgQyrEfdXX6SX5UcvcHKBjXqno+MkUp0aYvQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
|
@ -1808,9 +1808,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pocketbase": {
|
"pocketbase": {
|
||||||
"version": "0.4.1",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.5.0.tgz",
|
||||||
"integrity": "sha512-aDuN8ySDTRnY6P+jcNcOpb72yHojcdzSzU+3hDiXWxbERYDZP1+drVb9OEufFzbIlMaG7fhcth5ejdEK6sRELA==",
|
"integrity": "sha512-qgPBAp7BB4OmgPJAj65tA8VuvvSH7glDI4yIbqKh86f4jfeLYC0ITwnhnCobNGgkr0ER2P25BTYQeU1aGbTOyQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
|
@ -1866,9 +1866,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.54.4",
|
"version": "1.54.5",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.5.tgz",
|
||||||
"integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==",
|
"integrity": "sha512-p7DTOzxkUPa/63FU0R3KApkRHwcVZYC0PLnLm5iyZACyp15qSi32x7zVUhRdABAATmkALqgGrjCJAcWvobmhHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
@ -1941,9 +1941,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-3.0.9.tgz",
|
||||||
"integrity": "sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==",
|
"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.14.47",
|
"esbuild": "^0.14.47",
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^3.7.1",
|
||||||
"chartjs-adapter-luxon": "^1.1.0",
|
"chartjs-adapter-luxon": "^1.1.0",
|
||||||
"luxon": "^2.3.2",
|
"luxon": "^2.3.2",
|
||||||
"pocketbase": "^0.4.1",
|
"pocketbase": "^0.5.0",
|
||||||
"prismjs": "^1.28.0",
|
"prismjs": "^1.28.0",
|
||||||
"sass": "^1.45.0",
|
"sass": "^1.45.0",
|
||||||
"svelte": "^3.44.0",
|
"svelte": "^3.44.0",
|
||||||
|
|
|
@ -146,7 +146,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm(`Do you really want to delete collection "${original?.name}" and all its records?`, () => {
|
confirm(`Do you really want to delete collection "${original?.name}" and all its records?`, () => {
|
||||||
return ApiClient.collections.delete(original?.id)
|
return ApiClient.collections
|
||||||
|
.delete(original?.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
hide();
|
hide();
|
||||||
addSuccessToast(`Successfully deleted collection "${original?.name}".`);
|
addSuccessToast(`Successfully deleted collection "${original?.name}".`);
|
||||||
|
|
|
@ -149,7 +149,7 @@
|
||||||
{:else if field.type === "url"}
|
{:else if field.type === "url"}
|
||||||
URL address.
|
URL address.
|
||||||
{:else if field.type === "file"}
|
{:else if field.type === "file"}
|
||||||
FormData object.<br />
|
File object.<br />
|
||||||
Set to <code>null</code> to delete already uploaded file(s).
|
Set to <code>null</code> to delete already uploaded file(s).
|
||||||
{:else if field.type === "relation"}
|
{:else if field.type === "relation"}
|
||||||
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
{:else if field.type === "url"}
|
{:else if field.type === "url"}
|
||||||
URL address.
|
URL address.
|
||||||
{:else if field.type === "file"}
|
{:else if field.type === "file"}
|
||||||
FormData object.<br />
|
File object.<br />
|
||||||
Set to <code>null</code> to delete already uploaded file(s).
|
Set to <code>null</code> to delete already uploaded file(s).
|
||||||
{:else if field.type === "relation"}
|
{:else if field.type === "relation"}
|
||||||
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||||
|
|
|
@ -47,7 +47,8 @@
|
||||||
clearList();
|
clearList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ApiClient.records.getList(collection.id, page, 50, {
|
return ApiClient.records
|
||||||
|
.getList(collection.id, page, 50, {
|
||||||
sort: sort,
|
sort: sort,
|
||||||
filter: filter,
|
filter: filter,
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import CommonHelper from "@/utils/CommonHelper";
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
import Field from "@/components/base/Field.svelte";
|
import Field from "@/components/base/Field.svelte";
|
||||||
import Accordion from "@/components/base/Accordion.svelte";
|
import Accordion from "@/components/base/Accordion.svelte";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
export let key;
|
export let key;
|
||||||
export let title;
|
export let title;
|
||||||
|
@ -45,12 +46,12 @@
|
||||||
isEditorComponentLoading = false;
|
isEditorComponentLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadEditorComponent();
|
|
||||||
|
|
||||||
function copy(param) {
|
function copy(param) {
|
||||||
CommonHelper.copyToClipboard(param);
|
CommonHelper.copyToClipboard(param);
|
||||||
addInfoToast(`Copied ${param} to clipboard`, 2000);
|
addInfoToast(`Copied ${param} to clipboard`, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadEditorComponent();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Accordion bind:this={accordion} on:expand on:collapse on:toggle {...$$restProps}>
|
<Accordion bind:this={accordion} on:expand on:collapse on:toggle {...$$restProps}>
|
||||||
|
@ -108,18 +109,13 @@
|
||||||
<label for={uniqueId}>Body (HTML)</label>
|
<label for={uniqueId}>Body (HTML)</label>
|
||||||
|
|
||||||
{#if editorComponent && !isEditorComponentLoading}
|
{#if editorComponent && !isEditorComponentLoading}
|
||||||
<svelte:component
|
<svelte:component this={editorComponent} id={uniqueId} language="html" bind:value={config.body} />
|
||||||
this={editorComponent}
|
|
||||||
id={uniqueId}
|
|
||||||
language="html"
|
|
||||||
bind:value={config.body}
|
|
||||||
/>
|
|
||||||
{:else}
|
{:else}
|
||||||
<textarea
|
<textarea
|
||||||
id={uniqueId}
|
id={uniqueId}
|
||||||
class="txt-mono"
|
class="txt-mono"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
rows="12"
|
rows="14"
|
||||||
required
|
required
|
||||||
bind:value={config.body}
|
bind:value={config.body}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher, tick } from "svelte";
|
||||||
|
import ApiClient from "@/utils/ApiClient";
|
||||||
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
|
import { addErrorToast, addSuccessToast } from "@/stores/toasts";
|
||||||
|
import { setErrors } from "@/stores/errors";
|
||||||
|
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
|
||||||
|
import Field from "@/components/base/Field.svelte";
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
const formId = "email_test_" + CommonHelper.randomString(5);
|
||||||
|
const emailStorageKey = "last_email_test";
|
||||||
|
const testRequestKey = "email_test_request";
|
||||||
|
|
||||||
|
const templateOptions = [
|
||||||
|
{ label: '"Verification" template', value: "verification" },
|
||||||
|
{ label: '"Password reset" template', value: "password-reset" },
|
||||||
|
{ label: '"Confirm email change" template', value: "email-change" },
|
||||||
|
];
|
||||||
|
|
||||||
|
let panel;
|
||||||
|
let email = localStorage.getItem(emailStorageKey);
|
||||||
|
let template = templateOptions[0].value;
|
||||||
|
let isSubmitting = false;
|
||||||
|
let testTimeoutId = null;
|
||||||
|
|
||||||
|
$: canSubmit = !!email && !!template;
|
||||||
|
|
||||||
|
export function show(emailArg = "", templateArg = "") {
|
||||||
|
email = emailArg || localStorage.getItem(emailStorageKey);
|
||||||
|
template = templateArg || templateOptions[0].value;
|
||||||
|
|
||||||
|
setErrors({}); // reset any previous errors
|
||||||
|
|
||||||
|
panel?.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hide() {
|
||||||
|
clearTimeout(testTimeoutId);
|
||||||
|
return panel?.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
if (!canSubmit || isSubmitting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting = true;
|
||||||
|
|
||||||
|
// store in local storage for later use
|
||||||
|
localStorage?.setItem(emailStorageKey, email);
|
||||||
|
|
||||||
|
// auto cancel the test request after 30sec
|
||||||
|
clearTimeout(testTimeoutId);
|
||||||
|
testTimeoutId = setTimeout(() => {
|
||||||
|
ApiClient.cancelRequest(testRequestKey);
|
||||||
|
addErrorToast("Test email send timeout.");
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ApiClient.settings.testEmail(email, template, {
|
||||||
|
$cancelKey: testRequestKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
addSuccessToast("Successfully sent test email.");
|
||||||
|
dispatch("submit");
|
||||||
|
isSubmitting = false;
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
hide();
|
||||||
|
} catch (err) {
|
||||||
|
isSubmitting = false;
|
||||||
|
ApiClient.errorResponseHandler(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(testTimeoutId);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<OverlayPanel
|
||||||
|
bind:this={panel}
|
||||||
|
class="overlay-panel-sm email-test-popup"
|
||||||
|
overlayClose={!isSubmitting}
|
||||||
|
escClose={!isSubmitting}
|
||||||
|
beforeHide={() => !isSubmitting}
|
||||||
|
popup
|
||||||
|
on:show
|
||||||
|
on:hide
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<h4 class="center txt-break">Send test email</h4>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<form id={formId} autocomplete="off" on:submit|preventDefault={() => submit()}>
|
||||||
|
<Field class="form-field required" name="template" let:uniqueId>
|
||||||
|
{#each templateOptions as option (option.value)}
|
||||||
|
<div class="form-field-block">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="template"
|
||||||
|
id={uniqueId + option.value}
|
||||||
|
value={option.value}
|
||||||
|
bind:group={template}
|
||||||
|
/>
|
||||||
|
<label for={uniqueId + option.value}>{option.label}</label>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field class="form-field required m-0" name="email" let:uniqueId>
|
||||||
|
<label for={uniqueId}>To email address</label>
|
||||||
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
|
<input type="email" id={uniqueId} autofocus required bind:value={email} />
|
||||||
|
</Field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<svelte:fragment slot="footer">
|
||||||
|
<button type="button" class="btn btn-secondary" on:click={hide} disabled={isSubmitting}>Close</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
form={formId}
|
||||||
|
class="btn btn-expanded"
|
||||||
|
class:btn-loading={isSubmitting}
|
||||||
|
disabled={!canSubmit || isSubmitting}
|
||||||
|
on:click={() => submit()}
|
||||||
|
>
|
||||||
|
<i class="ri-mail-send-line" />
|
||||||
|
<span class="txt">Send</span>
|
||||||
|
</button>
|
||||||
|
</svelte:fragment>
|
||||||
|
</OverlayPanel>
|
|
@ -117,7 +117,7 @@
|
||||||
<i
|
<i
|
||||||
class="ri-information-line link-hint"
|
class="ri-information-line link-hint"
|
||||||
use:tooltip={{
|
use:tooltip={{
|
||||||
text: `This is useful to prevent making accidental schema changes on a production environment.`,
|
text: `This could prevent making accidental schema changes when in production environment.`,
|
||||||
position: "right",
|
position: "right",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
$: canImport = !isLoadingOldCollections && isValid && hasChanges;
|
$: canImport = !isLoadingOldCollections && isValid && hasChanges;
|
||||||
|
|
||||||
$: idReplacableCollections = newCollections.filter((collection) => {
|
$: idReplacableCollections = newCollections.filter((collection) => {
|
||||||
let old = CommonHelper.findByKey(oldCollections, "name", collection.name) ||
|
let old =
|
||||||
|
CommonHelper.findByKey(oldCollections, "name", collection.name) ||
|
||||||
CommonHelper.findByKey(oldCollections, "id", collection.id);
|
CommonHelper.findByKey(oldCollections, "id", collection.id);
|
||||||
|
|
||||||
if (!old) {
|
if (!old) {
|
||||||
|
@ -149,7 +150,8 @@
|
||||||
|
|
||||||
function replaceIds() {
|
function replaceIds() {
|
||||||
for (let collection of newCollections) {
|
for (let collection of newCollections) {
|
||||||
const old = CommonHelper.findByKey(oldCollections, "name", collection.name) ||
|
const old =
|
||||||
|
CommonHelper.findByKey(oldCollections, "name", collection.name) ||
|
||||||
CommonHelper.findByKey(oldCollections, "id", collection.id);
|
CommonHelper.findByKey(oldCollections, "id", collection.id);
|
||||||
|
|
||||||
if (!old) {
|
if (!old) {
|
||||||
|
@ -327,7 +329,8 @@
|
||||||
<span class="label label-warning list-label">Changed</span>
|
<span class="label label-warning list-label">Changed</span>
|
||||||
<div class="inline-flex flex-gap-5">
|
<div class="inline-flex flex-gap-5">
|
||||||
{#if pair.old.name !== pair.new.name}
|
{#if pair.old.name !== pair.new.name}
|
||||||
<strong class="txt-strikethrough txt-hint">{pair.old.name}</strong>
|
<strong class="txt-strikethrough txt-hint">{pair.old.name}</strong
|
||||||
|
>
|
||||||
<i class="ri-arrow-right-line txt-sm" />
|
<i class="ri-arrow-right-line txt-sm" />
|
||||||
{/if}
|
{/if}
|
||||||
<strong>
|
<strong>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
import RedactedPasswordInput from "@/components/base/RedactedPasswordInput.svelte";
|
import RedactedPasswordInput from "@/components/base/RedactedPasswordInput.svelte";
|
||||||
import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte";
|
import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte";
|
||||||
import EmailTemplateAccordion from "@/components/settings/EmailTemplateAccordion.svelte";
|
import EmailTemplateAccordion from "@/components/settings/EmailTemplateAccordion.svelte";
|
||||||
|
import EmailTestPopup from "@/components/settings/EmailTestPopup.svelte";
|
||||||
|
|
||||||
const tlsOptions = [
|
const tlsOptions = [
|
||||||
{ label: "Auto (StartTLS)", value: false },
|
{ label: "Auto (StartTLS)", value: false },
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
|
|
||||||
$pageTitle = "Mail settings";
|
$pageTitle = "Mail settings";
|
||||||
|
|
||||||
|
let testPopup;
|
||||||
let originalFormSettings = {};
|
let originalFormSettings = {};
|
||||||
let formSettings = {};
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
|
@ -217,6 +219,7 @@
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
|
||||||
{#if hasChanges}
|
{#if hasChanges}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -226,7 +229,6 @@
|
||||||
>
|
>
|
||||||
<span class="txt">Cancel</span>
|
<span class="txt">Cancel</span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
@ -236,8 +238,20 @@
|
||||||
>
|
>
|
||||||
<span class="txt">Save changes</span>
|
<span class="txt">Save changes</span>
|
||||||
</button>
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-expanded btn-outline"
|
||||||
|
on:click={() => testPopup?.show()}
|
||||||
|
>
|
||||||
|
<i class="ri-mail-check-line" />
|
||||||
|
<span class="txt">Send test email</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|
||||||
|
<EmailTestPopup bind:this={testPopup} />
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import CommonHelper from "@/utils/CommonHelper";
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
import { pageTitle } from "@/stores/app";
|
import { pageTitle } from "@/stores/app";
|
||||||
import { setErrors } from "@/stores/errors";
|
import { setErrors } from "@/stores/errors";
|
||||||
import { addSuccessToast } from "@/stores/toasts";
|
import { removeAllToasts, addWarningToast, addSuccessToast } from "@/stores/toasts";
|
||||||
import tooltip from "@/actions/tooltip";
|
import tooltip from "@/actions/tooltip";
|
||||||
import PageWrapper from "@/components/base/PageWrapper.svelte";
|
import PageWrapper from "@/components/base/PageWrapper.svelte";
|
||||||
import Field from "@/components/base/Field.svelte";
|
import Field from "@/components/base/Field.svelte";
|
||||||
|
@ -13,10 +13,15 @@
|
||||||
|
|
||||||
$pageTitle = "Files storage";
|
$pageTitle = "Files storage";
|
||||||
|
|
||||||
|
const testRequestKey = "s3_test_request";
|
||||||
|
|
||||||
let originalFormSettings = {};
|
let originalFormSettings = {};
|
||||||
let formSettings = {};
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
|
let isTesting = false;
|
||||||
|
let testS3Error = null;
|
||||||
|
let testS3TimeoutId = null;
|
||||||
|
|
||||||
$: initialHash = JSON.stringify(originalFormSettings);
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
|
@ -37,6 +42,24 @@
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function testS3() {
|
||||||
|
testS3Error = null;
|
||||||
|
|
||||||
|
if (!formSettings.s3.enabled) {
|
||||||
|
return; // nothing to test
|
||||||
|
}
|
||||||
|
|
||||||
|
isTesting = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ApiClient.settings.testS3({ $cancelKey: testRequestKey });
|
||||||
|
} catch (err) {
|
||||||
|
testS3Error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
isTesting = false;
|
||||||
|
}
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
if (isSaving || !hasChanges) {
|
if (isSaving || !hasChanges) {
|
||||||
return;
|
return;
|
||||||
|
@ -44,27 +67,49 @@
|
||||||
|
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|
||||||
|
// auto cancel the test request after 30sec
|
||||||
|
clearTimeout(testS3TimeoutId);
|
||||||
|
testS3TimeoutId = setTimeout(() => {
|
||||||
|
ApiClient.cancelRequest(testRequestKey);
|
||||||
|
addErrorToast("S3 test connection timeout.");
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
ApiClient.cancelRequest(testRequestKey);
|
||||||
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
||||||
init(settings);
|
|
||||||
setErrors({});
|
setErrors({});
|
||||||
|
|
||||||
|
await init(settings);
|
||||||
|
|
||||||
|
removeAllToasts();
|
||||||
|
|
||||||
|
if (testS3Error) {
|
||||||
|
addWarningToast("Successfully saved but failed to establish S3 connection.");
|
||||||
|
} else {
|
||||||
addSuccessToast("Successfully saved files storage settings.");
|
addSuccessToast("Successfully saved files storage settings.");
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ApiClient.errorResponseHandler(err);
|
ApiClient.errorResponseHandler(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearTimeout(testS3TimeoutId);
|
||||||
|
|
||||||
isSaving = false;
|
isSaving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(settings = {}) {
|
async function init(settings = {}) {
|
||||||
formSettings = {
|
formSettings = {
|
||||||
s3: settings?.s3 || {},
|
s3: settings?.s3 || {},
|
||||||
};
|
};
|
||||||
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
|
||||||
|
await testS3();
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
async function reset() {
|
||||||
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
|
|
||||||
|
await testS3();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -136,7 +181,7 @@
|
||||||
|
|
||||||
{#if formSettings.s3.enabled}
|
{#if formSettings.s3.enabled}
|
||||||
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="s3.endpoint" let:uniqueId>
|
<Field class="form-field required" name="s3.endpoint" let:uniqueId>
|
||||||
<label for={uniqueId}>Endpoint</label>
|
<label for={uniqueId}>Endpoint</label>
|
||||||
<input
|
<input
|
||||||
|
@ -147,7 +192,7 @@
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-3">
|
||||||
<Field class="form-field required" name="s3.bucket" let:uniqueId>
|
<Field class="form-field required" name="s3.bucket" let:uniqueId>
|
||||||
<label for={uniqueId}>Bucket</label>
|
<label for={uniqueId}>Bucket</label>
|
||||||
<input
|
<input
|
||||||
|
@ -158,7 +203,7 @@
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-3">
|
||||||
<Field class="form-field required" name="s3.region" let:uniqueId>
|
<Field class="form-field required" name="s3.region" let:uniqueId>
|
||||||
<label for={uniqueId}>Region</label>
|
<label for={uniqueId}>Region</label>
|
||||||
<input
|
<input
|
||||||
|
@ -216,6 +261,26 @@
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
|
||||||
|
{#if formSettings.s3?.enabled && !hasChanges && !isSaving}
|
||||||
|
{#if isTesting}
|
||||||
|
<span class="loader loader-sm" />
|
||||||
|
{:else if testS3Error}
|
||||||
|
<div
|
||||||
|
class="label label-sm label-warning entrance-right"
|
||||||
|
use:tooltip={testS3Error.data?.message}
|
||||||
|
>
|
||||||
|
<i class="ri-error-warning-line txt-warning" />
|
||||||
|
<span class="txt">Failed to establish S3 connection</span>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="label label-sm label-success entrance-right">
|
||||||
|
<i class="ri-checkbox-circle-line txt-success" />
|
||||||
|
<span class="txt">S3 connected successfully</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if hasChanges}
|
{#if hasChanges}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -226,6 +291,7 @@
|
||||||
<span class="txt">Cancel</span>
|
<span class="txt">Cancel</span>
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import PocketBase from "pocketbase";
|
||||||
import ApiClient from "@/utils/ApiClient";
|
import ApiClient from "@/utils/ApiClient";
|
||||||
import CommonHelper from "@/utils/CommonHelper";
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
import FullPage from "@/components/base/FullPage.svelte";
|
import FullPage from "@/components/base/FullPage.svelte";
|
||||||
|
@ -19,8 +20,11 @@
|
||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
|
// init a custom client to avoid interfering with the admin state
|
||||||
|
const client = new PocketBase(import.meta.env.PB_BACKEND_URL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ApiClient.users.confirmEmailChange(params?.token, password);
|
await client.users.confirmEmailChange(params?.token, password);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ApiClient.errorResponseHandler(err);
|
ApiClient.errorResponseHandler(err);
|
||||||
|
@ -45,13 +49,13 @@
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
<form on:submit|preventDefault={submit}>
|
<form on:submit|preventDefault={submit}>
|
||||||
<div class="content txt-center m-b-sm">
|
<div class="content txt-center m-b-base">
|
||||||
<h4 class="m-b-xs">
|
<h5>
|
||||||
Type your password to confirm changing your email address
|
Type your password to confirm changing your email address
|
||||||
{#if newEmail}
|
{#if newEmail}
|
||||||
to <strong class="txt-nowrap">{newEmail}</strong>
|
to <strong class="txt-nowrap">{newEmail}</strong>
|
||||||
{/if}
|
{/if}
|
||||||
</h4>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Field class="form-field required" name="password" let:uniqueId>
|
<Field class="form-field required" name="password" let:uniqueId>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import PocketBase from "pocketbase";
|
||||||
import ApiClient from "@/utils/ApiClient";
|
import ApiClient from "@/utils/ApiClient";
|
||||||
import CommonHelper from "@/utils/CommonHelper";
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
import FullPage from "@/components/base/FullPage.svelte";
|
import FullPage from "@/components/base/FullPage.svelte";
|
||||||
|
@ -20,8 +21,11 @@
|
||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
|
// init a custom client to avoid interfering with the admin state
|
||||||
|
const client = new PocketBase(import.meta.env.PB_BACKEND_URL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ApiClient.users.confirmPasswordReset(params?.token, newPassword, newPasswordConfirm);
|
await client.users.confirmPasswordReset(params?.token, newPassword, newPasswordConfirm);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ApiClient.errorResponseHandler(err);
|
ApiClient.errorResponseHandler(err);
|
||||||
|
@ -46,13 +50,13 @@
|
||||||
</button>
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
<form on:submit|preventDefault={submit}>
|
<form on:submit|preventDefault={submit}>
|
||||||
<div class="content txt-center m-b-sm">
|
<div class="content txt-center m-b-base">
|
||||||
<h4 class="m-b-xs">
|
<h5>
|
||||||
Reset your user password
|
Reset your user password
|
||||||
{#if email}
|
{#if email}
|
||||||
for <strong>{email}</strong>
|
for <strong>{email}</strong>
|
||||||
{/if}
|
{/if}
|
||||||
</h4>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Field class="form-field required" name="password" let:uniqueId>
|
<Field class="form-field required" name="password" let:uniqueId>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import ApiClient from "@/utils/ApiClient";
|
import PocketBase from "pocketbase";
|
||||||
import FullPage from "@/components/base/FullPage.svelte";
|
import FullPage from "@/components/base/FullPage.svelte";
|
||||||
|
|
||||||
export let params;
|
export let params;
|
||||||
|
@ -12,11 +12,13 @@
|
||||||
async function send() {
|
async function send() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
|
// init a custom client to avoid interfering with the admin state
|
||||||
|
const client = new PocketBase(import.meta.env.PB_BACKEND_URL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ApiClient.users.confirmVerification(params?.token);
|
await client.users.confirmVerification(params?.token);
|
||||||
success = true;
|
success = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(err);
|
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,37 +66,19 @@ const routes = {
|
||||||
|
|
||||||
"/users/confirm-password-reset/:token": wrap({
|
"/users/confirm-password-reset/:token": wrap({
|
||||||
asyncComponent: () => import("@/components/users/PageUserConfirmPasswordReset.svelte"),
|
asyncComponent: () => import("@/components/users/PageUserConfirmPasswordReset.svelte"),
|
||||||
conditions: baseConditions.concat([
|
conditions: baseConditions,
|
||||||
() => {
|
|
||||||
// ensure that there is no authenticated user/admin model
|
|
||||||
ApiClient.logout(false);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
userData: { showAppSidebar: false },
|
userData: { showAppSidebar: false },
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"/users/confirm-verification/:token": wrap({
|
"/users/confirm-verification/:token": wrap({
|
||||||
asyncComponent: () => import("@/components/users/PageUserConfirmVerification.svelte"),
|
asyncComponent: () => import("@/components/users/PageUserConfirmVerification.svelte"),
|
||||||
conditions: baseConditions.concat([
|
conditions: baseConditions,
|
||||||
() => {
|
|
||||||
// ensure that there is no authenticated user/admin model
|
|
||||||
ApiClient.logout(false);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
userData: { showAppSidebar: false },
|
userData: { showAppSidebar: false },
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"/users/confirm-email-change/:token": wrap({
|
"/users/confirm-email-change/:token": wrap({
|
||||||
asyncComponent: () => import("@/components/users/PageUserConfirmEmailChange.svelte"),
|
asyncComponent: () => import("@/components/users/PageUserConfirmEmailChange.svelte"),
|
||||||
conditions: baseConditions.concat([
|
conditions: baseConditions,
|
||||||
() => {
|
|
||||||
// ensure that there is no authenticated user/admin model
|
|
||||||
ApiClient.logout(false);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
userData: { showAppSidebar: false },
|
userData: { showAppSidebar: false },
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
@ -51,3 +50,47 @@
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes entranceLeft {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-5px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes entranceRight {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes entranceTop {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes entranceBottom {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -692,3 +692,17 @@ a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// base entrance animations
|
||||||
|
.entrance-top {
|
||||||
|
animation: entranceTop var(--entranceAnimationSpeed);
|
||||||
|
}
|
||||||
|
.entrance-bottom {
|
||||||
|
animation: entranceBottom var(--entranceAnimationSpeed);
|
||||||
|
}
|
||||||
|
.entrance-left {
|
||||||
|
animation: entranceLeft var(--entranceAnimationSpeed);
|
||||||
|
}
|
||||||
|
.entrance-right {
|
||||||
|
animation: entranceRight var(--entranceAnimationSpeed);
|
||||||
|
}
|
||||||
|
|
|
@ -628,11 +628,16 @@ select {
|
||||||
input[type="radio"] {
|
input[type="radio"] {
|
||||||
& ~ label:before {
|
& ~ label:before {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-size: 0.5rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
&:checked ~ label:before {
|
}
|
||||||
content: '\eb7c';
|
|
||||||
color: #fff;
|
.form-field-block {
|
||||||
|
@extend %block;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 0 var(--xsSpacing);
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,5 +1051,8 @@ select {
|
||||||
.cm-selectionMatch {
|
.cm-selectionMatch {
|
||||||
background: var(--infoAltColor);
|
background: var(--infoAltColor);
|
||||||
}
|
}
|
||||||
|
&.cm-focused .cm-matchingBracket {
|
||||||
|
background-color: rgba(50, 140, 130, 0.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
|
|
||||||
--baseAnimationSpeed: 150ms;
|
--baseAnimationSpeed: 150ms;
|
||||||
--activeAnimationSpeed: 70ms;
|
--activeAnimationSpeed: 70ms;
|
||||||
|
--entranceAnimationSpeed: 250ms;
|
||||||
|
|
||||||
--baseRadius: 3px;
|
--baseRadius: 3px;
|
||||||
--lgRadius: 12px;
|
--lgRadius: 12px;
|
||||||
|
|
|
@ -47,7 +47,7 @@ export function removeToast(messageOrToast) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeAll() {
|
export function removeAllToasts() {
|
||||||
toasts.update((t) => {
|
toasts.update((t) => {
|
||||||
for (let toast of t) {
|
for (let toast of t) {
|
||||||
removeToastFromArray(t, toast);
|
removeToastFromArray(t, toast);
|
||||||
|
|
Loading…
Reference in New Issue