Skip to content

Commit

Permalink
Merge 766c465 into aeb8e03
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx authored Feb 12, 2024
2 parents aeb8e03 + 766c465 commit 29cc706
Show file tree
Hide file tree
Showing 81 changed files with 1,270 additions and 780 deletions.
64 changes: 64 additions & 0 deletions internal/actor/actoruid/uid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package actoruid

import (
"errors"
"strings"

"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/google/uuid"
)

const prefix = "urn:opg:poas:makeregister:users:"

type UID struct{ value string }

func New() UID {
return UID{value: uuid.NewString()}
}

func FromRequest(r interface{ FormValue(string) string }) UID {
return UID{value: r.FormValue("id")}
}

func (u UID) IsZero() bool {
return len(u.value) == 0
}

func (u UID) String() string {
return u.value
}

func (u UID) PrefixedString() string {
return prefix + u.value
}

func (u UID) MarshalJSON() ([]byte, error) {
if u.value == "" {
return []byte("null"), nil
}

return []byte(`"` + u.PrefixedString() + `"`), nil
}

func (u *UID) UnmarshalText(text []byte) error {
if len(text) == 0 {
return nil
}

uid, found := strings.CutPrefix(string(text), prefix)
if !found {
return errors.New("invalid uid prefix")
}

u.value = uid
return nil
}

func (u UID) MarshalDynamoDBAttributeValue() (types.AttributeValue, error) {
return attributevalue.Marshal(u.value)
}

func (u *UID) UnmarshalDynamoDBAttributeValue(av types.AttributeValue) error {
return attributevalue.Unmarshal(av, &u.value)
}
71 changes: 71 additions & 0 deletions internal/actor/actoruid/uid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package actoruid

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

"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/stretchr/testify/assert"
)

func TestUID(t *testing.T) {
uid := UID{value: "abc"}

assert.Equal(t, "abc", uid.String())
assert.Equal(t, prefix+"abc", uid.PrefixedString())
}

func TestUIDFromRequest(t *testing.T) {
r, _ := http.NewRequest(http.MethodGet, "/?id=abc", nil)

assert.Equal(t, UID{value: "abc"}, FromRequest(r))
}

func TestUIDZero(t *testing.T) {
assert.True(t, UID{}.IsZero())
assert.False(t, New().IsZero())
}

func TestUIDJSON(t *testing.T) {
uid := UID{value: "abc"}

jsonData, _ := json.Marshal(uid)
assert.Equal(t, `"urn:opg:poas:makeregister:users:abc"`, string(jsonData))

var a UID
err := json.Unmarshal([]byte(`"urn:opg:poas:makeregister:users:abc"`), &a)
assert.Nil(t, err)
assert.Equal(t, a, uid)

emptyData, _ := json.Marshal(UID{})
assert.Equal(t, `null`, string(emptyData))

var b UID
err = json.Unmarshal([]byte(`null`), &b)
assert.Nil(t, err)
assert.True(t, b.IsZero())

var c UID
err = json.Unmarshal([]byte(`""`), &c)
assert.Nil(t, err)
assert.True(t, c.IsZero())
}

func TestUIDJSONInvalidPrefix(t *testing.T) {
var v UID
err := json.Unmarshal([]byte(`"urn:opg:poas:makeregister:users2:abc"`), &v)
assert.ErrorContains(t, err, "invalid uid prefix")
}

func TestUIDAttributeValue(t *testing.T) {
uid := UID{value: "abc"}

avData, _ := attributevalue.Marshal(uid)
assert.Equal(t, &types.AttributeValueMemberS{Value: "abc"}, avData)

var b UID
_ = attributevalue.Unmarshal(&types.AttributeValueMemberS{Value: "abc"}, &b)
assert.Equal(t, b, uid)
}
19 changes: 11 additions & 8 deletions internal/actor/attorney.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"fmt"
"slices"

"github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid"
"github.com/ministryofjustice/opg-modernising-lpa/internal/date"
"github.com/ministryofjustice/opg-modernising-lpa/internal/place"
)

// Attorney contains details about an attorney or replacement attorney, provided by the applicant
type Attorney struct {
// Identifies the attorney being edited
ID string
// UID for the actor
UID actoruid.UID
// First names of the attorney
FirstNames string
// Last name of the attorney
Expand All @@ -30,6 +31,8 @@ func (a Attorney) FullName() string {

// TrustCorporation contains details about a trust corporation, provided by the applicant
type TrustCorporation struct {
// UID for the actor
UID actoruid.UID
// Name of the company
Name string
// CompanyNumber as registered by Companies House
Expand Down Expand Up @@ -83,8 +86,8 @@ func (as Attorneys) Addresses() []place.Address {
return addresses
}

func (as Attorneys) Get(id string) (Attorney, bool) {
idx := as.Index(id)
func (as Attorneys) Get(uid actoruid.UID) (Attorney, bool) {
idx := as.Index(uid)
if idx == -1 {
return Attorney{}, false
}
Expand All @@ -93,7 +96,7 @@ func (as Attorneys) Get(id string) (Attorney, bool) {
}

func (as *Attorneys) Put(attorney Attorney) {
idx := as.Index(attorney.ID)
idx := as.Index(attorney.UID)
if idx == -1 {
as.Attorneys = append(as.Attorneys, attorney)
} else {
Expand All @@ -102,7 +105,7 @@ func (as *Attorneys) Put(attorney Attorney) {
}

func (as *Attorneys) Delete(attorney Attorney) bool {
idx := as.Index(attorney.ID)
idx := as.Index(attorney.UID)
if idx == -1 {
return false
}
Expand All @@ -111,8 +114,8 @@ func (as *Attorneys) Delete(attorney Attorney) bool {
return true
}

func (as *Attorneys) Index(id string) int {
return slices.IndexFunc(as.Attorneys, func(a Attorney) bool { return a.ID == id })
func (as *Attorneys) Index(uid actoruid.UID) int {
return slices.IndexFunc(as.Attorneys, func(a Attorney) bool { return a.UID == uid })
}

func (as Attorneys) FullNames() []string {
Expand Down
3 changes: 2 additions & 1 deletion internal/actor/attorney_provided.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package actor
import (
"time"

"github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid"
"github.com/ministryofjustice/opg-modernising-lpa/internal/form"
"github.com/ministryofjustice/opg-modernising-lpa/internal/localize"
)
Expand All @@ -12,7 +13,7 @@ import (
type AttorneyProvidedDetails struct {
PK, SK string
// The identifier of the attorney or replacement attorney being edited
ID string
UID actoruid.UID
// The identifier of the LPA the attorney or replacement attorney is named in
LpaID string
// Tracking when AttorneyProvidedDetails is updated
Expand Down
50 changes: 31 additions & 19 deletions internal/actor/attorney_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package actor
import (
"testing"

"github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid"
"github.com/ministryofjustice/opg-modernising-lpa/internal/place"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -94,29 +95,32 @@ func TestAttorneysAddresses(t *testing.T) {
}

func TestAttorneysGet(t *testing.T) {
uid1 := actoruid.New()
uid2 := actoruid.New()

testCases := map[string]struct {
attorneys Attorneys
expectedAttorney Attorney
id string
uid actoruid.UID
expectedFound bool
}{
"attorney exists": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1", FirstNames: "Bob"}, {ID: "2"}}},
expectedAttorney: Attorney{ID: "1", FirstNames: "Bob"},
id: "1",
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1, FirstNames: "Bob"}, {UID: uid2}}},
expectedAttorney: Attorney{UID: uid1, FirstNames: "Bob"},
uid: uid1,
expectedFound: true,
},
"attorney does not exist": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1", FirstNames: "Bob"}, {ID: "2"}}},
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1, FirstNames: "Bob"}, {UID: uid2}}},
expectedAttorney: Attorney{},
id: "4",
uid: actoruid.New(),
expectedFound: false,
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
a, found := tc.attorneys.Get(tc.id)
a, found := tc.attorneys.Get(tc.uid)

assert.Equal(t, tc.expectedFound, found)
assert.Equal(t, tc.expectedAttorney, a)
Expand All @@ -125,20 +129,25 @@ func TestAttorneysGet(t *testing.T) {
}

func TestAttorneysPut(t *testing.T) {
uid1 := actoruid.New()
uid2 := actoruid.New()

newAttorney := Attorney{UID: actoruid.New(), FirstNames: "Bob"}

testCases := map[string]struct {
attorneys Attorneys
expectedAttorneys Attorneys
updatedAttorney Attorney
}{
"attorney exists": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{ID: "1", FirstNames: "Bob"}, {ID: "2"}}},
updatedAttorney: Attorney{ID: "1", FirstNames: "Bob"},
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{UID: uid1, FirstNames: "Bob"}, {UID: uid2}}},
updatedAttorney: Attorney{UID: uid1, FirstNames: "Bob"},
},
"attorney does not exist": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}, {ID: "3", FirstNames: "Bob"}}},
updatedAttorney: Attorney{ID: "3", FirstNames: "Bob"},
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}, newAttorney}},
updatedAttorney: newAttorney,
},
}

Expand All @@ -152,22 +161,25 @@ func TestAttorneysPut(t *testing.T) {
}

func TestAttorneysDelete(t *testing.T) {
uid1 := actoruid.New()
uid2 := actoruid.New()

testCases := map[string]struct {
attorneys Attorneys
expectedAttorneys Attorneys
attorneyToDelete Attorney
expectedDeleted bool
}{
"attorney exists": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}}},
attorneyToDelete: Attorney{ID: "2"},
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}}},
attorneyToDelete: Attorney{UID: uid2},
expectedDeleted: true,
},
"attorney does not exist": {
attorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{ID: "1"}, {ID: "2"}}},
attorneyToDelete: Attorney{ID: "3"},
attorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}}},
expectedAttorneys: Attorneys{Attorneys: []Attorney{{UID: uid1}, {UID: uid2}}},
attorneyToDelete: Attorney{UID: actoruid.New()},
expectedDeleted: false,
},
}
Expand Down
3 changes: 3 additions & 0 deletions internal/actor/certificate_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package actor
import (
"fmt"

"github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid"
"github.com/ministryofjustice/opg-modernising-lpa/internal/place"
)

Expand Down Expand Up @@ -33,6 +34,8 @@ const (

// CertificateProvider contains details about the certificate provider, provided by the applicant
type CertificateProvider struct {
// UID for the actor
UID actoruid.UID
// First names of the certificate provider
FirstNames string
// Last name of the certificate provider
Expand Down
3 changes: 3 additions & 0 deletions internal/actor/donor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package actor
import (
"fmt"

"github.com/ministryofjustice/opg-modernising-lpa/internal/actor/actoruid"
"github.com/ministryofjustice/opg-modernising-lpa/internal/date"
"github.com/ministryofjustice/opg-modernising-lpa/internal/form"
"github.com/ministryofjustice/opg-modernising-lpa/internal/place"
)

// Donor contains details about the donor, provided by the applicant
type Donor struct {
// UID for the actor
UID actoruid.UID
// First names of the donor
FirstNames string
// Last name of the donor
Expand Down
Loading

0 comments on commit 29cc706

Please sign in to comment.