Skip to content

Commit 6192b1f

Browse files
authored
Merge pull request #559 from LerianStudio/feature/RPRTR-377
feat: implementing deadlines CRUD
2 parents 3ec6197 + 9fab850 commit 6192b1f

35 files changed

+7187
-82
lines changed

.trivyignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ CVE-2025-58186
88
CVE-2025-58187
99
CVE-2025-58188
1010
CVE-2025-61723
11-
CVE-2025-61724
11+
CVE-2025-61724
12+
CVE-2026-25882
13+
CVE-2026-22184
14+
CVE-2026-27171

components/manager/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ networks:
4343
# Shared network from broader Lerian platform (created by midaz infra)
4444
external: true
4545
reporter-manager-network:
46-
driver: bridge
46+
driver: bridge
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
// Copyright (c) 2026 Lerian Studio. All rights reserved.
2+
// Use of this source code is governed by the Elastic License 2.0
3+
// that can be found in the LICENSE file.
4+
5+
package in
6+
7+
import (
8+
"errors"
9+
10+
"github.com/LerianStudio/reporter/components/manager/internal/services"
11+
"github.com/LerianStudio/reporter/pkg/model"
12+
"github.com/LerianStudio/reporter/pkg/mongodb/deadline"
13+
"github.com/LerianStudio/reporter/pkg/net/http"
14+
15+
"github.com/LerianStudio/lib-commons/v3/commons"
16+
commonsHttp "github.com/LerianStudio/lib-commons/v3/commons/net/http"
17+
libOpentelemetry "github.com/LerianStudio/lib-commons/v3/commons/opentelemetry"
18+
"github.com/gofiber/fiber/v2"
19+
"github.com/google/uuid"
20+
"go.opentelemetry.io/otel/attribute"
21+
)
22+
23+
// DeadlineHandler handles HTTP requests for deadline operations.
24+
type DeadlineHandler struct {
25+
service *services.UseCase
26+
}
27+
28+
// NewDeadlineHandler creates a new DeadlineHandler with the given service dependency.
29+
// It returns an error if service is nil.
30+
func NewDeadlineHandler(service *services.UseCase) (*DeadlineHandler, error) {
31+
if service == nil {
32+
return nil, errors.New("service must not be nil for DeadlineHandler")
33+
}
34+
35+
return &DeadlineHandler{service: service}, nil
36+
}
37+
38+
// CreateDeadline is a method that creates a deadline.
39+
//
40+
// @Summary Create a Deadline
41+
// @Description Create a deadline with the input payload
42+
// @Tags Deadlines
43+
// @Accept json
44+
// @Produce json
45+
// @Security BearerAuth
46+
// @Param body deadline.CreateDeadlineInput true "Deadline input"
47+
// @Success 201 {object} deadline.Deadline
48+
// @Failure 400 {object} http.HTTPError
49+
// @Failure 401 {object} http.HTTPError
50+
// @Failure 403 {object} http.HTTPError
51+
// @Failure 500 {object} http.HTTPError
52+
// @Router /v1/deadlines [post]
53+
func (dh *DeadlineHandler) CreateDeadline(p any, c *fiber.Ctx) error {
54+
ctx := c.UserContext()
55+
logger, tracer, reqId, _ := commons.NewTrackingFromContext(ctx)
56+
57+
ctx, span := tracer.Start(ctx, "handler.deadline.create")
58+
defer span.End()
59+
60+
span.SetAttributes(
61+
attribute.String("app.request.request_id", reqId),
62+
)
63+
64+
logger.Info("Request to create deadline")
65+
66+
input := p.(*deadline.CreateDeadlineInput)
67+
68+
err := libOpentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", input)
69+
if err != nil {
70+
libOpentelemetry.HandleSpanError(&span, "Failed to set span attributes from struct", err)
71+
}
72+
73+
result, err := dh.service.CreateDeadline(ctx, input)
74+
if err != nil {
75+
if http.IsBusinessError(err) {
76+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to create deadline", err)
77+
} else {
78+
libOpentelemetry.HandleSpanError(&span, "Failed to create deadline", err)
79+
}
80+
81+
return http.WithError(c, err)
82+
}
83+
84+
logger.Infof("Successfully created deadline %s", result.ID)
85+
86+
return commonsHttp.Created(c, result)
87+
}
88+
89+
// GetAllDeadlines is a method that retrieves all deadlines.
90+
//
91+
// @Summary Get all deadlines
92+
// @Description List all the deadlines
93+
// @Tags Deadlines
94+
// @Produce json
95+
// @Security BearerAuth
96+
// @Param limit query int false "Limit" default(10)
97+
// @Param page query int false "Page" default(1)
98+
// @Success 200 {object} model.Pagination{items=[]deadline.Deadline,page=int,limit=int,total=int}
99+
// @Failure 400 {object} http.HTTPError
100+
// @Failure 401 {object} http.HTTPError
101+
// @Failure 403 {object} http.HTTPError
102+
// @Failure 500 {object} http.HTTPError
103+
// @Router /v1/deadlines [get]
104+
func (dh *DeadlineHandler) GetAllDeadlines(c *fiber.Ctx) error {
105+
ctx := c.UserContext()
106+
107+
logger, tracer, reqId, _ := commons.NewTrackingFromContext(ctx)
108+
109+
ctx, span := tracer.Start(ctx, "handler.deadline.get_all")
110+
defer span.End()
111+
112+
headerParams, err := http.ValidateParameters(c.Queries())
113+
if err != nil {
114+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to validate query parameters", err)
115+
116+
logger.Errorf("Failed to validate query parameters, Error: %s", err.Error())
117+
118+
return http.WithError(c, err)
119+
}
120+
121+
pagination := model.Pagination{
122+
Limit: headerParams.Limit,
123+
Page: headerParams.Page,
124+
}
125+
126+
logger.Infof("Initiating retrieval of all deadlines")
127+
128+
span.SetAttributes(
129+
attribute.String("app.request.request_id", reqId),
130+
)
131+
132+
err = libOpentelemetry.SetSpanAttributesFromStruct(&span, "app.request.query_params", headerParams)
133+
if err != nil {
134+
libOpentelemetry.HandleSpanError(&span, "Failed to convert query params to JSON string", err)
135+
}
136+
137+
deadlines, total, err := dh.service.GetAllDeadlines(ctx, *headerParams)
138+
if err != nil {
139+
if http.IsBusinessError(err) {
140+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to retrieve all deadlines on query", err)
141+
} else {
142+
libOpentelemetry.HandleSpanError(&span, "Failed to retrieve all deadlines on query", err)
143+
}
144+
145+
logger.Errorf("Failed to retrieve all deadlines, Error: %s", err.Error())
146+
147+
return http.WithError(c, err)
148+
}
149+
150+
logger.Infof("Successfully retrieved all deadlines")
151+
152+
pagination.SetItems(deadlines)
153+
pagination.SetTotal(int(total))
154+
155+
return commonsHttp.OK(c, pagination)
156+
}
157+
158+
// UpdateDeadlineByID is a method that updates a deadline by a given id.
159+
//
160+
// @Summary Update a deadline
161+
// @Description Update a deadline with the input payload
162+
// @Tags Deadlines
163+
// @Accept json
164+
// @Produce json
165+
// @Security BearerAuth
166+
// @Param id path string true "Deadline ID"
167+
// @Param body deadline.UpdateDeadlineInput true "Deadline update input"
168+
// @Success 200 {object} deadline.Deadline
169+
// @Failure 400 {object} http.HTTPError
170+
// @Failure 401 {object} http.HTTPError
171+
// @Failure 403 {object} http.HTTPError
172+
// @Failure 404 {object} http.HTTPError
173+
// @Failure 500 {object} http.HTTPError
174+
// @Router /v1/deadlines/{id} [patch]
175+
func (dh *DeadlineHandler) UpdateDeadlineByID(p any, c *fiber.Ctx) error {
176+
ctx := c.UserContext()
177+
178+
logger, tracer, reqId, _ := commons.NewTrackingFromContext(ctx)
179+
180+
ctx, span := tracer.Start(ctx, "handler.deadline.update")
181+
defer span.End()
182+
183+
raw := c.Locals("id")
184+
185+
id, ok := raw.(uuid.UUID)
186+
if !ok {
187+
return http.WithError(c, fiber.ErrBadRequest)
188+
}
189+
190+
logger.Infof("Initiating update of deadline with ID: %s", id)
191+
192+
span.SetAttributes(
193+
attribute.String("app.request.request_id", reqId),
194+
attribute.String("app.request.deadline_id", id.String()),
195+
)
196+
197+
input := p.(*deadline.UpdateDeadlineInput)
198+
199+
err := libOpentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", input)
200+
if err != nil {
201+
libOpentelemetry.HandleSpanError(&span, "Failed to set span attributes from struct", err)
202+
}
203+
204+
result, errUpdate := dh.service.UpdateDeadlineByID(ctx, id, input)
205+
if errUpdate != nil {
206+
if http.IsBusinessError(errUpdate) {
207+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to update deadline", errUpdate)
208+
} else {
209+
libOpentelemetry.HandleSpanError(&span, "Failed to update deadline", errUpdate)
210+
}
211+
212+
logger.Errorf("Failed to update deadline with ID: %s, Error: %s", id, errUpdate.Error())
213+
214+
return http.WithError(c, errUpdate)
215+
}
216+
217+
logger.Infof("Successfully updated deadline with ID: %s", id)
218+
219+
return commonsHttp.OK(c, result)
220+
}
221+
222+
// DeleteDeadlineByID is a method that removes a deadline by a given id.
223+
//
224+
// @Summary SoftDelete a Deadline by ID
225+
// @Description SoftDelete a deadline with the input ID. Returns 204 with no content on success.
226+
// @Tags Deadlines
227+
// @Produce json
228+
// @Security BearerAuth
229+
// @Param id path string true "Deadline ID"
230+
// @Success 204 "No content"
231+
// @Failure 400 {object} http.HTTPError
232+
// @Failure 401 {object} http.HTTPError
233+
// @Failure 403 {object} http.HTTPError
234+
// @Failure 404 {object} http.HTTPError
235+
// @Failure 500 {object} http.HTTPError
236+
// @Router /v1/deadlines/{id} [delete]
237+
func (dh *DeadlineHandler) DeleteDeadlineByID(c *fiber.Ctx) error {
238+
ctx := c.UserContext()
239+
240+
logger, tracer, reqId, _ := commons.NewTrackingFromContext(ctx)
241+
242+
ctx, span := tracer.Start(ctx, "handler.deadline.delete")
243+
defer span.End()
244+
245+
raw := c.Locals("id")
246+
247+
id, ok := raw.(uuid.UUID)
248+
if !ok {
249+
return http.WithError(c, fiber.ErrBadRequest)
250+
}
251+
252+
logger.Infof("Initiating removal of deadline with ID: %s", id.String())
253+
254+
span.SetAttributes(
255+
attribute.String("app.request.request_id", reqId),
256+
attribute.String("app.request.deadline_id", id.String()),
257+
)
258+
259+
if err := dh.service.DeleteDeadlineByID(ctx, id); err != nil {
260+
if http.IsBusinessError(err) {
261+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to remove deadline on database", err)
262+
} else {
263+
libOpentelemetry.HandleSpanError(&span, "Failed to remove deadline on database", err)
264+
}
265+
266+
logger.Errorf("Failed to remove deadline with ID: %s, Error: %s", id.String(), err.Error())
267+
268+
return http.WithError(c, err)
269+
}
270+
271+
logger.Infof("Successfully removed deadline with ID: %s", id.String())
272+
273+
return commonsHttp.NoContent(c)
274+
}
275+
276+
// DeliverDeadline is a method that marks a deadline as delivered or clears the delivery status.
277+
//
278+
// @Summary Deliver a Deadline
279+
// @Description Mark a deadline as delivered or clear the delivery status
280+
// @Tags Deadlines
281+
// @Accept json
282+
// @Produce json
283+
// @Security BearerAuth
284+
// @Param id path string true "Deadline ID"
285+
// @Param body deadline.DeliverDeadlineInput true "Deliver input"
286+
// @Success 200 {object} deadline.Deadline
287+
// @Failure 400 {object} http.HTTPError
288+
// @Failure 401 {object} http.HTTPError
289+
// @Failure 403 {object} http.HTTPError
290+
// @Failure 404 {object} http.HTTPError
291+
// @Failure 500 {object} http.HTTPError
292+
// @Router /v1/deadlines/{id}/deliver [patch]
293+
func (dh *DeadlineHandler) DeliverDeadline(p any, c *fiber.Ctx) error {
294+
ctx := c.UserContext()
295+
296+
logger, tracer, reqId, _ := commons.NewTrackingFromContext(ctx)
297+
298+
ctx, span := tracer.Start(ctx, "handler.deadline.deliver")
299+
defer span.End()
300+
301+
raw := c.Locals("id")
302+
303+
id, ok := raw.(uuid.UUID)
304+
if !ok {
305+
return http.WithError(c, fiber.ErrBadRequest)
306+
}
307+
308+
logger.Infof("Initiating deliver of deadline with ID: %s", id)
309+
310+
span.SetAttributes(
311+
attribute.String("app.request.request_id", reqId),
312+
attribute.String("app.request.deadline_id", id.String()),
313+
)
314+
315+
input := p.(*deadline.DeliverDeadlineInput)
316+
317+
err := libOpentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", input)
318+
if err != nil {
319+
libOpentelemetry.HandleSpanError(&span, "Failed to set span attributes from struct", err)
320+
}
321+
322+
result, errDeliver := dh.service.DeliverDeadline(ctx, id, input)
323+
if errDeliver != nil {
324+
if http.IsBusinessError(errDeliver) {
325+
libOpentelemetry.HandleSpanBusinessErrorEvent(&span, "Failed to deliver deadline", errDeliver)
326+
} else {
327+
libOpentelemetry.HandleSpanError(&span, "Failed to deliver deadline", errDeliver)
328+
}
329+
330+
logger.Errorf("Failed to deliver deadline with ID: %s, Error: %s", id, errDeliver.Error())
331+
332+
return http.WithError(c, errDeliver)
333+
}
334+
335+
logger.Infof("Successfully delivered deadline with ID: %s", id)
336+
337+
return commonsHttp.OK(c, result)
338+
}

0 commit comments

Comments
 (0)