diff --git a/lib/layout.go b/lib/layout.go new file mode 100644 index 0000000..4f6672f --- /dev/null +++ b/lib/layout.go @@ -0,0 +1,133 @@ +package lib + +import ( + "bytes" + "context" + "encoding/json" + "net/http" +) + +type LayoutService service + +func (l *LayoutService) Create(ctx context.Context, request CreateLayoutRequest) (*CreateLayoutResponse, error) { + var resp CreateLayoutResponse + URL := l.client.config.BackendURL.JoinPath("layouts") + + requestBody := CreateLayoutRequest{ + Name: request.Name, + Identifier: request.Identifier, + Description: request.Description, + Content: request.Content, + Variables: request.Variables, + IsDefault: request.IsDefault, + } + + jsonBody, _ := json.Marshal(requestBody) + b := bytes.NewBuffer(jsonBody) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, URL.String(), b) + if err != nil { + return nil, err + } + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (l *LayoutService) List(ctx context.Context, options *LayoutRequestOptions) (*LayoutsResponse, error) { + var resp LayoutsResponse + URL := l.client.config.BackendURL.JoinPath("layouts") + if options == nil { + options = &LayoutRequestOptions{} + } + queryParams, _ := json.Marshal(options) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, URL.String(), bytes.NewBuffer(queryParams)) + if err != nil { + return nil, err + } + + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (l *LayoutService) Get(ctx context.Context, key string) (*LayoutResponse, error) { + var resp LayoutResponse + URL := l.client.config.BackendURL.JoinPath("layouts", key) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, URL.String(), bytes.NewBuffer([]byte{})) + if err != nil { + return nil, err + } + + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (l *LayoutService) Delete(ctx context.Context, key string) error { + var resp interface{} + URL := l.client.config.BackendURL.JoinPath("layouts", key) + + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, URL.String(), http.NoBody) + if err != nil { + return err + } + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return err + } + return nil +} + +func (l *LayoutService) Update(ctx context.Context, key string, request CreateLayoutRequest) (*LayoutResponse, error) { + var resp LayoutResponse + URL := l.client.config.BackendURL.JoinPath("layouts", key) + + requestBody := CreateLayoutRequest{ + Name: request.Name, + Identifier: request.Identifier, + Description: request.Description, + Content: request.Content, + Variables: request.Variables, + IsDefault: request.IsDefault, + } + + jsonBody, _ := json.Marshal(requestBody) + + req, err := http.NewRequestWithContext(ctx, http.MethodPatch, URL.String(), bytes.NewBuffer(jsonBody)) + if err != nil { + return nil, err + } + + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return nil, err + } + + return &resp, nil +} + +func (l *LayoutService) SetDefault(ctx context.Context, key string) error { + var resp interface{} + URL := l.client.config.BackendURL.JoinPath("layouts", key, "default") + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, URL.String(), http.NoBody) + if err != nil { + return err + } + + _, err = l.client.sendRequest(req, &resp) + if err != nil { + return err + } + + return nil +} diff --git a/lib/layout_test.go b/lib/layout_test.go new file mode 100644 index 0000000..9b6e8b7 --- /dev/null +++ b/lib/layout_test.go @@ -0,0 +1,207 @@ +package lib_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "testing" + + "github.com/novuhq/go-novu/lib" + "github.com/stretchr/testify/require" +) + +const LayoutId = "2222" + +func TestLayoutService_Create_Layout_Success(t *testing.T) { + var createLayoutRequest *lib.CreateLayoutRequest = &lib.CreateLayoutRequest{ + Name: "layoutName", + Identifier: "layoutIdentifier", + Description: "layoutDescription", + Content: "layoutContent", + Variables: []interface{}(nil), + IsDefault: true, + } + res, _ := json.Marshal(createLayoutRequest) + fmt.Println(string(res)) + var expectedResponse *lib.CreateLayoutResponse = &lib.CreateLayoutResponse{ + Data: struct { + Id string `json:"_id"` + }{ + Id: "2222", + }, + } + + httpServer := createTestServer(t, TestServerOptions[lib.CreateLayoutRequest, lib.CreateLayoutResponse]{ + expectedURLPath: "/v1/layouts", + expectedSentBody: *createLayoutRequest, + expectedSentMethod: http.MethodPost, + responseStatusCode: http.StatusCreated, + responseBody: *expectedResponse, + }) + + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + resp, err := c.LayoutApi.Create(ctx, *createLayoutRequest) + + require.NoError(t, err) + require.Equal(t, expectedResponse, resp) +} + +func TestLayoutService_List_Layouts_Success(t *testing.T) { + body := map[string]string{} + var expectedResponse *lib.LayoutsResponse = &lib.LayoutsResponse{ + Page: 0, + PageSize: 20, + TotalCount: 1, + Data: []lib.LayoutResponse{{ + Id: "id", + OrganizationId: "orgId", + EnvironmentId: "envId", + CreatorId: "creatorId", + Name: "layoutName", + Identifier: "layoutIdentifier", + Description: "layoutDescription", + Channel: "in_app", + Content: "layoutContent", + ContentType: "layoutContentType", + Variables: []interface{}{}, + IsDefault: true, + IsDeleted: false, + CreatedAt: "createdAt", + UpdatedAt: "updatedAt", + ParentId: "parentId", + }}, + } + httpServer := createTestServer(t, TestServerOptions[map[string]string, lib.LayoutsResponse]{ + expectedURLPath: "/v1/layouts", + expectedSentMethod: http.MethodGet, + expectedSentBody: body, + responseStatusCode: http.StatusCreated, + responseBody: *expectedResponse, + }) + + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + resp, err := c.LayoutApi.List(ctx, nil) + + require.NoError(t, err) + require.Equal(t, expectedResponse, resp) +} + +func TestLayoutService_Get_Layout_Success(t *testing.T) { + + var expectedResponse *lib.LayoutResponse = &lib.LayoutResponse{ + Id: "id", + OrganizationId: "orgId", + EnvironmentId: "envId", + CreatorId: "creatorId", + Name: "layoutName", + Identifier: "layoutIdentifier", + Description: "layoutDescription", + Channel: "in_app", + Content: "layoutContent", + ContentType: "layoutContentType", + Variables: []interface{}{}, + IsDefault: true, + IsDeleted: false, + CreatedAt: "createdAt", + UpdatedAt: "updatedAt", + ParentId: "parentId", + } + + httpServer := createTestServer(t, TestServerOptions[map[string]string, lib.LayoutResponse]{ + expectedURLPath: fmt.Sprintf("/v1/layouts/%s", LayoutId), + expectedSentMethod: http.MethodGet, + responseStatusCode: http.StatusOK, + responseBody: *expectedResponse, + }) + + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + resp, err := c.LayoutApi.Get(ctx, "2222") + + require.NoError(t, err) + require.Equal(t, expectedResponse, resp) +} + +func TestLayoutService_Delete_Layout_Success(t *testing.T) { + + body := map[string]string{} + + httpServer := createTestServer(t, TestServerOptions[map[string]string, map[string]string]{ + expectedURLPath: fmt.Sprintf("/v1/layouts/%s", LayoutId), + expectedSentMethod: http.MethodDelete, + responseStatusCode: http.StatusOK, + responseBody: body, + }) + + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + err := c.LayoutApi.Delete(ctx, "2222") + + require.NoError(t, err) +} + +func TestLayoutService_Update_Layout_Success(t *testing.T) { + + var updateLayoutRequest *lib.CreateLayoutRequest = &lib.CreateLayoutRequest{ + Name: "layoutName", + Identifier: "layoutIdentifier", + Description: "layoutDescription", + Content: "layoutContent", + Variables: []interface{}(nil), + IsDefault: false, + } + res, _ := json.Marshal(updateLayoutRequest) + fmt.Println(string(res)) + var expectedResponse *lib.LayoutResponse = &lib.LayoutResponse{ + Id: "id", + OrganizationId: "orgId", + EnvironmentId: "envId", + CreatorId: "creatorId", + Name: "layoutName", + Identifier: "layoutIdentifier", + Description: "layoutDescription", + Channel: "in_app", + Content: "layoutContent", + ContentType: "layoutContentType", + Variables: []interface{}{}, + IsDefault: true, + IsDeleted: false, + CreatedAt: "createdAt", + UpdatedAt: "updatedAt", + ParentId: "parentId", + } + httpServer := createTestServer[lib.CreateLayoutRequest, lib.LayoutResponse](t, TestServerOptions[lib.CreateLayoutRequest, lib.LayoutResponse]{ + expectedURLPath: fmt.Sprintf("/v1/layouts/%s", LayoutId), + expectedSentBody: *updateLayoutRequest, + expectedSentMethod: http.MethodPatch, + responseStatusCode: http.StatusOK, + responseBody: *expectedResponse, + }) + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + resp, err := c.LayoutApi.Update(ctx, "2222", *updateLayoutRequest) + require.NoError(t, err) + require.Equal(t, expectedResponse, resp) +} + +func TestLayoutService_Layout_SetDefault(t *testing.T) { + + body := map[string]string{} + + httpServer := createTestServer(t, TestServerOptions[map[string]string, map[string]string]{ + expectedURLPath: fmt.Sprintf("/v1/layouts/%s/default", LayoutId), + expectedSentBody: body, + expectedSentMethod: http.MethodPost, + responseStatusCode: http.StatusNoContent, + responseBody: body, + }) + + ctx := context.Background() + c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)}) + err := c.LayoutApi.SetDefault(ctx, LayoutId) + + require.NoError(t, err) +} diff --git a/lib/model.go b/lib/model.go index ab12cdc..1c35906 100644 --- a/lib/model.go +++ b/lib/model.go @@ -409,6 +409,50 @@ type InboundParserResponse struct { Data MxRecordConfiguredStatus `json:"data"` } +type CreateLayoutRequest struct { + Name string `json:"name"` + Identifier string `json:"identifier"` + Description string `json:"description"` + Content string `json:"content"` + Variables []interface{} `json:"variables,omitempty"` + IsDefault bool `json:"isDefault,omitempty"` +} + +type CreateLayoutResponse struct { + Data struct { + Id string `json:"_id"` + } `json:"data"` +} +type LayoutRequestOptions struct { + Page *int `json:"page,omitempty"` + PageSize *int `json:"pageSize,omitempty"` + Key *string `json:"key,omitempty"` + OrderBy *int `json:"orderBy,omitempty"` +} +type LayoutResponse struct { + Id string `json:"_id"` + OrganizationId string `json:"_organizationId"` + EnvironmentId string `json:"_environmentId"` + CreatorId string `json:"_creatorId"` + Name string `json:"name"` + Identifier string `json:"identifier"` + Description string `json:"description"` + Channel string `json:"channel"` + Content string `json:"content"` + ContentType string `json:"contentType"` + Variables []interface{} `json:"variables"` + IsDefault bool `json:"isDefault"` + IsDeleted bool `json:"isDeleted"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` + ParentId string `json:"_parentId"` +} +type LayoutsResponse struct { + TotalCount int `json:"totalCount"` + Data []LayoutResponse `json:"data"` + PageSize int `json:"pageSize"` + Page int `json:"page"` +} type BlueprintByTemplateIdResponse struct { Id string `json:"_id,omitempty"` Name string `json:"name,omitempty"` diff --git a/lib/novu.go b/lib/novu.go index d3e0b1f..5f5925c 100644 --- a/lib/novu.go +++ b/lib/novu.go @@ -50,7 +50,8 @@ type APIClient struct { TopicsApi *TopicService IntegrationsApi *IntegrationService InboundParserApi *InboundParserService - TenantApi *TenantService + LayoutApi *LayoutService + TenantApi *TenantService } type service struct { @@ -108,6 +109,7 @@ func NewAPIClient(apiKey string, cfg *Config) *APIClient { c.TopicsApi = (*TopicService)(&c.common) c.IntegrationsApi = (*IntegrationService)(&c.common) c.InboundParserApi = (*InboundParserService)(&c.common) + c.LayoutApi = (*LayoutService)(&c.common) c.BlueprintApi = (*BlueprintService)(&c.common) c.TenantApi = (*TenantService)(&c.common) return c