diff --git a/lib/model.go b/lib/model.go index 3c137d8..a49765c 100644 --- a/lib/model.go +++ b/lib/model.go @@ -408,3 +408,36 @@ type MxRecordConfiguredStatus struct { type InboundParserResponse struct { Data MxRecordConfiguredStatus `json:"data"` } + +type CreateWorkflowGroupRequest struct { + Name string +} + +type UpdateWorkflowGroupRequest struct { + Name string `json:"name"` +} + +type ListWorkflowGroupsResponse struct { + Data []WorkflowGroup `json:"data"` +} + +type WorkflowGroup struct { + Id string `json:"_id"` + Name string `json:"name"` + EnvironmentId string `json:"_environmentId"` + OrganizationId string `json:"_organizationId"` + ParentId string `json:"_parentId"` +} + +type GetWorkflowResponse struct { + Data WorkflowGroup `json:"data"` +} + +type DeleteWorkflowGroupResponse struct { + Data DeleteWorkflowGroup `json:"data"` +} + +type DeleteWorkflowGroup struct { + Acknowledged bool `json:"acknowledged"` + Status string `json:"status"` +} diff --git a/lib/novu.go b/lib/novu.go index ce1b424..0231db7 100644 --- a/lib/novu.go +++ b/lib/novu.go @@ -36,6 +36,7 @@ type APIClient struct { TopicsApi *TopicService IntegrationsApi *IntegrationService InboundParserApi *InboundParserService + WorkflowGroupApi *WorkflowGroupService } type service struct { @@ -62,6 +63,7 @@ func NewAPIClient(apiKey string, cfg *Config) *APIClient { c.TopicsApi = (*TopicService)(&c.common) c.IntegrationsApi = (*IntegrationService)(&c.common) c.InboundParserApi = (*InboundParserService)(&c.common) + c.WorkflowGroupApi = (*WorkflowGroupService)(&c.common) return c } @@ -117,7 +119,6 @@ func (c APIClient) decode(v interface{}, b []byte) (err error) { } func buildBackendURL(cfg *Config) *url.URL { - if cfg.BackendURL == nil { rawURL := fmt.Sprintf("%s/%s", NovuURL, NovuVersion) return MustParseURL(rawURL) diff --git a/lib/workflow_groups.go b/lib/workflow_groups.go new file mode 100644 index 0000000..a474301 --- /dev/null +++ b/lib/workflow_groups.go @@ -0,0 +1,120 @@ +package lib + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + + "github.com/pkg/errors" +) + +type IWorkflowGroup interface { + Create(ctx context.Context, name string) (*GetWorkflowResponse, error) + Get(ctx context.Context, workflowGroupID string) (*GetWorkflowResponse, error) + List(ctx context.Context) (*ListWorkflowGroupsResponse, error) + Delete(ctx context.Context, workflowGroupID string) (*DeleteWorkflowGroupResponse, error) + Update(ctx context.Context, workflowGroupID string, request UpdateWorkflowGroupRequest) (*GetWorkflowResponse, error) +} + +type WorkflowGroupService service + +const WORKFLOW_GROUP_PATH = "notification-groups" + +func (t *WorkflowGroupService) Create(ctx context.Context, name string) (*GetWorkflowResponse, error) { + var resp GetWorkflowResponse + + URL := t.client.config.BackendURL.JoinPath(WORKFLOW_GROUP_PATH) + reqBody := CreateWorkflowGroupRequest{ + Name: name, + } + + jsonBody, _ := json.Marshal(reqBody) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, URL.String(), bytes.NewBuffer(jsonBody)) + if err != nil { + return nil, err + } + + httpResponse, err := t.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + if httpResponse.StatusCode != HTTPStatusCreated { + return nil, errors.Wrap(err, "unable to create workflow group") + } + + return &resp, nil +} + +func (t *WorkflowGroupService) List(ctx context.Context) (*ListWorkflowGroupsResponse, error) { + var resp ListWorkflowGroupsResponse + URL := t.client.config.BackendURL.JoinPath(WORKFLOW_GROUP_PATH) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, URL.String(), http.NoBody) + if err != nil { + return nil, err + } + + _, err = t.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + return &resp, nil +} + +func (t *WorkflowGroupService) Get(ctx context.Context, workflowGroupID string) (*GetWorkflowResponse, error) { + var resp GetWorkflowResponse + + URL := t.client.config.BackendURL.JoinPath(WORKFLOW_GROUP_PATH, workflowGroupID) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, URL.String(), bytes.NewBuffer([]byte{})) + if err != nil { + return nil, err + } + + _, err = t.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + return &resp, nil +} + +func (t *WorkflowGroupService) Delete(ctx context.Context, workflowGroupID string) (*DeleteWorkflowGroupResponse, error) { + var resp DeleteWorkflowGroupResponse + URL := t.client.config.BackendURL.JoinPath(WORKFLOW_GROUP_PATH, workflowGroupID) + + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, URL.String(), http.NoBody) + if err != nil { + return nil, err + } + + _, err = t.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + return &resp, nil +} + +func (t *WorkflowGroupService) Update(ctx context.Context, workflowGroupID string, request UpdateWorkflowGroupRequest) (*GetWorkflowResponse, error) { + var resp GetWorkflowResponse + + URL := t.client.config.BackendURL.JoinPath(WORKFLOW_GROUP_PATH, workflowGroupID) + jsonBody, _ := json.Marshal(request) + + req, err := http.NewRequestWithContext(ctx, http.MethodPatch, URL.String(), bytes.NewBuffer(jsonBody)) + if err != nil { + return nil, err + } + + _, err = t.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + return &resp, nil +} diff --git a/lib/workflow_groups_test.go b/lib/workflow_groups_test.go new file mode 100644 index 0000000..54d00d0 --- /dev/null +++ b/lib/workflow_groups_test.go @@ -0,0 +1,112 @@ +package lib_test + +import ( + "context" + "net/http" + "path/filepath" + "testing" + + "github.com/novuhq/go-novu/lib" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const WORKFLOW_GROUP_PATH = "/v1/notification-groups" + +var ctx = context.Background() + +func TestCreateWorkflowGroup_Success(t *testing.T) { + var response *lib.GetWorkflowResponse + fileToStruct(filepath.Join("../testdata", "create_workflow_group_response.json"), &response) + name := "workflow-group-name" + httpServer := createTestServer(t, TestServerOptions[lib.CreateWorkflowGroupRequest, *lib.GetWorkflowResponse]{ + expectedURLPath: WORKFLOW_GROUP_PATH, + expectedSentMethod: http.MethodPost, + expectedSentBody: lib.CreateWorkflowGroupRequest{ + Name: name, + }, + responseStatusCode: http.StatusCreated, + responseBody: response, + }) + + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + res, err := c.WorkflowGroupApi.Create(ctx, name) + + assert.Equal(t, response, res) + require.NoError(t, err) +} + +func TestGetWorkflowGroup_Success(t *testing.T) { + var response *lib.GetWorkflowResponse + fileToStruct(filepath.Join("../testdata", "get_workflow_group_response.json"), &response) + workflowId := "6425cb064a2a919bc61b0365" + httpServer := createTestServer(t, TestServerOptions[lib.CreateWorkflowGroupRequest, *lib.GetWorkflowResponse]{ + expectedURLPath: WORKFLOW_GROUP_PATH + "/" + workflowId, + expectedSentMethod: http.MethodGet, + responseStatusCode: http.StatusOK, + responseBody: response, + }) + + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + res, err := c.WorkflowGroupApi.Get(ctx, workflowId) + + assert.Equal(t, response, res) + require.NoError(t, err) +} + +func TestListWorkflowGroup_Success(t *testing.T) { + var response *lib.ListWorkflowGroupsResponse + fileToStruct(filepath.Join("../testdata", "list_workflow_groups_response.json"), &response) + httpServer := createTestServer(t, TestServerOptions[lib.CreateWorkflowGroupRequest, *lib.ListWorkflowGroupsResponse]{ + expectedURLPath: WORKFLOW_GROUP_PATH, + expectedSentMethod: http.MethodGet, + responseStatusCode: http.StatusOK, + responseBody: response, + }) + + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + res, err := c.WorkflowGroupApi.List(ctx) + + assert.Equal(t, response, res) + require.NoError(t, err) +} + +func TestDeleteWorkflowGroup_Success(t *testing.T) { + var response *lib.DeleteWorkflowGroupResponse + fileToStruct(filepath.Join("../testdata", "delete_workflow_group_response.json"), &response) + workflowId := "6425cb064a2a919bc61b0365" + httpServer := createTestServer(t, TestServerOptions[any, *lib.DeleteWorkflowGroupResponse]{ + expectedURLPath: WORKFLOW_GROUP_PATH + "/" + workflowId, + expectedSentMethod: http.MethodDelete, + responseStatusCode: http.StatusOK, + responseBody: response, + }) + + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + res, err := c.WorkflowGroupApi.Delete(ctx, workflowId) + + assert.Equal(t, response, res) + require.NoError(t, err) +} + +func TestUpdateWorkflowGroup_Success(t *testing.T) { + var response *lib.GetWorkflowResponse + fileToStruct(filepath.Join("../testdata", "update_workflow_group_response.json"), &response) + workflowId := "6425cb064a2a919bc61b0365" + updatedRequest := lib.UpdateWorkflowGroupRequest{ + Name: "updated-name", + } + httpServer := createTestServer(t, TestServerOptions[lib.UpdateWorkflowGroupRequest, *lib.GetWorkflowResponse]{ + expectedURLPath: WORKFLOW_GROUP_PATH + "/" + workflowId, + expectedSentMethod: http.MethodPatch, + expectedSentBody: updatedRequest, + responseStatusCode: http.StatusOK, + responseBody: response, + }) + + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + res, err := c.WorkflowGroupApi.Update(ctx, workflowId, updatedRequest) + + assert.Equal(t, response, res) + require.NoError(t, err) +} diff --git a/testdata/create_workflow_group_response.json b/testdata/create_workflow_group_response.json new file mode 100644 index 0000000..52b3a9e --- /dev/null +++ b/testdata/create_workflow_group_response.json @@ -0,0 +1,9 @@ +{ + "data": { + "_id": "6425cb064a2a919bc61b0365", + "name": "workflow-group-name", + "_environmentId": "6425cb40d22507199a000003", + "_organizationId": "7425cb40d22507199a000009", + "_parentId": "8495cb40d82507199a000002" + } +} diff --git a/testdata/delete_workflow_group_response.json b/testdata/delete_workflow_group_response.json new file mode 100644 index 0000000..f877099 --- /dev/null +++ b/testdata/delete_workflow_group_response.json @@ -0,0 +1,6 @@ +{ + "data": { + "acknowledged": true, + "status": "deleted" + } +} diff --git a/testdata/get_workflow_group_response.json b/testdata/get_workflow_group_response.json new file mode 100644 index 0000000..5a4c2d8 --- /dev/null +++ b/testdata/get_workflow_group_response.json @@ -0,0 +1,9 @@ +{ + "data": { + "_id": "6425cb064a2a919bc61b0365", + "name": "name", + "_environmentId": "6425cb40d22507199a000003", + "_organizationId": "7425cb40d22507199a000009", + "_parentId": "8495cb40d82507199a000002" + } +} diff --git a/testdata/list_workflow_groups_response.json b/testdata/list_workflow_groups_response.json new file mode 100644 index 0000000..0d8c772 --- /dev/null +++ b/testdata/list_workflow_groups_response.json @@ -0,0 +1,11 @@ +{ + "data": [ + { + "_id": "6425cb064a2a919bc61b0365", + "name": "name", + "_environmentId": "6425cb40d22507199a000003", + "_organizationId": "7425cb40d22507199a000009", + "_parentId": "8495cb40d82507199a000002" + } + ] +} diff --git a/testdata/update_workflow_group_response.json b/testdata/update_workflow_group_response.json new file mode 100644 index 0000000..21465f1 --- /dev/null +++ b/testdata/update_workflow_group_response.json @@ -0,0 +1,9 @@ +{ + "data": { + "_id": "6425cb064a2a919bc61b0365", + "name": "updated-name", + "_environmentId": "6425cb40d22507199a000003", + "_organizationId": "7425cb40d22507199a000009", + "_parentId": "8495cb40d82507199a000002" + } +}