tsk-8: Create Message endpoint (#15)
Closes #8 Reviewed-on: phoenix/textsender-api#15 Co-authored-by: phoenix <kundeng00@pm.me> Co-committed-by: phoenix <kundeng00@pm.me>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
package endpoint
|
||||
|
||||
const MESSAGE_DRAFT_ENDPOINT = "/api/v1/message/draft"
|
||||
const ADD_MESSAGE = "/api/v1/message/new"
|
||||
const ADD_CONTACT_ENDPOINT = "/api/v1/contact"
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"git.kundeng.us/phoenix/textsender-api/internal/store"
|
||||
"git.kundeng.us/phoenix/textsender-models/pkg/message"
|
||||
)
|
||||
|
||||
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 {
|
||||
MessageStore store.MessageStore
|
||||
}
|
||||
|
||||
func NewMessageHandler(str store.MessageStore) *MessageHandler {
|
||||
return &MessageHandler{MessageStore: str}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
newMessage := message.Message{Content: req.Content, UserId: req.UserId}
|
||||
|
||||
var statusCode int
|
||||
var resp AddMessageResponse
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
if exists, err := m.MessageStore.MessageExists(ctx, &newMessage); err != nil {
|
||||
fmt.Println("Error: ", err)
|
||||
statusCode = http.StatusInternalServerError
|
||||
resp.Message = err.Error()
|
||||
} else {
|
||||
if exists {
|
||||
statusCode = http.StatusBadRequest
|
||||
resp.Message = "Cannot create message"
|
||||
} else {
|
||||
if err = m.MessageStore.CreateMessage(ctx, &newMessage); err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
statusCode = http.StatusInternalServerError
|
||||
resp.Message = err.Error()
|
||||
} else {
|
||||
statusCode = http.StatusCreated
|
||||
resp.Message = "Message created"
|
||||
resp.Data = append(resp.Data, newMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RespondWithJSON(w, statusCode, &resp)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"git.kundeng.us/phoenix/textsender-api/internal/handler/endpoint"
|
||||
)
|
||||
|
||||
type CreateMessageRequest struct {
|
||||
Content string `json:"content"`
|
||||
UserId uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func TestCreateMessageWithMock(t *testing.T) {
|
||||
mockStore := NewMockMessageStore()
|
||||
handler := NewMessageHandler(mockStore)
|
||||
|
||||
testUserId := uuid.New()
|
||||
testBody := CreateMessageRequest{Content: "Who could tell?", UserId: testUserId}
|
||||
jsonValue, _ := json.Marshal(testBody)
|
||||
|
||||
req, _ := http.NewRequest("POST", endpoint.ADD_MESSAGE, strings.NewReader(string(jsonValue)))
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handler.AddMessage(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusCreated, rr.Code)
|
||||
|
||||
var response AddMessageResponse
|
||||
err := json.Unmarshal(rr.Body.Bytes(), &response)
|
||||
assert.NoError(t, err, "Error Creating message %v", err)
|
||||
|
||||
assert.NotEmpty(t, response.Data, "No Message created")
|
||||
|
||||
assert.NotNil(t, response.Data[0].Id, "Id should not be nil")
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
|
||||
"git.kundeng.us/phoenix/textsender-models/pkg/contact"
|
||||
"git.kundeng.us/phoenix/textsender-models/pkg/message"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
@@ -115,3 +116,57 @@ func (m *MockContactStore) ContactExists(ctx context.Context, phoneNumber string
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
type MessageKey struct {
|
||||
Content string
|
||||
UserId uuid.UUID
|
||||
}
|
||||
|
||||
type MockMessageStore struct {
|
||||
Messages map[uuid.UUID]*message.Message
|
||||
MessagesByKey map[MessageKey]*message.Message
|
||||
mu sync.RWMutex
|
||||
Error error // Optional: simulate errors
|
||||
}
|
||||
|
||||
func NewMockMessageStore() *MockMessageStore {
|
||||
return &MockMessageStore{
|
||||
Messages: make(map[uuid.UUID]*message.Message),
|
||||
MessagesByKey: make(map[MessageKey]*message.Message),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockMessageStore) CreateMessage(ctx context.Context, msg *message.Message) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if m.Error != nil {
|
||||
return m.Error
|
||||
}
|
||||
|
||||
if msg.Id == uuid.Nil {
|
||||
msg.Id = uuid.New()
|
||||
}
|
||||
|
||||
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.MessagesByKey[key] = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockMessageStore) MessageExists(ctx context.Context, msg *message.Message) (bool, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if m.Error != nil {
|
||||
return false, m.Error
|
||||
}
|
||||
|
||||
_, exists := m.MessagesByKey[MessageKey{Content: msg.Content, UserId: msg.UserId}]
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user