2025-05-14 21:45:16 +02:00

212 lines
9.8 KiB
TypeScript

import { Resolver, Query, FieldResolver, Root, Arg, Mutation, Ctx, Args, Authorized } from 'type-graphql';
import { addOneGeneric } from '@seed/graphql/BaseService';
import RoomModel, {
RoomArgs,
RemovePeopleFromRoomInput,
AddPeopleToRoomInput,
NewRoomInput,
} from '@services/api-messaging/functions/rooms/room.model';
import { ApolloContext } from '@seed/interfaces/context';
import { ApolloError } from 'apollo-server-lambda';
import AccountModel from '@src/accounts/account.model';
import { onCreate } from '@services/api-messaging/functions/rooms/room.model';
import _ from 'lodash';
import MessageModel, { MessageArgs } from '../messages/message.model';
import { oneToManyComplexity } from '@seed/graphql/Middleware';
import { UnreadCount } from '@services/api-messaging/components';
@Resolver(RoomModel)
export default class RoomResolver {
/*
███████╗██╗███████╗██╗ ██████╗ ███████╗
██╔════╝██║██╔════╝██║ ██╔══██╗██╔════╝
█████╗ ██║█████╗ ██║ ██║ ██║███████╗
██╔══╝ ██║██╔══╝ ██║ ██║ ██║╚════██║
██║ ██║███████╗███████╗██████╔╝███████║
╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚══════╝
*/
@FieldResolver()
async getAccounts(@Root() room: RoomModel, @Ctx() ctx: ApolloContext): Promise<(AccountModel | Error)[]> {
return await ctx.ctx.loaders.accountLoader.loadMany(room.r);
}
@FieldResolver(() => [MessageModel], { complexity: oneToManyComplexity })
async getMessages(@Args() args: MessageArgs, @Root() room: RoomModel, @Ctx() ctx: ApolloContext): Promise<MessageModel[]> {
try {
if (!args.pagination) args.pagination = { limit: 10, skip: 0, sort: 'createdAt desc' };
else if (args.pagination && !args.pagination.sort) args.pagination = { ...args.pagination, sort: 'createdAt desc' };
return new MessageModel().getMany({ roomId: room._id }, args.pagination, ctx);
} catch (error) {
throw error;
}
}
/*
██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗
██╔═══██╗██║ ██║██╔════╝██╔══██╗╚██╗ ██╔╝
██║ ██║██║ ██║█████╗ ██████╔╝ ╚████╔╝
██║▄▄ ██║██║ ██║██╔══╝ ██╔══██╗ ╚██╔╝
╚██████╔╝╚██████╔╝███████╗██║ ██║ ██║
╚══▀▀═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝
*/
@Query(() => RoomModel)
@Authorized()
async roomsGetOne(@Arg('id') id: string, @Ctx() ctx: ApolloContext): Promise<RoomModel> {
const model = new RoomModel();
const roomData = await model.getOne({ _id: id }, ctx);
if (!roomData.r.includes(ctx.ctx.user._id))
throw new ApolloError('permissions.notAllowed', '400', { you: ctx.ctx.user._id, allowed: roomData.r });
return roomData;
}
@Query(() => [RoomModel])
@Authorized()
async roomsGetMany(@Args() args: RoomArgs, @Ctx() ctx: ApolloContext): Promise<RoomModel[]> {
const model = new RoomModel();
const result = await model.getMany({ accountIds: ctx.ctx.user._id }, args.pagination, ctx);
return result;
}
@Query(() => [MessageModel])
@Authorized()
async roomsGetMessages(@Arg('id') id: string, @Args() args: RoomArgs, @Ctx() ctx: ApolloContext): Promise<MessageModel[]> {
const model = new RoomModel();
const roomData = await model.getOne({ _id: id }, ctx);
if (!roomData.r.includes(ctx.ctx.user._id))
throw new ApolloError('permissions.notAllowed', '400', { you: ctx.ctx.user._id, allowed: roomData.r });
if (!args.pagination) args.pagination = { limit: 10, skip: 0, sort: 'createdAt desc' };
else if (args.pagination && !args.pagination.sort) args.pagination = { ...args.pagination, sort: 'createdAt desc' };
return new MessageModel().getMany({ roomId: id }, args.pagination, ctx);
}
/*
███╗ ███╗██╗ ██╗████████╗ █████╗ ████████╗ ██████╗ ██████╗ ███████╗
████╗ ████║██║ ██║╚══██╔══╝██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝
██╔████╔██║██║ ██║ ██║ ███████║ ██║ ██║ ██║██████╔╝███████╗
██║╚██╔╝██║██║ ██║ ██║ ██╔══██║ ██║ ██║ ██║██╔══██╗╚════██║
██║ ╚═╝ ██║╚██████╔╝ ██║ ██║ ██║ ██║ ╚██████╔╝██║ ██║███████║
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
*/
@Mutation(() => RoomModel)
@Authorized()
async roomsCreateOne(@Arg('input') input: NewRoomInput, @Ctx() ctx: ApolloContext): Promise<RoomModel> {
const model = new RoomModel();
try {
await onCreate(input, ctx);
} catch (error) {
throw error;
}
input.accountIds.push(ctx.ctx.user._id);
input.accountIds = _.uniq(input.accountIds);
// Check if a room with the same user doesn't exists already
try {
return await model.getOne(
{
r: { $all: input.accountIds },
},
ctx,
);
} catch (error) {
const unreadCounts: UnreadCount[] = [];
for (let index = 0; index < input.accountIds.length; index++) {
unreadCounts.push({
accountId: input.accountIds[index],
count: 0,
});
}
const dataToSave: Partial<RoomModel> = {
...input,
r: input.accountIds,
w: input.accountIds,
stats: {
unreadCounts: unreadCounts,
},
};
return addOneGeneric(model, dataToSave, ctx);
}
}
@Mutation(() => RoomModel)
@Authorized()
async roomsAddPeople(@Arg('input') input: AddPeopleToRoomInput, @Ctx() ctx: ApolloContext): Promise<RoomModel> {
const model = new RoomModel();
// Get the room first to see if allowed
const roomData = await model.getOne({ _id: input.roomId }, ctx);
if (!roomData.r.includes(ctx.ctx.user._id))
throw new ApolloError('permissions.notAllowed', '400', { you: ctx.ctx.user._id, allowed: roomData.r });
const newAccountIds = _.uniq(roomData.r.concat(input.accountIds));
try {
await onCreate(input, ctx);
} catch (error) {
throw error;
}
// TODO : Remove from stats
return roomData.updateOne({ _id: input.roomId }, { r: newAccountIds, w: newAccountIds }, ctx);
}
@Mutation(() => RoomModel)
@Authorized()
async roomsRemovePeople(@Arg('input') input: RemovePeopleFromRoomInput, @Ctx() ctx: ApolloContext): Promise<RoomModel> {
const model = new RoomModel();
// Get the room first to see if allowed
const roomData = await model.getOne({ _id: input.roomId }, ctx);
if (!roomData.r.includes(ctx.ctx.user._id))
throw new ApolloError('permissions.notAllowed', '400', { you: ctx.ctx.user._id, allowed: roomData.r });
const newAccountIds = _.uniq(
roomData.r.filter(function(element) {
return roomData.r.indexOf(element) === -1;
}),
);
// TODO : Remove from stats
return roomData.updateOne({ _id: input.roomId }, { r: newAccountIds, w: newAccountIds }, ctx);
}
@Mutation(() => RoomModel)
@Authorized()
async roomsMarkAllMessageAsRead(@Arg('roomId') roomId: string, @Ctx() ctx: ApolloContext): Promise<RoomModel> {
const roomModel = new RoomModel();
await roomModel.getOne({ _id: roomId }, ctx);
// The hypothesis here is that the message are accessible only by concerned people.
const model = new MessageModel();
await (await model.db()).updateMany(
{ roomId: roomId, 'readBy.accountId': { $ne: ctx.ctx.user._id } },
{
$push: { readBy: { accountId: ctx.ctx.user._id, readAt: new Date() } },
},
);
// Update stats & notify
for (let index = 0; index < roomModel.stats.unreadCounts.length; index++) {
// Add a count to all the other one
if (roomModel.stats.unreadCounts[index].accountId == ctx.ctx.user._id) roomModel.stats.unreadCounts[index].count = 0;
}
await (await roomModel.db()).findOneAndUpdate(
{ _id: roomModel._id },
{ $set: { stats: roomModel.stats } },
{ upsert: false, returnOriginal: false },
);
return roomModel;
}
}