diff --git a/src/action/action.ts b/src/action/action.ts index e8bbe622..3871ae2e 100644 --- a/src/action/action.ts +++ b/src/action/action.ts @@ -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 }; diff --git a/src/action/factory.ts b/src/action/factory.ts index cca750c8..17d209fd 100644 --- a/src/action/factory.ts +++ b/src/action/factory.ts @@ -5,7 +5,7 @@ import { faker } from '@faker-js/faker'; export const ActionFactory = (a: Partial = {}): 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(), diff --git a/src/app/app.ts b/src/app/app.ts index 835234e6..3d679b1c 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -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 = { @@ -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 @@ -34,7 +34,7 @@ type Data = { [key: string]: unknown }; export type AppAction = { id: string; item: DiscriminatedItem; - member: Member; + account: Account; type: string; data: T; createdAt: string; @@ -48,8 +48,8 @@ export enum AppDataVisibility { export type AppData = { id: string; item: DiscriminatedItem; - creator: Member | null; - member: Member; + creator: Account | null; + account: Account; type: string; visibility: `${AppDataVisibility}` | AppDataVisibility; data: T; diff --git a/src/chat/chat.ts b/src/chat/chat.ts index 7aee6c8a..c145dc8d 100644 --- a/src/chat/chat.ts +++ b/src/chat/chat.ts @@ -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; @@ -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; @@ -51,7 +51,7 @@ export type DeleteChatMessageParamType = { export type ChatMention = { id: UUID; message: ChatMessage; - member: Member; + account: Account; createdAt: string; updatedAt: string; status: MentionStatus; diff --git a/src/index.ts b/src/index.ts index 6fe5bb28..93e200c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -190,6 +190,7 @@ export * from './itemLike/itemLike.js'; * Item Login */ export * from './itemLogin/itemLogin.js'; +export * from './itemLogin/factory.js'; /** * Item Memberships diff --git a/src/itemLogin/factory.ts b/src/itemLogin/factory.ts new file mode 100644 index 00000000..9abe0027 --- /dev/null +++ b/src/itemLogin/factory.ts @@ -0,0 +1,14 @@ +import { ItemLoginSchema, ItemLoginSchemaType } from './itemLogin.js'; +import { faker } from '@faker-js/faker'; + +export function ItemLoginSchemaFactory( + itemLoginSchema: Partial & Pick, +): ItemLoginSchema { + return { + id: faker.string.uuid(), + type: ItemLoginSchemaType.Username, + createdAt: faker.date.anytime().toISOString(), + updatedAt: faker.date.anytime().toISOString(), + ...itemLoginSchema, + }; +} diff --git a/src/itemLogin/itemLogin.ts b/src/itemLogin/itemLogin.ts index 5af6b8b5..c4fa00be 100644 --- a/src/itemLogin/itemLogin.ts +++ b/src/itemLogin/itemLogin.ts @@ -1,5 +1,4 @@ import { DiscriminatedItem } from '@/item/item.js'; -import { Member } from '@/member/member.js'; import { UUID } from '@/types.js'; export enum ItemLoginSchemaType { @@ -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; -}; diff --git a/src/itemMembership/factory.ts b/src/itemMembership/factory.ts index 908fedc6..581ee0fb 100644 --- a/src/itemMembership/factory.ts +++ b/src/itemMembership/factory.ts @@ -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, }); diff --git a/src/itemMembership/itemMembership.ts b/src/itemMembership/itemMembership.ts index 1bc28b76..345741d3 100644 --- a/src/itemMembership/itemMembership.ts +++ b/src/itemMembership/itemMembership.ts @@ -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; } diff --git a/src/member/constants.ts b/src/member/constants.ts deleted file mode 100644 index 2a6ab557..00000000 --- a/src/member/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const PSEUDO_USER_MAIL_REGEX = /[a-zA-Z0-9]{4}-\d{13}@graasp\.org/; diff --git a/src/member/factory.ts b/src/member/factory.ts index 06e47a29..4fd5b9b3 100644 --- a/src/member/factory.ts +++ b/src/member/factory.ts @@ -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 { + return { id: faker.string.uuid(), name: faker.person.fullName(), ...account }; +} + +function BaseAccountFactory( + baseAccount: Partial & { 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 => ({ - 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 & Pick, +): CompleteGuest => ({ + ...BaseAccountFactory({ type: AccountType.Guest }), + ...g, +}); diff --git a/src/member/member.test.ts b/src/member/member.test.ts index e3d415ef..c2a6fe9c 100644 --- a/src/member/member.test.ts +++ b/src/member/member.test.ts @@ -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(() => { @@ -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: 'mail@email.org' }); + const res2 = isPseudoMember({ type: AccountType.Group }); expect(res2).toBeFalsy(); - const res3 = isPseudoMember({ email: 'mail@graasp.org' }); - expect(res3).toBeFalsy(); }); it('check successfully member is pseudonymized for true values', () => { - const res3 = isPseudoMember({ email: '3242-1234567890123@graasp.org' }); + const res3 = isPseudoMember({ type: AccountType.Guest }); expect(res3).toBeTruthy(); }); }); diff --git a/src/member/member.ts b/src/member/member.ts index 0f705945..15e2d94b 100644 --- a/src/member/member.ts +++ b/src/member/member.ts @@ -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; @@ -33,9 +33,10 @@ export type PublicProfile = { updatedAt: string; }; -export enum MemberType { +export enum AccountType { Individual = 'individual', Group = 'group', + Guest = 'guest', } type MemberExtra = { @@ -52,22 +53,39 @@ export const buildMemberExtra = (extra: Partial) => ({ ...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; +}