Skip to content

Commit

Permalink
Add #244 Integrate policy endpoints
Browse files Browse the repository at this point in the history
Signed-off-by: George J Padayatti <[email protected]>
  • Loading branch information
albinpa authored and georgepadayatti committed Oct 15, 2023
1 parent 38af443 commit 3a6292f
Show file tree
Hide file tree
Showing 15 changed files with 1,114 additions and 163 deletions.
49 changes: 49 additions & 0 deletions src/common/utils.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package common

import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
Expand Down Expand Up @@ -119,6 +122,8 @@ func ParsePaginationQueryParameters(r *http.Request) (startID string, limit int)

if ok {
limit, _ = strconv.Atoi(limits[0])
} else {
limit = 10
}
return
}
Expand Down Expand Up @@ -172,3 +177,47 @@ func Sanitize(s string) string {
p := bluemonday.UGCPolicy()
return p.Sanitize(s)
}

func IntegerToSemver(version int) string {
major := version
minor := 0
patch := 0

return fmt.Sprintf("%d.%d.%d", major, minor, patch)
}

func BumpMajorVersion(version string) (string, error) {
// Split the version into major, minor, and patch
versionParts := strings.Split(version, ".")

// Parse the parts into integers
major, err := strconv.Atoi(versionParts[0])
if err != nil {
return version, err
}

// Increment the major version and reset minor and patch to zero
return fmt.Sprintf("%d.0.0", major+1), err
}

func CalculateSHA1(data string) (string, error) {
// Convert the JSON string to bytes
dataBytes := []byte(data)

// Create a new SHA-1 hasher
sha1Hasher := sha1.New()

// Write the data to the hasher
_, err := sha1Hasher.Write(dataBytes)
if err != nil {
return "", err
}

// Get the hash sum
hashSum := sha1Hasher.Sum(nil)

// Convert the hash sum to a hex string
hashHex := hex.EncodeToString(hashSum)

return hashHex, err
}
7 changes: 7 additions & 0 deletions src/config/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@ const (
PolicyId = "policyId"
DataAgreementRecordId = "dataAgreementRecordId"
)

// Schemas
const (
DataAgreement = "dataAgreement"
Policy = "policy"
DataAgreementRecord = "dataAgreementRecord"
)
5 changes: 5 additions & 0 deletions src/database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ func Init(config *config.Configuration) error {
return err
}

err = initCollection("policies", []string{"id"}, true)
if err != nil {
return err
}

return nil
}

Expand Down
135 changes: 135 additions & 0 deletions src/handlerv2/addglobalpolicyconfigurations_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package handlerv2

import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"

"github.com/asaskevich/govalidator"
"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/policy"
"github.com/bb-consent/api/src/token"
"go.mongodb.org/mongo-driver/bson/primitive"
)

type RevisionForSnapshot struct {
policy.Revision
SerializedSnapshot string `json:"-"`
Id string `json:"-"`
SuccessorId string `json:"-"`
PredecessorHash string `json:"-"`
PredecessorSignature string `json:"-"`
SerializedHash string `json:"-"`
}

type addPolicyReq struct {
Policy policy.Policy `json:"policy" valid:"required"`
}

type addPolicyResp struct {
Policy policy.Policy `json:"policy"`
Revision interface{} `json:"revision"`
}

func validateAddPolicyRequestBody(policyReq addPolicyReq) error {
// validating request payload
valid, err := govalidator.ValidateStruct(policyReq)
if err != nil {
return err
}

if !valid {
return errors.New("invalid request payload")
}

if strings.TrimSpace(policyReq.Policy.Name) == "" {
return errors.New("missing mandatory param - Name")
}

if strings.TrimSpace(policyReq.Policy.Url) == "" {
return errors.New("missing mandatory param - Url")

}

return nil
}

func updatePolicyFromAddPolicyRequestBody(requestBody addPolicyReq, newPolicy policy.Policy) policy.Policy {
newPolicy.Name = requestBody.Policy.Name
newPolicy.Url = requestBody.Policy.Url
newPolicy.Jurisdiction = requestBody.Policy.Jurisdiction
newPolicy.IndustrySector = requestBody.Policy.IndustrySector
newPolicy.DataRetentionPeriodDays = requestBody.Policy.DataRetentionPeriodDays
newPolicy.GeographicRestriction = requestBody.Policy.GeographicRestriction
newPolicy.StorageLocation = requestBody.Policy.StorageLocation
return newPolicy
}

// AddGlobalPolicyConfiguration Handler to add global policy configuration
func AddGlobalPolicyConfiguration(w http.ResponseWriter, r *http.Request) {
// Current user
orgAdminId := token.GetUserID(r)

// Headers
organisationId := r.Header.Get(config.OrganizationId)
organisationId = common.Sanitize(organisationId)

// Request body
var policyReq addPolicyReq
b, _ := io.ReadAll(r.Body)
defer r.Body.Close()
json.Unmarshal(b, &policyReq)

// Validate request body
err := validateAddPolicyRequestBody(policyReq)
if err != nil {
common.HandleErrorV2(w, http.StatusBadRequest, err.Error(), err)
return
}

version := common.IntegerToSemver(1)

// Initialise policy
var newPolicy policy.Policy
newPolicy.Id = primitive.NewObjectID()
// Update policy from request body
newPolicy = updatePolicyFromAddPolicyRequestBody(policyReq, newPolicy)
newPolicy.OrganisationId = organisationId
newPolicy.IsDeleted = false
newPolicy.Version = version

// Create new revision
newRevision, err := policy.CreateRevisionForPolicy(newPolicy, orgAdminId)
if err != nil {
m := fmt.Sprintf("Failed to create revision for new policy: %v", newPolicy.Name)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}
newPolicy.Revisions = append(newPolicy.Revisions, newRevision)

// Save the policy to db
savedPolicy, err := policy.Add(newPolicy)
if err != nil {
m := fmt.Sprintf("Failed to create new policy: %v", newPolicy.Name)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}

// Constructing the response
var resp addPolicyResp
resp.Policy = savedPolicy

var revisionForHTTPResponse policy.RevisionForHTTPResponse
revisionForHTTPResponse.Init(newRevision)
resp.Revision = revisionForHTTPResponse

response, _ := json.Marshal(resp)
w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON)
w.WriteHeader(http.StatusOK)
w.Write(response)

}
72 changes: 30 additions & 42 deletions src/handlerv2/getglobalpolicyconfigurations_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,54 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/org"
"github.com/bb-consent/api/src/orgtype"
"github.com/bb-consent/api/src/policy"
"github.com/gorilla/mux"
)

type globalPolicyConfigurationResp struct {
PolicyURL string
DataRetention org.DataRetention
Jurisdiction string
Disclosure string
Type orgtype.OrgType
Restriction string
Shared3PP bool
type getPolicyResp struct {
Policy policy.Policy `json:"policy"`
Revision interface{} `json:"revision"`
}

// GetGlobalPolicyConfiguration Handler to get global policy configurations
func GetGlobalPolicyConfiguration(w http.ResponseWriter, r *http.Request) {
organizationID := r.Header.Get(config.OrganizationId)
organisationId := r.Header.Get(config.OrganizationId)
organisationId = common.Sanitize(organisationId)

o, err := org.Get(organizationID)
if err != nil {
m := fmt.Sprintf("Failed to fetch organization: %v", organizationID)
common.HandleError(w, http.StatusInternalServerError, m, err)
return
}
policyId := mux.Vars(r)[config.PolicyId]

// Constructing the response
var resp globalPolicyConfigurationResp

resp.PolicyURL = o.PolicyURL
resp.DataRetention = o.DataRetention
// Parse the URL query parameters
queryParams := r.URL.Query()
revisionId := queryParams.Get("revisionId")

if len(strings.TrimSpace(o.Jurisdiction)) == 0 {
resp.Jurisdiction = o.Location
o.Jurisdiction = o.Location
} else {
resp.Jurisdiction = o.Jurisdiction
p, err := policy.Get(policyId, organisationId)
if err != nil {
m := fmt.Sprintf("Failed to fetch policy: %v", policyId)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}
var revision policy.Revision
if revisionId != "" {
for _, p := range p.Revisions {
if p.Id == revisionId {
revision = p
}
}

if len(strings.TrimSpace(o.Disclosure)) == 0 {
resp.Disclosure = "false"
o.Disclosure = "false"
} else {
resp.Disclosure = o.Disclosure
revision = p.Revisions[len(p.Revisions)-1]
}

resp.Type = o.Type
resp.Restriction = o.Restriction
resp.Shared3PP = o.Shared3PP
// Constructing the response
var resp getPolicyResp
resp.Policy = p

// Updating global configuration policy with defaults
_, err = org.Update(o)
if err != nil {
m := fmt.Sprintf("Failed to update global configuration with defaults to organization: %v", organizationID)
common.HandleError(w, http.StatusInternalServerError, m, err)
return
}
var revisionForHTTPResponse policy.RevisionForHTTPResponse
revisionForHTTPResponse.Init(revision)
resp.Revision = revisionForHTTPResponse

response, _ := json.Marshal(resp)
w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON)
Expand Down
31 changes: 28 additions & 3 deletions src/handlerv2/orgdeletepolicy_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,43 @@ package handlerv2

import (
"encoding/json"
"fmt"
"net/http"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/policy"
"github.com/gorilla/mux"
)

// OrgDeletePolicy Handler to delete global policy revision
func OrgDeletePolicy(w http.ResponseWriter, r *http.Request) {
organisationId := r.Header.Get(config.OrganizationId)
organisationId = common.Sanitize(organisationId)
policyId := mux.Vars(r)[config.PolicyId]

// Constructing the response
var resp globalPolicyConfigurationResp
currentPolicy, err := policy.Get(policyId, organisationId)
if err != nil {
m := fmt.Sprintf("Failed to fetch policy: %v", policyId)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}

response, _ := json.Marshal(resp)
currentRevision := currentPolicy.Revisions[len(currentPolicy.Revisions)-1]

currentPolicy.IsDeleted = true

_, err = policy.Update(currentPolicy, organisationId)
if err != nil {
m := fmt.Sprintf("Failed to delete policy: %v", policyId)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}

var revisionForHTTPResponse policy.RevisionForHTTPResponse
revisionForHTTPResponse.Init(currentRevision)

response, _ := json.Marshal(revisionForHTTPResponse)
w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON)
w.WriteHeader(http.StatusOK)
w.Write(response)
Expand Down
Loading

0 comments on commit 3a6292f

Please sign in to comment.