Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add guest and account types #585

Merged
merged 5 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/action/action.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Context } from '@/enums/context.js';
import { DiscriminatedItem } from '@/item/item.js';
import { ItemMembership } from '@/itemMembership/itemMembership.js';
import { Member } from '@/member/member.js';
import { Account, Member } from '@/member/member.js';

export type Action = {
id: string;
item?: DiscriminatedItem | null;
member?: Member | null;
account?: Account | null;
view: Context | 'Unknown';
type: string;
extra: { [key: string]: unknown };
Expand Down
2 changes: 1 addition & 1 deletion src/action/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { faker } from '@faker-js/faker';
export const ActionFactory = (a: Partial<Action> = {}): Action => ({
id: faker.string.uuid(),
// member and item default to null
member: null,
account: null,
item: null,
view: faker.helpers.arrayElement(Object.values(Context)),
type: faker.lorem.word(),
Expand Down
10 changes: 5 additions & 5 deletions src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Publisher } from './publisher.js';
import { DiscriminatedItem } from '@/item/item.js';
import { Member } from '@/member/member.js';
import { Account, Member } from '@/member/member.js';
import { UUID } from '@/types.js';

export type AppExtra = {
Expand All @@ -24,7 +24,7 @@ export interface AppIdentification {
}

export type AuthTokenSubject = {
memberId?: Member['id'];
accountId?: Account['id'];
itemId: DiscriminatedItem['id'];
origin: string;
} & AppIdentification; // from the graasp client/app wrapper // from the app itself
Expand All @@ -34,7 +34,7 @@ type Data = { [key: string]: unknown };
export type AppAction<T extends Data = Data> = {
id: string;
item: DiscriminatedItem;
member: Member;
account: Account;
type: string;
data: T;
createdAt: string;
Expand All @@ -48,8 +48,8 @@ export enum AppDataVisibility {
export type AppData<T extends Data = Data> = {
id: string;
item: DiscriminatedItem;
creator: Member | null;
member: Member;
creator: Account | null;
account: Account;
type: string;
visibility: `${AppDataVisibility}` | AppDataVisibility;
data: T;
Expand Down
8 changes: 4 additions & 4 deletions src/chat/chat.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DiscriminatedItem } from '../item/item.js';
import { Member } from '../member/member.js';
import { Account } from '../member/member.js';
import { UUID } from '../types.js';
import { MentionStatus } from './mentions.js';

export type ChatMessage = {
id: UUID;
item: DiscriminatedItem;
creator: Member | null;
creator: Account | null;
createdAt: string;
updatedAt: string;
body: string;
Expand All @@ -17,7 +17,7 @@ export type ChatMessage = {
export type ExportedChatMessage = {
id: UUID;
chatId: UUID;
creator: Member | null;
creator: Account | null;
creatorName: string;
createdAt: string;
updatedAt: string;
Expand Down Expand Up @@ -51,7 +51,7 @@ export type DeleteChatMessageParamType = {
export type ChatMention = {
id: UUID;
message: ChatMessage;
member: Member;
account: Account;
createdAt: string;
updatedAt: string;
status: MentionStatus;
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export * from './itemLike/itemLike.js';
* Item Login
*/
export * from './itemLogin/itemLogin.js';
export * from './itemLogin/factory.js';

/**
* Item Memberships
Expand Down
14 changes: 14 additions & 0 deletions src/itemLogin/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ItemLoginSchema, ItemLoginSchemaType } from './itemLogin.js';
import { faker } from '@faker-js/faker';

export function ItemLoginSchemaFactory(
itemLoginSchema: Partial<ItemLoginSchema> & Pick<ItemLoginSchema, 'item'>,
): ItemLoginSchema {
return {
id: faker.string.uuid(),
type: ItemLoginSchemaType.Username,
createdAt: faker.date.anytime().toISOString(),
updatedAt: faker.date.anytime().toISOString(),
...itemLoginSchema,
};
}
10 changes: 0 additions & 10 deletions src/itemLogin/itemLogin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { DiscriminatedItem } from '@/item/item.js';
import { Member } from '@/member/member.js';
import { UUID } from '@/types.js';

export enum ItemLoginSchemaType {
Expand All @@ -17,12 +16,3 @@ export interface ItemLoginSchema {
createdAt: string;
updatedAt: string;
}

export type ItemLogin = {
id: UUID;
member: Member;
itemLoginSchema: ItemLoginSchema;
password?: string;
createdAt: string;
updatedAt: string;
};
2 changes: 1 addition & 1 deletion src/itemMembership/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const ItemMembershipFactory = (
id: faker.string.uuid(),
createdAt: faker.date.anytime().toISOString(),
updatedAt: faker.date.anytime().toISOString(),
member: MemberFactory(im.member),
account: im.account ?? MemberFactory(),
permission: faker.helpers.enumValue(PermissionLevel),
...im,
});
14 changes: 11 additions & 3 deletions src/itemMembership/itemMembership.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { PermissionLevel } from '@/enums/permissionLevel/permissionLevel.js';
import { DiscriminatedItem } from '@/item/item.js';
import { Member } from '@/member/member.js';
import { Account, AccountType, Member } from '@/member/member.js';
import { UUID } from '@/types.js';

type AugmentedAccount =
| (Member & {
type: AccountType.Individual;
})
| (Account & {
type: AccountType.Guest;
});

export interface ItemMembership {
id: UUID;
member: Member;
account: AugmentedAccount;
item: DiscriminatedItem;
permission: PermissionLevel;
creator?: Member | null;
creator?: Account | null;
createdAt: string;
updatedAt: string;
}
1 change: 0 additions & 1 deletion src/member/constants.ts

This file was deleted.

37 changes: 30 additions & 7 deletions src/member/factory.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
import { CompleteMember, MemberType } from './member.js';
import {
Account,
AccountType,
CompleteAccount,
CompleteGuest,
CompleteMember,
} from './member.js';
import { faker } from '@faker-js/faker';

export function AccountFactory(account: Partial<Account> = {}): Account {
return { id: faker.string.uuid(), name: faker.person.fullName(), ...account };
}

function BaseAccountFactory<T extends AccountType>(
baseAccount: Partial<CompleteAccount> & { type: T },
): CompleteAccount & { type: T } {
return {
...AccountFactory(baseAccount),
createdAt: faker.date.anytime().toISOString(),
updatedAt: faker.date.anytime().toISOString(),
...baseAccount,
};
}

export const MemberFactory = (
m: Partial<CompleteMember> = {},
): CompleteMember => ({
id: faker.string.uuid(),
name: faker.person.fullName(),
email: faker.internet.email(),
createdAt: faker.date.anytime().toISOString(),
updatedAt: faker.date.anytime().toISOString(),
extra: faker.helpers.arrayElement([
{ lang: faker.helpers.arrayElement(['en', 'fr', 'de']) },
{},
]),
// todo: handle other member type when useful in backend
type: MemberType.Individual,
enableSaveActions: m.enableSaveActions ?? true,
isValidated: m.isValidated ?? true,
...BaseAccountFactory({ type: AccountType.Individual }),
...m,
});

export const GuestFactory = (
g: Partial<CompleteGuest> & Pick<CompleteGuest, 'itemLoginSchema'>,
): CompleteGuest => ({
...BaseAccountFactory({ type: AccountType.Guest }),
...g,
});
10 changes: 4 additions & 6 deletions src/member/member.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { isPseudoMember } from './member.js';
import { AccountType, isPseudoMember } from './member.js';

describe('Member Util Tests', () => {
beforeEach(() => {
Expand All @@ -9,16 +9,14 @@ describe('Member Util Tests', () => {

describe('isPseudoMember', () => {
it('check successfully member is pseudonymized for false values', () => {
const res1 = isPseudoMember({ email: 'mail' });
const res1 = isPseudoMember({ type: AccountType.Individual });
expect(res1).toBeFalsy();
const res2 = isPseudoMember({ email: '[email protected]' });
const res2 = isPseudoMember({ type: AccountType.Group });
expect(res2).toBeFalsy();
const res3 = isPseudoMember({ email: '[email protected]' });
expect(res3).toBeFalsy();
});

it('check successfully member is pseudonymized for true values', () => {
const res3 = isPseudoMember({ email: '[email protected]' });
const res3 = isPseudoMember({ type: AccountType.Guest });
expect(res3).toBeTruthy();
});
});
Expand Down
38 changes: 28 additions & 10 deletions src/member/member.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PSEUDO_USER_MAIL_REGEX } from './constants.js';
import { EmailFrequency } from '@/chat/mentions.js';
import { ItemLoginSchema } from '@/itemLogin/itemLogin.js';
import { UUID } from '@/types.js';

export type Password = string;
Expand Down Expand Up @@ -33,9 +33,10 @@ export type PublicProfile = {
updatedAt: string;
};

export enum MemberType {
export enum AccountType {
Individual = 'individual',
Group = 'group',
Guest = 'guest',
}

type MemberExtra = {
Expand All @@ -52,22 +53,39 @@ export const buildMemberExtra = (extra: Partial<MemberExtra>) => ({
...extra,
});

export type Member = {
export type Account = {
id: UUID;
name: string;
};

export type Member = Account & {
email: string;
};

export type CompleteMember = Member & {
type: `${MemberType}` | MemberType;
extra: MemberExtra;
enableSaveActions: boolean;
userAgreementsDate?: string;
export type CompleteAccount = Account & {
type: `${AccountType}` | AccountType;
createdAt: string;
updatedAt: string;
lastAuthenticatedAt?: string;
};

export type CompleteMember = CompleteAccount & {
type: AccountType.Individual;
email: string;
extra: MemberExtra;
enableSaveActions: boolean;
userAgreementsDate?: string;

isValidated: boolean;
};

export const isPseudoMember = (member: { email: string }) =>
PSEUDO_USER_MAIL_REGEX.test(member.email.toLowerCase());
export type CompleteGuest = CompleteAccount & {
type: AccountType.Guest;
itemLoginSchema: ItemLoginSchema;
};

export type CurrentAccount = CompleteMember | CompleteGuest;

export function isPseudoMember(member: { type: AccountType }) {
return member.type === AccountType.Guest;
}