tsk-59: Get MessageEventResponse endpoint (#61)

Closes #59

Reviewed-on: phoenix/textsender-api#61
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
This commit is contained in:
phoenix
2026-01-01 05:28:49 +00:00
committed by phoenix
parent 6641f384ab
commit 59c9aa0ff1
10 changed files with 712 additions and 113 deletions
+200 -29
View File
@@ -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}": { "/schedule/message/event/{id}": {
"delete": { "delete": {
"security": [ "security": [
@@ -642,9 +742,18 @@ const docTemplate = `{
"contact.Contact": { "contact.Contact": {
"type": "object", "type": "object",
"properties": { "properties": {
"first_name": {
"type": "string"
},
"id": { "id": {
"type": "string" "type": "string"
}, },
"last_name": {
"type": "string"
},
"nickname": {
"type": "string"
},
"phone_number": { "phone_number": {
"type": "string" "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": { "handler.AddContactResponse": {
"type": "object", "type": "object",
"properties": { "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": { "handler.GetMessageResponse": {
"type": "object", "type": "object",
"properties": { "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": { "handler.RequestAddContact": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -832,10 +1026,10 @@ const docTemplate = `{
"handler.RequestAddScheduledMessageEvent": { "handler.RequestAddScheduledMessageEvent": {
"type": "object", "type": "object",
"properties": { "properties": {
"message_id": { "contact_id": {
"type": "string" "type": "string"
}, },
"recipient_id": { "message_id": {
"type": "string" "type": "string"
}, },
"scheduled_message_id": { "scheduled_message_id": {
@@ -902,7 +1096,7 @@ const docTemplate = `{
"data": { "data": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/message.MessageEventResponse" "$ref": "#/definitions/event.MessageEventResponse"
} }
}, },
"message": { "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": { "scheduling.ScheduledMessage": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -970,6 +1141,9 @@ const docTemplate = `{
"scheduling.ScheduledMessageEvent": { "scheduling.ScheduledMessageEvent": {
"type": "object", "type": "object",
"properties": { "properties": {
"contact_id": {
"type": "string"
},
"created": { "created": {
"type": "string" "type": "string"
}, },
@@ -979,9 +1153,6 @@ const docTemplate = `{
"message_id": { "message_id": {
"type": "string" "type": "string"
}, },
"recipient_id": {
"type": "string"
},
"scheduled_message_id": { "scheduled_message_id": {
"type": "string" "type": "string"
} }
+200 -29
View File
@@ -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}": { "/schedule/message/event/{id}": {
"delete": { "delete": {
"security": [ "security": [
@@ -636,9 +736,18 @@
"contact.Contact": { "contact.Contact": {
"type": "object", "type": "object",
"properties": { "properties": {
"first_name": {
"type": "string"
},
"id": { "id": {
"type": "string" "type": "string"
}, },
"last_name": {
"type": "string"
},
"nickname": {
"type": "string"
},
"phone_number": { "phone_number": {
"type": "string" "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": { "handler.AddContactResponse": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -745,6 +884,20 @@
} }
} }
}, },
"handler.GetMessageEventResponseFetchedResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/event.MessageEventResponse"
}
},
"message": {
"type": "string"
}
}
},
"handler.GetMessageResponse": { "handler.GetMessageResponse": {
"type": "object", "type": "object",
"properties": { "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": { "handler.RequestAddContact": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -826,10 +1020,10 @@
"handler.RequestAddScheduledMessageEvent": { "handler.RequestAddScheduledMessageEvent": {
"type": "object", "type": "object",
"properties": { "properties": {
"message_id": { "contact_id": {
"type": "string" "type": "string"
}, },
"recipient_id": { "message_id": {
"type": "string" "type": "string"
}, },
"scheduled_message_id": { "scheduled_message_id": {
@@ -896,7 +1090,7 @@
"data": { "data": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/message.MessageEventResponse" "$ref": "#/definitions/event.MessageEventResponse"
} }
}, },
"message": { "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": { "scheduling.ScheduledMessage": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -964,6 +1135,9 @@
"scheduling.ScheduledMessageEvent": { "scheduling.ScheduledMessageEvent": {
"type": "object", "type": "object",
"properties": { "properties": {
"contact_id": {
"type": "string"
},
"created": { "created": {
"type": "string" "type": "string"
}, },
@@ -973,9 +1147,6 @@
"message_id": { "message_id": {
"type": "string" "type": "string"
}, },
"recipient_id": {
"type": "string"
},
"scheduled_message_id": { "scheduled_message_id": {
"type": "string" "type": "string"
} }
+130 -20
View File
@@ -2,13 +2,39 @@ basePath: /api/v1
definitions: definitions:
contact.Contact: contact.Contact:
properties: properties:
first_name:
type: string
id: id:
type: string type: string
last_name:
type: string
nickname:
type: string
phone_number: phone_number:
type: string type: string
user_id: user_id:
type: string type: string
type: object 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: handler.AddContactResponse:
properties: properties:
data: data:
@@ -72,6 +98,15 @@ definitions:
message: message:
type: string type: string
type: object type: object
handler.GetMessageEventResponseFetchedResponse:
properties:
data:
items:
$ref: '#/definitions/event.MessageEventResponse'
type: array
message:
type: string
type: object
handler.GetMessageResponse: handler.GetMessageResponse:
properties: properties:
data: data:
@@ -99,6 +134,33 @@ definitions:
message: message:
type: string type: string
type: object 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: handler.RequestAddContact:
properties: properties:
phone_number: phone_number:
@@ -124,9 +186,9 @@ definitions:
type: object type: object
handler.RequestAddScheduledMessageEvent: handler.RequestAddScheduledMessageEvent:
properties: properties:
message_id: contact_id:
type: string type: string
recipient_id: message_id:
type: string type: string
scheduled_message_id: scheduled_message_id:
type: string type: string
@@ -169,7 +231,7 @@ definitions:
properties: properties:
data: data:
items: items:
$ref: '#/definitions/message.MessageEventResponse' $ref: '#/definitions/event.MessageEventResponse'
type: array type: array
message: message:
type: string type: string
@@ -183,21 +245,6 @@ definitions:
user_id: user_id:
type: string type: string
type: object 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: scheduling.ScheduledMessage:
properties: properties:
created: created:
@@ -213,14 +260,14 @@ definitions:
type: object type: object
scheduling.ScheduledMessageEvent: scheduling.ScheduledMessageEvent:
properties: properties:
contact_id:
type: string
created: created:
type: string type: string
id: id:
type: string type: string
message_id: message_id:
type: string type: string
recipient_id:
type: string
scheduled_message_id: scheduled_message_id:
type: string type: string
type: object type: object
@@ -569,6 +616,69 @@ paths:
summary: Delete scheduled message event summary: Delete scheduled message event
tags: tags:
- scheduled message events - 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: /schedule/message/fetch:
get: get:
consumes: consumes:
+24 -15
View File
@@ -1,19 +1,28 @@
package endpoint package endpoint
const MESSAGE_DRAFT_ENDPOINT = "/api/v1/message/draft" const (
const ADD_MESSAGE = "/api/v1/message/new" MESSAGE_DRAFT_ENDPOINT = "/api/v1/message/draft"
const GET_MESSAGE = "/api/v1/message"
const GET_CONTACT = "/api/v1/contact" ADD_MESSAGE = "/api/v1/message/new"
const ADD_CONTACT_ENDPOINT = "/api/v1/contact/new" GET_MESSAGE = "/api/v1/message"
const ScheduleMessageEndpoint = "/api/v1/schedule/message"
const GetScheduledMessageEndpoint = "/api/v1/schedule/message" GET_CONTACT = "/api/v1/contact"
const AddEventToScheduledMessageEndpoint = "/api/v1/schedule/message/event" ADD_CONTACT_ENDPOINT = "/api/v1/contact/new"
const GetScheduledMessageEventEndpoint = "/api/v1/schedule/message/event"
const DeleteScheduledMessageEventEndpoint = "/api/v1/schedule/message/event/{id}" ScheduleMessageEndpoint = "/api/v1/schedule/message"
const UpdateScheduledMessageStatusEndpoint = "/api/v1/schedule/message/status/update" GetScheduledMessageEndpoint = "/api/v1/schedule/message"
const FetchNextScheduledMessageEndpoint = "/api/v1/schedule/message/fetch"
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: Tweak endpoint verbage for MessageEventResponse endpoint
// TODO: Make RecordEventResponse more consistent with MessageEventResponse // TODO: Make RecordEventResponse more consistent with MessageEventResponse
const RecordEventResponse = "/api/v1/schedule/message/event/response/record" RecordEventResponse = "/api/v1/schedule/message/event/response/record"
const FetchMessageEventResponse = "/api/v1/schedule/message/event/response" FetchMessageEventResponse = "/api/v1/schedule/message/event/response"
const SendInstantMessageEndpoint = "/api/v1/instant/message"
SendInstantMessageEndpoint = "/api/v1/instant/message"
)
+34
View File
@@ -2,6 +2,7 @@ package handler
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"os" "os"
"path" "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 { func TestScheduledMessageEvent(messageId, contactId, scheduledMessageId uuid.UUID) scheduling.ScheduledMessageEvent {
return scheduling.ScheduledMessageEvent{MessageId: messageId, ContactId: contactId, ScheduledMessageId: scheduledMessageId} 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
}
}
@@ -36,6 +36,18 @@ type RecordEventResponse struct {
Data []*event.MessageEventResponse `json:"data"` 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) { func (e *EventResponseHandler) RecordResponse(w http.ResponseWriter, r *http.Request) {
var req RecordEventRequest var req RecordEventRequest
if err := ExtractFromRequest(r, &req); err != nil { if err := ExtractFromRequest(r, &req); err != nil {
@@ -107,6 +119,18 @@ type GetMessageEventResponseFetchedResponse struct {
Data []*event.MessageEventResponse `json:"data"` 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) { func (e *EventResponseHandler) Fetch(w http.ResponseWriter, r *http.Request) {
queryParams := r.URL.Query() queryParams := r.URL.Query()
var userId uuid.UUID var userId uuid.UUID
@@ -2,13 +2,14 @@ package handler
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings" "strings"
"testing" "testing"
"time" "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" "git.kundeng.us/phoenix/textsender-models/tx0/message/scheduling"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -30,12 +31,12 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) {
assert.NoError(t, err, "Error getting app") assert.NoError(t, err, "Error getting app")
handler := NewEventResponseHandler(apiApp, merStore) handler := NewEventResponseHandler(apiApp, merStore)
recipientId := uuid.New() contactId := uuid.New()
messageId := uuid.New() messageId := uuid.New()
scheduledMessageId := uuid.New() scheduledMessageId := uuid.New()
testUserId := uuid.New() testUserId := uuid.New()
con := TestContact(recipientId, testUserId) con := TestContact(contactId, testUserId)
msg := TestMessage(messageId, testUserId) msg := TestMessage(messageId, testUserId)
schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now) schMsg := TestScheduledMessage(scheduledMessageId, testUserId, now)
event := scheduling.ScheduledMessageEvent{} event := scheduling.ScheduledMessageEvent{}
@@ -50,17 +51,19 @@ func TestRecordMessageEventResponseWithMock(t *testing.T) {
assert.NoError(t, err, "Error creating scheduled message: %v", err) assert.NoError(t, err, "Error creating scheduled message: %v", err)
} }
event.MessageId = msg.Id event.MessageId = *msg.Id
event.RecipientId = *con.Id event.ContactId = *con.Id
event.ScheduledMessageId = schMsg.Id event.ScheduledMessageId = schMsg.Id
if err := mockStore.CreateScheduledMessageEvent(ctx, &event); err != nil { if err := mockStore.CreateScheduledMessageEvent(ctx, &event); err != nil {
assert.NoError(t, err, "Error creating scheduled message event: %v", err) assert.NoError(t, err, "Error creating scheduled message event: %v", err)
} }
sent := now.Add(30 * time.Minute) 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) jsonValue, _ := json.Marshal(testReq)
req, _ := http.NewRequest("POST", endpoint.RecordEventResponse, strings.NewReader(string(jsonValue))) 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") assert.NotEmpty(t, response.Data, "No message event response created")
var msgEventResp message.MessageEventResponse var msgEventResp evnt.MessageEventResponse
msgEventResp = *response.Data[0] msgEventResp = *response.Data[0]
assert.NotEmpty(t, msgEventResp.Response, "The response of the message event response is empty") 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") 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")
}
@@ -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) { 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" 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 { if err != nil {
return nil, fmt.Errorf("Error querying: %w", err) return nil, fmt.Errorf("Error querying: %w", err)
} }
@@ -11,7 +11,7 @@ import (
) )
type ScheduledMessageEventKey struct { type ScheduledMessageEventKey struct {
RecipientId uuid.UUID ContactId uuid.UUID
MessageId uuid.UUID MessageId uuid.UUID
ScheduledMessageId 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) copiedEventsKey := make(map[ScheduledMessageEventKey]*scheduling.ScheduledMessageEvent)
for i, schMsgEvent := range m.ScheduledMessageEvents { 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 { if schMsgEvent.Id != id {
copiedEvents[i] = schMsgEvent copiedEvents[i] = schMsgEvent
copiedEventsKey[key] = schMsgEvent copiedEventsKey[key] = schMsgEvent
@@ -132,7 +132,7 @@ func (m *MockScheduledMessageEventStore) CreateScheduledMessageEvent(ctx context
event.Id = uuid.New() 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 { if _, exists := m.ScheduledMessageEventsByKey[key]; exists {
return fmt.Errorf("Already exists") return fmt.Errorf("Already exists")
@@ -152,7 +152,7 @@ func (m *MockScheduledMessageEventStore) Exists(ctx context.Context, event *sche
return false, m.Error 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] _, exists := m.ScheduledMessageEventsByKey[key]
return exists, nil return exists, nil
+7 -5
View File
@@ -36,16 +36,18 @@ func (m *MockMessageStore) CreateMessage(ctx context.Context, msg *message.Messa
return m.Error return m.Error
} }
if msg.Id == uuid.Nil { var id uuid.UUID
msg.Id = uuid.New() 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 { if _, exists := m.MessagesByKey[key]; exists {
return errors.New("Message already exists") return errors.New("Message already exists")
} }
m.Messages[msg.Id] = msg m.Messages[*msg.Id] = msg
m.MessagesByKey[key] = msg m.MessagesByKey[key] = msg
return nil return nil
} }
@@ -88,7 +90,7 @@ func (m *MockMessageStore) MessageExists(ctx context.Context, msg *message.Messa
return false, m.Error 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 return exists, nil
} }