+ contact requests
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
Some checks failed
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
This commit is contained in:
@@ -85,6 +85,11 @@ func CreateAPI(a api.API) (*NotificationAPI, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.Register().Consumer(snotifications.NewContactRequestProcessor(p.logger, p.onContactRequest)); err != nil {
|
||||
p.logger.Error("Failed to register contact request handler", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -99,3 +104,15 @@ func (a *NotificationAPI) onDemoRequest(ctx context.Context, request *model.Demo
|
||||
a.logger.Info("Demo request sent via Telegram", zap.String("name", request.Name), zap.String("organization", request.OrganizationName))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *NotificationAPI) onContactRequest(ctx context.Context, request *model.ContactRequest) error {
|
||||
if a.tg == nil {
|
||||
return merrors.Internal("telegram client is not configured")
|
||||
}
|
||||
if err := a.tg.SendContactRequest(ctx, request); err != nil {
|
||||
a.logger.Warn("Failed to send contact request via telegram", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
a.logger.Info("Contact request sent via Telegram", zap.String("name", request.Name), zap.String("topic", request.Topic))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -24,6 +23,7 @@ const defaultAPIURL = "https://api.telegram.org"
|
||||
|
||||
type Client interface {
|
||||
SendDemoRequest(ctx context.Context, request *model.DemoRequest) error
|
||||
SendContactRequest(ctx context.Context, request *model.ContactRequest) error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
@@ -102,15 +102,7 @@ func (c *client) SendDemoRequest(ctx context.Context, request *model.DemoRequest
|
||||
if request == nil {
|
||||
return merrors.InvalidArgument("demo request payload is nil", "request")
|
||||
}
|
||||
message := buildMessage(request, c.parseMode)
|
||||
payload := sendMessagePayload{
|
||||
ChatID: c.chatID,
|
||||
Text: message,
|
||||
ParseMode: c.parseMode,
|
||||
ThreadID: c.threadID,
|
||||
DisablePreview: true,
|
||||
}
|
||||
return c.sendMessage(ctx, payload)
|
||||
return c.sendForm(ctx, newDemoRequestTemplate(request))
|
||||
}
|
||||
|
||||
func (c *client) sendMessage(ctx context.Context, payload sendMessagePayload) error {
|
||||
@@ -162,89 +154,21 @@ func (c *client) endpoint() string {
|
||||
return fmt.Sprintf("%s/bot%s/sendMessage", c.apiURL, c.botToken)
|
||||
}
|
||||
|
||||
func buildMessage(req *model.DemoRequest, parseMode string) string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("New demo request received\n")
|
||||
builder.WriteString("-----------------------------\n")
|
||||
|
||||
formatter := selectValueFormatter(parseMode)
|
||||
appendMessageField(&builder, "Name", req.Name, formatter)
|
||||
appendMessageField(&builder, "Organization", req.OrganizationName, formatter)
|
||||
appendMessageField(&builder, "Phone", req.Phone, formatter)
|
||||
appendMessageField(&builder, "Work email", req.WorkEmail, formatter)
|
||||
appendMessageField(&builder, "Payout volume", req.PayoutVolume, formatter)
|
||||
if strings.TrimSpace(req.Comment) != "" {
|
||||
appendMessageField(&builder, "Comment", req.Comment, formatter)
|
||||
func (c *client) SendContactRequest(ctx context.Context, request *model.ContactRequest) error {
|
||||
if request == nil {
|
||||
return merrors.InvalidArgument("contact request payload is nil", "request")
|
||||
}
|
||||
return builder.String()
|
||||
return c.sendForm(ctx, newContactRequestTemplate(request))
|
||||
}
|
||||
|
||||
type valueFormatter func(string) string
|
||||
|
||||
func appendMessageField(builder *strings.Builder, label, value string, formatter valueFormatter) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
value = "—"
|
||||
} else if formatter != nil {
|
||||
value = formatter(value)
|
||||
func (c *client) sendForm(ctx context.Context, template messageTemplate) error {
|
||||
message := template.Format(c.parseMode)
|
||||
payload := sendMessagePayload{
|
||||
ChatID: c.chatID,
|
||||
Text: message,
|
||||
ParseMode: c.parseMode,
|
||||
ThreadID: c.threadID,
|
||||
DisablePreview: true,
|
||||
}
|
||||
fmt.Fprintf(builder, "• %s: %s\n", label, value)
|
||||
}
|
||||
|
||||
func selectValueFormatter(parseMode string) valueFormatter {
|
||||
switch strings.ToLower(parseMode) {
|
||||
case "markdown":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("*%s*", escapeMarkdown(value))
|
||||
}
|
||||
case "markdownv2":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("*%s*", escapeMarkdownV2(value))
|
||||
}
|
||||
case "html":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("<b>%s</b>", html.EscapeString(value))
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var markdownEscaper = strings.NewReplacer(
|
||||
"*", "\\*",
|
||||
"_", "\\_",
|
||||
"[", "\\[",
|
||||
"]", "\\]",
|
||||
"(", "\\(",
|
||||
")", "\\)",
|
||||
"`", "\\`",
|
||||
)
|
||||
|
||||
var markdownV2Escaper = strings.NewReplacer(
|
||||
"_", "\\_",
|
||||
"*", "\\*",
|
||||
"[", "\\[",
|
||||
"]", "\\]",
|
||||
"(", "\\(",
|
||||
")", "\\)",
|
||||
"~", "\\~",
|
||||
"`", "\\`",
|
||||
">", "\\>",
|
||||
"#", "\\#",
|
||||
"+", "\\+",
|
||||
"-", "\\-",
|
||||
"=", "\\=",
|
||||
"|", "\\|",
|
||||
"{", "\\{",
|
||||
"}", "\\}",
|
||||
".", "\\.",
|
||||
"!", "\\!",
|
||||
)
|
||||
|
||||
func escapeMarkdown(value string) string {
|
||||
return markdownEscaper.Replace(value)
|
||||
}
|
||||
|
||||
func escapeMarkdownV2(value string) string {
|
||||
return markdownV2Escaper.Replace(value)
|
||||
return c.sendMessage(ctx, payload)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package telegram
|
||||
|
||||
import "github.com/tech/sendico/pkg/model"
|
||||
|
||||
func newContactRequestTemplate(request *model.ContactRequest) messageTemplate {
|
||||
return messageTemplate{
|
||||
title: "New contact request received",
|
||||
fields: []messageField{
|
||||
{label: "Name", value: request.Name},
|
||||
{label: "Email", value: request.Email},
|
||||
{label: "Phone", value: request.Phone},
|
||||
{label: "Company", value: request.Company},
|
||||
{label: "Topic", value: request.Topic},
|
||||
{label: "Message", value: request.Message},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tech/sendico/pkg/model"
|
||||
)
|
||||
|
||||
func newDemoRequestTemplate(request *model.DemoRequest) messageTemplate {
|
||||
fields := []messageField{
|
||||
{label: "Name", value: request.Name},
|
||||
{label: "Organization", value: request.OrganizationName},
|
||||
{label: "Phone", value: request.Phone},
|
||||
{label: "Work email", value: request.WorkEmail},
|
||||
{label: "Payout volume", value: request.PayoutVolume},
|
||||
}
|
||||
if strings.TrimSpace(request.Comment) != "" {
|
||||
fields = append(fields, messageField{label: "Comment", value: request.Comment})
|
||||
}
|
||||
return messageTemplate{
|
||||
title: "New demo request received",
|
||||
fields: fields,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type messageField struct {
|
||||
label string
|
||||
value string
|
||||
}
|
||||
|
||||
type messageTemplate struct {
|
||||
title string
|
||||
fields []messageField
|
||||
}
|
||||
|
||||
func (mt messageTemplate) Format(parseMode string) string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(mt.title)
|
||||
builder.WriteString("\n")
|
||||
builder.WriteString("-----------------------------\n")
|
||||
|
||||
formatter := selectValueFormatter(parseMode)
|
||||
for _, field := range mt.fields {
|
||||
appendMessageField(&builder, field.label, field.value, formatter)
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type valueFormatter func(string) string
|
||||
|
||||
func appendMessageField(builder *strings.Builder, label, value string, formatter valueFormatter) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
value = "—"
|
||||
} else if formatter != nil {
|
||||
value = formatter(value)
|
||||
}
|
||||
fmt.Fprintf(builder, "• %s: %s\n", label, value)
|
||||
}
|
||||
|
||||
func selectValueFormatter(parseMode string) valueFormatter {
|
||||
switch strings.ToLower(parseMode) {
|
||||
case "markdown":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("*%s*", escapeMarkdown(value))
|
||||
}
|
||||
case "markdownv2":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("*%s*", escapeMarkdownV2(value))
|
||||
}
|
||||
case "html":
|
||||
return func(value string) string {
|
||||
return fmt.Sprintf("<b>%s</b>", html.EscapeString(value))
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var markdownEscaper = strings.NewReplacer(
|
||||
"*", "\\*",
|
||||
"_", "\\_",
|
||||
"[", "\\[",
|
||||
"]", "\\]",
|
||||
"(", "\\(",
|
||||
")", "\\)",
|
||||
"`", "\\`",
|
||||
)
|
||||
|
||||
var markdownV2Escaper = strings.NewReplacer(
|
||||
"_", "\\_",
|
||||
"*", "\\*",
|
||||
"[", "\\[",
|
||||
"]", "\\]",
|
||||
"(", "\\(",
|
||||
")", "\\)",
|
||||
"~", "\\~",
|
||||
"`", "\\`",
|
||||
">", "\\>",
|
||||
"#", "\\#",
|
||||
"+", "\\+",
|
||||
"-", "\\-",
|
||||
"=", "\\=",
|
||||
"|", "\\|",
|
||||
"{", "\\{",
|
||||
"}", "\\}",
|
||||
".", "\\.",
|
||||
"!", "\\!",
|
||||
)
|
||||
|
||||
func escapeMarkdown(value string) string {
|
||||
return markdownEscaper.Replace(value)
|
||||
}
|
||||
|
||||
func escapeMarkdownV2(value string) string {
|
||||
return markdownV2Escaper.Replace(value)
|
||||
}
|
||||
Reference in New Issue
Block a user