mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 10:19:20 +03:00
feat: added chat controller
This commit is contained in:
parent
c6472013a3
commit
97ed27a50a
38
app/Controllers/Http/Api/v1/ChatController.ts
Normal file
38
app/Controllers/Http/Api/v1/ChatController.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
import { ConversationType } from 'App/Store/MessageStore';
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
import HttpStatusEnum from 'App/Datatypes/Enums/HttpStatusEnum';
|
||||
|
||||
/**
|
||||
* Services
|
||||
*/
|
||||
import WsService from 'App/Services/WsService';
|
||||
|
||||
import BaseController from '../../BaseController';
|
||||
|
||||
@inject()
|
||||
export default class ChatController extends BaseController {
|
||||
/**
|
||||
* Get list of conversations (users)
|
||||
* GET /chat/conversations
|
||||
*/
|
||||
public async getConversations(ctx: HttpContextContract) {
|
||||
const user = await ctx.auth.authenticate();
|
||||
const data = await WsService.messageStore.getConversations(user.id);
|
||||
const result: IResponse<ConversationType[]> = {
|
||||
success: true,
|
||||
status: HttpStatusEnum.OK,
|
||||
message: 'Fetched conversations.',
|
||||
data,
|
||||
};
|
||||
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(ChatController);
|
||||
@ -1,5 +1,6 @@
|
||||
import { RedisConnectionContract } from '@ioc:Adonis/Addons/Redis';
|
||||
import Logger from '@ioc:Adonis/Core/Logger';
|
||||
import User from 'App/Models/User';
|
||||
import { DateTime } from 'luxon';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
@ -10,6 +11,12 @@ type MessageDataType = {
|
||||
time: string;
|
||||
};
|
||||
|
||||
export type ConversationType = {
|
||||
userId: string;
|
||||
fullname: string;
|
||||
lastMessage: MessageDataType;
|
||||
};
|
||||
|
||||
const MESSAGE_TTL = 185 * 24 * 60 * 60; // 185 days
|
||||
const MAX_MESSAGES_HISTORY = 100;
|
||||
|
||||
@ -62,6 +69,40 @@ class RedisMessageStore {
|
||||
return messages.sort((m1, m2) => new Date(m1.time).valueOf() - new Date(m2.time).valueOf());
|
||||
}
|
||||
|
||||
public async getConversations(userId: string): Promise<ConversationType[]> {
|
||||
/**
|
||||
* Getting conversations that had some message history
|
||||
*/
|
||||
const conversations = await this.redisClient.keys(`conversation:*${userId}*`);
|
||||
const userIds = conversations
|
||||
.map(id => id.split(':')[1])
|
||||
.map(id => (userId !== id.split('&')[0] ? id.split('&')[0] : id.split('&')[1]));
|
||||
|
||||
/**
|
||||
* Fetch this users
|
||||
*/
|
||||
const users = await User.query().select('id', 'first_name', 'last_name').where('id', 'in', userIds);
|
||||
|
||||
/**
|
||||
* Fetch last message of each conversation
|
||||
*/
|
||||
const result = await Promise.all(
|
||||
users.map(async u => {
|
||||
const convKey = this.createConversationKey(userId, u.id);
|
||||
const msgKey = await this.redisClient.lindex(convKey, 0);
|
||||
const lastMessage = await this.getMessage(`message:${msgKey}`);
|
||||
|
||||
return {
|
||||
userId: u.id,
|
||||
fullname: `${u.first_name} ${u.last_name}`,
|
||||
lastMessage,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async getMessage(key: string): Promise<MessageDataType> {
|
||||
const message = (await this.redisClient.hgetall(key)) as MessageDataType;
|
||||
return message;
|
||||
@ -70,7 +111,7 @@ class RedisMessageStore {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
private createConversationKey(userId1: string, userId2: string): string {
|
||||
const [id1, id2] = [userId1, userId2].sort();
|
||||
return `conversation:${id1}-${id2}`;
|
||||
return `conversation:${id1}&${id2}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
routes/apis/v1/chat.ts
Normal file
7
routes/apis/v1/chat.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import Route from '@ioc:Adonis/Core/Route';
|
||||
|
||||
Route.group(() => {
|
||||
Route.get('/conversations', 'Api/v1/ChatController.getConversations')
|
||||
.middleware('role:admin,teacher,student')
|
||||
.as('chat.get-conversations');
|
||||
}).prefix('chat');
|
||||
@ -68,6 +68,11 @@ Route.group(() => {
|
||||
* Stat module
|
||||
*/
|
||||
require('./stat');
|
||||
|
||||
/**
|
||||
* Chat module
|
||||
*/
|
||||
require('./chat');
|
||||
}).middleware('auth');
|
||||
})
|
||||
.prefix('v1')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user