From 8728fe9b6071117201826bb9129ddfc70aa301ad Mon Sep 17 00:00:00 2001 From: phoenix Date: Tue, 30 Dec 2025 19:13:51 -0500 Subject: [PATCH 01/20] tsk-59: Added code to get MessageEventResponse --- .../store/message_event_response_store.go | 25 +++++++++++++++++++ .../mock/message_event_response_store.go | 2 ++ 2 files changed, 27 insertions(+) diff --git a/internal/store/message_event_response_store.go b/internal/store/message_event_response_store.go index 031d25e..4075772 100644 --- a/internal/store/message_event_response_store.go +++ b/internal/store/message_event_response_store.go @@ -11,6 +11,7 @@ import ( type MessageEventResponseStore interface { Create(ctx context.Context, mer *message.MessageEventResponse) error + GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) } type PGMessageEventResponseStore struct { @@ -34,3 +35,27 @@ func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *message.M return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId).Scan(&mer.Id) } } + +func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) { + query := "SELECT id, scheduled_message_event_id, response, user_id, sent, contact_id, message_id FROM message_event_responses WHERE user_id = $1" + rows, err := m.db.Query(ctx, query) + if err != nil { + return nil, fmt.Errorf("Error querying: %w", err) + } + defer rows.Close() + + var sentMessages []*message.MessageEventResponse + for rows.Next() { + var msg message.MessageEventResponse + if err := rows.Scan(&msg.Id, &msg.ScheduledMessageEventId, &msg.Response, &msg.UserId, &msg.Sent, &msg.ContactId, &msg.MessageId,); err != nil { + return nil, fmt.Errorf("Scanning row: %w", err) + } + sentMessages = append(sentMessages, &msg) + } + + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("Iterating message_event_responses: %w", err) + } + + return sentMessages, nil +} diff --git a/internal/store/mock/message_event_response_store.go b/internal/store/mock/message_event_response_store.go index a06a7b0..3833738 100644 --- a/internal/store/mock/message_event_response_store.go +++ b/internal/store/mock/message_event_response_store.go @@ -60,3 +60,5 @@ func (m *MockMessageEventResponseStore) Create(ctx context.Context, mer *message return nil } } + +// TODO: Add code to get mock MessageEventResponse From aefa26199da502d696bba3bd3a9a434b8d952d39 Mon Sep 17 00:00:00 2001 From: phoenix Date: Tue, 30 Dec 2025 19:30:23 -0500 Subject: [PATCH 02/20] tsk-59: Added endpoint constant and made changes to handler --- internal/handler/endpoint/endpoint.go | 2 ++ internal/handler/message_event_response.go | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/internal/handler/endpoint/endpoint.go b/internal/handler/endpoint/endpoint.go index 03ec1ff..dd45add 100644 --- a/internal/handler/endpoint/endpoint.go +++ b/internal/handler/endpoint/endpoint.go @@ -12,5 +12,7 @@ const GetScheduledMessageEventEndpoint = "/api/v1/schedule/message/event" const DeleteScheduledMessageEventEndpoint = "/api/v1/schedule/message/event/{id}" const UpdateScheduledMessageStatusEndpoint = "/api/v1/schedule/message/status/update" const FetchNextScheduledMessageEndpoint = "/api/v1/schedule/message/fetch" +// TODO: Make RecordEventResponse more consistent with MessageEventResponse const RecordEventResponse = "/api/v1/schedule/message/event/response/record" +const FetchMessageEventResponse = "/api/v1/schedule/message/event/response" const SendInstantMessageEndpoint = "/api/v1/instant/message" diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index cd9646b..40768d0 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -86,3 +86,15 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req RespondWithJSON(w, statusCode, &resp) } + +type GetMessageEventResponseFetchedResponse struct { + Message string `json:"message"` + Data []*message.MessageEventResponse `json:"data"` +} + +func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) { + var statusCode int + var resp GetMessageEventResponseFetchedResponse + + RespondWithJSON(w, statusCode, &resp) +} From 1a3a244c07ccf33148e255421be53e9a3cbef457 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 31 Dec 2025 14:28:09 -0500 Subject: [PATCH 03/20] tsk-59: Changes to store and mock package --- internal/store/message_event_response_store.go | 12 ++++++------ .../store/mock/message_event_response_store.go | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/store/message_event_response_store.go b/internal/store/message_event_response_store.go index 4075772..ad0300e 100644 --- a/internal/store/message_event_response_store.go +++ b/internal/store/message_event_response_store.go @@ -28,16 +28,16 @@ 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, 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) + query = fmt.Sprintf("%s (response, user_id, sent, contact_id, message_id, status) VALUES ($1, $2, $3, $4, $5, $6) %s", queryBase, queryReturn) + return m.db.QueryRow(ctx, query, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId, mer.Status).Scan(&mer.Id) } else { - 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) + query = fmt.Sprintf("%s (scheduled_message_event_id, response, user_id, sent, contact_id, message_id, status) VALUES ($1, $2, $3, $4, $5, $6, $7) %s", queryBase, queryReturn) + return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId, mer.Status,).Scan(&mer.Id) } } func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) { - query := "SELECT id, scheduled_message_event_id, response, user_id, sent, contact_id, message_id FROM message_event_responses WHERE user_id = $1" + query := "SELECT id, scheduled_message_event_id, response, user_id, sent, contact_id, message_id, status FROM message_event_responses WHERE user_id = $1" rows, err := m.db.Query(ctx, query) if err != nil { return nil, fmt.Errorf("Error querying: %w", err) @@ -47,7 +47,7 @@ func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId var sentMessages []*message.MessageEventResponse for rows.Next() { var msg message.MessageEventResponse - if err := rows.Scan(&msg.Id, &msg.ScheduledMessageEventId, &msg.Response, &msg.UserId, &msg.Sent, &msg.ContactId, &msg.MessageId,); err != nil { + if err := rows.Scan(&msg.Id, &msg.ScheduledMessageEventId, &msg.Response, &msg.UserId, &msg.Sent, &msg.ContactId, &msg.MessageId, &msg.Status,); err != nil { return nil, fmt.Errorf("Scanning row: %w", err) } sentMessages = append(sentMessages, &msg) diff --git a/internal/store/mock/message_event_response_store.go b/internal/store/mock/message_event_response_store.go index 3833738..ee3d668 100644 --- a/internal/store/mock/message_event_response_store.go +++ b/internal/store/mock/message_event_response_store.go @@ -62,3 +62,21 @@ func (m *MockMessageEventResponseStore) Create(ctx context.Context, mer *message } // TODO: Add code to get mock MessageEventResponse +func (m *MockMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) { + m.mu.Lock() + defer m.mu.Unlock() + + if m.Error != nil { + return nil, m.Error + } + + var messages []*message.MessageEventResponse + for _, msg := range m.MessageEventResponses { + if msg.UserId == userId { + messages = append(messages, msg) + } + } + + + return messages, nil +} From b58174eef2b56eae4d828b24ff73620be5e2df1d Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 31 Dec 2025 14:44:43 -0500 Subject: [PATCH 04/20] tsk-59: Got the code for MER and added TODO --- internal/handler/endpoint/endpoint.go | 1 + internal/handler/message_event_response.go | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/internal/handler/endpoint/endpoint.go b/internal/handler/endpoint/endpoint.go index dd45add..c6bda68 100644 --- a/internal/handler/endpoint/endpoint.go +++ b/internal/handler/endpoint/endpoint.go @@ -12,6 +12,7 @@ const GetScheduledMessageEventEndpoint = "/api/v1/schedule/message/event" const DeleteScheduledMessageEventEndpoint = "/api/v1/schedule/message/event/{id}" const UpdateScheduledMessageStatusEndpoint = "/api/v1/schedule/message/status/update" const FetchNextScheduledMessageEndpoint = "/api/v1/schedule/message/fetch" +// TODO: Tweak endpoint verbage for MessageEventResponse endpoint // TODO: Make RecordEventResponse more consistent with MessageEventResponse const RecordEventResponse = "/api/v1/schedule/message/event/response/record" const FetchMessageEventResponse = "/api/v1/schedule/message/event/response" diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index 40768d0..f90a8bf 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -93,8 +93,43 @@ type GetMessageEventResponseFetchedResponse struct { } func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) { + queryParams := r.URL.Query() + var userId uuid.UUID + + if _, exists := queryParams["user_id"]; !exists { + http.Error(w, "Query params", http.StatusBadRequest) + return + } else { + var err error + userId, err = uuid.Parse(queryParams.Get("user_id")) + if err != nil { + http.Error(w, "Query params", http.StatusBadRequest) + return + } + } + var statusCode int var resp GetMessageEventResponseFetchedResponse + if userId == uuid.Nil { + statusCode = http.StatusBadRequest + resp.Message = "User Id is nil" + } else { + ctx := r.Context() + if sentMessages, err := e.MessageEventResponseStore.GetWithUserId(ctx, userId); err != nil { + statusCode = http.StatusInternalServerError + resp.Message = err.Error() + } else { + if len(sentMessages) == 0 { + statusCode = http.StatusNotFound + resp.Message = "Not MessageEventResponses found" + } else { + statusCode = http.StatusOK + resp.Message = "Successful" + resp.Data = sentMessages + } + } + } + RespondWithJSON(w, statusCode, &resp) } From 996b67d8907c2cd5dc98a892b32caad57c9ec2ac Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 31 Dec 2025 14:49:49 -0500 Subject: [PATCH 05/20] tsk-59: Made endpoint available --- cmd/api/main.go | 1 + cmd/api/main_test.go | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 6a7e0a6..01c0885 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -119,6 +119,7 @@ func main() { router.Method("GET", endpoint.GetScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.GetScheduledMessage))) router.Method("GET", endpoint.FetchNextScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.FetchNextMessage))) router.Method("POST", endpoint.RecordEventResponse, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(eventHandler.RecordResponse))) + router.Method("GET", endpoint.FetchMessageEventResponse, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(eventHandler.Fetch))) router.Method("POST", endpoint.SendInstantMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(instantMessageHandler.Send))) router.Method("GET", "/swagger/*", httpSwagger.Handler( diff --git a/cmd/api/main_test.go b/cmd/api/main_test.go index d7f734f..953fff1 100644 --- a/cmd/api/main_test.go +++ b/cmd/api/main_test.go @@ -3,7 +3,6 @@ package main import ( "context" "flag" - "fmt" "log" "net/http" "os" @@ -30,8 +29,8 @@ func TestMain(m *testing.M) { database, err := db.NewDatabase(cfg.GetDBConnString()) if err != nil { - fmt.Println(err.Error()) - panic("Failed to initialize database") + log.Println(err.Error()) + log.Fatal("Failed to initialize database") } defer database.Close() @@ -39,18 +38,18 @@ func TestMain(m *testing.M) { if cfg.ResetDB { if err = database.ResetDatabase(ctx); err != nil { - fmt.Println(err.Error()) - panic("Failed to initialize database") + log.Println(err.Error()) + log.Fatalln("Failed to initialize database") } } else { if exists, err := db.TableExists(ctx, database.Pool, "contacts "); err == nil && !exists { - fmt.Println("Resetting database") + log.Println("Resetting database") err = database.ResetDatabase(ctx) if err != nil { - fmt.Printf("Error:%v", err) + log.Println("Error:", err) } } else { - fmt.Printf("Error:%v", err) + log.Println("Error:", err) } } @@ -68,6 +67,7 @@ func TestMain(m *testing.M) { scheduledMessageEventHandler := handler.NewScheduledMessageEventHandler(apiApp, schMsgEventStore, schStore) scheduledMessageStatusHandler := handler.NewScheduledMessageStatusHandler(apiApp, schMsgEventStore, schStore) eventHandler := handler.NewEventResponseHandler(apiApp, merStore) + instantMessageHandler := handler.NewSendInstantMessageHandler(apiApp, merStore, contactStore, messageStore) testRouter = chi.NewRouter() testRouter.Handle(endpoint.ADD_CONTACT_ENDPOINT, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(contactHandler.AddContact))) @@ -81,6 +81,8 @@ func TestMain(m *testing.M) { testRouter.Method("GET", endpoint.GetScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.GetScheduledMessage))) testRouter.Method("GET", endpoint.FetchNextScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.FetchNextMessage))) testRouter.Method("POST", endpoint.RecordEventResponse, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(eventHandler.RecordResponse))) + testRouter.Method("GET", endpoint.FetchMessageEventResponse, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(eventHandler.Fetch))) + testRouter.Method("POST", endpoint.SendInstantMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(instantMessageHandler.Send))) code := m.Run() os.Exit(code) From 29f8c943a693d2a5d24c3a011de96aa7a2c7622e Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 31 Dec 2025 15:11:04 -0500 Subject: [PATCH 06/20] tsk-59: Tweaking code --- internal/handler/message_event_response.go | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index f90a8bf..646d613 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -1,6 +1,8 @@ package handler import ( + "fmt" + "log" "net/http" "time" @@ -47,6 +49,8 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req var rp message.MessageEventResponse var resp RecordEventResponse + defer RespondWithJSON(w, statusCode, &resp) + if req.Sent == nil { statusCode = http.StatusBadRequest resp.Message = "Sent time is empty" @@ -60,31 +64,42 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req statusCode = http.StatusBadRequest resp.Message = "Scheduled message event Id is empty" } else { + log.Println("Starting process to record Message Event Response") rp.ScheduledMessageEventId = req.ScheduledMessageEventId + fmt.Println(req.Response) rp.Response = req.Response rp.UserId = req.UserId rp.Sent = *req.Sent - if req.Status == message.Message_Event_Response_Status_Instant { + switch req.Status { + case message.Message_Event_Response_Status_Instant: { + log.Println("Status:", req.Status) rp.Status = req.Status rp.MessageId = req.MessageId rp.ContactId = req.ContactId - } else if req.Status == message.Message_Event_Response_Status_Scheduled { + } + case message.Message_Event_Response_Status_Scheduled: { + log.Println("Status:", req.Status) rp.Status = req.Status } + default: { + statusCode = http.StatusBadRequest + resp.Message = "Status is invalid" + } + } ctx := r.Context() if err := e.MessageEventResponseStore.Create(ctx, &rp); err != nil { + log.Println("Error:", err) resp.Message = err.Error() statusCode = http.StatusInternalServerError } else { + log.Println("Created Message Event Response") statusCode = http.StatusCreated resp.Message = "Successful" resp.Data = append(resp.Data, &rp) } } - - RespondWithJSON(w, statusCode, &resp) } type GetMessageEventResponseFetchedResponse struct { From 8860d6c8012c67baee7ade606c4ba6c734bb4570 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 00:59:14 +0000 Subject: [PATCH 07/20] tsk-57: Change schema of scheduled_message_events (#65) Closes #57 Reviewed-on: https://git.kundeng.us/phoenix/textsender-api/pulls/65 Co-authored-by: phoenix Co-committed-by: phoenix --- go.mod | 4 +- go.sum | 8 +-- internal/app/app.go | 4 +- internal/config/config.go | 10 +-- internal/handler/contact_test.go | 10 --- internal/handler/helper_test.go | 45 +++++++++++++ internal/handler/message.go | 20 +++--- internal/handler/message_event_response.go | 35 ++++++----- .../handler/message_event_response_test.go | 6 +- internal/handler/schedule_message_status.go | 20 +++--- .../handler/schedule_message_status_test.go | 8 +-- internal/handler/scheduled_message.go | 38 +++++------ internal/handler/scheduled_message_event.go | 50 +++++++-------- .../handler/scheduled_message_event_test.go | 63 +++++-------------- internal/handler/scheduled_message_test.go | 10 +-- .../store/message_event_response_store.go | 18 +++--- .../mock/message_event_response_store.go | 17 +++-- .../store/scheduled_message_event_store.go | 16 ++--- migrations/schema.sql | 2 +- 19 files changed, 195 insertions(+), 189 deletions(-) diff --git a/go.mod b/go.mod index 51f4ae7..fe6c45b 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-8-523c7cf67c-556 - git.kundeng.us/phoenix/textsender-models v0.0.12 + git.kundeng.us/phoenix/swoosh v0.1.0-main-3c1f8a1a27-556 + git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556 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 848543d..112117a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -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= +git.kundeng.us/phoenix/swoosh v0.1.0-main-3c1f8a1a27-556 h1:KsX+w6iUSPWajQs6fkpDhTBixcUjq9vb4NGXFWKA7fM= +git.kundeng.us/phoenix/swoosh v0.1.0-main-3c1f8a1a27-556/go.mod h1:XGXsm6S8+W52FXsMnYo4eOpILHAu5S86IgboZALfyQw= +git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556 h1:869mq7lyB+XaNqJOMOGWdfHs97sC2OrreIxW4zkIjkQ= +git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556/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 f2ef963..9948d51 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -1,9 +1,9 @@ package app import ( - "git.kundeng.us/phoenix/textsender-models/tx0/config" + auxcfg "git.kundeng.us/phoenix/textsender-models/tx0/config/auxiliary" ) type App struct { - TwilioConfig *config.TwilioConfig + TwilioConfig *auxcfg.TwilioConfig } diff --git a/internal/config/config.go b/internal/config/config.go index f330faa..d23f4dc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "git.kundeng.us/phoenix/textsender-models/tx0/config" + auxcfg "git.kundeng.us/phoenix/textsender-models/tx0/config/auxiliary" "github.com/joho/godotenv" "git.kundeng.us/phoenix/textsender-api/internal/version" @@ -18,7 +18,7 @@ type Config struct { ServerPort string ResetDB bool JWTSecret string `env:"JWT_SECRET" required:"true"` - TwilioConfig *config.TwilioConfig + TwilioConfig *auxcfg.TwilioConfig AllowedOrigins []string } @@ -49,7 +49,7 @@ func PrintName() { fmt.Println(version.String()) } -func Load() (*Config, *config.TwilioConfig, error) { +func Load() (*Config, *auxcfg.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") @@ -138,7 +138,7 @@ func unpackAllowedOrigins() []string { return allowedOriginsSplit } -func TwilioConfig() (*config.TwilioConfig, error) { +func TwilioConfig() (*auxcfg.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.TwilioConfig, error) { } else if len(phoneNumber) == 0 { return nil, fmt.Errorf("Twilio config phone number not found") } else { - var cfg config.TwilioConfig + var cfg auxcfg.TwilioConfig cfg.AccountSID = authSid cfg.ServiceSID = serviceSid cfg.AuthToken = authToken diff --git a/internal/handler/contact_test.go b/internal/handler/contact_test.go index 1ee4388..a132d85 100644 --- a/internal/handler/contact_test.go +++ b/internal/handler/contact_test.go @@ -1,7 +1,6 @@ package handler import ( - "context" "encoding/json" "fmt" "net/http" @@ -13,7 +12,6 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" - "git.kundeng.us/phoenix/textsender-api/internal/db" "git.kundeng.us/phoenix/textsender-api/internal/handler/endpoint" "git.kundeng.us/phoenix/textsender-api/internal/store/mock" ) @@ -80,11 +78,3 @@ func TestGetContactWithMock(t *testing.T) { assert.NotNil(t, response.Data[0].Id, "Id should not be nil") } - -func resetTestDB(t *testing.T) { - t.Helper() - _, err := db.Pool.Exec(context.Background(), "DELETE FROM contacts") - if err != nil { - t.Fatalf("Failed to reset test database: %v", err) - } -} diff --git a/internal/handler/helper_test.go b/internal/handler/helper_test.go index a980d0c..4a8f190 100644 --- a/internal/handler/helper_test.go +++ b/internal/handler/helper_test.go @@ -1,14 +1,22 @@ package handler import ( + "context" "fmt" "os" "path" + "testing" + "time" + "git.kundeng.us/phoenix/textsender-models/tx0/contact" + "git.kundeng.us/phoenix/textsender-models/tx0/message" + "git.kundeng.us/phoenix/textsender-models/tx0/message/scheduling" + "github.com/google/uuid" "github.com/joho/godotenv" "git.kundeng.us/phoenix/textsender-api/internal/app" "git.kundeng.us/phoenix/textsender-api/internal/config" + "git.kundeng.us/phoenix/textsender-api/internal/db" ) func GetApp() (*app.App, error) { @@ -29,3 +37,40 @@ func GetApp() (*app.App, error) { return &app.App{TwilioConfig: tCfg}, nil } } + +func ResetTestDB(t *testing.T, tableName string) { + t.Helper() + _, err := db.Pool.Exec(context.Background(), fmt.Sprintf("DELETE FROM ", tableName)) + if err != nil { + t.Fatalf("Failed to reset test database: %v", err) + } +} + +func TestContact(id uuid.UUID, userId uuid.UUID) contact.Contact { + if id == uuid.Nil { + id = uuid.New() + return contact.Contact{Id: &id, PhoneNumber: "+10123456789", UserId: &userId} + } else { + return contact.Contact{Id: &id, PhoneNumber: "+10123456789", UserId: &userId} + } +} + +func TestMessage(id uuid.UUID, userId uuid.UUID) message.Message { + if id == uuid.Nil { + return message.Message{Id: uuid.New(), Content: "Oh how the mighty have fallen", UserId: userId} + } else { + return message.Message{Id: id, Content: "Oh how the mighty have fallen", UserId: userId} + } +} + +func TestScheduledMessage(id uuid.UUID, userId uuid.UUID, now time.Time) scheduling.ScheduledMessage { + if id == uuid.Nil { + return scheduling.ScheduledMessage{Id: uuid.New(), UserId: userId, Scheduled: now.Add(20 * time.Minute), Status: scheduling.Pending} + } else { + return scheduling.ScheduledMessage{Id: id, UserId: userId, Scheduled: now.Add(20 * time.Minute), Status: scheduling.Pending} + } +} + +func TestScheduledMessageEvent(messageId, contactId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent { + return scheduling.ScheduledMessageEvent{MessageId: messageId, ContactId: contactId, ScheduledMessageId: scheduledMessageId} +} diff --git a/internal/handler/message.go b/internal/handler/message.go index 8211e86..07dfa4d 100644 --- a/internal/handler/message.go +++ b/internal/handler/message.go @@ -12,16 +12,6 @@ import ( "git.kundeng.us/phoenix/textsender-api/internal/store" ) -type RequestAddMessage struct { - Content string `json:"content"` - UserId uuid.UUID `json:"user_id"` -} - -type AddMessageResponse struct { - Message string `json:"message"` - Data []message.Message `json:"data"` -} - type MessageHandler struct { App *app.App MessageStore store.MessageStore @@ -33,6 +23,16 @@ func NewMessageHandler(apiApp *app.App, str store.MessageStore) *MessageHandler const Message_Limit = 200 +type RequestAddMessage struct { + Content string `json:"content"` + UserId uuid.UUID `json:"user_id"` +} + +type AddMessageResponse struct { + Message string `json:"message"` + Data []message.Message `json:"data"` +} + // AddMessage godoc // @Summary Add message // @Description Add a message record to send a text to (requires JWT) diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index 646d613..5fc4fb4 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -72,20 +72,23 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req rp.Sent = *req.Sent switch req.Status { - case message.Message_Event_Response_Status_Instant: { - log.Println("Status:", req.Status) - rp.Status = req.Status - rp.MessageId = req.MessageId - rp.ContactId = req.ContactId - } - case message.Message_Event_Response_Status_Scheduled: { - log.Println("Status:", req.Status) - rp.Status = req.Status - } - default: { - statusCode = http.StatusBadRequest - resp.Message = "Status is invalid" - } + case message.Message_Event_Response_Status_Instant: + { + log.Println("Status:", req.Status) + rp.Status = req.Status + rp.MessageId = req.MessageId + rp.ContactId = req.ContactId + } + case message.Message_Event_Response_Status_Scheduled: + { + log.Println("Status:", req.Status) + rp.Status = req.Status + } + default: + { + statusCode = http.StatusBadRequest + resp.Message = "Status is invalid" + } } ctx := r.Context() @@ -103,8 +106,8 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req } type GetMessageEventResponseFetchedResponse struct { - Message string `json:"message"` - Data []*message.MessageEventResponse `json:"data"` + Message string `json:"message"` + Data []*message.MessageEventResponse `json:"data"` } func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) { diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index 210099e..243b83f 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -35,9 +35,9 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) + con := TestContact(recipientId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) event := scheduling.ScheduledMessageEvent{} ctx := t.Context() diff --git a/internal/handler/schedule_message_status.go b/internal/handler/schedule_message_status.go index 265f32d..f935d75 100644 --- a/internal/handler/schedule_message_status.go +++ b/internal/handler/schedule_message_status.go @@ -10,6 +10,16 @@ import ( "git.kundeng.us/phoenix/textsender-api/internal/store" ) +type ScheduledMessageStatusHandler struct { + App *app.App + ScheduledMessageEventStore store.ScheduledMessageEventStore + ScheduledMessageStore store.ScheduledMessageStore +} + +func NewScheduledMessageStatusHandler(apiApp *app.App, str store.ScheduledMessageEventStore, schStore store.ScheduledMessageStore) *ScheduledMessageStatusHandler { + return &ScheduledMessageStatusHandler{App: apiApp, ScheduledMessageEventStore: str, ScheduledMessageStore: schStore} +} + type RequestScheduledMessageStatus struct { ScheduledMessageId uuid.UUID `json:"scheduled_message_id"` Status string `json:"status"` @@ -25,16 +35,6 @@ type ScheduledMessageStatusResponse struct { Data []ScheduledMessageChange `json:"data"` } -type ScheduledMessageStatusHandler struct { - App *app.App - ScheduledMessageEventStore store.ScheduledMessageEventStore - ScheduledMessageStore store.ScheduledMessageStore -} - -func NewScheduledMessageStatusHandler(apiApp *app.App, str store.ScheduledMessageEventStore, schStore store.ScheduledMessageStore) *ScheduledMessageStatusHandler { - return &ScheduledMessageStatusHandler{App: apiApp, ScheduledMessageEventStore: str, ScheduledMessageStore: schStore} -} - // UpdateStatus godoc // @Summary Update status // @Description Update the status of a scheduled message (requires JWT) diff --git a/internal/handler/schedule_message_status_test.go b/internal/handler/schedule_message_status_test.go index 10dcbe4..0d8a2f4 100644 --- a/internal/handler/schedule_message_status_test.go +++ b/internal/handler/schedule_message_status_test.go @@ -29,10 +29,10 @@ func TestUpdateScheduledMessageStatusWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) - event := testScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := TestContact(recipientId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) ctx := t.Context() diff --git a/internal/handler/scheduled_message.go b/internal/handler/scheduled_message.go index ba88bc1..8af8ee2 100644 --- a/internal/handler/scheduled_message.go +++ b/internal/handler/scheduled_message.go @@ -13,6 +13,15 @@ import ( "git.kundeng.us/phoenix/textsender-api/internal/store" ) +type ScheduledMessageHandler struct { + App *app.App + ScheduledMessageStore store.ScheduledMessageStore +} + +func NewScheduledMessageHandler(apiApp *app.App, str store.ScheduledMessageStore) *ScheduledMessageHandler { + return &ScheduledMessageHandler{App: apiApp, ScheduledMessageStore: str} +} + type RequestAddScheduledMessage struct { Scheduled time.Time `json:"scheduled"` Status string `json:"status"` @@ -24,25 +33,6 @@ type AddScheduledMessageResponse struct { Data []scheduling.ScheduledMessage `json:"data"` } -type GetScheduledMessageResponse struct { - Message string `json:"message"` - Data []scheduling.ScheduledMessage `json:"data"` -} - -type FetchNextMessageResponse struct { - Message string `json:"message"` - Data []scheduling.ScheduledMessage `json:"data"` -} - -type ScheduledMessageHandler struct { - App *app.App - ScheduledMessageStore store.ScheduledMessageStore -} - -func NewScheduledMessageHandler(apiApp *app.App, str store.ScheduledMessageStore) *ScheduledMessageHandler { - return &ScheduledMessageHandler{App: apiApp, ScheduledMessageStore: str} -} - // AddScheduledMessage godoc // @Summary Add scheduled message // @Description Adds a scheduled message (requires JWT) @@ -106,6 +96,11 @@ func (s *ScheduledMessageHandler) AddScheduledMessage(w http.ResponseWriter, r * RespondWithJSON(w, statusCode, &resp) } +type GetScheduledMessageResponse struct { + Message string `json:"message"` + Data []scheduling.ScheduledMessage `json:"data"` +} + // GetScheduledMessage godoc // @Summary Get scheduled message // @Description Get a scheduled message (requires JWT) @@ -183,6 +178,11 @@ func (s *ScheduledMessageHandler) GetScheduledMessage(w http.ResponseWriter, r * RespondWithJSON(w, statusCode, &resp) } +type FetchNextMessageResponse struct { + Message string `json:"message"` + Data []scheduling.ScheduledMessage `json:"data"` +} + // FetchNextMessage godoc // @Summary Fetch scheduled message // @Description Fetches a scheduled message that is available to be processed (requires JWT) diff --git a/internal/handler/scheduled_message_event.go b/internal/handler/scheduled_message_event.go index f05de6e..9c4e17e 100644 --- a/internal/handler/scheduled_message_event.go +++ b/internal/handler/scheduled_message_event.go @@ -12,27 +12,6 @@ import ( "git.kundeng.us/phoenix/textsender-api/internal/store" ) -type RequestAddScheduledMessageEvent struct { - RecipientId uuid.UUID `json:"recipient_id"` - MessageId uuid.UUID `json:"message_id"` - ScheduledMessageId uuid.UUID `json:"scheduled_message_id"` -} - -type AddScheduledMessageEventResponse struct { - Message string `json:"message"` - Data []scheduling.ScheduledMessageEvent `json:"data"` -} - -type GetScheduledMessageEventResponse struct { - Message string `json:"message"` - Data []scheduling.ScheduledMessageEvent `json:"data"` -} - -type DeleteScheduledMessageEventResponse struct { - Message string `json:"message"` - Data []scheduling.ScheduledMessageEvent `json:"data"` -} - type ScheduledMessageEventHandler struct { App *app.App ScheduledMessageEventStore store.ScheduledMessageEventStore @@ -43,7 +22,18 @@ func NewScheduledMessageEventHandler(apiApp *app.App, str store.ScheduledMessage return &ScheduledMessageEventHandler{App: apiApp, ScheduledMessageEventStore: str, ScheduledMessageStore: schStore} } -// AddContact godoc +type RequestAddScheduledMessageEvent struct { + ContactId uuid.UUID `json:"contact_id"` + MessageId uuid.UUID `json:"message_id"` + ScheduledMessageId uuid.UUID `json:"scheduled_message_id"` +} + +type AddScheduledMessageEventResponse struct { + Message string `json:"message"` + Data []scheduling.ScheduledMessageEvent `json:"data"` +} + +// AddScheduledMessageEvent godoc // @Summary Add scheduled message event // @Description Add a scheduled message event (requires JWT) // @Tags scheduled message events @@ -67,14 +57,14 @@ func (s *ScheduledMessageEventHandler) AddScheduledMessageEvent(w http.ResponseW } defer r.Body.Close() - event := scheduling.ScheduledMessageEvent{RecipientId: req.RecipientId, MessageId: req.MessageId, ScheduledMessageId: req.ScheduledMessageId} + event := scheduling.ScheduledMessageEvent{ContactId: req.ContactId, MessageId: req.MessageId, ScheduledMessageId: req.ScheduledMessageId} var statusCode int var resp AddScheduledMessageEventResponse - if event.RecipientId == uuid.Nil { + if event.ContactId == uuid.Nil { statusCode = http.StatusBadRequest - resp.Message = "Recipient Id is nil" + resp.Message = "Contact Id is nil" } else if event.MessageId == uuid.Nil { statusCode = http.StatusBadRequest resp.Message = "Message Id is nil" @@ -117,6 +107,11 @@ func (s *ScheduledMessageEventHandler) AddScheduledMessageEvent(w http.ResponseW RespondWithJSON(w, statusCode, &resp) } +type GetScheduledMessageEventResponse struct { + Message string `json:"message"` + Data []scheduling.ScheduledMessageEvent `json:"data"` +} + // GetScheduledMessageEvent godoc // @Summary Get scheduled message event // @Description Gets a scheduled message event (requires JWT) @@ -181,6 +176,11 @@ func (s *ScheduledMessageEventHandler) GetScheduledMessageEvent(w http.ResponseW RespondWithJSON(w, statusCode, &resp) } +type DeleteScheduledMessageEventResponse struct { + Message string `json:"message"` + Data []scheduling.ScheduledMessageEvent `json:"data"` +} + // DeleteScheduledMessageEvent godoc // @Summary Delete scheduled message event // @Description Deletes a scheduled message event (requires JWT) diff --git a/internal/handler/scheduled_message_event_test.go b/internal/handler/scheduled_message_event_test.go index 56fed9f..ade1517 100644 --- a/internal/handler/scheduled_message_event_test.go +++ b/internal/handler/scheduled_message_event_test.go @@ -9,8 +9,6 @@ import ( "testing" "time" - "git.kundeng.us/phoenix/textsender-models/tx0/contact" - "git.kundeng.us/phoenix/textsender-models/tx0/message" "git.kundeng.us/phoenix/textsender-models/tx0/message/scheduling" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -20,14 +18,14 @@ import ( ) var ( - recipientId = uuid.New() + contactId = uuid.New() messageId = uuid.New() scheduledMessageId = uuid.New() testUserId = uuid.New() ) type CreateScheduledMessageEventRequest struct { - RecipientId uuid.UUID `json:"recipient_id"` + ContactId uuid.UUID `json:"recipient_id"` MessageId uuid.UUID `json:"message_id"` ScheduledMessageId uuid.UUID `json:"scheduled_message_id"` } @@ -44,14 +42,14 @@ func TestCreateScheduledMessageEventWithMock(t *testing.T) { assert.NoError(t, err, "Error getting app") handler := NewScheduledMessageEventHandler(apiApp, mockStore, schMsgStore) - recipientId := uuid.New() + contactId := uuid.New() messageId := uuid.New() scheduledMessageId := uuid.New() testUserId := uuid.New() - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) + con := TestContact(contactId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) ctx := t.Context() @@ -63,7 +61,7 @@ func TestCreateScheduledMessageEventWithMock(t *testing.T) { assert.NoError(t, err, "Error creating scheduled message: %v", err) } - testReq := CreateScheduledMessageEventRequest{RecipientId: recipientId, MessageId: messageId, ScheduledMessageId: scheduledMessageId} + testReq := CreateScheduledMessageEventRequest{ContactId: contactId, MessageId: messageId, ScheduledMessageId: scheduledMessageId} jsonValue, _ := json.Marshal(testReq) req, _ := http.NewRequest("POST", endpoint.AddEventToScheduledMessageEndpoint, strings.NewReader(string(jsonValue))) @@ -96,15 +94,15 @@ func TestGetScheduledMessageEventWithMock(t *testing.T) { assert.NoError(t, err, "Error getting app") handler := NewScheduledMessageEventHandler(apiApp, schMsgEventStore, schMsgStore) - recipientId := uuid.New() + contactId := uuid.New() messageId := uuid.New() scheduledMessageId := uuid.New() testUserId := uuid.New() - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) - event := testScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := TestContact(contactId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) ctx := t.Context() @@ -147,10 +145,10 @@ func TestDeleteScheduledMessageEventWithMock(t *testing.T) { assert.NoError(t, err, "Error getting app") handler := NewScheduledMessageEventHandler(apiApp, schMsgEventStore, schMsgStore) - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) - event := testScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := TestContact(contactId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) ctx := t.Context() @@ -182,32 +180,3 @@ func TestDeleteScheduledMessageEventWithMock(t *testing.T) { assert.NotEmpty(t, msgEvent.Created, "Created date should not be empty") } - -func testContact(id uuid.UUID, userId uuid.UUID) contact.Contact { - if id == uuid.Nil { - id = uuid.New() - return contact.Contact{Id: &id, PhoneNumber: "+10123456789", UserId: &userId} - } else { - return contact.Contact{Id: &id, PhoneNumber: "+10123456789", UserId: &userId} - } -} - -func testMessage(id uuid.UUID, userId uuid.UUID) message.Message { - if id == uuid.Nil { - return message.Message{Id: uuid.New(), Content: "Oh how the mighty have fallen", UserId: userId} - } else { - return message.Message{Id: id, Content: "Oh how the mighty have fallen", UserId: userId} - } -} - -func testScheduledMessage(id uuid.UUID, userId uuid.UUID, now time.Time) scheduling.ScheduledMessage { - if id == uuid.Nil { - return scheduling.ScheduledMessage{Id: uuid.New(), UserId: userId, Scheduled: now.Add(20 * time.Minute), Status: scheduling.Pending} - } else { - return scheduling.ScheduledMessage{Id: id, UserId: userId, Scheduled: now.Add(20 * time.Minute), Status: scheduling.Pending} - } -} - -func testScheduledMessageEvent(messageId, recipientId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent { - return scheduling.ScheduledMessageEvent{MessageId: messageId, RecipientId: recipientId, ScheduledMessageId: scheduledMessageId} -} diff --git a/internal/handler/scheduled_message_test.go b/internal/handler/scheduled_message_test.go index b3ca5c3..60ce7dd 100644 --- a/internal/handler/scheduled_message_test.go +++ b/internal/handler/scheduled_message_test.go @@ -89,15 +89,15 @@ func TestFetchScheduledMessageWithMock(t *testing.T) { messageStore := mock.NewMockMessageStore() schMsgEventStore := mock.NewMockScheduledMessageEventStore() - recipientId := uuid.New() + contactId := uuid.New() messageId := uuid.New() scheduledMessageId := uuid.New() testUserId := uuid.New() - con := testContact(recipientId, testUserId) - msg := testMessage(messageId, testUserId) - schMsg := testScheduledMessage(scheduledMessageId, testUserId, now) - event := testScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := TestContact(contactId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) ctx := t.Context() diff --git a/internal/store/message_event_response_store.go b/internal/store/message_event_response_store.go index ad0300e..2a9f4de 100644 --- a/internal/store/message_event_response_store.go +++ b/internal/store/message_event_response_store.go @@ -4,14 +4,14 @@ import ( "context" "fmt" - "git.kundeng.us/phoenix/textsender-models/tx0/message" + "git.kundeng.us/phoenix/textsender-models/tx0/message/event" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) type MessageEventResponseStore interface { - Create(ctx context.Context, mer *message.MessageEventResponse) error - GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) + Create(ctx context.Context, mer *event.MessageEventResponse) error + GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*event.MessageEventResponse, error) } type PGMessageEventResponseStore struct { @@ -22,7 +22,7 @@ func NewMessageEventResponseStore(db *pgxpool.Pool) *PGMessageEventResponseStore return &PGMessageEventResponseStore{db: db} } -func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *message.MessageEventResponse) error { +func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *event.MessageEventResponse) error { var query string queryBase := "INSERT INTO message_event_responses" queryReturn := "RETURNING id" @@ -32,11 +32,11 @@ func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *message.M return m.db.QueryRow(ctx, query, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId, mer.Status).Scan(&mer.Id) } else { query = fmt.Sprintf("%s (scheduled_message_event_id, response, user_id, sent, contact_id, message_id, status) VALUES ($1, $2, $3, $4, $5, $6, $7) %s", queryBase, queryReturn) - return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId, mer.Status,).Scan(&mer.Id) + return m.db.QueryRow(ctx, query, mer.ScheduledMessageEventId, mer.Response, mer.UserId, mer.Sent, mer.ContactId, mer.MessageId, mer.Status).Scan(&mer.Id) } } -func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) { +func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*event.MessageEventResponse, error) { query := "SELECT id, scheduled_message_event_id, response, user_id, sent, contact_id, message_id, status FROM message_event_responses WHERE user_id = $1" rows, err := m.db.Query(ctx, query) if err != nil { @@ -44,10 +44,10 @@ func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId } defer rows.Close() - var sentMessages []*message.MessageEventResponse + var sentMessages []*event.MessageEventResponse for rows.Next() { - var msg message.MessageEventResponse - if err := rows.Scan(&msg.Id, &msg.ScheduledMessageEventId, &msg.Response, &msg.UserId, &msg.Sent, &msg.ContactId, &msg.MessageId, &msg.Status,); err != nil { + var msg event.MessageEventResponse + if err := rows.Scan(&msg.Id, &msg.ScheduledMessageEventId, &msg.Response, &msg.UserId, &msg.Sent, &msg.ContactId, &msg.MessageId, &msg.Status); err != nil { return nil, fmt.Errorf("Scanning row: %w", err) } sentMessages = append(sentMessages, &msg) diff --git a/internal/store/mock/message_event_response_store.go b/internal/store/mock/message_event_response_store.go index ee3d668..5ffc0ff 100644 --- a/internal/store/mock/message_event_response_store.go +++ b/internal/store/mock/message_event_response_store.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "git.kundeng.us/phoenix/textsender-models/tx0/message" + "git.kundeng.us/phoenix/textsender-models/tx0/message/event" "github.com/google/uuid" ) @@ -15,20 +15,20 @@ type MessageEventResponseKey struct { UserId uuid.UUID } type MockMessageEventResponseStore struct { - MessageEventResponses map[uuid.UUID]*message.MessageEventResponse - MessageEventResponsesByKey map[MessageEventResponseKey]*message.MessageEventResponse + MessageEventResponses map[uuid.UUID]*event.MessageEventResponse + MessageEventResponsesByKey map[MessageEventResponseKey]*event.MessageEventResponse mu sync.RWMutex Error error } func NewMockMessageEventResponseStore() *MockMessageEventResponseStore { return &MockMessageEventResponseStore{ - MessageEventResponses: make(map[uuid.UUID]*message.MessageEventResponse), - MessageEventResponsesByKey: make(map[MessageEventResponseKey]*message.MessageEventResponse), + MessageEventResponses: make(map[uuid.UUID]*event.MessageEventResponse), + MessageEventResponsesByKey: make(map[MessageEventResponseKey]*event.MessageEventResponse), } } -func (m *MockMessageEventResponseStore) Create(ctx context.Context, mer *message.MessageEventResponse) error { +func (m *MockMessageEventResponseStore) Create(ctx context.Context, mer *event.MessageEventResponse) error { m.mu.Lock() defer m.mu.Unlock() @@ -62,7 +62,7 @@ func (m *MockMessageEventResponseStore) Create(ctx context.Context, mer *message } // TODO: Add code to get mock MessageEventResponse -func (m *MockMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*message.MessageEventResponse, error) { +func (m *MockMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*event.MessageEventResponse, error) { m.mu.Lock() defer m.mu.Unlock() @@ -70,13 +70,12 @@ func (m *MockMessageEventResponseStore) GetWithUserId(ctx context.Context, userI return nil, m.Error } - var messages []*message.MessageEventResponse + var messages []*event.MessageEventResponse for _, msg := range m.MessageEventResponses { if msg.UserId == userId { messages = append(messages, msg) } } - return messages, nil } diff --git a/internal/store/scheduled_message_event_store.go b/internal/store/scheduled_message_event_store.go index e17fc7e..ae27c50 100644 --- a/internal/store/scheduled_message_event_store.go +++ b/internal/store/scheduled_message_event_store.go @@ -27,11 +27,11 @@ func NewScheduledMessageEventStore(db *pgxpool.Pool) *PGScheduledMessageEventSto } func (s *PGScheduledMessageEventStore) Get(ctx context.Context, id uuid.UUID) (*scheduling.ScheduledMessageEvent, error) { - query := `SELECT id, recipient_id, message_id, scheduled_message_id, created FROM scheduled_message_events WHERE id = $1` + query := `SELECT id, contact_id, message_id, scheduled_message_id, created FROM scheduled_message_events WHERE id = $1` var event scheduling.ScheduledMessageEvent err := s.db.QueryRow(ctx, query, id).Scan( - &event.Id, &event.RecipientId, &event.MessageId, &event.ScheduledMessageId, &event.Created, + &event.Id, &event.ContactId, &event.MessageId, &event.ScheduledMessageId, &event.Created, ) if err == pgx.ErrNoRows { @@ -45,7 +45,7 @@ func (s *PGScheduledMessageEventStore) Get(ctx context.Context, id uuid.UUID) (* func (s *PGScheduledMessageEventStore) GetWithScheduleMessageId(ctx context.Context, schMsgId uuid.UUID) ([]*scheduling.ScheduledMessageEvent, error) { var events []*scheduling.ScheduledMessageEvent - query := `SELECT id, recipient_id, message_id, scheduled_message_id, created FROM scheduled_message_events WHERE scheduled_message_id = $1 + query := `SELECT id, contact_id, message_id, scheduled_message_id, created FROM scheduled_message_events WHERE scheduled_message_id = $1 ` rows, err := s.db.Query(ctx, query, schMsgId) @@ -57,7 +57,7 @@ func (s *PGScheduledMessageEventStore) GetWithScheduleMessageId(ctx context.Cont for rows.Next() { var event scheduling.ScheduledMessageEvent - if err := rows.Scan(&event.Id, &event.RecipientId, &event.MessageId, &event.ScheduledMessageId, &event.Created); err != nil { + if err := rows.Scan(&event.Id, &event.ContactId, &event.MessageId, &event.ScheduledMessageId, &event.Created); err != nil { return nil, fmt.Errorf("Error fetching data from row: %w", err) } else { events = append(events, &event) @@ -90,21 +90,21 @@ func (s *PGScheduledMessageEventStore) Delete(ctx context.Context, id uuid.UUID) func (s *PGScheduledMessageEventStore) CreateScheduledMessageEvent(ctx context.Context, event *scheduling.ScheduledMessageEvent) error { query := ` - INSERT INTO scheduled_message_events (recipient_id, message_id, scheduled_message_id) + INSERT INTO scheduled_message_events (contact_id, message_id, scheduled_message_id) VALUES ($1, $2, $3) RETURNING id, created ` - return s.db.QueryRow(ctx, query, event.RecipientId, event.MessageId, event.ScheduledMessageId).Scan( + return s.db.QueryRow(ctx, query, event.ContactId, event.MessageId, event.ScheduledMessageId).Scan( &event.Id, &event.Created, ) } func (s *PGScheduledMessageEventStore) Exists(ctx context.Context, event *scheduling.ScheduledMessageEvent) (bool, error) { - query := `SELECT EXISTS(SELECT 1 FROM scheduled_message_events WHERE scheduled_message_id = $1 AND recipient_id = $2)` + query := `SELECT EXISTS(SELECT 1 FROM scheduled_message_events WHERE scheduled_message_id = $1 AND contact_id = $2)` var exists bool - err := s.db.QueryRow(ctx, query, event.ScheduledMessageId, event.RecipientId).Scan(&exists) + err := s.db.QueryRow(ctx, query, event.ScheduledMessageId, event.ContactId).Scan(&exists) if err != nil { return false, fmt.Errorf("Scheduled message event does not exist: %w", err) } else { diff --git a/migrations/schema.sql b/migrations/schema.sql index f7a8a1a..b8d3401 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS scheduled_messages ( CREATE TABLE IF NOT EXISTS scheduled_message_events ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - recipient_id UUID NOT NULL, + contact_id UUID NOT NULL, message_id UUID NOT NULL, scheduled_message_id UUID NOT NULL, created timestamptz DEFAULT now() From 6641f384ab87fc0a8a26b49fd3e64b8a72e18be1 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 01:39:12 +0000 Subject: [PATCH 08/20] tsk-62: Modify how the Response from event.MessageEventResponse is handled (#63) Closes #62 Reviewed-on: https://git.kundeng.us/phoenix/textsender-api/pulls/63 Co-authored-by: phoenix Co-committed-by: phoenix --- internal/handler/helper.go | 3 +- internal/handler/instant_message.go | 39 ++++++++++------------ internal/handler/message.go | 4 +-- internal/handler/message_event_response.go | 37 ++++++++++---------- 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/internal/handler/helper.go b/internal/handler/helper.go index adb68b2..0b135d9 100644 --- a/internal/handler/helper.go +++ b/internal/handler/helper.go @@ -25,7 +25,8 @@ func InvalidJson(err error) string { func RespondWithJSON(w http.ResponseWriter, statusCode int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) - if err := json.NewEncoder(w).Encode(data); err != nil { + encoder := json.NewEncoder(w) + if err := encoder.Encode(data); err != nil { log.Printf("Error encoding JSON: %v", err) } } diff --git a/internal/handler/instant_message.go b/internal/handler/instant_message.go index 3160d4b..46ad663 100644 --- a/internal/handler/instant_message.go +++ b/internal/handler/instant_message.go @@ -2,7 +2,6 @@ package handler import ( "context" - "encoding/json" "fmt" "log" "net/http" @@ -12,6 +11,7 @@ import ( "git.kundeng.us/phoenix/swoosh/swoop/send" "git.kundeng.us/phoenix/textsender-models/tx0/contact" "git.kundeng.us/phoenix/textsender-models/tx0/message" + "git.kundeng.us/phoenix/textsender-models/tx0/message/event" "github.com/google/uuid" "git.kundeng.us/phoenix/textsender-api/internal/app" @@ -38,8 +38,8 @@ type SendInstantMessageRequest struct { } type SendInstantMessageResponse struct { - Message string `json:"message"` - Data []*message.MessageEventResponse `json:"data"` + Message string `json:"message"` + Data []*event.MessageEventResponse `json:"data"` } // Sent godoc @@ -93,34 +93,29 @@ func (s *SendInstantMessageHandler) Send(w http.ResponseWriter, r *http.Request) if s.App != nil { msgSender := send.MessageSender{Config: s.App.TwilioConfig} for _, c := range contacts { - if twilioResp, err := msgSender.Send(*msg, *c, nil); err != nil { + if twilioResp, twilioRespObject, err := msgSender.Send(*msg, *c, nil); err != nil { statusCode = http.StatusInternalServerError resp.Message = err.Error() } else { - if data, err := json.Marshal(twilioResp); err != nil { + dateStr := strings.TrimSpace(*twilioResp.DateUpdated) + if parsedTime, err := time.Parse(time.RFC1123Z, dateStr); err != nil { statusCode = http.StatusInternalServerError resp.Message = err.Error() } else { - dateStr := strings.TrimSpace(*twilioResp.DateUpdated) - if parsedTime, err := time.Parse(time.RFC1123Z, dateStr); err != nil { + mer := event.MessageEventResponse{} + mer.Response = twilioRespObject + mer.UserId = req.UserId + mer.Sent = parsedTime + mer.Status = event.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() } else { - mer := message.MessageEventResponse{} - 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() - } else { - statusCode = http.StatusOK - resp.Message = "Successful" - resp.Data = append(resp.Data, &mer) - } + statusCode = http.StatusOK + resp.Message = "Successful" + resp.Data = append(resp.Data, &mer) } } } diff --git a/internal/handler/message.go b/internal/handler/message.go index 07dfa4d..eed2b39 100644 --- a/internal/handler/message.go +++ b/internal/handler/message.go @@ -59,7 +59,7 @@ func (m *MessageHandler) AddMessage(w http.ResponseWriter, r *http.Request) { var statusCode int var resp AddMessageResponse - newMessage := message.Message{Content: req.Content, UserId: req.UserId} + newMessage := message.Message{Content: req.Content, UserId: &req.UserId} if isMessageValid(&newMessage) { ctx := r.Context() @@ -160,7 +160,7 @@ func (c *MessageHandler) GetMessage(w http.ResponseWriter, r *http.Request) { if messages, err := c.MessageStore.GetAllMessages(ctx); err == nil { log.Println("Amount of messages:", len(messages)) for _, msg := range messages { - if msg.UserId == userId { + if *msg.UserId == userId { resp.Data = append(resp.Data, *msg) } } diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index 5fc4fb4..9092602 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -1,13 +1,11 @@ package handler import ( - "fmt" "log" "net/http" "time" - "git.kundeng.us/phoenix/textsender-models/tx0/message" - "git.kundeng.us/phoenix/textsender-models/tx0/types" + "git.kundeng.us/phoenix/textsender-models/tx0/message/event" "github.com/google/uuid" "git.kundeng.us/phoenix/textsender-api/internal/app" @@ -24,18 +22,18 @@ func NewEventResponseHandler(apiApp *app.App, str store.MessageEventResponseStor } type RecordEventRequest struct { - ScheduledMessageEventId uuid.UUID `json:"scheduled_message_event_id"` - 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"` + ScheduledMessageEventId uuid.UUID `json:"scheduled_message_event_id"` + Response map[string]any `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 { - Message string `json:"message"` - Data []*message.MessageEventResponse `json:"data"` + Message string `json:"message"` + Data []*event.MessageEventResponse `json:"data"` } func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Request) { @@ -46,11 +44,9 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req defer r.Body.Close() var statusCode int - var rp message.MessageEventResponse + var rp event.MessageEventResponse var resp RecordEventResponse - defer RespondWithJSON(w, statusCode, &resp) - if req.Sent == nil { statusCode = http.StatusBadRequest resp.Message = "Sent time is empty" @@ -66,20 +62,19 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req } else { log.Println("Starting process to record Message Event Response") rp.ScheduledMessageEventId = req.ScheduledMessageEventId - fmt.Println(req.Response) rp.Response = req.Response rp.UserId = req.UserId rp.Sent = *req.Sent switch req.Status { - case message.Message_Event_Response_Status_Instant: + case event.Message_Event_Response_Status_Instant: { log.Println("Status:", req.Status) rp.Status = req.Status rp.MessageId = req.MessageId rp.ContactId = req.ContactId } - case message.Message_Event_Response_Status_Scheduled: + case event.Message_Event_Response_Status_Scheduled: { log.Println("Status:", req.Status) rp.Status = req.Status @@ -103,11 +98,13 @@ func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Req resp.Data = append(resp.Data, &rp) } } + + RespondWithJSON(w, statusCode, &resp) } type GetMessageEventResponseFetchedResponse struct { - Message string `json:"message"` - Data []*message.MessageEventResponse `json:"data"` + Message string `json:"message"` + Data []*event.MessageEventResponse `json:"data"` } func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) { From 59c9aa0ff12c39d6efec2d07f81d26f1442c12cc Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 05:28:49 +0000 Subject: [PATCH 09/20] tsk-59: Get MessageEventResponse endpoint (#61) Closes #59 Reviewed-on: https://git.kundeng.us/phoenix/textsender-api/pulls/61 Co-authored-by: phoenix Co-committed-by: phoenix --- docs/docs.go | 229 +++++++++++++++--- docs/swagger.json | 229 +++++++++++++++--- docs/swagger.yaml | 150 ++++++++++-- internal/handler/endpoint/endpoint.go | 43 ++-- internal/handler/helper_test.go | 34 +++ internal/handler/message_event_response.go | 24 ++ .../handler/message_event_response_test.go | 94 ++++++- .../store/message_event_response_store.go | 2 +- .../mock/scheduled_message_event_store.go | 8 +- internal/store/mock/store.go | 12 +- 10 files changed, 712 insertions(+), 113 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 39cbb99..a5cbb4c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -490,6 +490,106 @@ const docTemplate = `{ } } }, + "/schedule/message/event/response": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Fetches a MessageEventResponse given a user id (requires JWT)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "message" + ], + "summary": "Fetcht MessageEventResponse", + "parameters": [ + { + "type": "string", + "description": "User Id", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + } + } + } + }, + "/schedule/message/event/response/record": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Saves the result of sending a text message (requires JWT)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "message" + ], + "summary": "Record MessageEventResponse", + "parameters": [ + { + "description": "Data to add MessageEventResponse", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.RecordEventRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + } + } + } + }, "/schedule/message/event/{id}": { "delete": { "security": [ @@ -642,9 +742,18 @@ const docTemplate = `{ "contact.Contact": { "type": "object", "properties": { + "first_name": { + "type": "string" + }, "id": { "type": "string" }, + "last_name": { + "type": "string" + }, + "nickname": { + "type": "string" + }, "phone_number": { "type": "string" }, @@ -653,6 +762,36 @@ const docTemplate = `{ } } }, + "event.MessageEventResponse": { + "type": "object", + "properties": { + "contact_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "response": { + "type": "object", + "additionalProperties": {} + }, + "scheduled_message_event_id": { + "type": "string" + }, + "sent": { + "type": "string" + }, + "status": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, "handler.AddContactResponse": { "type": "object", "properties": { @@ -751,6 +890,20 @@ const docTemplate = `{ } } }, + "handler.GetMessageEventResponseFetchedResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/event.MessageEventResponse" + } + }, + "message": { + "type": "string" + } + } + }, "handler.GetMessageResponse": { "type": "object", "properties": { @@ -793,6 +946,47 @@ const docTemplate = `{ } } }, + "handler.RecordEventRequest": { + "type": "object", + "properties": { + "contact_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "response": { + "type": "object", + "additionalProperties": {} + }, + "scheduled_message_event_id": { + "type": "string" + }, + "sent": { + "type": "string" + }, + "status": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, + "handler.RecordEventResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/event.MessageEventResponse" + } + }, + "message": { + "type": "string" + } + } + }, "handler.RequestAddContact": { "type": "object", "properties": { @@ -832,10 +1026,10 @@ const docTemplate = `{ "handler.RequestAddScheduledMessageEvent": { "type": "object", "properties": { - "message_id": { + "contact_id": { "type": "string" }, - "recipient_id": { + "message_id": { "type": "string" }, "scheduled_message_id": { @@ -902,7 +1096,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/message.MessageEventResponse" + "$ref": "#/definitions/event.MessageEventResponse" } }, "message": { @@ -924,29 +1118,6 @@ const docTemplate = `{ } } }, - "message.MessageEventResponse": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "response": { - "type": "array", - "items": { - "type": "integer" - } - }, - "scheduled_message_event_id": { - "type": "string" - }, - "sent": { - "type": "string" - }, - "user_id": { - "type": "string" - } - } - }, "scheduling.ScheduledMessage": { "type": "object", "properties": { @@ -970,6 +1141,9 @@ const docTemplate = `{ "scheduling.ScheduledMessageEvent": { "type": "object", "properties": { + "contact_id": { + "type": "string" + }, "created": { "type": "string" }, @@ -979,9 +1153,6 @@ const docTemplate = `{ "message_id": { "type": "string" }, - "recipient_id": { - "type": "string" - }, "scheduled_message_id": { "type": "string" } diff --git a/docs/swagger.json b/docs/swagger.json index 7dddc2b..52f8d48 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -484,6 +484,106 @@ } } }, + "/schedule/message/event/response": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Fetches a MessageEventResponse given a user id (requires JWT)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "message" + ], + "summary": "Fetcht MessageEventResponse", + "parameters": [ + { + "type": "string", + "description": "User Id", + "name": "user_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handler.GetMessageEventResponseFetchedResponse" + } + } + } + } + }, + "/schedule/message/event/response/record": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Saves the result of sending a text message (requires JWT)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "message" + ], + "summary": "Record MessageEventResponse", + "parameters": [ + { + "description": "Data to add MessageEventResponse", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.RecordEventRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handler.RecordEventResponse" + } + } + } + } + }, "/schedule/message/event/{id}": { "delete": { "security": [ @@ -636,9 +736,18 @@ "contact.Contact": { "type": "object", "properties": { + "first_name": { + "type": "string" + }, "id": { "type": "string" }, + "last_name": { + "type": "string" + }, + "nickname": { + "type": "string" + }, "phone_number": { "type": "string" }, @@ -647,6 +756,36 @@ } } }, + "event.MessageEventResponse": { + "type": "object", + "properties": { + "contact_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "response": { + "type": "object", + "additionalProperties": {} + }, + "scheduled_message_event_id": { + "type": "string" + }, + "sent": { + "type": "string" + }, + "status": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, "handler.AddContactResponse": { "type": "object", "properties": { @@ -745,6 +884,20 @@ } } }, + "handler.GetMessageEventResponseFetchedResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/event.MessageEventResponse" + } + }, + "message": { + "type": "string" + } + } + }, "handler.GetMessageResponse": { "type": "object", "properties": { @@ -787,6 +940,47 @@ } } }, + "handler.RecordEventRequest": { + "type": "object", + "properties": { + "contact_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "response": { + "type": "object", + "additionalProperties": {} + }, + "scheduled_message_event_id": { + "type": "string" + }, + "sent": { + "type": "string" + }, + "status": { + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, + "handler.RecordEventResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/event.MessageEventResponse" + } + }, + "message": { + "type": "string" + } + } + }, "handler.RequestAddContact": { "type": "object", "properties": { @@ -826,10 +1020,10 @@ "handler.RequestAddScheduledMessageEvent": { "type": "object", "properties": { - "message_id": { + "contact_id": { "type": "string" }, - "recipient_id": { + "message_id": { "type": "string" }, "scheduled_message_id": { @@ -896,7 +1090,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/message.MessageEventResponse" + "$ref": "#/definitions/event.MessageEventResponse" } }, "message": { @@ -918,29 +1112,6 @@ } } }, - "message.MessageEventResponse": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "response": { - "type": "array", - "items": { - "type": "integer" - } - }, - "scheduled_message_event_id": { - "type": "string" - }, - "sent": { - "type": "string" - }, - "user_id": { - "type": "string" - } - } - }, "scheduling.ScheduledMessage": { "type": "object", "properties": { @@ -964,6 +1135,9 @@ "scheduling.ScheduledMessageEvent": { "type": "object", "properties": { + "contact_id": { + "type": "string" + }, "created": { "type": "string" }, @@ -973,9 +1147,6 @@ "message_id": { "type": "string" }, - "recipient_id": { - "type": "string" - }, "scheduled_message_id": { "type": "string" } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 9c5f966..6ebfb30 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2,13 +2,39 @@ basePath: /api/v1 definitions: contact.Contact: properties: + first_name: + type: string id: type: string + last_name: + type: string + nickname: + type: string phone_number: type: string user_id: type: string type: object + event.MessageEventResponse: + properties: + contact_id: + type: string + id: + type: string + message_id: + type: string + response: + additionalProperties: {} + type: object + scheduled_message_event_id: + type: string + sent: + type: string + status: + type: string + user_id: + type: string + type: object handler.AddContactResponse: properties: data: @@ -72,6 +98,15 @@ definitions: message: type: string type: object + handler.GetMessageEventResponseFetchedResponse: + properties: + data: + items: + $ref: '#/definitions/event.MessageEventResponse' + type: array + message: + type: string + type: object handler.GetMessageResponse: properties: data: @@ -99,6 +134,33 @@ definitions: message: type: string type: object + handler.RecordEventRequest: + properties: + contact_id: + type: string + message_id: + type: string + response: + additionalProperties: {} + type: object + scheduled_message_event_id: + type: string + sent: + type: string + status: + type: string + user_id: + type: string + type: object + handler.RecordEventResponse: + properties: + data: + items: + $ref: '#/definitions/event.MessageEventResponse' + type: array + message: + type: string + type: object handler.RequestAddContact: properties: phone_number: @@ -124,9 +186,9 @@ definitions: type: object handler.RequestAddScheduledMessageEvent: properties: - message_id: + contact_id: type: string - recipient_id: + message_id: type: string scheduled_message_id: type: string @@ -169,7 +231,7 @@ definitions: properties: data: items: - $ref: '#/definitions/message.MessageEventResponse' + $ref: '#/definitions/event.MessageEventResponse' type: array message: type: string @@ -183,21 +245,6 @@ definitions: user_id: type: string type: object - message.MessageEventResponse: - properties: - id: - type: string - response: - items: - type: integer - type: array - scheduled_message_event_id: - type: string - sent: - type: string - user_id: - type: string - type: object scheduling.ScheduledMessage: properties: created: @@ -213,14 +260,14 @@ definitions: type: object scheduling.ScheduledMessageEvent: properties: + contact_id: + type: string created: type: string id: type: string message_id: type: string - recipient_id: - type: string scheduled_message_id: type: string type: object @@ -569,6 +616,69 @@ paths: summary: Delete scheduled message event tags: - scheduled message events + /schedule/message/event/response: + get: + consumes: + - application/json + description: Fetches a MessageEventResponse given a user id (requires JWT) + parameters: + - description: User Id + in: path + name: user_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.GetMessageEventResponseFetchedResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handler.GetMessageEventResponseFetchedResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handler.GetMessageEventResponseFetchedResponse' + security: + - BearerAuth: [] + summary: Fetcht MessageEventResponse + tags: + - message + /schedule/message/event/response/record: + post: + consumes: + - application/json + description: Saves the result of sending a text message (requires JWT) + parameters: + - description: Data to add MessageEventResponse + in: body + name: request + required: true + schema: + $ref: '#/definitions/handler.RecordEventRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/handler.RecordEventResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handler.RecordEventResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handler.RecordEventResponse' + security: + - BearerAuth: [] + summary: Record MessageEventResponse + tags: + - message /schedule/message/fetch: get: consumes: diff --git a/internal/handler/endpoint/endpoint.go b/internal/handler/endpoint/endpoint.go index c6bda68..1c3676d 100644 --- a/internal/handler/endpoint/endpoint.go +++ b/internal/handler/endpoint/endpoint.go @@ -1,19 +1,28 @@ package endpoint -const MESSAGE_DRAFT_ENDPOINT = "/api/v1/message/draft" -const ADD_MESSAGE = "/api/v1/message/new" -const GET_MESSAGE = "/api/v1/message" -const GET_CONTACT = "/api/v1/contact" -const ADD_CONTACT_ENDPOINT = "/api/v1/contact/new" -const ScheduleMessageEndpoint = "/api/v1/schedule/message" -const GetScheduledMessageEndpoint = "/api/v1/schedule/message" -const AddEventToScheduledMessageEndpoint = "/api/v1/schedule/message/event" -const GetScheduledMessageEventEndpoint = "/api/v1/schedule/message/event" -const DeleteScheduledMessageEventEndpoint = "/api/v1/schedule/message/event/{id}" -const UpdateScheduledMessageStatusEndpoint = "/api/v1/schedule/message/status/update" -const FetchNextScheduledMessageEndpoint = "/api/v1/schedule/message/fetch" -// TODO: Tweak endpoint verbage for MessageEventResponse endpoint -// TODO: Make RecordEventResponse more consistent with MessageEventResponse -const RecordEventResponse = "/api/v1/schedule/message/event/response/record" -const FetchMessageEventResponse = "/api/v1/schedule/message/event/response" -const SendInstantMessageEndpoint = "/api/v1/instant/message" +const ( + MESSAGE_DRAFT_ENDPOINT = "/api/v1/message/draft" + + ADD_MESSAGE = "/api/v1/message/new" + GET_MESSAGE = "/api/v1/message" + + GET_CONTACT = "/api/v1/contact" + ADD_CONTACT_ENDPOINT = "/api/v1/contact/new" + + ScheduleMessageEndpoint = "/api/v1/schedule/message" + GetScheduledMessageEndpoint = "/api/v1/schedule/message" + + AddEventToScheduledMessageEndpoint = "/api/v1/schedule/message/event" + GetScheduledMessageEventEndpoint = "/api/v1/schedule/message/event" + DeleteScheduledMessageEventEndpoint = "/api/v1/schedule/message/event/{id}" + UpdateScheduledMessageStatusEndpoint = "/api/v1/schedule/message/status/update" + + FetchNextScheduledMessageEndpoint = "/api/v1/schedule/message/fetch" + + // TODO: Tweak endpoint verbage for MessageEventResponse endpoint + // TODO: Make RecordEventResponse more consistent with MessageEventResponse + RecordEventResponse = "/api/v1/schedule/message/event/response/record" + FetchMessageEventResponse = "/api/v1/schedule/message/event/response" + + SendInstantMessageEndpoint = "/api/v1/instant/message" +) diff --git a/internal/handler/helper_test.go b/internal/handler/helper_test.go index 4a8f190..4c4c656 100644 --- a/internal/handler/helper_test.go +++ b/internal/handler/helper_test.go @@ -2,6 +2,7 @@ package handler import ( "context" + "encoding/json" "fmt" "os" "path" @@ -74,3 +75,36 @@ func TestScheduledMessage(id uuid.UUID, userId uuid.UUID, now time.Time) schedul func TestScheduledMessageEvent(messageId, contactId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent { return scheduling.ScheduledMessageEvent{MessageId: messageId, ContactId: contactId, ScheduledMessageId: scheduledMessageId} } + +func TestMERResponseInString() string { + return `{ + "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" + } +}` +} + +func TestConvertStringToMapOfAny(response string) (map[string]any, error) { + bytes := []byte(response) + var merResponse map[string]any + err := json.Unmarshal(bytes, &merResponse) + if err != nil { + return nil, err + } else { + return merResponse, nil + } +} diff --git a/internal/handler/message_event_response.go b/internal/handler/message_event_response.go index 9092602..7dc00ac 100644 --- a/internal/handler/message_event_response.go +++ b/internal/handler/message_event_response.go @@ -36,6 +36,18 @@ type RecordEventResponse struct { Data []*event.MessageEventResponse `json:"data"` } +// RecordMessageEventResponse godoc +// @Summary Record MessageEventResponse +// @Description Saves the result of sending a text message (requires JWT) +// @Tags message +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param request body RecordEventRequest true "Data to add MessageEventResponse" +// @Success 201 {object} RecordEventResponse +// @Failure 400 {object} RecordEventResponse +// @Failure 500 {object} RecordEventResponse +// @Router /schedule/message/event/response/record [post] func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Request) { var req RecordEventRequest if err := ExtractFromRequest(r, &req); err != nil { @@ -107,6 +119,18 @@ type GetMessageEventResponseFetchedResponse struct { Data []*event.MessageEventResponse `json:"data"` } +// FetchtMessageEventResponse godoc +// @Summary Fetcht MessageEventResponse +// @Description Fetches a MessageEventResponse given a user id (requires JWT) +// @Tags message +// @Accept json +// @Produce json +// @Param user_id path string true "User Id" +// @Security BearerAuth +// @Success 200 {object} GetMessageEventResponseFetchedResponse +// @Failure 400 {object} GetMessageEventResponseFetchedResponse +// @Failure 500 {object} GetMessageEventResponseFetchedResponse +// @Router /schedule/message/event/response [get] func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) { queryParams := r.URL.Query() var userId uuid.UUID diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index 243b83f..b6e48ba 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -2,13 +2,14 @@ package handler import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" - "git.kundeng.us/phoenix/textsender-models/tx0/message" + evnt "git.kundeng.us/phoenix/textsender-models/tx0/message/event" "git.kundeng.us/phoenix/textsender-models/tx0/message/scheduling" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -30,12 +31,12 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { assert.NoError(t, err, "Error getting app") handler := NewEventResponseHandler(apiApp, merStore) - recipientId := uuid.New() + contactId := uuid.New() messageId := uuid.New() scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(recipientId, testUserId) + con := TestContact(contactId, testUserId) msg := TestMessage(messageId, testUserId) schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) event := scheduling.ScheduledMessageEvent{} @@ -50,17 +51,19 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { assert.NoError(t, err, "Error creating scheduled message: %v", err) } - event.MessageId = msg.Id - event.RecipientId = *con.Id + event.MessageId = *msg.Id + event.ContactId = *con.Id event.ScheduledMessageId = schMsg.Id if err := mockStore.CreateScheduledMessageEvent(ctx, &event); err != nil { assert.NoError(t, err, "Error creating scheduled message event: %v", err) } 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\"}}") + var merResponse map[string]any + merResponse, err = TestConvertStringToMapOfAny(TestMERResponseInString()) + assert.NoError(t, err, "Error Converting to map[string]any") - testReq := RecordEventRequest{ScheduledMessageEventId: event.Id, Response: bytes, UserId: schMsg.UserId, Sent: &sent, Status: message.Message_Event_Response_Status_Scheduled} + testReq := RecordEventRequest{ScheduledMessageEventId: event.Id, Response: merResponse, UserId: schMsg.UserId, Sent: &sent, Status: evnt.Message_Event_Response_Status_Scheduled} jsonValue, _ := json.Marshal(testReq) req, _ := http.NewRequest("POST", endpoint.RecordEventResponse, strings.NewReader(string(jsonValue))) @@ -76,9 +79,84 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { assert.NotEmpty(t, response.Data, "No message event response created") - var msgEventResp message.MessageEventResponse + var msgEventResp evnt.MessageEventResponse msgEventResp = *response.Data[0] assert.NotEmpty(t, msgEventResp.Response, "The response of the message event response is empty") assert.Equal(t, msgEventResp.Response, testReq.Response, "Responses do not match") } + +func TestGetMessageEventResponse(t *testing.T) { + now := time.Now() + + mockStore := mock.NewMockScheduledMessageEventStore() + contactStore := mock.NewMockContactStore() + messageStore := mock.NewMockMessageStore() + schMsgStore := mock.NewMockScheduledMessageStore() + merStore := mock.NewMockMessageEventResponseStore() + + apiApp, err := GetApp() + assert.NoError(t, err, "Error getting app") + handler := NewEventResponseHandler(apiApp, merStore) + + contactId := uuid.New() + messageId := uuid.New() + scheduledMessageId := uuid.New() + testUserId := uuid.New() + + con := TestContact(contactId, testUserId) + msg := TestMessage(messageId, testUserId) + schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + event := scheduling.ScheduledMessageEvent{} + + ctx := t.Context() + + if err := contactStore.CreateContact(ctx, &con); err != nil { + assert.NoError(t, err, "Error creating contact: %v", err) + } else if err = messageStore.CreateMessage(ctx, &msg); err != nil { + assert.NoError(t, err, "Error creating message: %v", err) + } else if err = schMsgStore.CreateScheduledMessage(ctx, &schMsg); err != nil { + assert.NoError(t, err, "Error creating scheduled message: %v", err) + } + + event.MessageId = *msg.Id + event.ContactId = *con.Id + event.ScheduledMessageId = schMsg.Id + sent := now.Add(30 * time.Minute) + if err := mockStore.CreateScheduledMessageEvent(ctx, &event); err != nil { + assert.NoError(t, err, "Error creating scheduled message event: %v", err) + } else { + m := evnt.MessageEventResponse{} + m.ScheduledMessageEventId = event.Id + m.UserId = schMsg.UserId + m.Status = evnt.Message_Event_Response_Status_Scheduled + m.Sent = sent + var merResponse map[string]any + merResponse, err = TestConvertStringToMapOfAny(TestMERResponseInString()) + assert.NoError(t, err, "Error Converting to map[string]any") + m.Response = merResponse + + if err := merStore.Create(ctx, &m); err != nil { + assert.NoError(t, err, "Error creating MessageEventResponse: %v", err) + } + } + + url := fmt.Sprintf("%s?user_id=%s", endpoint.FetchMessageEventResponse, testUserId.String()) + req, _ := http.NewRequest("GET", url, nil) + rr := httptest.NewRecorder() + + handler.RecordResponse(rr, req) + + assert.Equal(t, http.StatusOK, rr.Code) + + var response GetMessageEventResponseFetchedResponse + err = json.Unmarshal(rr.Body.Bytes(), &response) + assert.NoError(t, err, "Error parsing message event response: %v", err) + + assert.NotEmpty(t, response.Data, "No message event response found") + + var msgEventResp evnt.MessageEventResponse + msgEventResp = *response.Data[0] + + assert.NotEmpty(t, msgEventResp.Response, "The response of the message event response is empty") +} diff --git a/internal/store/message_event_response_store.go b/internal/store/message_event_response_store.go index 2a9f4de..4cf0a19 100644 --- a/internal/store/message_event_response_store.go +++ b/internal/store/message_event_response_store.go @@ -38,7 +38,7 @@ func (m *PGMessageEventResponseStore) Create(ctx context.Context, mer *event.Mes func (m *PGMessageEventResponseStore) GetWithUserId(ctx context.Context, userId uuid.UUID) ([]*event.MessageEventResponse, error) { query := "SELECT id, scheduled_message_event_id, response, user_id, sent, contact_id, message_id, status FROM message_event_responses WHERE user_id = $1" - rows, err := m.db.Query(ctx, query) + rows, err := m.db.Query(ctx, query, userId) if err != nil { return nil, fmt.Errorf("Error querying: %w", err) } diff --git a/internal/store/mock/scheduled_message_event_store.go b/internal/store/mock/scheduled_message_event_store.go index b7b3cf8..f8631f8 100644 --- a/internal/store/mock/scheduled_message_event_store.go +++ b/internal/store/mock/scheduled_message_event_store.go @@ -11,7 +11,7 @@ import ( ) type ScheduledMessageEventKey struct { - RecipientId uuid.UUID + ContactId uuid.UUID MessageId uuid.UUID ScheduledMessageId uuid.UUID } @@ -94,7 +94,7 @@ func (m *MockScheduledMessageEventStore) Delete(ctx context.Context, id uuid.UUI copiedEventsKey := make(map[ScheduledMessageEventKey]*scheduling.ScheduledMessageEvent) for i, schMsgEvent := range m.ScheduledMessageEvents { - key := ScheduledMessageEventKey{RecipientId: schMsgEvent.RecipientId, MessageId: schMsgEvent.MessageId, ScheduledMessageId: schMsgEvent.ScheduledMessageId} + key := ScheduledMessageEventKey{ContactId: schMsgEvent.ContactId, MessageId: schMsgEvent.MessageId, ScheduledMessageId: schMsgEvent.ScheduledMessageId} if schMsgEvent.Id != id { copiedEvents[i] = schMsgEvent copiedEventsKey[key] = schMsgEvent @@ -132,7 +132,7 @@ func (m *MockScheduledMessageEventStore) CreateScheduledMessageEvent(ctx context event.Id = uuid.New() } - key := ScheduledMessageEventKey{RecipientId: event.RecipientId, MessageId: event.MessageId, ScheduledMessageId: event.ScheduledMessageId} + key := ScheduledMessageEventKey{ContactId: event.ContactId, MessageId: event.MessageId, ScheduledMessageId: event.ScheduledMessageId} if _, exists := m.ScheduledMessageEventsByKey[key]; exists { return fmt.Errorf("Already exists") @@ -152,7 +152,7 @@ func (m *MockScheduledMessageEventStore) Exists(ctx context.Context, event *sche return false, m.Error } - key := ScheduledMessageEventKey{RecipientId: event.RecipientId, MessageId: event.MessageId, ScheduledMessageId: event.ScheduledMessageId} + key := ScheduledMessageEventKey{ContactId: event.ContactId, MessageId: event.MessageId, ScheduledMessageId: event.ScheduledMessageId} _, exists := m.ScheduledMessageEventsByKey[key] return exists, nil diff --git a/internal/store/mock/store.go b/internal/store/mock/store.go index aa2b014..df469e8 100644 --- a/internal/store/mock/store.go +++ b/internal/store/mock/store.go @@ -36,16 +36,18 @@ func (m *MockMessageStore) CreateMessage(ctx context.Context, msg *message.Messa return m.Error } - if msg.Id == uuid.Nil { - msg.Id = uuid.New() + var id uuid.UUID + if msg.Id != nil && msg.Id == uuid.Nil { + id = uuid.New() + msg.Id = &id } - key := MessageKey{Content: msg.Content, UserId: msg.UserId} + key := MessageKey{Content: msg.Content, UserId: *msg.UserId} if _, exists := m.MessagesByKey[key]; exists { return errors.New("Message already exists") } - m.Messages[msg.Id] = msg + m.Messages[*msg.Id] = msg m.MessagesByKey[key] = msg return nil } @@ -88,7 +90,7 @@ func (m *MockMessageStore) MessageExists(ctx context.Context, msg *message.Messa return false, m.Error } - _, exists := m.MessagesByKey[MessageKey{Content: msg.Content, UserId: msg.UserId}] + _, exists := m.MessagesByKey[MessageKey{Content: msg.Content, UserId: *msg.UserId}] return exists, nil } From 57619759d5d0792bb9e3d0ee9171668dc3904828 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 13:56:51 -0500 Subject: [PATCH 10/20] Test changes --- internal/handler/helper_test.go | 17 +++++++++-------- internal/handler/message_event_response_test.go | 12 ++++++------ internal/handler/message_test.go | 2 +- .../handler/schedule_message_status_test.go | 10 +++++----- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/internal/handler/helper_test.go b/internal/handler/helper_test.go index 4c4c656..0fd8221 100644 --- a/internal/handler/helper_test.go +++ b/internal/handler/helper_test.go @@ -47,7 +47,7 @@ func ResetTestDB(t *testing.T, tableName string) { } } -func TestContact(id uuid.UUID, userId uuid.UUID) contact.Contact { +func ContactTest(id uuid.UUID, userId uuid.UUID) contact.Contact { if id == uuid.Nil { id = uuid.New() return contact.Contact{Id: &id, PhoneNumber: "+10123456789", UserId: &userId} @@ -56,15 +56,16 @@ func TestContact(id uuid.UUID, userId uuid.UUID) contact.Contact { } } -func TestMessage(id uuid.UUID, userId uuid.UUID) message.Message { +func MessageTest(id uuid.UUID, userId uuid.UUID) message.Message { if id == uuid.Nil { - return message.Message{Id: uuid.New(), Content: "Oh how the mighty have fallen", UserId: userId} + id = uuid.New() + return message.Message{Id: &id, Content: "Oh how the mighty have fallen", UserId: &userId} } else { - return message.Message{Id: id, Content: "Oh how the mighty have fallen", UserId: userId} + return message.Message{Id: &id, Content: "Oh how the mighty have fallen", UserId: &userId} } } -func TestScheduledMessage(id uuid.UUID, userId uuid.UUID, now time.Time) scheduling.ScheduledMessage { +func ScheduledMessageTest(id uuid.UUID, userId uuid.UUID, now time.Time) scheduling.ScheduledMessage { if id == uuid.Nil { return scheduling.ScheduledMessage{Id: uuid.New(), UserId: userId, Scheduled: now.Add(20 * time.Minute), Status: scheduling.Pending} } else { @@ -72,11 +73,11 @@ func TestScheduledMessage(id uuid.UUID, userId uuid.UUID, now time.Time) schedul } } -func TestScheduledMessageEvent(messageId, contactId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent { +func ScheduledMessageEventTest(messageId, contactId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent { return scheduling.ScheduledMessageEvent{MessageId: messageId, ContactId: contactId, ScheduledMessageId: scheduledMessageId} } -func TestMERResponseInString() string { +func MERResponseInString() string { return `{ "body": "Whoknows?", "num_segments": "0", @@ -98,7 +99,7 @@ func TestMERResponseInString() string { }` } -func TestConvertStringToMapOfAny(response string) (map[string]any, error) { +func ConvertStringToMapOfAny(response string) (map[string]any, error) { bytes := []byte(response) var merResponse map[string]any err := json.Unmarshal(bytes, &merResponse) diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index b6e48ba..388763e 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -36,9 +36,9 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) event := scheduling.ScheduledMessageEvent{} ctx := t.Context() @@ -104,9 +104,9 @@ func TestGetMessageEventResponse(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) event := scheduling.ScheduledMessageEvent{} ctx := t.Context() diff --git a/internal/handler/message_test.go b/internal/handler/message_test.go index 0fbb03e..d162e78 100644 --- a/internal/handler/message_test.go +++ b/internal/handler/message_test.go @@ -51,7 +51,7 @@ func TestGetMessageWithMock(t *testing.T) { mockstore := mock.NewMockMessageStore() testUserId := uuid.New() - testCon := message.Message{Content: "Who is the one that benefits?", UserId: testUserId} + testCon := message.Message{Content: "Who is the one that benefits?", UserId: &testUserId} ctx := t.Context() if err := mockstore.CreateMessage(ctx, &testCon); err != nil { assert.NoError(t, err, "Error creating message") diff --git a/internal/handler/schedule_message_status_test.go b/internal/handler/schedule_message_status_test.go index 0d8a2f4..d868620 100644 --- a/internal/handler/schedule_message_status_test.go +++ b/internal/handler/schedule_message_status_test.go @@ -24,15 +24,15 @@ func TestUpdateScheduledMessageStatusWithMock(t *testing.T) { messageStore := mock.NewMockMessageStore() schMsgStore := mock.NewMockScheduledMessageStore() - recipientId := uuid.New() + contactId := uuid.New() messageId := uuid.New() scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(recipientId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) - event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) + event := ScheduledMessageEventTest(*msg.Id, *con.Id, schMsg.Id) ctx := t.Context() From f73c9598308ec8322a05481152c8f3d14cda0adc Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:01:58 -0500 Subject: [PATCH 11/20] More test changes --- .../handler/message_event_response_test.go | 4 ++-- .../handler/scheduled_message_event_test.go | 22 +++++++++---------- internal/handler/scheduled_message_test.go | 12 +++++----- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index 388763e..7b03a0c 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) var merResponse map[string]any - merResponse, err = TestConvertStringToMapOfAny(TestMERResponseInString()) + merResponse, err = ConvertStringToMapOfAny(MERResponseInString()) assert.NoError(t, err, "Error Converting to map[string]any") testReq := RecordEventRequest{ScheduledMessageEventId: event.Id, Response: merResponse, UserId: schMsg.UserId, Sent: &sent, Status: evnt.Message_Event_Response_Status_Scheduled} @@ -132,7 +132,7 @@ func TestGetMessageEventResponse(t *testing.T) { m.Status = evnt.Message_Event_Response_Status_Scheduled m.Sent = sent var merResponse map[string]any - merResponse, err = TestConvertStringToMapOfAny(TestMERResponseInString()) + merResponse, err = ConvertStringToMapOfAny(MERResponseInString()) assert.NoError(t, err, "Error Converting to map[string]any") m.Response = merResponse diff --git a/internal/handler/scheduled_message_event_test.go b/internal/handler/scheduled_message_event_test.go index ade1517..ce98975 100644 --- a/internal/handler/scheduled_message_event_test.go +++ b/internal/handler/scheduled_message_event_test.go @@ -47,9 +47,9 @@ func TestCreateScheduledMessageEventWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) ctx := t.Context() @@ -99,10 +99,10 @@ func TestGetScheduledMessageEventWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) - event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) + event := ScheduledMessageEventTest(*msg.Id, *con.Id, schMsg.Id) ctx := t.Context() @@ -145,10 +145,10 @@ func TestDeleteScheduledMessageEventWithMock(t *testing.T) { assert.NoError(t, err, "Error getting app") handler := NewScheduledMessageEventHandler(apiApp, schMsgEventStore, schMsgStore) - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) - event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) + event := ScheduledMessageEventTest(*msg.Id, *con.Id, schMsg.Id) ctx := t.Context() diff --git a/internal/handler/scheduled_message_test.go b/internal/handler/scheduled_message_test.go index 60ce7dd..364f328 100644 --- a/internal/handler/scheduled_message_test.go +++ b/internal/handler/scheduled_message_test.go @@ -31,7 +31,7 @@ func TestCreateScheduledMessageWithMock(t *testing.T) { handler := NewScheduledMessageHandler(apiApp, mockStore) testUserId := uuid.New() - testBody := testCreateScheduledMessageRequest(testUserId, now) + testBody := createScheduledMessageRequest(testUserId, now) jsonValue, _ := json.Marshal(testBody) req, _ := http.NewRequest("POST", endpoint.ScheduleMessageEndpoint, strings.NewReader(string(jsonValue))) @@ -94,10 +94,10 @@ func TestFetchScheduledMessageWithMock(t *testing.T) { scheduledMessageId := uuid.New() testUserId := uuid.New() - con := TestContact(contactId, testUserId) - msg := TestMessage(messageId, testUserId) - schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) - event := TestScheduledMessageEvent(msg.Id, *con.Id, schMsg.Id) + con := ContactTest(contactId, testUserId) + msg := MessageTest(messageId, testUserId) + schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) + event := ScheduledMessageEventTest(*msg.Id, *con.Id, schMsg.Id) ctx := t.Context() @@ -135,7 +135,7 @@ func TestFetchScheduledMessageWithMock(t *testing.T) { assert.Equal(t, scheduling.Processing, fetchedSchMsg.Status, "The statuses do not match") } -func testCreateScheduledMessageRequest(userId uuid.UUID, now time.Time) CreateScheduledMessageRequest { +func createScheduledMessageRequest(userId uuid.UUID, now time.Time) CreateScheduledMessageRequest { scheduled := now.Add(5 * time.Minute) return CreateScheduledMessageRequest{Status: scheduling.Pending, UserId: userId, Scheduled: scheduled} } From 49f5e0ea40885b7f9f9a29d55ea9e8b39f25604e Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:04:06 -0500 Subject: [PATCH 12/20] Fix build issue --- internal/store/mock/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/store/mock/store.go b/internal/store/mock/store.go index df469e8..cad38b8 100644 --- a/internal/store/mock/store.go +++ b/internal/store/mock/store.go @@ -37,7 +37,7 @@ func (m *MockMessageStore) CreateMessage(ctx context.Context, msg *message.Messa } var id uuid.UUID - if msg.Id != nil && msg.Id == uuid.Nil { + if msg.Id != nil && *msg.Id == uuid.Nil { id = uuid.New() msg.Id = &id } From 0334c67c368b72bd7a2991e1ec8d56f196b0b533 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:07:09 -0500 Subject: [PATCH 13/20] Fix another test issue --- internal/handler/scheduled_message_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handler/scheduled_message_test.go b/internal/handler/scheduled_message_test.go index 364f328..95a4936 100644 --- a/internal/handler/scheduled_message_test.go +++ b/internal/handler/scheduled_message_test.go @@ -55,7 +55,7 @@ func TestGetScheduledMessageWithMock(t *testing.T) { mockStore := mock.NewMockScheduledMessageStore() testUserId := uuid.New() - testBody := testCreateScheduledMessageRequest(testUserId, now) + testBody := createScheduledMessageRequest(testUserId, now) ctx := t.Context() schMsg := scheduling.ScheduledMessage{} From 161d0da3772368553113ea1975a41297c7063bf2 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:09:20 -0500 Subject: [PATCH 14/20] Another one --- internal/handler/helper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handler/helper_test.go b/internal/handler/helper_test.go index 0fd8221..81ca2ea 100644 --- a/internal/handler/helper_test.go +++ b/internal/handler/helper_test.go @@ -41,7 +41,7 @@ func GetApp() (*app.App, error) { func ResetTestDB(t *testing.T, tableName string) { t.Helper() - _, err := db.Pool.Exec(context.Background(), fmt.Sprintf("DELETE FROM ", tableName)) + _, err := db.Pool.Exec(context.Background(), fmt.Sprintf("DELETE FROM %s", tableName)) if err != nil { t.Fatalf("Failed to reset test database: %v", err) } From 08650619dc26261d2116eac8c2be314aa0f04f61 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:11:44 -0500 Subject: [PATCH 15/20] Minor refactor --- internal/handler/helper.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/handler/helper.go b/internal/handler/helper.go index 0b135d9..adb68b2 100644 --- a/internal/handler/helper.go +++ b/internal/handler/helper.go @@ -25,8 +25,7 @@ func InvalidJson(err error) string { func RespondWithJSON(w http.ResponseWriter, statusCode int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) - encoder := json.NewEncoder(w) - if err := encoder.Encode(data); err != nil { + if err := json.NewEncoder(w).Encode(data); err != nil { log.Printf("Error encoding JSON: %v", err) } } From b33c05531ba939b4f6d301c95da10e0961b08a88 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:18:56 -0500 Subject: [PATCH 16/20] Test change --- internal/handler/message_event_response_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index 7b03a0c..bb908c1 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -107,7 +107,6 @@ func TestGetMessageEventResponse(t *testing.T) { con := ContactTest(contactId, testUserId) msg := MessageTest(messageId, testUserId) schMsg := ScheduledMessageTest(scheduledMessageId, testUserId, now) - event := scheduling.ScheduledMessageEvent{} ctx := t.Context() @@ -119,6 +118,7 @@ func TestGetMessageEventResponse(t *testing.T) { assert.NoError(t, err, "Error creating scheduled message: %v", err) } + event := scheduling.ScheduledMessageEvent{} event.MessageId = *msg.Id event.ContactId = *con.Id event.ScheduledMessageId = schMsg.Id @@ -141,7 +141,7 @@ func TestGetMessageEventResponse(t *testing.T) { } } - url := fmt.Sprintf("%s?user_id=%s", endpoint.FetchMessageEventResponse, testUserId.String()) + url := fmt.Sprintf("%s?user_id=%s", endpoint.FetchMessageEventResponse, testUserId) req, _ := http.NewRequest("GET", url, nil) rr := httptest.NewRecorder() From 400490b633a46e88d99cb3a9e5e066a91e46528e Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:19:36 -0500 Subject: [PATCH 17/20] Whoops --- internal/handler/message_event_response_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handler/message_event_response_test.go b/internal/handler/message_event_response_test.go index bb908c1..0792ffa 100644 --- a/internal/handler/message_event_response_test.go +++ b/internal/handler/message_event_response_test.go @@ -145,7 +145,7 @@ func TestGetMessageEventResponse(t *testing.T) { req, _ := http.NewRequest("GET", url, nil) rr := httptest.NewRecorder() - handler.RecordResponse(rr, req) + handler.Fetch(rr, req) assert.Equal(t, http.StatusOK, rr.Code) From a0bab48f40c96f5ef36c050af8ea1f76768b1871 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:28:55 -0500 Subject: [PATCH 18/20] Could it be? --- internal/handler/message.go | 5 ----- internal/store/mock/store.go | 11 ++++++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/handler/message.go b/internal/handler/message.go index eed2b39..0d2cd06 100644 --- a/internal/handler/message.go +++ b/internal/handler/message.go @@ -46,11 +46,6 @@ type AddMessageResponse struct { // @Failure 500 {object} AddMessageResponse // @Router /message/new [post] func (m *MessageHandler) AddMessage(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) - return - } - var req RequestAddMessage if err := ExtractFromRequest(r, &req); err != nil { http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest) diff --git a/internal/store/mock/store.go b/internal/store/mock/store.go index cad38b8..ec48680 100644 --- a/internal/store/mock/store.go +++ b/internal/store/mock/store.go @@ -3,6 +3,7 @@ package mock import ( "context" "errors" + "fmt" "sync" "git.kundeng.us/phoenix/textsender-models/tx0/message" @@ -37,9 +38,13 @@ func (m *MockMessageStore) CreateMessage(ctx context.Context, msg *message.Messa } var id uuid.UUID - if msg.Id != nil && *msg.Id == uuid.Nil { - id = uuid.New() - msg.Id = &id + if msg != nil { + if msg.Id == nil || *msg.Id == uuid.Nil { + id = uuid.New() + msg.Id = &id + } + } else { + return fmt.Errorf("Message not populated") } key := MessageKey{Content: msg.Content, UserId: *msg.UserId} From 0e956da330530bbfab9afd50b6f13985561552dd Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 14:33:44 -0500 Subject: [PATCH 19/20] Missed another one --- internal/handler/scheduled_message_event_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handler/scheduled_message_event_test.go b/internal/handler/scheduled_message_event_test.go index ce98975..2889cc8 100644 --- a/internal/handler/scheduled_message_event_test.go +++ b/internal/handler/scheduled_message_event_test.go @@ -25,7 +25,7 @@ var ( ) type CreateScheduledMessageEventRequest struct { - ContactId uuid.UUID `json:"recipient_id"` + ContactId uuid.UUID `json:"contact_id"` MessageId uuid.UUID `json:"message_id"` ScheduledMessageId uuid.UUID `json:"scheduled_message_id"` } From a33af13f45f3fcc5d26f3fadd7453e8d315f9b16 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 1 Jan 2026 16:00:49 -0500 Subject: [PATCH 20/20] textsender-models and swoosh version bump --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index fe6c45b..cda6632 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.1.0-main-3c1f8a1a27-556 - git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556 + git.kundeng.us/phoenix/swoosh v0.1.0 + git.kundeng.us/phoenix/textsender-models v0.1.6 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 112117a..1091a14 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -git.kundeng.us/phoenix/swoosh v0.1.0-main-3c1f8a1a27-556 h1:KsX+w6iUSPWajQs6fkpDhTBixcUjq9vb4NGXFWKA7fM= -git.kundeng.us/phoenix/swoosh v0.1.0-main-3c1f8a1a27-556/go.mod h1:XGXsm6S8+W52FXsMnYo4eOpILHAu5S86IgboZALfyQw= -git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556 h1:869mq7lyB+XaNqJOMOGWdfHs97sC2OrreIxW4zkIjkQ= -git.kundeng.us/phoenix/textsender-models v0.1.6-30-f4e2336771-556/go.mod h1:9iPDQJg1Tc6WMNoW5+f8YKmnosMwlWHJ++hmxNLDEe0= +git.kundeng.us/phoenix/swoosh v0.1.0 h1:9P+wLuJsIZmVcRoG+W22l06hwp54eNrYbsBtGjucnjI= +git.kundeng.us/phoenix/swoosh v0.1.0/go.mod h1:6/97/aS8KVdYqlczQ9ALvS3GVoce1UVl+D8VQK42Bd0= +git.kundeng.us/phoenix/textsender-models v0.1.6 h1:d/rhvqjFSt1Ty/3UfwS21be+lYb9EtWEaDtkzfbzEp0= +git.kundeng.us/phoenix/textsender-models v0.1.6/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=