Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Created the Analytics Confluence service. #184

Merged
merged 1 commit into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions confluence/api_client_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,21 @@ func New(httpClient common.HttpClient, site string) (*Client, error) {
client.Label = internal.NewLabelService(client)
client.Search = internal.NewSearchService(client)
client.LongTask = internal.NewTaskService(client)
client.Analytics = internal.NewAnalyticsService(client)

return client, nil
}

type Client struct {
HTTP common.HttpClient
Site *url.URL
Auth common.Authentication
Content *internal.ContentService
Space *internal.SpaceService
Label *internal.LabelService
Search *internal.SearchService
LongTask *internal.TaskService
HTTP common.HttpClient
Site *url.URL
Auth common.Authentication
Content *internal.ContentService
Space *internal.SpaceService
Label *internal.LabelService
Search *internal.SearchService
LongTask *internal.TaskService
Analytics *internal.AnalyticsService
}

func (c *Client) NewFormRequest(ctx context.Context, method, apiEndpoint, contentType string, payload io.Reader) (*http.Request, error) {
Expand Down
105 changes: 105 additions & 0 deletions confluence/internal/analytics_impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
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"
"strings"
)

func NewAnalyticsService(client service.Client) *AnalyticsService {

return &AnalyticsService{
internalClient: &internalAnalyticsServiceImpl{c: client},
}
}

type AnalyticsService struct {
internalClient confluence.AnalyticsConnector
}

// Get gets the total number of views a piece of content has.
//
// GET /wiki/rest/api/analytics/content/{contentId}/views
//
// https://docs.go-atlassian.io/confluence-cloud/analytics#get-views
func (a *AnalyticsService) Get(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error) {
return a.internalClient.Get(ctx, contentId, fromDate)
}

// Distinct get the total number of distinct viewers a piece of content has.
//
// GET /wiki/rest/api/analytics/content/{contentId}/viewers
//
// https://docs.go-atlassian.io/confluence-cloud/analytics#get-viewers
func (a *AnalyticsService) Distinct(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error) {
return a.internalClient.Distinct(ctx, contentId, fromDate)
}

type internalAnalyticsServiceImpl struct {
c service.Client
}

func (i *internalAnalyticsServiceImpl) Get(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error) {

if contentId == "" {
return nil, nil, model.ErrNoContentIDError
}

var endpoint strings.Builder
endpoint.WriteString(fmt.Sprintf("wiki/rest/api/analytics/content/%v/views", contentId))

if fromDate != "" {
query := url.Values{}
query.Add("fromDate", fromDate)

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
}

views := new(model.ContentViewScheme)
response, err := i.c.Call(request, views)
if err != nil {
return nil, response, err
}

return views, response, nil
}

func (i *internalAnalyticsServiceImpl) Distinct(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error) {

if contentId == "" {
return nil, nil, model.ErrNoContentIDError
}

var endpoint strings.Builder
endpoint.WriteString(fmt.Sprintf("wiki/rest/api/analytics/content/%v/viewers", contentId))

if fromDate != "" {
query := url.Values{}
query.Add("fromDate", fromDate)

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
}

views := new(model.ContentViewScheme)
response, err := i.c.Call(request, views)
if err != nil {
return nil, response, err
}

return views, response, nil
}
232 changes: 232 additions & 0 deletions confluence/internal/analytics_impl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
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_internalAnalyticsServiceImpl_Get(t *testing.T) {

type fields struct {
c service.Client
}

type args struct {
ctx context.Context
contentId, fromDate 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(),
contentId: "2337372172371",
fromDate: "2023-10-03",
},
on: func(fields *fields) {

client := mocks.NewClient(t)

client.On("NewRequest",
context.Background(),
http.MethodGet,
"wiki/rest/api/analytics/content/2337372172371/views?fromDate=2023-10-03",
nil).
Return(&http.Request{}, nil)

client.On("Call",
&http.Request{},
&model.ContentViewScheme{}).
Return(&model.ResponseScheme{}, nil)

fields.c = client
},
},

{
name: "when the http request cannot be created",
args: args{
ctx: context.TODO(),
contentId: "2337372172371",
fromDate: "2023-10-03",
},
on: func(fields *fields) {

client := mocks.NewClient(t)

client.On("NewRequest",
context.Background(),
http.MethodGet,
"wiki/rest/api/analytics/content/2337372172371/views?fromDate=2023-10-03",
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 content id is not provided",
args: args{
ctx: context.TODO(),
},
wantErr: true,
Err: model.ErrNoContentIDError,
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {

if testCase.on != nil {
testCase.on(&testCase.fields)
}

newService := NewAnalyticsService(testCase.fields.c)

gotResult, gotResponse, err := newService.Get(testCase.args.ctx, testCase.args.contentId, testCase.args.fromDate)

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_internalAnalyticsServiceImpl_Distinct(t *testing.T) {

type fields struct {
c service.Client
}

type args struct {
ctx context.Context
contentId, fromDate 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(),
contentId: "2337372172371",
fromDate: "2023-10-03",
},
on: func(fields *fields) {

client := mocks.NewClient(t)

client.On("NewRequest",
context.Background(),
http.MethodGet,
"wiki/rest/api/analytics/content/2337372172371/viewers?fromDate=2023-10-03",
nil).
Return(&http.Request{}, nil)

client.On("Call",
&http.Request{},
&model.ContentViewScheme{}).
Return(&model.ResponseScheme{}, nil)

fields.c = client
},
},

{
name: "when the http request cannot be created",
args: args{
ctx: context.TODO(),
contentId: "2337372172371",
fromDate: "2023-10-03",
},
on: func(fields *fields) {

client := mocks.NewClient(t)

client.On("NewRequest",
context.Background(),
http.MethodGet,
"wiki/rest/api/analytics/content/2337372172371/viewers?fromDate=2023-10-03",
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 content id is not provided",
args: args{
ctx: context.TODO(),
},
wantErr: true,
Err: model.ErrNoContentIDError,
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {

if testCase.on != nil {
testCase.on(&testCase.fields)
}

newService := NewAnalyticsService(testCase.fields.c)

gotResult, gotResponse, err := newService.Distinct(testCase.args.ctx, testCase.args.contentId, testCase.args.fromDate)

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)
}

})
}
}
6 changes: 6 additions & 0 deletions pkg/infra/models/confluence_analytics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package models

type ContentViewScheme struct {
ID int `json:"id,omitempty"`
Count int `json:"count,omitempty"`
}
23 changes: 23 additions & 0 deletions service/confluence/analytics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package confluence

import (
"context"
model "github.com/ctreminiom/go-atlassian/pkg/infra/models"
)

type AnalyticsConnector interface {

// Get gets the total number of views a piece of content has.
//
// GET /wiki/rest/api/analytics/content/{contentId}/views
//
// https://docs.go-atlassian.io/confluence-cloud/analytics#get-views
Get(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error)

// Distinct get the total number of distinct viewers a piece of content has.
//
// GET /wiki/rest/api/analytics/content/{contentId}/viewers
//
// https://docs.go-atlassian.io/confluence-cloud/analytics#get-viewers
Distinct(ctx context.Context, contentId, fromDate string) (*model.ContentViewScheme, *model.ResponseScheme, error)
}