diff --git a/src/read-models/members/get-all.ts b/src/read-models/members/get-all.ts index fc451eb9..5d18835f 100644 --- a/src/read-models/members/get-all.ts +++ b/src/read-models/members/get-all.ts @@ -95,33 +95,43 @@ export const liftActorOrUser = (actorOrUser: Actor | User) => const redactEmail = (member: MemberDetails): MemberDetails => Object.assign({}, member, {emailAddress: '******'}); -const redactEmails = (details: MultipleMemberDetails) => { - const redactedDetails = new Map(); - for (const [k, v] of details.entries()) { - redactedDetails.set(k, redactEmail(v)); - } - return redactedDetails; -}; - -const redactDetailsForActor = - (actor: Actor) => (details: MultipleMemberDetails) => { +// If a given |actor|, with the context of |details| is viewing |member| +// should sensitive details (email) about that member be redacted. +const shouldRedact = + (actor: Actor) => + (details: MultipleMemberDetails) => + (member: MemberDetails) => { switch (actor.tag) { case 'token': - return details; + return false; case 'system': - return details; + return false; case 'user': { - for (const member of details.values()) { - if ( - member.emailAddress === actor.user.emailAddress && - member.isSuperUser - ) { - return details; - } + const viewingUser = actor.user; + const viewingMember = details.get(viewingUser.memberNumber); + if (viewingMember !== undefined && viewingMember.isSuperUser) { + return false; + } + if (viewingUser.memberNumber === member.memberNumber) { + return false; } - return redactEmails(details); + return true; + } + } + }; + +const redactDetailsForActor = + (actor: Actor) => (details: MultipleMemberDetails) => { + const needsRedaction = shouldRedact(actor)(details); + const redactedDetails = new Map(); + for (const [memberNumber, member] of details.entries()) { + if (needsRedaction(member)) { + redactedDetails.set(memberNumber, redactEmail(member)); + } else { + redactedDetails.set(memberNumber, member); } } + return redactedDetails; }; export const getAllDetailsAsActor = diff --git a/src/read-models/members/get.ts b/src/read-models/members/get.ts index b84f96d6..67f75587 100644 --- a/src/read-models/members/get.ts +++ b/src/read-models/members/get.ts @@ -1,8 +1,14 @@ import {pipe} from 'fp-ts/lib/function'; import * as RA from 'fp-ts/ReadonlyArray'; import * as O from 'fp-ts/Option'; -import {MemberDetails, DomainEvent, filterByName} from '../../types'; -import {getAllDetails, pertinentEvents} from './get-all'; +import { + MemberDetails, + DomainEvent, + filterByName, + Actor, + User, +} from '../../types'; +import {getAllDetails, getAllDetailsAsActor, pertinentEvents} from './get-all'; export const getDetails = (memberNumber: number) => @@ -14,3 +20,11 @@ export const getDetails = getAllDetails, allDetails => O.fromNullable(allDetails.get(memberNumber)) ); + +export const getDetailsAsActor = + (actorOrUser: Actor | User) => + (memberNumber: number) => + (events: ReadonlyArray) => + pipe(events, getAllDetailsAsActor(actorOrUser), allDetails => + O.fromNullable(allDetails.get(memberNumber)) + ); diff --git a/src/read-models/members/index.ts b/src/read-models/members/index.ts index 2284af6b..221339c3 100644 --- a/src/read-models/members/index.ts +++ b/src/read-models/members/index.ts @@ -1,5 +1,5 @@ import {getAll, getAllDetails, getAllDetailsAsActor} from './get-all'; -import {getDetails} from './get'; +import {getDetails, getDetailsAsActor} from './get'; import {lookupByEmail} from './lookup-by-email'; import {getPotentialOwners} from './get-potential-owners'; import {getFailedImports} from './get-failed-imports'; @@ -10,6 +10,7 @@ export const members = { getAllDetails, getAllDetailsAsActor, getDetails, + getDetailsAsActor, getFailedImports, getPotentialOwners, };