Merge pull request #209 from authorizerdev/feat/send-email-based-on-template
feat: send email based on template
This commit is contained in:
commit
5c6e643efb
21
dashboard/package-lock.json
generated
21
dashboard/package-lock.json
generated
|
@ -2798,7 +2798,8 @@
|
||||||
"@chakra-ui/css-reset": {
|
"@chakra-ui/css-reset": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
||||||
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg=="
|
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@chakra-ui/descendant": {
|
"@chakra-ui/descendant": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
|
@ -3402,7 +3403,8 @@
|
||||||
"@graphql-typed-document-node/core": {
|
"@graphql-typed-document-node/core": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
||||||
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
|
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@popperjs/core": {
|
"@popperjs/core": {
|
||||||
"version": "2.11.0",
|
"version": "2.11.0",
|
||||||
|
@ -3739,7 +3741,8 @@
|
||||||
"draft-js-utils": {
|
"draft-js-utils": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/draft-js-utils/-/draft-js-utils-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/draft-js-utils/-/draft-js-utils-1.4.1.tgz",
|
||||||
"integrity": "sha512-xE81Y+z/muC5D5z9qWmKfxEW1XyXfsBzSbSBk2JRsoD0yzMGGHQm/0MtuqHl/EUDkaBJJLjJ2EACycoDMY/OOg=="
|
"integrity": "sha512-xE81Y+z/muC5D5z9qWmKfxEW1XyXfsBzSbSBk2JRsoD0yzMGGHQm/0MtuqHl/EUDkaBJJLjJ2EACycoDMY/OOg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"draftjs-to-html": {
|
"draftjs-to-html": {
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
|
@ -3749,7 +3752,8 @@
|
||||||
"draftjs-utils": {
|
"draftjs-utils": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/draftjs-utils/-/draftjs-utils-0.10.2.tgz",
|
||||||
"integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg=="
|
"integrity": "sha512-EstHqr3R3JVcilJrBaO/A+01GvwwKmC7e4TCjC7S94ZeMh4IVmf60OuQXtHHpwItK8C2JCi3iljgN5KHkJboUg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"error-ex": {
|
"error-ex": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
|
@ -4043,7 +4047,8 @@
|
||||||
"html-to-draftjs": {
|
"html-to-draftjs": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-to-draftjs/-/html-to-draftjs-1.5.0.tgz",
|
||||||
"integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ=="
|
"integrity": "sha512-kggLXBNciKDwKf+KYsuE+V5gw4dZ7nHyGMX9m0wy7urzWjKGWyNFetmArRLvRV0VrxKN70WylFsJvMTJx02OBQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"immutable": {
|
"immutable": {
|
||||||
"version": "3.7.6",
|
"version": "3.7.6",
|
||||||
|
@ -4272,7 +4277,8 @@
|
||||||
"react-icons": {
|
"react-icons": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
||||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
|
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
|
@ -4483,7 +4489,8 @@
|
||||||
"use-callback-ref": {
|
"use-callback-ref": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
||||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg=="
|
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"use-sidecar": {
|
"use-sidecar": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
|
|
|
@ -62,8 +62,7 @@ interface validatorDataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
const initTemplateData: emailTemplateDataType = {
|
const initTemplateData: emailTemplateDataType = {
|
||||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
|
||||||
emailTemplateEventNames.BASIC_AUTH_SIGNUP,
|
|
||||||
[EmailTemplateInputDataFields.SUBJECT]: '',
|
[EmailTemplateInputDataFields.SUBJECT]: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -206,10 +205,10 @@ const UpdateEmailTemplate = ({
|
||||||
).reduce((acc, varData): any => {
|
).reduce((acc, varData): any => {
|
||||||
if (
|
if (
|
||||||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
|
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
|
||||||
emailTemplateEventNames.VERIFY_OTP &&
|
emailTemplateEventNames['Verify Otp'] &&
|
||||||
varData[1] === emailTemplateVariables.otp) ||
|
varData[1] === emailTemplateVariables.otp) ||
|
||||||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] ===
|
(templateData[EmailTemplateInputDataFields.EVENT_NAME] ===
|
||||||
emailTemplateEventNames.VERIFY_OTP &&
|
emailTemplateEventNames['Verify Otp'] &&
|
||||||
varData[1] === emailTemplateVariables.verification_url)
|
varData[1] === emailTemplateVariables.verification_url)
|
||||||
) {
|
) {
|
||||||
return acc;
|
return acc;
|
||||||
|
|
|
@ -94,7 +94,7 @@ interface validatorDataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
const initWebhookData: webhookDataType = {
|
const initWebhookData: webhookDataType = {
|
||||||
[WebhookInputDataFields.EVENT_NAME]: webhookEventNames.USER_LOGIN,
|
[WebhookInputDataFields.EVENT_NAME]: webhookEventNames['User login'],
|
||||||
[WebhookInputDataFields.ENDPOINT]: '',
|
[WebhookInputDataFields.ENDPOINT]: '',
|
||||||
[WebhookInputDataFields.ENABLED]: true,
|
[WebhookInputDataFields.ENABLED]: true,
|
||||||
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
[WebhookInputDataFields.HEADERS]: [{ ...initHeadersData }],
|
||||||
|
|
|
@ -183,20 +183,21 @@ export enum UpdateModalViews {
|
||||||
export const pageLimits: number[] = [5, 10, 15];
|
export const pageLimits: number[] = [5, 10, 15];
|
||||||
|
|
||||||
export const webhookEventNames = {
|
export const webhookEventNames = {
|
||||||
USER_SIGNUP: 'user.signup',
|
'User signup': 'user.signup',
|
||||||
USER_CREATED: 'user.created',
|
'User created': 'user.created',
|
||||||
USER_LOGIN: 'user.login',
|
'User login': 'user.login',
|
||||||
USER_DELETED: 'user.deleted',
|
'User deleted': 'user.deleted',
|
||||||
USER_ACCESS_ENABLED: 'user.access_enabled',
|
'User access enabled': 'user.access_enabled',
|
||||||
USER_ACCESS_REVOKED: 'user.access_revoked',
|
'User access revoked': 'user.access_revoked',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const emailTemplateEventNames = {
|
export const emailTemplateEventNames = {
|
||||||
BASIC_AUTH_SIGNUP: 'basic_auth_signup',
|
Signup: 'basic_auth_signup',
|
||||||
MAGIC_LINK_LOGIN: 'magic_link_login',
|
'Magic Link Login': 'magic_link_login',
|
||||||
UPDATE_EMAIL: 'update_email',
|
'Update Email': 'update_email',
|
||||||
FORGOT_PASSWORD: 'forgot_password',
|
'Forgot Password': 'forgot_password',
|
||||||
VERIFY_OTP: 'verify_otp',
|
'Verify Otp': 'verify_otp',
|
||||||
|
'Invite member': 'invite_member',
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum webhookVerifiedStatus {
|
export enum webhookVerifiedStatus {
|
||||||
|
@ -206,27 +207,27 @@ export enum webhookVerifiedStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emailTemplateVariables = {
|
export const emailTemplateVariables = {
|
||||||
'user.id': '{user.id}}',
|
'user.id': '{.user.id}}',
|
||||||
'user.email': '{user.email}}',
|
'user.email': '{.user.email}}',
|
||||||
'user.given_name': '{user.given_name}}',
|
'user.given_name': '{.user.given_name}}',
|
||||||
'user.family_name': '{user.family_name}}',
|
'user.family_name': '{.user.family_name}}',
|
||||||
'user.signup_methods': '{user.signup_methods}}',
|
'user.signup_methods': '{.user.signup_methods}}',
|
||||||
'user.email_verified': '{user.email_verified}}',
|
'user.email_verified': '{.user.email_verified}}',
|
||||||
'user.picture': '{user.picture}}',
|
'user.picture': '{.user.picture}}',
|
||||||
'user.roles': '{user.roles}}',
|
'user.roles': '{.user.roles}}',
|
||||||
'user.middle_name': '{user.middle_name}}',
|
'user.middle_name': '{.user.middle_name}}',
|
||||||
'user.nickname': '{user.nickname}}',
|
'user.nickname': '{.user.nickname}}',
|
||||||
'user.preferred_username': '{user.preferred_username}}',
|
'user.preferred_username': '{.user.preferred_username}}',
|
||||||
'user.gender': '{user.gender}}',
|
'user.gender': '{.user.gender}}',
|
||||||
'user.birthdate': '{user.birthdate}}',
|
'user.birthdate': '{.user.birthdate}}',
|
||||||
'user.phone_number': '{user.phone_number}}',
|
'user.phone_number': '{.user.phone_number}}',
|
||||||
'user.phone_number_verified': '{user.phone_number_verified}}',
|
'user.phone_number_verified': '{.user.phone_number_verified}}',
|
||||||
'user.created_at': '{user.created_at}}',
|
'user.created_at': '{.user.created_at}}',
|
||||||
'user.updated_at': '{user.updated_at}}',
|
'user.updated_at': '{.user.updated_at}}',
|
||||||
'organization.name': '{organization.name}}',
|
'organization.name': '{.organization.name}}',
|
||||||
'organization.logo': '{organization.logo}}',
|
'organization.logo': '{.organization.logo}}',
|
||||||
verification_url: '{verification_url}}',
|
verification_url: '{.verification_url}}',
|
||||||
otp: '{otp}}',
|
otp: '{.otp}}',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const webhookPayloadExample: string = `{
|
export const webhookPayloadExample: string = `{
|
||||||
|
|
|
@ -126,7 +126,7 @@ export const WebhooksDataQuery = `
|
||||||
export const EmailTemplatesQuery = `
|
export const EmailTemplatesQuery = `
|
||||||
query getEmailTemplates($params: PaginatedInput!) {
|
query getEmailTemplates($params: PaginatedInput!) {
|
||||||
_email_templates(params: $params) {
|
_email_templates(params: $params) {
|
||||||
EmailTemplates {
|
email_templates {
|
||||||
id
|
id
|
||||||
event_name
|
event_name
|
||||||
subject
|
subject
|
||||||
|
|
|
@ -40,7 +40,7 @@ import {
|
||||||
UpdateModalViews,
|
UpdateModalViews,
|
||||||
EmailTemplateInputDataFields,
|
EmailTemplateInputDataFields,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { EmailTemplatesQuery, WebhooksDataQuery } from '../graphql/queries';
|
import { EmailTemplatesQuery } from '../graphql/queries';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import DeleteEmailTemplateModal from '../components/DeleteEmailTemplateModal';
|
import DeleteEmailTemplateModal from '../components/DeleteEmailTemplateModal';
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ const EmailTemplates = () => {
|
||||||
})
|
})
|
||||||
.toPromise();
|
.toPromise();
|
||||||
if (res.data?._email_templates) {
|
if (res.data?._email_templates) {
|
||||||
const { pagination, EmailTemplates: emailTemplates } =
|
const { pagination, email_templates: emailTemplates } =
|
||||||
res.data?._email_templates;
|
res.data?._email_templates;
|
||||||
const maxPages = getMaxPages(pagination);
|
const maxPages = getMaxPages(pagination);
|
||||||
if (emailTemplates?.length) {
|
if (emailTemplates?.length) {
|
||||||
|
|
|
@ -9,4 +9,8 @@ const (
|
||||||
VerificationTypeUpdateEmail = "update_email"
|
VerificationTypeUpdateEmail = "update_email"
|
||||||
// VerificationTypeForgotPassword is the forgot_password verification type
|
// VerificationTypeForgotPassword is the forgot_password verification type
|
||||||
VerificationTypeForgotPassword = "forgot_password"
|
VerificationTypeForgotPassword = "forgot_password"
|
||||||
|
// VerificationTypeInviteMember is the invite_member verification type
|
||||||
|
VerificationTypeInviteMember = "invite_member"
|
||||||
|
// VerificationTypeOTP is the otp verification type
|
||||||
|
VerificationTypeOTP = "otp"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
@ -64,3 +65,10 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) ToMap() map[string]interface{} {
|
||||||
|
res := map[string]interface{}{}
|
||||||
|
data, _ := json.Marshal(user) // Convert to a json string
|
||||||
|
json.Unmarshal(data, &res) // Convert to a map
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ package email
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
@ -11,27 +11,75 @@ import (
|
||||||
gomail "gopkg.in/mail.v2"
|
gomail "gopkg.in/mail.v2"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// addEmailTemplate is used to add html template in email body
|
func getDefaultTemplate(event string) *model.EmailTemplate {
|
||||||
func addEmailTemplate(a string, b map[string]interface{}, templateName string) string {
|
switch event {
|
||||||
tmpl, err := template.New(templateName).Parse(a)
|
case constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeMagicLinkLogin:
|
||||||
if err != nil {
|
return &model.EmailTemplate{
|
||||||
output, _ := json.Marshal(b)
|
Subject: emailVerificationSubject,
|
||||||
return string(output)
|
Template: emailVerificationTemplate,
|
||||||
}
|
}
|
||||||
buf := &bytes.Buffer{}
|
case constants.VerificationTypeForgotPassword:
|
||||||
err = tmpl.Execute(buf, b)
|
return &model.EmailTemplate{
|
||||||
if err != nil {
|
Subject: forgotPasswordSubject,
|
||||||
panic(err)
|
Template: forgotPasswordTemplate,
|
||||||
|
}
|
||||||
|
case constants.VerificationTypeInviteMember:
|
||||||
|
return &model.EmailTemplate{
|
||||||
|
Subject: inviteEmailSubject,
|
||||||
|
Template: inviteEmailTemplate,
|
||||||
|
}
|
||||||
|
case constants.VerificationTypeOTP:
|
||||||
|
return &model.EmailTemplate{
|
||||||
|
Subject: otpEmailSubject,
|
||||||
|
Template: otpEmailTemplate,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
s := buf.String()
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMail function to send mail
|
func getEmailTemplate(event string, data map[string]interface{}) (*model.EmailTemplate, error) {
|
||||||
func SendMail(to []string, Subject, bodyMessage string) error {
|
ctx := context.Background()
|
||||||
|
tmp, err := db.Provider.GetEmailTemplateByEventName(ctx, event)
|
||||||
|
if err != nil || tmp == nil {
|
||||||
|
tmp = getDefaultTemplate(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
templ, err := template.New(event + "_template.tmpl").Parse(tmp.Template)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err = templ.Execute(buf, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
templateString := buf.String()
|
||||||
|
|
||||||
|
subject, err := template.New(event + "_subject.tmpl").Parse(tmp.Subject)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf = &bytes.Buffer{}
|
||||||
|
err = subject.Execute(buf, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
subjectString := buf.String()
|
||||||
|
|
||||||
|
return &model.EmailTemplate{
|
||||||
|
Template: templateString,
|
||||||
|
Subject: subjectString,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendEmail function to send mail
|
||||||
|
func SendEmail(to []string, event string, data map[string]interface{}) error {
|
||||||
// dont trigger email sending in case of test
|
// dont trigger email sending in case of test
|
||||||
envKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEnv)
|
envKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -40,6 +88,13 @@ func SendMail(to []string, Subject, bodyMessage string) error {
|
||||||
if envKey == constants.TestEnv {
|
if envKey == constants.TestEnv {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp, err := getEmailTemplate(event, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get event template: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
m := gomail.NewMessage()
|
m := gomail.NewMessage()
|
||||||
senderEmail, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderEmail)
|
senderEmail, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeySenderEmail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -79,8 +134,8 @@ func SendMail(to []string, Subject, bodyMessage string) error {
|
||||||
|
|
||||||
m.SetHeader("From", senderEmail)
|
m.SetHeader("From", senderEmail)
|
||||||
m.SetHeader("To", to...)
|
m.SetHeader("To", to...)
|
||||||
m.SetHeader("Subject", Subject)
|
m.SetHeader("Subject", tmp.Subject)
|
||||||
m.SetBody("text/html", bodyMessage)
|
m.SetBody("text/html", tmp.Template)
|
||||||
port, _ := strconv.Atoi(smtpPort)
|
port, _ := strconv.Atoi(smtpPort)
|
||||||
d := gomail.NewDialer(smtpHost, port, smtpUsername, smtpPassword)
|
d := gomail.NewDialer(smtpHost, port, smtpUsername, smtpPassword)
|
||||||
if !isProd {
|
if !isProd {
|
||||||
|
|
|
@ -1,19 +1,8 @@
|
||||||
package email
|
package email
|
||||||
|
|
||||||
import (
|
const (
|
||||||
log "github.com/sirupsen/logrus"
|
emailVerificationSubject = "Please verify your email"
|
||||||
|
emailVerificationTemplate = `
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SendVerificationMail to send verification email
|
|
||||||
func SendVerificationMail(toEmail, token, hostname string) error {
|
|
||||||
// The receiver needs to be in slice as the receive supports multiple receiver
|
|
||||||
Receiver := []string{toEmail}
|
|
||||||
|
|
||||||
Subject := "Please verify your email"
|
|
||||||
message := `
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
<head>
|
<head>
|
||||||
|
@ -98,23 +87,4 @@ func SendVerificationMail(toEmail, token, hostname string) error {
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
data := make(map[string]interface{}, 3)
|
)
|
||||||
var err error
|
|
||||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["verification_url"] = hostname + "/verify_email?token=" + token
|
|
||||||
message = addEmailTemplate(message, data, "verify_email.tmpl")
|
|
||||||
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
|
||||||
|
|
||||||
err = SendMail(Receiver, Subject, message)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("error sending email: ", err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,28 +1,8 @@
|
||||||
package email
|
package email
|
||||||
|
|
||||||
import (
|
const (
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
forgotPasswordSubject = "Reset Password"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
forgotPasswordTemplate = `
|
||||||
)
|
|
||||||
|
|
||||||
// SendForgotPasswordMail to send forgot password email
|
|
||||||
func SendForgotPasswordMail(toEmail, token, hostname string) error {
|
|
||||||
resetPasswordUrl, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if resetPasswordUrl == "" {
|
|
||||||
if err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The receiver needs to be in slice as the receive supports multiple receiver
|
|
||||||
Receiver := []string{toEmail}
|
|
||||||
|
|
||||||
Subject := "Reset Password"
|
|
||||||
|
|
||||||
message := `
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
<head>
|
<head>
|
||||||
|
@ -73,13 +53,13 @@ func SendForgotPasswordMail(toEmail, token, hostname string) error {
|
||||||
<table width="100%%" cellspacing="0" cellpadding="0">
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||||
<p>Hey there 👋</p>
|
<p>Hey there 👋</p>
|
||||||
<p>We have received a request to reset password for email: <b>{{.org_name}}</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
|
<p>We have received a request to reset password for email: <b>{{.organization.name}}</b>. If this is correct, please reset the password clicking the button below.</p> <br/>
|
||||||
<a clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
|
<a clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Reset Password</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -106,18 +86,4 @@ func SendForgotPasswordMail(toEmail, token, hostname string) error {
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
)
|
||||||
data := make(map[string]interface{}, 3)
|
|
||||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["verification_url"] = resetPasswordUrl + "?token=" + token
|
|
||||||
message = addEmailTemplate(message, data, "reset_password_email.tmpl")
|
|
||||||
|
|
||||||
return SendMail(Receiver, Subject, message)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +1,8 @@
|
||||||
package email
|
package email
|
||||||
|
|
||||||
import (
|
const (
|
||||||
log "github.com/sirupsen/logrus"
|
inviteEmailSubject = "Please accept the invitation"
|
||||||
|
inviteEmailTemplate = `
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InviteEmail to send invite email
|
|
||||||
func InviteEmail(toEmail, token, verificationURL, redirectURI string) error {
|
|
||||||
// The receiver needs to be in slice as the receive supports multiple receiver
|
|
||||||
Receiver := []string{toEmail}
|
|
||||||
|
|
||||||
Subject := "Please accept the invitation"
|
|
||||||
message := `
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
<head>
|
<head>
|
||||||
|
@ -64,13 +53,13 @@ func InviteEmail(toEmail, token, verificationURL, redirectURI string) error {
|
||||||
<table width="100%%" cellspacing="0" cellpadding="0">
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||||
<p>Hi there 👋</p>
|
<p>Hi there 👋</p>
|
||||||
<p>Join us! You are invited to sign-up for <b>{{.org_name}}</b>. Please accept the invitation by clicking the button below.</p> <br/>
|
<p>Join us! You are invited to sign-up for <b>{{.organization.name}}</b>. Please accept the invitation by clicking the button below.</p> <br/>
|
||||||
<a
|
<a
|
||||||
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Get Started</a>
|
clicktracking="off" href="{{.verification_url}}" class="es-button" target="_blank" style="text-decoration: none;padding:10px 15px;background-color: rgba(59,130,246,1);color: #fff;font-size: 1em;border-radius:5px;">Get Started</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -98,23 +87,4 @@ func InviteEmail(toEmail, token, verificationURL, redirectURI string) error {
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
data := make(map[string]interface{}, 3)
|
)
|
||||||
var err error
|
|
||||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["verification_url"] = verificationURL + "?token=" + token + "&redirect_uri=" + redirectURI
|
|
||||||
message = addEmailTemplate(message, data, "invite_email.tmpl")
|
|
||||||
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
|
||||||
|
|
||||||
err = SendMail(Receiver, Subject, message)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("error sending email: ", err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +1,8 @@
|
||||||
package email
|
package email
|
||||||
|
|
||||||
import (
|
const (
|
||||||
log "github.com/sirupsen/logrus"
|
otpEmailSubject = "OTP for your multi factor authentication"
|
||||||
|
otpEmailTemplate = `
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SendOtpMail to send otp email
|
|
||||||
func SendOtpMail(toEmail, otp string) error {
|
|
||||||
// The receiver needs to be in slice as the receive supports multiple receiver
|
|
||||||
Receiver := []string{toEmail}
|
|
||||||
|
|
||||||
Subject := "OTP for your multi factor authentication"
|
|
||||||
message := `
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
<head>
|
<head>
|
||||||
|
@ -64,13 +53,13 @@ func SendOtpMail(toEmail, otp string) error {
|
||||||
<table width="100%%" cellspacing="0" cellpadding="0">
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.organization.logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||||
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||||
<p>Hey there 👋</p>
|
<p>Hey there 👋</p>
|
||||||
<b>{{.otp}}</b> is your one time password (OTP) for accessing {{.org_name}}. Please keep your OTP confidential and it will expire in 1 minute.
|
<b>{{.otp}}</b> is your one time password (OTP) for accessing {{.organization.name}}. Please keep your OTP confidential and it will expire in 1 minute.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -96,23 +85,4 @@ func SendOtpMail(toEmail, otp string) error {
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
data := make(map[string]interface{}, 3)
|
)
|
||||||
var err error
|
|
||||||
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data["otp"] = otp
|
|
||||||
message = addEmailTemplate(message, data, "otp.tmpl")
|
|
||||||
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
|
||||||
|
|
||||||
err = SendMail(Receiver, Subject, message)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("error sending email: ", err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
1
server/email/utils.go
Normal file
1
server/email/utils.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package email
|
|
@ -441,7 +441,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.EmailTemplate.UpdatedAt(childComplexity), true
|
return e.complexity.EmailTemplate.UpdatedAt(childComplexity), true
|
||||||
|
|
||||||
case "EmailTemplates.EmailTemplates":
|
case "EmailTemplates.email_templates":
|
||||||
if e.complexity.EmailTemplates.EmailTemplates == nil {
|
if e.complexity.EmailTemplates.EmailTemplates == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -2066,7 +2066,7 @@ type EmailTemplate {
|
||||||
|
|
||||||
type EmailTemplates {
|
type EmailTemplates {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
EmailTemplates: [EmailTemplate!]!
|
email_templates: [EmailTemplate!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEnvInput {
|
input UpdateEnvInput {
|
||||||
|
@ -3404,7 +3404,7 @@ func (ec *executionContext) _EmailTemplates_pagination(ctx context.Context, fiel
|
||||||
return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res)
|
return ec.marshalNPagination2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐPagination(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _EmailTemplates_EmailTemplates(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplates) (ret graphql.Marshaler) {
|
func (ec *executionContext) _EmailTemplates_email_templates(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplates) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
@ -12198,8 +12198,8 @@ func (ec *executionContext) _EmailTemplates(ctx context.Context, sel ast.Selecti
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
case "EmailTemplates":
|
case "email_templates":
|
||||||
out.Values[i] = ec._EmailTemplates_EmailTemplates(ctx, field, obj)
|
out.Values[i] = ec._EmailTemplates_email_templates(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ type EmailTemplate struct {
|
||||||
|
|
||||||
type EmailTemplates struct {
|
type EmailTemplates struct {
|
||||||
Pagination *Pagination `json:"pagination"`
|
Pagination *Pagination `json:"pagination"`
|
||||||
EmailTemplates []*EmailTemplate `json:"EmailTemplates"`
|
EmailTemplates []*EmailTemplate `json:"email_templates"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Env struct {
|
type Env struct {
|
||||||
|
|
|
@ -201,7 +201,7 @@ type EmailTemplate {
|
||||||
|
|
||||||
type EmailTemplates {
|
type EmailTemplates {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
EmailTemplates: [EmailTemplate!]!
|
email_templates: [EmailTemplate!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEnvInput {
|
input UpdateEnvInput {
|
||||||
|
|
|
@ -14,8 +14,6 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO add template validator
|
|
||||||
|
|
||||||
// AddEmailTemplateResolver resolver for add email template mutation
|
// AddEmailTemplateResolver resolver for add email template mutation
|
||||||
func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplateRequest) (*model.Response, error) {
|
func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplateRequest) (*model.Response, error) {
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
|
|
@ -49,7 +49,7 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"email": params.Email,
|
"email": params.Email,
|
||||||
})
|
})
|
||||||
_, err = db.Provider.GetUserByEmail(ctx, params.Email)
|
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("User not found: ", err)
|
log.Debug("User not found: ", err)
|
||||||
return res, fmt.Errorf(`user with this email not found`)
|
return res, fmt.Errorf(`user with this email not found`)
|
||||||
|
@ -84,8 +84,12 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routin so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go email.SendForgotPasswordMail(params.Email, verificationToken, hostname)
|
go email.SendEmail([]string{params.Email}, constants.VerificationTypeForgotPassword, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetForgotPasswordURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
|
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
Message: `Please check your inbox! We have sent a password reset link.`,
|
Message: `Please check your inbox! We have sent a password reset link.`,
|
||||||
|
|
|
@ -115,7 +115,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURL)
|
verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeInviteMember, hostname, nonceHash, redirectURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to create verification token: ", err)
|
log.Debug("Failed to create verification token: ", err)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
|
||||||
} else {
|
} else {
|
||||||
// use basic authentication if that option is on
|
// use basic authentication if that option is on
|
||||||
user.SignupMethods = constants.AuthRecipeMethodBasicAuth
|
user.SignupMethods = constants.AuthRecipeMethodBasicAuth
|
||||||
verificationRequest.Identifier = constants.VerificationTypeForgotPassword
|
verificationRequest.Identifier = constants.VerificationTypeInviteMember
|
||||||
|
|
||||||
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -162,7 +162,12 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go emailservice.InviteEmail(email, verificationToken, verifyEmailURL, redirectURL)
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
go emailservice.SendEmail([]string{user.Email}, constants.VerificationTypeInviteMember, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetInviteVerificationURL(verifyEmailURL, verificationToken, redirectURL),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &model.Response{
|
return &model.Response{
|
||||||
|
|
|
@ -123,7 +123,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := email.SendOtpMail(user.Email, otpData.Otp)
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
go email.SendEmail([]string{params.Email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"otp": otpData.Otp,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to send otp email: ", err)
|
log.Debug("Failed to send otp email: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,8 +219,12 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routing so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go email.SendVerificationMail(params.Email, verificationToken, hostname)
|
go email.SendEmail([]string{params.Email}, constants.VerificationTypeMagicLinkLogin, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetEmailVerificationURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
|
|
|
@ -84,7 +84,12 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := email.SendOtpMail(params.Email, otp)
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
go email.SendEmail([]string{params.Email}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"otp": otp,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error sending otp email: ", otp)
|
log.Debug("Error sending otp email: ", otp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,11 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
|
||||||
return res, fmt.Errorf("invalid identifier")
|
return res, fmt.Errorf("invalid identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
||||||
|
if err != nil {
|
||||||
|
return res, fmt.Errorf("invalid user")
|
||||||
|
}
|
||||||
|
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, params.Email, params.Identifier)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, params.Email, params.Identifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get verification request: ", err)
|
log.Debug("Failed to get verification request: ", err)
|
||||||
|
@ -74,8 +79,12 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
|
||||||
log.Debug("Failed to add verification request: ", err)
|
log.Debug("Failed to add verification request: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routin so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go email.SendVerificationMail(params.Email, verificationToken, hostname)
|
go email.SendEmail([]string{params.Email}, params.Identifier, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetEmailVerificationURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
|
|
||||||
res = &model.Response{
|
res = &model.Response{
|
||||||
Message: `Verification email has been sent. Please check your inbox`,
|
Message: `Verification email has been sent. Please check your inbox`,
|
||||||
|
|
|
@ -221,9 +221,14 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routin so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go func() {
|
go func() {
|
||||||
email.SendVerificationMail(params.Email, verificationToken, hostname)
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
email.SendEmail([]string{params.Email}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetEmailVerificationURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
utils.RegisterEvent(ctx, constants.UserCreatedWebhookEvent, constants.AuthRecipeMethodBasicAuth, user)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,6 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO add template validator
|
|
||||||
|
|
||||||
// UpdateEmailTemplateResolver resolver for update email template mutation
|
// UpdateEmailTemplateResolver resolver for update email template mutation
|
||||||
func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTemplateRequest) (*model.Response, error) {
|
func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTemplateRequest) (*model.Response, error) {
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
|
|
@ -244,8 +244,12 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routin so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go email.SendVerificationMail(newEmail, verificationToken, hostname)
|
go email.SendEmail([]string{user.Email}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetEmailVerificationURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,8 +156,12 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec it as go routin so that we can reduce the api latency
|
// exec it as go routine so that we can reduce the api latency
|
||||||
go email.SendVerificationMail(newEmail, verificationToken, hostname)
|
go email.SendEmail([]string{user.Email}, constants.VerificationTypeBasicAuthSignup, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"verification_url": utils.GetEmailVerificationURL(verificationToken, hostname),
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StringSliceContains checks if a string slice contains a particular string
|
// StringSliceContains checks if a string slice contains a particular string
|
||||||
|
@ -58,3 +61,46 @@ func ConvertInterfaceToStringSlice(slice interface{}) []string {
|
||||||
}
|
}
|
||||||
return resSlice
|
return resSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOrganization to get organization object
|
||||||
|
func GetOrganization() map[string]interface{} {
|
||||||
|
orgLogo, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
orgName, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
organization := map[string]interface{}{
|
||||||
|
"name": orgName,
|
||||||
|
"logo": orgLogo,
|
||||||
|
}
|
||||||
|
|
||||||
|
return organization
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForgotPasswordURL to get url for given token and hostname
|
||||||
|
func GetForgotPasswordURL(token, hostname string) string {
|
||||||
|
resetPasswordUrl, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyResetPasswordURL)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if resetPasswordUrl == "" {
|
||||||
|
if err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyResetPasswordURL, hostname+"/app/reset-password"); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verificationURL := resetPasswordUrl + "?token=" + token
|
||||||
|
return verificationURL
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInviteVerificationURL to get url for invite email verification
|
||||||
|
func GetInviteVerificationURL(verificationURL, token, redirectURI string) string {
|
||||||
|
return verificationURL + "?token=" + token + "&redirect_uri=" + redirectURI
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmailVerificationURL to get url for invite email verification
|
||||||
|
func GetEmailVerificationURL(token, hostname string) string {
|
||||||
|
return hostname + "/verify_email?token=" + token
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import "github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
|
||||||
// IsValidEmailTemplateEventName function to validate email template events
|
// IsValidEmailTemplateEventName function to validate email template events
|
||||||
func IsValidEmailTemplateEventName(eventName string) bool {
|
func IsValidEmailTemplateEventName(eventName string) bool {
|
||||||
if eventName != constants.VerificationTypeBasicAuthSignup && eventName != constants.VerificationTypeForgotPassword && eventName != constants.VerificationTypeMagicLinkLogin && eventName != constants.VerificationTypeUpdateEmail {
|
if eventName != constants.VerificationTypeBasicAuthSignup && eventName != constants.VerificationTypeForgotPassword && eventName != constants.VerificationTypeMagicLinkLogin && eventName != constants.VerificationTypeUpdateEmail && eventName != constants.VerificationTypeOTP && eventName != constants.VerificationTypeInviteMember {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user