Skip to content

Commit 2bdd031

Browse files
committed
Add api to archive messages
1 parent ae71763 commit 2bdd031

9 files changed

Lines changed: 133 additions & 11 deletions

api/pkg/entities/message_thread.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ func (thread *MessageThread) Update(timestamp time.Time, messageID uuid.UUID, co
2828
thread.LastMessageContent = content
2929
return thread
3030
}
31+
32+
// UpdateArchive sets a message thread as archived
33+
func (thread *MessageThread) UpdateArchive(isArchived bool) *MessageThread {
34+
thread.IsArchived = isArchived
35+
return thread
36+
}

api/pkg/handlers/message_handler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (h *MessageHandler) PostSend(c *fiber.Ctx) error {
7777
return h.responseBadRequest(c, err)
7878
}
7979

80-
if errors := h.validator.ValidateMessageSend(ctx, request); len(errors) != 0 {
80+
if errors := h.validator.ValidateMessageSend(ctx, request.Sanitize()); len(errors) != 0 {
8181
msg := fmt.Sprintf("validation errors [%s], while sending payload [%s]", spew.Sdump(errors), c.Body())
8282
ctxLogger.Warn(stacktrace.NewError(msg))
8383
return h.responseUnprocessableEntity(c, errors, "validation errors while sending message")
@@ -269,7 +269,7 @@ func (h *MessageHandler) PostReceive(c *fiber.Ctx) error {
269269
return h.responseBadRequest(c, err)
270270
}
271271

272-
if errors := h.validator.ValidateMessageReceive(ctx, request); len(errors) != 0 {
272+
if errors := h.validator.ValidateMessageReceive(ctx, request.Sanitize()); len(errors) != 0 {
273273
msg := fmt.Sprintf("validation errors [%s], while sending payload [%s]", spew.Sdump(errors), c.Body())
274274
ctxLogger.Warn(stacktrace.NewError(msg))
275275
return h.responseUnprocessableEntity(c, errors, "validation errors while receiving message")

api/pkg/handlers/message_thread_handler.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func NewMessageThreadHandler(
3939
// RegisterRoutes registers the routes for the MessageHandler
4040
func (h *MessageThreadHandler) RegisterRoutes(router fiber.Router) {
4141
router.Get("/message-threads", h.Index)
42+
router.Put("/message-threads/:messageThreadID", h.Update)
4243
}
4344

4445
// Index returns message threads for a phone number
@@ -88,3 +89,46 @@ func (h *MessageThreadHandler) Index(c *fiber.Ctx) error {
8889

8990
return h.responseOK(c, fmt.Sprintf("fetched %d message %s", len(*threads), h.pluralize("thread", len(*threads))), threads)
9091
}
92+
93+
// Update an entities.MessageThread
94+
// @Summary Update a message thread
95+
// @Description Updates the details of a message thread
96+
// @Security ApiKeyAuth
97+
// @Tags Message Threads
98+
// @Accept json
99+
// @Produce json
100+
// @Param payload body requests.MessageThreadUpdate true "Payload of message thread details to update"
101+
// @Success 200 {object} responses.PhoneResponse
102+
// @Failure 400 {object} responses.BadRequest
103+
// @Failure 401 {object} responses.Unauthorized
104+
// @Failure 422 {object} responses.UnprocessableEntity
105+
// @Failure 500 {object} responses.InternalServerError
106+
// @Router /message-threads/{messageThreadID} [put]
107+
func (h *MessageThreadHandler) Update(c *fiber.Ctx) error {
108+
ctx, span := h.tracer.StartFromFiberCtx(c)
109+
defer span.End()
110+
111+
ctxLogger := h.tracer.CtxLogger(h.logger, span)
112+
113+
var request requests.MessageThreadUpdate
114+
if err := c.BodyParser(&request); err != nil {
115+
msg := fmt.Sprintf("cannot marshall params [%s] into %T", c.OriginalURL(), request)
116+
ctxLogger.Warn(stacktrace.Propagate(err, msg))
117+
return h.responseBadRequest(c, err)
118+
}
119+
120+
if errors := h.validator.ValidateUpdate(ctx, request); len(errors) != 0 {
121+
msg := fmt.Sprintf("validation errors [%s], while updating message thread [%+#v]", spew.Sdump(errors), request)
122+
ctxLogger.Warn(stacktrace.NewError(msg))
123+
return h.responseUnprocessableEntity(c, errors, "validation errors while updating message thread")
124+
}
125+
126+
thread, err := h.service.UpdateStatus(ctx, request.ToUpdateParams())
127+
if err != nil {
128+
msg := fmt.Sprintf("cannot update message thread with params [%+#v]", request)
129+
ctxLogger.Error(stacktrace.Propagate(err, msg))
130+
return h.responseInternalServerError(c)
131+
}
132+
133+
return h.responseOK(c, "message thread updated successfully", thread)
134+
}

api/pkg/handlers/user_handler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (h *UserHandler) Show(c *fiber.Ctx) error {
7878
// @Summary Update a user
7979
// @Description Updates the details of the currently authenticated user
8080
// @Security ApiKeyAuth
81-
// @Tags Phones
81+
// @Tags Users
8282
// @Accept json
8383
// @Produce json
8484
// @Param payload body requests.UserUpdate true "Payload of user details to update"
@@ -104,7 +104,7 @@ func (h *UserHandler) Update(c *fiber.Ctx) error {
104104
if errors := h.validator.ValidateUpdate(ctx, request.Sanitize()); len(errors) != 0 {
105105
msg := fmt.Sprintf("validation errors [%s], while updating user [%+#v]", spew.Sdump(errors), request)
106106
ctxLogger.Warn(stacktrace.NewError(msg))
107-
return h.responseUnprocessableEntity(c, errors, "validation errors while fetching phones")
107+
return h.responseUnprocessableEntity(c, errors, "validation errors while updating user")
108108
}
109109

110110
user, err := h.service.Update(ctx, h.userFromContext(c), request.ToUpdateParams())

api/pkg/repositories/gorm_message_thread_repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (repository *gormMessageThreadRepository) Update(ctx context.Context, threa
6060
}
6161

6262
// Load a thread between 2 users
63-
func (repository *gormMessageThreadRepository) Load(ctx context.Context, owner string, contact string) (*entities.MessageThread, error) {
63+
func (repository *gormMessageThreadRepository) LoadByOwnerContact(ctx context.Context, owner string, contact string) (*entities.MessageThread, error) {
6464
ctx, span := repository.tracer.Start(ctx)
6565
defer span.End()
6666

api/pkg/repositories/message_thread_repository.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package repositories
33
import (
44
"context"
55

6+
"github.com/google/uuid"
7+
68
"github.com/NdoleStudio/http-sms-manager/pkg/entities"
79
)
810

@@ -14,9 +16,12 @@ type MessageThreadRepository interface {
1416
// Update a new entities.MessageThread
1517
Update(ctx context.Context, thread *entities.MessageThread) error
1618

17-
// Load a thread between 2 users
18-
Load(ctx context.Context, owner string, contact string) (*entities.MessageThread, error)
19+
// LoadByOwnerContact fetches a thread between owner and contact
20+
LoadByOwnerContact(ctx context.Context, owner string, contact string) (*entities.MessageThread, error)
21+
22+
// Load a thread by ID
23+
Load(ctx context.Context, ID uuid.UUID) (*entities.MessageThread, error)
1924

2025
// Index message threads for an owner
21-
Index(ctx context.Context, owner string, params IndexParams) (*[]entities.MessageThread, error)
26+
Index(ctx context.Context, owner string, archived bool, params IndexParams) (*[]entities.MessageThread, error)
2227
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package requests
2+
3+
import (
4+
"github.com/google/uuid"
5+
6+
"github.com/NdoleStudio/http-sms-manager/pkg/services"
7+
)
8+
9+
// MessageThreadUpdate is the payload for updating a message thread
10+
type MessageThreadUpdate struct {
11+
request
12+
IsArchived bool `json:"is_archived" example:"true"`
13+
14+
MessageThreadID string `json:"messageThreadID" swaggerignore:"true"` // used internally for validation
15+
}
16+
17+
// ToUpdateParams converts MessageThreadUpdate to services.MessageThreadStatusParams
18+
func (input *MessageThreadUpdate) ToUpdateParams() services.MessageThreadStatusParams {
19+
return services.MessageThreadStatusParams{
20+
MessageThreadID: uuid.MustParse(input.MessageThreadID),
21+
IsArchived: input.IsArchived,
22+
}
23+
}

api/pkg/services/message_thread_service.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (service *MessageThreadService) UpdateThread(ctx context.Context, params Me
4949

5050
ctxLogger := service.tracer.CtxLogger(service.logger, span)
5151

52-
thread, err := service.repository.Load(ctx, params.Owner, params.Contact)
52+
thread, err := service.repository.LoadByOwnerContact(ctx, params.Owner, params.Contact)
5353
if err != nil && stacktrace.GetCode(err) == repositories.ErrCodeNotFound {
5454
ctxLogger.Info(fmt.Sprintf("cannot find thread with owner [%s], and contact [%s]. creating new thread", params.Owner, params.Contact))
5555
return service.createThread(ctx, params)
@@ -74,6 +74,34 @@ func (service *MessageThreadService) UpdateThread(ctx context.Context, params Me
7474
return nil
7575
}
7676

77+
// MessageThreadStatusParams are parameters for updating a thread status
78+
type MessageThreadStatusParams struct {
79+
IsArchived bool
80+
MessageThreadID uuid.UUID
81+
}
82+
83+
// UpdateStatus updates a thread between an owner and a contact
84+
func (service *MessageThreadService) UpdateStatus(ctx context.Context, params MessageThreadStatusParams) (*entities.MessageThread, error) {
85+
ctx, span := service.tracer.Start(ctx)
86+
defer span.End()
87+
88+
ctxLogger := service.tracer.CtxLogger(service.logger, span)
89+
90+
thread, err := service.repository.Load(ctx, params.MessageThreadID)
91+
if err != nil {
92+
msg := fmt.Sprintf("cannot find thread with id [%s]", params.MessageThreadID)
93+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
94+
}
95+
96+
if err = service.repository.Update(ctx, thread.UpdateArchive(params.IsArchived)); err != nil {
97+
msg := fmt.Sprintf("cannot update message thread with id [%s] with archive status [%t]", thread.ID, params.IsArchived)
98+
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))
99+
}
100+
101+
ctxLogger.Info(fmt.Sprintf("thread with id [%s] updated with archive status [%t]", thread.ID, thread.IsArchived))
102+
return thread, nil
103+
}
104+
77105
func (service *MessageThreadService) createThread(ctx context.Context, params MessageThreadUpdateParams) error {
78106
ctx, span := service.tracer.Start(ctx)
79107
defer span.End()
@@ -134,7 +162,8 @@ func (service *MessageThreadService) getColor() string {
134162
// MessageThreadGetParams parameters fetching threads
135163
type MessageThreadGetParams struct {
136164
repositories.IndexParams
137-
Owner string
165+
IsArchived bool
166+
Owner string
138167
}
139168

140169
// GetThreads fetches threads for an owner
@@ -144,7 +173,7 @@ func (service *MessageThreadService) GetThreads(ctx context.Context, params Mess
144173

145174
ctxLogger := service.tracer.CtxLogger(service.logger, span)
146175

147-
threads, err := service.repository.Index(ctx, params.Owner, params.IndexParams)
176+
threads, err := service.repository.Index(ctx, params.Owner, params.IsArchived, params.IndexParams)
148177
if err != nil {
149178
msg := fmt.Sprintf("could not fetch messages threads for params [%+#v]", params)
150179
return nil, service.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, msg))

api/pkg/validators/message_thread_handler_validator.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,18 @@ func (validator *MessageThreadHandlerValidator) ValidateMessageThreadIndex(_ con
5555
})
5656
return v.ValidateStruct()
5757
}
58+
59+
// ValidateUpdate validates requests.UserUpdate
60+
func (validator *MessageThreadHandlerValidator) ValidateUpdate(_ context.Context, request requests.MessageThreadUpdate) url.Values {
61+
v := govalidator.New(govalidator.Options{
62+
Data: &request,
63+
Rules: govalidator.MapData{
64+
"messageThreadID": []string{
65+
"required",
66+
"uuid",
67+
},
68+
},
69+
})
70+
71+
return v.ValidateStruct()
72+
}

0 commit comments

Comments
 (0)