account state changes #463
@@ -1,8 +1,60 @@
|
|||||||
package telegram
|
package telegram
|
||||||
|
|
||||||
import "github.com/tech/sendico/pkg/model"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const legacyContactRequestTopicSignup = "signup_request"
|
||||||
|
|
||||||
func newContactRequestTemplate(request *model.ContactRequest) messageTemplate {
|
func newContactRequestTemplate(request *model.ContactRequest) messageTemplate {
|
||||||
|
if request == nil {
|
||||||
|
request = &model.ContactRequest{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch normalizeContactRequestTopic(request.Topic) {
|
||||||
|
case model.ContactRequestTopicAccountVerificationCompleted:
|
||||||
|
return newAccountVerificationCompletedTemplate(request)
|
||||||
|
case model.ContactRequestTopicSignupCompleted:
|
||||||
|
return newSignupCompletedTemplate(request)
|
||||||
|
default:
|
||||||
|
return newSiteContactTemplate(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeContactRequestTopic(topic string) string {
|
||||||
|
normalized := strings.ToLower(strings.TrimSpace(topic))
|
||||||
|
if normalized == legacyContactRequestTopicSignup {
|
||||||
|
return model.ContactRequestTopicSignupCompleted
|
||||||
|
}
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAccountVerificationCompletedTemplate(request *model.ContactRequest) messageTemplate {
|
||||||
|
return messageTemplate{
|
||||||
|
title: "Account verification completed",
|
||||||
|
emphasize: []string{"verification completed"},
|
||||||
|
fields: []messageField{
|
||||||
|
{label: "Name", value: request.Name},
|
||||||
|
{label: "Email", value: request.Email},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSignupCompletedTemplate(request *model.ContactRequest) messageTemplate {
|
||||||
|
return messageTemplate{
|
||||||
|
title: "New signup completed",
|
||||||
|
emphasize: []string{"signup completed"},
|
||||||
|
fields: []messageField{
|
||||||
|
{label: "Organization", value: request.Company},
|
||||||
|
{label: "Name", value: request.Name},
|
||||||
|
{label: "Email", value: request.Email},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSiteContactTemplate(request *model.ContactRequest) messageTemplate {
|
||||||
return messageTemplate{
|
return messageTemplate{
|
||||||
title: "New site request received",
|
title: "New site request received",
|
||||||
emphasize: []string{"site request"},
|
emphasize: []string{"site request"},
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_SignupTopic(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(&model.ContactRequest{
|
||||||
|
Name: "Alice Example",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
Company: "Acme Inc",
|
||||||
|
Topic: model.ContactRequestTopicSignupCompleted,
|
||||||
|
})
|
||||||
|
|
||||||
|
if template.title != "New signup completed" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.emphasize, []string{"signup completed"}) {
|
||||||
|
t.Fatalf("unexpected emphasize words: %#v", template.emphasize)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedFields := []messageField{
|
||||||
|
{label: "Organization", value: "Acme Inc"},
|
||||||
|
{label: "Name", value: "Alice Example"},
|
||||||
|
{label: "Email", value: "alice@example.com"},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.fields, expectedFields) {
|
||||||
|
t.Fatalf("unexpected fields: %#v", template.fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_LegacySignupTopic(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(&model.ContactRequest{
|
||||||
|
Name: "Alice Example",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
Company: "Acme Inc",
|
||||||
|
Topic: "signup_request",
|
||||||
|
})
|
||||||
|
|
||||||
|
if template.title != "New signup completed" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_DefaultTopic(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(&model.ContactRequest{
|
||||||
|
Name: "Alice Example",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
Phone: "+123456",
|
||||||
|
Company: "Acme Inc",
|
||||||
|
Topic: "partnership",
|
||||||
|
Message: "Hi there",
|
||||||
|
})
|
||||||
|
|
||||||
|
if template.title != "New site request received" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.emphasize, []string{"site request"}) {
|
||||||
|
t.Fatalf("unexpected emphasize words: %#v", template.emphasize)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedFields := []messageField{
|
||||||
|
{label: "Name", value: "Alice Example"},
|
||||||
|
{label: "Email", value: "alice@example.com"},
|
||||||
|
{label: "Phone", value: "+123456"},
|
||||||
|
{label: "Company", value: "Acme Inc"},
|
||||||
|
{label: "Topic", value: "partnership"},
|
||||||
|
{label: "Message", value: "Hi there"},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.fields, expectedFields) {
|
||||||
|
t.Fatalf("unexpected fields: %#v", template.fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_AccountVerificationCompletedTopic(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(&model.ContactRequest{
|
||||||
|
Name: "Alice Example",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
Topic: model.ContactRequestTopicAccountVerificationCompleted,
|
||||||
|
})
|
||||||
|
|
||||||
|
if template.title != "Account verification completed" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.emphasize, []string{"verification completed"}) {
|
||||||
|
t.Fatalf("unexpected emphasize words: %#v", template.emphasize)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedFields := []messageField{
|
||||||
|
{label: "Name", value: "Alice Example"},
|
||||||
|
{label: "Email", value: "alice@example.com"},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(template.fields, expectedFields) {
|
||||||
|
t.Fatalf("unexpected fields: %#v", template.fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_NilRequest(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(nil)
|
||||||
|
if template.title != "New site request received" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContactRequestTemplate_LegacySignupTopicCaseInsensitive(t *testing.T) {
|
||||||
|
template := newContactRequestTemplate(&model.ContactRequest{
|
||||||
|
Name: "Alice Example",
|
||||||
|
Email: "alice@example.com",
|
||||||
|
Company: "Acme Inc",
|
||||||
|
Topic: " SIGNUP_REQUEST ",
|
||||||
|
})
|
||||||
|
if template.title != "New signup completed" {
|
||||||
|
t.Fatalf("unexpected title: %s", template.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,12 @@ type ContactRequest struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ContactRequestTopicSiteContact = "site_contact_request"
|
||||||
|
ContactRequestTopicSignupCompleted = "signup_completed"
|
||||||
|
ContactRequestTopicAccountVerificationCompleted = "account_verification_completed"
|
||||||
|
)
|
||||||
|
|
||||||
// Normalize trims whitespace from all string fields.
|
// Normalize trims whitespace from all string fields.
|
||||||
func (cr *ContactRequest) Normalize() {
|
func (cr *ContactRequest) Normalize() {
|
||||||
if cr == nil {
|
if cr == nil {
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ func (a *AccountAPI) verify(r *http.Request) http.HandlerFunc {
|
|||||||
a.logger.Warn("Failed to save account while verifying account", zap.Error(err))
|
a.logger.Warn("Failed to save account while verifying account", zap.Error(err))
|
||||||
return response.Internal(a.logger, a.Name(), err)
|
return response.Internal(a.logger, a.Name(), err)
|
||||||
}
|
}
|
||||||
|
if err := a.sendAccountVerificationCompletedNotification(&user); err != nil {
|
||||||
|
a.logger.Warn("Failed to enqueue account verification notification", zap.Error(err), zap.String("email", user.Login))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Send verification confirmation email
|
// TODO: Send verification confirmation email
|
||||||
return response.Success(a.logger)
|
return response.Success(a.logger)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/tech/sendico/pkg/api/http/response"
|
"github.com/tech/sendico/pkg/api/http/response"
|
||||||
"github.com/tech/sendico/pkg/db/storable"
|
"github.com/tech/sendico/pkg/db/storable"
|
||||||
"github.com/tech/sendico/pkg/merrors"
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
|
snotifications "github.com/tech/sendico/pkg/messaging/notifications/site"
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
"github.com/tech/sendico/pkg/mutil/mzap"
|
"github.com/tech/sendico/pkg/mutil/mzap"
|
||||||
@@ -104,10 +105,52 @@ func (a *AccountAPI) signup(r *http.Request) http.HandlerFunc {
|
|||||||
if err := a.sendWelcomeEmail(newAccount, verificationToken); err != nil {
|
if err := a.sendWelcomeEmail(newAccount, verificationToken); err != nil {
|
||||||
a.logger.Warn("Failed to send welcome email", zap.Error(err), mzap.StorableRef(newAccount))
|
a.logger.Warn("Failed to send welcome email", zap.Error(err), mzap.StorableRef(newAccount))
|
||||||
}
|
}
|
||||||
|
if err := a.sendSignupNotification(newAccount, &sr); err != nil {
|
||||||
|
a.logger.Warn("Failed to enqueue signup notification", zap.Error(err), zap.String("login", newAccount.Login))
|
||||||
|
}
|
||||||
|
|
||||||
return sresponse.SignUp(a.logger, newAccount)
|
return sresponse.SignUp(a.logger, newAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AccountAPI) sendSignupNotification(account *model.Account, request *srequest.Signup) error {
|
||||||
|
if account == nil || request == nil {
|
||||||
|
return merrors.InvalidArgument("signup notification payload is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
signupNotification := &model.ContactRequest{
|
||||||
|
Name: accountNotificationName(account),
|
||||||
|
Email: strings.TrimSpace(account.Login),
|
||||||
|
Company: strings.TrimSpace(request.Organization.Name),
|
||||||
|
Topic: model.ContactRequestTopicSignupCompleted,
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.producer.SendMessage(snotifications.ContactRequest(a.Name(), signupNotification))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccountAPI) sendAccountVerificationCompletedNotification(account *model.Account) error {
|
||||||
|
if account == nil {
|
||||||
|
return merrors.InvalidArgument("account verification notification payload is empty", "account")
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := &model.ContactRequest{
|
||||||
|
Name: accountNotificationName(account),
|
||||||
|
Email: strings.TrimSpace(account.Login),
|
||||||
|
Topic: model.ContactRequestTopicAccountVerificationCompleted,
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.producer.SendMessage(snotifications.ContactRequest(a.Name(), notification))
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountNotificationName(account *model.Account) string {
|
||||||
|
if account == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(strings.Join([]string{
|
||||||
|
strings.TrimSpace(account.Name),
|
||||||
|
strings.TrimSpace(account.LastName),
|
||||||
|
}, " "))
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AccountAPI) signupAvailability(r *http.Request) http.HandlerFunc {
|
func (a *AccountAPI) signupAvailability(r *http.Request) http.HandlerFunc {
|
||||||
login := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("login")))
|
login := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("login")))
|
||||||
if login == "" {
|
if login == "" {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ func (a *SiteAPI) contactRequest(r *http.Request) http.HandlerFunc {
|
|||||||
return response.BadRequest(a.logger, a.Name(), "invalid_payload", "Failed to decode contact request payload")
|
return response.BadRequest(a.logger, a.Name(), "invalid_payload", "Failed to decode contact request payload")
|
||||||
}
|
}
|
||||||
request.Normalize()
|
request.Normalize()
|
||||||
|
if request.Topic == "" {
|
||||||
|
request.Topic = model.ContactRequestTopicSiteContact
|
||||||
|
}
|
||||||
if err := request.Validate(); err != nil {
|
if err := request.Validate(); err != nil {
|
||||||
a.logger.Warn("Contact request validation failed", zap.Error(err))
|
a.logger.Warn("Contact request validation failed", zap.Error(err))
|
||||||
return response.BadPayload(a.logger, a.Name(), err)
|
return response.BadPayload(a.logger, a.Name(), err)
|
||||||
|
|||||||
Reference in New Issue
Block a user