diff --git a/confluence/internal/attachment_impl.go b/confluence/internal/attachment_impl.go index 0f4319be..c71e9a37 100644 --- a/confluence/internal/attachment_impl.go +++ b/confluence/internal/attachment_impl.go @@ -13,14 +13,16 @@ import ( ) // NewAttachmentService returns a new Confluence V2 Page service -func NewAttachmentService(client service.Connector) *AttachmentService { +func NewAttachmentService(client service.Connector, version *AttachmentVersionService) *AttachmentService { return &AttachmentService{ internalClient: &internalAttachmentImpl{c: client}, + Version: version, } } type AttachmentService struct { internalClient confluence.AttachmentConnector + Version *AttachmentVersionService } // Get returns a specific attachment. @@ -51,10 +53,35 @@ func (a *AttachmentService) Gets(ctx context.Context, entityID int, entityType s return a.internalClient.Gets(ctx, entityID, entityType, options, cursor, limit) } +// Delete deletes an attachment by id. +// +// DELETE /wiki/api/v2/attachments/{id} +// +// https://docs.go-atlassian.io/confluence-cloud/v2/attachments#delete-attachment +func (a *AttachmentService) Delete(ctx context.Context, attachmentID string) (*model.ResponseScheme, error) { + return a.internalClient.Delete(ctx, attachmentID) +} + type internalAttachmentImpl struct { c service.Connector } +func (i *internalAttachmentImpl) Delete(ctx context.Context, attachmentID string) (*model.ResponseScheme, error) { + + if attachmentID == "" { + return nil, model.ErrNoContentAttachmentIDError + } + + endpoint := fmt.Sprintf("wiki/api/v2/attachments/%v", attachmentID) + + request, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil) + if err != nil { + return nil, err + } + + return i.c.Call(request, nil) +} + func (i *internalAttachmentImpl) Get(ctx context.Context, attachmentID string, versionID int, serializeIDs bool) (*model.AttachmentScheme, *model.ResponseScheme, error) { if attachmentID == "" { diff --git a/confluence/internal/attachment_impl_test.go b/confluence/internal/attachment_impl_test.go index 3ef3cdbe..42288262 100644 --- a/confluence/internal/attachment_impl_test.go +++ b/confluence/internal/attachment_impl_test.go @@ -104,7 +104,7 @@ func Test_internalAttachmentImpl_Get(t *testing.T) { testCase.on(&testCase.fields) } - attachmentService := NewAttachmentService(testCase.fields.c) + attachmentService := NewAttachmentService(testCase.fields.c, nil) gotResult, gotResponse, err := attachmentService.Get(testCase.args.ctx, testCase.args.attachmentID, testCase.args.versionID, testCase.args.serializeIDs) @@ -248,7 +248,7 @@ func Test_internalAttachmentImpl_Gets(t *testing.T) { testCase.on(&testCase.fields) } - attachmentService := NewAttachmentService(testCase.fields.c) + attachmentService := NewAttachmentService(testCase.fields.c, nil) gotResult, gotResponse, err := attachmentService.Gets(testCase.args.ctx, testCase.args.entityID, testCase.args.entityType, testCase.args.options, testCase.args.cursor, testCase.args.limit) @@ -271,3 +271,112 @@ func Test_internalAttachmentImpl_Gets(t *testing.T) { }) } } + +func Test_internalAttachmentImpl_Delete(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + attachmentID string + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + attachmentID: "att10001", + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodDelete, + "wiki/api/v2/attachments/att10001", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + nil). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + attachmentID: "att10001", + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodDelete, + "wiki/api/v2/attachments/att10001", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the attachment id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoContentAttachmentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + attachmentService := NewAttachmentService(testCase.fields.c, nil) + + gotResponse, err := attachmentService.Delete(testCase.args.ctx, testCase.args.attachmentID) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + } + + }) + } +} diff --git a/confluence/internal/attachment_version_impl.go b/confluence/internal/attachment_version_impl.go new file mode 100644 index 00000000..b344d8ff --- /dev/null +++ b/confluence/internal/attachment_version_impl.go @@ -0,0 +1,100 @@ +package internal + +import ( + "context" + "fmt" + model "github.com/ctreminiom/go-atlassian/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/service" + "github.com/ctreminiom/go-atlassian/service/confluence" + "net/http" + "net/url" + "strconv" +) + +// NewAttachmentVersionService returns a new Confluence V2 Attachment Version service +func NewAttachmentVersionService(client service.Connector) *AttachmentVersionService { + return &AttachmentVersionService{ + internalClient: &internalAttachmentVersionImpl{c: client}, + } +} + +type AttachmentVersionService struct { + internalClient confluence.AttachmentVersionConnector +} + +// Gets returns the versions of specific attachment. +// +// GET /wiki/api/v2/attachments/{id}/versions +// +// https://docs.go-atlassian.io/confluence-cloud/v2/attachments/versions#get-attachment-versions +func (a *AttachmentVersionService) Gets(ctx context.Context, attachmentID, cursor, sort string, limit int) (*model.AttachmentVersionPageScheme, *model.ResponseScheme, error) { + return a.internalClient.Gets(ctx, attachmentID, cursor, sort, limit) +} + +// Get retrieves version details for the specified attachment and version number. +// +// GET /wiki/api/v2/attachments/{attachment-id}/versions/{version-number} +// +// https://docs.go-atlassian.io/confluence-cloud/v2/attachments/versions#get-attachment-version +func (a *AttachmentVersionService) Get(ctx context.Context, attachmentID string, versionID int) (*model.DetailedVersionScheme, *model.ResponseScheme, error) { + return a.internalClient.Get(ctx, attachmentID, versionID) +} + +type internalAttachmentVersionImpl struct { + c service.Connector +} + +func (i *internalAttachmentVersionImpl) Gets(ctx context.Context, attachmentID, cursor, sort string, limit int) (*model.AttachmentVersionPageScheme, *model.ResponseScheme, error) { + + if attachmentID == "" { + return nil, nil, model.ErrNoContentAttachmentIDError + } + + query := url.Values{} + query.Add("limit", strconv.Itoa(limit)) + + if cursor != "" { + query.Add("cursor", cursor) + } + + if sort != "" { + query.Add("sort", sort) + } + + endpoint := fmt.Sprintf("wiki/api/v2/attachments/%v/versions?%v", attachmentID, query.Encode()) + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil) + if err != nil { + return nil, nil, err + } + + page := new(model.AttachmentVersionPageScheme) + response, err := i.c.Call(request, page) + if err != nil { + return nil, response, err + } + + return page, response, nil +} + +func (i *internalAttachmentVersionImpl) Get(ctx context.Context, attachmentID string, versionID int) (*model.DetailedVersionScheme, *model.ResponseScheme, error) { + + if attachmentID == "" { + return nil, nil, model.ErrNoContentAttachmentIDError + } + + endpoint := fmt.Sprintf("wiki/api/v2/attachments/%v/versions/%v", attachmentID, versionID) + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil) + if err != nil { + return nil, nil, err + } + + version := new(model.DetailedVersionScheme) + response, err := i.c.Call(request, version) + if err != nil { + return nil, response, err + } + + return version, response, nil +} diff --git a/confluence/internal/attachment_version_impl_test.go b/confluence/internal/attachment_version_impl_test.go new file mode 100644 index 00000000..c3cbcacf --- /dev/null +++ b/confluence/internal/attachment_version_impl_test.go @@ -0,0 +1,243 @@ +package internal + +import ( + "context" + "errors" + model "github.com/ctreminiom/go-atlassian/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/service" + "github.com/ctreminiom/go-atlassian/service/mocks" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func Test_internalAttachmentVersionImpl_Gets(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + attachmentID, cursor, sort string + limit int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + attachmentID: "100001", + sort: "-modified-date", + cursor: "uuid-sample", + limit: 100, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/attachments/100001/versions?cursor=uuid-sample&limit=100&sort=-modified-date", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.AttachmentVersionPageScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + attachmentID: "100001", + sort: "-modified-date", + cursor: "uuid-sample", + limit: 100, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/attachments/100001/versions?cursor=uuid-sample&limit=100&sort=-modified-date", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the attachment id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoContentAttachmentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + attachmentService := NewAttachmentVersionService(testCase.fields.c) + + gotResult, gotResponse, err := attachmentService.Gets(testCase.args.ctx, testCase.args.attachmentID, testCase.args.cursor, + testCase.args.sort, testCase.args.limit) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} + +func Test_internalAttachmentVersionImpl_Get(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + attachmentID string + versionID int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + attachmentID: "100001", + versionID: 10002, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/attachments/100001/versions/10002", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.DetailedVersionScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + attachmentID: "100001", + versionID: 10002, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/attachments/100001/versions/10002", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the attachment id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoContentAttachmentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + attachmentService := NewAttachmentVersionService(testCase.fields.c) + + gotResult, gotResponse, err := attachmentService.Get(testCase.args.ctx, testCase.args.attachmentID, testCase.args.versionID) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} diff --git a/confluence/internal/custom_content_impl.go b/confluence/internal/custom_content_impl.go new file mode 100644 index 00000000..b5489ac9 --- /dev/null +++ b/confluence/internal/custom_content_impl.go @@ -0,0 +1,231 @@ +package internal + +import ( + "context" + "fmt" + model "github.com/ctreminiom/go-atlassian/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/service" + "github.com/ctreminiom/go-atlassian/service/confluence" + "net/http" + "net/url" + "strconv" + "strings" +) + +func NewCustomContentService(client service.Connector) *CustomContentService { + + return &CustomContentService{ + internalClient: &internalCustomContentServiceImpl{c: client}, + } +} + +type CustomContentService struct { + internalClient confluence.CustomContentConnector +} + +// Gets returns all custom content for a given type. +// +// GET /wiki/api/v2/custom-content +// +// https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#get-custom-content-by-type +func (c *CustomContentService) Gets(ctx context.Context, type_ string, options *model.CustomContentOptionsScheme, cursor string, limit int) (*model.CustomContentPageScheme, *model.ResponseScheme, error) { + return c.internalClient.Gets(ctx, type_, options, cursor, limit) +} + +// Create creates a new custom content in the given space, page, blogpost or other custom content. +// +// POST /wiki/api/v2/custom-content +// +// https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#create-custom-content +func (c *CustomContentService) Create(ctx context.Context, payload *model.CustomContentPayloadScheme) (*model.CustomContentScheme, *model.ResponseScheme, error) { + return c.internalClient.Create(ctx, payload) +} + +// Get returns a specific piece of custom content. +// +// GET /wiki/api/v2/custom-content/{id} +// +// https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#get-custom-content-by-id +func (c *CustomContentService) Get(ctx context.Context, customContentID int, format string, versionID int) (*model.CustomContentScheme, *model.ResponseScheme, error) { + return c.internalClient.Get(ctx, customContentID, format, versionID) +} + +// Update updates a custom content by id. +// +// The spaceId is always required and maximum one of pageId, blogPostId, +// +// or customContentId is allowed in the request body +// +// PUT /wiki/api/v2/custom-content/{id} +// +// https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#update-custom-content +func (c *CustomContentService) Update(ctx context.Context, customContentID int, payload *model.CustomContentPayloadScheme) (*model.CustomContentScheme, *model.ResponseScheme, error) { + return c.internalClient.Update(ctx, customContentID, payload) +} + +// Delete deletes a custom content by id. +// +// DELETE /wiki/api/v2/custom-content/{id} +// +// https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#delete-custom-content +func (c *CustomContentService) Delete(ctx context.Context, customContentID int) (*model.ResponseScheme, error) { + return c.internalClient.Delete(ctx, customContentID) +} + +type internalCustomContentServiceImpl struct { + c service.Connector +} + +func (i *internalCustomContentServiceImpl) Gets(ctx context.Context, type_ string, options *model.CustomContentOptionsScheme, cursor string, limit int) (*model.CustomContentPageScheme, *model.ResponseScheme, error) { + + if type_ == "" { + return nil, nil, model.ErrNoCustomContentTypeError + } + + query := url.Values{} + query.Add("limit", strconv.Itoa(limit)) + + if cursor != "" { + query.Add("cursor", cursor) + } + + if options != nil { + + if len(options.IDs) != 0 { + + var ids []string + for _, id := range options.IDs { + ids = append(ids, strconv.Itoa(id)) + } + + query.Add("id", strings.Join(ids, ",")) + } + + if len(options.SpaceIDs) != 0 { + + var ids []string + for _, id := range options.IDs { + ids = append(ids, strconv.Itoa(id)) + } + + query.Add("space-id", strings.Join(ids, ",")) + } + + if options.Sort != "" { + query.Add("sort", options.Sort) + } + + if options.BodyFormat != "" { + query.Add("body-format", options.BodyFormat) + } + } + + endpoint := fmt.Sprintf("wiki/api/v2/custom-content?%v", query.Encode()) + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil) + if err != nil { + return nil, nil, err + } + + page := new(model.CustomContentPageScheme) + response, err := i.c.Call(request, page) + if err != nil { + return nil, response, err + } + + return page, response, nil +} + +func (i *internalCustomContentServiceImpl) Create(ctx context.Context, payload *model.CustomContentPayloadScheme) (*model.CustomContentScheme, *model.ResponseScheme, error) { + + endpoint := "wiki/api/v2/custom-content" + + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + customContent := new(model.CustomContentScheme) + response, err := i.c.Call(request, customContent) + if err != nil { + return nil, response, err + } + + return customContent, response, nil +} + +func (i *internalCustomContentServiceImpl) Get(ctx context.Context, customContentID int, format string, versionID int) (*model.CustomContentScheme, *model.ResponseScheme, error) { + + if customContentID == 0 { + return nil, nil, model.ErrNoCustomContentIDError + } + + query := url.Values{} + + if format != "" { + query.Add("body-format", format) + } + + if versionID != 0 { + query.Add("version", strconv.Itoa(versionID)) + } + + var endpoint strings.Builder + endpoint.WriteString(fmt.Sprintf("wiki/api/v2/custom-content/%v", customContentID)) + + if query.Encode() != "" { + endpoint.WriteString(fmt.Sprintf("?%v", query.Encode())) + } + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), "", nil) + if err != nil { + return nil, nil, err + } + + customContent := new(model.CustomContentScheme) + response, err := i.c.Call(request, customContent) + if err != nil { + return nil, response, err + } + + return customContent, response, nil +} + +func (i *internalCustomContentServiceImpl) Update(ctx context.Context, customContentID int, payload *model.CustomContentPayloadScheme) (*model.CustomContentScheme, *model.ResponseScheme, error) { + + if customContentID == 0 { + return nil, nil, model.ErrNoCustomContentIDError + } + + endpoint := fmt.Sprintf("wiki/api/v2/custom-content/%v", customContentID) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + customContent := new(model.CustomContentScheme) + response, err := i.c.Call(request, customContent) + if err != nil { + return nil, response, err + } + + return customContent, response, nil + +} + +func (i *internalCustomContentServiceImpl) Delete(ctx context.Context, customContentID int) (*model.ResponseScheme, error) { + + if customContentID == 0 { + return nil, model.ErrNoCustomContentIDError + } + + endpoint := fmt.Sprintf("wiki/api/v2/custom-content/%v", customContentID) + + request, err := i.c.NewRequest(ctx, http.MethodDelete, endpoint, "", nil) + if err != nil { + return nil, err + } + + return i.c.Call(request, nil) +} diff --git a/confluence/internal/custom_content_impl_test.go b/confluence/internal/custom_content_impl_test.go new file mode 100644 index 00000000..2211a534 --- /dev/null +++ b/confluence/internal/custom_content_impl_test.go @@ -0,0 +1,623 @@ +package internal + +import ( + "context" + "errors" + model "github.com/ctreminiom/go-atlassian/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/service" + "github.com/ctreminiom/go-atlassian/service/mocks" + "github.com/stretchr/testify/assert" + "net/http" + "testing" +) + +func Test_internalCustomContentServiceImpl_Gets(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + type_ string + options *model.CustomContentOptionsScheme + cursor string + limit int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + type_: "custom_content_type_id", + options: &model.CustomContentOptionsScheme{ + IDs: []int{101, 102}, + SpaceIDs: []int{10001, 10002}, + Sort: "created-date", + BodyFormat: "atlas_doc_format", + }, + cursor: "cursor-id", + limit: 200, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/custom-content?body-format=atlas_doc_format&cursor=cursor-id&id=101%2C102&limit=200&sort=created-date&space-id=101%2C102", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.CustomContentPageScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + type_: "custom_content_type_id", + options: &model.CustomContentOptionsScheme{ + IDs: []int{101, 102}, + SpaceIDs: []int{10001, 10002}, + Sort: "created-date", + BodyFormat: "atlas_doc_format", + }, + cursor: "cursor-id", + limit: 200, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/custom-content?body-format=atlas_doc_format&cursor=cursor-id&id=101%2C102&limit=200&sort=created-date&space-id=101%2C102", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the type is not provided are correct", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoCustomContentTypeError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewCustomContentService(testCase.fields.c) + + gotResult, gotResponse, err := newService.Gets( + testCase.args.ctx, + testCase.args.type_, + testCase.args.options, + testCase.args.cursor, + testCase.args.limit, + ) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} + +func Test_internalCustomContentServiceImpl_Create(t *testing.T) { + + payloadMocked := &model.CustomContentPayloadScheme{ + Type: "", + Status: "", + PageID: "", + CustomContentID: "", + Title: "", + Body: &model.BodyTypeScheme{ + Representation: "", + Value: "", + }, + } + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + payload *model.CustomContentPayloadScheme + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + payload: payloadMocked, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodPost, + "wiki/api/v2/custom-content", + "", payloadMocked). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.CustomContentScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + payload: payloadMocked, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodPost, + "wiki/api/v2/custom-content", + "", payloadMocked). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewCustomContentService(testCase.fields.c) + + gotResult, gotResponse, err := newService.Create( + testCase.args.ctx, + testCase.args.payload, + ) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} + +func Test_internalCustomContentServiceImpl_Update(t *testing.T) { + + payloadMocked := &model.CustomContentPayloadScheme{ + Type: "", + Status: "", + PageID: "", + CustomContentID: "", + Title: "", + Body: &model.BodyTypeScheme{ + Representation: "", + Value: "", + }, + Version: &model.CustomContentPayloadVersionScheme{ + Number: 1, + Message: "message sample", + }, + } + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + customContentID int + payload *model.CustomContentPayloadScheme + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + payload: payloadMocked, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "wiki/api/v2/custom-content/10001", + "", payloadMocked). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.CustomContentScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + payload: payloadMocked, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "wiki/api/v2/custom-content/10001", + "", payloadMocked). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the custom content id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoCustomContentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewCustomContentService(testCase.fields.c) + + gotResult, gotResponse, err := newService.Update( + testCase.args.ctx, + testCase.args.customContentID, + testCase.args.payload, + ) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} + +func Test_internalCustomContentServiceImpl_Delete(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + customContentID int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodDelete, + "wiki/api/v2/custom-content/10001", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + nil). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodDelete, + "wiki/api/v2/custom-content/10001", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the custom content id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoCustomContentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewCustomContentService(testCase.fields.c) + + gotResponse, err := newService.Delete( + testCase.args.ctx, + testCase.args.customContentID) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + } + + }) + } +} + +func Test_internalCustomContentServiceImpl_Get(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + customContentID int + format string + versionID int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + format: "anonymous_export_view", + versionID: 2, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/custom-content/10001?body-format=anonymous_export_view&version=2", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.CustomContentScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + customContentID: 10001, + format: "anonymous_export_view", + versionID: 2, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/custom-content/10001?body-format=anonymous_export_view&version=2", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + + { + name: "when the custom content id is not provided", + args: args{ + ctx: context.TODO(), + }, + wantErr: true, + Err: model.ErrNoCustomContentIDError, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewCustomContentService(testCase.fields.c) + + gotResult, gotResponse, err := newService.Get( + testCase.args.ctx, + testCase.args.customContentID, + testCase.args.format, + testCase.args.versionID, + ) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} diff --git a/confluence/internal/space_v2_impl.go b/confluence/internal/space_v2_impl.go index f248d482..9d2da516 100644 --- a/confluence/internal/space_v2_impl.go +++ b/confluence/internal/space_v2_impl.go @@ -40,6 +40,13 @@ func (s *SpaceV2Service) Get(ctx context.Context, spaceID int, descriptionFormat return s.internalClient.Get(ctx, spaceID, descriptionFormat) } +// Permissions returns space permissions for a specific space. +// +// GET /wiki/api/v2/spaces/{id}/permissions +func (s *SpaceV2Service) Permissions(ctx context.Context, spaceID int, cursor string, limit int) (*model.SpacePermissionPageScheme, *model.ResponseScheme, error) { + return s.internalClient.Permissions(ctx, spaceID, cursor, limit) +} + func NewSpaceV2Service(client service.Connector) *SpaceV2Service { return &SpaceV2Service{ @@ -51,6 +58,35 @@ type internalSpaceV2Impl struct { c service.Connector } +func (i *internalSpaceV2Impl) Permissions(ctx context.Context, spaceID int, cursor string, limit int) (*model.SpacePermissionPageScheme, *model.ResponseScheme, error) { + + if spaceID == 0 { + return nil, nil, model.ErrNoSpaceIDError + } + + query := url.Values{} + query.Add("limit", strconv.Itoa(limit)) + + if cursor != "" { + query.Add("cursor", cursor) + } + + endpoint := fmt.Sprintf("wiki/api/v2/spaces/%v/permissions?%v", spaceID, query.Encode()) + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, "", nil) + if err != nil { + return nil, nil, err + } + + chunk := new(model.SpacePermissionPageScheme) + response, err := i.c.Call(request, chunk) + if err != nil { + return nil, response, err + } + + return chunk, response, nil +} + func (i *internalSpaceV2Impl) Bulk(ctx context.Context, options *model.GetSpacesOptionSchemeV2, cursor string, limit int) (*model.SpaceChunkV2Scheme, *model.ResponseScheme, error) { query := url.Values{} diff --git a/confluence/internal/space_v2_impl_test.go b/confluence/internal/space_v2_impl_test.go index f99af064..51484dd0 100644 --- a/confluence/internal/space_v2_impl_test.go +++ b/confluence/internal/space_v2_impl_test.go @@ -242,3 +242,111 @@ func Test_internalSpaceV2Impl_Get(t *testing.T) { }) } } + +func Test_internalSpaceV2Impl_Permissions(t *testing.T) { + + type fields struct { + c service.Connector + } + + type args struct { + ctx context.Context + spaceID int + cursor string + limit int + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the parameters are correct", + args: args{ + ctx: context.TODO(), + spaceID: 10001, + cursor: "cursor_sample_uuid", + limit: 50, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/spaces/10001/permissions?cursor=cursor_sample_uuid&limit=50", + "", nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.SpacePermissionPageScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + + }, + }, + + { + name: "when the http request cannot be created", + args: args{ + ctx: context.TODO(), + spaceID: 10001, + cursor: "cursor_sample_uuid", + limit: 50, + }, + on: func(fields *fields) { + + client := mocks.NewConnector(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "wiki/api/v2/spaces/10001/permissions?cursor=cursor_sample_uuid&limit=50", + "", nil). + Return(&http.Request{}, errors.New("error, unable to create the http request")) + + fields.c = client + + }, + wantErr: true, + Err: errors.New("error, unable to create the http request"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + newService := NewSpaceV2Service(testCase.fields.c) + + gotResult, gotResponse, err := newService.Permissions(testCase.args.ctx, testCase.args.spaceID, testCase.args.cursor, + testCase.args.limit) + + if testCase.wantErr { + + if err != nil { + t.Logf("error returned: %v", err.Error()) + } + + assert.EqualError(t, err, testCase.Err.Error()) + + } else { + + assert.NoError(t, err) + assert.NotEqual(t, gotResponse, nil) + assert.NotEqual(t, gotResult, nil) + } + + }) + } +} diff --git a/confluence/v2/api_client_impl.go b/confluence/v2/api_client_impl.go index 508a6630..df4e1b92 100644 --- a/confluence/v2/api_client_impl.go +++ b/confluence/v2/api_client_impl.go @@ -41,18 +41,20 @@ func New(httpClient common.HttpClient, site string) (*Client, error) { client.Auth = internal.NewAuthenticationService(client) client.Page = internal.NewPageService(client) client.Space = internal.NewSpaceV2Service(client) - client.Attachment = internal.NewAttachmentService(client) + client.Attachment = internal.NewAttachmentService(client, internal.NewAttachmentVersionService(client)) + client.CustomContent = internal.NewCustomContentService(client) return client, nil } type Client struct { - HTTP common.HttpClient - Site *url.URL - Auth common.Authentication - Page *internal.PageService - Space *internal.SpaceV2Service - Attachment *internal.AttachmentService + HTTP common.HttpClient + Site *url.URL + Auth common.Authentication + Page *internal.PageService + Space *internal.SpaceV2Service + Attachment *internal.AttachmentService + CustomContent *internal.CustomContentService } func (c *Client) NewRequest(ctx context.Context, method, urlStr, type_ string, body interface{}) (*http.Request, error) { diff --git a/pkg/infra/models/confluence_attachment.go b/pkg/infra/models/confluence_attachment.go index 93d2e2c2..c63c3e79 100644 --- a/pkg/infra/models/confluence_attachment.go +++ b/pkg/infra/models/confluence_attachment.go @@ -18,11 +18,17 @@ type AttachmentScheme struct { } type AttachmentVersionScheme struct { - CreatedAt string `json:"createdAt,omitempty"` - Message string `json:"message,omitempty"` - Number int `json:"number,omitempty"` - MinorEdit bool `json:"minorEdit,omitempty"` - AuthorID string `json:"authorId,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + Message string `json:"message,omitempty"` + Number int `json:"number,omitempty"` + MinorEdit bool `json:"minorEdit,omitempty"` + AuthorID string `json:"authorId,omitempty"` + Attachment *AttachmentVersionBodyScheme `json:"attachment,omitempty"` +} + +type AttachmentVersionBodyScheme struct { + Title string `json:"title,omitempty"` + ID string `json:"id,omitempty"` } type AttachmentParamsScheme struct { @@ -45,10 +51,27 @@ type AttachmentParamsScheme struct { } type AttachmentPageScheme struct { - Results []*AttachmentScheme `json:"results,omitempty"` - Links *AttachmentPageLinksScheme `json:"_links,omitempty"` + Results []*AttachmentScheme `json:"results,omitempty"` + Links *PageLinkScheme `json:"_links,omitempty"` } -type AttachmentPageLinksScheme struct { +type PageLinkScheme struct { Next string `json:"next,omitempty"` } + +type AttachmentVersionPageScheme struct { + Results []*AttachmentVersionScheme `json:"results,omitempty"` + Links *PageLinkScheme `json:"_links,omitempty"` +} + +type DetailedVersionScheme struct { + Number int `json:"number,omitempty"` + AuthorID string `json:"authorId,omitempty"` + Message string `json:"message,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + MinorEdit bool `json:"minorEdit,omitempty"` + ContentTypeModified bool `json:"contentTypeModified,omitempty"` + Collaborators []string `json:"collaborators,omitempty"` + PrevVersion int `json:"prevVersion,omitempty"` + NextVersion int `json:"nextVersion,omitempty"` +} diff --git a/pkg/infra/models/confluence_custom_content.go b/pkg/infra/models/confluence_custom_content.go new file mode 100644 index 00000000..3c7eac8a --- /dev/null +++ b/pkg/infra/models/confluence_custom_content.go @@ -0,0 +1,74 @@ +package models + +type CustomContentOptionsScheme struct { + IDs []int + SpaceIDs []int + Sort string + BodyFormat string +} + +type CustomContentPageScheme struct { + Results []*CustomContentScheme `json:"results,omitempty"` + Links *CustomContentPageLinksScheme `json:"_links,omitempty"` +} + +type CustomContentPageLinksScheme struct { + Next string `json:"next,omitempty"` +} + +type CustomContentScheme struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Status string `json:"status,omitempty"` + Title string `json:"title,omitempty"` + SpaceID string `json:"spaceId,omitempty"` + PageID string `json:"pageId,omitempty"` + BlogPostID string `json:"blogPostId,omitempty"` + CustomContentID string `json:"customContentId,omitempty"` + AuthorID string `json:"authorId,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + Version *CustomContentVersionScheme `json:"version,omitempty"` + Body *CustomContentBodyScheme `json:"body,omitempty"` + Links *CustomContentLinksScheme `json:"_links,omitempty"` +} + +type CustomContentVersionScheme struct { + CreatedAt string `json:"createdAt,omitempty"` + Message string `json:"message,omitempty"` + Number int `json:"number,omitempty"` + MinorEdit bool `json:"minorEdit,omitempty"` + AuthorID string `json:"authorId,omitempty"` +} + +type CustomContentBodyScheme struct { + Raw *BodyTypeScheme `json:"raw,omitempty"` + Storage *BodyTypeScheme `json:"storage,omitempty"` + AtlasDocFormat *BodyTypeScheme `json:"atlas_doc_format,omitempty"` +} + +type CustomContentLinksScheme struct { + Webui string `json:"webui,omitempty"` +} + +type BodyTypeScheme struct { + Representation string `json:"representation,omitempty"` + Value string `json:"value,omitempty"` +} + +type CustomContentPayloadScheme struct { + ID string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Status string `json:"status,omitempty"` + SpaceID string `json:"spaceId,omitempty"` + PageID string `json:"pageId,omitempty"` + BlogPostID string `json:"blogPostId,omitempty"` + CustomContentID string `json:"customContentId,omitempty"` + Title string `json:"title,omitempty"` + Body *BodyTypeScheme `json:"body,omitempty"` + Version *CustomContentPayloadVersionScheme `json:"version,omitempty"` +} + +type CustomContentPayloadVersionScheme struct { + Number int `json:"number,omitempty"` + Message string `json:"message,omitempty"` +} diff --git a/pkg/infra/models/confluence_space_v2.go b/pkg/infra/models/confluence_space_v2.go index 3974d4a5..3186af00 100644 --- a/pkg/infra/models/confluence_space_v2.go +++ b/pkg/infra/models/confluence_space_v2.go @@ -36,3 +36,28 @@ type SpaceDescriptionSchemeV2 struct { Plain *PageBodyRepresentationScheme `json:"plain,omitempty"` View *PageBodyRepresentationScheme `json:"view,omitempty"` } + +type SpacePermissionPageScheme struct { + Results []*SpacePermissionsV2Scheme `json:"results,omitempty"` + Links *SpacePermissionPageLinkScheme `json:"_links,omitempty"` +} + +type SpacePermissionsV2Scheme struct { + ID string `json:"id"` + Principal *SpacePermissionsPrincipalScheme `json:"principal"` + Operation *SpacePermissionsOperationScheme `json:"operation"` +} + +type SpacePermissionsPrincipalScheme struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` +} + +type SpacePermissionsOperationScheme struct { + Key string `json:"key,omitempty"` + TargetType string `json:"targetType,omitempty"` +} + +type SpacePermissionPageLinkScheme struct { + Next string `json:"next,omitempty"` +} diff --git a/pkg/infra/models/errors.go b/pkg/infra/models/errors.go index 70554537..f69f1cd1 100644 --- a/pkg/infra/models/errors.go +++ b/pkg/infra/models/errors.go @@ -36,6 +36,8 @@ var ( ErrNoContentAttachmentNameError = errors.New("confluence: no attachment filename set") ErrNoContentReaderError = errors.New("confluence: no reader set") ErrNoContentIDError = errors.New("confluence: no content id set") + ErrNoCustomContentTypeError = errors.New("confluence: no custom content type set") + ErrNoCustomContentIDError = errors.New("confluence: no custom content id set") ErrNoPageIDError = errors.New("confluence: no page id set") ErrNoSpaceIDError = errors.New("confluence: no space id set") ErrNoTargetIDError = errors.New("confluence: no target id set") diff --git a/service/confluence/attachment.go b/service/confluence/attachment.go index 8fd5c2cd..5989b1df 100644 --- a/service/confluence/attachment.go +++ b/service/confluence/attachment.go @@ -65,4 +65,28 @@ type AttachmentConnector interface { // // https://docs.go-atlassian.io/confluence-cloud/v2/attachments#get-attachments-by-type Gets(ctx context.Context, entityID int, entityType string, options *model.AttachmentParamsScheme, cursor string, limit int) (*model.AttachmentPageScheme, *model.ResponseScheme, error) + + // Delete deletes an attachment by id. + // + // DELETE /wiki/api/v2/attachments/{id} + // + // https://docs.go-atlassian.io/confluence-cloud/v2/attachments#delete-attachment + Delete(ctx context.Context, attachmentID string) (*model.ResponseScheme, error) +} + +type AttachmentVersionConnector interface { + + // Gets returns the versions of specific attachment. + // + // GET /wiki/api/v2/attachments/{id}/versions + // + // https://docs.go-atlassian.io/confluence-cloud/v2/attachments/versions#get-attachment-versions + Gets(ctx context.Context, attachmentID, cursor, sort string, limit int) (*model.AttachmentVersionPageScheme, *model.ResponseScheme, error) + + // Get retrieves version details for the specified attachment and version number. + // + // GET /wiki/api/v2/attachments/{attachment-id}/versions/{version-number} + // + // https://docs.go-atlassian.io/confluence-cloud/v2/attachments/versions#get-attachment-version + Get(ctx context.Context, attachmentID string, versionID int) (*model.DetailedVersionScheme, *model.ResponseScheme, error) } diff --git a/service/confluence/custom-content.go b/service/confluence/custom-content.go new file mode 100644 index 00000000..6ae411c7 --- /dev/null +++ b/service/confluence/custom-content.go @@ -0,0 +1,49 @@ +package confluence + +import ( + "context" + "github.com/ctreminiom/go-atlassian/pkg/infra/models" +) + +type CustomContentConnector interface { + + // Gets returns all custom content for a given type. + // + // GET /wiki/api/v2/custom-content + // + // https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#get-custom-content-by-type + Gets(ctx context.Context, type_ string, options *models.CustomContentOptionsScheme, cursor string, limit int) ( + *models.CustomContentPageScheme, *models.ResponseScheme, error) + + // Create creates a new custom content in the given space, page, blogpost or other custom content. + // + // POST /wiki/api/v2/custom-content + // + // https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#create-custom-content + Create(ctx context.Context, payload *models.CustomContentPayloadScheme) (*models.CustomContentScheme, *models.ResponseScheme, error) + + // Get returns a specific piece of custom content. + // + // GET /wiki/api/v2/custom-content/{id} + // + // https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#get-custom-content-by-id + Get(ctx context.Context, customContentID int, format string, versionID int) (*models.CustomContentScheme, *models.ResponseScheme, error) + + // Update updates a custom content by id. + // + // The spaceId is always required and maximum one of pageId, blogPostId, + // + // or customContentId is allowed in the request body + // + // PUT /wiki/api/v2/custom-content/{id} + // + // https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#update-custom-content + Update(ctx context.Context, customContentID int, payload *models.CustomContentPayloadScheme) (*models.CustomContentScheme, *models.ResponseScheme, error) + + // Delete deletes a custom content by id. + // + // DELETE /wiki/api/v2/custom-content/{id} + // + // https://docs.go-atlassian.io/confluence-cloud/v2/custom-content#delete-custom-content + Delete(ctx context.Context, customContentID int) (*models.ResponseScheme, error) +} diff --git a/service/confluence/space.go b/service/confluence/space.go index f624363f..12fbfaf4 100644 --- a/service/confluence/space.go +++ b/service/confluence/space.go @@ -26,6 +26,11 @@ type SpaceV2Connector interface { // // https://docs.go-atlassian.io/confluence-cloud/v2/space#get-space-by-id Get(ctx context.Context, spaceID int, descriptionFormat string) (*model.SpaceSchemeV2, *model.ResponseScheme, error) + + // Permissions returns space permissions for a specific space. + // + // GET /wiki/api/v2/spaces/{id}/permissions + Permissions(ctx context.Context, spaceID int, cursor string, limit int) (*model.SpacePermissionPageScheme, *model.ResponseScheme, error) } type SpaceConnector interface {