From 4e250d095cf43b350fe84816805b41613ca56404 Mon Sep 17 00:00:00 2001 From: phoenix Date: Tue, 6 Jan 2026 02:40:01 +0000 Subject: [PATCH] tsk-60: Save extra fields to DB for Contact (#66) Closes #60 Reviewed-on: https://git.kundeng.us/phoenix/textsender-api/pulls/66 Co-authored-by: phoenix Co-committed-by: phoenix --- cmd/api/main.go | 12 +++++------ internal/handler/contact.go | 35 ++++++++++++++++----------------- internal/store/contact_store.go | 32 ++++++++++++++---------------- migrations/schema.sql | 5 ++++- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cmd/api/main.go b/cmd/api/main.go index 01c0885..731d263 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -107,12 +107,12 @@ func main() { router.Use(middleware.Timeout(60 * time.Second)) router.Use(mdlware.JSONContentType) - router.Handle(endpoint.ADD_CONTACT_ENDPOINT, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(contactHandler.AddContact))) - router.Handle(endpoint.GET_CONTACT, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(contactHandler.GetContact))) - router.Handle(endpoint.ADD_MESSAGE, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(messageHandler.AddMessage))) - router.Handle(endpoint.GET_MESSAGE, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(messageHandler.GetMessage))) - router.Handle(endpoint.ScheduleMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.AddScheduledMessage))) - router.Handle(endpoint.AddEventToScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageEventHandler.AddScheduledMessageEvent))) + router.Method("POST", endpoint.ADD_CONTACT_ENDPOINT, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(contactHandler.AddContact))) + router.Method("GET", endpoint.GET_CONTACT, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(contactHandler.GetContact))) + router.Method("POST", endpoint.ADD_MESSAGE, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(messageHandler.AddMessage))) + router.Method("GET", endpoint.GET_MESSAGE, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(messageHandler.GetMessage))) + router.Method("POST", endpoint.ScheduleMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageHandler.AddScheduledMessage))) + router.Method("POST", endpoint.AddEventToScheduledMessageEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageEventHandler.AddScheduledMessageEvent))) router.Method("GET", endpoint.GetScheduledMessageEventEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageEventHandler.GetScheduledMessageEvent))) router.Method("DELETE", endpoint.DeleteScheduledMessageEventEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageEventHandler.DeleteScheduledMessageEvent))) router.Method("PATCH", endpoint.UpdateScheduledMessageStatusEndpoint, mdlware.AuthMiddleware(jwtService)(http.HandlerFunc(scheduledMessageStatusHandler.UpdateStatus))) diff --git a/internal/handler/contact.go b/internal/handler/contact.go index bacd14f..bdb6d3e 100644 --- a/internal/handler/contact.go +++ b/internal/handler/contact.go @@ -2,6 +2,7 @@ package handler import ( "fmt" + "log" "net/http" "git.kundeng.us/phoenix/textsender-models/tx0/contact" @@ -11,16 +12,6 @@ import ( "git.kundeng.us/phoenix/textsender-api/internal/store" ) -type RequestAddContact struct { - PhoneNumber string `json:"phone_number"` - UserId uuid.UUID `json:"user_id"` -} - -type AddContactResponse struct { - Message string `json:"message"` - Data []contact.Contact `json:"data"` -} - type ContactHandler struct { App *app.App ContactStore store.ContactStore @@ -30,6 +21,19 @@ func NewContactHandler(apiApp *app.App, str store.ContactStore) *ContactHandler return &ContactHandler{App: apiApp, ContactStore: str} } +type RequestAddContact struct { + PhoneNumber string `json:"phone_number"` + UserId uuid.UUID `json:"user_id"` + Firstname *string `json:"first_name,omitempty"` + Lastname *string `json:"last_name,omitempty"` + Nickname *string `json:"nickname,omitempty"` +} + +type AddContactResponse struct { + Message string `json:"message"` + Data []contact.Contact `json:"data"` +} + // AddContact godoc // @Summary Add contact // @Description Add a contact record to have a recipient to send a text to (requires JWT) @@ -43,18 +47,13 @@ func NewContactHandler(apiApp *app.App, str store.ContactStore) *ContactHandler // @Failure 500 {object} AddContactResponse // @Router /contact/new [post] func (c *ContactHandler) AddContact(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) - return - } - var req RequestAddContact if err := ExtractFromRequest(r, &req); err != nil { http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest) } defer r.Body.Close() - newContact := contact.Contact{PhoneNumber: req.PhoneNumber, UserId: &req.UserId} + newContact := contact.Contact{PhoneNumber: req.PhoneNumber, UserId: &req.UserId, Firstname: req.Firstname, Lastname: req.Lastname, Nickname: req.Nickname} var statusCode int var resp AddContactResponse @@ -62,7 +61,7 @@ func (c *ContactHandler) AddContact(w http.ResponseWriter, r *http.Request) { ctx := r.Context() if exists, err := c.ContactStore.ContactExists(ctx, newContact.PhoneNumber, *newContact.UserId); err != nil { - fmt.Printf("Error: %v", err) + log.Printf("Error: %v", err) statusCode = http.StatusInternalServerError resp.Message = err.Error() } else { @@ -71,7 +70,7 @@ func (c *ContactHandler) AddContact(w http.ResponseWriter, r *http.Request) { resp.Message = "Cannot create contact" } else { if err := c.ContactStore.CreateContact(ctx, &newContact); err != nil { - fmt.Printf("Error: %v", err) + log.Printf("Error: %v", err) statusCode = http.StatusInternalServerError resp.Message = err.Error() } else { diff --git a/internal/store/contact_store.go b/internal/store/contact_store.go index 7e9d72c..31ab41a 100644 --- a/internal/store/contact_store.go +++ b/internal/store/contact_store.go @@ -28,54 +28,52 @@ func NewContactStore(db *pgxpool.Pool) *PGContactStore { func (s *PGContactStore) CreateContact(ctx context.Context, con *contact.Contact) error { query := ` - INSERT INTO contacts (phone_number, user_id) - VALUES ($1, $2) + INSERT INTO contacts (phone_number, user_id, first_name, last_name, nickname) + VALUES ($1, $2, $3, $4, $5) RETURNING id, phone_number, user_id ` - return s.db.QueryRow(ctx, query, con.PhoneNumber, con.UserId).Scan( + return s.db.QueryRow(ctx, query, con.PhoneNumber, con.UserId, con.Firstname, con.Lastname, con.Nickname).Scan( &con.Id, &con.PhoneNumber, &con.UserId, ) } func (s *PGContactStore) GetContactByID(ctx context.Context, id uuid.UUID) (*contact.Contact, error) { - query := `SELECT id, phone_number, user_id FROM contacts WHERE id = $1` + query := `SELECT id, phone_number, user_id, first_name, last_name, nickname FROM contacts WHERE id = $1` var con contact.Contact err := s.db.QueryRow(ctx, query, id).Scan( - &con.Id, &con.PhoneNumber, &con.UserId, + &con.Id, &con.PhoneNumber, &con.UserId, &con.Firstname, &con.Lastname, &con.Nickname, ) if err == pgx.ErrNoRows { return nil, nil - } - if err != nil { + } else if err != nil { return nil, fmt.Errorf("getting contact by ID: %w", err) + } else { + return &con, nil } - - return &con, nil } func (s *PGContactStore) GetContactByPhone(ctx context.Context, phone string, userId uuid.UUID) (*contact.Contact, error) { - query := `SELECT id, phone_number, user_id FROM contacts WHERE phone_number = $1 AND user_id = $2` + query := `SELECT id, phone_number, user_id, first_name, last_name, nickname FROM contacts WHERE phone_number = $1 AND user_id = $2` var con contact.Contact err := s.db.QueryRow(ctx, query, phone, userId).Scan( - &con.Id, &con.PhoneNumber, &con.UserId, + &con.Id, &con.PhoneNumber, &con.UserId, &con.Firstname, &con.Lastname, &con.Nickname, ) if err == pgx.ErrNoRows { return nil, nil - } - if err != nil { + } else if err != nil { return nil, fmt.Errorf("getting contact by phone and User ID: %w", err) + } else { + return &con, nil } - - return &con, nil } func (s *PGContactStore) GetAllContacts(ctx context.Context) ([]*contact.Contact, error) { - query := `SELECT id, phone_number, user_id FROM contacts` + query := `SELECT id, phone_number, user_id, first_name, last_name, nickname FROM contacts` rows, err := s.db.Query(ctx, query) if err != nil { @@ -87,7 +85,7 @@ func (s *PGContactStore) GetAllContacts(ctx context.Context) ([]*contact.Contact for rows.Next() { var con contact.Contact if err := rows.Scan( - &con.Id, &con.PhoneNumber, &con.UserId, + &con.Id, &con.PhoneNumber, &con.UserId, &con.Firstname, &con.Lastname, &con.Nickname, ); err != nil { return nil, fmt.Errorf("scanning contact row: %w", err) } diff --git a/migrations/schema.sql b/migrations/schema.sql index b8d3401..23587c6 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -9,7 +9,10 @@ DROP TABLE IF EXISTS message_event_responses CASCADE; CREATE TABLE IF NOT EXISTS contacts ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), phone_number TEXT NOT NULL, - user_id UUID NOT NULL + user_id UUID NOT NULL, + first_name TEXT NULL, + last_name TEXT NULL, + nickname TEXT NULL ); CREATE TABLE IF NOT EXISTS messages (