Move emails to platform, make sure to create phone and email in DB
This commit is contained in:
parent
dd33c6ab5e
commit
648e0ee567
17 changed files with 203 additions and 281 deletions
|
|
@ -5,10 +5,10 @@ import (
|
|||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/text"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package background
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/email"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Gleipnir-Technology/bob/types/pgtypes"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/aarondl/opt/omitnull"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func convertToPGData(data map[string]string) pgtypes.HStore {
|
||||
result := pgtypes.HStore{}
|
||||
for k, v := range data {
|
||||
result[k] = sql.Null[string]{V: v, Valid: true}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func convertFromPGData(d pgtypes.HStore) map[string]string {
|
||||
result := make(map[string]string, 0)
|
||||
for k, v := range d {
|
||||
value, err := v.Value()
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Str("key", k).Msg("Failed to convert from HSTORE")
|
||||
continue
|
||||
}
|
||||
value_str, ok := value.(string)
|
||||
if !ok {
|
||||
log.Warn().Msg("Failed to convert to string")
|
||||
}
|
||||
result[k] = value_str
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ensureInDB(ctx context.Context, destination string) (err error) {
|
||||
_, err = models.FindCommsEmailContact(ctx, db.PGInstance.BobDB, destination)
|
||||
if err != nil {
|
||||
// doesn't exist
|
||||
if err.Error() == "sql: no rows in result set" {
|
||||
public_id := fmt.Sprintf("%x", sha256.Sum256([]byte(destination)))
|
||||
_, err = models.CommsEmailContacts.Insert(&models.CommsEmailContactSetter{
|
||||
Address: omit.From(destination),
|
||||
Confirmed: omit.From(false),
|
||||
IsSubscribed: omit.From(false),
|
||||
PublicID: omit.From(public_id),
|
||||
}).One(ctx, db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to insert new email: %w", err)
|
||||
}
|
||||
log.Info().Str("email", destination).Msg("Added email to the comms database")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Unexpected error searching for contact: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func insertEmailLog(ctx context.Context, data map[string]string, destination string, public_id string, source string, subject string, template_id int32) (err error) {
|
||||
data_for_insert := convertToPGData(data)
|
||||
var type_ enums.CommsMessagetypeemail
|
||||
switch template_id {
|
||||
case templateReportNotificationConfirmationID:
|
||||
type_ = enums.CommsMessagetypeemailReportNotificationConfirmation
|
||||
case templateInitialID:
|
||||
type_ = enums.CommsMessagetypeemailInitialContact
|
||||
default:
|
||||
return fmt.Errorf("Unrecognized template ID %d", template_id)
|
||||
}
|
||||
_, err = models.CommsEmailLogs.Insert(&models.CommsEmailLogSetter{
|
||||
//ID:
|
||||
Created: omit.From(time.Now()),
|
||||
DeliveryStatus: omit.From("initial"),
|
||||
Destination: omit.From(destination),
|
||||
PublicID: omit.From(public_id),
|
||||
SentAt: omitnull.FromPtr[time.Time](nil),
|
||||
Source: omit.From(source),
|
||||
Subject: omit.From(subject),
|
||||
TemplateID: omit.From(template_id),
|
||||
TemplateData: omit.From(data_for_insert),
|
||||
Type: omit.From(type_),
|
||||
}).One(ctx, db.PGInstance.BobDB)
|
||||
|
||||
return err
|
||||
}
|
||||
func generatePublicId(t enums.CommsMessagetypeemail, m map[string]string) string {
|
||||
if m == nil || len(m) == 0 {
|
||||
// Return hash of empty string for empty maps
|
||||
emptyHash := sha256.Sum256([]byte(""))
|
||||
return hex.EncodeToString(emptyHash[:])
|
||||
}
|
||||
|
||||
// Get and sort keys for deterministic ordering
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Build a string with all key-value pairs
|
||||
var sb strings.Builder
|
||||
// Add type first
|
||||
sb.WriteString(fmt.Sprintf("type:%s,", t))
|
||||
for _, k := range keys {
|
||||
sb.WriteString(k)
|
||||
sb.WriteString(":") // Separator between key and value
|
||||
sb.WriteString(m[k])
|
||||
sb.WriteString(",") // Separator between pairs
|
||||
}
|
||||
|
||||
// Compute SHA-256 hash
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(sb.String()))
|
||||
hashBytes := hasher.Sum(nil)
|
||||
|
||||
// Convert to hex string and return
|
||||
return hex.EncodeToString(hashBytes)
|
||||
}
|
||||
|
|
@ -18,23 +18,7 @@ type attachmentRequest struct {
|
|||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type contentEmailBase struct {
|
||||
URLLogo string
|
||||
URLUnsubscribe string
|
||||
URLViewInBrowser string
|
||||
}
|
||||
|
||||
type contentEmailReportConfirmation struct {
|
||||
Base contentEmailBase
|
||||
URLReportStatus string
|
||||
}
|
||||
type contentEmailInitial struct {
|
||||
Base contentEmailBase
|
||||
Destination string
|
||||
URLSubscribe string
|
||||
}
|
||||
|
||||
type emailRequest struct {
|
||||
type Request struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
CC []string `json:"cc,omitempty"`
|
||||
|
|
@ -83,7 +67,7 @@ type emailResponse struct {
|
|||
|
||||
var FORWARDEMAIL_API = "https://api.forwardemail.net/v1/emails"
|
||||
|
||||
func sendEmail(ctx context.Context, email emailRequest, t enums.CommsMessagetypeemail) (response emailResponse, err error) {
|
||||
func Send(ctx context.Context, email Request, t enums.CommsMessagetypeemail) (response emailResponse, err error) {
|
||||
payload, err := json.Marshal(email)
|
||||
if err != nil {
|
||||
return response, fmt.Errorf("Failed to marshal email request: %w", err)
|
||||
|
|
|
|||
|
|
@ -1,102 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Thank You for Your Mosquito Report</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
color: #333333;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.view-browser {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #777777;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.view-browser a {
|
||||
color: #555555;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.logo {
|
||||
max-width: 150px;
|
||||
height: auto;
|
||||
}
|
||||
.content {
|
||||
background-color: #f9f9f9;
|
||||
padding: 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: #0066cc;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
padding: 12px 25px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.footer a {
|
||||
color: #777777;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{if not .IsBrowser}}
|
||||
<div class="view-browser">
|
||||
Email not displaying correctly? <a href="{{.C.URLViewInBrowser}}">View it in your browser</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="header">
|
||||
<!-- Logo Placeholder -->
|
||||
<img src="{{.C.URLLogo}}" alt="Report Mosquitoes Online Logo" class="logo">
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1>Thank You for Your Report</h1>
|
||||
|
||||
<p>We've received your mosquito report {{.C.ReportIDStr}}. Thanks! We appreciate you taking the time to submit it.</p>
|
||||
|
||||
<p>You can check the current status of your report at any time by clicking the button below:</p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{{.C.URLReportStatus}}" class="button">View Report Status</a>
|
||||
</div>
|
||||
|
||||
<p>We'll send you additional updates as work is scheduled and completed.</p>
|
||||
|
||||
<p>If you have any questions or need further assistance, please don't hesitate to contact us by replying to this email.</p>
|
||||
<p>You can unsubscribe from notifications about this report by clicking <a hrep="{{.C.URLReportUnsubscribe}}">here</a></p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>This email was sent to you because you requested updates on your mosquito nuisance report.</p>
|
||||
<p>If you no longer wish to receive these updates, <a href="{{.C.URLReportUnsubscribe}}">click here to unsubscribe</a>.</p>
|
||||
<p>© 2026 Gleipnir LLC. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
2
main.go
2
main.go
|
|
@ -13,11 +13,11 @@ import (
|
|||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/auth"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/background"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/html"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/llm"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/text"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/rmo"
|
||||
nidussync "github.com/Gleipnir-Technology/nidus-sync/sync"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
|
|
@ -11,6 +12,12 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type contentEmailInitial struct {
|
||||
Base contentEmailBase
|
||||
Destination string
|
||||
URLSubscribe string
|
||||
}
|
||||
|
||||
type jobInitial struct {
|
||||
base jobEmailBase
|
||||
}
|
||||
|
|
@ -20,7 +27,7 @@ func (job jobInitial) Destination() string {
|
|||
}
|
||||
|
||||
func maybeSendInitialEmail(ctx context.Context, destination string) error {
|
||||
err := ensureInDB(ctx, destination)
|
||||
err := EnsureInDB(ctx, destination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to add email recipient to database: %w", err)
|
||||
}
|
||||
|
|
@ -65,7 +72,7 @@ func sendEmailInitialContact(ctx context.Context, destination string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed to store email log: %w", err)
|
||||
}
|
||||
resp, err := sendEmail(ctx, emailRequest{
|
||||
resp, err := email.Send(ctx, email.Request{
|
||||
From: source,
|
||||
HTML: html,
|
||||
Subject: subject,
|
||||
|
|
@ -4,11 +4,17 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type contentEmailReportConfirmation struct {
|
||||
Base contentEmailBase
|
||||
URLReportStatus string
|
||||
}
|
||||
|
||||
func NewJobReportNotificationConfirmation(destination, report_id string) Job {
|
||||
return jobEmailReportNotificationConfirmation{
|
||||
dest: destination,
|
||||
|
|
@ -68,7 +74,7 @@ func sendEmailReportConfirmation(ctx context.Context, job Job) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed to store email log: %w", err)
|
||||
}
|
||||
resp, err := sendEmail(ctx, emailRequest{
|
||||
resp, err := email.Send(ctx, email.Request{
|
||||
From: config.ForwardEmailReportAddress,
|
||||
HTML: html,
|
||||
Subject: subject,
|
||||
|
|
@ -37,6 +37,12 @@ var (
|
|||
templateReportNotificationConfirmationID int32
|
||||
)
|
||||
|
||||
type contentEmailBase struct {
|
||||
URLLogo string
|
||||
URLUnsubscribe string
|
||||
URLViewInBrowser string
|
||||
}
|
||||
|
||||
type ContentEmailRender struct {
|
||||
IsBrowser bool
|
||||
C any
|
||||
130
platform/email/template/report-notification-confirmation.html
Normal file
130
platform/email/template/report-notification-confirmation.html
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Thank You for Your Mosquito Report</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
color: #333333;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.view-browser {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #777777;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.view-browser a {
|
||||
color: #555555;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.logo {
|
||||
max-width: 150px;
|
||||
height: auto;
|
||||
}
|
||||
.content {
|
||||
background-color: #f9f9f9;
|
||||
padding: 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
background-color: #0066cc;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
padding: 12px 25px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.footer a {
|
||||
color: #777777;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{ if not .IsBrowser }}
|
||||
<div class="view-browser">
|
||||
Email not displaying correctly?
|
||||
<a href="{{ .C.URLViewInBrowser }}">View it in your browser</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="header">
|
||||
<!-- Logo Placeholder -->
|
||||
<img
|
||||
src="{{ .C.URLLogo }}"
|
||||
alt="Report Mosquitoes Online Logo"
|
||||
class="logo"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1>Thank You for Your Report</h1>
|
||||
|
||||
<p>
|
||||
We've received your mosquito report {{ .C.ReportIDStr }}. Thanks! We
|
||||
appreciate you taking the time to submit it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can check the current status of your report at any time by
|
||||
clicking the button below:
|
||||
</p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{{ .C.URLReportStatus }}" class="button"
|
||||
>View Report Status</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
We'll send you additional updates as work is scheduled and completed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have any questions or need further assistance, please don't
|
||||
hesitate to contact us by replying to this email.
|
||||
</p>
|
||||
<p>
|
||||
You can unsubscribe from notifications about this report by clicking
|
||||
<a hrep="{{ .C.URLReportUnsubscribe }}">here</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>
|
||||
This email was sent to you because you requested updates on your
|
||||
mosquito nuisance report.
|
||||
</p>
|
||||
<p>
|
||||
If you no longer wish to receive these updates,
|
||||
<a href="{{ .C.URLReportUnsubscribe }}">click here to unsubscribe</a>.
|
||||
</p>
|
||||
<p>© 2026 Gleipnir LLC. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/sql"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/text"
|
||||
"github.com/rs/zerolog/log"
|
||||
//"github.com/stephenafamo/scan"
|
||||
|
|
@ -65,16 +66,20 @@ func GenerateReportID() (string, error) {
|
|||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func RegisterNotificationEmail(ctx context.Context, txn bob.Tx, report_id string, email string) *ErrorWithCode {
|
||||
func RegisterNotificationEmail(ctx context.Context, txn bob.Tx, report_id string, destination string) *ErrorWithCode {
|
||||
some_report, err := findSomeReport(ctx, report_id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = some_report.addNotificationEmail(ctx, txn, email)
|
||||
e := email.EnsureInDB(ctx, destination)
|
||||
if e != nil {
|
||||
return newInternalError(e, "Failed to ensure phone is in DB")
|
||||
}
|
||||
err = some_report.addNotificationEmail(ctx, txn, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
background.ReportSubscriptionConfirmationEmail(email, report_id)
|
||||
background.ReportSubscriptionConfirmationEmail(destination, report_id)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +88,10 @@ func RegisterNotificationPhone(ctx context.Context, txn bob.Tx, report_id string
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e := text.EnsureInDB(ctx, phone)
|
||||
if e != nil {
|
||||
return newInternalError(e, "Failed to ensure phone is in DB")
|
||||
}
|
||||
err = some_report.addNotificationPhone(ctx, txn, phone)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -92,11 +101,11 @@ func RegisterNotificationPhone(ctx context.Context, txn bob.Tx, report_id string
|
|||
}
|
||||
|
||||
func RegisterSubscriptionEmail(ctx context.Context, txn bob.Tx, email string) *ErrorWithCode {
|
||||
log.Warn().Msg("RegisterSubscription not implemented yet")
|
||||
log.Warn().Str("email", email).Msg("RegisterSubscription not implemented yet")
|
||||
return nil
|
||||
}
|
||||
func RegisterSubscriptionPhone(ctx context.Context, txn bob.Tx, phone text.E164) *ErrorWithCode {
|
||||
log.Warn().Msg("RegisterSubscription not implemented yet")
|
||||
log.Warn().Str("phone", text.PhoneString(phone)).Msg("RegisterSubscription not implemented yet")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,9 @@ import (
|
|||
|
||||
type E164 = phonenumbers.PhoneNumber
|
||||
|
||||
func PhoneString(p E164) string {
|
||||
return phonenumbers.Format(&p, phonenumbers.E164)
|
||||
func EnsureInDB(ctx context.Context, destination E164) (err error) {
|
||||
return ensureInDB(ctx, PhoneString(destination))
|
||||
}
|
||||
|
||||
func HandleTextMessage(src string, dst string, body string) {
|
||||
ctx := context.Background()
|
||||
|
||||
|
|
@ -98,15 +97,27 @@ func ParsePhoneNumber(input string) (*E164, error) {
|
|||
return phonenumbers.Parse(input, "US")
|
||||
}
|
||||
|
||||
func PhoneString(p E164) string {
|
||||
return phonenumbers.Format(&p, phonenumbers.E164)
|
||||
}
|
||||
|
||||
func StoreSources() error {
|
||||
ctx := context.TODO()
|
||||
for _, n := range []string{config.PhoneNumberReportStr, config.PhoneNumberSupportStr, config.VoipMSNumber} {
|
||||
var err error
|
||||
// Deal with Voip.ms not expecting API calls with the prefixed +1
|
||||
if !strings.HasPrefix(n, "+1") {
|
||||
err = ensureInDB(ctx, "+1"+n)
|
||||
dest, err := ParsePhoneNumber("+1" + n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse +1'%s' as phone number: %w", n, err)
|
||||
}
|
||||
err = EnsureInDB(ctx, *dest)
|
||||
} else {
|
||||
err = ensureInDB(ctx, n)
|
||||
dest, err := ParsePhoneNumber(n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse '%s' as phone number: %w", n, err)
|
||||
}
|
||||
err = EnsureInDB(ctx, *dest)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to add number '%s' to DB: %w", n, err)
|
||||
|
|
@ -172,21 +183,6 @@ func sendInitialText(ctx context.Context, src string, dst string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ensureInitialText(ctx context.Context, src string, dst string) error {
|
||||
//
|
||||
rows, err := models.CommsTextLogs.Query(
|
||||
models.SelectWhere.CommsTextLogs.Destination.EQ(dst),
|
||||
models.SelectWhere.CommsTextLogs.IsWelcome.EQ(true),
|
||||
).All(ctx, db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to query text logs: %w", err)
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
return nil
|
||||
}
|
||||
return sendInitialText(ctx, src, dst)
|
||||
}
|
||||
|
||||
func ensureInDB(ctx context.Context, destination string) (err error) {
|
||||
_, err = models.FindCommsPhone(ctx, db.PGInstance.BobDB, destination)
|
||||
if err != nil {
|
||||
|
|
@ -208,6 +204,21 @@ func ensureInDB(ctx context.Context, destination string) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ensureInitialText(ctx context.Context, src string, dst string) error {
|
||||
//
|
||||
rows, err := models.CommsTextLogs.Query(
|
||||
models.SelectWhere.CommsTextLogs.Destination.EQ(dst),
|
||||
models.SelectWhere.CommsTextLogs.IsWelcome.EQ(true),
|
||||
).All(ctx, db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to query text logs: %w", err)
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
return nil
|
||||
}
|
||||
return sendInitialText(ctx, src, dst)
|
||||
}
|
||||
|
||||
func generateNextMessage(ctx context.Context, history []llm.Message, customer_phone string) (llm.Message, error) {
|
||||
_handle_report_status := func() (string, error) {
|
||||
return "Report: ABCD-1234-5678, District: Delta MVCD, Status: scheduled, Appointment: Wednesday 3:30pm", nil
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package rmo
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/comms/email"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/html"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/email"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue