From 6fa5ede3587cfc70553313f4dca0e96c080ae13f Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Dec 2025 22:39:29 +0000 Subject: [PATCH] tsk-54: Tweak instant message endpoint to save contact and message identification (#56) Closes #54 Reviewed-on: https://git.kundeng.us/phoenix/textsender-api/pulls/56 Co-authored-by: phoenix Co-committed-by: phoenix --- go.mod | 4 ++-- go.sum | 8 +++---- internal/app/app.go | 2 +- internal/config/config.go | 24 +++++++++---------- internal/handler/contact.go | 6 ++--- internal/handler/instant_message.go | 3 +++ internal/handler/message_event_response.go | 11 +++++++++ .../handler/message_event_response_test.go | 2 +- .../store/message_event_response_store.go | 8 +++---- migrations/schema.sql | 5 +++- 10 files changed, 45 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 2e182ff..51f4ae7 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module git.kundeng.us/phoenix/textsender-api go 1.25.4 require ( - git.kundeng.us/phoenix/swoosh v0.0.7 - git.kundeng.us/phoenix/textsender-models v0.0.11 + git.kundeng.us/phoenix/swoosh v0.0.7-8-523c7cf67c-556 + git.kundeng.us/phoenix/textsender-models v0.0.12 github.com/go-chi/chi/v5 v5.2.3 github.com/go-chi/cors v1.2.2 github.com/golang-jwt/jwt/v5 v5.3.0 diff --git a/go.sum b/go.sum index 17b1333..848543d 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -git.kundeng.us/phoenix/swoosh v0.0.7 h1:9M42tgKr6o34YOiwds7offvjCUoFzYN2B5TrFKbefFo= -git.kundeng.us/phoenix/swoosh v0.0.7/go.mod h1:9iXlBd7UCMA7/jj8gZ1CxEfBualsClpiJrqGj8Fo2Xw= -git.kundeng.us/phoenix/textsender-models v0.0.11 h1:kd2FdeZJhJJAXBm8MoyadtgNGyzC+puU1oR8B8N+MfE= -git.kundeng.us/phoenix/textsender-models v0.0.11/go.mod h1:9iPDQJg1Tc6WMNoW5+f8YKmnosMwlWHJ++hmxNLDEe0= +git.kundeng.us/phoenix/swoosh v0.0.7-8-523c7cf67c-556 h1:vzTrhx7auc8OlUGmfTDektHXCkoFOKzVhdsW+6oKXMI= +git.kundeng.us/phoenix/swoosh v0.0.7-8-523c7cf67c-556/go.mod h1:OAh9jVBQ3vRJ1EHTM6pFyWd9eXf1H+CevbDKkJuoDZU= +git.kundeng.us/phoenix/textsender-models v0.0.12 h1:ps9H3FS5LyCwQhAiIvg4vYyfLZZ64dex1y9ytb0o9C4= +git.kundeng.us/phoenix/textsender-models v0.0.12/go.mod h1:9iPDQJg1Tc6WMNoW5+f8YKmnosMwlWHJ++hmxNLDEe0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= diff --git a/internal/app/app.go b/internal/app/app.go index f09df6f..f2ef963 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -5,5 +5,5 @@ import ( ) type App struct { - TwilioConfig *config.TwiloConfig + TwilioConfig *config.TwilioConfig } diff --git a/internal/config/config.go b/internal/config/config.go index 9efeea0..f330faa 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,11 +14,11 @@ import ( ) type Config struct { - DBConnString string - ServerPort string - ResetDB bool - JWTSecret string `env:"JWT_SECRET" required:"true"` - TwilioConfig *config.TwiloConfig + DBConnString string + ServerPort string + ResetDB bool + JWTSecret string `env:"JWT_SECRET" required:"true"` + TwilioConfig *config.TwilioConfig AllowedOrigins []string } @@ -49,7 +49,7 @@ func PrintName() { fmt.Println(version.String()) } -func Load() (*Config, *config.TwiloConfig, error) { +func Load() (*Config, *config.TwilioConfig, error) { versionFlag := flag.Bool("version", false, "Print version information") resetDb := flag.Bool("reset-db", false, "Reset the database schema and exit") port := flag.String("port", PORT, "Server port") @@ -72,10 +72,10 @@ func Load() (*Config, *config.TwiloConfig, error) { } else { allowedOrigins := unpackAllowedOrigins() return &Config{ - DBConnString: dbConnString, - ServerPort: *port, - ResetDB: *resetDb, - JWTSecret: os.Getenv("JWT_SECRET"), + DBConnString: dbConnString, + ServerPort: *port, + ResetDB: *resetDb, + JWTSecret: os.Getenv("JWT_SECRET"), AllowedOrigins: allowedOrigins, }, cfg, nil } @@ -138,7 +138,7 @@ func unpackAllowedOrigins() []string { return allowedOriginsSplit } -func TwilioConfig() (*config.TwiloConfig, error) { +func TwilioConfig() (*config.TwilioConfig, error) { authSid := os.Getenv("TWILIO_AUTH_SID") serviceSid := os.Getenv("TWILIO_SERVICE_SID") authToken := os.Getenv("TWILIO_AUTH_TOKEN") @@ -153,7 +153,7 @@ func TwilioConfig() (*config.TwiloConfig, error) { } else if len(phoneNumber) == 0 { return nil, fmt.Errorf("Twilio config phone number not found") } else { - var cfg config.TwiloConfig + var cfg config.TwilioConfig cfg.AccountSID = authSid cfg.ServiceSID = serviceSid cfg.AuthToken = authToken diff --git a/internal/handler/contact.go b/internal/handler/contact.go index 55c6097..bacd14f 100644 --- a/internal/handler/contact.go +++ b/internal/handler/contact.go @@ -54,14 +54,14 @@ func (c *ContactHandler) AddContact(w http.ResponseWriter, r *http.Request) { } defer r.Body.Close() - newContact := contact.Contact{PhoneNumber: req.PhoneNumber, UserId: req.UserId} + newContact := contact.Contact{PhoneNumber: req.PhoneNumber, UserId: &req.UserId} var statusCode int var resp AddContactResponse ctx := r.Context() - if exists, err := c.ContactStore.ContactExists(ctx, newContact.PhoneNumber, newContact.UserId); err != nil { + if exists, err := c.ContactStore.ContactExists(ctx, newContact.PhoneNumber, *newContact.UserId); err != nil { fmt.Printf("Error: %v", err) statusCode = http.StatusInternalServerError resp.Message = err.Error() @@ -157,7 +157,7 @@ func (c *ContactHandler) GetContact(w http.ResponseWriter, r *http.Request) { fmt.Println("Checking with User Id") if contacts, err := c.ContactStore.GetAllContacts(ctx); err == nil { for _, con := range contacts { - if con.UserId == userId { + if *con.UserId == userId { resp.Data = append(resp.Data, *con) } } diff --git a/internal/handler/instant_message.go b/internal/handler/instant_message.go index deafa46..3160d4b 100644 --- a/internal/handler/instant_message.go +++ b/internal/handler/instant_message.go @@ -110,6 +110,9 @@ func (s *SendInstantMessageHandler) Send(w http.ResponseWriter, r *http.Request) mer.Response = data mer.UserId = req.UserId mer.Sent = parsedTime + mer.Status = message.Message_Event_Response_Status_Instant + mer.ContactId = c.Id + mer.MessageId = &msg.Id if err := s.MERStore.Create(ctx, &mer); err != nil { statusCode = http.StatusInternalServerError resp.Message = err.Error() diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index 8fbe6ec..cd9646b 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -26,6 +26,9 @@ type RecordEventRequest struct { Response types.JSONB `json:"response"` UserId uuid.UUID `json:"user_id"` Sent *time.Time `json:"sent,omitempty"` + Status string `json:"status"` + ContactId *uuid.UUID `json:"contact_id"` + MessageId *uuid.UUID `json:"message_id"` } type RecordEventResponse struct { @@ -62,6 +65,14 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req rp.UserId = req.UserId rp.Sent = *req.Sent + if req.Status == message.Message_Event_Response_Status_Instant { + rp.Status = req.Status + rp.MessageId = req.MessageId + rp.ContactId = req.ContactId + } else if req.Status == message.Message_Event_Response_Status_Scheduled { + rp.Status = req.Status + } + ctx := r.Context() if err := e.MessageEventResponseStore.Create(ctx, &rp); err != nil { resp.Message = err.Error() diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index 879ab9f..5420999 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -60,7 +60,7 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { sent := now.Add(30 * time.Minute) bytes := []byte("{\"body\":\"Whoknows?\",\"num_segments\":\"0\",\"direction\":\"outbound-api\",\"from\":\"+12243026041\",\"to\":\"+16303831708\",\"date_updated\":\"Sat,29Nov202519:06:59+0000\",\"uri\":\"/2010-04-01/Accounts/ACefa1ef516314c9d1a68cbd657de49277/Messages/SM1193a529e7f7a840667cd1e0f13ea95a.json\",\"account_sid\":\"ACefa1ef516314c9d1a68cbd657de49277\",\"num_media\":\"0\",\"status\":\"scheduled\",\"messaging_service_sid\":\"MG803f3676706b92eb02e18dd820c447f2\",\"sid\":\"SM1193a529e7f7a840667cd1e0f13ea95a\",\"date_created\":\"Sat,29Nov202519:06:59+0000\",\"api_version\":\"2010-04-01\",\"subresource_uris\":{\"media\":\"/2010-04-01/Accounts/ACefa1ef516314c9d1a68cbd657de49277/Messages/SM1193a529e7f7a840667cd1e0f13ea95a/Media.json\"}}") - testReq := RecordEventRequest{ScheduledMessageEventId: event.Id, Response: bytes, UserId: schMsg.UserId, Sent: &sent} + testReq := RecordEventRequest{ScheduledMessageEventId: event.Id, Response: bytes, UserId: schMsg.UserId, Sent: &sent, Status: message.Message_Event_Response_Status_Scheduled} jsonValue, _ := json.Marshal(testReq) req, _ := http.NewRequest("POST", endpoint.RecordEventResponse, strings.NewReader(string(jsonValue))) diff --git a/internal/store/message_event_response_store.go b/internal/store/message_event_response_store.go index 9eae924..031d25e 100644 --- a/internal/store/message_event_response_store.go +++ b/internal/store/message_event_response_store.go @@ -27,10 +27,10 @@ func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *message.M queryReturn := "RETURNING id" if mer.ScheduledMessageEventId == uuid.Nil { - query = fmt.Sprintf("%s (response, user_id, sent) VALUES ($1, $2, $3) %s", queryBase, queryReturn) - return m.db.QueryRow(ctx, query, mer.Response, mer.UserId, mer.Sent).Scan(&mer.Id) + query = fmt.Sprintf("%s (response, user_id, sent, contact_id, message_id) VALUES ($1, $2, $3, $4, $5) %s", queryBase, queryReturn) + return m.db.QueryRow(ctx, query, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId).Scan(&mer.Id) } else { - query = fmt.Sprintf("%s (scheduled_message_event_id, response, user_id, sent) %s", queryBase, queryReturn) - return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent).Scan(&mer.Id) + query = fmt.Sprintf("%s (scheduled_message_event_id, response, user_id, sent, contact_id, message_id) VALUES ($1, $2, $3, $4, $5, $6) %s", queryBase, queryReturn) + return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId).Scan(&mer.Id) } } diff --git a/migrations/schema.sql b/migrations/schema.sql index b37adad..f7a8a1a 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -39,5 +39,8 @@ CREATE TABLE IF NOT EXISTS message_event_responses ( scheduled_message_event_id UUID NULL, response JSONB NOT NULL, user_id UUID NOT NULL, - sent timestamptz NOT NULL + sent timestamptz NOT NULL, + contact_id UUID NULL, + message_id UUID NULL, + status TEXT CHECK (status IN ('INSTANT', 'SCHEDULED')) );