+notification from site +version bump fix
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/fx_oracle Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
ci/woodpecker/push/frontend 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
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/fx_oracle Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
ci/woodpecker/push/frontend 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
This commit is contained in:
@@ -5,6 +5,7 @@ matrix:
|
|||||||
NOTIFICATION_MONGO_SECRET_PATH: sendico/db
|
NOTIFICATION_MONGO_SECRET_PATH: sendico/db
|
||||||
NOTIFICATION_MAIL_SECRET_PATH: sendico/notification/mail
|
NOTIFICATION_MAIL_SECRET_PATH: sendico/notification/mail
|
||||||
NOTIFICATION_API_SECRET_PATH: sendico/api/endpoint
|
NOTIFICATION_API_SECRET_PATH: sendico/api/endpoint
|
||||||
|
NOTIFICATION_TELEGRAM_SECRET_PATH: sendico/notification/telegram
|
||||||
NOTIFICATION_ENV: prod
|
NOTIFICATION_ENV: prod
|
||||||
|
|
||||||
when:
|
when:
|
||||||
|
|||||||
@@ -53,14 +53,21 @@ api:
|
|||||||
password_env: MAIL_SECRET
|
password_env: MAIL_SECRET
|
||||||
host: "smtp.mail.ru"
|
host: "smtp.mail.ru"
|
||||||
port: 465
|
port: 465
|
||||||
from: "MeetX Tech"
|
from: "Sendico Tech"
|
||||||
network_timeout: 10
|
network_timeout: 10
|
||||||
|
telegram:
|
||||||
|
bot_token_env: TELEGRAM_BOT_TOKEN
|
||||||
|
chat_id_env: TELEGRAM_CHAT_ID
|
||||||
|
thread_id_env: TELEGRAM_THREAD_ID
|
||||||
|
api_url: "https://api.telegram.org"
|
||||||
|
timeout_seconds: 10
|
||||||
|
parse_mode: ""
|
||||||
|
|
||||||
localizer:
|
localizer:
|
||||||
path: "./i18n"
|
path: "./i18n"
|
||||||
languages: ["en", "ru", "uk"]
|
languages: ["en", "ru", "uk"]
|
||||||
service_name: "Sendico"
|
service_name: "Sendico"
|
||||||
support: "support@meetx.space"
|
support: "support@sendico.io"
|
||||||
|
|
||||||
app:
|
app:
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,14 @@ package notificationimp
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Driver string `yaml:"driver"`
|
Driver string `yaml:"driver"`
|
||||||
Settings map[string]any `yaml:"settings,omitempty"`
|
Settings map[string]any `yaml:"settings,omitempty"`
|
||||||
|
Telegram *TelegramConfig `yaml:"telegram"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TelegramConfig struct {
|
||||||
|
BotTokenEnv string `yaml:"bot_token_env"`
|
||||||
|
ChatIDEnv string `yaml:"chat_id_env"`
|
||||||
|
ThreadIDEnv string `yaml:"thread_id_env,omitempty"`
|
||||||
|
APIURL string `yaml:"api_url,omitempty"`
|
||||||
|
ParseMode string `yaml:"parse_mode,omitempty"`
|
||||||
|
TimeoutSeconds int `yaml:"timeout_seconds"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ package notificationimp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/tech/sendico/notification/interface/api"
|
"github.com/tech/sendico/notification/interface/api"
|
||||||
mmail "github.com/tech/sendico/notification/internal/server/notificationimp/mail"
|
mmail "github.com/tech/sendico/notification/internal/server/notificationimp/mail"
|
||||||
|
"github.com/tech/sendico/notification/internal/server/notificationimp/telegram"
|
||||||
"github.com/tech/sendico/pkg/domainprovider"
|
"github.com/tech/sendico/pkg/domainprovider"
|
||||||
na "github.com/tech/sendico/pkg/messaging/notifications/account"
|
na "github.com/tech/sendico/pkg/messaging/notifications/account"
|
||||||
ni "github.com/tech/sendico/pkg/messaging/notifications/invitation"
|
ni "github.com/tech/sendico/pkg/messaging/notifications/invitation"
|
||||||
|
snotifications "github.com/tech/sendico/pkg/messaging/notifications/site"
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
@@ -17,6 +21,7 @@ type NotificationAPI struct {
|
|||||||
logger mlogger.Logger
|
logger mlogger.Logger
|
||||||
client mmail.Client
|
client mmail.Client
|
||||||
dp domainprovider.DomainProvider
|
dp domainprovider.DomainProvider
|
||||||
|
tg telegram.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *NotificationAPI) Name() mservice.Type {
|
func (a *NotificationAPI) Name() mservice.Type {
|
||||||
@@ -33,11 +38,22 @@ func CreateAPI(a api.API) (*NotificationAPI, error) {
|
|||||||
}
|
}
|
||||||
p.logger = a.Logger().Named(p.Name())
|
p.logger = a.Logger().Named(p.Name())
|
||||||
|
|
||||||
|
if a.Config().Notification == nil {
|
||||||
|
return nil, fmt.Errorf("notification configuration is missing")
|
||||||
|
}
|
||||||
|
if a.Config().Notification.Telegram == nil {
|
||||||
|
return nil, fmt.Errorf("telegram configuration is missing")
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if p.client, err = mmail.CreateMailClient(p.logger.Named("mailer"), p.Name(), a.Register().Producer(), a.Localizer(), a.DomainProvider(), a.Config().Notification); err != nil {
|
if p.client, err = mmail.CreateMailClient(p.logger.Named("mailer"), p.Name(), a.Register().Producer(), a.Localizer(), a.DomainProvider(), a.Config().Notification); err != nil {
|
||||||
p.logger.Error("Failed to create mail connection", zap.Error(err), zap.String("driver", a.Config().Notification.Driver))
|
p.logger.Error("Failed to create mail connection", zap.Error(err), zap.String("driver", a.Config().Notification.Driver))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if p.tg, err = telegram.NewClient(p.logger.Named("telegram"), a.Config().Notification.Telegram); err != nil {
|
||||||
|
p.logger.Error("Failed to create telegram client", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
db, err := a.DBFactory().NewAccountDB()
|
db, err := a.DBFactory().NewAccountDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,5 +80,22 @@ func CreateAPI(a api.API) (*NotificationAPI, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := a.Register().Consumer(snotifications.NewDemoRequestProcessor(p.logger, p.onDemoRequest)); err != nil {
|
||||||
|
p.logger.Error("Failed to register demo request handler", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *NotificationAPI) onDemoRequest(ctx context.Context, request *model.DemoRequest) error {
|
||||||
|
if a.tg == nil {
|
||||||
|
return fmt.Errorf("telegram client is not configured")
|
||||||
|
}
|
||||||
|
if err := a.tg.SendDemoRequest(ctx, request); err != nil {
|
||||||
|
a.logger.Warn("Failed to send demo request via telegram", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.logger.Info("Demo request sent via Telegram", zap.String("name", request.Name), zap.String("organization", request.OrganizationName))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
notconfig "github.com/tech/sendico/notification/interface/services/notification/config"
|
||||||
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultAPIURL = "https://api.telegram.org"
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
SendDemoRequest(ctx context.Context, request *model.DemoRequest) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
logger mlogger.Logger
|
||||||
|
httpClient *http.Client
|
||||||
|
apiURL string
|
||||||
|
botToken string
|
||||||
|
chatID string
|
||||||
|
threadID *int64
|
||||||
|
parseMode string
|
||||||
|
}
|
||||||
|
|
||||||
|
type sendMessagePayload struct {
|
||||||
|
ChatID string `json:"chat_id"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
ParseMode string `json:"parse_mode,omitempty"`
|
||||||
|
ThreadID *int64 `json:"message_thread_id,omitempty"`
|
||||||
|
DisablePreview bool `json:"disable_web_page_preview,omitempty"`
|
||||||
|
DisableNotify bool `json:"disable_notification,omitempty"`
|
||||||
|
ProtectContent bool `json:"protect_content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(logger mlogger.Logger, cfg *notconfig.TelegramConfig) (Client, error) {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil, fmt.Errorf("telegram configuration is not provided")
|
||||||
|
}
|
||||||
|
token := strings.TrimSpace(os.Getenv(cfg.BotTokenEnv))
|
||||||
|
if token == "" {
|
||||||
|
return nil, fmt.Errorf("telegram bot token env %s is empty", cfg.BotTokenEnv)
|
||||||
|
}
|
||||||
|
chatID := strings.TrimSpace(os.Getenv(cfg.ChatIDEnv))
|
||||||
|
if chatID == "" {
|
||||||
|
return nil, fmt.Errorf("telegram chat id env %s is empty", cfg.ChatIDEnv)
|
||||||
|
}
|
||||||
|
|
||||||
|
var threadID *int64
|
||||||
|
if env := strings.TrimSpace(cfg.ThreadIDEnv); env != "" {
|
||||||
|
raw := strings.TrimSpace(os.Getenv(env))
|
||||||
|
if raw != "" {
|
||||||
|
val, err := strconv.ParseInt(raw, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("telegram thread id env %s is invalid: %w", env, err)
|
||||||
|
}
|
||||||
|
threadID = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.Duration(cfg.TimeoutSeconds) * time.Second
|
||||||
|
if timeout <= 0 {
|
||||||
|
timeout = 10 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
apiURL := strings.TrimSpace(cfg.APIURL)
|
||||||
|
if apiURL == "" {
|
||||||
|
apiURL = defaultAPIURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return &client{
|
||||||
|
logger: logger.Named("telegram"),
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: timeout,
|
||||||
|
},
|
||||||
|
apiURL: strings.TrimRight(apiURL, "/"),
|
||||||
|
botToken: token,
|
||||||
|
chatID: chatID,
|
||||||
|
threadID: threadID,
|
||||||
|
parseMode: strings.TrimSpace(cfg.ParseMode),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) SendDemoRequest(ctx context.Context, request *model.DemoRequest) error {
|
||||||
|
if request == nil {
|
||||||
|
return fmt.Errorf("demo request payload is nil")
|
||||||
|
}
|
||||||
|
message := buildMessage(request)
|
||||||
|
payload := sendMessagePayload{
|
||||||
|
ChatID: c.chatID,
|
||||||
|
Text: message,
|
||||||
|
ParseMode: c.parseMode,
|
||||||
|
ThreadID: c.threadID,
|
||||||
|
DisablePreview: true,
|
||||||
|
}
|
||||||
|
return c.sendMessage(ctx, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) sendMessage(ctx context.Context, payload sendMessagePayload) error {
|
||||||
|
body, err := json.Marshal(&payload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpoint(), bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 4<<10))
|
||||||
|
return fmt.Errorf("telegram sendMessage failed with status %d: %s", resp.StatusCode, string(respBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) endpoint() string {
|
||||||
|
return fmt.Sprintf("%s/bot%s/sendMessage", c.apiURL, c.botToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMessage(req *model.DemoRequest) string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString("New demo request received\n")
|
||||||
|
builder.WriteString(fmt.Sprintf("Name: %s\n", req.Name))
|
||||||
|
builder.WriteString(fmt.Sprintf("Organization: %s\n", req.OrganizationName))
|
||||||
|
builder.WriteString(fmt.Sprintf("Phone: %s\n", req.Phone))
|
||||||
|
builder.WriteString(fmt.Sprintf("Work email: %s\n", req.WorkEmail))
|
||||||
|
builder.WriteString(fmt.Sprintf("Payout volume: %s\n", req.PayoutVolume))
|
||||||
|
if req.Comment != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("Comment: %s\n", req.Comment))
|
||||||
|
}
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
gmessaging "github.com/tech/sendico/pkg/generated/gmessaging"
|
||||||
|
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
nm "github.com/tech/sendico/pkg/model/notification"
|
||||||
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DemoRequestNotification struct {
|
||||||
|
messaging.Envelope
|
||||||
|
request *model.DemoRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drn *DemoRequestNotification) Serialize() ([]byte, error) {
|
||||||
|
if drn.request == nil {
|
||||||
|
return nil, fmt.Errorf("demo request payload is empty")
|
||||||
|
}
|
||||||
|
msg := gmessaging.DemoRequestEvent{
|
||||||
|
Name: drn.request.Name,
|
||||||
|
OrganizationName: drn.request.OrganizationName,
|
||||||
|
Phone: drn.request.Phone,
|
||||||
|
WorkEmail: drn.request.WorkEmail,
|
||||||
|
PayoutVolume: drn.request.PayoutVolume,
|
||||||
|
Comment: drn.request.Comment,
|
||||||
|
}
|
||||||
|
data, err := proto.Marshal(&msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return drn.Envelope.Wrap(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDemoRequestEvent() model.NotificationEvent {
|
||||||
|
return model.NewNotification(mservice.Site, nm.NACreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDemoRequestEnvelope(sender string, request *model.DemoRequest) messaging.Envelope {
|
||||||
|
return &DemoRequestNotification{
|
||||||
|
Envelope: messaging.CreateEnvelope(sender, NewDemoRequestEvent()),
|
||||||
|
request: request,
|
||||||
|
}
|
||||||
|
}
|
||||||
11
api/pkg/messaging/notifications/site/demo_request.go
Normal file
11
api/pkg/messaging/notifications/site/demo_request.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
internalsite "github.com/tech/sendico/pkg/messaging/internal/notifications/site"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DemoRequest(sender string, request *model.DemoRequest) messaging.Envelope {
|
||||||
|
return internalsite.NewDemoRequestEnvelope(sender, request)
|
||||||
|
}
|
||||||
9
api/pkg/messaging/notifications/site/handler/handler.go
Normal file
9
api/pkg/messaging/notifications/site/handler/handler.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DemoRequestHandler = func(context.Context, *model.DemoRequest) error
|
||||||
50
api/pkg/messaging/notifications/site/processor.go
Normal file
50
api/pkg/messaging/notifications/site/processor.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
gmessaging "github.com/tech/sendico/pkg/generated/gmessaging"
|
||||||
|
me "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
internalsite "github.com/tech/sendico/pkg/messaging/internal/notifications/site"
|
||||||
|
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||||
|
handler "github.com/tech/sendico/pkg/messaging/notifications/site/handler"
|
||||||
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DemoRequestProcessor struct {
|
||||||
|
logger mlogger.Logger
|
||||||
|
handler handler.DemoRequestHandler
|
||||||
|
event model.NotificationEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drp *DemoRequestProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||||
|
var msg gmessaging.DemoRequestEvent
|
||||||
|
if err := proto.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||||
|
drp.logger.Warn("Failed to decode demo request envelope", zap.Error(err), zap.String("topic", drp.event.ToString()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request := &model.DemoRequest{
|
||||||
|
Name: msg.GetName(),
|
||||||
|
OrganizationName: msg.GetOrganizationName(),
|
||||||
|
Phone: msg.GetPhone(),
|
||||||
|
WorkEmail: msg.GetWorkEmail(),
|
||||||
|
PayoutVolume: msg.GetPayoutVolume(),
|
||||||
|
Comment: msg.GetComment(),
|
||||||
|
}
|
||||||
|
return drp.handler(ctx, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (drp *DemoRequestProcessor) GetSubject() model.NotificationEvent {
|
||||||
|
return drp.event
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDemoRequestProcessor(logger mlogger.Logger, handler handler.DemoRequestHandler) np.EnvelopeProcessor {
|
||||||
|
return &DemoRequestProcessor{
|
||||||
|
logger: logger.Named("demo_request_processor"),
|
||||||
|
handler: handler,
|
||||||
|
event: internalsite.NewDemoRequestEvent(),
|
||||||
|
}
|
||||||
|
}
|
||||||
53
api/pkg/model/demorequest.go
Normal file
53
api/pkg/model/demorequest.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DemoRequest represents a request submitted from the marketing site to request a demo.
|
||||||
|
type DemoRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
OrganizationName string `json:"organizationName"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
WorkEmail string `json:"workEmail"`
|
||||||
|
PayoutVolume string `json:"payoutVolume"`
|
||||||
|
Comment string `json:"comment,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize trims whitespace from all string fields.
|
||||||
|
func (dr *DemoRequest) Normalize() {
|
||||||
|
if dr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dr.Name = strings.TrimSpace(dr.Name)
|
||||||
|
dr.OrganizationName = strings.TrimSpace(dr.OrganizationName)
|
||||||
|
dr.Phone = strings.TrimSpace(dr.Phone)
|
||||||
|
dr.WorkEmail = strings.TrimSpace(dr.WorkEmail)
|
||||||
|
dr.PayoutVolume = strings.TrimSpace(dr.PayoutVolume)
|
||||||
|
dr.Comment = strings.TrimSpace(dr.Comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate ensures that all required fields are present.
|
||||||
|
func (dr *DemoRequest) Validate() error {
|
||||||
|
if dr == nil {
|
||||||
|
return merrors.InvalidArgument("request payload is empty")
|
||||||
|
}
|
||||||
|
if dr.Name == "" {
|
||||||
|
return merrors.InvalidArgument("name must not be empty")
|
||||||
|
}
|
||||||
|
if dr.OrganizationName == "" {
|
||||||
|
return merrors.InvalidArgument("organization name must not be empty")
|
||||||
|
}
|
||||||
|
if dr.Phone == "" {
|
||||||
|
return merrors.InvalidArgument("phone must not be empty")
|
||||||
|
}
|
||||||
|
if dr.WorkEmail == "" {
|
||||||
|
return merrors.InvalidArgument("work email must not be empty")
|
||||||
|
}
|
||||||
|
if dr.PayoutVolume == "" {
|
||||||
|
return merrors.InvalidArgument("payout volume must not be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
api/pkg/model/demorequest_test.go
Normal file
31
api/pkg/model/demorequest_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDemoRequestNormalizeAndValidate(t *testing.T) {
|
||||||
|
req := &DemoRequest{
|
||||||
|
Name: " Alice ",
|
||||||
|
OrganizationName: " Sendico ",
|
||||||
|
Phone: " +1 234 ",
|
||||||
|
WorkEmail: " demo@sendico.io ",
|
||||||
|
PayoutVolume: " 100k ",
|
||||||
|
Comment: " Excited ",
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Normalize()
|
||||||
|
if err := req.Validate(); err != nil {
|
||||||
|
t.Fatalf("expected request to be valid, got error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name != "Alice" || req.OrganizationName != "Sendico" || req.Phone != "+1 234" || req.WorkEmail != "demo@sendico.io" || req.PayoutVolume != "100k" || req.Comment != "Excited" {
|
||||||
|
t.Fatalf("normalize failed: %+v", req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDemoRequestValidateMissing(t *testing.T) {
|
||||||
|
req := &DemoRequest{}
|
||||||
|
req.Normalize()
|
||||||
|
if err := req.Validate(); err == nil {
|
||||||
|
t.Fatalf("expected validation error for empty request")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ type Type = string
|
|||||||
const (
|
const (
|
||||||
Accounts Type = "accounts" // Represents user accounts in the system
|
Accounts Type = "accounts" // Represents user accounts in the system
|
||||||
Amplitude Type = "amplitude" // Represents analytics integration with Amplitude
|
Amplitude Type = "amplitude" // Represents analytics integration with Amplitude
|
||||||
|
Site Type = "site" // Represents public site endpoints
|
||||||
Automations Type = "automation" // Represents automation workflows
|
Automations Type = "automation" // Represents automation workflows
|
||||||
Changes Type = "changes" // Tracks changes made to resources
|
Changes Type = "changes" // Tracks changes made to resources
|
||||||
Clients Type = "clients" // Represents client information
|
Clients Type = "clients" // Represents client information
|
||||||
@@ -59,7 +60,7 @@ const (
|
|||||||
|
|
||||||
func StringToSType(s string) (Type, error) {
|
func StringToSType(s string) (Type, error) {
|
||||||
switch Type(s) {
|
switch Type(s) {
|
||||||
case Accounts, Amplitude, Automations, Changes, Clients, Comments, ChainGateway, ChainWallets, ChainWalletBalances,
|
case Accounts, Amplitude, Site, Automations, Changes, Clients, Comments, ChainGateway, ChainWallets, ChainWalletBalances,
|
||||||
ChainTransfers, ChainDeposits, FXOracle, FeePlans, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
ChainTransfers, ChainDeposits, FXOracle, FeePlans, FilterProjects, Invitations, Invoices, Logo, Ledger,
|
||||||
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
LedgerAccounts, LedgerBalances, LedgerEntries, LedgerOutbox, LedgerParties, LedgerPlines, Notifications,
|
||||||
Organizations, Payments, PaymentOrchestrator, Permissions, Policies, PolicyAssignements, Priorities,
|
Organizations, Payments, PaymentOrchestrator, Permissions, Policies, PolicyAssignements, Priorities,
|
||||||
|
|||||||
12
api/proto/demo_request.proto
Normal file
12
api/proto/demo_request.proto
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "github.com/tech/sendico/pkg/generated/gmessaging";
|
||||||
|
|
||||||
|
message DemoRequestEvent {
|
||||||
|
string Name = 1;
|
||||||
|
string OrganizationName = 2;
|
||||||
|
string Phone = 3;
|
||||||
|
string WorkEmail = 4;
|
||||||
|
string PayoutVolume = 5;
|
||||||
|
string Comment = 6;
|
||||||
|
}
|
||||||
11
api/server/interface/services/site/site.go
Normal file
11
api/server/interface/services/site/site.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package site
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
|
eapi "github.com/tech/sendico/server/interface/api"
|
||||||
|
"github.com/tech/sendico/server/internal/server/siteimp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Create(a eapi.API) (mservice.MicroService, error) {
|
||||||
|
return siteimp.CreateAPI(a)
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/tech/sendico/server/interface/services/logo"
|
"github.com/tech/sendico/server/interface/services/logo"
|
||||||
"github.com/tech/sendico/server/interface/services/organization"
|
"github.com/tech/sendico/server/interface/services/organization"
|
||||||
"github.com/tech/sendico/server/interface/services/permission"
|
"github.com/tech/sendico/server/interface/services/permission"
|
||||||
|
"github.com/tech/sendico/server/interface/services/site"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ func (a *APIImp) installServices() error {
|
|||||||
srvf = append(srvf, invitation.Create)
|
srvf = append(srvf, invitation.Create)
|
||||||
srvf = append(srvf, logo.Create)
|
srvf = append(srvf, logo.Create)
|
||||||
srvf = append(srvf, permission.Create)
|
srvf = append(srvf, permission.Create)
|
||||||
|
srvf = append(srvf, site.Create)
|
||||||
|
|
||||||
for _, v := range srvf {
|
for _, v := range srvf {
|
||||||
if err := a.addMicroservice(v); err != nil {
|
if err := a.addMicroservice(v); err != nil {
|
||||||
|
|||||||
60
api/server/internal/server/siteimp/service.go
Normal file
60
api/server/internal/server/siteimp/service.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package siteimp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
api "github.com/tech/sendico/pkg/api/http"
|
||||||
|
"github.com/tech/sendico/pkg/api/http/response"
|
||||||
|
"github.com/tech/sendico/pkg/messaging"
|
||||||
|
snotifications "github.com/tech/sendico/pkg/messaging/notifications/site"
|
||||||
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
|
eapi "github.com/tech/sendico/server/interface/api"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SiteAPI struct {
|
||||||
|
logger mlogger.Logger
|
||||||
|
producer messaging.Producer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *SiteAPI) Name() mservice.Type {
|
||||||
|
return mservice.Site
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *SiteAPI) Finish(_ context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *SiteAPI) demoRequest(r *http.Request) http.HandlerFunc {
|
||||||
|
var request model.DemoRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||||
|
a.logger.Warn("Failed to decode demo request payload", zap.Error(err))
|
||||||
|
return response.BadRequest(a.logger, a.Name(), "invalid_payload", "Failed to decode demo request payload")
|
||||||
|
}
|
||||||
|
request.Normalize()
|
||||||
|
if err := request.Validate(); err != nil {
|
||||||
|
a.logger.Warn("Demo request validation failed", zap.Error(err))
|
||||||
|
return response.BadPayload(a.logger, a.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.producer.SendMessage(snotifications.DemoRequest(a.Name(), &request)); err != nil {
|
||||||
|
a.logger.Warn("Failed to enqueue demo request notification", zap.Error(err))
|
||||||
|
return response.Internal(a.logger, a.Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Accepted(a.logger, map[string]string{"status": "queued"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateAPI(a eapi.API) (*SiteAPI, error) {
|
||||||
|
p := &SiteAPI{
|
||||||
|
logger: a.Logger().Named(mservice.Site),
|
||||||
|
producer: a.Register().Messaging().Producer(),
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Register().Handler(mservice.Site, "/demo/request", api.Post, p.demoRequest)
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
@@ -15,9 +15,9 @@ PERMISSION_IS_FILTERED=false
|
|||||||
AMPLI_ENVIRONMENT=production
|
AMPLI_ENVIRONMENT=production
|
||||||
API_PROTOCOL=https
|
API_PROTOCOL=https
|
||||||
SERVICE_HOST=app.sendico.io
|
SERVICE_HOST=app.sendico.io
|
||||||
API_ENDPOINT=https://app.sendico.io/api
|
API_ENDPOINT=/api/v1
|
||||||
WS_PROTOCOL=wss
|
WS_PROTOCOL=wss
|
||||||
WS_ENDPOINT=wss://app.sendico.io/ws
|
WS_ENDPOINT=/ws
|
||||||
AMPLITUDE_SECRET=c3d75b3e2520d708440acbb16b923e79
|
AMPLITUDE_SECRET=c3d75b3e2520d708440acbb16b923e79
|
||||||
DEFAULT_LOCALE=en
|
DEFAULT_LOCALE=en
|
||||||
DEFAULT_CURRENCY=EUR
|
DEFAULT_CURRENCY=EUR
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ services:
|
|||||||
NATS_URL: ${NATS_URL}
|
NATS_URL: ${NATS_URL}
|
||||||
MAIL_USER: ${MAIL_USER}
|
MAIL_USER: ${MAIL_USER}
|
||||||
MAIL_SECRET: ${MAIL_SECRET}
|
MAIL_SECRET: ${MAIL_SECRET}
|
||||||
|
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN}
|
||||||
|
TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID}
|
||||||
|
TELEGRAM_THREAD_ID: ${TELEGRAM_THREAD_ID}
|
||||||
MONGO_HOST: ${MONGO_HOST}
|
MONGO_HOST: ${MONGO_HOST}
|
||||||
MONGO_PORT: ${MONGO_PORT}
|
MONGO_PORT: ${MONGO_PORT}
|
||||||
MONGO_DATABASE: ${MONGO_DATABASE}
|
MONGO_DATABASE: ${MONGO_DATABASE}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ REQUIRED_SECRETS=(
|
|||||||
NATS_USER
|
NATS_USER
|
||||||
NATS_PASSWORD
|
NATS_PASSWORD
|
||||||
NATS_URL
|
NATS_URL
|
||||||
|
TELEGRAM_BOT_TOKEN
|
||||||
|
TELEGRAM_CHAT_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
for var in "${REQUIRED_SECRETS[@]}"; do
|
for var in "${REQUIRED_SECRETS[@]}"; do
|
||||||
@@ -50,6 +52,9 @@ API_ENDPOINT_SECRET_B64="$(b64enc "${API_ENDPOINT_SECRET}")"
|
|||||||
NATS_USER_B64="$(b64enc "${NATS_USER}")"
|
NATS_USER_B64="$(b64enc "${NATS_USER}")"
|
||||||
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
|
NATS_PASSWORD_B64="$(b64enc "${NATS_PASSWORD}")"
|
||||||
NATS_URL_B64="$(b64enc "${NATS_URL}")"
|
NATS_URL_B64="$(b64enc "${NATS_URL}")"
|
||||||
|
TELEGRAM_BOT_TOKEN_B64="$(b64enc "${TELEGRAM_BOT_TOKEN}")"
|
||||||
|
TELEGRAM_CHAT_ID_B64="$(b64enc "${TELEGRAM_CHAT_ID}")"
|
||||||
|
TELEGRAM_THREAD_ID_B64="$(b64enc "${TELEGRAM_THREAD_ID:-}")"
|
||||||
|
|
||||||
SSH_OPTS=(
|
SSH_OPTS=(
|
||||||
-i /root/.ssh/id_rsa
|
-i /root/.ssh/id_rsa
|
||||||
@@ -86,6 +91,9 @@ ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" \
|
|||||||
NATS_USER_B64="$NATS_USER_B64" \
|
NATS_USER_B64="$NATS_USER_B64" \
|
||||||
NATS_PASSWORD_B64="$NATS_PASSWORD_B64" \
|
NATS_PASSWORD_B64="$NATS_PASSWORD_B64" \
|
||||||
NATS_URL_B64="$NATS_URL_B64" \
|
NATS_URL_B64="$NATS_URL_B64" \
|
||||||
|
TELEGRAM_BOT_TOKEN_B64="$TELEGRAM_BOT_TOKEN_B64" \
|
||||||
|
TELEGRAM_CHAT_ID_B64="$TELEGRAM_CHAT_ID_B64" \
|
||||||
|
TELEGRAM_THREAD_ID_B64="$TELEGRAM_THREAD_ID_B64" \
|
||||||
bash -s <<'EOSSH'
|
bash -s <<'EOSSH'
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "${REMOTE_DIR}/compose"
|
cd "${REMOTE_DIR}/compose"
|
||||||
@@ -135,10 +143,14 @@ API_ENDPOINT_SECRET="$(decode_b64 "$API_ENDPOINT_SECRET_B64")"
|
|||||||
NATS_USER="$(decode_b64 "$NATS_USER_B64")"
|
NATS_USER="$(decode_b64 "$NATS_USER_B64")"
|
||||||
NATS_PASSWORD="$(decode_b64 "$NATS_PASSWORD_B64")"
|
NATS_PASSWORD="$(decode_b64 "$NATS_PASSWORD_B64")"
|
||||||
NATS_URL="$(decode_b64 "$NATS_URL_B64")"
|
NATS_URL="$(decode_b64 "$NATS_URL_B64")"
|
||||||
|
TELEGRAM_BOT_TOKEN="$(decode_b64 "$TELEGRAM_BOT_TOKEN_B64")"
|
||||||
|
TELEGRAM_CHAT_ID="$(decode_b64 "$TELEGRAM_CHAT_ID_B64")"
|
||||||
|
TELEGRAM_THREAD_ID="$(decode_b64 "$TELEGRAM_THREAD_ID_B64")"
|
||||||
|
|
||||||
export MONGO_USER MONGO_PASSWORD
|
export MONGO_USER MONGO_PASSWORD
|
||||||
export MAIL_USER MAIL_SECRET API_ENDPOINT_SECRET
|
export MAIL_USER MAIL_SECRET API_ENDPOINT_SECRET
|
||||||
export NATS_USER NATS_PASSWORD NATS_URL
|
export NATS_USER NATS_PASSWORD NATS_URL
|
||||||
|
export TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID TELEGRAM_THREAD_ID
|
||||||
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
|
COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT"
|
||||||
export COMPOSE_PROJECT_NAME
|
export COMPOSE_PROJECT_NAME
|
||||||
read -r -a SERVICES <<<"${SERVICES_LINE}"
|
read -r -a SERVICES <<<"${SERVICES_LINE}"
|
||||||
|
|||||||
@@ -4,7 +4,14 @@ set -eu
|
|||||||
START_DIR="$(pwd)"
|
START_DIR="$(pwd)"
|
||||||
echo "[bump-version] invoked from ${START_DIR}"
|
echo "[bump-version] invoked from ${START_DIR}"
|
||||||
|
|
||||||
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
REPO_ROOT=""
|
||||||
|
if command -v git >/dev/null 2>&1; then
|
||||||
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
if [ -z "${REPO_ROOT}" ]; then
|
||||||
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||||
|
fi
|
||||||
echo "[bump-version] repo root resolved to ${REPO_ROOT}"
|
echo "[bump-version] repo root resolved to ${REPO_ROOT}"
|
||||||
cd "${REPO_ROOT}"
|
cd "${REPO_ROOT}"
|
||||||
|
|
||||||
@@ -60,4 +67,20 @@ if [ -z "${BRANCH}" ] || [ "${BRANCH}" = "HEAD" ]; then
|
|||||||
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NETRC_MACHINE="${CI_NETRC_MACHINE:-${WOODPECKER_NETRC_MACHINE:-}}"
|
||||||
|
NETRC_USERNAME="${CI_NETRC_USERNAME:-${WOODPECKER_NETRC_USERNAME:-${CI_NETRC_LOGIN:-${WOODPECKER_NETRC_LOGIN:-}}}}"
|
||||||
|
NETRC_PASSWORD="${CI_NETRC_PASSWORD:-${WOODPECKER_NETRC_PASSWORD:-}}"
|
||||||
|
if [ -n "${NETRC_MACHINE}" ] && [ -n "${NETRC_USERNAME}" ] && [ -n "${NETRC_PASSWORD}" ]; then
|
||||||
|
NETRC_FILE="${HOME:-/root}/.netrc"
|
||||||
|
if [ ! -f "${NETRC_FILE}" ]; then
|
||||||
|
{
|
||||||
|
printf 'machine %s\n' "${NETRC_MACHINE}"
|
||||||
|
printf 'login %s\n' "${NETRC_USERNAME}"
|
||||||
|
printf 'password %s\n' "${NETRC_PASSWORD}"
|
||||||
|
} > "${NETRC_FILE}"
|
||||||
|
chmod 600 "${NETRC_FILE}"
|
||||||
|
echo "[bump-version] wrote credentials for ${NETRC_MACHINE}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
git push origin "HEAD:${BRANCH}"
|
git push origin "HEAD:${BRANCH}"
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ load_env_file ./.env.version
|
|||||||
NOTIFICATION_MONGO_SECRET_PATH="${NOTIFICATION_MONGO_SECRET_PATH:?missing NOTIFICATION_MONGO_SECRET_PATH}"
|
NOTIFICATION_MONGO_SECRET_PATH="${NOTIFICATION_MONGO_SECRET_PATH:?missing NOTIFICATION_MONGO_SECRET_PATH}"
|
||||||
NOTIFICATION_MAIL_SECRET_PATH="${NOTIFICATION_MAIL_SECRET_PATH:?missing NOTIFICATION_MAIL_SECRET_PATH}"
|
NOTIFICATION_MAIL_SECRET_PATH="${NOTIFICATION_MAIL_SECRET_PATH:?missing NOTIFICATION_MAIL_SECRET_PATH}"
|
||||||
NOTIFICATION_API_SECRET_PATH="${NOTIFICATION_API_SECRET_PATH:?missing NOTIFICATION_API_SECRET_PATH}"
|
NOTIFICATION_API_SECRET_PATH="${NOTIFICATION_API_SECRET_PATH:?missing NOTIFICATION_API_SECRET_PATH}"
|
||||||
|
NOTIFICATION_TELEGRAM_SECRET_PATH="${NOTIFICATION_TELEGRAM_SECRET_PATH:?missing NOTIFICATION_TELEGRAM_SECRET_PATH}"
|
||||||
: "${NATS_HOST:?missing NATS_HOST}"
|
: "${NATS_HOST:?missing NATS_HOST}"
|
||||||
: "${NATS_PORT:?missing NATS_PORT}"
|
: "${NATS_PORT:?missing NATS_PORT}"
|
||||||
|
|
||||||
@@ -60,6 +61,14 @@ export MAIL_SECRET="$(./ci/vlt kv_get kv "${NOTIFICATION_MAIL_SECRET_PATH}" pass
|
|||||||
|
|
||||||
export API_ENDPOINT_SECRET="$(./ci/vlt kv_get kv "${NOTIFICATION_API_SECRET_PATH}" secret)"
|
export API_ENDPOINT_SECRET="$(./ci/vlt kv_get kv "${NOTIFICATION_API_SECRET_PATH}" secret)"
|
||||||
|
|
||||||
|
export TELEGRAM_BOT_TOKEN="$(./ci/vlt kv_get kv "${NOTIFICATION_TELEGRAM_SECRET_PATH}" bot_token)"
|
||||||
|
export TELEGRAM_CHAT_ID="$(./ci/vlt kv_get kv "${NOTIFICATION_TELEGRAM_SECRET_PATH}" chat_id)"
|
||||||
|
TELEGRAM_THREAD_ID=""
|
||||||
|
if TELEGRAM_THREAD_ID_VALUE="$(./ci/vlt kv_get kv "${NOTIFICATION_TELEGRAM_SECRET_PATH}" thread_id 2>/dev/null)"; then
|
||||||
|
TELEGRAM_THREAD_ID="$TELEGRAM_THREAD_ID_VALUE"
|
||||||
|
fi
|
||||||
|
export TELEGRAM_THREAD_ID
|
||||||
|
|
||||||
export NATS_USER="$(./ci/vlt kv_get kv sendico/nats user)"
|
export NATS_USER="$(./ci/vlt kv_get kv sendico/nats user)"
|
||||||
export NATS_PASSWORD="$(./ci/vlt kv_get kv sendico/nats password)"
|
export NATS_PASSWORD="$(./ci/vlt kv_get kv sendico/nats password)"
|
||||||
export NATS_URL="nats://${NATS_USER}:${NATS_PASSWORD}@${NATS_HOST}:${NATS_PORT}"
|
export NATS_URL="nats://${NATS_USER}:${NATS_PASSWORD}@${NATS_HOST}:${NATS_PORT}"
|
||||||
|
|||||||
Reference in New Issue
Block a user