Skip to content

Commit

Permalink
Merge branch 'release/v2.26.9'
Browse files Browse the repository at this point in the history
  • Loading branch information
guillobits committed Dec 19, 2024
2 parents b2e31a5 + 2d4c1a6 commit d4ff08d
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/logging.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class LoggingInterceptor implements NestInterceptor {
const span = tracer.scope().active();

if (span) {
span.setTag('resource.name', 'LoggingInterceptor'); // this is what will be shown in the UI beside the span name
span.setTag('resource.name', 'LoggingInterceptor');
span.setTag('http.client_ip', clientIp);
}

Expand Down
6 changes: 6 additions & 0 deletions src/messaging/messaging.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { UserPayload } from 'src/auth/guards';
import { User } from 'src/users/models/user.model';
import { CreateMessagePipe, CreateMessageDto } from './dto';
import { ReportConversationDto } from './dto/report-conversation.dto';
import { ReportAbusePipe } from './dto/report-conversation.pipe';
Expand Down Expand Up @@ -49,12 +50,17 @@ export class MessagingController {
@Post('messages')
@UseGuards(CanParticipate)
async postMessage(
@UserPayload() user: User,
@UserPayload('id', new ParseUUIDPipe()) userId: string,
@Body(new CreateMessagePipe())
createMessageDto: CreateMessageDto
) {
// Create the conversation if needed
if (!createMessageDto.conversationId && createMessageDto.participantIds) {
await this.messagingService.handleDailyConversationLimit(
user,
createMessageDto.content
);
const participants = [...createMessageDto.participantIds];
// Add the current user to the participants
participants.push(userId);
Expand Down
46 changes: 44 additions & 2 deletions src/messaging/messaging.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { Op, Sequelize } from 'sequelize';
import { SlackService } from 'src/external-services/slack/slack.service';
Expand All @@ -15,7 +15,10 @@ import {
messagingConversationIncludes,
messagingMessageIncludes,
} from './messaging.includes';
import { generateSlackMsgConfigConversationReported } from './messaging.utils';
import {
generateSlackMsgConfigConversationReported,
generateSlackMsgConfigUserSuspiciousUser,
} from './messaging.utils';
import { ConversationParticipant } from './models';
import { Conversation } from './models/conversation.model';
import { Message } from './models/message.model';
Expand Down Expand Up @@ -239,6 +242,45 @@ export class MessagingService {
});
}

async countDailyConversations(userId: string) {
return this.conversationParticipantModel.count({
where: {
userId,
createdAt: {
[Op.gte]: new Date(new Date().setHours(0, 0, 0, 0)),
},
},
});
}

async handleDailyConversationLimit(user: User, message: string) {
const countDailyConversation = await this.countDailyConversations(user.id);
if (countDailyConversation === 4 || countDailyConversation >= 7) {
const slackMsgConfig: SlackBlockConfig =
generateSlackMsgConfigUserSuspiciousUser(
user,
`Un utilisateur tente de créer sa ${
countDailyConversation + 1
}ème conversation aujourd\'hui`,
message
);
const slackMessage =
this.slackService.generateSlackBlockMsg(slackMsgConfig);
this.slackService.sendMessage(
slackChannels.ENTOURAGE_PRO_MODERATION,
slackMessage,
'Conversation de la messagerie signalée'
);
}

if (countDailyConversation >= 7) {
throw new HttpException(
'DAILY_CONVERSATION_LIMIT_REACHED',
HttpStatus.TOO_MANY_REQUESTS
);
}
}

private async isUserInConversation(conversationId: string, userId: string) {
return this.conversationParticipantModel.findOne({
where: {
Expand Down
34 changes: 34 additions & 0 deletions src/messaging/messaging.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,37 @@ export const generateSlackMsgConfigConversationReported = (
],
};
};

export const generateSlackMsgConfigUserSuspiciousUser = (
user: User,
context: string,
message?: string
): SlackBlockConfig => {
const adminUserProfileUrl = `${process.env.FRONT_URL}/backoffice/admin/membres/aeb196a0-9c51-4810-ac91-6850611394cd${user.id}`;

return {
title: '🔬 Comportement suspect detecté 👿',
context: [
{
title: `➡️ Que se passe-t-il ?`,
content: context,
},
{
title: '👿 Qui est-ce ?',
content: `${user.firstName} ${user.lastName} <${user.email}>`,
},
],
msgParts: [
{
content: `*Message* :\n${message}`,
},
],
actions: [
{
label: 'Voir le profil',
url: adminUserProfileUrl,
value: 'see-profile',
},
],
};
};
84 changes: 84 additions & 0 deletions tests/messaging/messaging.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,90 @@ describe('MESSAGING', () => {
.set('authorization', `Bearer ${loggedInCandidate.token}`);
expect(response.status).toBe(400);
});

it('should return 429 when create an 8th conversation', async () => {
// Create the coachs
const coachs = await databaseHelper.createEntities(userFactory, 7, {
role: UserRoles.COACH,
});

// Create the conversations
const conversations = await databaseHelper.createEntities(
conversationFactory,
7
);
// And link the conversations to the coachs and the logged in candidate
const linkPromises = conversations.map((conversation, idx) =>
messagingHelper.associationParticipantsToConversation(
conversation.id,
[loggedInCandidate.user.id, coachs[idx].id]
)
);
await Promise.all(linkPromises);

// Add messages to the conversations
const messagePromises = conversations.map((conversation) =>
messagingHelper.addMessagesToConversation(
2,
conversation.id,
loggedInCandidate.user.id
)
);

await Promise.all(messagePromises);

const response: APIResponse<MessagingController['postMessage']> =
await request(server)
.post(`/messaging/messages`)
.send({
content: 'Super message',
participantIds: [loggedInCoach.user.id],
})
.set('authorization', `Bearer ${loggedInCandidate.token}`);
expect(response.status).toBe(429);
});

it('should return 201 when create a 7th conversation', async () => {
// Create the coachs
const coachs = await databaseHelper.createEntities(userFactory, 6, {
role: UserRoles.COACH,
});

// Create the conversations
const conversations = await databaseHelper.createEntities(
conversationFactory,
6
);
// And link the conversations to the coachs and the logged in candidate
const linkPromises = conversations.map((conversation, idx) =>
messagingHelper.associationParticipantsToConversation(
conversation.id,
[loggedInCandidate.user.id, coachs[idx].id]
)
);
await Promise.all(linkPromises);

// Add messages to the conversations
const messagePromises = conversations.map((conversation) =>
messagingHelper.addMessagesToConversation(
2,
conversation.id,
loggedInCandidate.user.id
)
);

await Promise.all(messagePromises);

const response: APIResponse<MessagingController['postMessage']> =
await request(server)
.post(`/messaging/messages`)
.send({
content: 'Super message',
participantIds: [loggedInCoach.user.id],
})
.set('authorization', `Bearer ${loggedInCandidate.token}`);
expect(response.status).toBe(201);
});
});
});

Expand Down

0 comments on commit d4ff08d

Please sign in to comment.