Repository: ctreminiom/go-atlassian
Pull request #174 (2023-03-07 17:22:35)

Bug/fix jira audit service


Patch:
diff --git a/jira/internal/audit_impl.go b/jira/internal/audit_impl.go
new file mode 100644
index 0000000..63aa9c5
--- /dev/null
+++ b/jira/internal/audit_impl.go
@@ -0,0 +1,85 @@
+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"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+func NewAuditRecordService(client service.Client, version string) (*AuditRecordService, error) {
+
+	if version == "" {
+		return nil, model.ErrNoVersionProvided
+	}
+
+	return &AuditRecordService{
+		internalClient: &internalAuditRecordImpl{c: client, version: version},
+	}, nil
+}
+
+type AuditRecordService struct {
+	internalClient jira.AuditRecordConnector
+}
+
+// Get allows you to retrieve the audit records for specific activities that have occurred within Jira.
+//
+// GET /rest/api/{2-3}/auditing/record
+//
+// https://docs.go-atlassian.io/jira-software-cloud/audit-records#get-audit-records
+func (a *AuditRecordService) Get(ctx context.Context, options *model.AuditRecordGetOptions, offSet, limit int) (*model.AuditRecordPageScheme, *model.ResponseScheme, error) {
+	return a.internalClient.Get(ctx, options, offSet, limit)
+}
+
+type internalAuditRecordImpl struct {
+	c       service.Client
+	version string
+}
+
+func (i *internalAuditRecordImpl) Get(ctx context.Context, options *model.AuditRecordGetOptions, offSet, limit int) (*model.AuditRecordPageScheme, *model.ResponseScheme, error) {
+
+	params := url.Values{}
+	params.Add("offset", strconv.Itoa(offSet))
+	params.Add("limit", strconv.Itoa(limit))
+
+	if options != nil {
+
+		if options.Filter != "" {
+			params.Add("", options.Filter)
+		}
+
+		if !options.To.IsZero() {
+			params.Add("to", options.To.Format("2006-01-02"))
+		}
+
+		if !options.From.IsZero() {
+			params.Add("from", options.From.Format("2006-01-02"))
+		}
+
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("rest/api/%v/auditing/record", i.version))
+
+	if params.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", params.Encode()))
+	}
+
+	request, err := i.c.NewRequest(ctx, http.MethodGet, endpoint.String(), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	records := new(model.AuditRecordPageScheme)
+	response, err := i.c.Call(request, records)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return records, response, nil
+}
diff --git a/jira/v2/api_client_impl.go b/jira/v2/api_client_impl.go
index 1055338..cb5ee9b 100644
--- a/jira/v2/api_client_impl.go
+++ b/jira/v2/api_client_impl.go
@@ -35,6 +35,11 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
 		Site: siteAsURL,
 	}
 
+	auditRecordService, err := internal.NewAuditRecordService(client, "2")
+	if err != nil {
+		return nil, err
+	}
+
 	applicationRoleService, err := internal.NewApplicationRoleService(client, "2")
 	if err != nil {
 		return nil, err
@@ -338,6 +343,7 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
 		return nil, err
 	}
 
+	client.Audit = auditRecordService
 	client.Permission = permission
 	client.MySelf = mySelf
 	client.Auth = internal.NewAuthenticationService(client)
@@ -362,6 +368,7 @@ type Client struct {
 	Auth       common.Authentication
 	Site       *url.URL
 	Role       *internal.ApplicationRoleService
+	Audit      *internal.AuditRecordService
 	Dashboard  *internal.DashboardService
 	Filter     *internal.FilterService
 	Group      *internal.GroupService
diff --git a/jira/v3/api_client_impl.go b/jira/v3/api_client_impl.go
index 1991166..4bfa6be 100644
--- a/jira/v3/api_client_impl.go
+++ b/jira/v3/api_client_impl.go
@@ -35,6 +35,11 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
 		Site: siteAsURL,
 	}
 
+	auditRecord, err := internal.NewAuditRecordService(client, "3")
+	if err != nil {
+		return nil, err
+	}
+
 	applicationRoleService, err := internal.NewApplicationRoleService(client, "3")
 	if err != nil {
 		return nil, err
@@ -338,6 +343,7 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
 		return nil, err
 	}
 
+	client.Audit = auditRecord
 	client.Permission = permission
 	client.MySelf = mySelf
 	client.Auth = internal.NewAuthenticationService(client)
@@ -361,6 +367,7 @@ type Client struct {
 	HTTP       common.HttpClient
 	Auth       common.Authentication
 	Site       *url.URL
+	Audit      *internal.AuditRecordService
 	Role       *internal.ApplicationRoleService
 	Dashboard  *internal.DashboardService
 	Filter     *internal.FilterService
diff --git a/service/jira/audit.go b/service/jira/audit.go
new file mode 100644
index 0000000..2befc6e
--- /dev/null
+++ b/service/jira/audit.go
@@ -0,0 +1,18 @@
+package jira
+
+import (
+	"context"
+	model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
+)
+
+// AuditRecordConnector  audits that record activities undertaken in Jira.
+// Use it to get a list of audit records.
+type AuditRecordConnector interface {
+
+	// Get allows you to retrieve the audit records for specific activities that have occurred within Jira.
+	//
+	// GET /rest/api/{2-3}/auditing/record
+	//
+	// https://docs.go-atlassian.io/jira-software-cloud/audit-records#get-audit-records
+	Get(ctx context.Context, options *model.AuditRecordGetOptions, offSet, limit int) (*model.AuditRecordPageScheme, *model.ResponseScheme, error)
+}


Test patch:
diff --git a/jira/internal/audit_impl_test.go b/jira/internal/audit_impl_test.go
new file mode 100644
index 0000000..cc70c62
--- /dev/null
+++ b/jira/internal/audit_impl_test.go
@@ -0,0 +1,248 @@
+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"
+	"time"
+)
+
+func Test_internalAuditRecordImpl_Get(t *testing.T) {
+
+	type fields struct {
+		c       service.Client
+		version string
+	}
+
+	type args struct {
+		ctx     context.Context
+		options *model.AuditRecordGetOptions
+		offSet  int
+		limit   int
+	}
+
+	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(),
+				options: &model.AuditRecordGetOptions{
+					Filter: "summary",
+					From:   time.Now().AddDate(0, -2, 0),
+					To:     time.Now().AddDate(0, -1, 0),
+				},
+				offSet: 2000,
+				limit:  1000,
+			},
+			fields: fields{version: "2"},
+			on: func(fields *fields) {
+				client := mocks.NewClient(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/2/auditing/record?=summary&from=2023-01-07&limit=1000&offset=2000&to=2023-02-07",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.AuditRecordPageScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name: "when the api version is v3",
+			args: args{
+				ctx: context.Background(),
+				options: &model.AuditRecordGetOptions{
+					Filter: "summary",
+					From:   time.Now().AddDate(0, -2, 0),
+					To:     time.Now().AddDate(0, -1, 0),
+				},
+				offSet: 2000,
+				limit:  1000,
+			},
+			fields: fields{version: "3"},
+			on: func(fields *fields) {
+				client := mocks.NewClient(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/3/auditing/record?=summary&from=2023-01-07&limit=1000&offset=2000&to=2023-02-07",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.AuditRecordPageScheme{}).
+					Return(&model.ResponseScheme{}, nil)
+
+				fields.c = client
+			},
+		},
+
+		{
+			name:   "when the http request cannot be created",
+			fields: fields{version: "2"},
+			args: args{
+				ctx: context.Background(),
+				options: &model.AuditRecordGetOptions{
+					Filter: "summary",
+					From:   time.Now().AddDate(0, -2, 0),
+					To:     time.Now().AddDate(0, -1, 0),
+				},
+				offSet: 2000,
+				limit:  1000,
+			},
+			on: func(fields *fields) {
+				client := mocks.NewClient(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/2/auditing/record?=summary&from=2023-01-07&limit=1000&offset=2000&to=2023-02-07",
+					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(),
+				options: &model.AuditRecordGetOptions{
+					Filter: "summary",
+					From:   time.Now().AddDate(0, -2, 0),
+					To:     time.Now().AddDate(0, -1, 0),
+				},
+				offSet: 2000,
+				limit:  1000,
+			},
+			on: func(fields *fields) {
+				client := mocks.NewClient(t)
+
+				client.On("NewRequest",
+					context.Background(),
+					http.MethodGet,
+					"rest/api/2/auditing/record?=summary&from=2023-01-07&limit=1000&offset=2000&to=2023-02-07",
+					nil).
+					Return(&http.Request{}, nil)
+
+				client.On("Call",
+					&http.Request{},
+					&model.AuditRecordPageScheme{}).
+					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)
+			}
+
+			service, err := NewAuditRecordService(testCase.fields.c, testCase.fields.version)
+			assert.NoError(t, err)
+
+			gotResult, gotResponse, err := service.Get(testCase.args.ctx, testCase.args.options, testCase.args.offSet,
+				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 TestNewAuditRecordService(t *testing.T) {
+
+	type args struct {
+		client  service.Client
+		version string
+	}
+
+	testCases := []struct {
+		name    string
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "when the parameters are correct",
+			args: args{
+				client:  nil,
+				version: "3",
+			},
+			wantErr: false,
+		},
+
+		{
+			name: "when the version is not provided",
+			args: args{
+				client:  nil,
+				version: "",
+			},
+			wantErr: true,
+			err:     model.ErrNoVersionProvided,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			got, err := NewAuditRecordService(testCase.args.client, testCase.args.version)
+
+			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, got, nil)
+			}
+		})
+	}
+}