diff --git a/docs/auth0_terraform_generate.md b/docs/auth0_terraform_generate.md index b3f8f89e5..f75e676b3 100644 --- a/docs/auth0_terraform_generate.md +++ b/docs/auth0_terraform_generate.md @@ -33,7 +33,7 @@ auth0 terraform generate [flags] ``` --force Skip confirmation. -o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") - -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_email_provider,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) + -r, --resources strings Resource types to generate Terraform config for. If not provided, config files for all available resources will be generated. (default [auth0_action,auth0_attack_protection,auth0_branding,auth0_client,auth0_client_grant,auth0_connection,auth0_custom_domain,auth0_email_provider,auth0_email_template,auth0_guardian,auth0_organization,auth0_pages,auth0_prompt,auth0_prompt_custom_text,auth0_resource_server,auth0_role,auth0_tenant,auth0_trigger_actions]) ``` diff --git a/internal/auth0/email_provider.go b/internal/auth0/email_provider.go index ee4244989..127217feb 100644 --- a/internal/auth0/email_provider.go +++ b/internal/auth0/email_provider.go @@ -1,3 +1,5 @@ +//go:generate mockgen -source=email_provider.go -destination=mock/email_provider_mock.go -package=mock + package auth0 import ( diff --git a/internal/auth0/email_template.go b/internal/auth0/email_template.go index 1f489f5cd..1d250dea8 100644 --- a/internal/auth0/email_template.go +++ b/internal/auth0/email_template.go @@ -1,3 +1,5 @@ +//go:generate mockgen -source=email_template.go -destination=mock/email_template_mock.go -package=mock + package auth0 import ( diff --git a/internal/auth0/mock/email_provider_mock.go b/internal/auth0/mock/email_provider_mock.go index c153e1f79..149873b61 100644 --- a/internal/auth0/mock/email_provider_mock.go +++ b/internal/auth0/mock/email_provider_mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: action.go +// Source: email_provider.go // Package mock is a generated GoMock package. package mock @@ -53,4 +53,4 @@ func (mr *MockEmailProviderAPIMockRecorder) Read(ctx interface{}, opts ...interf mr.mock.ctrl.T.Helper() varargs := append([]interface{}{ctx}, opts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockEmailProviderAPI)(nil).Read), varargs...) -} \ No newline at end of file +} diff --git a/internal/auth0/mock/email_template_mock.go b/internal/auth0/mock/email_template_mock.go new file mode 100644 index 000000000..db3d52312 --- /dev/null +++ b/internal/auth0/mock/email_template_mock.go @@ -0,0 +1,94 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: email_template.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + management "github.com/auth0/go-auth0/management" + gomock "github.com/golang/mock/gomock" +) + +// MockEmailTemplateAPI is a mock of EmailTemplateAPI interface. +type MockEmailTemplateAPI struct { + ctrl *gomock.Controller + recorder *MockEmailTemplateAPIMockRecorder +} + +// MockEmailTemplateAPIMockRecorder is the mock recorder for MockEmailTemplateAPI. +type MockEmailTemplateAPIMockRecorder struct { + mock *MockEmailTemplateAPI +} + +// NewMockEmailTemplateAPI creates a new mock instance. +func NewMockEmailTemplateAPI(ctrl *gomock.Controller) *MockEmailTemplateAPI { + mock := &MockEmailTemplateAPI{ctrl: ctrl} + mock.recorder = &MockEmailTemplateAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmailTemplateAPI) EXPECT() *MockEmailTemplateAPIMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockEmailTemplateAPI) Create(ctx context.Context, template *management.EmailTemplate, opts ...management.RequestOption) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, template} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Create", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockEmailTemplateAPIMockRecorder) Create(ctx, template interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, template}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockEmailTemplateAPI)(nil).Create), varargs...) +} + +// Read mocks base method. +func (m *MockEmailTemplateAPI) Read(ctx context.Context, template string, opts ...management.RequestOption) (*management.EmailTemplate, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, template} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Read", varargs...) + ret0, _ := ret[0].(*management.EmailTemplate) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Read indicates an expected call of Read. +func (mr *MockEmailTemplateAPIMockRecorder) Read(ctx, template interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, template}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockEmailTemplateAPI)(nil).Read), varargs...) +} + +// Update mocks base method. +func (m *MockEmailTemplateAPI) Update(ctx context.Context, template string, e *management.EmailTemplate, opts ...management.RequestOption) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, template, e} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Update", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockEmailTemplateAPIMockRecorder) Update(ctx, template, e interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, template, e}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockEmailTemplateAPI)(nil).Update), varargs...) +} diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index 7e556be2d..e00c38900 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -74,6 +74,8 @@ func (i *terraformInputs) parseResourceFetchers(api *auth0.API) ([]resourceDataF fetchers = append(fetchers, &customDomainResourceFetcher{api}) case "auth0_email_provider": fetchers = append(fetchers, &emailProviderResourceFetcher{api}) + case "auth0_email_template": + fetchers = append(fetchers, &emailTemplateResourceFetcher{api}) case "auth0_guardian": fetchers = append(fetchers, &guardianResourceFetcher{}) case "auth0_log_stream": diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index 5356f3692..6ec7f1f36 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -11,7 +11,7 @@ import ( "github.com/auth0/auth0-cli/internal/auth0" ) -var defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_email_provider", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} +var defaultResources = []string{"auth0_action", "auth0_attack_protection", "auth0_branding", "auth0_client", "auth0_client_grant", "auth0_connection", "auth0_custom_domain", "auth0_email_provider", "auth0_email_template", "auth0_guardian", "auth0_organization", "auth0_pages", "auth0_prompt", "auth0_prompt_custom_text", "auth0_resource_server", "auth0_role", "auth0_tenant", "auth0_trigger_actions"} type ( importDataList []importDataItem @@ -54,6 +54,10 @@ type ( api *auth0.API } + emailTemplateResourceFetcher struct { + api *auth0.API + } + guardianResourceFetcher struct{} logStreamResourceFetcher struct { api *auth0.API @@ -245,6 +249,29 @@ func (f *emailProviderResourceFetcher) FetchData(ctx context.Context) (importDat }, nil } +func (f *emailTemplateResourceFetcher) FetchData(ctx context.Context) (importDataList, error) { + var data importDataList + + templates := []string{`verify_email`, `reset_email`, `welcome_email`, `blocked_account`, `stolen_credentials`, `enrollment_email`, `mfa_oob_code`, `change_password`, `password_reset`} + + for _, template := range templates { + emailTemplate, err := f.api.EmailTemplate.Read(ctx, template) + if err != nil { + if mErr, ok := err.(management.Error); ok && mErr.Status() == http.StatusNotFound { + continue + } + return nil, err + } + + data = append(data, importDataItem{ + ResourceName: "auth0_email_template." + sanitizeResourceName(emailTemplate.GetTemplate()), + ImportID: sanitizeResourceName(emailTemplate.GetTemplate()), + }) + } + + return data, nil +} + func (f *guardianResourceFetcher) FetchData(_ context.Context) (importDataList, error) { return []importDataItem{ { diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index ca264ad81..4466266eb 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -639,6 +639,124 @@ func TestEmailProviderResourceFetcher_FetchData(t *testing.T) { assert.EqualError(t, err, "failed to read email provider") }) } +func TestEmailTemplateResourceFetcher_FetchData(t *testing.T) { + t.Run("it successfully retrieves email templates data", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + emailTemplateAPI := mock.NewMockEmailTemplateAPI(ctrl) + templates := []string{ + "verify_email", "reset_email", "welcome_email", + "blocked_account", "stolen_credentials", + "enrollment_email", "mfa_oob_code", + "change_password", "password_reset", + } + + for _, tmpl := range templates { + emailTemplateAPI.EXPECT(). + Read(gomock.Any(), tmpl). + Return(&management.EmailTemplate{Template: auth0.String(tmpl)}, nil) + } + + fetcher := emailTemplateResourceFetcher{ + api: &auth0.API{ + EmailTemplate: emailTemplateAPI, + }, + } + + expectedData := importDataList{ + { + ResourceName: "auth0_email_template.verify_email", + ImportID: "verify_email", + }, + { + ResourceName: "auth0_email_template.reset_email", + ImportID: "reset_email", + }, + { + ResourceName: "auth0_email_template.welcome_email", + ImportID: "welcome_email", + }, + { + ResourceName: "auth0_email_template.blocked_account", + ImportID: "blocked_account", + }, + { + ResourceName: "auth0_email_template.stolen_credentials", + ImportID: "stolen_credentials", + }, + { + ResourceName: "auth0_email_template.enrollment_email", + ImportID: "enrollment_email", + }, + { + ResourceName: "auth0_email_template.mfa_oob_code", + ImportID: "mfa_oob_code", + }, + { + ResourceName: "auth0_email_template.change_password", + ImportID: "change_password", + }, + { + ResourceName: "auth0_email_template.password_reset", + ImportID: "password_reset", + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Equal(t, expectedData, data) + }) + + t.Run("it does not generate email template import data if email template does not exist", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mErr := mockManagamentError{status: http.StatusNotFound} + emailTemplateAPI := mock.NewMockEmailTemplateAPI(ctrl) + templates := []string{ + "verify_email", "reset_email", "welcome_email", + "blocked_account", "stolen_credentials", + "enrollment_email", "mfa_oob_code", + "change_password", "password_reset", + } + + for _, tmpl := range templates { + emailTemplateAPI.EXPECT(). + Read(gomock.Any(), tmpl). + Return(nil, mErr) + } + + fetcher := emailTemplateResourceFetcher{ + api: &auth0.API{ + EmailTemplate: emailTemplateAPI, + }, + } + + data, err := fetcher.FetchData(context.Background()) + assert.NoError(t, err) + assert.Len(t, data, 0) + }) + + t.Run("it returns an error if api call fails", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + emailTemplateAPI := mock.NewMockEmailTemplateAPI(ctrl) + emailTemplateAPI.EXPECT(). + Read(gomock.Any(), gomock.Any()). + Return(nil, fmt.Errorf("failed to read email template")) + + fetcher := emailTemplateResourceFetcher{ + api: &auth0.API{ + EmailTemplate: emailTemplateAPI, + }, + } + + _, err := fetcher.FetchData(context.Background()) + assert.EqualError(t, err, "failed to read email template") + }) +} func TestLogStreamResourceFetcher_FetchData(t *testing.T) { t.Run("it successfully retrieves log streams data", func(t *testing.T) {