-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9218aab
commit 638c283
Showing
11 changed files
with
234 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import {getMembershipStore} from "./store"; | ||
|
||
export async function deleteMembership(membershipId: string) { | ||
const store = getMembershipStore(); | ||
return store.delete(membershipId); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import {getMembershipStore} from "./store"; | ||
|
||
export function getMembership(membershipId: string) { | ||
const store = getMembershipStore(); | ||
return store.get(membershipId); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import {setMembership} from "./set-membership"; | ||
import {Membership, MembershipData} from "./types"; | ||
|
||
export async function createMembershipReferences(input: (string | MembershipData)[]): Promise<Membership[]> { | ||
const membershipInput = parseMembershipReferences(input); | ||
return membershipInput.length ? await Promise.all( | ||
membershipInput.map(setMembership) | ||
) : []; | ||
} | ||
|
||
export function getMembershipReferenceMap(memberships: Membership[]) { | ||
return new Map( | ||
memberships.map(membership => [membership.reference, membership]) | ||
); | ||
} | ||
|
||
export function parseMembershipReferences(memberships: (MembershipData | string)[]): MembershipData[] { | ||
return [ | ||
...(memberships ?? []).map(membership => { | ||
if (typeof membership === "string") { | ||
return { reference: membership } | ||
} | ||
return membership; | ||
}) | ||
] | ||
.filter( | ||
(value, index, array) => { | ||
const before = array.slice(0, index); | ||
return !before.find(other => other.reference === value.reference); | ||
} | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from "./types"; | ||
export * from "./get-membership"; | ||
export * from "./set-membership"; | ||
export * from "./store"; | ||
export * from "./delete-membership"; | ||
export * as membershipSchema from "./schema"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
export const membershipData = { | ||
type: "object", | ||
properties: { | ||
reference: { | ||
type: "string" | ||
}, | ||
name: { | ||
type: "string", | ||
nullable: true | ||
}, | ||
email: { | ||
type: "string", | ||
nullable: true | ||
}, | ||
membershipId: { | ||
type: "string", | ||
nullable: true | ||
}, | ||
createdAt: { | ||
type: "string", | ||
nullable: true | ||
}, | ||
}, | ||
additionalProperties: true, | ||
required: [ | ||
"reference" | ||
] | ||
} | ||
|
||
export const membership = { | ||
type: "object", | ||
properties: { | ||
...membershipData.properties, | ||
membershipId: { | ||
type: "string", | ||
}, | ||
createdAt: { | ||
type: "string", | ||
}, | ||
}, | ||
additionalProperties: true, | ||
required: [ | ||
...membershipData.required, | ||
"membershipId", | ||
"createdAt" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import {getMembershipStore} from "./store"; | ||
import {Membership, PartialMembership} from "./types"; | ||
import {createHash} from "crypto"; | ||
import {getMembership} from "./get-membership"; | ||
import {entries} from "../entries"; | ||
import {getMaybePartner, getMaybeUser, isUnauthenticated} from "../../authentication"; | ||
import {v4} from "uuid"; | ||
import {ok} from "../../is"; | ||
|
||
const { | ||
ATTENDEE_DISABLE_PARTITION, | ||
ATTENDEE_PARTITION, | ||
} = process.env; | ||
|
||
function getPartitionPrefix() { | ||
if (ATTENDEE_PARTITION) { | ||
return ATTENDEE_PARTITION; | ||
} | ||
const partner = getMaybePartner(); | ||
// If authenticated, membership information will be retained across happenings | ||
if (partner?.partnerId) { | ||
return `partner:${partner.partnerId}:` | ||
} | ||
const user = getMaybeUser(); | ||
if (user?.userId) { | ||
// Users can create their own memberships | ||
return `user:${user.userId}:` | ||
} | ||
ok(isUnauthenticated(), "Expected user or partner if not anonymous"); | ||
// Random every time if no authentication :) | ||
// If creating a happening tree, each new tree request will have a new set of memberships | ||
return v4(); | ||
} | ||
|
||
/** | ||
* Allows partial update of an membership, retains existing properties | ||
* @param data | ||
*/ | ||
export async function setMembership(data: PartialMembership) { | ||
const store = getMembershipStore(); | ||
let reference = data.reference, | ||
membershipId = data.membershipId; | ||
// Allows for either reference or membershipId to be provided as a reference string | ||
if (!membershipId) { | ||
const existing = await getMembership(reference); | ||
if (existing) { | ||
reference = existing.reference; | ||
membershipId = existing.membershipId; | ||
} | ||
} | ||
if (!membershipId) { | ||
membershipId = createMembershipId(); | ||
} | ||
const existing = await getMembership(membershipId); | ||
if (existing && !isDifferent(existing)) { | ||
return existing; | ||
} | ||
const createdAt = data.createdAt || new Date().toISOString(); | ||
const createdByPartnerId = getMaybePartner()?.partnerId; | ||
const createdByUserId = getMaybeUser()?.userId; | ||
const membership: Membership = { | ||
...existing, | ||
...data, | ||
reference, | ||
membershipId, | ||
createdAt, | ||
createdByPartnerId, | ||
createdByUserId | ||
}; | ||
await store.set(membershipId, membership); | ||
return membership; | ||
|
||
function isDifferent(value: Membership) { | ||
return !!entries(data).find(entry => value[entry[0]] !== entry[1]); | ||
} | ||
|
||
function createMembershipId() { | ||
if (ATTENDEE_DISABLE_PARTITION) { | ||
return data.reference; | ||
} | ||
const hash = createHash("sha512"); | ||
hash.update(getPartitionPrefix()); | ||
hash.update(data.reference); | ||
return hash.digest().toString("hex"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {getKeyValueStore} from "../kv"; | ||
import {Membership} from "./types"; | ||
|
||
const STORE_NAME = "membership" as const; | ||
|
||
export function getMembershipStore() { | ||
return getKeyValueStore<Membership>(STORE_NAME, { | ||
counter: true | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
export interface MembershipData extends Record<string, unknown> { | ||
reference: string; | ||
name?: string; | ||
email?: string; | ||
} | ||
|
||
export interface Membership extends MembershipData { | ||
membershipId: string; | ||
createdAt: string; | ||
createdByPartnerId?: string; | ||
createdByUserId?: string; | ||
} | ||
|
||
export type PartialMembership = MembershipData & Partial<Membership>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters