mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-28 17:31:58 +08:00

* feat: adds server and handler changes Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * feat: add tracefunnel module and handler Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * feat: add required types for tracefunnels Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * feat: db operations, module and handler implementation Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * feat: add db migrations Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: add utility functions Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * test: add utility function tests Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * test: add handler tests Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * test: add trace funnel module tests Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: refactor handler and utils Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: add funnel validation while processing funnel steps Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * test: add more tests to utils Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: fix package naming Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: fix naming convention Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: update normalize funnel steps Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: added some improvements Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: optimize funnel creation by combining insert and update operations Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * chore: fix error handling Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * feat: trace funnel state management Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: updated unit tests and mocks Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: review comments Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: minor fixes Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: update funnel migration number Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: review comments and some changes Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> * fix: update modules Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com> --------- Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com>
236 lines
6.0 KiB
Go
236 lines
6.0 KiB
Go
package impltracefunnel
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/SigNoz/signoz/pkg/errors"
|
|
"github.com/SigNoz/signoz/pkg/http/render"
|
|
"github.com/SigNoz/signoz/pkg/modules/tracefunnel"
|
|
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
|
tf "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
|
|
"github.com/SigNoz/signoz/pkg/valuer"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
type handler struct {
|
|
module tracefunnel.Module
|
|
}
|
|
|
|
func NewHandler(module tracefunnel.Module) tracefunnel.Handler {
|
|
return &handler{module: module}
|
|
}
|
|
|
|
func (handler *handler) New(rw http.ResponseWriter, r *http.Request) {
|
|
var req tf.PostableFunnel
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
funnel, err := handler.module.Create(r.Context(), req.Timestamp, req.Name, valuer.MustNewUUID(claims.UserID), valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to create funnel: %v", err))
|
|
return
|
|
}
|
|
|
|
response := tf.ConstructFunnelResponse(funnel, &claims)
|
|
render.Success(rw, http.StatusOK, response)
|
|
}
|
|
|
|
func (handler *handler) UpdateSteps(rw http.ResponseWriter, r *http.Request) {
|
|
var req tf.PostableFunnel
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
updatedAt, err := tf.ValidateAndConvertTimestamp(req.Timestamp)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
funnel, err := handler.module.Get(r.Context(), req.FunnelID, valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"funnel not found: %v", err))
|
|
return
|
|
}
|
|
|
|
steps, err := tf.ProcessFunnelSteps(req.Steps)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
funnel.Steps = steps
|
|
funnel.UpdatedAt = updatedAt
|
|
funnel.UpdatedBy = claims.UserID
|
|
|
|
if req.Name != "" {
|
|
funnel.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
funnel.Description = req.Description
|
|
}
|
|
|
|
if err := handler.module.Update(r.Context(), funnel, valuer.MustNewUUID(claims.UserID)); err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to update funnel in database: %v", err))
|
|
return
|
|
}
|
|
|
|
updatedFunnel, err := handler.module.Get(r.Context(), funnel.ID, valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to get updated funnel: %v", err))
|
|
return
|
|
}
|
|
|
|
response := tf.ConstructFunnelResponse(updatedFunnel, &claims)
|
|
render.Success(rw, http.StatusOK, response)
|
|
}
|
|
|
|
func (handler *handler) UpdateFunnel(rw http.ResponseWriter, r *http.Request) {
|
|
var req tf.PostableFunnel
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
updatedAt, err := tf.ValidateAndConvertTimestamp(req.Timestamp)
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
funnelID := vars["funnel_id"]
|
|
|
|
funnel, err := handler.module.Get(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"funnel not found: %v", err))
|
|
return
|
|
}
|
|
|
|
funnel.UpdatedAt = updatedAt
|
|
funnel.UpdatedBy = claims.UserID
|
|
|
|
if req.Name != "" {
|
|
funnel.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
funnel.Description = req.Description
|
|
}
|
|
|
|
if err := handler.module.Update(r.Context(), funnel, valuer.MustNewUUID(claims.UserID)); err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to update funnel in database: %v", err))
|
|
return
|
|
}
|
|
|
|
updatedFunnel, err := handler.module.Get(r.Context(), funnel.ID, valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to get updated funnel: %v", err))
|
|
return
|
|
}
|
|
|
|
response := tf.ConstructFunnelResponse(updatedFunnel, &claims)
|
|
render.Success(rw, http.StatusOK, response)
|
|
}
|
|
|
|
func (handler *handler) List(rw http.ResponseWriter, r *http.Request) {
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
funnels, err := handler.module.List(r.Context(), valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to list funnels: %v", err))
|
|
return
|
|
}
|
|
|
|
var response []tf.GettableFunnel
|
|
for _, f := range funnels {
|
|
response = append(response, tf.ConstructFunnelResponse(f, &claims))
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, response)
|
|
}
|
|
|
|
func (handler *handler) Get(rw http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
funnelID := vars["funnel_id"]
|
|
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
funnel, err := handler.module.Get(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID))
|
|
if err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"funnel not found: %v", err))
|
|
return
|
|
}
|
|
response := tf.ConstructFunnelResponse(funnel, &claims)
|
|
render.Success(rw, http.StatusOK, response)
|
|
}
|
|
|
|
func (handler *handler) Delete(rw http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
funnelID := vars["funnel_id"]
|
|
|
|
claims, err := authtypes.ClaimsFromContext(r.Context())
|
|
|
|
if err != nil {
|
|
render.Error(rw, err)
|
|
return
|
|
}
|
|
|
|
if err := handler.module.Delete(r.Context(), valuer.MustNewUUID(funnelID), valuer.MustNewUUID(claims.OrgID)); err != nil {
|
|
render.Error(rw, errors.Newf(errors.TypeInvalidInput,
|
|
errors.CodeInvalidInput,
|
|
"failed to delete funnel: %v", err))
|
|
return
|
|
}
|
|
|
|
render.Success(rw, http.StatusOK, nil)
|
|
}
|