-
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
a179b23
commit cbb4bdc
Showing
17 changed files
with
595 additions
and
71 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
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,13 @@ | ||
import {MembershipStatus} from "./types"; | ||
import {getConfig} from "../../config"; | ||
|
||
export const DEFAULT_MEMBERSHIP_STATUS: MembershipStatus = "active"; | ||
|
||
export interface MembershipStatusConfig { | ||
DEFAULT_MEMBERSHIP_STATUS?: MembershipStatus; | ||
} | ||
|
||
export function getDefaultMembershipStatus() { | ||
const config = getConfig(); | ||
return config.DEFAULT_MEMBERSHIP_STATUS || DEFAULT_MEMBERSHIP_STATUS; | ||
} |
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 |
---|---|---|
@@ -1,90 +1,72 @@ | ||
import {getMembershipStore} from "./store"; | ||
import {getMembershipIdentifierCounterStore, 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 {getMaybePartner, getMaybeUser} from "../../authentication"; | ||
import {v4} from "uuid"; | ||
import {ok} from "../../is"; | ||
import {isNumberString} from "../../is"; | ||
import {getConfig} from "../../config"; | ||
import {getDefaultMembershipStatus} from "./membership-status"; | ||
|
||
export interface SetMembershipConfig { | ||
createMembershipId?(data: PartialMembership): string; | ||
createMembershipReference?(data: PartialMembership): string | Promise<string>; | ||
} | ||
|
||
const { | ||
ATTENDEE_DISABLE_PARTITION, | ||
ATTENDEE_PARTITION, | ||
MEMBERSHIP_IDENTIFIER_COUNTER = "counter", | ||
MEMBERSHIP_REFERENCE_PREFIX = "", | ||
MEMBERSHIP_REFERENCE_LENGTH | ||
} = 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(); | ||
} | ||
const DEFAULT_MEMBERSHIP_REFERENCE_LENGTH = 6; | ||
|
||
/** | ||
* Allows partial update of an membership, retains existing properties | ||
* @param data | ||
*/ | ||
export async function setMembership(data: PartialMembership) { | ||
const config = getConfig(); | ||
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; | ||
let reference = data.reference | ||
if (!reference) { | ||
reference = await createMembershipReference(); | ||
} | ||
const membershipId = data.membershipId || v4(); | ||
const createdAt = data.createdAt || new Date().toISOString(); | ||
const updatedAt = new Date().toISOString(); | ||
const createdByPartnerId = getMaybePartner()?.partnerId; | ||
const createdByUserId = getMaybeUser()?.userId; | ||
const status = data.status || getDefaultMembershipStatus(); | ||
const membership: Membership = { | ||
...existing, | ||
...data, | ||
history: data.history || [ | ||
{ | ||
status, | ||
statusAt: updatedAt, | ||
updatedAt | ||
} | ||
], | ||
status, | ||
reference, | ||
membershipId, | ||
createdAt, | ||
createdByPartnerId, | ||
createdByUserId | ||
createdByUserId, | ||
updatedAt | ||
}; | ||
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; | ||
async function createMembershipReference() { | ||
if (config.createMembershipReference) { | ||
return config.createMembershipReference(data); | ||
} | ||
const hash = createHash("sha512"); | ||
hash.update(getPartitionPrefix()); | ||
hash.update(data.reference); | ||
return hash.digest().toString("hex"); | ||
const counter = await incrementMembershipIdentifier(); | ||
const length = isNumberString(MEMBERSHIP_REFERENCE_LENGTH) ? +MEMBERSHIP_REFERENCE_LENGTH : DEFAULT_MEMBERSHIP_REFERENCE_LENGTH; | ||
return `${MEMBERSHIP_REFERENCE_PREFIX}${counter.toString().padStart(length, "0")}`; | ||
} | ||
} | ||
|
||
export async function addMembership(data: PartialMembership) { | ||
return setMembership(data); | ||
} | ||
|
||
export async function incrementMembershipIdentifier() { | ||
const store = await getMembershipIdentifierCounterStore(); | ||
return await store.increment(MEMBERSHIP_IDENTIFIER_COUNTER); | ||
} |
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
Oops, something went wrong.