diff --git a/api/api.go b/api/api.go index 30918b8507..2fbcf47184 100644 --- a/api/api.go +++ b/api/api.go @@ -185,6 +185,13 @@ func (a *ApplicationHandler) BuildControlPlaneRoutes() *chi.Mux { }) }) + projectSubRouter.Route("/event-types", func(eventTypesRouter chi.Router) { + eventTypesRouter.Get("/", handler.GetEventTypes) + eventTypesRouter.With(handler.RequireEnabledProject()).Post("/", handler.CreateEventType) + eventTypesRouter.With(handler.RequireEnabledProject()).Put("/{eventTypeId}", handler.UpdateEventType) + eventTypesRouter.With(handler.RequireEnabledProject()).Post("/{eventTypeId}/deprecate", handler.DeprecateEventType) + }) + projectSubRouter.Route("/eventdeliveries", func(eventDeliveryRouter chi.Router) { eventDeliveryRouter.With(middleware.Pagination).Get("/", handler.GetEventDeliveriesPaged) eventDeliveryRouter.With(handler.RequireEnabledProject()).Post("/forceresend", handler.ForceResendEventDeliveries) @@ -353,6 +360,13 @@ func (a *ApplicationHandler) BuildControlPlaneRoutes() *chi.Mux { }) }) + projectSubRouter.Route("/event-types", func(eventTypesRouter chi.Router) { + eventTypesRouter.Get("/", handler.GetEventTypes) + eventTypesRouter.With(handler.RequireEnabledProject()).Post("/", handler.CreateEventType) + eventTypesRouter.With(handler.RequireEnabledProject()).Put("/{eventTypeId}", handler.UpdateEventType) + eventTypesRouter.With(handler.RequireEnabledProject()).Post("/{eventTypeId}/deprecate", handler.DeprecateEventType) + }) + projectSubRouter.Route("/eventdeliveries", func(eventDeliveryRouter chi.Router) { eventDeliveryRouter.With(middleware.Pagination).Get("/", handler.GetEventDeliveriesPaged) eventDeliveryRouter.With(handler.RequireEnabledProject()).Post("/forceresend", handler.ForceResendEventDeliveries) diff --git a/api/handlers/event_types.go b/api/handlers/event_types.go new file mode 100644 index 0000000000..44ebc6780d --- /dev/null +++ b/api/handlers/event_types.go @@ -0,0 +1,184 @@ +package handlers + +import ( + "github.com/frain-dev/convoy/api/models" + "github.com/frain-dev/convoy/database/postgres" + "github.com/frain-dev/convoy/datastore" + "github.com/frain-dev/convoy/util" + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" + "github.com/oklog/ulid/v2" + "net/http" +) + +// GetEventTypes +// +// @Summary Retrieves a project's event types +// @Description This endpoint fetches the project's event types +// @Id GetEventTypes +// @Tags EventTypes +// @Accept json +// @Produce json +// @Param projectID path string true "Project ID" +// @Success 200 {object} util.ServerResponse{data=models.EventTypeListResponse} +// @Failure 400,401,404 {object} util.ServerResponse{data=Stub} +// @Security ApiKeyAuth +// @Router /v1/projects/{projectID}/event-types [get] +func (h *Handler) GetEventTypes(w http.ResponseWriter, r *http.Request) { + project, err := h.retrieveProject(r) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + eventTypeRepo := postgres.NewEventTypesRepo(h.A.DB) + eventTypes, err := eventTypeRepo.FetchAllEventTypes(r.Context(), project.UID) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + resp := &models.EventTypeListResponse{EventTypes: eventTypes} + _ = render.Render(w, r, util.NewServerResponse("Event types fetched successfully", resp, http.StatusOK)) +} + +// CreateEventType +// +// @Summary Create an event type +// @Description This endpoint creates an event type +// @Id CreateEventType +// @Tags EventTypes +// @Accept json +// @Produce json +// @Param projectID path string true "Project ID" +// @Param eventType body models.CreateEventType true "Event Type Details" +// @Success 201 {object} util.ServerResponse{data=models.EventTypeResponse} +// @Failure 400,401,404 {object} util.ServerResponse{data=Stub} +// @Security ApiKeyAuth +// @Router /v1/projects/{projectID}/event-types [post] +func (h *Handler) CreateEventType(w http.ResponseWriter, r *http.Request) { + project, err := h.retrieveProject(r) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + var newEventType models.CreateEventType + err = util.ReadJSON(r, &newEventType) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + err = newEventType.Validate() + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + pe := &datastore.ProjectEventType{ + ProjectId: project.UID, + Name: newEventType.Name, + ID: ulid.Make().String(), + Category: newEventType.Category, + Description: newEventType.Description, + } + + eventTypeRepo := postgres.NewEventTypesRepo(h.A.DB) + err = eventTypeRepo.CreateEventType(r.Context(), pe) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + resp := &models.EventTypeResponse{EventType: pe} + _ = render.Render(w, r, util.NewServerResponse("Event type created successfully", resp, http.StatusCreated)) +} + +// UpdateEventType +// +// @Summary Updates an event type +// @Description This endpoint updates an event type +// @Id CreateEventType +// @Tags EventTypes +// @Accept json +// @Produce json +// @Param projectID path string true "Project ID" +// @Param eventType body models.UpdateEventType true "Event Type Details" +// @Success 201 {object} util.ServerResponse{data=models.EventTypeResponse} +// @Failure 400,401,404 {object} util.ServerResponse{data=Stub} +// @Security ApiKeyAuth +// @Router /v1/projects/{projectID}/event-types/{eventTypeId} [put] +func (h *Handler) UpdateEventType(w http.ResponseWriter, r *http.Request) { + project, err := h.retrieveProject(r) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + eventTypeId := chi.URLParam(r, "eventTypeId") + + var ue models.UpdateEventType + err = util.ReadJSON(r, &ue) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + eventTypeRepo := postgres.NewEventTypesRepo(h.A.DB) + pe, err := eventTypeRepo.FetchEventTypeById(r.Context(), eventTypeId, project.UID) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + if !util.IsStringEmpty(ue.Description) { + pe.Description = ue.Description + } + + if !util.IsStringEmpty(ue.Category) { + pe.Category = ue.Category + } + + err = eventTypeRepo.UpdateEventType(r.Context(), pe) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + resp := &models.EventTypeResponse{EventType: pe} + _ = render.Render(w, r, util.NewServerResponse("Event type created successfully", resp, http.StatusAccepted)) +} + +// DeprecateEventType +// +// @Summary Create an event type +// @Description This endpoint creates an event type +// @Id DeprecateEventType +// @Tags EventTypes +// @Accept json +// @Produce json +// @Param projectID path string true "Project ID" +// @Param eventTypeId path string true "Event Type ID" +// @Success 201 {object} util.ServerResponse{data=models.EventTypeResponse} +// @Failure 400,401,404 {object} util.ServerResponse{data=Stub} +// @Security ApiKeyAuth +// @Router /v1/projects/{projectID}/event-types/{eventTypeId}/deprecate [post] +func (h *Handler) DeprecateEventType(w http.ResponseWriter, r *http.Request) { + project, err := h.retrieveProject(r) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + eventTypeId := chi.URLParam(r, "eventTypeId") + eventTypeRepo := postgres.NewEventTypesRepo(h.A.DB) + pe, err := eventTypeRepo.DeprecateEventType(r.Context(), eventTypeId, project.UID) + if err != nil { + _ = render.Render(w, r, util.NewErrorResponse(err.Error(), http.StatusBadRequest)) + return + } + + resp := &models.EventTypeResponse{EventType: pe} + _ = render.Render(w, r, util.NewServerResponse("Event type deprecated successfully", resp, http.StatusOK)) +} diff --git a/api/ingest_integration_test.go b/api/ingest_integration_test.go index 09e8f53ac6..e1aa2cf6ac 100644 --- a/api/ingest_integration_test.go +++ b/api/ingest_integration_test.go @@ -209,7 +209,6 @@ func (i *IngestIntegrationTestSuite) Test_IngestEvent_GoodAPIKey() { // Act. i.Router.ServeHTTP(w, req) - fmt.Println("eee", w.Body.String()) // Assert. require.Equal(i.T(), expectedStatusCode, w.Code) } diff --git a/api/models/endpoint.go b/api/models/endpoint.go index 5938238642..535b233157 100644 --- a/api/models/endpoint.go +++ b/api/models/endpoint.go @@ -30,7 +30,7 @@ type CreateEndpoint struct { AdvancedSignatures *bool `json:"advanced_signatures"` // Endpoint name. - Name string `json:"name" valid:"required~please provide your endpointName"` + Name string `json:"name" valid:"required~please provide your endpoint name"` // Endpoint developers support email. This is used for communicating endpoint state // changes. You should always turn this on when disabling endpoints are enabled. diff --git a/api/models/event_types.go b/api/models/event_types.go new file mode 100644 index 0000000000..3f8de0f1b0 --- /dev/null +++ b/api/models/event_types.go @@ -0,0 +1,37 @@ +package models + +import ( + "github.com/frain-dev/convoy/datastore" + "github.com/frain-dev/convoy/util" +) + +type CreateEventType struct { + // Name is the event type name. E.g., invoice.created + Name string `json:"name" valid:"required~please provide a name for this event type"` + + // Category is a product-specific grouping for the event type + Category string `json:"category"` + + // Description is used to describe what the event type does + Description string `json:"description"` +} + +func (ce *CreateEventType) Validate() error { + return util.Validate(ce) +} + +type EventTypeResponse struct { + EventType *datastore.ProjectEventType `json:"event_type"` +} + +type EventTypeListResponse struct { + EventTypes []datastore.ProjectEventType `json:"event_types"` +} + +type UpdateEventType struct { + // Category is a product-specific grouping for the event type + Category string `json:"category"` + + // Description is used to describe what the event type does + Description string `json:"description"` +} diff --git a/api/public_integration_test.go b/api/public_integration_test.go index 3caf9e98f3..48677b3813 100644 --- a/api/public_integration_test.go +++ b/api/public_integration_test.go @@ -2773,3 +2773,162 @@ func (s *PublicMetaEventIntegrationTestSuite) Test_GetMetaEvent_Valid_MetaEvent( func TestPublicMetaEventIntegrationTestSuite(t *testing.T) { suite.Run(t, new(PublicMetaEventIntegrationTestSuite)) } + +type PublicEventTypeIntegrationTestSuite struct { + suite.Suite + DB database.Database + Router http.Handler + ConvoyApp *ApplicationHandler + DefaultOrg *datastore.Organisation + DefaultProject *datastore.Project + APIKey string +} + +func (s *PublicEventTypeIntegrationTestSuite) SetupSuite() { + s.DB = getDB() + s.ConvoyApp = buildServer() + s.Router = s.ConvoyApp.BuildControlPlaneRoutes() +} + +func (s *PublicEventTypeIntegrationTestSuite) SetupTest() { + testdb.PurgeDB(s.T(), s.DB) + + user, err := testdb.SeedDefaultUser(s.ConvoyApp.A.DB) + require.NoError(s.T(), err) + + org, err := testdb.SeedDefaultOrganisation(s.ConvoyApp.A.DB, user) + require.NoError(s.T(), err) + s.DefaultOrg = org + + // Setup Default Project. + s.DefaultProject, err = testdb.SeedDefaultProject(s.ConvoyApp.A.DB, org.UID) + require.NoError(s.T(), err) + + // Seed Auth + role := auth.Role{ + Type: auth.RoleAdmin, + Project: s.DefaultProject.UID, + } + + _, s.APIKey, _ = testdb.SeedAPIKey(s.ConvoyApp.A.DB, role, "", "test", "", "") +} + +func (s *PublicEventTypeIntegrationTestSuite) TearDownTest() { + testdb.PurgeDB(s.T(), s.DB) + metrics.Reset() +} + +func (s *PublicEventTypeIntegrationTestSuite) Test_GetEventTypes() { + expectedStatusCode := http.StatusOK + + url := fmt.Sprintf("/api/v1/projects/%s/event-types", s.DefaultProject.UID) + req := createRequest(http.MethodGet, url, s.APIKey, nil) + w := httptest.NewRecorder() + + eventTypeId := ulid.Make().String() + // Just Before: Create an event type to update + _, err := testdb.SeedEventType(s.ConvoyApp.A.DB, s.DefaultProject.UID, eventTypeId, "Initial Name", "Initial Description", "Initial Category") + require.NoError(s.T(), err) + + // Act. + s.Router.ServeHTTP(w, req) + + // Assert. + require.Equal(s.T(), expectedStatusCode, w.Code) + + // Deep Assert. + var resp models.EventTypeListResponse + parseResponse(s.T(), w.Result(), &resp) + require.NotEmpty(s.T(), resp.EventTypes) +} + +func (s *PublicEventTypeIntegrationTestSuite) Test_CreateEventType() { + expectedStatusCode := http.StatusCreated + eventTypeName := "Test Event Type" + + // Arrange Request + url := fmt.Sprintf("/api/v1/projects/%s/event-types", s.DefaultProject.UID) + body := serialize(`{ + "name": "%s", + "category": "Test Category", + "description": "Test Description" + }`, eventTypeName) + req := createRequest(http.MethodPost, url, s.APIKey, body) + w := httptest.NewRecorder() + + // Act. + s.Router.ServeHTTP(w, req) + + // Assert. + require.Equal(s.T(), expectedStatusCode, w.Code) + + // Deep Assert. + var resp models.EventTypeResponse + parseResponse(s.T(), w.Result(), &resp) + require.Equal(s.T(), eventTypeName, resp.EventType.Name) +} + +func (s *PublicEventTypeIntegrationTestSuite) Test_UpdateEventType() { + expectedStatusCode := http.StatusAccepted + eventTypeId := ulid.Make().String() + + // Just Before: Create an event type to update + _, err := testdb.SeedEventType(s.ConvoyApp.A.DB, s.DefaultProject.UID, eventTypeId, "Initial Name", "Initial Description", "Initial Category") + require.NoError(s.T(), err) + + // Arrange Request + url := fmt.Sprintf("/api/v1/projects/%s/event-types/%s", s.DefaultProject.UID, eventTypeId) + body := serialize(`{ + "name": "Updated Event Type", + "description": "Updated Description", + "category": "Updated Category" + }`) + req := createRequest(http.MethodPut, url, s.APIKey, body) + w := httptest.NewRecorder() + + // Act. + s.Router.ServeHTTP(w, req) + + // Assert. + require.Equal(s.T(), expectedStatusCode, w.Code) + + // Deep Assert. + var resp models.EventTypeResponse + parseResponse(s.T(), w.Result(), &resp) + require.Equal(s.T(), "Updated Category", resp.EventType.Category) + require.Equal(s.T(), "Updated Description", resp.EventType.Description) + + // Name should not change + require.Equal(s.T(), "Initial Name", resp.EventType.Name) +} + +func (s *PublicEventTypeIntegrationTestSuite) Test_DeprecateEventType() { + expectedStatusCode := http.StatusOK + eventTypeId := ulid.Make().String() + + // Just Before: Create an event type to deprecate + _, err := testdb.SeedEventType(s.ConvoyApp.A.DB, s.DefaultProject.UID, eventTypeId, "Deprecate Me", "Description", "Category") + require.NoError(s.T(), err) + + // Arrange Request + url := fmt.Sprintf("/api/v1/projects/%s/event-types/%s/deprecate", s.DefaultProject.UID, eventTypeId) + req := createRequest(http.MethodPost, url, s.APIKey, nil) + w := httptest.NewRecorder() + + // Act. + s.Router.ServeHTTP(w, req) + + // Assert. + require.Equal(s.T(), expectedStatusCode, w.Code) + + // Deep Assert. + var resp models.EventTypeResponse + parseResponse(s.T(), w.Result(), &resp) + require.Equal(s.T(), eventTypeId, resp.EventType.ID) + require.NotNil(s.T(), resp.EventType.DeprecatedAt) + require.True(s.T(), resp.EventType.DeprecatedAt.Valid) +} + +func TestPublicEventTypeIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(PublicEventTypeIntegrationTestSuite)) +} diff --git a/api/testdb/seed.go b/api/testdb/seed.go index 4a7d25d4cd..0869844e63 100644 --- a/api/testdb/seed.go +++ b/api/testdb/seed.go @@ -24,6 +24,24 @@ import ( "github.com/xdg-go/pbkdf2" ) +func SeedEventType(db database.Database, projectId, uid, name, desc, category string) (*datastore.ProjectEventType, error) { + + evtTypesRepo := postgres.NewEventTypesRepo(db) + pe := &datastore.ProjectEventType{ + ID: uid, + Name: name, + Category: category, + ProjectId: projectId, + Description: desc, + } + + err := evtTypesRepo.CreateEventType(context.Background(), pe) + if err != nil { + return &datastore.ProjectEventType{}, err + } + return pe, nil +} + // SeedEndpoint creates a random endpoint for integration tests. func SeedEndpoint(db database.Database, g *datastore.Project, uid, title, ownerID string, disabled bool, status datastore.EndpointStatus) (*datastore.Endpoint, error) { if util.IsStringEmpty(uid) { diff --git a/database/postgres/event_types.go b/database/postgres/event_types.go new file mode 100644 index 0000000000..d9126e9a09 --- /dev/null +++ b/database/postgres/event_types.go @@ -0,0 +1,150 @@ +package postgres + +import ( + "context" + "database/sql" + "errors" + "github.com/frain-dev/convoy/database" + "github.com/frain-dev/convoy/datastore" + "github.com/jmoiron/sqlx" +) + +var ( + ErrEventTypeNotFound = errors.New("event type not found") + ErrEventTypeNotCreated = errors.New("event type could not be created") + ErrEventTypeNotUpdated = errors.New("event type could not be updated") +) + +const ( + createEventType = ` + INSERT INTO convoy.event_types (id, name, description, category, project_id, created_at, updated_at) + VALUES ($1, $2, $3, $4, $5, now(), now()); + ` + + updateEventType = ` + UPDATE convoy.event_types SET + description = $3, + category = $4, + updated_at = NOW() + WHERE id = $1 and project_id = $2; + ` + + deprecateEventType = ` + UPDATE convoy.event_types SET + deprecated_at = NOW() + WHERE id = $1 and project_id = $2 + returning *; + ` + + fetchEventTypeById = ` + SELECT * FROM convoy.event_types + WHERE id = $1 and project_id = $2; + ` + + fetchAllEventTypes = ` + SELECT * FROM convoy.event_types where project_id = $1; + ` +) + +type eventTypesRepo struct { + db *sqlx.DB +} + +func NewEventTypesRepo(db database.Database) datastore.EventTypesRepository { + return &eventTypesRepo{db: db.GetDB()} +} + +func (e *eventTypesRepo) CreateEventType(ctx context.Context, eventType *datastore.ProjectEventType) error { + r, err := e.db.ExecContext(ctx, createEventType, + eventType.ID, + eventType.Name, + eventType.Description, + eventType.Category, + eventType.ProjectId, + ) + if err != nil { + return err + } + + rowsAffected, err := r.RowsAffected() + if err != nil { + return err + } + + if rowsAffected < 1 { + return ErrEventTypeNotCreated + } + + return nil +} + +func (e *eventTypesRepo) UpdateEventType(ctx context.Context, eventType *datastore.ProjectEventType) error { + r, err := e.db.ExecContext(ctx, updateEventType, + eventType.ID, + eventType.ProjectId, + eventType.Description, + eventType.Category, + ) + if err != nil { + return err + } + + rowsAffected, err := r.RowsAffected() + if err != nil { + return err + } + + if rowsAffected < 1 { + return ErrEventTypeNotUpdated + } + + return nil +} + +func (e *eventTypesRepo) DeprecateEventType(ctx context.Context, id, projectId string) (*datastore.ProjectEventType, error) { + eventType := &datastore.ProjectEventType{} + err := e.db.QueryRowxContext(ctx, deprecateEventType, id, projectId).StructScan(eventType) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrEventTypeNotFound + } + return nil, err + } + + return eventType, nil +} + +func (e *eventTypesRepo) FetchEventTypeById(ctx context.Context, id, projectId string) (*datastore.ProjectEventType, error) { + eventType := &datastore.ProjectEventType{} + err := e.db.QueryRowxContext(ctx, fetchEventTypeById, id, projectId).StructScan(eventType) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrEventTypeNotFound + } + return nil, err + } + + return eventType, nil +} + +func (e *eventTypesRepo) FetchAllEventTypes(ctx context.Context, projectId string) ([]datastore.ProjectEventType, error) { + var eventTypes []datastore.ProjectEventType + rows, err := e.db.QueryxContext(ctx, fetchAllEventTypes, projectId) + if err != nil { + return nil, err + } + defer closeWithError(rows) + + for rows.Next() { + var eventType datastore.ProjectEventType + + err = rows.StructScan(&eventType) + if err != nil { + return nil, err + } + + eventTypes = append(eventTypes, eventType) + } + + return eventTypes, nil +} diff --git a/datastore/models.go b/datastore/models.go index 468a210bb8..01e0d45199 100644 --- a/datastore/models.go +++ b/datastore/models.go @@ -1435,6 +1435,17 @@ const ( DeviceStatusDisabled DeviceStatus = "disabled" ) +type ProjectEventType struct { + ID string `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Category string `db:"category" json:"category"` + ProjectId string `db:"project_id" json:"-"` + CreatedAt time.Time `db:"created_at" json:"-"` + UpdatedAt time.Time `db:"updated_at" json:"-"` + Description string `db:"description" json:"description"` + DeprecatedAt null.Time `db:"deprecated_at" json:"deprecated_at"` +} + type Job struct { UID string `json:"uid" db:"id"` Type string `json:"type" db:"type"` diff --git a/datastore/repository.go b/datastore/repository.go index cf0315ca65..cd462eba3a 100644 --- a/datastore/repository.go +++ b/datastore/repository.go @@ -210,3 +210,11 @@ type DeliveryAttemptsRepository interface { DeleteProjectDeliveriesAttempts(ctx context.Context, projectID string, filter *DeliveryAttemptsFilter, hardDelete bool) error GetFailureAndSuccessCounts(ctx context.Context, lookBackDuration uint64, resetTimes map[string]time.Time) (resultsMap map[string]circuit_breaker.PollResult, err error) } + +type EventTypesRepository interface { + CreateEventType(context.Context, *ProjectEventType) error + UpdateEventType(context.Context, *ProjectEventType) error + DeprecateEventType(context.Context, string, string) (*ProjectEventType, error) + FetchEventTypeById(context.Context, string, string) (*ProjectEventType, error) + FetchAllEventTypes(context.Context, string) ([]ProjectEventType, error) +} diff --git a/go.sum b/go.sum index 9d9561ff76..32dd67ab51 100644 --- a/go.sum +++ b/go.sum @@ -883,8 +883,6 @@ github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM4 github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getkin/kin-openapi v0.80.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8= -github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI= @@ -938,8 +936,6 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= -github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= @@ -957,8 +953,6 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= -github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -1262,8 +1256,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= diff --git a/scripts/build.sh b/scripts/build.sh index 91a0e7b4c1..105c081000 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,9 @@ #!/bin/bash +# export CGO_ENABLED=0 +# export GOOS=linux +# export GOARCH=arm64 + buildConvoy() { echo "Building Convoy ..." diff --git a/sql/1730027360.sql b/sql/1730027360.sql new file mode 100644 index 0000000000..af5e252b12 --- /dev/null +++ b/sql/1730027360.sql @@ -0,0 +1,40 @@ +-- +migrate Up +create table if not exists convoy.event_types ( + id varchar primary key, + name varchar not null, + description text, + project_id varchar not null references convoy.projects(id), + category varchar, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + deprecated_at timestamptz +); + +create index if not exists idx_event_types_name + on convoy.event_types(name); + +create index if not exists idx_event_types_category + on convoy.event_types(category); + +create index if not exists idx_event_types_name_not_deprecated + on convoy.event_types(name) where deprecated_at is null; + +create index if not exists idx_event_types_name_deprecated + on convoy.event_types(name) where deprecated_at is not null; + +create index if not exists idx_event_types_category_not_deprecated + on convoy.event_types(category) where deprecated_at is null; + +create index if not exists idx_event_types_category_deprecated + on convoy.event_types(category) where deprecated_at is not null; + +-- +migrate Down +drop index if exists convoy.idx_event_types_category; +drop index if exists convoy.idx_event_types_name; +drop index if exists convoy.idx_event_types_category_deprecated; +drop index if exists convoy.idx_event_types_category_not_deprecated; +drop index if exists convoy.idx_event_types_name_deprecated; +drop index if exists convoy.idx_event_types_name_not_deprecated; +drop table if exists convoy.event_types; + +