From adf0ac41a32ef41ddd92fd8dbb93386cc1249983 Mon Sep 17 00:00:00 2001 From: Nico Franke Date: Thu, 23 Feb 2023 22:27:59 +0100 Subject: [PATCH] Code cleanup --- apps/api/src/trpc/middlewares/oauth.ts | 57 +++++++--------- apps/api/src/trpc/routes/lobby/index.ts | 86 +++++++++++-------------- apps/web/components/Avatar.vue | 7 +- apps/web/composables/useAuthProxyFn.ts | 20 ++++++ apps/web/layouts/auth.vue | 12 ++-- apps/web/pages/join/[code].vue | 3 +- apps/web/pages/join/index.vue | 5 +- apps/web/pages/lobby/index.vue | 53 ++++++++++++++- 8 files changed, 148 insertions(+), 95 deletions(-) create mode 100644 apps/web/composables/useAuthProxyFn.ts diff --git a/apps/api/src/trpc/middlewares/oauth.ts b/apps/api/src/trpc/middlewares/oauth.ts index 2285571a..7d13c60e 100644 --- a/apps/api/src/trpc/middlewares/oauth.ts +++ b/apps/api/src/trpc/middlewares/oauth.ts @@ -32,42 +32,35 @@ const isOAuthed = middleware(async ({ ctx, next }) => { throw new TRPCError({ code: 'UNAUTHORIZED' }) } - try { - // Check if token is valid and get user info - const response = await ofetch(`${env.ZITADEL_URL}/oidc/v1/userinfo`, { - headers: { - Authorization: `Bearer ${token}`, - }, - }).catch((e) => { - throw new TRPCError({ code: 'UNAUTHORIZED', cause: e }) - }) + // Check if token is valid and get user info + const response = await ofetch(`${env.ZITADEL_URL}/oidc/v1/userinfo`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }).catch((e) => { + throw new TRPCError({ code: 'UNAUTHORIZED', cause: e }) + }) - // remove org domain from username - const orgDomain = response['urn:zitadel:iam:org:domain:primary'] - const username = response.preferred_username.replace(`@${orgDomain}`, '') + // remove org domain from username + const orgDomain = response['urn:zitadel:iam:org:domain:primary'] + const username = response.preferred_username.replace(`@${orgDomain}`, '') - // validate user info - const parsedUser = userSchema.parse({ - id: response.sub, - username, - picture: response.picture, - orgDomain, - }) + // validate user info + const parsedUser = userSchema.parse({ + id: response.sub, + username, + picture: response.picture, + orgDomain, + }) - // create or update user - const user = await ctx.prisma.user.upsert({ - where: { id: parsedUser.id }, - update: { ...parsedUser }, - create: { ...parsedUser }, - }) - return next({ ctx: { ...ctx, user } }) - } catch (e) { - if (e instanceof TRPCError) { - throw e - } + // create or update user + const user = await ctx.prisma.user.upsert({ + where: { id: parsedUser.id }, + update: { ...parsedUser }, + create: { ...parsedUser }, + }) - throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', cause: e }) - } + return next({ ctx: { ...ctx, user } }) }) export const oAuthedProcedure = publicProcedure.use(isOAuthed) diff --git a/apps/api/src/trpc/routes/lobby/index.ts b/apps/api/src/trpc/routes/lobby/index.ts index e71304d0..f5206642 100644 --- a/apps/api/src/trpc/routes/lobby/index.ts +++ b/apps/api/src/trpc/routes/lobby/index.ts @@ -78,23 +78,14 @@ export const lobbyRouter = router({ } }), leave: oAuthedProcedure.mutation(async ({ ctx }) => { - try { - await ctx.prisma.user.update({ - where: { id: ctx.user.id }, - data: { - lobby: { - disconnect: true, - }, + await ctx.prisma.user.update({ + where: { id: ctx.user.id }, + data: { + lobby: { + disconnect: true, }, - }) - return - } catch (e) { - throw new TRPCError({ - code: 'INTERNAL_SERVER_ERROR', - message: 'Failed to leave lobby', - cause: e, - }) - } + }, + }) }), joined: oAuthedProcedure.query(async ({ ctx }) => { const user = await ctx.prisma.user.findUnique({ @@ -107,47 +98,46 @@ export const lobbyRouter = router({ return { lobby: user?.lobby } }), status: authedProcedure.query(async ({ ctx }) => { - try { - const lobby = await ctx.prisma.lobby.findUnique({ - where: { id: ctx.user.sub }, - include: { - users: true, + const lobby = await ctx.prisma.lobby.findUnique({ + where: { id: ctx.user.sub }, + include: { + users: true, + }, + }) + + if (!lobby) throw new TRPCError({ code: 'NOT_FOUND', message: 'Lobby not found' }) + + return { lobby } + }), + users: oAuthedProcedure.query(async ({ ctx }) => { + const user = await ctx.prisma.user.findUnique({ + where: { id: ctx.user.id }, + include: { + lobby: { + include: { + users: true, + }, }, - }) + }, + }) - if (!lobby) throw new TRPCError({ code: 'NOT_FOUND', message: 'Lobby not found' }) + if (!user?.lobby) throw new TRPCError({ code: 'NOT_FOUND', message: 'Lobby not found' }) - return { lobby } - } catch (e) { - throw new TRPCError({ - code: 'INTERNAL_SERVER_ERROR', - message: 'Failed to get lobby status', - cause: e, - }) - } + return { users: user.lobby.users } }), kick: authedProcedure .input(z.object({ userId: z.string() })) .mutation(async ({ ctx, input }) => { - try { - await ctx.prisma.lobby.update({ - where: { id: ctx.user.sub }, - data: { - users: { - disconnect: { - id: input.userId, - }, + await ctx.prisma.lobby.update({ + where: { id: ctx.user.sub }, + data: { + users: { + disconnect: { + id: input.userId, }, }, - }) - return - } catch (e) { - throw new TRPCError({ - code: 'INTERNAL_SERVER_ERROR', - message: 'Failed to kick user from lobby', - cause: e, - }) - } + }, + }) }), delete: authedProcedure.mutation(async ({ ctx }) => { await ctx.prisma.lobby.delete({ diff --git a/apps/web/components/Avatar.vue b/apps/web/components/Avatar.vue index c9421df6..0256519e 100644 --- a/apps/web/components/Avatar.vue +++ b/apps/web/components/Avatar.vue @@ -2,8 +2,6 @@ const props = defineProps<{ src?: string alt?: string - firstName?: string - lastName?: string username?: string }>() @@ -19,11 +17,8 @@ watch(() => props.src, (src) => { }, { immediate: true }) const initials = computed(() => { - if (props.firstName && props.lastName) { - return `${props.firstName[0]}${props.lastName[0]}` - } if (props.username) { - return props.username[0] + return props.username[0].toUpperCase() } return '?' }) diff --git a/apps/web/composables/useAuthProxyFn.ts b/apps/web/composables/useAuthProxyFn.ts new file mode 100644 index 00000000..cf4ba2a5 --- /dev/null +++ b/apps/web/composables/useAuthProxyFn.ts @@ -0,0 +1,20 @@ +import { TRPCClientError } from '@trpc/client' + +type InferArgs = T extends (...t: [...infer Arg]) => any ? Arg : never +type InferReturn = T extends (...t: [...infer Arg]) => infer Res ? Res : never + +export default function useAuthProxyFn any>(fn: TFunc): (...args: InferArgs) => InferReturn { + const { logIn } = useAuth() + return (...args: InferArgs) => { + const val = fn(...args) + if (val instanceof Promise) { + return val.catch(async (e) => { + if (e instanceof TRPCClientError && e.data.code === 'UNAUTHORIZED') { + await logIn() + } + throw e + }) + } + return val + } +} diff --git a/apps/web/layouts/auth.vue b/apps/web/layouts/auth.vue index 9be94e48..892ab737 100644 --- a/apps/web/layouts/auth.vue +++ b/apps/web/layouts/auth.vue @@ -15,8 +15,8 @@ const leave = useMutation({ retry: 2, retryDelay: 0, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['queryJoined'] }) - router.push('/') + queryClient.invalidateQueries({ queryKey: ['queryJoined', 'queryUsers'] }) + router.push('/join') }, onError: () => { notify({ @@ -35,7 +35,7 @@ const leave = useMutation({
Open user menu - +
@@ -44,7 +44,7 @@ const leave = useMutation({ Edit profile - Leave session + Leave lobby Sign out @@ -53,6 +53,8 @@ const leave = useMutation({ - +
+ +
diff --git a/apps/web/pages/join/[code].vue b/apps/web/pages/join/[code].vue index a4de7ab6..d2ff7c65 100644 --- a/apps/web/pages/join/[code].vue +++ b/apps/web/pages/join/[code].vue @@ -13,9 +13,10 @@ const router = useRouter() const { notify } = useNotification() const mutateJoin = (code: string) => client.lobby.join.mutate({ code }) +const proxy = useAuthProxyFn(mutateJoin) const join = useMutation({ - mutationFn: mutateJoin, + mutationFn: proxy, retry: 2, retryDelay: 0, onSuccess: () => { diff --git a/apps/web/pages/join/index.vue b/apps/web/pages/join/index.vue index dfc22230..7e164e49 100644 --- a/apps/web/pages/join/index.vue +++ b/apps/web/pages/join/index.vue @@ -11,9 +11,10 @@ const queryClient = useQueryClient() const { notify } = useNotification() const mutateJoin = (code: string) => client.lobby.join.mutate({ code }) +const proxy = useAuthProxyFn(mutateJoin) const join = useMutation({ - mutationFn: mutateJoin, + mutationFn: proxy, retry: 2, retryDelay: 0, onSuccess: () => { @@ -48,7 +49,7 @@ const onSubmit = (e: Event) => {