diff --git a/backend/package.json b/backend/package.json index fbd03466c..6ef8db146 100644 --- a/backend/package.json +++ b/backend/package.json @@ -103,6 +103,7 @@ "#graphql/*": "./src/graphql/*", "#inputs/*": "./src/graphql/inputs/*", "#models/*": "./src/graphql/models/*", + "#resolvers/*": "./src/graphql/resolvers/*", "#src/*": "./src/*", "#test/*": "./test/*", "#types/*": "./src/graphql/types/*" diff --git a/backend/src/graphql/models/TableModel.ts b/backend/src/graphql/models/TableModel.ts index f2016ff9d..38ac74dfa 100644 --- a/backend/src/graphql/models/TableModel.ts +++ b/backend/src/graphql/models/TableModel.ts @@ -19,19 +19,22 @@ export const getAttendees = (meeting: MeetingInfo): Attendee[] => { @ObjectType() export class Table { - constructor(data: Pick) { + constructor(data: Pick) { Object.assign(this, data) } static fromMeeting(meeting: Meeting, usersWithMeetings: UsersWithMeetings[]) { - const { id, name } = meeting + const { id, meetingID, name } = meeting const users = usersWithMeetings.map((u) => new UserInMeeting(u)) - return new Table({ id, name, public: meeting.public, users }) + return new Table({ id, meetingID, name, public: meeting.public, users }) } @Field(() => Int) id: number + @Field(() => String) + meetingID: string + @Field() name: string diff --git a/backend/src/graphql/resolvers/TableResolver.spec.ts b/backend/src/graphql/resolvers/TableResolver.spec.ts index 299151cb0..c4acf6db4 100644 --- a/backend/src/graphql/resolvers/TableResolver.spec.ts +++ b/backend/src/graphql/resolvers/TableResolver.spec.ts @@ -337,7 +337,7 @@ describe('TableResolver', () => { describe('joinTableAsGuest', () => { const query = ` - query ($tableId: Int!, $userName: String!) { + query ($tableId: String!, $userName: String!) { joinTableAsGuest(tableId: $tableId, userName: $userName) } ` @@ -349,7 +349,7 @@ describe('TableResolver', () => { query, variables: { userName: 'Pinky Pie', - tableId: 25, + tableId: '25', }, }, { contextValue: mockContextValue() }, @@ -390,7 +390,7 @@ describe('TableResolver', () => { query, variables: { userName: 'Pinky Pie', - tableId, + tableId: 'Pony Ville', }, }, { contextValue: mockContextValue() }, @@ -429,7 +429,7 @@ describe('TableResolver', () => { describe('getTableName', () => { const query = ` - query ($tableId: Int!) { + query ($tableId: String!) { getTableName(tableId: $tableId) } ` @@ -440,7 +440,7 @@ describe('TableResolver', () => { { query, variables: { - tableId: 25, + tableId: '25', }, }, { contextValue: mockContextValue() }, @@ -458,15 +458,13 @@ describe('TableResolver', () => { }) describe('table in DB', () => { - let tableId: number beforeEach(async () => { - const meeting = await prisma.meeting.create({ + await prisma.meeting.create({ data: { name: 'Club of Rome', - meetingID: 'Club of Rome', + meetingID: 'club-of-rome', }, }) - tableId = meeting.id }) afterEach(async () => { @@ -479,7 +477,7 @@ describe('TableResolver', () => { { query, variables: { - tableId, + tableId: 'club-of-rome', }, }, { contextValue: mockContextValue() }, diff --git a/backend/src/graphql/resolvers/TableResolver.ts b/backend/src/graphql/resolvers/TableResolver.ts index 234cd0895..01c5fa9e1 100644 --- a/backend/src/graphql/resolvers/TableResolver.ts +++ b/backend/src/graphql/resolvers/TableResolver.ts @@ -189,7 +189,7 @@ export class TableResolver { if (!dbMeeting) throw new Error('Meeting not found!') - const inviteLink = createInviteLink(dbMeeting.id) + const inviteLink = createInviteLink(dbMeeting.meetingID) await createBBBMeeting(prisma)({ meetingID: dbMeeting.meetingID, @@ -307,7 +307,7 @@ export class TableResolver { (table.user && table.user.id === user.id) || table.users.some((e) => e.userId === user.id && e.role === 'MODERATOR') ) { - const inviteLink = createInviteLink(table.id) + const inviteLink = createInviteLink(table.meetingID) const meeting = await createBBBMeeting(prisma)({ meetingID: table.meetingID, name: table.name, @@ -345,7 +345,7 @@ export class TableResolver { @Query(() => String) async joinTableAsGuest( @Arg('userName') userName: string, - @Arg('tableId', () => Int) tableId: number, + @Arg('tableId', () => String) tableId: string, @Ctx() context: AuthenticatedContext, ): Promise { const { @@ -353,7 +353,7 @@ export class TableResolver { } = context const meeting = await prisma.meeting.findUnique({ where: { - id: tableId, + meetingID: tableId, }, include: { user: true, @@ -370,7 +370,7 @@ export class TableResolver { @Query(() => String) async getTableName( - @Arg('tableId', () => Int) tableId: number, + @Arg('tableId', () => String) tableId: string, @Ctx() context: AuthenticatedContext, ): Promise { const { @@ -378,7 +378,7 @@ export class TableResolver { } = context const meeting = await prisma.meeting.findUnique({ where: { - id: tableId, + meetingID: tableId, }, }) if (!meeting) throw new Error('Table does not exist') @@ -643,7 +643,7 @@ const findUsersInMeetings = })) as UsersWithMeetings[] } -const createMeetingID = (prisma: PrismaClient) => async (): Promise => { +export const createMeetingID = (prisma: PrismaClient) => async (): Promise => { let meetingID: string = uuidv4() while ( await prisma.meeting.count({ @@ -657,7 +657,7 @@ const createMeetingID = (prisma: PrismaClient) => async (): Promise => { return meetingID } -function createInviteLink(tableId: number) { +const createInviteLink = (tableId: string): string => { return new URL(`join-table/${tableId}`, CONFIG.FRONTEND_URL).toString() } diff --git a/backend/src/graphql/resolvers/dal/handleOpenTables.spec.ts b/backend/src/graphql/resolvers/dal/handleOpenTables.spec.ts index 659fff205..a56b726d6 100644 --- a/backend/src/graphql/resolvers/dal/handleOpenTables.spec.ts +++ b/backend/src/graphql/resolvers/dal/handleOpenTables.spec.ts @@ -153,7 +153,8 @@ describe('handleOpenTables', () => { }), expect.objectContaining({ name: 'Meeting 2', - meetingID: 'Meeting-2', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + meetingID: expect.any(String), createTime: null, }), ]), @@ -175,12 +176,14 @@ describe('handleOpenTables', () => { expect.arrayContaining([ expect.objectContaining({ name: 'Meeting 1', - meetingID: 'Meeting-1', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + meetingID: expect.any(String), createTime: null, }), expect.objectContaining({ name: 'Meeting 2', - meetingID: 'Meeting-2', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + meetingID: expect.any(String), createTime: null, }), ]), diff --git a/backend/src/graphql/resolvers/dal/handleOpenTables.ts b/backend/src/graphql/resolvers/dal/handleOpenTables.ts index e19e5de97..3b9fad339 100644 --- a/backend/src/graphql/resolvers/dal/handleOpenTables.ts +++ b/backend/src/graphql/resolvers/dal/handleOpenTables.ts @@ -1,4 +1,5 @@ import { getMeetings, MeetingInfo } from '#api/BBB' +import { createMeetingID } from '#resolvers/TableResolver' import { pubSub } from '#src/graphql/pubSub' import { prisma } from '#src/prisma' @@ -15,6 +16,7 @@ export const handleOpenTables = async (): Promise => { }, }, data: { + meetingID: await createMeetingID(prisma)(), attendeePW: null, moderatorPW: null, voiceBridge: null, diff --git a/backend/tsconfig.json b/backend/tsconfig.json index a468f2eb6..cf128c858 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -13,6 +13,7 @@ "#graphql/*": ["./src/graphql/*"], "#inputs/*": ["./src/graphql/inputs/*"], "#models/*": ["./src/graphql/models/*"], + "#resolvers/*": ["./src/graphql/resolvers/*"], "#src/*": ["./src/*"], "#test/*": ["./test/*"], "#types/*": ["./src/graphql/types/*"] diff --git a/frontend/src/components/cockpit/my-tables/create-table/CreateTable.vue b/frontend/src/components/cockpit/my-tables/create-table/CreateTable.vue index fc3ecd731..fee8bb2e4 100644 --- a/frontend/src/components/cockpit/my-tables/create-table/CreateTable.vue +++ b/frontend/src/components/cockpit/my-tables/create-table/CreateTable.vue @@ -27,9 +27,11 @@ export type CreateTableModel = { name: string userIds: number[] tableId?: number + meetingID?: string } const createTableModel = reactive({ + meetingID: '', isPrivate: false, name: '', userIds: [], @@ -76,6 +78,7 @@ const onSubmit = async () => { } createTableModel.tableId = table.id + createTableModel.meetingID = table.meetingID stepControl.value?.next() } diff --git a/frontend/src/components/cockpit/my-tables/create-table/TableCreated.vue b/frontend/src/components/cockpit/my-tables/create-table/TableCreated.vue index 04e252f60..25718cbec 100644 --- a/frontend/src/components/cockpit/my-tables/create-table/TableCreated.vue +++ b/frontend/src/components/cockpit/my-tables/create-table/TableCreated.vue @@ -27,11 +27,13 @@ const pageContext = usePageContext() const { META } = pageContext.publicEnv const createTableModel = defineModel({ required: true }) +const meetingID = createTableModel.value.meetingID const tableId = createTableModel.value.tableId +if (!meetingID) throw new Error('Meeting ID is required') if (!tableId) throw new Error('Table ID is required') -const tableUrl = tablesStore.getJoinTableUrl(tableId, META.BASE_URL) +const tableUrl = tablesStore.getJoinTableUrl(meetingID, META.BASE_URL) const props = defineProps() const emit = defineEmits() diff --git a/frontend/src/components/malltalk/interfaces/MyTableSettings.ts b/frontend/src/components/malltalk/interfaces/MyTableSettings.ts index e445d2c5c..7b7f55f04 100644 --- a/frontend/src/components/malltalk/interfaces/MyTableSettings.ts +++ b/frontend/src/components/malltalk/interfaces/MyTableSettings.ts @@ -3,4 +3,5 @@ export default interface MyTableSettings { isPrivate: boolean users: number[] tableId?: number + meetingID?: string } diff --git a/frontend/src/components/malltalk/settings/TableSettings.vue b/frontend/src/components/malltalk/settings/TableSettings.vue index 081aa92fa..53c557bd6 100644 --- a/frontend/src/components/malltalk/settings/TableSettings.vue +++ b/frontend/src/components/malltalk/settings/TableSettings.vue @@ -30,12 +30,14 @@ const tableSettings = reactive({ name: myTable.value?.name || '', isPrivate: !myTable.value?.public || false, users: myTable.value?.users.map((u) => u.id) || [], + meetingID: myTable.value?.meetingID || '', }) watch(myTable, (value) => { tableSettings.name = value?.name || '' tableSettings.isPrivate = !value?.public || false tableSettings.users = value?.users.map((u) => u.id) || [] + tableSettings.meetingID = value?.meetingID || '' }) const steps: Step[] = [ diff --git a/frontend/src/components/malltalk/settings/TableSettingsRoot.vue b/frontend/src/components/malltalk/settings/TableSettingsRoot.vue index a635c229d..5c13a5af9 100644 --- a/frontend/src/components/malltalk/settings/TableSettingsRoot.vue +++ b/frontend/src/components/malltalk/settings/TableSettingsRoot.vue @@ -24,6 +24,7 @@