diff --git a/jira/internal/announcement_banner_impl.go b/jira/internal/announcement_banner_impl.go new file mode 100644 index 00000000..cc3afb6f --- /dev/null +++ b/jira/internal/announcement_banner_impl.go @@ -0,0 +1,79 @@ +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/jira" + "net/http" +) + +func NewAnnouncementBannerService(client service.Client, version string) *AnnouncementBannerService { + + return &AnnouncementBannerService{ + internalClient: &internalAnnouncementBannerImpl{c: client, version: version}, + } +} + +type AnnouncementBannerService struct { + internalClient jira.AnnouncementBannerConnector +} + +// Get returns the current announcement banner configuration. +// +// GET /rest/api/{2-3}/announcementBanner +// +// https://docs.go-atlassian.io/jira-software-cloud/announcement-banner#get-announcement-banner-configuration +func (a *AnnouncementBannerService) Get(ctx context.Context) (*model.AnnouncementBannerScheme, *model.ResponseScheme, error) { + return a.internalClient.Get(ctx) +} + +// Update updates the announcement banner configuration. +// +// PUT /rest/api/{2-3}/announcementBanner +// +// https://docs.go-atlassian.io/jira-software-cloud/announcement-banner#get-announcement-banner-configuration +func (a *AnnouncementBannerService) Update(ctx context.Context, payload *model.AnnouncementBannerPayloadScheme) (*model.ResponseScheme, error) { + return a.internalClient.Update(ctx, payload) +} + +type internalAnnouncementBannerImpl struct { + c service.Client + version string +} + +func (i *internalAnnouncementBannerImpl) Get(ctx context.Context) (*model.AnnouncementBannerScheme, *model.ResponseScheme, error) { + + endpoint := fmt.Sprintf("rest/api/%v/announcementBanner", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint, nil) + if err != nil { + return nil, nil, err + } + + banner := new(model.AnnouncementBannerScheme) + response, err := i.c.Call(request, banner) + if err != nil { + return nil, response, err + } + + return banner, response, nil +} + +func (i *internalAnnouncementBannerImpl) Update(ctx context.Context, payload *model.AnnouncementBannerPayloadScheme) (*model.ResponseScheme, error) { + + reader, err := i.c.TransformStructToReader(payload) + if err != nil { + return nil, err + } + + endpoint := fmt.Sprintf("rest/api/%v/announcementBanner", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, reader) + if err != nil { + return nil, err + } + + return i.c.Call(request, nil) +} diff --git a/jira/internal/announcement_banner_impl_test.go b/jira/internal/announcement_banner_impl_test.go new file mode 100644 index 00000000..066e45d5 --- /dev/null +++ b/jira/internal/announcement_banner_impl_test.go @@ -0,0 +1,336 @@ +package internal + +import ( + "bytes" + "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_internalAnnouncementBannerImpl_Get(t *testing.T) { + + type fields struct { + c service.Client + version string + } + + type args struct { + ctx context.Context + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the api version is v2", + args: args{ + ctx: context.Background(), + }, + fields: fields{version: "2"}, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "rest/api/2/announcementBanner", + nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.AnnouncementBannerScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + }, + }, + + { + name: "when the api version is v3", + args: args{ + ctx: context.Background(), + }, + fields: fields{version: "3"}, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "rest/api/3/announcementBanner", + nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.AnnouncementBannerScheme{}). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + }, + }, + + { + name: "when the http request cannot be created", + fields: fields{version: "2"}, + args: args{ + ctx: context.Background(), + }, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "rest/api/2/announcementBanner", + nil). + Return(&http.Request{}, errors.New("unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("unable to create the http request"), + }, + + { + name: "when the http call cannot be executed", + fields: fields{version: "2"}, + args: args{ + ctx: context.Background(), + }, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("NewRequest", + context.Background(), + http.MethodGet, + "rest/api/2/announcementBanner", + nil). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + &model.AnnouncementBannerScheme{}). + Return(&model.ResponseScheme{}, errors.New("error, unable to execute the http call")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to execute the http call"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + bannerService := NewAnnouncementBannerService(testCase.fields.c, testCase.fields.version) + + gotResult, gotResponse, err := bannerService.Get(testCase.args.ctx) + + 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_internalAnnouncementBannerImpl_Update(t *testing.T) { + + payloadMocked := &model.AnnouncementBannerPayloadScheme{ + IsDismissible: false, + IsEnabled: true, + Message: "This is a public, enabled, non-dismissible banner, set using the API", + Visibility: "public", + } + + type fields struct { + c service.Client + version string + } + + type args struct { + ctx context.Context + payload *model.AnnouncementBannerPayloadScheme + } + + testCases := []struct { + name string + fields fields + args args + on func(*fields) + wantErr bool + Err error + }{ + { + name: "when the api version is v2", + args: args{ + ctx: context.Background(), + payload: payloadMocked, + }, + fields: fields{version: "2"}, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("TransformStructToReader", + payloadMocked). + Return(bytes.NewReader([]byte{}), nil) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "rest/api/2/announcementBanner", + bytes.NewReader([]byte{})). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + nil). + Return(&model.ResponseScheme{}, nil) + + fields.c = client + }, + }, + + { + name: "when the api version is v3", + args: args{ + ctx: context.Background(), + payload: payloadMocked, + }, + fields: fields{version: "3"}, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("TransformStructToReader", + payloadMocked). + Return(bytes.NewReader([]byte{}), nil) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "rest/api/3/announcementBanner", + bytes.NewReader([]byte{})). + 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", + fields: fields{version: "2"}, + args: args{ + ctx: context.Background(), + payload: payloadMocked, + }, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("TransformStructToReader", + payloadMocked). + Return(bytes.NewReader([]byte{}), nil) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "rest/api/2/announcementBanner", + bytes.NewReader([]byte{})). + Return(&http.Request{}, errors.New("unable to create the http request")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("unable to create the http request"), + }, + + { + name: "when the http call cannot be executed", + fields: fields{version: "2"}, + args: args{ + ctx: context.Background(), + payload: payloadMocked, + }, + on: func(fields *fields) { + client := mocks.NewClient(t) + + client.On("TransformStructToReader", + payloadMocked). + Return(bytes.NewReader([]byte{}), nil) + + client.On("NewRequest", + context.Background(), + http.MethodPut, + "rest/api/2/announcementBanner", + bytes.NewReader([]byte{})). + Return(&http.Request{}, nil) + + client.On("Call", + &http.Request{}, + nil). + Return(&model.ResponseScheme{}, errors.New("error, unable to execute the http call")) + + fields.c = client + }, + wantErr: true, + Err: errors.New("error, unable to execute the http call"), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + + if testCase.on != nil { + testCase.on(&testCase.fields) + } + + bannerService := NewAnnouncementBannerService(testCase.fields.c, testCase.fields.version) + + gotResponse, err := bannerService.Update(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) + } + }) + } +} diff --git a/jira/v2/api_client_impl.go b/jira/v2/api_client_impl.go index 99c296ad..5c99f528 100644 --- a/jira/v2/api_client_impl.go +++ b/jira/v2/api_client_impl.go @@ -356,6 +356,7 @@ func New(httpClient common.HttpClient, site string) (*Client, error) { client.Permission = permission client.MySelf = mySelf client.Auth = internal.NewAuthenticationService(client) + client.Banner = internal.NewAnnouncementBannerService(client, "2") client.Role = applicationRoleService client.Dashboard = dashboardService client.Filter = filterService @@ -378,6 +379,7 @@ type Client struct { Auth common.Authentication Site *url.URL Role *internal.ApplicationRoleService + Banner *internal.AnnouncementBannerService Audit *internal.AuditRecordService Dashboard *internal.DashboardService Filter *internal.FilterService diff --git a/jira/v3/api_client_impl.go b/jira/v3/api_client_impl.go index 33e14c77..1df18996 100644 --- a/jira/v3/api_client_impl.go +++ b/jira/v3/api_client_impl.go @@ -356,6 +356,7 @@ func New(httpClient common.HttpClient, site string) (*Client, error) { client.Permission = permission client.MySelf = mySelf client.Auth = internal.NewAuthenticationService(client) + client.Banner = internal.NewAnnouncementBannerService(client, "3") client.Role = applicationRoleService client.Dashboard = dashboardService client.Filter = filterService @@ -379,6 +380,7 @@ type Client struct { Site *url.URL Audit *internal.AuditRecordService Role *internal.ApplicationRoleService + Banner *internal.AnnouncementBannerService Dashboard *internal.DashboardService Filter *internal.FilterService Group *internal.GroupService diff --git a/pkg/infra/models/jira_announcement_banner.go b/pkg/infra/models/jira_announcement_banner.go new file mode 100644 index 00000000..b2dedf4c --- /dev/null +++ b/pkg/infra/models/jira_announcement_banner.go @@ -0,0 +1,16 @@ +package models + +type AnnouncementBannerScheme struct { + HashId string `json:"hashId,omitempty"` + IsDismissible bool `json:"isDismissible,omitempty"` + IsEnabled bool `json:"isEnabled,omitempty"` + Message string `json:"message,omitempty"` + Visibility string `json:"visibility,omitempty"` +} + +type AnnouncementBannerPayloadScheme struct { + IsDismissible bool `json:"isDismissible,omitempty"` + IsEnabled bool `json:"isEnabled,omitempty"` + Message string `json:"message,omitempty"` + Visibility string `json:"visibility,omitempty"` +} diff --git a/service/jira/announcement-banner.go b/service/jira/announcement-banner.go new file mode 100644 index 00000000..58a325e5 --- /dev/null +++ b/service/jira/announcement-banner.go @@ -0,0 +1,25 @@ +package jira + +import ( + "context" + "github.com/ctreminiom/go-atlassian/pkg/infra/models" +) + +// AnnouncementBannerConnector resource represents the Jira announcement banner. +// Use it to retrieve and update banner configuration. +type AnnouncementBannerConnector interface { + + // Get returns the current announcement banner configuration. + // + // GET /rest/api/{2-3}/announcementBanner + // + // https://docs.go-atlassian.io/jira-software-cloud/announcement-banner#get-announcement-banner-configuration + Get(ctx context.Context) (*models.AnnouncementBannerScheme, *models.ResponseScheme, error) + + // Update updates the announcement banner configuration. + // + // PUT /rest/api/{2-3}/announcementBanner + // + // https://docs.go-atlassian.io/jira-software-cloud/announcement-banner#get-announcement-banner-configuration + Update(ctx context.Context, payload *models.AnnouncementBannerPayloadScheme) (*models.ResponseScheme, error) +}