diff --git a/server/db/models/email_templates.go b/server/db/models/email_templates.go index 23ac7fa..8c6de30 100644 --- a/server/db/models/email_templates.go +++ b/server/db/models/email_templates.go @@ -12,6 +12,7 @@ type EmailTemplate struct { Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty"` // for arangodb ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id"` EventName string `gorm:"unique" json:"event_name" bson:"event_name" cql:"event_name"` + Subject string `gorm:"type:text" json:"subject" bson:"subject" cql:"subject"` Template string `gorm:"type:text" json:"template" bson:"template" cql:"template"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"` @@ -26,6 +27,7 @@ func (e *EmailTemplate) AsAPIEmailTemplate() *model.EmailTemplate { return &model.EmailTemplate{ ID: id, EventName: e.EventName, + Subject: e.Subject, Template: e.Template, CreatedAt: refs.NewInt64Ref(e.CreatedAt), UpdatedAt: refs.NewInt64Ref(e.UpdatedAt), diff --git a/server/db/providers/cassandradb/email_template.go b/server/db/providers/cassandradb/email_template.go index 4fa9109..ea18fce 100644 --- a/server/db/providers/cassandradb/email_template.go +++ b/server/db/providers/cassandradb/email_template.go @@ -29,7 +29,7 @@ func (p *provider) AddEmailTemplate(ctx context.Context, emailTemplate models.Em return nil, fmt.Errorf("Email template with %s event_name already exists", emailTemplate.EventName) } - insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, template, created_at, updated_at) VALUES ('%s', '%s', '%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt) + insertQuery := fmt.Sprintf("INSERT INTO %s (id, event_name, subject, template, created_at, updated_at) VALUES ('%s', '%s', '%s','%s', %d, %d)", KeySpace+"."+models.Collections.EmailTemplate, emailTemplate.ID, emailTemplate.EventName, emailTemplate.Subject, emailTemplate.Template, emailTemplate.CreatedAt, emailTemplate.UpdatedAt) err := p.db.Query(insertQuery).Exec() if err != nil { return nil, err @@ -103,14 +103,14 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin // there is no offset in cassandra // so we fetch till limit + offset // and return the results from offset to limit - query := fmt.Sprintf("SELECT id, event_name, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset) + query := fmt.Sprintf("SELECT id, event_name, subject, template, created_at, updated_at FROM %s LIMIT %d", KeySpace+"."+models.Collections.EmailTemplate, pagination.Limit+pagination.Offset) scanner := p.db.Query(query).Iter().Scanner() counter := int64(0) for scanner.Next() { if counter >= pagination.Offset { var emailTemplate models.EmailTemplate - err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) + err := scanner.Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { return nil, err } @@ -128,8 +128,8 @@ func (p *provider) ListEmailTemplate(ctx context.Context, pagination model.Pagin // GetEmailTemplateByID to get EmailTemplate by id func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID string) (*model.EmailTemplate, error) { var emailTemplate models.EmailTemplate - query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID) - err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) + query := fmt.Sprintf(`SELECT id, event_name, subject, template, created_at, updated_at FROM %s WHERE id = '%s' LIMIT 1`, KeySpace+"."+models.Collections.EmailTemplate, emailTemplateID) + err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { return nil, err } @@ -139,8 +139,8 @@ func (p *provider) GetEmailTemplateByID(ctx context.Context, emailTemplateID str // GetEmailTemplateByEventName to get EmailTemplate by event_name func (p *provider) GetEmailTemplateByEventName(ctx context.Context, eventName string) (*model.EmailTemplate, error) { var emailTemplate models.EmailTemplate - query := fmt.Sprintf(`SELECT id, event_name, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName) - err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) + query := fmt.Sprintf(`SELECT id, event_name, subject, template, created_at, updated_at FROM %s WHERE event_name = '%s' LIMIT 1 ALLOW FILTERING`, KeySpace+"."+models.Collections.EmailTemplate, eventName) + err := p.db.Query(query).Consistency(gocql.One).Scan(&emailTemplate.ID, &emailTemplate.EventName, &emailTemplate.Subject, &emailTemplate.Template, &emailTemplate.CreatedAt, &emailTemplate.UpdatedAt) if err != nil { return nil, err } diff --git a/server/db/providers/cassandradb/provider.go b/server/db/providers/cassandradb/provider.go index e5a0469..08b2a26 100644 --- a/server/db/providers/cassandradb/provider.go +++ b/server/db/providers/cassandradb/provider.go @@ -214,6 +214,12 @@ func NewProvider() (*provider, error) { if err != nil { return nil, err } + // add subject on email_templates table + emailTemplateAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD subject text;`, KeySpace, models.Collections.EmailTemplate) + err = session.Query(emailTemplateAlterQuery).Exec() + if err != nil { + return nil, err + } return &provider{ db: session, diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 6b159e4..7acb942 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -56,6 +56,7 @@ type ComplexityRoot struct { CreatedAt func(childComplexity int) int EventName func(childComplexity int) int ID func(childComplexity int) int + Subject func(childComplexity int) int Template func(childComplexity int) int UpdatedAt func(childComplexity int) int } @@ -403,6 +404,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.EmailTemplate.ID(childComplexity), true + case "EmailTemplate.subject": + if e.complexity.EmailTemplate.Subject == nil { + break + } + + return e.complexity.EmailTemplate.Subject(childComplexity), true + case "EmailTemplate.template": if e.complexity.EmailTemplate.Template == nil { break @@ -1978,6 +1986,7 @@ type EmailTemplate { id: ID! event_name: String! template: String! + subject: String! created_at: Int64 updated_at: Int64 } @@ -2193,6 +2202,7 @@ input TestEndpointRequest { input AddEmailTemplateRequest { event_name: String! + subject: String! template: String! } @@ -2200,6 +2210,7 @@ input UpdateEmailTemplateRequest { id: ID! event_name: String template: String + subject: String } input DeleteEmailTemplateRequest { @@ -3108,6 +3119,41 @@ func (ec *executionContext) _EmailTemplate_template(ctx context.Context, field g return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _EmailTemplate_subject(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "EmailTemplate", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Subject, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _EmailTemplate_created_at(ctx context.Context, field graphql.CollectedField, obj *model.EmailTemplate) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -10087,6 +10133,14 @@ func (ec *executionContext) unmarshalInputAddEmailTemplateRequest(ctx context.Co if err != nil { return it, err } + case "subject": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subject")) + it.Subject, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } case "template": var err error @@ -10866,6 +10920,14 @@ func (ec *executionContext) unmarshalInputUpdateEmailTemplateRequest(ctx context if err != nil { return it, err } + case "subject": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subject")) + it.Subject, err = ec.unmarshalOString2áš–string(ctx, v) + if err != nil { + return it, err + } } } @@ -11632,6 +11694,11 @@ func (ec *executionContext) _EmailTemplate(ctx context.Context, sel ast.Selectio if out.Values[i] == graphql.Null { invalids++ } + case "subject": + out.Values[i] = ec._EmailTemplate_subject(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } case "created_at": out.Values[i] = ec._EmailTemplate_created_at(ctx, field, obj) case "updated_at": diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index 70762dc..6d7f319 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -4,6 +4,7 @@ package model type AddEmailTemplateRequest struct { EventName string `json:"event_name"` + Subject string `json:"subject"` Template string `json:"template"` } @@ -43,6 +44,7 @@ type EmailTemplate struct { ID string `json:"id"` EventName string `json:"event_name"` Template string `json:"template"` + Subject string `json:"subject"` CreatedAt *int64 `json:"created_at"` UpdatedAt *int64 `json:"updated_at"` } @@ -240,6 +242,7 @@ type UpdateEmailTemplateRequest struct { ID string `json:"id"` EventName *string `json:"event_name"` Template *string `json:"template"` + Subject *string `json:"subject"` } type UpdateEnvInput struct { diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index ca0e7df..e163379 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -189,6 +189,7 @@ type EmailTemplate { id: ID! event_name: String! template: String! + subject: String! created_at: Int64 updated_at: Int64 } @@ -404,6 +405,7 @@ input TestEndpointRequest { input AddEmailTemplateRequest { event_name: String! + subject: String! template: String! } @@ -411,6 +413,7 @@ input UpdateEmailTemplateRequest { id: ID! event_name: String template: String + subject: String } input DeleteEmailTemplateRequest { diff --git a/server/resolvers/add_email_template.go b/server/resolvers/add_email_template.go index 1cba02f..092d017 100644 --- a/server/resolvers/add_email_template.go +++ b/server/resolvers/add_email_template.go @@ -34,6 +34,10 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate return nil, fmt.Errorf("invalid event name %s", params.EventName) } + if strings.TrimSpace(params.Subject) == "" { + return nil, fmt.Errorf("empty subject not allowed") + } + if strings.TrimSpace(params.Template) == "" { return nil, fmt.Errorf("empty template not allowed") } @@ -41,6 +45,7 @@ func AddEmailTemplateResolver(ctx context.Context, params model.AddEmailTemplate _, err = db.Provider.AddEmailTemplate(ctx, models.EmailTemplate{ EventName: params.EventName, Template: params.Template, + Subject: params.Subject, }) if err != nil { log.Debug("Failed to add email template: ", err) diff --git a/server/resolvers/update_email_template.go b/server/resolvers/update_email_template.go index 95362c0..5eab5aa 100644 --- a/server/resolvers/update_email_template.go +++ b/server/resolvers/update_email_template.go @@ -51,6 +51,14 @@ func UpdateEmailTemplateResolver(ctx context.Context, params model.UpdateEmailTe emailTemplateDetails.EventName = refs.StringValue(params.EventName) } + if params.Subject != nil && emailTemplateDetails.Subject != refs.StringValue(params.Subject) { + if strings.TrimSpace(refs.StringValue(params.Subject)) == "" { + log.Debug("empty subject not allowed") + return nil, fmt.Errorf("empty subject not allowed") + } + emailTemplateDetails.Subject = refs.StringValue(params.Subject) + } + if params.Template != nil && emailTemplateDetails.Template != refs.StringValue(params.Template) { if strings.TrimSpace(refs.StringValue(params.Template)) == "" { log.Debug("empty template not allowed") diff --git a/server/test/add_email_template_test.go b/server/test/add_email_template_test.go index 743ed12..40cf94e 100644 --- a/server/test/add_email_template_test.go +++ b/server/test/add_email_template_test.go @@ -31,10 +31,21 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) { assert.Nil(t, emailTemplate) }) + t.Run("should not add email template for empty template", func(t *testing.T) { + emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ + EventName: s.TestInfo.TestEmailTemplateEventTypes[0], + Template: " test ", + Subject: " ", + }) + assert.Error(t, err) + assert.Nil(t, emailTemplate) + }) + t.Run("should not add email template for empty template", func(t *testing.T) { emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ EventName: s.TestInfo.TestEmailTemplateEventTypes[0], Template: " ", + Subject: "test", }) assert.Error(t, err) assert.Nil(t, emailTemplate) @@ -43,7 +54,8 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) { t.Run("should add email template for "+eventType, func(t *testing.T) { emailTemplate, err := resolvers.AddEmailTemplateResolver(ctx, model.AddEmailTemplateRequest{ EventName: eventType, - Template: `Test email`, + Template: "Test email", + Subject: "Test email", }) assert.NoError(t, err) assert.NotNil(t, emailTemplate) @@ -52,6 +64,7 @@ func addEmailTemplateTest(t *testing.T, s TestSetup) { et, err := db.Provider.GetEmailTemplateByEventName(ctx, eventType) assert.NoError(t, err) assert.Equal(t, et.EventName, eventType) + assert.Equal(t, "Test email", et.Subject) }) } }) diff --git a/server/test/update_email_template_test.go b/server/test/update_email_template_test.go index 1f23ff4..4f2a999 100644 --- a/server/test/update_email_template_test.go +++ b/server/test/update_email_template_test.go @@ -31,6 +31,7 @@ func updateEmailTemplateTest(t *testing.T, s TestSetup) { res, err := resolvers.UpdateEmailTemplateResolver(ctx, model.UpdateEmailTemplateRequest{ ID: emailTemplate.ID, Template: refs.NewStringRef("Updated test template"), + Subject: refs.NewStringRef("Updated subject"), }) assert.NoError(t, err) @@ -42,5 +43,6 @@ func updateEmailTemplateTest(t *testing.T, s TestSetup) { assert.NotNil(t, updatedEmailTemplate) assert.Equal(t, emailTemplate.ID, updatedEmailTemplate.ID) assert.Equal(t, updatedEmailTemplate.Template, "Updated test template") + assert.Equal(t, updatedEmailTemplate.Subject, "Updated subject") }) }