tsk-58: Update names of Contact endpoint (#67)
Closes #58 Reviewed-on: phoenix/textsender-api#67 Co-authored-by: phoenix <kundeng00@pm.me> Co-committed-by: phoenix <kundeng00@pm.me>
This commit is contained in:
@@ -179,3 +179,68 @@ func (c *ContactHandler) GetContact(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
RespondWithJSON(w, statusCode, &resp)
|
||||
}
|
||||
|
||||
type UpdateNameRequest struct {
|
||||
Nickname *string `json:"nickname,omitempty"`
|
||||
Firstname *string `json:"first_name,omitempty"`
|
||||
Lastname *string `json:"last_name,omitempty"`
|
||||
ContactId uuid.UUID `json:"contact_id"`
|
||||
UserId uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
type UpdateNameResponse struct {
|
||||
Message string `json:"message"`
|
||||
Data []contact.Contact `json:"data"`
|
||||
}
|
||||
|
||||
// UpdateName godoc
|
||||
// @Summary Update names of Contact
|
||||
// @Description Update the first, last, or nickname of a Contact (requires JWT)
|
||||
// @Tags contacts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param request body UpdateNameRequest true "Data to update contact's names"
|
||||
// @Success 200 {object} UpdateNameResponse
|
||||
// @Failure 400 {object} UpdateNameResponse
|
||||
// @Failure 500 {object} UpdateNameResponse
|
||||
// @Router /contact/update [patch]
|
||||
func (c *ContactHandler) UpdateName(w http.ResponseWriter, r *http.Request) {
|
||||
var req UpdateNameRequest
|
||||
if err := ExtractFromRequest(r, &req); err != nil {
|
||||
http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
var statusCode int
|
||||
var resp UpdateNameResponse
|
||||
|
||||
if req.UserId == uuid.Nil {
|
||||
statusCode = http.StatusBadRequest
|
||||
resp.Message = "User Id not provided"
|
||||
} else if req.ContactId == uuid.Nil {
|
||||
statusCode = http.StatusBadRequest
|
||||
resp.Message = "Contact Id not provided"
|
||||
} else if req.Firstname == nil && req.Lastname == nil && req.Nickname == nil {
|
||||
statusCode = http.StatusBadRequest
|
||||
resp.Message = "No name provided"
|
||||
} else {
|
||||
ctx := r.Context()
|
||||
if con, err := c.ContactStore.GetContactByID(ctx, req.ContactId); err != nil {
|
||||
resp.Message = err.Error()
|
||||
statusCode = http.StatusInternalServerError
|
||||
} else {
|
||||
if affectedRows, err := c.ContactStore.UpdateNames(ctx, con, req.Firstname, req.Lastname, req.Nickname); err != nil {
|
||||
statusCode = http.StatusInternalServerError
|
||||
resp.Message = err.Error()
|
||||
} else {
|
||||
log.Println("Updated", affectedRows, "rows")
|
||||
statusCode = http.StatusOK
|
||||
resp.Message = "Successful"
|
||||
resp.Data = append(resp.Data, *con)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RespondWithJSON(w, statusCode, &resp)
|
||||
}
|
||||
|
||||
@@ -78,3 +78,46 @@ func TestGetContactWithMock(t *testing.T) {
|
||||
|
||||
assert.NotNil(t, response.Data[0].Id, "Id should not be nil")
|
||||
}
|
||||
|
||||
func TestUpdateContactNamesWithMock(t *testing.T) {
|
||||
mockstore := mock.NewMockContactStore()
|
||||
testUserId := uuid.New()
|
||||
|
||||
testCon := contact.Contact{PhoneNumber: "+12335403383", UserId: &testUserId}
|
||||
ctx := t.Context()
|
||||
var firstname, lastname, nickname string
|
||||
firstname = "Bob"
|
||||
lastname = "De-Buildor"
|
||||
nickname = "With The Tool"
|
||||
if err := mockstore.CreateContact(ctx, &testCon); err != nil {
|
||||
assert.NoError(t, err, "Error creating contact")
|
||||
return
|
||||
}
|
||||
|
||||
var requestBody UpdateNameRequest
|
||||
requestBody.Firstname = &firstname
|
||||
requestBody.Lastname = &lastname
|
||||
requestBody.Nickname = &nickname
|
||||
requestBody.ContactId = *testCon.Id
|
||||
requestBody.UserId = testUserId
|
||||
jsonValue, _ := json.Marshal(requestBody)
|
||||
req, _ := http.NewRequest("PATCH", endpoint.Update_Names_Endpoint, strings.NewReader(string(jsonValue)))
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
apiApp, err := GetApp()
|
||||
assert.NoError(t, err, "Error getting app")
|
||||
contactHandler := NewContactHandler(apiApp, mockstore)
|
||||
contactHandler.UpdateName(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rr.Code)
|
||||
|
||||
var response UpdateNameResponse
|
||||
err = json.Unmarshal(rr.Body.Bytes(), &response)
|
||||
assert.NoError(t, err, "Error updating names of contact %v", err)
|
||||
|
||||
assert.NotEmpty(t, response.Data, "No Contact updated")
|
||||
|
||||
assert.NotNil(t, response.Data[0].Firstname, "Firstname should not be nil")
|
||||
assert.NotNil(t, response.Data[0].Lastname, "Lastname should not be nil")
|
||||
assert.NotNil(t, response.Data[0].Nickname, "Nickname should not be nil")
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ const (
|
||||
ADD_MESSAGE = "/api/v1/message/new"
|
||||
GET_MESSAGE = "/api/v1/message"
|
||||
|
||||
GET_CONTACT = "/api/v1/contact"
|
||||
ADD_CONTACT_ENDPOINT = "/api/v1/contact/new"
|
||||
GET_CONTACT = "/api/v1/contact"
|
||||
ADD_CONTACT_ENDPOINT = "/api/v1/contact/new"
|
||||
Update_Names_Endpoint = "/api/v1/contact/update"
|
||||
|
||||
ScheduleMessageEndpoint = "/api/v1/schedule/message"
|
||||
GetScheduledMessageEndpoint = "/api/v1/schedule/message"
|
||||
|
||||
@@ -16,11 +16,6 @@ import (
|
||||
"git.kundeng.us/phoenix/textsender-api/internal/store/mock"
|
||||
)
|
||||
|
||||
type CreateMessageRequest struct {
|
||||
Content string `json:"content"`
|
||||
UserId uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func TestCreateMessageWithMock(t *testing.T) {
|
||||
mockStore := mock.NewMockMessageStore()
|
||||
apiApp, err := GetApp()
|
||||
@@ -28,7 +23,7 @@ func TestCreateMessageWithMock(t *testing.T) {
|
||||
handler := NewMessageHandler(apiApp, mockStore)
|
||||
|
||||
testUserId := uuid.New()
|
||||
testBody := CreateMessageRequest{Content: "Who could tell?", UserId: testUserId}
|
||||
testBody := RequestAddMessage{Content: "Who could tell?", UserId: testUserId}
|
||||
jsonValue, _ := json.Marshal(testBody)
|
||||
|
||||
req, _ := http.NewRequest("POST", endpoint.ADD_MESSAGE, strings.NewReader(string(jsonValue)))
|
||||
|
||||
@@ -16,6 +16,7 @@ type ContactStore interface {
|
||||
GetContactByPhone(ctx context.Context, phone string, userId uuid.UUID) (*contact.Contact, error)
|
||||
GetAllContacts(ctx context.Context) ([]*contact.Contact, error)
|
||||
ContactExists(ctx context.Context, phone string, userId uuid.UUID) (bool, error)
|
||||
UpdateNames(ctx context.Context, con *contact.Contact, firstname *string, lastname *string, nickname *string) (int64, error)
|
||||
}
|
||||
|
||||
type PGContactStore struct {
|
||||
@@ -110,3 +111,72 @@ func (s *PGContactStore) ContactExists(ctx context.Context, phone string, userId
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (s *PGContactStore) UpdateNames(ctx context.Context, con *contact.Contact, firstname *string, lastname *string, nickname *string) (int64, error) {
|
||||
if firstname == nil && lastname == nil && nickname == nil {
|
||||
return 0, fmt.Errorf("Names are nil")
|
||||
} else {
|
||||
if firstname != nil && lastname != nil && nickname != nil {
|
||||
query := "UPDATE contacts SET first_name = $1, last_name = $2, nickname = $3 WHERE id = $4"
|
||||
if affected, err := s.db.Exec(ctx, query, firstname, lastname, nickname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Firstname = firstname
|
||||
con.Lastname = lastname
|
||||
con.Nickname = nickname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else if firstname != nil && lastname != nil {
|
||||
query := "UPDATE contacts SET first_name = $1, last_name = $2 WHERE id = $3"
|
||||
if affected, err := s.db.Exec(ctx, query, firstname, lastname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Firstname = firstname
|
||||
con.Lastname = lastname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else if lastname != nil && nickname != nil {
|
||||
query := "UPDATE contacts SET last_name = $1, nickname = $2 WHERE id = $3"
|
||||
if affected, err := s.db.Exec(ctx, query, lastname, nickname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Lastname = lastname
|
||||
con.Nickname = nickname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else if nickname != nil && firstname != nil {
|
||||
query := "UPDATE contacts SET nickname = $1, firstname = $2 WHERE id = $3"
|
||||
if affected, err := s.db.Exec(ctx, query, nickname, firstname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Firstname = firstname
|
||||
con.Nickname = nickname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else if firstname != nil {
|
||||
query := "UPDATE contacts SET firstname = $1 WHERE id = $2"
|
||||
if affected, err := s.db.Exec(ctx, query, firstname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Firstname = firstname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else if lastname != nil {
|
||||
query := "UPDATE contacts SET lastname = $1 WHERE id = $2"
|
||||
if affected, err := s.db.Exec(ctx, query, lastname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Lastname = lastname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
} else {
|
||||
query := "UPDATE contacts SET nickname = $1 WHERE id = $2"
|
||||
if affected, err := s.db.Exec(ctx, query, nickname, con.Id); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
con.Nickname = nickname
|
||||
return affected.RowsAffected(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package mock
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"git.kundeng.us/phoenix/textsender-models/tx0/contact"
|
||||
@@ -116,3 +117,30 @@ func (m *MockContactStore) ContactExists(ctx context.Context, phoneNumber string
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (m *MockContactStore) UpdateNames(ctx context.Context, con *contact.Contact, firstname *string, lastname *string, nickname *string) (int64, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if m.Error != nil {
|
||||
return 0, m.Error
|
||||
} else if firstname == nil && lastname == nil && nickname == nil {
|
||||
return 0, fmt.Errorf("Names are not provided")
|
||||
} else {
|
||||
if c, exists := m.Contacts[*con.Id]; !exists {
|
||||
return 0, fmt.Errorf("Contact does not exist")
|
||||
} else {
|
||||
if firstname != nil {
|
||||
c.Firstname = firstname
|
||||
}
|
||||
if lastname != nil {
|
||||
c.Lastname = lastname
|
||||
}
|
||||
if nickname != nil {
|
||||
c.Nickname = nickname
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user