- Implemented robust token-based authentication with access and refresh tokens - Added JWT token generation, verification, and rotation mechanisms - Created services for token management, Memcached, and MinIO storage - Enhanced user registration and login with device-specific tokens - Added support for profile picture upload and management via MinIO - Implemented secure password hashing with crypto - Updated Prisma schema to support refresh tokens and profile picture storage - Added GraphQL mutations for logout, token refresh, and profile picture handling - Integrated environment configuration with Zod validation - Improved error handling and authentication middleware
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
import { GraphQLError } from 'graphql';
|
|
import { IResolvers, withFilter } from 'mercurius';
|
|
import { MutationResolvers, QueryResolvers } from '../generated/graphql';
|
|
import { withAuth } from '../utils';
|
|
|
|
export const MESSAGE_ADDED = 'MESSAGE_ADDED';
|
|
|
|
export const messageResolvers: IResolvers = {
|
|
Query: {
|
|
messages: withAuth<QueryResolvers['messages']>(
|
|
async (_, { roomId }, { prisma, jwt }) => {
|
|
const room = await prisma.room.findUnique({
|
|
where: { id: roomId, members: { some: { id: jwt.sub } } },
|
|
});
|
|
|
|
if (!room) {
|
|
throw new GraphQLError('Room not found', {
|
|
extensions: {
|
|
code: 'NOT_FOUND',
|
|
},
|
|
});
|
|
}
|
|
|
|
return prisma.message.findMany({
|
|
where: { roomId },
|
|
orderBy: { createdAt: 'asc' },
|
|
});
|
|
}
|
|
),
|
|
},
|
|
Mutation: {
|
|
sendMessage: withAuth<MutationResolvers['sendMessage']>(
|
|
async (_, { content, roomId }, { prisma, jwt, pubsub }) => {
|
|
const room = await prisma.room.findUnique({
|
|
where: { id: roomId, members: { some: { id: jwt.sub } } },
|
|
});
|
|
|
|
if (!room) {
|
|
throw new GraphQLError('Room not found', {
|
|
extensions: {
|
|
code: 'NOT_FOUND',
|
|
},
|
|
});
|
|
}
|
|
|
|
const message = await prisma.message.create({
|
|
data: {
|
|
content,
|
|
user: {
|
|
connect: { id: jwt.sub },
|
|
},
|
|
room: {
|
|
connect: { id: roomId },
|
|
},
|
|
},
|
|
include: {
|
|
user: true,
|
|
room: true,
|
|
},
|
|
});
|
|
|
|
pubsub.publish({
|
|
topic: MESSAGE_ADDED,
|
|
payload: { messageAdded: message, roomId },
|
|
});
|
|
|
|
return message;
|
|
}
|
|
),
|
|
},
|
|
Subscription: {
|
|
messageAdded: {
|
|
subscribe: withFilter(
|
|
(_, __, { pubsub }) => pubsub.subscribe([MESSAGE_ADDED]),
|
|
(payload, variables) => {
|
|
return payload.roomId === variables.roomId;
|
|
}
|
|
),
|
|
},
|
|
},
|
|
Message: {
|
|
user: async (parent, _, { prisma }) =>
|
|
parent.user
|
|
? parent.user
|
|
: prisma.user.findUnique({
|
|
where: { id: parent.userId },
|
|
}),
|
|
room: async (parent, _, { prisma }) =>
|
|
parent.room
|
|
? parent.room
|
|
: prisma.room.findUnique({
|
|
where: { id: parent.roomId },
|
|
}),
|
|
},
|
|
};
|