Repository: ctreminiom/go-atlassian
Pull request #99 (2022-01-18 06:11:18)

:sparkles: Added the Confluence Restriction Service
1. Added the following method under *contentRestriction.go*
* Get restrictions
* Update restrictions
* Add restrictions
* Delete restrictions

2. Parsed the Content Restriction Operations
3. Parsed the Content Restriction Operation for groups.

4. Added the github.com/google/uuid library


Patch:
diff --git a/confluence/confluence.go b/confluence/confluence.go
index 7b32ac5..a26720d 100644
--- a/confluence/confluence.go
+++ b/confluence/confluence.go
@@ -51,6 +51,12 @@ func New(httpClient *http.Client, site string) (client *Client, err error) {
 		Permission:         &ContentPermissionService{client: client},
 		Label:              &ContentLabelService{client: client},
 		Property:           &ContentPropertyService{client: client},
+		Restriction: &ContentRestrictionService{
+			client: client,
+			Operation: &ContentRestrictionOperationService{
+				client: client,
+				Group:  &ContentRestrictionOperationGroupService{client: client},
+			}},
 	}
 
 	client.Space = &SpaceService{client: client}
@@ -128,6 +134,8 @@ func transformTheHTTPResponse(response *http.Response, structure interface{}) (r
 			}
 
 			responseTransformed.API = &apiError
+			responseTransformed.Bytes.Write(responseAsBytes)
+
 			return responseTransformed, fmt.Errorf(requestFailedError, response.StatusCode)
 		}
 		return responseTransformed, fmt.Errorf(requestFailedError, response.StatusCode)
diff --git a/confluence/content.go b/confluence/content.go
index ca921b4..9bd0402 100644
--- a/confluence/content.go
+++ b/confluence/content.go
@@ -18,6 +18,7 @@ type ContentService struct {
 	Permission         *ContentPermissionService
 	Label              *ContentLabelService
 	Property           *ContentPropertyService
+	Restriction        *ContentRestrictionService
 }
 
 // Gets returns all content in a Confluence instance.
diff --git a/confluence/contentRestriction.go b/confluence/contentRestriction.go
new file mode 100644
index 0000000..641456d
--- /dev/null
+++ b/confluence/contentRestriction.go
@@ -0,0 +1,170 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type ContentRestrictionService struct {
+	client    *Client
+	Operation *ContentRestrictionOperationService
+}
+
+// Gets returns the restrictions on a piece of content.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions#get-restrictions
+func (c *ContentRestrictionService) Gets(ctx context.Context, contentID string, expand []string, startAt, maxResults int) (
+	result *models.ContentRestrictionPageScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	query := url.Values{}
+	query.Add("start", strconv.Itoa(startAt))
+	query.Add("limit", strconv.Itoa(maxResults))
+
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	endpoint := fmt.Sprintf("wiki/rest/api/content/%v/restriction?%v", contentID, query.Encode())
+
+	request, err := c.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
+
+// Add adds restrictions to a piece of content. Note, this does not change any existing restrictions on the content.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions#add-restrictions
+func (c *ContentRestrictionService) Add(ctx context.Context, contentID string, payload *models.ContentRestrictionUpdatePayloadScheme,
+	expand []string) (result *models.ContentRestrictionPageScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction", contentID))
+
+	query := url.Values{}
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	payloadAsReader, err := transformStructToReader(payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodPost, endpoint.String(), payloadAsReader)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
+
+// Delete removes all restrictions (read and update) on a piece of content.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions#delete-restrictions
+func (c *ContentRestrictionService) Delete(ctx context.Context, contentID string, expand []string) (
+	result *models.ContentRestrictionPageScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction", contentID))
+
+	query := url.Values{}
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodDelete, endpoint.String(), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
+
+// Update updates restrictions for a piece of content. This removes the existing restrictions and replaces them with the restrictions in the request.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions#update-restrictions
+func (c *ContentRestrictionService) Update(ctx context.Context, contentID string, payload *models.ContentRestrictionUpdatePayloadScheme,
+	expand []string) (result *models.ContentRestrictionPageScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction", contentID))
+
+	query := url.Values{}
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	payloadAsReader, err := transformStructToReader(payload)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodPut, endpoint.String(), payloadAsReader)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+	request.Header.Set("Content-Type", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
diff --git a/confluence/contentRestrictionOperationGroup.go b/confluence/contentRestrictionOperationGroup.go
new file mode 100644
index 0000000..cc272dd
--- /dev/null
+++ b/confluence/contentRestrictionOperationGroup.go
@@ -0,0 +1,140 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/google/uuid"
+	"net/http"
+	"strings"
+)
+
+type ContentRestrictionOperationGroupService struct{ client *Client }
+
+// Get returns whether the specified content restriction applies to a group
+// Note that a response of true does not guarantee that the group can view the page,
+// as it does not account for account-inherited restrictions, space permissions, or even product access.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions/operations/group#get-content-restriction-status-for-group
+func (c *ContentRestrictionOperationGroupService) Get(ctx context.Context, contentID, operationKey, groupNameOrID string) (response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, models.ErrNoContentIDError
+	}
+
+	if len(operationKey) == 0 {
+		return nil, models.ErrNoContentRestrictionKeyError
+	}
+
+	if len(groupNameOrID) == 0 {
+		return nil, models.ErrNoConfluenceGroupError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction/byOperation/%v/", contentID, operationKey))
+
+	// check if the group id is an uuid type
+	// if so, it's the group id
+	groupID, err := uuid.Parse(groupNameOrID)
+
+	if err == nil {
+		endpoint.WriteString(fmt.Sprintf("byGroupId/%v", groupID.String()))
+	} else {
+		endpoint.WriteString(fmt.Sprintf("group/%v", groupNameOrID))
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodGet, endpoint.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	response, err = c.client.Call(request, nil)
+	if err != nil {
+		return response, err
+	}
+
+	return
+}
+
+// Add adds a group to a content restriction. That is, grant read or update permission to the group for a piece of content.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions/operations/group#add-group-to-content-restriction
+func (c *ContentRestrictionOperationGroupService) Add(ctx context.Context, contentID, operationKey, groupNameOrID string) (response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, models.ErrNoContentIDError
+	}
+
+	if len(operationKey) == 0 {
+		return nil, models.ErrNoContentRestrictionKeyError
+	}
+
+	if len(groupNameOrID) == 0 {
+		return nil, models.ErrNoConfluenceGroupError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction/byOperation/%v/", contentID, operationKey))
+
+	// check if the group id is an uuid type
+	// if so, it's the group id
+	groupID, err := uuid.Parse(groupNameOrID)
+
+	if err == nil {
+		endpoint.WriteString(fmt.Sprintf("byGroupId/%v", groupID.String()))
+	} else {
+		endpoint.WriteString(fmt.Sprintf("group/%v", groupNameOrID))
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodPut, endpoint.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	response, err = c.client.Call(request, nil)
+	if err != nil {
+		return response, err
+	}
+
+	return
+}
+
+// Remove removes a group from a content restriction. That is, remove read or update permission for the group for a piece of content.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions/operations/group#remove-group-from-content-restriction
+func (c *ContentRestrictionOperationGroupService) Remove(ctx context.Context, contentID, operationKey, groupNameOrID string) (response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, models.ErrNoContentIDError
+	}
+
+	if len(operationKey) == 0 {
+		return nil, models.ErrNoContentRestrictionKeyError
+	}
+
+	if len(groupNameOrID) == 0 {
+		return nil, models.ErrNoConfluenceGroupError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction/byOperation/%v/", contentID, operationKey))
+
+	// check if the group id is an uuid type
+	// if so, it's the group id
+	groupID, err := uuid.Parse(groupNameOrID)
+
+	if err == nil {
+		endpoint.WriteString(fmt.Sprintf("byGroupId/%v", groupID.String()))
+	} else {
+		endpoint.WriteString(fmt.Sprintf("group/%v", groupNameOrID))
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodDelete, endpoint.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	response, err = c.client.Call(request, nil)
+	if err != nil {
+		return response, err
+	}
+
+	return
+}
diff --git a/confluence/contentRestrictionsOperation.go b/confluence/contentRestrictionsOperation.go
new file mode 100644
index 0000000..7d23b37
--- /dev/null
+++ b/confluence/contentRestrictionsOperation.go
@@ -0,0 +1,92 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"net/http"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type ContentRestrictionOperationService struct {
+	client *Client
+	Group  *ContentRestrictionOperationGroupService
+}
+
+// Gets returns restrictions on a piece of content by operation.
+// This method is similar to Get restrictions except that the operations are properties
+// of the return object, rather than items in a results array.
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions/operations#get-restrictions-by-operation
+func (c *ContentRestrictionOperationService) Gets(ctx context.Context, contentID string, expand []string) (
+	result *models.ContentRestrictionByOperationScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	var endpoint strings.Builder
+	endpoint.WriteString(fmt.Sprintf("wiki/rest/api/content/%v/restriction/byOperation", contentID))
+
+	query := url.Values{}
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	if query.Encode() != "" {
+		endpoint.WriteString(fmt.Sprintf("?%v", query.Encode()))
+	}
+
+	request, err := c.client.newRequest(ctx, http.MethodGet, endpoint.String(), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
+
+// Get returns the restrictions on a piece of content for a given operation (read or update).
+// Docs: https://docs.go-atlassian.io/confluence-cloud/content/restrictions/operations#get-restrictions-for-operation
+func (c *ContentRestrictionOperationService) Get(ctx context.Context, contentID, operationKey string, expand []string,
+	startAt, maxResults int) (result *models.ContentRestrictionScheme, response *ResponseScheme, err error) {
+
+	if len(contentID) == 0 {
+		return nil, nil, models.ErrNoContentIDError
+	}
+
+	if len(operationKey) == 0 {
+		return nil, nil, models.ErrNoContentRestrictionKeyError
+	}
+
+	query := url.Values{}
+	query.Add("start", strconv.Itoa(startAt))
+	query.Add("limit", strconv.Itoa(maxResults))
+
+	if len(expand) != 0 {
+		query.Add("expand", strings.Join(expand, ","))
+	}
+
+	endpoint := fmt.Sprintf("wiki/rest/api/content/%v/restriction/byOperation/%v?%v", contentID, operationKey, query.Encode())
+
+	request, err := c.client.newRequest(ctx, http.MethodGet, endpoint, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	request.Header.Set("Accept", "application/json")
+
+	response, err = c.client.Call(request, &result)
+	if err != nil {
+		return nil, response, err
+	}
+
+	return
+}
diff --git a/confluence/mocks/get-content-restriction-by-operation.json b/confluence/mocks/get-content-restriction-by-operation.json
new file mode 100644
index 0000000..d104c57
--- /dev/null
+++ b/confluence/mocks/get-content-restriction-by-operation.json
@@ -0,0 +1,155 @@
+{
+  "operationType": {
+    "operation": "administer",
+    "restrictions": {
+      "user": {
+        "results": [
+          {
+            "type": "known"
+          }
+        ],
+        "start": 2154,
+        "limit": 2154,
+        "size": 2154,
+        "_links": {}
+      },
+      "group": {
+        "results": [
+          {
+            "type": "group",
+            "name": "<string>"
+          }
+        ],
+        "start": 2154,
+        "limit": 2154,
+        "size": 2154
+      },
+      "_expandable": {
+        "user": "<string>",
+        "group": "<string>"
+      }
+    },
+    "content": {
+      "id": "<string>",
+      "type": "<string>",
+      "status": "<string>",
+      "title": "<string>",
+      "space": {
+        "key": "<string>",
+        "name": "<string>",
+        "type": "<string>",
+        "status": "<string>",
+        "_expandable": {},
+        "_links": {}
+      },
+      "history": {
+        "latest": true
+      },
+      "version": {
+        "when": "<string>",
+        "number": 57,
+        "minorEdit": true
+      },
+      "ancestors": [],
+      "operations": [
+        {
+          "operation": "administer",
+          "targetType": "<string>"
+        }
+      ],
+      "children": {},
+      "childTypes": {},
+      "descendants": {},
+      "container": {},
+      "body": {
+        "view": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "export_view": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "styled_view": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "storage": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "wiki": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "editor": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "editor2": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "anonymous_export_view": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "atlas_doc_format": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "dynamic": {
+          "value": "<string>",
+          "representation": "view"
+        },
+        "_expandable": {
+          "editor": "<string>",
+          "view": "<string>",
+          "export_view": "<string>",
+          "styled_view": "<string>",
+          "storage": "<string>",
+          "editor2": "<string>",
+          "anonymous_export_view": "<string>",
+          "atlas_doc_format": "<string>",
+          "wiki": "<string>",
+          "dynamic": "<string>",
+          "raw": "<string>"
+        }
+      },
+      "restrictions": {
+        "_expandable": {
+          "read": "<string>",
+          "update": "<string>"
+        },
+        "_links": {}
+      },
+      "metadata": {},
+      "macroRenderedOutput": {},
+      "extensions": {},
+      "_expandable": {
+        "childTypes": "<string>",
+        "container": "<string>",
+        "metadata": "<string>",
+        "operations": "<string>",
+        "children": "<string>",
+        "restrictions": "<string>",
+        "history": "<string>",
+        "ancestors": "<string>",
+        "body": "<string>",
+        "version": "<string>",
+        "descendants": "<string>",
+        "space": "<string>",
+        "extensions": "<string>",
+        "schedulePublishDate": "<string>",
+        "macroRenderedOutput": "<string>"
+      },
+      "_links": {}
+    },
+    "_expandable": {
+      "restrictions": "<string>",
+      "content": "<string>"
+    },
+    "_links": {}
+  },
+  "_links": {}
+}
\ No newline at end of file
diff --git a/confluence/mocks/get-content-restrictions.json b/confluence/mocks/get-content-restrictions.json
new file mode 100644
index 0000000..9b8b334
--- /dev/null
+++ b/confluence/mocks/get-content-restrictions.json
@@ -0,0 +1,161 @@
+{
+  "results": [
+    {
+      "operation": "administer",
+      "restrictions": {
+        "user": {
+          "results": [
+            {
+              "type": "known"
+            }
+          ],
+          "start": 2154,
+          "limit": 2154,
+          "size": 2154,
+          "_links": {}
+        },
+        "group": {
+          "results": [
+            {
+              "type": "group",
+              "name": "<string>"
+            }
+          ],
+          "start": 2154,
+          "limit": 2154,
+          "size": 2154
+        },
+        "_expandable": {
+          "user": "<string>",
+          "group": "<string>"
+        }
+      },
+      "content": {
+        "id": "<string>",
+        "type": "<string>",
+        "status": "<string>",
+        "title": "<string>",
+        "space": {
+          "key": "<string>",
+          "name": "<string>",
+          "type": "<string>",
+          "status": "<string>",
+          "_expandable": {},
+          "_links": {}
+        },
+        "history": {
+          "latest": true
+        },
+        "version": {
+          "when": "<string>",
+          "number": 57,
+          "minorEdit": true
+        },
+        "ancestors": [],
+        "operations": [
+          {
+            "operation": "administer",
+            "targetType": "<string>"
+          }
+        ],
+        "children": {},
+        "childTypes": {},
+        "descendants": {},
+        "container": {},
+        "body": {
+          "view": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "export_view": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "styled_view": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "storage": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "wiki": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "editor": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "editor2": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "anonymous_export_view": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "atlas_doc_format": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "dynamic": {
+            "value": "<string>",
+            "representation": "view"
+          },
+          "_expandable": {
+            "editor": "<string>",
+            "view": "<string>",
+            "export_view": "<string>",
+            "styled_view": "<string>",
+            "storage": "<string>",
+            "editor2": "<string>",
+            "anonymous_export_view": "<string>",
+            "atlas_doc_format": "<string>",
+            "wiki": "<string>",
+            "dynamic": "<string>",
+            "raw": "<string>"
+          }
+        },
+        "restrictions": {
+          "_expandable": {
+            "read": "<string>",
+            "update": "<string>"
+          },
+          "_links": {}
+        },
+        "metadata": {},
+        "macroRenderedOutput": {},
+        "extensions": {},
+        "_expandable": {
+          "childTypes": "<string>",
+          "container": "<string>",
+          "metadata": "<string>",
+          "operations": "<string>",
+          "children": "<string>",
+          "restrictions": "<string>",
+          "history": "<string>",
+          "ancestors": "<string>",
+          "body": "<string>",
+          "version": "<string>",
+          "descendants": "<string>",
+          "space": "<string>",
+          "extensions": "<string>",
+          "schedulePublishDate": "<string>",
+          "macroRenderedOutput": "<string>"
+        },
+        "_links": {}
+      },
+      "_expandable": {
+        "restrictions": "<string>",
+        "content": "<string>"
+      },
+      "_links": {}
+    }
+  ],
+  "start": 2154,
+  "limit": 2154,
+  "size": 2154,
+  "restrictionsHash": "<string>",
+  "_links": {}
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index e992d50..96e646d 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/ctreminiom/go-atlassian
 go 1.15
 
 require (
+	github.com/google/uuid v1.3.0
 	github.com/imdario/mergo v0.3.12
 	github.com/stretchr/testify v1.7.0
 	github.com/tidwall/gjson v1.12.1
diff --git a/go.sum b/go.sum
index 050ebfc..0188f7b 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,7 @@
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
 github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
diff --git a/pkg/infra/models/confluence_content.go b/pkg/infra/models/confluence_content.go
index c0819d7..d4129a7 100644
--- a/pkg/infra/models/confluence_content.go
+++ b/pkg/infra/models/confluence_content.go
@@ -3,10 +3,12 @@ package models
 import "time"
 
 type GetContentOptionsScheme struct {
-	ContextType, SpaceKey   string
-	Title, Trigger, OrderBy string
-	Status, Expand          []string
-	PostingDay              time.Time
+	ContextType, SpaceKey string
+	Title                 string
+	Trigger               string
+	OrderBy               string
+	Status, Expand        []string
+	PostingDay            time.Time
 }
 
 type ContentPageScheme struct {
diff --git a/pkg/infra/models/confluence_content_restriction.go b/pkg/infra/models/confluence_content_restriction.go
new file mode 100644
index 0000000..48ff6fc
--- /dev/null
+++ b/pkg/infra/models/confluence_content_restriction.go
@@ -0,0 +1,45 @@
+package models
+
+type ContentRestrictionPageScheme struct {
+	Start            int                         `json:"start,omitempty"`
+	Limit            int                         `json:"limit,omitempty"`
+	Size             int                         `json:"size,omitempty"`
+	RestrictionsHash string                      `json:"restrictionsHash,omitempty"`
+	Results          []*ContentRestrictionScheme `json:"results,omitempty"`
+}
+
+type ContentRestrictionScheme struct {
+	Operation    string                              `json:"operation,omitempty"`
+	Restrictions *ContentRestrictionDetailScheme     `json:"restrictions,omitempty"`
+	Content      *ContentScheme                      `json:"content,omitempty"`
+	Expandable   *ContentRestrictionExpandableScheme `json:"_expandable,omitempty"`
+}
+
+type ContentRestrictionExpandableScheme struct {
+	Restrictions string `json:"restrictions,omitempty"`
+	Content      string `json:"content,omitempty"`
+}
+
+type ContentRestrictionDetailScheme struct {
+	User  *UserPermissionScheme  `json:"user,omitempty"`
+	Group *GroupPermissionScheme `json:"group,omitempty"`
+}
+
+type ContentRestrictionUpdatePayloadScheme struct {
+	Results []*ContentRestrictionUpdateScheme `json:"results,omitempty"`
+}
+
+type ContentRestrictionUpdateScheme struct {
+	Operation    string                                     `json:"operation,omitempty"`
+	Restrictions *ContentRestrictionRestrictionUpdateScheme `json:"restrictions,omitempty"`
+	Content      *ContentScheme                             `json:"content,omitempty"`
+}
+
+type ContentRestrictionRestrictionUpdateScheme struct {
+	Group []*SpaceGroupScheme  `json:"group,omitempty"`
+	User  []*ContentUserScheme `json:"user,omitempty"`
+}
+
+type ContentRestrictionByOperationScheme struct {
+	OperationType *ContentRestrictionScheme `json:"operationType,omitempty"`
+}
diff --git a/pkg/infra/models/confluence_space.go b/pkg/infra/models/confluence_space.go
index 24a1e48..613642c 100644
--- a/pkg/infra/models/confluence_space.go
+++ b/pkg/infra/models/confluence_space.go
@@ -82,8 +82,8 @@ type SubjectPermissionScheme struct {
 }
 
 type UserPermissionScheme struct {
-	Results []*UserScheme `json:"results,omitempty"`
-	Size    int           `json:"size,omitempty"`
+	Results []*ContentUserScheme `json:"results,omitempty"`
+	Size    int                  `json:"size,omitempty"`
 }
 
 type GroupPermissionScheme struct {
diff --git a/pkg/infra/models/errors.go b/pkg/infra/models/errors.go
index 78ef723..2b53c64 100644
--- a/pkg/infra/models/errors.go
+++ b/pkg/infra/models/errors.go
@@ -26,15 +26,17 @@ var (
 	ErrNoFileNameError            = errors.New("sm: no file name set")
 	ErrNoFileReaderError          = errors.New("sm: no io.Reader set")
 
-	ErrNoContentIDError        = errors.New("confluence: no content id set")
-	ErrNoCQLError              = errors.New("confluence: no CQL query set")
-	ErrNoContentTypeError      = errors.New("confluence: no content type set")
-	ErrInvalidContentTypeError = errors.New("confluence: invalid content type: (page, comment, attachment)")
-	ValidContentTypes          = []string{"page", "comment", "attachment"}
-	ErrNoContentLabelError     = errors.New("confluence: no content label set")
-	ErrNoContentPropertyError  = errors.New("confluence: no content property set")
-	ErrNoSpaceNameError        = errors.New("confluence: no space name set")
-	ErrNoSpaceKeyError         = errors.New("confluence: no space key set")
+	ErrNoContentIDError             = errors.New("confluence: no content id set")
+	ErrNoCQLError                   = errors.New("confluence: no CQL query set")
+	ErrNoContentTypeError           = errors.New("confluence: no content type set")
+	ErrInvalidContentTypeError      = errors.New("confluence: invalid content type: (page, comment, attachment)")
+	ValidContentTypes               = []string{"page", "comment", "attachment"}
+	ErrNoContentLabelError          = errors.New("confluence: no content label set")
+	ErrNoContentPropertyError       = errors.New("confluence: no content property set")
+	ErrNoSpaceNameError             = errors.New("confluence: no space name set")
+	ErrNoSpaceKeyError              = errors.New("confluence: no space key set")
+	ErrNoContentRestrictionKeyError = errors.New("confluence: no content restriction operation key set")
+	ErrNoConfluenceGroupError       = errors.New("confluence: no group id or name set")
 
 	ErrNoBoardIDError  = errors.New("agile: no board id set")
 	ErrNoFilterIDError = errors.New("agile: no filter id set")


Test patch:
diff --git a/confluence/contentRestrictionOperationGroup_test.go b/confluence/contentRestrictionOperationGroup_test.go
new file mode 100644
index 0000000..b90f41d
--- /dev/null
+++ b/confluence/contentRestrictionOperationGroup_test.go
@@ -0,0 +1,520 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func Test_Content_Restriction_Operation_Group_Service_Get(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		operationKey       string
+		groupNameOrID      string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:               "when the group id is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/byGroupId/61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the group name is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the operation key is not provided",
+			contentID:          "233838383",
+			operationKey:       "",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content restriction operation key set",
+		},
+
+		{
+			name:               "when the group name or id is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no group id or name set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is invalid",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionOperationGroupService{client: mockClient}
+
+			gotResponse, err := service.Get(testCase.context, testCase.contentID, testCase.operationKey, testCase.groupNameOrID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func Test_Content_Restriction_Operation_Group_Service_Add(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		operationKey       string
+		groupNameOrID      string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:               "when the group id is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/byGroupId/61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the group name is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the operation key is not provided",
+			contentID:          "233838383",
+			operationKey:       "",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content restriction operation key set",
+		},
+
+		{
+			name:               "when the group name or id is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no group id or name set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is invalid",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionOperationGroupService{client: mockClient}
+
+			gotResponse, err := service.Add(testCase.context, testCase.contentID, testCase.operationKey, testCase.groupNameOrID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func Test_Content_Restriction_Operation_Group_Service_Remove(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		operationKey       string
+		groupNameOrID      string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:               "when the group id is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/byGroupId/61eb397f-3bb8-4fb8-843f-a290b9ff17d0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the group name is provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the operation key is not provided",
+			contentID:          "233838383",
+			operationKey:       "",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no content restriction operation key set",
+		},
+
+		{
+			name:               "when the group name or id is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "confluence: no group id or name set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusNoContent,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is invalid",
+			contentID:          "233838383",
+			operationKey:       "read",
+			groupNameOrID:      "confluence-system-admins",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read/group/confluence-system-admins",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionOperationGroupService{client: mockClient}
+
+			gotResponse, err := service.Remove(testCase.context, testCase.contentID, testCase.operationKey, testCase.groupNameOrID)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
diff --git a/confluence/contentRestriction_test.go b/confluence/contentRestriction_test.go
new file mode 100644
index 0000000..2736721
--- /dev/null
+++ b/confluence/contentRestriction_test.go
@@ -0,0 +1,787 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/ctreminiom/go-atlassian/pkg/infra/models"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func TestContentRestrictionService_Gets(t *testing.T) {
+
+	testCases := []struct {
+		name                string
+		contentID           string
+		expand              []string
+		startAt, maxResults int
+		mockFile            string
+		wantHTTPMethod      string
+		endpoint            string
+		context             context.Context
+		wantHTTPCodeReturn  int
+		wantErr             bool
+		expectedError       string
+	}{
+		{
+			name:               "when the parameters are correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is not correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:               "when the response body is not empty",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Gets(testCase.context, testCase.contentID, testCase.expand,
+				testCase.startAt, testCase.maxResults)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func TestContentRestrictionService_Add(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		payload            *models.ContentRestrictionUpdatePayloadScheme
+		expand             []string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:      "when the parameters are correct",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+		},
+
+		{
+			name:               "when the payload is not provided",
+			contentID:          "233838383",
+			payload:            nil,
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "failed to parse the interface pointer, please provide a valid one",
+		},
+
+		{
+			name:      "when the content id is not provided",
+			contentID: "",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:      "when the context is not provided",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:      "when the response status is not correct",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:      "when the response body is not empty",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodPost,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Add(testCase.context, testCase.contentID, testCase.payload, testCase.expand)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func TestContentRestrictionService_Delete(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		expand             []string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:               "when the parameters are correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is not correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:               "when the response body is not empty",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodDelete,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Delete(testCase.context, testCase.contentID, testCase.expand)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func TestContentRestrictionService_Update(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		payload            *models.ContentRestrictionUpdatePayloadScheme
+		expand             []string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:      "when the parameters are correct",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+		},
+
+		{
+			name:               "when the payload is not provided",
+			contentID:          "233838383",
+			payload:            nil,
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "failed to parse the interface pointer, please provide a valid one",
+		},
+
+		{
+			name:      "when the content id is not provided",
+			contentID: "",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:      "when the context is not provided",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:      "when the response status is not correct",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:      "when the response body is not empty",
+			contentID: "233838383",
+			payload: &models.ContentRestrictionUpdatePayloadScheme{
+				Results: []*models.ContentRestrictionUpdateScheme{
+					{
+						Operation: "administer",
+						Restrictions: &models.ContentRestrictionRestrictionUpdateScheme{
+							Group: []*models.SpaceGroupScheme{
+								{
+									Type: "group",
+									Name: "confluence-users",
+								},
+							},
+						},
+					},
+				},
+			},
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodPut,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusCreated,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Update(testCase.context, testCase.contentID, testCase.payload, testCase.expand)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
diff --git a/confluence/contentRestrictionsOperation_test.go b/confluence/contentRestrictionsOperation_test.go
new file mode 100644
index 0000000..9f31245
--- /dev/null
+++ b/confluence/contentRestrictionsOperation_test.go
@@ -0,0 +1,336 @@
+package confluence
+
+import (
+	"context"
+	"fmt"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"net/url"
+	"testing"
+)
+
+func TestContentRestrictionOperationService_Gets(t *testing.T) {
+
+	testCases := []struct {
+		name               string
+		contentID          string
+		expand             []string
+		mockFile           string
+		wantHTTPMethod     string
+		endpoint           string
+		context            context.Context
+		wantHTTPCodeReturn int
+		wantErr            bool
+		expectedError      string
+	}{
+		{
+			name:               "when the parameters are correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restriction-by-operation.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restriction-by-operation.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restriction-by-operation.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation?expand=restrictions.user%2Crestrictions.group",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is not correct",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/get-content-restriction-by-operation.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:               "when the response body is not empty",
+			contentID:          "233838383",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation?expand=restrictions.user%2Crestrictions.group",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionOperationService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Gets(testCase.context, testCase.contentID, testCase.expand)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}
+
+func TestContentRestrictionOperationService_Get(t *testing.T) {
+
+	testCases := []struct {
+		name                string
+		contentID           string
+		operationKey        string
+		expand              []string
+		startAt, maxResults int
+		mockFile            string
+		wantHTTPMethod      string
+		endpoint            string
+		context             context.Context
+		wantHTTPCodeReturn  int
+		wantErr             bool
+		expectedError       string
+	}{
+		{
+			name:               "when the parameters are correct",
+			contentID:          "233838383",
+			operationKey:       "read",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+		},
+
+		{
+			name:               "when the operation key is not provided",
+			contentID:          "233838383",
+			operationKey:       "",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "confluence: no content restriction operation key set",
+		},
+
+		{
+			name:               "when the content id is not provided",
+			contentID:          "",
+			operationKey:       "read",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "confluence: no content id set",
+		},
+
+		{
+			name:               "when the context is not provided",
+			contentID:          "233838383",
+			operationKey:       "read",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            nil,
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "request creation failed: net/http: nil Context",
+		},
+
+		{
+			name:               "when the response status is not correct",
+			contentID:          "233838383",
+			operationKey:       "read",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/get-content-restrictions.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusBadRequest,
+			wantErr:            true,
+			expectedError:      "request failed. Please analyze the request body for more details. Status Code: 400",
+		},
+
+		{
+			name:               "when the response body is not empty",
+			contentID:          "233838383",
+			operationKey:       "read",
+			expand:             []string{"restrictions.user", "restrictions.group"},
+			startAt:            0,
+			maxResults:         50,
+			mockFile:           "./mocks/empty-json.json",
+			wantHTTPMethod:     http.MethodGet,
+			endpoint:           "/wiki/rest/api/content/233838383/restriction/byOperation/read?expand=restrictions.user%2Crestrictions.group&limit=50&start=0",
+			context:            context.Background(),
+			wantHTTPCodeReturn: http.StatusOK,
+			wantErr:            true,
+			expectedError:      "unexpected end of JSON input",
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+
+			//Init a new HTTP mock server
+			mockOptions := mockServerOptions{
+				Endpoint:           testCase.endpoint,
+				MockFilePath:       testCase.mockFile,
+				MethodAccepted:     testCase.wantHTTPMethod,
+				ResponseCodeWanted: testCase.wantHTTPCodeReturn,
+			}
+
+			mockServer, err := startMockServer(&mockOptions)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			defer mockServer.Close()
+
+			//Init the library instance
+			mockClient, err := startMockClient(mockServer.URL)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			service := &ContentRestrictionOperationService{client: mockClient}
+
+			gotResult, gotResponse, err := service.Get(testCase.context, testCase.contentID, testCase.operationKey, testCase.expand,
+				testCase.startAt, testCase.maxResults)
+
+			if testCase.wantErr {
+
+				if err != nil {
+					t.Logf("error returned: %v", err.Error())
+				}
+
+				assert.EqualError(t, err, testCase.expectedError)
+
+				if gotResponse != nil {
+					t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				}
+
+			} else {
+
+				assert.NoError(t, err)
+				assert.NotEqual(t, gotResponse, nil)
+				assert.NotEqual(t, gotResult, nil)
+
+				apiEndpoint, err := url.Parse(gotResponse.Endpoint)
+				if err != nil {
+					t.Fatal(err)
+				}
+
+				var endpointToAssert string
+
+				if apiEndpoint.Query().Encode() != "" {
+					endpointToAssert = fmt.Sprintf("%v?%v", apiEndpoint.Path, apiEndpoint.Query().Encode())
+				} else {
+					endpointToAssert = apiEndpoint.Path
+				}
+
+				t.Logf("HTTP Endpoint Wanted: %v, HTTP Endpoint Returned: %v", testCase.endpoint, endpointToAssert)
+				assert.Equal(t, testCase.endpoint, endpointToAssert)
+
+				t.Logf("HTTP Code Wanted: %v, HTTP Code Returned: %v", testCase.wantHTTPCodeReturn, gotResponse.Code)
+				assert.Equal(t, gotResponse.Code, testCase.wantHTTPCodeReturn)
+			}
+		})
+	}
+}