Skip to content

Commit

Permalink
Merge pull request #1434 from ministryofjustice/MLPAB-1909-voucher-id…
Browse files Browse the repository at this point in the history
…entity

MLPAB-1909 Add pages for voucher identity check
  • Loading branch information
hawx authored Aug 20, 2024
2 parents 3288ba1 + e6fe3f3 commit 008a4c2
Show file tree
Hide file tree
Showing 31 changed files with 1,031 additions and 54 deletions.
39 changes: 39 additions & 0 deletions cypress/e2e/voucher/confirm-your-identity.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
describe('Confirm your identity', () => {
beforeEach(() => {
cy.visit('/fixtures/voucher?redirect=/confirm-your-identity&progress=verifyDonorDetails');
});

it('can be confirmed', () => {
cy.checkA11yApp();
cy.contains('a', 'Continue').click();
cy.contains('label', 'Vivian Vaughn').click();
cy.contains('button', 'Continue').click();

cy.url().should('contain', '/one-login-identity-details');
cy.checkA11yApp();
cy.contains('a', 'Continue').click();

cy.get('.govuk-task-list li:nth-child(3)').should('contain', 'Completed');
cy.contains('a', 'Confirm your identity').click();

cy.url().should('contain', '/one-login-identity-details');
cy.contains('a', 'Continue').click();

cy.contains('a', 'Confirm your name').click();
cy.contains('a', 'Change').should('not.exist');

cy.contains('a', 'Manage your LPAs').click();
cy.contains('I’m vouching for someone');
});

it('can fail', () => {
cy.contains('a', 'Continue').click();
cy.contains('label', 'Sam Smith').click();
cy.contains('button', 'Continue').click();

cy.url().should('contain', '/unable-to-confirm-identity');

cy.contains('a', 'Manage your LPAs').click();
cy.contains('I’m vouching for someone').should('not.exist');;
});
});
2 changes: 2 additions & 0 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func App(
dashboardStore,
errorHandler,
lpaStoreResolvingService,
notifyClient,
appPublicURL,
)

supporterpage.Register(
Expand Down
3 changes: 2 additions & 1 deletion internal/dashboard/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ func (s *Store) GetAll(ctx context.Context) (results dashboarddata.Results, err

lpaID := voucherProvidedDetails.LpaID

if voucherProvidedDetails.Tasks.SignTheDeclaration.IsCompleted() {
if voucherProvidedDetails.Tasks.SignTheDeclaration.IsCompleted() ||
(voucherProvidedDetails.Tasks.ConfirmYourIdentity.IsCompleted() && !voucherProvidedDetails.IdentityConfirmed()) {
delete(voucherMap, lpaID)
}

Expand Down
4 changes: 4 additions & 0 deletions internal/lpastore/lpadata/voucher.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ type Voucher struct {
LastName string
Email string
}

func (v Voucher) FullName() string {
return v.FirstNames + " " + v.LastName
}
11 changes: 11 additions & 0 deletions internal/lpastore/lpadata/voucher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package lpadata

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestVoucherFullName(t *testing.T) {
assert.Equal(t, "John Smith", Voucher{FirstNames: "John", LastName: "Smith"}.FullName())
}
12 changes: 12 additions & 0 deletions internal/notify/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,15 @@ type AttorneyOptedOutEmail struct {
func (e AttorneyOptedOutEmail) emailID(isProduction bool) string {
return "TODO"
}

type VoucherFailedIdentityCheckEmail struct {
Greeting string
DonorFullName string
VoucherFullName string
LpaType string
DonorStartPageURL string
}

func (e VoucherFailedIdentityCheckEmail) emailID(isProduction bool) string {
return "TODO"
}
13 changes: 13 additions & 0 deletions internal/page/fixtures/voucher.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ministryofjustice/opg-modernising-lpa/internal/appcontext"
"github.com/ministryofjustice/opg-modernising-lpa/internal/donor"
"github.com/ministryofjustice/opg-modernising-lpa/internal/donor/donordata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/identity"
"github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/page"
"github.com/ministryofjustice/opg-modernising-lpa/internal/random"
Expand All @@ -32,6 +33,7 @@ func Voucher(
progressValues := []string{
"confirmYourName",
"verifyDonorDetails",
"confirmYourIdentity",
}

return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request) error {
Expand Down Expand Up @@ -125,13 +127,24 @@ func Voucher(
}

if progress >= slices.Index(progressValues, "confirmYourName") {
voucherDetails.FirstNames = donorDetails.Voucher.FirstNames
voucherDetails.LastName = donorDetails.Voucher.LastName
voucherDetails.Tasks.ConfirmYourName = task.StateCompleted
}

if progress >= slices.Index(progressValues, "verifyDonorDetails") {
voucherDetails.Tasks.VerifyDonorDetails = task.StateCompleted
}

if progress >= slices.Index(progressValues, "confirmYourIdentity") {
voucherDetails.IdentityUserData = identity.UserData{
Status: identity.StatusConfirmed,
FirstNames: voucherDetails.FirstNames,
LastName: voucherDetails.LastName,
}
voucherDetails.Tasks.ConfirmYourIdentity = task.StateCompleted
}

if err := voucherStore.Put(voucherCtx, voucherDetails); err != nil {
return err
}
Expand Down
2 changes: 0 additions & 2 deletions internal/templatefn/fn.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/ministryofjustice/opg-modernising-lpa/internal/localize"
"github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore"
"github.com/ministryofjustice/opg-modernising-lpa/internal/lpastore/lpadata"
"github.com/ministryofjustice/opg-modernising-lpa/internal/voucher"
)

// Globals contains values that are used in templates and do not change as the
Expand Down Expand Up @@ -88,7 +87,6 @@ func All(globals *Globals) map[string]any {
"checkboxEq": checkboxEq,
"lpaDecisions": lpaDecisions,
"summaryRow": summaryRow,
"voucherCanGoTo": voucher.CanGoTo,
}
}

Expand Down
10 changes: 6 additions & 4 deletions internal/templatefn/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ type voucherPaths struct {
Login page.Path
Start page.Path

TaskList voucher.Path
YourName voucher.Path
TaskList voucher.Path
YourName voucher.Path
IdentityWithOneLogin voucher.Path
}

type appPaths struct {
Expand Down Expand Up @@ -325,8 +326,9 @@ var paths = appPaths{
Login: page.PathVoucherLogin,
Start: page.PathVoucherStart,

TaskList: voucher.PathTaskList,
YourName: voucher.PathYourName,
TaskList: voucher.PathTaskList,
YourName: voucher.PathYourName,
IdentityWithOneLogin: voucher.PathIdentityWithOneLogin,
},

HealthCheck: healthCheckPaths{
Expand Down
27 changes: 17 additions & 10 deletions internal/voucher/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import (
)

const (
PathTaskList = Path("/task-list")
PathConfirmAllowedToVouch = Path("/confirm-allowed-to-vouch")
PathConfirmYourName = Path("/confirm-your-name")
PathYourName = Path("/your-name")
PathVerifyDonorDetails = Path("/verify-donor-details")
PathDonorDetailsDoNotMatch = Path("/donor-details-do-not-match")
PathConfirmYourIdentity = Path("/confirm-your-identity")
PathSignTheDeclaration = Path("/sign-the-declaration")
PathTaskList = Path("/task-list")
PathConfirmAllowedToVouch = Path("/confirm-allowed-to-vouch")
PathConfirmYourName = Path("/confirm-your-name")
PathYourName = Path("/your-name")
PathVerifyDonorDetails = Path("/verify-donor-details")
PathDonorDetailsDoNotMatch = Path("/donor-details-do-not-match")
PathConfirmYourIdentity = Path("/confirm-your-identity")
PathSignTheDeclaration = Path("/sign-the-declaration")
PathIdentityWithOneLogin = Path("/identity-with-one-login")
PathIdentityWithOneLoginCallback = Path("/identity-with-one-login-callback")
PathOneLoginIdentityDetails = Path("/one-login-identity-details")
PathUnableToConfirmIdentity = Path("/unable-to-confirm-identity")
)

type Path string
Expand All @@ -39,8 +43,11 @@ func (p Path) Redirect(w http.ResponseWriter, r *http.Request, appData appcontex
return nil
}

func (p Path) canVisit(provided *voucherdata.Provided) bool {
func (p Path) CanGoTo(provided *voucherdata.Provided) bool {
switch p {
case PathYourName:
return !provided.Tasks.ConfirmYourIdentity.IsCompleted()

case PathVerifyDonorDetails:
return provided.Tasks.ConfirmYourName.IsCompleted() &&
!provided.Tasks.VerifyDonorDetails.IsCompleted()
Expand All @@ -67,7 +74,7 @@ func CanGoTo(provided *voucherdata.Provided, url string) bool {

if strings.HasPrefix(path, "/voucher/") {
_, voucherPath, _ := strings.Cut(strings.TrimPrefix(path, "/voucher/"), "/")
return Path("/" + voucherPath).canVisit(provided)
return Path("/" + voucherPath).CanGoTo(provided)
}

return true
Expand Down
12 changes: 12 additions & 0 deletions internal/voucher/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ func TestCanGoTo(t *testing.T) {
url: PathTaskList.Format("123"),
expected: true,
},
"your name": {
provided: &voucherdata.Provided{},
url: PathYourName.Format("123"),
expected: true,
},
"your name when identity completed": {
provided: &voucherdata.Provided{
Tasks: voucherdata.Tasks{ConfirmYourIdentity: task.StateCompleted},
},
url: PathYourName.Format("123"),
expected: false,
},
"verify donor details": {
provided: &voucherdata.Provided{},
url: PathVerifyDonorDetails.Format("123"),
Expand Down
14 changes: 10 additions & 4 deletions internal/voucher/voucherdata/provided.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ministryofjustice/opg-modernising-lpa/internal/dynamo"
"github.com/ministryofjustice/opg-modernising-lpa/internal/form"
"github.com/ministryofjustice/opg-modernising-lpa/internal/identity"
"github.com/ministryofjustice/opg-modernising-lpa/internal/task"
)

Expand All @@ -20,15 +21,20 @@ type Provided struct {
Tasks Tasks
// Email is the email address of the voucher
Email string
// FirstNames is the first names provided by the voucher. If set it overrides
// that provided by the donor.
// FirstNames is the first names confirmed by the voucher.
FirstNames string
// LastName is a last name provided by the voucher. If set it overrides that
// provided by the donor.
// LastName is the last name confirmed by the voucher.
LastName string
// DonorDetailsMatch records whether the voucher confirms that the details
// presented to them match the donor they expected to vouch for.
DonorDetailsMatch form.YesNo
// IdentityUserData records the results of the identity check taken by the
// voucher.
IdentityUserData identity.UserData
}

func (p Provided) IdentityConfirmed() bool {
return p.IdentityUserData.Status.IsConfirmed() && p.IdentityUserData.MatchName(p.FirstNames, p.LastName)
}

type Tasks struct {
Expand Down
5 changes: 5 additions & 0 deletions internal/voucher/voucherpage/confirm_your_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type confirmYourNameData struct {
App appcontext.Data
Errors validation.List
Lpa *lpadata.Lpa
Tasks voucherdata.Tasks
FirstNames string
LastName string
}
Expand All @@ -41,6 +42,9 @@ func ConfirmYourName(tmpl template.Template, lpaStoreResolvingService LpaStoreRe
redirect := voucher.PathTaskList
state := task.StateCompleted

provided.FirstNames = firstNames
provided.LastName = lastName

if lastName == lpa.Donor.LastName {
redirect = voucher.PathConfirmAllowedToVouch
state = task.StateInProgress
Expand All @@ -57,6 +61,7 @@ func ConfirmYourName(tmpl template.Template, lpaStoreResolvingService LpaStoreRe
return tmpl(w, &confirmYourNameData{
App: appData,
Lpa: lpa,
Tasks: provided.Tasks,
FirstNames: firstNames,
LastName: lastName,
})
Expand Down
12 changes: 7 additions & 5 deletions internal/voucher/voucherpage/guidance.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ import (
)

type guidanceData struct {
App appcontext.Data
Errors validation.List
Lpa *lpadata.Lpa
App appcontext.Data
Errors validation.List
Voucher *voucherdata.Provided
Lpa *lpadata.Lpa
}

func Guidance(tmpl template.Template, lpaStoreResolvingService LpaStoreResolvingService) Handler {
return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, _ *voucherdata.Provided) error {
return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, provided *voucherdata.Provided) error {
data := &guidanceData{
App: appData,
App: appData,
Voucher: provided,
}

if lpaStoreResolvingService != nil {
Expand Down
40 changes: 40 additions & 0 deletions internal/voucher/voucherpage/identity_with_one_login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package voucherpage

import (
"net/http"

"github.com/ministryofjustice/opg-modernising-lpa/internal/appcontext"
"github.com/ministryofjustice/opg-modernising-lpa/internal/localize"
"github.com/ministryofjustice/opg-modernising-lpa/internal/sesh"
"github.com/ministryofjustice/opg-modernising-lpa/internal/voucher"
"github.com/ministryofjustice/opg-modernising-lpa/internal/voucher/voucherdata"
)

func IdentityWithOneLogin(oneLoginClient OneLoginClient, sessionStore SessionStore, randomString func(int) string) Handler {
return func(appData appcontext.Data, w http.ResponseWriter, r *http.Request, _ *voucherdata.Provided) error {
locale := ""
if appData.Lang == localize.Cy {
locale = "cy"
}

state := randomString(12)
nonce := randomString(12)

authCodeURL, err := oneLoginClient.AuthCodeURL(state, nonce, locale, true)
if err != nil {
return err
}

if err := sessionStore.SetOneLogin(r, w, &sesh.OneLoginSession{
State: state,
Nonce: nonce,
Locale: locale,
Redirect: voucher.PathIdentityWithOneLoginCallback.Format(appData.LpaID),
}); err != nil {
return err
}

http.Redirect(w, r, authCodeURL, http.StatusFound)
return nil
}
}
Loading

0 comments on commit 008a4c2

Please sign in to comment.